def fullflattriareas(surfacemesh): ptsP = [P3(*p) for p in surfacemesh["pts"]] fptsP = [P2(*p) for p in surfacemesh["fpts"]] tris = surfacemesh["tris"] def P2Cross(a, b): return a.u * b.v - b.u * a.v triareas = [] ftriareas = [] cornerangs = [] fcornerangs = [] for tri in tris: p0, p1, p2 = ptsP[tri[0]], ptsP[tri[1]], ptsP[tri[2]] parea = 0.5 * P3.Cross(p1 - p0, p2 - p0).Len() triareas.append(parea) cornerangs.append(P3.Cross(P3.ZNorm(p1 - p0), P3.ZNorm(p2 - p0)).Len()) f0, f1, f2 = fptsP[tri[0]], fptsP[tri[1]], fptsP[tri[2]] farea = 0.5 * abs(P2Cross(f1 - f0, f2 - f0)) ftriareas.append(farea) fcornerangs.append(abs(P2Cross(P2.ZNorm(f1 - f0), P2.ZNorm(f2 - f0)))) surfacemesh["triareas"] = numpy.array(triareas) surfacemesh["ftriareas"] = numpy.array(ftriareas) surfacemesh["cornerangs"] = numpy.array(cornerangs) surfacemesh["fcornerangs"] = numpy.array(fcornerangs)
def StarSplitFace(bm, bar, node): lbar, lnode = bar, node Dcounts = 0 pnodebars = [] while True: pnodebars.append((lnode, lbar)) lnode = lbar.GetNodeFore(lbar.nodeback == lnode) if lnode == node: break lbar = lbar.GetForeRightBL(lbar.nodefore == lnode) Dcounts += 1 assert Dcounts < 1000 cpt = sum( (lnode.p for (lnode, lbar) in pnodebars), P3(0, 0, 0)) * (1 / len(pnodebars)) cnode = bm.NewNode(cpt) cnode.pointzone = barmesh.PointZone(0, -1, P3(0, 0, 0)) np = len(pnodebars) cbars = [barmesh.Bar(lnode, cnode) for lnode, lbar in pnodebars] for i in range(np): cbars[i].barforeright = cbars[i - 1 if i != 0 else np - 1] cbars[i].barbackleft = pnodebars[i][ 1] # cbars[i-1 if i!=0 else np-1] lnode, lbar = pnodebars[i] lnode = lbar.GetNodeFore(lbar.nodeback == lnode) lbar.SetForeRightBL(lbar.nodefore == lnode, cbars[i + 1 if i != np - 1 else 0]) bm.bars.extend(cbars)
def PolyCutBar(ktbar, ktnode1, vc, vch, btop): assert not ktbar.bbardeleted, "polycutbar hits deletion" Dktbarstart = ktbar ktnoded1 = P3.Dot(vc, ktnode1.p) assert btop == (P3.Dot(vc, ktbar.nodemid.p) < vch), ("fg", btop, P3.Dot( vc, ktbar.nodemid.p), vch) #assert ktnoded0 < vch # not necessarily true if bar points back with mid on end Dcount = 0 while True: ktnode0 = ktnode1 ktnode1 = ktbar.GetNodeFore(ktbar.nodeback == ktnode0) ktnoded0 = ktnoded1 ktnoded1 = P3.Dot(vc, ktnode1.p) if btop == (ktnoded1 > vch): break ktbar = ktbar.GetForeRightBL(ktbar.nodefore == ktnode1) assert not ktbar.bbardeleted assert Dktbarstart != ktbar Dcount += 1 assert Dcount < 1000 ktbarlam = (vch - ktnoded0) / (ktnoded1 - ktnoded0) return ktnode0, ktbar, ktbarlam
def DistPtrianglePZ(self, p0, p1, p2): v1 = p1 - p0 v2 = p2 - p0 v1sq = v1.Lensq() v2sq = v2.Lensq() v1dv2 = P3.Dot(v1, v2) det = v1sq * v2sq - v1dv2**2 if det == 0.0: return # near zero width triangle has no face to touch invdet = 1.0 / det # should do distance by the dot on the crossproduct normal lv = self.p - p0 v1dlv = P3.Dot(v1, lv) v2dlv = P3.Dot(v2, lv) # solve vd = lv - v1 * lam1 - v2 * lam2, where vd.v1 = vd.v2 = 0 # (v1sq v1dv2) ( lam1 ) ( v1dlv ) # (v1dv2 v2sq) . ( lam2 ) = ( v2dlv ) lam1 = (v2sq * v1dlv - v1dv2 * v2dlv) * invdet lam2 = (-v1dv2 * v1dlv + v1sq * v2dlv) * invdet if 0 < lam1 and 0 < lam2 and lam1 + lam2 < 1: vd = lv - v1 * lam1 - v2 * lam2 assert abs(P3.Dot(vd, v1)) < 0.001 assert abs(P3.Dot(vd, v2)) < 0.001 vdlen = vd.Len() if vdlen < self.r: self.r = vdlen self.v = -vd
def getbarendclos(self, barstosplit): # for plotting closest approaches pcs = [] for bar in barstosplit: if bar.bbardeleted: continue if not ((bar.nodeback.pointzone.izone == barmesh.PZ_BEYOND_R) and (bar.nodefore.pointzone.izone == barmesh.PZ_BEYOND_R)): continue vb = bar.nodefore.p - bar.nodeback.p vbsq = vb.Lensq() if bar.nodeback.pointzone.v is not None: lampcb = P3.Dot(bar.nodeback.pointzone.v, vb) / vbsq if 0 < lampcb < 1: dvb = bar.nodeback.pointzone.v - vb * lampcb assert abs(P3.Dot(dvb, vb)) < 0.001 dvbsq = dvb.Lensq() if dvbsq < self.rdsq: pcs.append(bar.nodeback.p + bar.nodeback.pointzone.v) if bar.nodefore.pointzone.v is not None: lampcf = -P3.Dot(bar.nodefore.pointzone.v, vb) / vbsq if 0 < lampcf < 1: dvf = bar.nodefore.pointzone.v + vb * lampcf assert abs(P3.Dot(dvf, vb)) < 0.001 dvfsq = dvf.Lensq() if dvfsq < self.rdsq: pcs.append(bar.nodeback.p + bar.nodefore.pointzone.v) return pcs
def CubeNode(ncode): bxlo, bylo, bzlo = (ncode & 0b100, ncode & 0b010, ncode & 0b001) node = bm.NewNode( P3(xlo if bxlo else xhi, ylo if bylo else yhi, zlo if bzlo else zhi)) node.pointzone = barmesh.PointZone( 0, -1, P3(w if bxlo else -w, w if bylo else -w, w if bzlo else -w)) return node
def InsertNodeIntoBarF(self, bar, newnode, bcolinear): assert newnode.p != bar.nodeback.p and newnode.p != bar.nodefore.p, newnode.p assert newnode in self.nodes if __debug__: if bcolinear: Dv = bar.nodefore.p - bar.nodeback.p Dv0 = newnode.p - bar.nodeback.p Dlam = P3.Dot(Dv0, Dv) / Dv.Lensq() assert 0 < Dlam < 1, Dlam Dvd = Dv0 - Dv * Dlam assert abs(P3.Dot(Dvd, Dv)) < 0.001 assert Dvd.Len() < 0.01, (Dv, Dv0) barforeleft = bar.GetBarForeLeft() barbackright = bar.GetBarBackRight() barback = Bar(bar.nodeback, newnode) barfore = Bar(bar.nodefore, newnode) if bcolinear: # copy over so we can identify colinearity from creation and not attempt to split along it assert (bar.barvecN - barback.barvecN).Len() < 1e-5, ( bar.nodeback.p, newnode.p, bar.nodefore.p) assert (bar.barvecN + barfore.barvecN).Len() < 1e-5, ( bar.nodeback.p, newnode.p, bar.nodefore.p) barback.barvecN = bar.barvecN barfore.barvecN = -bar.barvecN barback.cellmarkleft, barback.cellmarkright = bar.cellmarkleft, bar.cellmarkright barfore.cellmarkright, barfore.cellmarkleft = bar.cellmarkleft, bar.cellmarkright if barbackright: barback.barforeright = barfore barfore.barbackleft = bar.barforeright barbackright.SetForeRightBL(barbackright.nodefore == bar.nodeback, barback) if barforeleft: barback.barbackleft = bar.barbackleft barfore.barforeright = barback barforeleft.SetForeRightBL(barforeleft.nodefore == bar.nodefore, barfore) assert not barforeleft or barback.GetBarForeLeft( ) == barfore, barback.GetBarForeLeft() assert not barbackright or barfore.GetBarForeLeft( ) == barback, barfore.GetBarForeLeft() self.bars.append(barback) self.bars.append(barfore) bar.barforeright = barfore bar.barbackleft = barback bar.bbardeleted = True return newnode
def DistPedgePZ(self, p0, p1): lv = self.p - p0 v = p1 - p0 vsq = v.Lensq() lam = P3.Dot(v, lv) / vsq if 0.0 < lam < 1.0: vd = lv - v * lam assert abs(P3.Dot(vd, v)) < 0.0001 vdlen = vd.Len() if vdlen < self.r: self.r = vdlen self.v = -vd
def BuildTriangleBarmesh(self, trpts): # strip out duplicates in the corner points of the triangles ipts, jtrs = [], [] for i, tr in enumerate(trpts): ipts.append((tr[0:3], i * 3 + 0)) ipts.append((tr[3:6], i * 3 + 1)) ipts.append((tr[6:9], i * 3 + 2)) jtrs.append([-1, -1, -1]) ipts.sort(key=self.nodesortkey) prevpt = None for pt, i3 in ipts: if not prevpt or prevpt != pt: self.NewNode(P3(pt[0], pt[1], pt[2])) prevpt = pt jtrs[i3 // 3][i3 % 3] = len(self.nodes) - 1 del ipts # create the barcycles around each triangle tbars = [] for jt0, jt1, jt2 in jtrs: if jt0 != jt1 and jt0 != jt2 and jt1 != jt2: # are all the points distinct? tbars.append( jt0 < jt1 and TriangleBar(self.nodes[jt0], self.nodes[jt1]) or TriangleBar(self.nodes[jt1], self.nodes[jt0])) tbars.append( jt1 < jt2 and TriangleBar(self.nodes[jt1], self.nodes[jt2]) or TriangleBar(self.nodes[jt2], self.nodes[jt1])) tbars.append( jt2 < jt0 and TriangleBar(self.nodes[jt2], self.nodes[jt0]) or TriangleBar(self.nodes[jt0], self.nodes[jt2])) tbars[-3].SetForeRightBL(jt0 < jt1, tbars[-2]) tbars[-2].SetForeRightBL(jt1 < jt2, tbars[-1]) tbars[-1].SetForeRightBL(jt2 < jt0, tbars[-3]) del jtrs # strip out duplicates of bars where two triangles meet tbars.sort(key=lambda bar: (bar.nodeback.i, bar.nodefore.i, not bar.barbackleft)) prevbar = None for bar in tbars: if prevbar and prevbar.nodeback == bar.nodeback and prevbar.nodefore == bar.nodefore and \ prevbar.barbackleft and not prevbar.barforeright and not bar.barbackleft and bar.barforeright: prevbar.barforeright = bar.barforeright node2 = bar.barforeright.GetNodeFore( bar.nodefore == bar.barforeright.nodeback) bar2 = bar.barforeright.GetForeRightBL( bar.nodefore == bar.barforeright.nodeback) assert bar2.GetNodeFore(bar2.nodeback == node2) == bar.nodeback assert bar2.GetForeRightBL(bar2.nodeback == node2) == bar bar2.SetForeRightBL(bar2.nodeback == node2, prevbar) prevbar = None else: prevbar = bar assert prevbar.i == -1 prevbar.i = len(self.bars) self.bars.append(bar) del tbars
def DistLamPedgePZ(self, p0, p1): v = p1 - p0 vsq = v.Lensq() lv = self.p - p0 # solve |lv + vp * lam - v * mu| == r, where (lv + vp * lam - v * mu) . vp == 0 mu0 = P3.Dot(lv, v) / vsq lvf = lv - v * mu0 vpdv = P3.Dot(self.vp, v) muvp = vpdv / vsq vpf = self.vp - v * muvp vpfsq = vpf.Lensq() if vpfsq == 0.0: return assert abs(vpfsq - (self.vpsq - muvp * vpdv)) < 0.001 lvfdvpf = P3.Dot(lvf, vpf) lamc = -lvfdvpf / vpfsq cp = lvf + vpf * lamc cpsq = cp.Lensq() lvfsq = lvf.Lensq() assert abs(cpsq - (lvfsq + 2 * lvfdvpf * lamc + vpfsq * lamc * lamc)) < 0.001 assert abs(P3.Dot(cp, vpf)) < 0.001 llamdsq = self.rsq - cp.Lensq() if llamdsq < 0.0: return lamd = math.sqrt(llamdsq / vpfsq) if lamc + lamd < 0.0: return lam = lamc - lamd if lam < 0.0: return # check closer stuff if lam > self.lam: return mu = mu0 + muvp * lam if mu < 0 or mu > 1: return dv = lv + self.vp * lam - v * mu assert abs(dv.Len() - self.r) < 0.001 assert abs(P3.Dot(dv, v)) < 0.001 self.lam = lam
def calcsplithalfpos(self): # midpoint, but could be informed by multiple subdivisions on the rate of curvature # should also measure the bc.calccellcuttangency() and find a spot where it is properly wide and doesn't need to be tested vch = P3.Dot(self.vc, self.bar.nodemid.p + self.vc * 0.5) # find the splitting points self.ktnodetop, self.ktbartop, self.ktbartoplam = PolyCutBar( self.bar, self.node, self.vc, vch, True) self.ktnodebot, self.ktbarbot, self.ktbarbotlam = PolyCutBar( self.cbar, self.cbar.GetNodeFore(self.cbar.nodeback == self.cnode), self.vc, vch, False)
def __init__(self, fname, Isect=7): self.Isect = Isect # Fix the section all rectangle unwrapping is relative to self.sections, self.zvals = loadwinggeometry(fname, 0.001) self.nsections = len(self.zvals) assert self.nsections == len(self.sections) self.nchorddivs = len(self.sections[0]) assert self.nchorddivs == len(self.sections[-1]) self.sectionchordlengths = [ ] self.sectionchordranges = [ ] for section in self.sections: chordlengths = [ 0 ] for p0, p1 in zip(section, section[1:]): chordlengths.append(chordlengths[-1] + (p0-p1).Len()) self.sectionchordlengths.append(chordlengths) self.sectionchordranges.append((-chordlengths[-1]*0.5, chordlengths[-1]*0.5)) self.leadingedgelengths = [ 0 ] for i in range(1, self.nsections): p0 = P3.ConvertGZ(self.sectionchordeval(i-1, 0), self.zvals[i-1]) p1 = P3.ConvertGZ(self.sectionchordeval(i, 0), self.zvals[i]) self.leadingedgelengths.append(self.leadingedgelengths[-1] + (p0-p1).Len()) self.urange = (self.leadingedgelengths[0], self.leadingedgelengths[-1]) self.vrange = self.sectionchordranges[self.Isect]
def __init__(self, nodeback, nodefore): self.nodeback = nodeback self.nodefore = nodefore self.barforeright = None self.barbackleft = None self.bbardeleted = False assert nodefore.i > nodeback.i self.nodemid = None # used to specify a contour cut or a voronoi polygon boundary cut self.midcontournumber = -1 # will be set to -2 to denote connecting to out of tolerance/unchecked tolerance trailing contour segment self.cellmarkright = None self.cellmarkleft = None self.barvecN = P3.ZNorm( self.nodefore.p - self.nodeback.p ) # used to detect colinearity as it's preserved on splitting
def deriveflatpathstretchratios(self, surfacemeshes): nodepairreallengths = {} nodepairflatlengths = {} for surfacemesh in surfacemeshes: polynodes = surfacemesh["polynodes"] uvpts = surfacemesh["uvpts"] pts = surfacemesh["pts"] fpts = surfacemesh["fpts"] linecontour = surfacemesh["linecontour"] for i in range(len(polynodes)): n1, n2 = polynodes[i], polynodes[(i + 1) % len(polynodes)] p1, p2 = self.nodes[n1], self.nodes[n2] i1, i2 = uvpts.index(p1), uvpts.index(p2) j1, j2 = linecontour.index(i1), linecontour.index(i2) if j2 == 0: j2 = len(linecontour) - 1 assert (j1 < j2) lenreal = sum((P3(*pts[linecontour[j + 1]]) - P3(*pts[linecontour[j]])).Len() for j in range(j1, j2)) lenflat = sum((P2(*fpts[linecontour[j + 1]]) - P2(*fpts[linecontour[j]])).Len() for j in range(j1, j2)) nodepairflatlengths[(n1, n2)] = lenflat nodepairreallengths[(n1, n2)] = lenreal self.flatpathratios = {} self.flatpathtable = [] for i in range(0, len(self.paths), 2): n1, n2 = self.paths[i], self.paths[i + 1] lenga = nodepairflatlengths.get((n1, n2), -1) lengb = nodepairflatlengths.get((n2, n1), -1) if lenga != -1 and lengb != -1: self.flatpathratios[(n1, n2)] = lenga / lengb lengreal = nodepairreallengths.get( (n1, n2)) or nodepairreallengths.get((n2, n1)) or -1 self.flatpathtable.append((n1, n2, lenga, lengb, lengreal))
def calccellcuttangency( self ): # could be checked before splitting on the lines to give an option of picking a less tangential position assert not self.leadsplitbartop.bbardeleted and not self.leadsplitbarbot.bbardeleted node1, bar1, node2, bar2 = self.splitnodetop, self.leadsplitbartop, self.splitnodebot, self.leadsplitbarbot bar1a = bar1.GetForeRightBL(bar1.nodefore == node1) bar2a = bar2.GetForeRightBL(bar2.nodefore == node2) vtopbot = P3.ZNorm(self.splitnodebot.p - self.splitnodetop.p) db1 = -node1.cperpbardotN(bar1, vtopbot) db1a = node1.cperpbardotN(bar1a, vtopbot) db2 = node2.cperpbardotN(bar2, vtopbot) db2a = -node2.cperpbardotN(bar2a, vtopbot) res = min(db1, db1a, db2, db2a) assert res > -0.0001 return res
def shoulddivide(self, rd, contourdelta, contourdotdiff, b2dcontournormals): if self.vc.Len() <= contourdelta: return False if b2dcontournormals: nd = P2.Dot( P2.ZNorm( P2(self.bar.nodemid.pointzone.v.x, self.bar.nodemid.pointzone.v.y)), P2.ZNorm( P2(self.cbar.nodemid.pointzone.v.x, self.cbar.nodemid.pointzone.v.y))) else: nd = P3.Dot(self.bar.nodemid.pointzone.v, self.cbar.nodemid.pointzone.v) / (rd * rd) if nd >= contourdotdiff: return False return True
def winguv2xyz(uvx, uvy, sections, zvals): wingmeshuvudivisions = len(sections)-1 #print(wingmeshuvudivisions) wingmeshuvvdivisions = len(sections[0]) #print(wingmeshuvvdivisions) usecl = uvx*wingmeshuvudivisions usec = int(max(0, min(wingmeshuvudivisions-1, math.floor(usecl)))) ropepointlamda = usecl - usec aroundsegmentl = uvy*wingmeshuvvdivisions-1 aroundsegment = int(max(0, min(wingmeshuvvdivisions-2, math.floor(aroundsegmentl)))) lambdaCalong = aroundsegmentl - aroundsegment p00 = sections[usec][aroundsegment] p01 = sections[usec][aroundsegment+1] p10 = sections[usec+1][aroundsegment] p11 = sections[usec+1][aroundsegment+1] z = zvals[usec]*(1-ropepointlamda) + zvals[usec+1]*ropepointlamda p0 = p00*(1-ropepointlamda) + p10*ropepointlamda p1 = p01*(1-ropepointlamda) + p11*ropepointlamda p = p0*(1-lambdaCalong) + p1*lambdaCalong return P3(p[0], p[1], z)
def DistLamPpointPZ(self, p0): lv = p0 - self.p if lv.z < min(self.vp.z, 0) - self.r or lv.z > max(self.vp.z, 0) + self.r: return # |lv - vp * lam| = r # qa = vpsq qb2 = -P3.Dot(self.vp, lv) qc = lv.Lensq() - self.rsq qdq = qb2 * qb2 - self.vpsq * qc if qdq < 0.0: return qs = math.sqrt(qdq) / self.vpsq qm = -qb2 / self.vpsq assert abs(qc + (qm + qs) * (2 * qb2 + (qm + qs) * self.vpsq)) < 0.002 if qm + qs <= 0.0: return laml = qm - qs if laml < 0.0: self.lam = 0.0 # shouldn't happen elif laml < self.lam: self.lam = laml
def BuildRectBarMesh(self, xpart, ypart, z): nxs = xpart.nparts + 1 nodes = self.nodes xbars = [] # multiple of nxs ybars = [] # multiple of nxs-1 self.bars = [] for y in ypart.vs: bfirstrow = (len(nodes) == 0) for i in range(nxs): nnode = self.NewNode(P3(xpart.vs[i], y, z)) assert nnode == nodes[-1] if not bfirstrow: xbars.append(Bar(nodes[-nxs - 1], nodes[-1])) self.bars.append(xbars[-1]) if i != 0: xbars[-1].barbackleft = ybars[1 - nxs] ybars[1 - nxs].barbackleft = xbars[-2] if i != 0: ybars.append(Bar(nodes[-2], nodes[-1])) self.bars.append(ybars[-1]) if not bfirstrow: ybars[-1].barforeright = xbars[-1] xbars[-2].barforeright = ybars[-1] assert len(self.bars) == len(xbars) + len(ybars)
def cperpbardotN(self, bar, v): assert self == bar.nodeback or self == bar.nodefore vb = (bar.nodefore.p - bar.nodeback.p) vbs = (self == bar.nodeback and +1 or -1) cperpvb = P3(vb.y * vbs, -vb.x * vbs, 0) return P3.Dot(cperpvb, v) / vb.Len()
def splitbarsdirectionchangesR(self, barstosplit): barsplitsdc = [] bsdsq = self.barsplitdelta * self.barsplitdelta for bar in barstosplit: if bar.bbardeleted: continue if not ((bar.nodeback.pointzone.izone == barmesh.PZ_BEYOND_R) and (bar.nodefore.pointzone.izone == barmesh.PZ_BEYOND_R)): continue vb = bar.nodefore.p - bar.nodeback.p vbsq = vb.Lensq() if vbsq < bsdsq: continue lamclossplit = -1 dvbsq = -1 if bar.nodeback.pointzone.v is not None: lampcb = P3.Dot(bar.nodeback.pointzone.v, vb) / vbsq if 0 < lampcb < 1: dvb = bar.nodeback.pointzone.v - vb * lampcb assert abs(P3.Dot(dvb, vb)) < 0.001 dvbsq = dvb.Lensq() if dvbsq < self.rdsq: lamclossplit = lampcb if bar.nodefore.pointzone.v is not None: lampcf = -P3.Dot(bar.nodefore.pointzone.v, vb) / vbsq if 0 < lampcf < 1: dvf = bar.nodefore.pointzone.v + vb * lampcf assert abs(P3.Dot(dvf, vb)) < 0.001 dvfsq = dvf.Lensq() if dvfsq < self.rdsq: if lamclossplit == -1 or dvfsq < dvbsq: lamclossplit = 1 - lampcf if lamclossplit != -1: barsplitsdc.append((bar, lamclossplit)) # split the bars nowsplitbars = [] splitnodes = [] for bar, lamc in barsplitsdc: splitnode = self.bm.InsertNodeIntoBarF( bar, self.bm.NewNode(Along(lamc, bar.nodeback.p, bar.nodefore.p)), True) assert bar.bbardeleted splitnodes.append(splitnode) nowsplitbars.append(bar.barforeright) nowsplitbars.append(bar.barbackleft) # make the measurements on all the new splitnodes self.MakePointZoneRFS(splitnodes) # make the measurements on all the new bars newbarpolycuts = [] for bar in nowsplitbars: if IsCutBar(bar, barmesh.PZ_BEYOND_R): newbarpolycuts.append(bar) self.CutbarRFS(newbarpolycuts) #print("splitbarsdirectionchanges", len(barstosplit), len(nowsplitbars)) return nowsplitbars
def DistLamPtrianglePZ(self, p0, p1, p2): # solve vd = lv + vp * lam - v1 * lam1 - v2 * lam2, where |vd| = r and vd.v1 = vd.v2 = 0 # solve +-r = (lv + vp * lam) . vnorm = lv . vnorm + vp . vnorm lam v1 = p1 - p0 v2 = p2 - p0 vcross = P3.Cross(v1, v2) assert abs(P3.Dot(vcross, v1)) < 0.001 assert abs(P3.Dot(vcross, v2)) < 0.001 vnorm = P3.ZNorm(vcross) lv = self.p - p0 lvdvnorm = P3.Dot(lv, vnorm) vpdvnorm = P3.Dot(self.vp, vnorm) if vpdvnorm == 0.0: return # lam = (+-r - lvdvnorm)/vpdvnorm if vpdvnorm > 0.0: lam = (-self.r - lvdvnorm) / vpdvnorm else: lam = (self.r - lvdvnorm) / vpdvnorm if lam < 0 or lam > self.lam: return lvl = lv + self.vp * lam v1dlv = P3.Dot(v1, lvl) v2dlv = P3.Dot(v2, lvl) v1sq = v1.Lensq() v2sq = v2.Lensq() v1dv2 = P3.Dot(v1, v2) det = v1sq * v2sq - v1dv2**2 if det == 0.0: return # no face size invdet = 1.0 / det # solve vd = lv - v1 * lam1 - v2 * lam2, where vd.v1 = vd.v2 = 0 # (v1sq v1dv2) ( lam1 ) ( v1dlv ) # (v1dv2 v2sq) . ( lam2 ) = ( v2dlv ) lam1 = (v2sq * v1dlv - v1dv2 * v2dlv) * invdet lam2 = (-v1dv2 * v1dlv + v1sq * v2dlv) * invdet if 0 < lam1 and 0 < lam2 and lam1 + lam2 < 1: vd = lvl - v1 * lam1 - v2 * lam2 assert abs(P3.Dot(vd, v1)) < 0.001 assert abs(P3.Dot(vd, v2)) < 0.001 assert abs(vd.Len() - self.r) < 0.001 self.lam = lam
def AlongP3Z(z, p0, p1): assert (p0.z < z) != (p1.z < z) or p0.z == z, (p0.z, z, p1.z) lam = (z - p0.z) / (p1.z - p0.z) assert 0.0 <= lam <= 1.0 return P3(p0.x * (1 - lam) + p1.x * lam, p0.y * (1 - lam) + p1.y * lam, z)
def sevalI(self, p): i = max(0, min(self.nsections-2, int(p[0]))) m = p[0] - i p0 = P3.ConvertGZ(self.sectionchordevalI(i, p[1]), self.zvals[i]) p1 = P3.ConvertGZ(self.sectionchordevalI(i+1, p[1]), self.zvals[i+1]) return p0*(1-m) + p1*m
def seval(self, p): if p[0] < 0.0: s = self.sevalI(self.sevalconv((-p[0], p[1]))) return P3(s.x, s.y, -s.z) return self.sevalI(self.sevalconv(p))
def GetNodePoint(self, i): return P3(*self.nnodes[i,])