def dualPointFromHyperplane(hyperplane, centerPoint=None): if not centerPoint: centerPoint=(0,)*len(hyperplane.normal) dist=hyperplane.orientedDistance(centerPoint) if abs(dist) < 0.0001: raise RuntimeError("Hyperplane passing through the center") return algebra.vectSum(algebra.vectMult(-1/dist, hyperplane.normal), centerPoint)
def cutFigure(wholeFigure, hyperplane): facesAscending=[] queue=[wholeFigure] mark=object() while queue: figure=queue.pop(0) if figure.mark==mark: continue figure.mark=mark facesAscending.insert(0,figure) queue.extend(figure.boundary) for figure in facesAscending: figure.usedInSection=False figure.sectionFacets=[] if figure.dim == 0: # Vertex dist=hyperplane.orientedDistance(figure.position) if abs(dist)<0.0001: figure.cuttingCache=([], [figure], []) elif dist>0: figure.cuttingCache=([], [], [figure]) else: figure.cuttingCache=([figure], [], []) continue; # Edge, face, ... left,middle,right = \ zip(*map(lambda f: f.cuttingCache, figure.boundary)) left,middle,right = (reduce(lambda a,b: a+b, l) for l in (left,middle,right)) if not right and not left: # All in the hyperplane figure.cuttingCache=([], [figure], []) continue if not right or not left: for f in middle: if f.dim==figure.dim-1: for f2 in f.boundary: f2.usedInSection=True figure.sectionFacets.append(f) middle2=[] for f in middle: if not f.usedInSection or f.dim == figure.dim-2: middle2.append(f) middle=middle2 if not right: # Nothing right figure.cuttingCache=([figure], middle, []) continue if not left: # Nothing left figure.cuttingCache=([], middle, [figure]) continue section=[] middle2=set() for f in middle: if f.dim == figure.dim-2: middle2.add(f) elif f.dim != figure.dim-1: section.append(f) middle=middle2 if figure.dim == 1: # Cutting edge diff=algebra.vectDiff(right[0].position, left[0].position) prod=algebra.dotProduct(diff, hyperplane.normal) dist=hyperplane.orientedDistance(left[0].position) vert=Vertex(algebra.vectSum(left[0].position, algebra.vectMult(-dist/prod, diff))) vert.usedInSection=True leftEdge=Figure([left[0], vert]) rightEdge=Figure([right[0], vert]) leftEdge.sectionFacets=[vert] rightEdge.sectionFacets=[vert] figure.cuttingCache=([leftEdge], [vert], [rightEdge]) continue # Cutting face (at least 2-dimensional) leftComp=check.findComponents(left, middle) rightComp=check.findComponents(right, middle) leftComp=[Figure(c) for c in leftComp] rightComp=[Figure(c) for c in rightComp] for rightFigure in rightComp: rightFigure.sectionFacets=[] rightFigure.sectionRidges=set() for f in rightFigure.boundary: rightFigure.sectionRidges.update(f.sectionFacets) for leftFigure in leftComp: leftFigure.sectionFacets=[] leftRidges=set() for f in leftFigure.boundary: leftRidges.update(f.sectionFacets) for rightFigure in rightComp: rightRidges=rightFigure.sectionRidges commonRidges=leftRidges | rightRidges if commonRidges: f=Figure(commonRidges) f.usedInSection=True leftFigure.sectionFacets.append(f) rightFigure.sectionFacets.append(f) leftFigure.boundary.add(f) rightFigure.boundary.add(f) section.append(f) for f in middle: if not f.usedInSection: section.append(f) figure.cuttingCache=(leftComp, section, rightComp) ret=wholeFigure.cuttingCache; for figure in wholeFigure: del figure.cuttingCache del figure.usedInSection return ret;
def stellateFigure(figure): objFigure.updateVerticesLists(figure) objFigure.updateParentsLists(figure) innerPoint=algebra.vectAvg(*[v.position for v in figure.vertices]) for f in figure.boundary: f.hyperplane=spaceCuts.hyperplaneOfFacet(f, innerPoint); f.hyperplane.origFacet=f newFacets=[] for f in figure.boundary: facets=set() for f2 in f.boundary: facets.update(f2.parents) facets.remove(f) hyperplanes=[f2.hyperplane for f2 in facets] hyperplane=f.hyperplane.inverse() hyperplane.origFacet=f apexPoint=algebra.vectAvg(*[v.position for v in f.vertices]) dist=float('inf') for h in hyperplanes: p=algebra.dotProduct(hyperplane.normal, h.normal) if p<-0.0001: d=-h.orientedDistance(apexPoint)/p if d<0.0001: raise RuntimeError("The figure is not convex") elif d<dist: dist=d if dist == float('inf'): raise RuntimeError("Infinite stellations are not supported") hyperplanes.append(hyperplane) apexInnerPoint=algebra.vectSum(apexPoint, algebra.vectMult(dist/2.0, hyperplane.normal)) apexFigure=spaceCuts.figureFromArea(hyperplanes, apexInnerPoint) apexBaseFacet=[f3 for f3 in apexFigure.boundary if f3.origHypp.origFacet==f][0] for f3 in apexFigure: f3.origFace=None apexFigure.rmFromBoundary(apexBaseFacet) for apexFacet in apexFigure.boundary: apexRidge=(apexFacet.boundary & apexBaseFacet.boundary).pop() apexRidge.origFace=(apexFacet.origHypp.origFacet.boundary & f.boundary).pop() objFigure.updateParentsLists(apexBaseFacet) queue=[] for apexRidge in apexBaseFacet.boundary: queue.extend(apexRidge.boundary) while queue: apexFace=queue.pop(0) if apexFace.origFace: continue origP1=apexFace.parents[0].origFace origP2=apexFace.parents[1].origFace apexFace.origFace=(origP1.boundary & origP2.boundary).pop() queue.extend(apexFace.boundary) for f3 in apexBaseFacet: del f3.parents queue=[apexFigure] apexFigure.mark=True while queue: apexFace=queue.pop(0) if not apexFace.mark: continue apexFace.mark=None for apexFace2 in list(apexFace.boundary): if apexFace2.origFace: apexFace.boundary.remove(apexFace2) apexFace.boundary.add(apexFace2.origFace) else: apexFace2.mark=True queue.append(apexFace2) newFacets.extend(apexFigure.boundary) return objFigure.Figure(newFacets)
def stellateFigure(figure): for f in figure.boundary: for f2 in f: f2.bounds=[] for f in figure.boundary: for f2 in f: f2.bounds.append(f) vertsPos=[v.position for v in figure if v.dim == 0] innerPoint=algebra.vectMult(1.0/len(vertsPos), algebra.vectSum(*vertsPos)) figByBoundary=dict() for f in sorted(figure, key=attrgetter("dim")): if f.dim == 0: pass else: figByBoundary[frozenset(f.boundary)]=f newFacets=[] for f in figure.boundary: facets=set() for f2 in f.boundary: facets=facets.union(f2.bounds) # to be in-place facets.remove(f) hyperplanes=[spaceCuts.hyperplaneOfFacet(f2, innerPoint) for f2 in facets] hyperplane=spaceCuts.hyperplaneOfFacet(f, innerPoint).inverse() fv=[v.position for v in f if v.dim==0] apexPoint=algebra.vectMult(1.0/len(fv), algebra.vectSum(*fv)) dist=float('inf') for h in hyperplanes: p=algebra.dotProduct(hyperplane.normal, h.normal) if p<-0.0001: d=-h.orientedDistance(apexPoint)/p if d<0.0001: raise RuntimeError("The figure is not convex") elif d<dist: dist=d if dist == float('inf'): raise RuntimeError("Infinite stellations are not supported") hyperplanes.append(hyperplane) apexInnerPoint=algebra.vectSum(apexPoint, algebra.vectMult(dist/2.0, hyperplane.normal)) apexFigure=spaceCuts.figureFromArea(hyperplanes, apexInnerPoint) vertices=[v for v in f if v.dim == 0] apexVertices=[v for v in apexFigure if v.dim == 0] for f2 in sorted(apexFigure, key=attrgetter('dim')): f2.copy=None if f2.dim==0: for v in vertices: # slow, can be improved if algebra.pointsDist(v.position, f2.position) < 0.0001: f2.copy = v break else: boundary=set() shared=True for f3 in f2.boundary: boundary.add(f3.copy or f3) shared = shared and f3.copy f2.boundary=boundary if shared: f2.copy=figByBoundary[frozenset(boundary)] elif f2.dim==f.dim: newFacets.append(f2) return objFigure.Figure(newFacets)
def cutFigure(figure, hyperplane, reuseCache=False): if not reuseCache: for f in figure: f.cuttingCache=None if figure.cuttingCache: # Already computed return figure.cuttingCache def cache(left, section, right): # Caching before returning if reuseCache: figure.cuttingCache=left,section,right else: # Remove cache for f in figure: del f.cuttingCache return left, section, right if figure.dim == 0: # Vertex dist=hyperplane.orientedDistance(figure.position) if abs(dist)<0.00001: return cache([], [figure], []) elif dist<0: return cache([figure], [], []) else: return cache([], [], [figure]) else: # Edge, face, ... left,middle,right = \ zip(*map(lambda f: cutFigure(f, hyperplane, True), figure.boundary)) left,middle,right = (reduce(lambda a,b: a+b, l) for l in (left,middle,right)) if not right and not left: # All in the hyperplane return cache([], [figure], []) elif not right: # Nothing right return cache([figure], middle, []) elif not left: # Nothing left return cache([], middle, [figure]) elif figure.dim == 1: # Cutting edge diff=algebra.vectDiff(right[0].position, left[0].position) prod=algebra.dotProduct(diff, hyperplane.normal) dist=hyperplane.orientedDistance(left[0].position) vert=Vertex(algebra.vectSum(left[0].position, algebra.vectMult(-dist/prod, diff))) leftEdge=Figure([left[0], vert]) rightEdge=Figure([right[0], vert]) return cache([leftEdge], [vert], [rightEdge]) else: # Cutting face (at least 2-dimensional) middle.sort(key=attrgetter('dim'), reverse=True) for f in figuresIterator(middle): f.used=False section=[] middle2=set() for f in middle: if not f.used: if f.dim == figure.dim-2: middle2.add(f) else: section.append(f) for f2 in f: f2.used=True for f in figuresIterator(middle): del f.used if True: # General case def findComponents(figures, exclude): for f in figures: f.group=None f.groupIndex=None f.groupRank=0 for f2 in f.boundary: f2.groupRank=0 f2.group=None def find(f): f2=f while f.group: f=f.group while f2.group: f3=f2.group f2.group=f f2=f3 return f def union(parent, child): parent=find(parent) child=find(child) if child == parent: return if parent.groupRank>child.groupRank: child.group=parent elif parent.groupRank == child.groupRank: child.group=parent parent.groupRank+=1 else: parent.group=child return for f in figures: for f2 in f.boundary: if not f2 in exclude: union(f, f2) groups=[] for f in figures: g=find(f) if g.groupIndex == None: g.groupIndex=len(groups) groups.append([]) groups[g.groupIndex].append(f) for f in figures: del f.group del f.groupIndex del f.groupRank for f2 in f.boundary: f2.group=None del f2.group f2.groupRank=None del f2.groupRank return groups leftComp=findComponents(left, middle2) rightComp=findComponents(right, middle2) leftComp=[Figure(c) for c in leftComp] rightComp=[Figure(c) for c in rightComp] sectComp=[] for f in leftComp: comp=[set()] for f2 in f.boundary: comp[0] |= f2.boundary & middle2 sectComp.append(comp) f.sect=comp # sectComp=[ [set(vertices)] ] for f in rightComp: f.sect=[] for c in sectComp: m=c.pop() for f in rightComp: comp=[set()] for f2 in f.boundary: comp[0] |= f2.boundary & m c.append(comp) f.sect.append(comp) # sectComp=[ [[set(vertices)]] ] for l in sectComp: for m in l: m.append(Figure(m.pop())) section.append(m[0]) for f in leftComp+rightComp: for f2 in f.sect: f.addToBoundary(f2[0]) del f.sect else: # Convex only newSect=Figure(middle2) leftComp=[Figure(left + [newSect])] rightComp=[Figure(right + [newSect])] section.append(newSect) return cache(leftComp, section, rightComp)