Skip to content

Commit

Permalink
Prevention of merge around apse centers.
Browse files Browse the repository at this point in the history
  • Loading branch information
polarkernel committed Jan 4, 2021
1 parent 4f4d671 commit 5139c12
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 14 deletions.
50 changes: 45 additions & 5 deletions bpypolyskel/bpypolyskel.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,6 @@ def get(self):
def getAllEqualDistance(self):
item = heapq.heappop(self.__data)
equalDistanceList = [item]
samePositionList = []
# from top of queue, get all events that have the same distance as the one on top
while self.__data and abs(self.__data[0].distance-item.distance) < 0.001:
queueTop = heapq.heappop(self.__data)
Expand Down Expand Up @@ -541,7 +540,37 @@ def removeGhosts(skeleton):
sinksAltered = True
break

def findClusters(skeleton, candidates, contourVertices, thresh):
def detectApses(outerContour):
import re
# compute cross-product between consecutive edges of outer contour
# set True for angles a, where sin(a) < 0.5 -> 30°
sequence = "".join([ 'L' if abs(p.norm.cross(n.norm))<0.5 else 'H' for p,n in _iterCircularPrevNext(outerContour) ])
# special case, see test_306011654_pescara_pattinodromo
if all([p=='L' for p in sequence]):
return None
N = len(sequence)
# match at least 6 low angles in sequence (assume that the first match is longest)
pattern = re.compile(r"(L){6,}")
# sequence may be circular, like 'LLHHHHHLLLLL'
matches = [r for r in pattern.finditer(sequence+sequence)]
if not matches:
return None

centers = []
# circular overlapping pattern must start in first sequence
nextStart = 0
for apse in matches:
s = apse.span()[0]
if s < N and s >= nextStart:
apseIndices = [ i%len(sequence) for i in range(*apse.span())]
apseVertices = [outerContour[i].p1 for i in apseIndices]
center, R = fitCircle3Points(apseVertices)
centers.append(center)

return centers

def findClusters(skeleton, candidates, contourVertices, edgeContours, thresh):
apseCenters = detectApses(edgeContours[0])
clusters = []
while candidates:
c0 = candidates[0]
Expand All @@ -556,6 +585,19 @@ def findClusters(skeleton, candidates, contourVertices, thresh):
if c in candidates:
candidates.remove(c)
if len(cluster)>1:
# if cluster is near to an apse center, don't merge any nodes
if apseCenters:
isApseCluster = False
for apseCenter in apseCenters:
for node in cluster:
if abs(apseCenter.x-skeleton[node].source.x) + abs(apseCenter.y-skeleton[node].source.y) < 3.0:
isApseCluster = True
break
if isApseCluster:
break
if isApseCluster:
continue

# detect sinks in this cluster, that are contour vertices of the footprint
nrOfContourSinks = 0
contourSinks = []
Expand Down Expand Up @@ -654,7 +696,7 @@ def mergeNodeClusters(skeleton,edgeContours):
hadCluster = False
# find clusters within short range and short height difference
candidates = [c for c in range(len(skeleton))]
clusters = findClusters(skeleton,candidates,contourVertices,smallThresh)
clusters = findClusters(skeleton,candidates,contourVertices,edgeContours,smallThresh)
# check if there are cluster candidates
if not clusters:
break
Expand Down Expand Up @@ -953,8 +995,6 @@ def polygonize(verts, firstVertIndex, numVerts, holesInfo=None, height=0., tan=0
edgeContours.append(holeEdges)
uIndex += numVertsHole

nrOfEdges = len(edges2D)

# compute skeleton
skeleton = skeletonize(edgeContours)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,30 @@
holesInfo = None
firstVertIndex = 20
numPolygonVerts = 20
faces = []

bpypolyskel.debugOutputs["skeleton"] = 1


faces = bpypolyskel.polygonize(verts, firstVertIndex, numPolygonVerts, holesInfo, 0.0, 0.5, None, unitVectors)
@pytest.mark.dependency()
@pytest.mark.timeout(10)
def test_polygonize():
global faces
faces = bpypolyskel.polygonize(verts, firstVertIndex, numPolygonVerts, holesInfo, 0.0, 0.5, None, unitVectors)


# the number of vertices in a face
for face in faces:
assert len(face) >= 3
@pytest.mark.dependency(depends=["test_polygonize"])
def test_numVertsInFace():
for face in faces:
assert len(face) >= 3


# duplications of vertex indices
for face in faces:
assert len(face) == len(set(face))
@pytest.mark.dependency(depends=["test_polygonize"])
def test_duplication():
for face in faces:
assert len(face) == len(set(face))


# edge crossing
assert not bpypolyskel.checkEdgeCrossing(bpypolyskel.debugOutputs["skeleton"])
@pytest.mark.dependency(depends=["test_polygonize"])
def test_edgeCrossing():
assert not bpypolyskel.checkEdgeCrossing(bpypolyskel.debugOutputs["skeleton"])

0 comments on commit 5139c12

Please sign in to comment.