fixed issues in paperfold

This commit is contained in:
leyghisbb 2021-05-10 13:54:23 +02:00
parent 9d6d01f845
commit 89b478fd47
2 changed files with 117 additions and 87 deletions

View File

@ -37,23 +37,27 @@
<param name="fontSize" type="int" min="1" max="100" gui-text="Label font size (%)">15</param> <param name="fontSize" type="int" min="1" max="100" gui-text="Label font size (%)">15</param>
<param name="flipLabels" type="bool" gui-text="Flip labels">false</param> <param name="flipLabels" type="bool" gui-text="Flip labels">false</param>
<param name="dashes" type="bool" gui-text="Dashes for cut/coplanar lines">true</param> <param name="dashes" type="bool" gui-text="Dashes for cut/coplanar lines">true</param>
<param name="saturationsForAngles" type="bool" gui-text="Adjust color saturation for folding edges" gui-description="The larger the angle the darker the color">false</param> <param name="edgeStyle" type="optiongroup" appearance="combo" gui-text="Edge style">
<option value="regular">regular</option>
<option value="saturationsForAngles">saturations for angles</option>
<option value="opacitiesForAngles">opacities for angles</option>
</param>
<param name="separateGluePairsByColor" type="bool" gui-text="Separate glue tab pairs by color" gui-description="Generates random color sets for glue tab pairs">false</param> <param name="separateGluePairsByColor" type="bool" gui-text="Separate glue tab pairs by color" gui-description="Generates random color sets for glue tab pairs">false</param>
<param name="colorValleyCut" type="color" appearance="colorbutton" gui-text="Valley cut edges">255</param> <param name="colorCutEdges" type="color" appearance="colorbutton" gui-text="Cut edges">255</param>
<param name="colorMountainCut" type="color" appearance="colorbutton" gui-text="Mountain cut edges">1968208895</param>
<param name="colorCoplanarEdges" type="color" appearance="colorbutton" gui-text="Coplanar edges">1943148287</param> <param name="colorCoplanarEdges" type="color" appearance="colorbutton" gui-text="Coplanar edges">1943148287</param>
<param name="colorValleyPerforates" type="color" appearance="colorbutton" gui-text="Valley perforation edges">3422552319</param> <param name="colorValleyFolds" type="color" appearance="colorbutton" gui-text="Valley fold edges">3422552319</param>
<param name="colorMountainPerforates" type="color" appearance="colorbutton" gui-text="Mountain perforation edges">879076607</param> <param name="colorMountainFolds" type="color" appearance="colorbutton" gui-text="Mountain fold edges">879076607</param>
</vbox> </vbox>
</hbox> </hbox>
</page> </page>
<page name="tab_postprocessing" gui-text="Post Processing"> <page name="tab_postprocessing" gui-text="Post Processing">
<label appearance="header">Joinery</label> <label appearance="header">Joinery</label>
<label>Joinery only works on ungrouped paths.</label> <label>Joinery is a tool to add interlockings, tabs and other connectors to your edges. It only works on ungrouped paths (flat structure).</label>
<param name="joineryMode" type="bool" gui-text="Enable joinery mode" gui-description="Makes flat file instead creating groups. Guarantees compability for joinery.">false</param> <param name="joineryMode" type="bool" gui-text="Enable joinery mode" gui-description="Makes flat file instead creating groups. Guarantees compability for joinery.">false</param>
<label appearance="url">https://clementzheng.github.io/joinery</label> <label appearance="url">https://clementzheng.github.io/joinery</label>
<label appearance="url">https://www.instructables.com/Joinery-Joints-for-Laser-Cut-Assemblies</label> <label appearance="url">https://www.instructables.com/Joinery-Joints-for-Laser-Cut-Assemblies</label>
<label appearance="header">Origami Simulator</label> <label appearance="header">Origami Simulator</label>
<label>Simulate your foldings in 3D! See Origami Simulator: "File" -> "Design Tips" -> "Importing SVG"</label>
<label appearance="url">https://origamisimulator.org</label> <label appearance="url">https://origamisimulator.org</label>
<label appearance="url">https://github.com/amandaghassaei/OrigamiSimulator</label> <label appearance="url">https://github.com/amandaghassaei/OrigamiSimulator</label>
<param name="origamiSimulatorMode" type="bool" gui-text="Enable origami simulator mode" gui-description="Overwrites styles to be compatible to origami simulator.">false</param> <param name="origamiSimulatorMode" type="bool" gui-text="Enable origami simulator mode" gui-description="Overwrites styles to be compatible to origami simulator.">false</param>

