#! /usr/bin/python3 # Last edited on 2024-09-18 10:41:20 by stolfi from math import sin, cos, tan, sqrt, pi, inf, floor, sqrt import rn import sys import re from slicing_lib import make_edge, make_face, check_repeated_edge, prte, prtf def triangulate(Ns, Nr, Nb, Vind, Vlst, Elst, Flst, prec, verbose): # See the main program and {make_vertices} for the description of the object. # # Subdivides the faces of the original mesh of the object Into # triangles. Assumes that the vertices are given by the structured # table {Vind} and flat list {Vlst}, the edges are given by the flat # list {Elst},and the faces are given by the flat list {Flst}. The # lists {Vlst,Elst,Flst} are indexed from 1; element 0 is not used. # # Returns new flat lists {Ftri} and {Etri} of faces and edges # of the triangulation. No new vertices are created. The # original edges are preserved with their original indices, # and the new diagonal edges are appended after them, with {etype=1}. # # Each quadrangular face "fv.{ks}{kr}" on the side of the keg is # subdivided into {2*(Nb+1)} triangles by {Nb} horizontal edges and # {Nb+1} diagonal edges, in alternating directions. The diagonals and # horizontal edegs will have the same label as the face, with the "f" # replaced by "d" or "h", respectively. The triangles will have labels # "fv.{ks}.{kr}.{kb}.{kt}" where {kb} ranges in {0..Nb} and {kt} is 0 # or 1. # # The triangular top and bottom faces "fh.{ks}.{kz}" are copied unchanged, except that # their indices in {Ftri} will be different from their indices in {Flst}. Nv_in = len(Vlst)-1 # Total vertex count (input and output). Ne_in = len(Elst)-1 # Total input edge count. Nf_in = len(Flst)-1 # Total input faces. Nv_ot = Ns*(Nr*(Nb+1) + 1) + 2 # Expected total output vertex count. Ne_ot = Ns*(3*Nr*(Nb+1) + 3) # Expected total output edge count. Nf_ot = Ns*(2*Nr*(Nb+1) + 2) # Expected total output face (triangle) count. assert Nv_ot == Nv_in, "{Nv,Vlst} inconsistent" sys.stderr.write("triangulate:\n") sys.stderr.write(" expecting %d triangulation edges\n" % Ne_ot) sys.stderr.write(" expecting %d triangulation faces\n" % Nf_ot) Etri = Elst.copy() + [None]*(Ne_ot-Ne_in) Ftri = [None]*(Nf_ot+1) Eset = set() # Set of edges as pairs, to check for repetitions. for je in range(1,Ne_in+1): e = Elst[je] Eset.add((e[0],e[1])) ne = Ne_in # Number of edges created so far. nf = 0 # Number of faces created so far. def Svdi(kv_org, kv_dst, elab): # Adds the diagonal edge from {Vlst[kv_org]} to {Vlst[kv_dst]} to {Etri}, # reoriented in increasing index sense. nonlocal ne, nf if kv_org > kv_dst: kv_org, kv_dst = kv_dst, kv_org etype = 1 e = make_edge(Vlst[kv_org], Vlst[kv_dst], ne+1, etype, elab, prec) assert e != None if verbose: prte(e, prec) ne += 1 Etri[ne] = e check_repeated_edge(ne, Etri, Eset, prec) return None def Tri(kva,kvb,kvc,flab): # Adds to {Etri} the triangle with vertices {Vlst[kva],Vlst[kvb],Vlst[kvc]} # assumed to be CCW seen from outside. nonlocal ne, nf nf += 1 t = make_face((kva,kvb,kvc), nf, flab, Vlst, prec) if verbose: prtf(t, Vlst, prec) Ftri[nf] = t for f in Flst[1:]: Nx,Ny,Nz,Fiv,kf,flab = f; if verbose: sys.stderr.write("\n") sys.stderr.write(" IN: ") prtf(f, Vlst, prec) sys.stderr.write("\n") ks = int(re.sub(r'[.].*$', '', flab[3:])); assert ks >= 0 and ks < Ns if flab[0:2] == "fh": # Top/bottom face: kz = int(re.sub(r'^.*[.]', '', flab[3:])); assert kz == 0 or kz == 1 assert len(Fiv) == 3; Tri(Fiv[0],Fiv[1],Fiv[2],flab) elif flab[0:2] == "fv": # Barrel side face: kr = int(re.sub(r'^.*[.]', '', flab[3:])); assert kr >= 0 and kr < Nr deg = len(Fiv) assert deg == 4 + 2*Nb; for kb in range(Nb+1): iva = Fiv[(deg-kb) % deg] ivb = Fiv[kb+1] ivc = Fiv[kb+2] ivd = Fiv[deg-1-kb] if (ks + kr) % 2 == 0: Tri(iva,ivb,ivc,flab + f".{kb}.0") Tri(ivc,ivd,iva,flab + f".{kb}.1") Svdi(iva,ivc,"d" + flab[1:]) else: Tri(iva,ivb,ivd,flab + f".{kb}.0") Tri(ivb,ivc,ivd,flab + f".{kb}.1") Svdi(ivb,ivd,"d" + flab[1:]) if kb > 0: Svdi(iva,ivb,"h" + flab[1:]) else: assert False, f"invalid face label '{flab}'" if nf < Nf_ot: sys.stderr.write("!! missing some faces\n") assert nf <= Nf_ot if ne < Ne_ot: sys.stderr.write("!! missing some edges\n") assert ne <= Ne_ot return Etri, Ftri