def test_strings(): c = drawcontext.DrawContext("testfont", ".", 8, 8) c.setStrokeColorRGB(1, 0, 0) drawStringToDrawContext(c, FEZ_STR, fontS2, bdggeom.Vec2f(0.5, 0.5), 0.05) drawStringToDrawContext(c, TV_STR, fontS2, bdggeom.Vec2f(0.5, 1.0), 0.05) drawStringToDrawContext(c, WALTZ_STR, fontS2, bdggeom.Vec2f(0.5, 1.5), 0.05) drawStringToDrawContext(c, SPHINX_STR, fontS2, bdggeom.Vec2f(0.5, 2.0), 0.05) drawStringToDrawContext(c, JUG_STR, fontS2, bdggeom.Vec2f(0.5, 2.5), 0.05) drawStringToDrawContext(c, MAZE_STR, fontS2, bdggeom.Vec2f(0.5, 3.0), 0.05) drawStringToDrawContext(c, HOME_STR, fontS2, bdggeom.Vec2f(0.5, 3.5), 0.05) drawStringToDrawContext(c, PYTHAG_STR, fontS2, bdggeom.Vec2f(0.5, 4.0), 0.05) drawStringToDrawContext(c, MULT_STR, fontS2, bdggeom.Vec2f(0.5, 4.5), 0.05) c.save()
def drawDebugTransformedToCanvas(self, c): p = c.beginPath() ptCvt0 = self.grid.indexToWorld(*self.points[0]) cvtVec0 = bdggeom.Vec2f(*ptCvt0) transformed0 = self.transformMatrix.mulVec(cvtVec0) p.moveTo(transformed0.x, transformed0.y) for pt in self.points[1:]: ptCvt = self.grid.indexToWorld(*pt) cvtVec = bdggeom.Vec2f(*ptCvt) transformed = self.transformMatrix.mulVec(cvtVec) p.lineTo(transformed.x, transformed.y) p.lineTo(transformed0.x, transformed0.y) c.drawPath(p)
def drawColoredPieceToCanvas(self, drawContext, color): drawContext.setFillColorRGB(*color) p = drawContext.beginPath() ptCvt0 = self.grid.indexToWorld(*self.points[0]) cvtVec0 = bdggeom.Vec2f(*ptCvt0) transformed0 = self.transformMatrix.mulVec(cvtVec0) p.moveTo(transformed0.x, transformed0.y) for pt in self.points[1:]: ptCvt = self.grid.indexToWorld(*pt) cvtVec = bdggeom.Vec2f(*ptCvt) transformed = self.transformMatrix.mulVec(cvtVec) p.lineTo(transformed.x, transformed.y) p.lineTo(transformed0.x, transformed0.y) drawContext.drawFilledPath(p)
def invertMatrix(self, wx, wy): worldVec = bdggeom.Vec2f(wx, wy) localVec = self.worldToGridTransform.mulVec(worldVec) wx = localVec.x wy = localVec.y #wx = ix * self.bases[0].x + iy * self.bases[1].x #wy = ix * self.bases[0].y + iy * self.bases[1].y #wx = ix * A + iy * B #wy = ix * C + iy * D # if A != 0 # ix = (wx - iy * B) / A # wy = (wx - iy * B) * C / A + iy * D # wy = wx * C - iy * BC/A + iy * D # wy - wx * C = iy * ( D - BC/A) # iy = (wy - wx * C) / (D - BC/A) A = self.bases[0].x B = self.bases[1].x C = self.bases[0].y D = self.bases[1].y if (abs(C) < 0.001): return self.c0snapper(wx, wy) if ((abs(A) > 0.001) and (abs(D-B*C/A) > 0.001)): iy = (wy - wx * C) / (D - B*C/A) ix = (wx - iy * B) / A else: assert(False) return ix, iy
def drawStringToDrawContext(drawContext, string, font, posVec, height): string = string.upper() for ci, char in enumerate(string): x = posVec.x + ci * 3 * height y = posVec.y charVec = bdggeom.Vec2f(x, y) drawLetterToDrawContext(drawContext, char, font, charVec, height)
def collectTransformedVertices(self): vecs = [] for ip in self.points: ptCvt = self.grid.indexToWorld(*ip) cvtVec = bdggeom.Vec2f(*ptCvt) transformed = self.transformMatrix.mulVec(cvtVec) vecs.append(transformed) return vecs
def collectVertices(self): """ transforms self.points by self.transformMatrix, returning a list of vec2fs""" verts = [] for p in self.points: wx, wy = self.grid.indexToWorld(*p) wVec = bdggeom.Vec2f(wx, wy) tVec = self.transformMatrix.mulVec(wVec) verts.append(tVec) return verts
def findClusterCenter(pieces, clusterIndex): centerPoint = bdggeom.Vec2f(0, 0) pieceCount = 0 for p in pieces: if p.clusterIndex == clusterIndex: pieceCount += 1 centerPoint += p.getCenter() if pieceCount == 0: return None return centerPoint * (1.0 / pieceCount)
def makeInverseMatrix(self, grid): # first apply a negative translation by the rotCenter # then apply the rotation # then reverse the rotCenter centerVec = bdggeom.Vec2f(*grid.indexToWorld(*self.rotCenterIndices)) rotRad = 2 * math.pi / self.rotCount negTrans = bdggeom.makeTranslationMatrix(-centerVec.x, -centerVec.y) posTrans = bdggeom.makeTranslationMatrix(centerVec.x, centerVec.y) rotTrans = bdggeom.makeRotationMatrix(-rotRad) return posTrans.mulMat(rotTrans.mulMat(negTrans))
def findCenterOfUnusedPieces(pieces): centroid = bdggeom.Vec2f(0, 0) unusedCount = 0 unusedIndices = getUnusedPieceIndices(pieces) if not unusedIndices: return None for ui in unusedIndices: ur = pieces[ui] urc = ur.getCenter() centroid += urc unusedCount += 1 return centroid * (1.0 / unusedCount)
def makeExactHalfPlanes(puzzleDesc): pwi = puzzleDesc.getPageWidthInches() phi = puzzleDesc.getPageWidthInches() leftHP = halfplane.HalfPlane(bdggeom.Vec2f(0, 0), bdggeom.Vec2f(1, 0)) rightHP = halfplane.HalfPlane(bdggeom.Vec2f(pwi, 0), bdggeom.Vec2f(-1, 0)) bottomHP = halfplane.HalfPlane(bdggeom.Vec2f(0, 0), bdggeom.Vec2f(0, 1)) topHP = halfplane.HalfPlane(bdggeom.Vec2f(0, phi), bdggeom.Vec2f(0, -1)) exactHalfPlanes = [leftHP, rightHP, bottomHP, topHP] return exactHalfPlanes
def collectVertices(triList, tolerance): verts = [] for t in triList: for tv in t.verts: foundDup = False tVec = bdggeom.Vec2f(*tv) fInd = findVecInList(verts, tVec, tolerance) if (fInd == -1): #print "adding",tVec insertVecIntoList(verts, tVec) else: #print "found existing" pass return verts
def makeInnerHalfPlanes(puzzleDesc): bwi = puzzleDesc.getBorderWidthInches() pwi = puzzleDesc.getPageWidthInches() phi = puzzleDesc.getPageWidthInches() leftHP = halfplane.HalfPlane(bdggeom.Vec2f(bwi, 0), bdggeom.Vec2f(1, 0)) rightHP = halfplane.HalfPlane(bdggeom.Vec2f(pwi - bwi, 0), bdggeom.Vec2f(-1, 0)) bottomHP = halfplane.HalfPlane(bdggeom.Vec2f(0, bwi), bdggeom.Vec2f(0, 1)) topHP = halfplane.HalfPlane(bdggeom.Vec2f(0, phi - bwi), bdggeom.Vec2f(0, -1)) innerHalfPlanes = [leftHP, rightHP, bottomHP, topHP] return innerHalfPlanes
def makeClustersWithRelaxation(pieces, numClusters, width, height): seedVertices = {} for clusterIndex in range(1, numClusters + 1): seedVertices[clusterIndex] = bdggeom.Vec2f(random.uniform(0, width), random.uniform(0, height)) TOLERANCE = 0.01 while True: setClustersByProximity(pieces, seedVertices) anyMoved = False for clusterIndex, clusterCenter in seedVertices.iteritems(): newClusterCenter = findClusterCenter(pieces, clusterIndex) if newClusterCenter is None: anyMoved = True continue dist = (clusterCenter - newClusterCenter).magnitude() if dist > TOLERANCE: anyMoved = True #print "cluster {0} moved by {1}".format(clusterIndex, dist) seedVertices[clusterIndex] = newClusterCenter if not anyMoved: return
def render(self): runCount = 1 if self.desc.isLimitedRun(): runCount = self.desc.getLimitedRunCount() for serialNumber in range(1, runCount + 1): if self.desc.isLimitedRun(): runCountStr = str(self.desc.getLimitedRunCount()) runCountDigitCount = len(runCountStr) serialNumberStr = str(serialNumber) while len(serialNumberStr) < runCountDigitCount: serialNumberStr = "0" + serialNumberStr label = "{0} {1}/{2}".format(self.desc.getName(), serialNumberStr, runCountStr) filename = "{0}_{1}_{2}".format(self.desc.getOutputFilename(), serialNumberStr, runCountStr) else: label = self.desc.getName() filename = self.desc.getOutputFilename() drawContext = drawcontext.DrawContext( filename, self.outputdir, self.desc.getPageWidthInches(), self.desc.getPageHeightInches(), self.desc.isPDFEnabled(), self.desc.isSVGEnabled()) # TODO - support drawing strategies DRAW_SINGLE_PIECE = False if DRAW_SINGLE_PIECE: drawSinglePiece(drawContext, self.pieces[0]) DRAW_SURROUND = False if DRAW_SURROUND: centerIndex = len(self.pieces) / 2 drawSinglePiece(drawContext, self.pieces[centerIndex]) for ni in self.pieces[centerIndex].neighborPieces: drawSinglePiece(drawContext, self.pieces[ni]) debugColors = { 0: (0.5, 0.5, 0.5), 1: (1, 0, 0), 2: (0, 1, 0), 3: (0, 0, 1), 4: (0.5, 1, 0), 5: (0, 0.5, 1), 6: (1, 0, 0.5), 7: (1, 0.5, 0), 8: (0, 1, 0.5), 9: (0.5, 0, 1), } # draw colored clusters DRAW_COLORED_CLUSTERS = False if DRAW_COLORED_CLUSTERS: for p in self.pieces: ci = p.clusterIndex if ci not in debugColors: debugColors[ci] = (random.uniform(0.2, 0.8), random.uniform(0.2, 0.8), random.uniform(0.2, 0.8)) p.drawColoredPieceToCanvas(drawContext, debugColors[ci]) #for p in pieces: # p.drawDebugTransformedToCanvas(c) # draw edges DRAW_EDGES = True if DRAW_EDGES: for e, pieceIndices in self.edgeToPieceIndexDictionary.iteritems( ): isCut = False isError = False if len(pieceIndices) == 1: isCut = False isError = True else: if len(pieceIndices) != 2: print "ERROR: found non-2 piece list in drawing edges:", pieceIndices else: p0, p1 = pieceIndices if self.pieces[p0].clusterIndex != self.pieces[ p1].clusterIndex: isCut = True v0, v1 = e edge = (bdggeom.Vec2f(*self.grid.indexToWorld(*v0)), bdggeom.Vec2f(*self.grid.indexToWorld(*v1))) newEdge = clipEdgeToHalfPlaneList(edge, self.exactHalfPlanes) if newEdge is None: continue p = drawContext.beginPath() if isError: drawContext.setStrokeColorRGB(0, 0, 255) elif isCut: drawContext.setStrokeColorRGB(*CUT_COLOR) else: drawContext.setStrokeColorRGB(*ENGRAVE_COLOR) v0, v1 = newEdge if isError: print "WARNING: found edge with one piece", e, pieceIndices p.moveTo(v0.x, v0.y) p.lineTo(v1.x, v1.y) drawContext.drawPath(p) drawBoundingBox(drawContext, 0, 0, self.desc.getPageWidthInches(), self.desc.getPageHeightInches()) drawContext.setStrokeColorRGB(*LABEL_COLOR) DRAW_LABEL = True if DRAW_LABEL: print "drawing label", label font.drawStringToDrawContext(drawContext, label, font.fontS2, bdggeom.Vec2f(0.3, 0.15), 0.04) drawContext.save()
def makeInverseMatrix(self, grid): offsetVec = bdggeom.Vec2f(*grid.indexToWorld(*self.offset)) return bdggeom.makeTranslationMatrix(-offsetVec.x, -offsetVec.y)
def makeTriangularGrid(width): g = Grid(width) g.bases[1] = bdggeom.Vec2f(0.5 * g.unit, math.sin(math.pi / 3) * g.unit) return g
def getCenter(self): cv = bdggeom.Vec2f(0, 0) for v in self.collectTransformedVertices(): cv += v cv *= (1.0 / len(self.points)) return cv
def __init__(self, unit): self.unit = unit self.bases = [bdggeom.Vec2f(unit, 0), bdggeom.Vec2f(0, unit)] self.gridToWorldTransform = bdggeom.makeIdentityMatrix() self.worldToGridTransform = bdggeom.makeIdentityMatrix()
def snappedPairsMatch(self, pair1, pair2): v1 = bdggeom.Vec2f(*pair1) v2 = bdggeom.Vec2f(*pair2) d = (v2 - v1).magnitude() return d < self.unit * 0.1