def _pointInHole(polygon, level = 2): sl = geomap.scanPoly(polygon) for y in range(sl.startIndex(), sl.endIndex()): inside = 0 x = 0 for seg in sl[y]: if inside and x < seg.begin: return Vector2(x, y) x = seg.end inside += seg.direction result = geomap.centroid(polygon) if polygon.contains(result): return result result = [] bbox = polygon.boundingBox() midPoint = (bbox.begin() + bbox.end())/2 xRange = numpy.arange(bbox.begin()[0], bbox.end()[0], 1.0/level) for y in numpy.arange(bbox.begin()[1], bbox.end()[1], 1.0/level): for x in xRange: p = Vector2(x, y) if polygon.contains(p): result.append((squaredNorm(p-midPoint), p)) if not result: return _pointInHole(polygon, level+1) result.sort() return result[0][1]
def offset(freemanCodes, pointIndex, closed = True): if closed: pointIndex = pointIndex % len(freemanCodes) dsl, ofs = geomap.tangentDSL(freemanCodes, pointIndex, closed) if not ofs: return Vector2(0, 0) fc1 = freemanCodes[pointIndex - ofs] count = len(freemanCodes) for crackIndex in range(pointIndex - ofs + 1, pointIndex + ofs): fc2 = freemanCodes[crackIndex % count] if fc2 != fc1: break q = quadrant(fc1, fc2) alpha = (2.*dsl.pos+dsl.b-1)/(2*dsl.b) if q == 0: return Vector2( alpha, -alpha) elif q == 1: return Vector2(-alpha, -alpha) elif q == 2: return Vector2(-alpha, alpha) else: return Vector2( alpha, alpha)
def kochCurve(level=5): result = Polygon() p0 = Vector2(-0.5, -math.sqrt(1. / 12)) result.append(p0) p1 = p0 + Vector2(_kochCos, _kochSin) result.append(p1) p2 = p1 + Vector2(_kochCos, -_kochSin) result.append(p2) result.append(p0) for i in range(level): result = _kochIteration(result) return result
def _kochIteration(poly): result = Polygon() for i in range(len(poly) - 1): segment = poly[i + 1] - poly[i] smaller = segment / 3 left = Vector2(smaller[0] * _kochCos - smaller[1] * _kochSin, smaller[0] * _kochSin + smaller[1] * _kochCos) right = Vector2(smaller[0] * _kochCos + smaller[1] * _kochSin, -smaller[0] * _kochSin + smaller[1] * _kochCos) p1 = poly[i] + smaller p2 = p1 + left p3 = p2 + right result.append(poly[i]) result.append(p1) result.append(p2) result.append(p3) result.append(result[0]) return result
def rectifiedJunctionNodePosition(chords): """Defition of node position for junction triangles from rectified CAT article. Not as good as the original definition for triangles, but works for other polygons, too.""" totalWeights = 0.0 result = Vector2(0, 0) for chord in chords: weight = chord.edge().length() result += middlePoint(chord) * weight totalWeights += weight return result / totalWeights
def offset2(freemanCodes, pointIndex, closed = True): """My own derivation of the necessary offset(), perpendicular to the tangent - gives different, but nearly indistinguishable results. The RMSE of the points' radii in the circle example from __main__ is 0.4 percent lower, so this is the default / used in euclideanPath. ;-)""" if closed: pointIndex = pointIndex % len(freemanCodes) dsl, ofs = crackEdgeTangent(freemanCodes, pointIndex, closed) cp = Rational(2*dsl.pos+dsl.width()-1, 2*(sq(dsl.a) + sq(dsl.b))) return Vector2(float(dsl.a*cp), float(-dsl.b*cp))
def circumCircle(p1, p2, p3): """circumCircle(p1, p2, p3) -> (Vector2, float) Returns the center and radius of the circumcircle of the given three points.""" p1sm = squaredNorm(p1) x1 = p1[0] y1 = p1[1] p2sm = squaredNorm(p2) x2 = p2[0] y2 = p2[1] p3sm = squaredNorm(p3) x3 = p3[0] y3 = p3[1] a = numpy.linalg.det( numpy.array([[x1, y1, 1], [x2, y2, 1], [x3, y3, 1]])) d = numpy.linalg.det( -numpy.array([[p1sm, y1, 1], [p2sm, y2, 1], [p3sm, y3, 1]])) e = numpy.linalg.det( numpy.array([[p1sm, x1, 1], [p2sm, x2, 1], [p3sm, x3, 1]])) f = numpy.linalg.det( -numpy.array([[p1sm, x1, y1], [p2sm, x2, y2], [p3sm, x3, y3]])) circumCenter = Vector2(-d/(2*a), -e/(2*a)) denom = 4*math.sq(a) - f/a circumRadius2 = (math.sq(d) + math.sq(e)) / (4*math.sq(a)) - f/a if circumRadius2 > 0: circumRadius = math.sqrt(circumRadius2) else: lengths = [(p2-p1).magnitude(), (p3-p2).magnitude(), (p1-p3).magnitude()] lengths.sort() circumRadius = (lengths[1] + lengths[2]) / 4.0 sys.stderr.write("circumcircle: side lengths^2 are %s -> improvised radius = %s\n" % (lengths, circumRadius)) return circumCenter, circumRadius
def pruneByMorphologicalSignificance(skel, ratio = 0.1): for edge in skel.edgeIter(): edge.setFlag(IS_BARB, False) if edge.startNode().hasDegree(1): edge.setFlag(IS_BARB, True) endSide = edge.endSide[0]-edge.endSide[1] minDist = ratio * numpy.linalg.norm(endSide) endNormal = Vector2(endSide[1], -endSide[0]) endNormal /= numpy.linalg.norm(endNormal) for p in edge: if abs(dot(p - edge[-1], endNormal)) > minDist: edge.setFlag(IS_BARB, False) break if edge.flag(IS_BARB): continue # no need to test other side if edge.endNode().hasDegree(1): edge.setFlag(IS_BARB, True) startSide = edge.startSide[0]-edge.startSide[1] minDist = ratio * max(1.0, numpy.linalg.norm(startSide)) startNormal = Vector2(startSide[1], -startSide[0]) startNormal /= numpy.linalg.norm(startNormal) for p in edge: if abs(dot(p - edge[0], startNormal)) > minDist: edge.setFlag(IS_BARB, False) break return _pruneBarbsInternal(skel)
import Gnuplot def gpLine(points, with_ = "lines", **kwargs): return Gnuplot.Data(points, with_ = with_, **kwargs) g = Gnuplot.Gnuplot() g("set size ratio -1") ep = [p + offset(fc, i) for i, p in enumerate(list(crackPoly)[:-1])] ep.append(ep[0]) ep2 = [p + offset2(fc, i) for i, p in enumerate(list(crackPoly)[:-1])] ep2.append(ep2[0]) g.plot(gpLine(crackPoly), gpLine(ep), gpLine(ep2)) g2 = Gnuplot.Gnuplot() g2.plot([norm(p-Vector2(25,25))-20 for p in ep], [norm(p-Vector2(25,25))-20 for p in ep2]) # tangents = [tangentDSL(fc, i, True)[0] for i in range(len(fc))] # g.plot(gpLine(tangentList(ep, 1), "lp"), # gpLine([atan2(t.b, t.a)+math.pi/2 for t in tangents], "lp")) # e = DSLExperiment(True) # for code in [1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1]: # if not e(code): # break # print "code %s -> %s" % (code, e.dsl) # index = 43 # print "debugging %d:" % index # dsl, ofs = tangentDSL(fc, index, True)
# print "%d edges were deleted (e.g. at image border)." % ( # len(map.deleted), ) # if hasattr(map, "unsortable") and map.unsortable: # print "%d unsortable groups of edges occured." % ( # len(map.unsortable), ) # if hasattr(map, "unembeddableContours") and map.unembeddableContours: # print "%d outer contours could not be embedded into " \ # "their surrounding faces!" % (len(map.unembeddableContours), ) # -------------------------------------------------------------------- print "- creating empty GeoMap..." tm = geomap.GeoMap([], [], Size2D(256, 256)) points = geomap.Vector2Array([ Vector2(232.20846246994, 81.488755298170375), Vector2(228.16750125077627, 81.481533365106415), Vector2(224.94552025882538, 81.580691309124461) ]) n1 = tm.addNode(points[0]) n2 = tm.addNode(points[-1]) print "- endnodes %d and %d created." % (n1.label(), n2.label()) print "- adding edge..." edge = tm.addEdge(n1, n2, points) print "- testing DartPointIter..." dart = tm.dart(-edge.label()) for i, p in enumerate(dart): assert p == dart[i]