fixed issues in paperfold
This commit is contained in:
parent
9d6d01f845
commit
89b478fd47
@ -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>
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user