View File

@ -37,17 +37,19 @@ Module licenses
possible import file types -> https://www.graphics.rwth-aachen.de/media/openmesh_static/Documentations/OpenMesh-8.0-Documentation/a04096.html possible import file types -> https://www.graphics.rwth-aachen.de/media/openmesh_static/Documentations/OpenMesh-8.0-Documentation/a04096.html
todo: todo:
- debug coplanar color for edges for some cases
- make angleRange global for complete unfolding (to match glue pairs between multiple unfoldings)
- option to render all triangles in a detached way (overlapping lines/independent) + merge coplanar adjacent triangles to polygons - option to render all triangles in a detached way (overlapping lines/independent) + merge coplanar adjacent triangles to polygons
- write tab and slot generator (like joinery/polyhedra extension) - write tab and slot generator (like joinery/polyhedra extension)
- fstl preview - fstl preview
- origami simulator docu + add support for opacities - fix line: dualGraph.add_edge(face1.idx(), face2.idx(), idx=edge.idx(), weight=edgeweight) # #might fail without throwing any error (silent aborts) ...
- fix line: dualGraph.add_edge(face1.idx(), face2.idx(), idx=edge.idx(), weight=edgeweight) # #might fail without throwing any error ...
""" """
class Unfold(inkex.EffectExtension): class Unfold(inkex.EffectExtension):
angleRangeCalculated = False #set to true after first calculation iteration (needed globally)
minAngle = 0
minAngle = 0
angleRange = 0
# Compute the third point of a triangle when two points and all edge lengths are given # Compute the third point of a triangle when two points and all edge lengths are given
def getThirdPoint(self, v0, v1, l01, l12, l20): def getThirdPoint(self, v0, v1, l01, l12, l20):
v2rotx = (l01 ** 2 + l20 ** 2 - l12 ** 2) / (2 * l01) v2rotx = (l01 ** 2 + l20 ** 2 - l12 ** 2) / (2 * l01)
@ -112,9 +114,9 @@ class Unfold(inkex.EffectExtension):
# Functions for visualisation and output # Functions for visualisation and output
def addVisualisationData(self, mesh, unfoldedMesh, originalHalfedges, unfoldedHalfedges, glueNumber, foldingDirection): def addVisualisationData(self, mesh, unfoldedMesh, originalHalfedges, unfoldedHalfedges, glueNumber, dihedralAngles):
for i in range(3): for i in range(3):
foldingDirection[unfoldedMesh.edge_handle(unfoldedHalfedges[i]).idx()] = round(math.degrees(mesh.calc_dihedral_angle(originalHalfedges[i])), self.options.roundingDigits) dihedralAngles[unfoldedMesh.edge_handle(unfoldedHalfedges[i]).idx()] = round(math.degrees(mesh.calc_dihedral_angle(originalHalfedges[i])), self.options.roundingDigits)
# Information, which edges belong together # Information, which edges belong together
glueNumber[unfoldedMesh.edge_handle(unfoldedHalfedges[i]).idx()] = mesh.edge_handle(originalHalfedges[i]).idx() glueNumber[unfoldedMesh.edge_handle(unfoldedHalfedges[i]).idx()] = mesh.edge_handle(originalHalfedges[i]).idx()
@ -129,8 +131,7 @@ class Unfold(inkex.EffectExtension):
isFoldingEdge = np.zeros(numUnfoldedEdges, dtype=bool) # Indicates whether an edge is folded or cut isFoldingEdge = np.zeros(numUnfoldedEdges, dtype=bool) # Indicates whether an edge is folded or cut
glueNumber = np.empty(numUnfoldedEdges, dtype=int) # Saves with which edge is glued together glueNumber = np.empty(numUnfoldedEdges, dtype=int) # Saves with which edge is glued together
foldingDirection = np.empty(numUnfoldedEdges, dtype=float) # Valley folding or mountain folding dihedralAngles = np.empty(numUnfoldedEdges, dtype=float) # Valley folding or mountain folding
connections = np.empty(numFaces, dtype=int) # Saves which original triangle belongs to the unrolled one connections = np.empty(numFaces, dtype=int) # Saves which original triangle belongs to the unrolled one
# Select the first triangle as desired # Select the first triangle as desired
@ -185,7 +186,21 @@ class Unfold(inkex.EffectExtension):
# Associated triangle in 3D mesh # Associated triangle in 3D mesh
connections[unfoldedFace.idx()] = startingTriangle.idx() connections[unfoldedFace.idx()] = startingTriangle.idx()
# Folding direction and adhesive number # Folding direction and adhesive number
self.addVisualisationData(mesh, unfoldedMesh, originalHalfEdges, unfoldedHalfEdges, glueNumber, foldingDirection) self.addVisualisationData(mesh, unfoldedMesh, originalHalfEdges, unfoldedHalfEdges, glueNumber, dihedralAngles)
if self.angleRangeCalculated is False:
self.minAngle = min(dihedralAngles)
self.maxAngle = max(dihedralAngles)
#sometimes weird large value are returned, like -34345645435464565453356788761029782
if self.minAngle < -180.0:
self.minAngle = -180.0
if self.maxAngle > 180.0:
self.maxAngle = 180.0
self.angleRange = self.maxAngle - self.minAngle
#self.msg(minAngle)
#self.msg(maxAngle)
#self.msg(angleRange)
self.angleRangeCalculated = True
halfEdgeConnections = {firstHalfEdge.idx(): firstUnfoldedHalfEdge.idx(), halfEdgeConnections = {firstHalfEdge.idx(): firstUnfoldedHalfEdge.idx(),
secondHalfEdge.idx(): secondUnfoldedHalfEdge.idx(), secondHalfEdge.idx(): secondUnfoldedHalfEdge.idx(),
@ -243,7 +258,7 @@ class Unfold(inkex.EffectExtension):
isFoldingEdge[unfoldedLastEdge.idx()] = True isFoldingEdge[unfoldedLastEdge.idx()] = True
# Gluing number and folding direction # Gluing number and folding direction
self.addVisualisationData(mesh, unfoldedMesh, originalHalfEdges, unfoldedHalfEdges, glueNumber, foldingDirection) self.addVisualisationData(mesh, unfoldedMesh, originalHalfEdges, unfoldedHalfEdges, glueNumber, dihedralAngles)
# Related page # Related page
connections[newface.idx()] = dualEdge[1] connections[newface.idx()] = dualEdge[1]
@ -252,15 +267,16 @@ class Unfold(inkex.EffectExtension):
for i in range(3): for i in range(3):
halfEdgeConnections[originalHalfEdges[i].idx()] = unfoldedHalfEdges[i].idx() halfEdgeConnections[originalHalfEdges[i].idx()] = unfoldedHalfEdges[i].idx()
return [unfoldedMesh, isFoldingEdge, connections, glueNumber, foldingDirection] return [unfoldedMesh, isFoldingEdge, connections, glueNumber, dihedralAngles]
except Exception as e: except Exception as e:
inkex.utils.debug(str(e))
inkex.utils.debug("Error: model could not be unfolded. Check for:") inkex.utils.debug("Error: model could not be unfolded. Check for:")
inkex.utils.debug(" - watertight model / intact hull") inkex.utils.debug(" - watertight model / intact hull")
inkex.utils.debug(" - duplicated edges or faces") inkex.utils.debug(" - duplicated edges or faces")
inkex.utils.debug(" - detached faces or holes") inkex.utils.debug(" - detached faces or holes")
inkex.utils.debug(" - missing units") inkex.utils.debug(" - missing units")
inkex.utils.debug(" - missing coordinate system") inkex.utils.debug(" - missing coordinate system")
inkex.utils.debug(" - multiple bodies in one file")
inkex.utils.debug("error was: " + str(e))
exit(1) exit(1)
@ -271,7 +287,7 @@ class Unfold(inkex.EffectExtension):
numFaces = mesh.n_faces() numFaces = mesh.n_faces()
if numFaces > self.options.maxNumFaces: if numFaces > self.options.maxNumFaces:
inkex.utils.debug("Aborted. Target STL file has " + str(numFaces) + " faces, but only " + str(maxNumFaces) + " are allowed.") inkex.utils.debug("Aborted. Target STL file has " + str(numFaces) + " faces, but only " + str( self.options.maxNumFaces) + " are allowed.")
exit(1) exit(1)
if self.options.printStats is True: if self.options.printStats is True:
@ -325,7 +341,7 @@ class Unfold(inkex.EffectExtension):
# Unfold the tree # Unfold the tree
fullUnfolding = self.unfoldSpanningTree(mesh, spanningTree) fullUnfolding = self.unfoldSpanningTree(mesh, spanningTree)
[unfoldedMesh, isFoldingEdge, connections, glueNumber, foldingDirection] = fullUnfolding [unfoldedMesh, isFoldingEdge, connections, glueNumber, dihedralAngles] = fullUnfolding
# Resolve the intersections # Resolve the intersections
@ -443,12 +459,11 @@ class Unfold(inkex.EffectExtension):
mesh = unfolding[0] mesh = unfolding[0]
isFoldingEdge = unfolding[1] isFoldingEdge = unfolding[1]
glueNumber = unfolding[3] glueNumber = unfolding[3]
foldingDirection = unfolding[4] dihedralAngles = unfolding[4]
#statistic values #statistic values
gluePairs = 0 gluePairs = 0
mountainCuts = 0 cuts = 0
valleyCuts = 0
coplanarEdges = 0 coplanarEdges = 0
mountainPerforations = 0 mountainPerforations = 0
valleyPerforations = 0 valleyPerforations = 0
@ -463,15 +478,8 @@ class Unfold(inkex.EffectExtension):
dashLength = boxSize * self.options.fontSize / 2000 dashLength = boxSize * self.options.fontSize / 2000
spaceLength = boxSize * self.options.fontSize / 800 spaceLength = boxSize * self.options.fontSize / 800
textDistance = boxSize * self.options.fontSize / 800 textDistance = boxSize * self.options.fontSize / 800
textStrokewidth = boxSize * self.options.fontSize / 3000 textStrokeWidth = boxSize * self.options.fontSize / 3000
fontsize = boxSize * self.options.fontSize / 1000 fontsize = boxSize * self.options.fontSize / 1000
minAngle = min(foldingDirection)
maxAngle = max(foldingDirection)
angleRange = maxAngle - minAngle
#self.msg(minAngle)
#self.msg(maxAngle)
#self.msg(angleRange)
# Grouping # Grouping
uniqueMainId = self.svg.get_unique_id("") uniqueMainId = self.svg.get_unique_id("")
@ -497,30 +505,34 @@ class Unfold(inkex.EffectExtension):
om.write_mesh(os.path.join(self.options.TwoDSTLdir, uniqueMainId + "-paperfold-page.stl"), mesh) om.write_mesh(os.path.join(self.options.TwoDSTLdir, uniqueMainId + "-paperfold-page.stl"), mesh)
#########################################################
# Nmbering triangle faces with circle around
#########################################################
if self.options.printTriangleNumbers is True: if self.options.printTriangleNumbers is True:
for face in mesh.faces(): for face in mesh.faces():
centroid = mesh.calc_face_centroid(face) centroid = mesh.calc_face_centroid(face)
textFaceGroup = inkex.Group(id=uniqueMainId + "-textFace-" + str(face.idx())) textFaceGroup = inkex.Group(id=uniqueMainId + "-textFace-" + str(face.idx()))
circle = textFaceGroup.add(Circle(cx=str(centroid[0]), cy=str(centroid[1]), r=str(fontsize))) circle = textFaceGroup.add(Circle(cx=str(centroid[0]), cy=str(centroid[1]), r=str(fontsize)))
circle.set('id', uniqueMainId + "-textFaceCricle-" + str(face.idx())) circle.set('id', uniqueMainId + "-textFaceCricle-" + str(face.idx()))
circle.set("style", "stroke:#000000;stroke-width:" + str(strokewidth/2) + ";fill:none") circle.set("style", "stroke:#000000;stroke-width {:0.6f}".format(strokewidth/2) + ";fill:none")
text = textFaceGroup.add(TextElement(id=uniqueMainId + "-textFaceNumber-" + str(face.idx()))) text = textFaceGroup.add(TextElement(id=uniqueMainId + "-textFaceNumber-" + str(face.idx())))
text.set("x", str(centroid[0])) text.set("x", str(centroid[0]))
text.set("y", str(centroid[1] + fontsize / 3)) text.set("y", str(centroid[1] + fontsize / 3))
text.set("font-size", str(fontsize)) text.set("font-size", str(fontsize))
text.set("style", "stroke-width:" + str(textStrokewidth) + ";text-anchor:middle;text-align:center") text.set("style", "stroke-width {:0.6f}".format(textStrokeWidth) + ";text-anchor:middle;text-align:center")
tspan = text.add(Tspan(id=uniqueMainId + "-textFaceNumberTspan-" + str(face.idx()))) tspan = text.add(Tspan(id=uniqueMainId + "-textFaceNumberTspan-" + str(face.idx())))
tspan.set("x", str(centroid[0])) tspan.set("x", str(centroid[0]))
tspan.set("y", str(centroid[1] + fontsize / 3)) tspan.set("y", str(centroid[1] + fontsize / 3))
tspan.set("style", "stroke-width:" + str(textStrokewidth) + ";text-anchor:middle;text-align:center") tspan.set("style", "stroke-width {:0.6f}".format(textStrokeWidth) + ";text-anchor:middle;text-align:center")
tspan.text = str(face.idx()) tspan.text = str(face.idx())
textFacesGroup.append(textFaceGroup) textFacesGroup.append(textFaceGroup)
#########################################################
# Nmbering triangle edges and style them according to their type
#########################################################
# Go over all edges of the grid # Go over all edges of the grid
for edge in mesh.edges(): for edge in mesh.edges():
# The two endpoints # The two endpoints
@ -534,46 +546,34 @@ class Unfold(inkex.EffectExtension):
# Colour depending on folding direction # Colour depending on folding direction
lineStyle = {"fill": "none"} lineStyle = {"fill": "none"}
dihedralAngle = foldingDirection[edge.idx()] lineStyle.update({"stroke": self.options.colorCutEdges})
line.set("id", uniqueMainId + "-cut-edge-" + str(edge.idx()))
if dihedralAngle > 0:
lineStyle.update({"stroke": self.options.colorMountainCut})
line.set("id", uniqueMainId + "-mountain-cut-" + str(edge.idx()))
mountainCuts += 1
elif dihedralAngle < 0:
lineStyle.update({"stroke": self.options.colorValleyCut})
line.set("id", uniqueMainId + "-valley-cut-" + str(edge.idx()))
valleyCuts += 1
elif dihedralAngle == 0:
lineStyle.update({"stroke": self.options.colorCoplanarEdges})
line.set("id", uniqueMainId + "-coplanar-edge-" + str(edge.idx()))
#if self.options.importCoplanarEdges is False:
# line.delete()
coplanarEdges += 1
lineStyle.update({"stroke-width":str(strokewidth)}) lineStyle.update({"stroke-width": "{:0.6f}".format(strokewidth)})
lineStyle.update({"stroke-linecap":"butt"}) lineStyle.update({"stroke-linecap":"butt"})
lineStyle.update({"stroke-linejoin":"miter"}) lineStyle.update({"stroke-linejoin":"miter"})
lineStyle.update({"stroke-miterlimit":"4"}) lineStyle.update({"stroke-miterlimit":"4"})
dihedralAngle = dihedralAngles[edge.idx()]
# Dotted lines for folding edges # Dotted lines for folding edges
if isFoldingEdge[edge.idx()]: if isFoldingEdge[edge.idx()]:
if self.options.dashes is True: if self.options.dashes is True:
lineStyle.update({"stroke-dasharray":(str(dashLength) + ", " + str(spaceLength))}) lineStyle.update({"stroke-dasharray":(str(dashLength) + ", " + str(spaceLength))})
if dihedralAngle > 0: if dihedralAngle > 0:
lineStyle.update({"stroke": self.options.colorMountainPerforates}) lineStyle.update({"stroke": self.options.colorMountainFolds})
line.set("id", uniqueMainId + "-mountain-perforate-" + str(edge.idx())) line.set("id", uniqueMainId + "-mountain-fold-" + str(edge.idx()))
mountainPerforations += 1 mountainPerforations += 1
if dihedralAngle < 0: if dihedralAngle < 0:
lineStyle.update({"stroke": self.options.colorValleyPerforates}) lineStyle.update({"stroke": self.options.colorValleyFolds})
line.set("id", uniqueMainId + "-valley-perforate-" + str(edge.idx())) line.set("id", uniqueMainId + "-valley-fold-" + str(edge.idx()))
valleyPerforations += 1 valleyPerforations += 1
if dihedralAngle == 0: if dihedralAngle == 0:
lineStyle.update({"stroke": self.options.colorCoplanarEdges}) lineStyle.update({"stroke": self.options.colorCoplanarEdges})
line.set("id", uniqueMainId + "-coplanar-edge-" + str(edge.idx())) line.set("id", uniqueMainId + "-coplanar-edge-" + str(edge.idx()))
if self.options.importCoplanarEdges is False: if self.options.importCoplanarEdges is False:
line.delete() line.delete()
valleyPerforations += 1 coplanarEdges += 1
else: else:
lineStyle.update({"stroke-dasharray":"none"}) lineStyle.update({"stroke-dasharray":"none"})
@ -583,21 +583,26 @@ class Unfold(inkex.EffectExtension):
lineStyle.update({"stroke": randomColorSet[glueNumber[edge.idx()]]}) lineStyle.update({"stroke": randomColorSet[glueNumber[edge.idx()]]})
gluePairs += 1 gluePairs += 1
lineStyle.update({"stroke-dashoffset":"0"}) lineStyle.update({"stroke-dashoffset":"0.0"})
lineStyle.update({"stroke-opacity":"1"}) lineStyle.update({"stroke-opacity":"1.0"})
if self.options.saturationsForAngles is True: if self.options.edgeStyle == "saturationsForAngles":
if dihedralAngle != 0: #we dont want to apply HSL adjustments for zero angle lines because they would be invisible then if dihedralAngle != 0: #we dont want to apply HSL adjustments for zero angle lines because they would be invisible then
hslColor = inkex.Color(lineStyle.get('stroke')).to_hsl() hslColor = inkex.Color(lineStyle.get('stroke')).to_hsl()
newSaturation = abs(dihedralAngle / angleRange) * 100 #percentage values newSaturation = abs(dihedralAngle / self.angleRange) * 100 #percentage values
hslColor.saturation = newSaturation hslColor.saturation = newSaturation
lineStyle.update({"stroke":hslColor.to_rgb()}) lineStyle.update({"stroke":hslColor.to_rgb()})
elif self.options.edgeStyle == "opacitiesForAngles":
if dihedralAngle != 0: #we dont want to apply opacity adjustments for zero angle lines because they would be invisible then
opacity = abs(dihedralAngle / 180)
lineStyle.update({"stroke-opacity": "{:0.6f}".format(opacity)})
line.style = lineStyle line.style = lineStyle
######################################################## #########################################################
# Textual things # Textual things
######################################################## #########################################################
halfEdge = mesh.halfedge_handle(edge, 0) # Find halfedge in the face halfEdge = mesh.halfedge_handle(edge, 0) # Find halfedge in the face
if mesh.face_handle(halfEdge).idx() == -1: if mesh.face_handle(halfEdge).idx() == -1:
halfEdge = mesh.opposite_halfedge_handle(halfEdge) halfEdge = mesh.opposite_halfedge_handle(halfEdge)
@ -618,13 +623,13 @@ class Unfold(inkex.EffectExtension):
text.set("x", str(position[0])) text.set("x", str(position[0]))
text.set("y", str(position[1])) text.set("y", str(position[1]))
text.set("font-size", str(fontsize)) text.set("font-size", str(fontsize))
text.set("style", "stroke-width:" + str(textStrokewidth) + ";text-anchor:middle;text-align:center") text.set("style", "stroke-width {:0.6f}".format(textStrokeWidth) + ";text-anchor:middle;text-align:center")
text.set("transform", "rotate(" + str(rotation) + "," + str(position[0]) + "," + str(position[1]) + ")") text.set("transform", "rotate(" + str(rotation) + "," + str(position[0]) + "," + str(position[1]) + ")")
tspan = text.add(Tspan()) tspan = text.add(Tspan())
tspan.set("x", str(position[0])) tspan.set("x", str(position[0]))
tspan.set("y", str(position[1])) tspan.set("y", str(position[1]))
tspan.set("style", "stroke-width:" + str(textStrokewidth) + ";text-anchor:middle;text-align:center") tspan.set("style", "stroke-width {:0.6f}".format(textStrokeWidth) + ";text-anchor:middle;text-align:center")
tspanText = [] tspanText = []
if self.options.printGluePairNumbers is True and not isFoldingEdge[edge.idx()]: if self.options.printGluePairNumbers is True and not isFoldingEdge[edge.idx()]:
tspanText.append(str(glueNumber[edge.idx()])) tspanText.append(str(glueNumber[edge.idx()]))
@ -653,15 +658,14 @@ class Unfold(inkex.EffectExtension):
textGroup.delete() #delete if empty set textGroup.delete() #delete if empty set
if self.options.printStats is True: if self.options.printStats is True:
inkex.utils.debug(" * Number of mountain cuts: " + str(mountainCuts)) inkex.utils.debug(" * Number of cuts: " + str(cuts))
inkex.utils.debug(" * Number of valley cuts: " + str(valleyCuts))
inkex.utils.debug(" * Number of coplanar edges: " + str(coplanarEdges)) inkex.utils.debug(" * Number of coplanar edges: " + str(coplanarEdges))
inkex.utils.debug(" * Number of mountain perforations: " + str(mountainPerforations)) inkex.utils.debug(" * Number of mountain folds: " + str(mountainPerforations))
inkex.utils.debug(" * Number of valley perforations: " + str(valleyPerforations)) inkex.utils.debug(" * Number of valley folds: " + str(valleyPerforations))
inkex.utils.debug(" * Number of glue pairs: {:0.0f}".format(gluePairs / 2)) inkex.utils.debug(" * Number of glue pairs: {:0.0f}".format(gluePairs / 2))
inkex.utils.debug(" * min angle: {:0.2f}".format(minAngle)) inkex.utils.debug(" * min angle: {:0.2f}".format(self.minAngle))
inkex.utils.debug(" * max angle: {:0.2f}".format(maxAngle)) inkex.utils.debug(" * max angle: {:0.2f}".format(self.maxAngle))
inkex.utils.debug(" * Edge angle range: {:0.2f}".format(angleRange)) inkex.utils.debug(" * Edge angle range: {:0.2f}".format(self.angleRange))
return paperfoldPageGroup return paperfoldPageGroup
@ -691,13 +695,12 @@ class Unfold(inkex.EffectExtension):
pars.add_argument("--fontSize", type=int, default=15, help="Label font size (%)") pars.add_argument("--fontSize", type=int, default=15, help="Label font size (%)")
pars.add_argument("--flipLabels", type=inkex.Boolean, default=False, help="Flip labels") pars.add_argument("--flipLabels", type=inkex.Boolean, default=False, help="Flip labels")
pars.add_argument("--dashes", type=inkex.Boolean, default=True, help="Dashes for cut/coplanar edges") pars.add_argument("--dashes", type=inkex.Boolean, default=True, help="Dashes for cut/coplanar edges")
pars.add_argument("--saturationsForAngles", type=inkex.Boolean, help="Adjust color saturation for folding edges. The larger the angle the darker the color") pars.add_argument("--edgeStyle", help="Adjust color saturation or opacity for folding edges. The larger the angle the darker the color")
pars.add_argument("--separateGluePairsByColor", type=inkex.Boolean, default=False, help="Separate glue pairs by color") pars.add_argument("--separateGluePairsByColor", type=inkex.Boolean, default=False, help="Separate glue pairs by color")
pars.add_argument("--colorValleyCut", type=Color, default='255', help="Valley cut edges") pars.add_argument("--colorCutEdges", type=Color, default='255', help="Cut edges")
pars.add_argument("--colorMountainCut", type=Color, default='1968208895', help="Mountain cut edges")
pars.add_argument("--colorCoplanarEdges", type=Color, default='1943148287', help="Coplanar edges") pars.add_argument("--colorCoplanarEdges", type=Color, default='1943148287', help="Coplanar edges")
pars.add_argument("--colorValleyPerforates", type=Color, default='3422552319', help="Valley perforation edges") pars.add_argument("--colorValleyFolds", type=Color, default='3422552319', help="Valley fold edges")
pars.add_argument("--colorMountainPerforates", type=Color, default='879076607', help="Mountain perforation edges") pars.add_argument("--colorMountainFolds", type=Color, default='879076607', help="Mountain fold edges")
#Post Processing #Post Processing
pars.add_argument("--joineryMode", type=inkex.Boolean, default=False, help="Enable joinery mode") pars.add_argument("--joineryMode", type=inkex.Boolean, default=False, help="Enable joinery mode")
@ -737,18 +740,41 @@ class Unfold(inkex.EffectExtension):
if newColor not in randomColorSet: if newColor not in randomColorSet:
randomColorSet.append(newColor) randomColorSet.append(newColor)
#some mode configs: #########################################################
# mode config for joinery:
#########################################################
if self.options.joineryMode is True: if self.options.joineryMode is True:
self.options.separateGluePairsByColor = True #we need random colors in this mode self.options.separateGluePairsByColor = True #we need random colors in this mode
#########################################################
# mode config for origami simulator:
#########################################################
'''
required style for Origami Simulator:
colors:
- #ff0000 (red) - mountain folds
- #0000ff (blue) - valley folds
- #000000 (black) - boundary cuts (for both the outline of the pattern and any internal holes)
- #ffff00 (yellow) - coplonar triangle edges ("facet creases") (no support for polygons > 3 edges)
- #00ff00 (green) - thin slits
- #ff00ff (magenta) - undriven creases (swing freely)
opacity:
- final fold angle of a mountain or valley fold is set by its opacity. Any fold angle between 0° and 180° may be used. For example:
- 1.0 = 180° (fully folded)
- 0.5 = 90°
- 0 = 0° (flat)
'''
if self.options.origamiSimulatorMode is True: if self.options.origamiSimulatorMode is True:
self.options.joineryMode = True #we set to true even if false because we need the same flat structure for origami simulator self.options.joineryMode = True #we set to true even if false because we need the same flat structure for origami simulator
self.options.separateGluePairsByColor = False #we need to have no weird random colors in this mode self.options.separateGluePairsByColor = False #we need to have no weird random colors in this mode
self.options.colorMountainCut = "#000000" #black self.options.edgeStyle = "opacitiesForAngles" #highly important for simulation
self.options.colorValleyCut = "#000000" #black self.options.importCoplanarEdges = True
self.options.colorCoplanarEdges = "#000000" #black self.options.colorCutEdges = "#000000" #black
self.options.colorMountainPerforates = "#ff0000" #red self.options.colorCoplanarEdges = "#ffff00" #yellow
self.options.colorValleyPerforates = "#0000ff" #blue self.options.colorMountainFolds = "#ff0000" #red
self.options.colorValleyFolds = "#0000ff" #blue
# Create a new container group to attach all paperfolds # Create a new container group to attach all paperfolds
paperfoldMainGroup = self.document.getroot().add(inkex.Group(id=self.svg.get_unique_id("paperfold-"))) #make a new group at root level paperfoldMainGroup = self.document.getroot().add(inkex.Group(id=self.svg.get_unique_id("paperfold-"))) #make a new group at root level