fix in paperfold

This commit is contained in:
Mario Voigt 2021-05-06 15:21:10 +02:00
parent 8f7465bb0f
commit 88eb5d0a89
3 changed files with 53 additions and 13 deletions

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
*.pyc
/.project
/.pydevproject
/.nohup.out
*.out
extensions/fablabchemnitz/animate_order/drawing.svg
extensions/fablabchemnitz/animate_order/animate_order.html

View File

@ -5,6 +5,7 @@
<param name="tab" type="notebook">
<page name="tab_settings" gui-text="Paperfold for Inkscape">
<param name="inputfile" type="path" gui-text="Input File" filetypes="obj,off,ply,stl" gui-description="The model to unfold" mode="file">/your/beautiful/3dmodel/file</param>
<param name="maxNumFaces" type="int" min="1" max="99999" gui-text="Maximum allowed faces" gui-description="If the STL file has too much detail it contains a large number of faces. This will make unfolding extremely slow. So we can limit it.">200</param>
<param name="printNumbers" type="bool" gui-text="Print numbers on the cut edges">true</param>
<param name="scalefactor" type="float" precision="3" min="0.0001" max="10000.0" gui-text="Manual scale factor" gui-description="default is 1.0">1.0</param>
<param name="resizetoimport" type="bool" gui-text="Resize the canvas to the imported drawing's bounding box">true</param>
@ -20,6 +21,7 @@
<param name="color_mountain_cut" type="color" appearance="colorbutton" gui-text="Color for mountain cuts">1968208895</param>
<param name="color_valley_perforate" type="color" appearance="colorbutton" gui-text="Color for valley perforations">3422552319</param>
<param name="color_mountain_perforate" type="color" appearance="colorbutton" gui-text="Color for mountain perforations">879076607</param>
<param name="printStats" type="bool" gui-text="Show some unfold statistics">true</param>
</page>
<page name="tab_about" gui-text="About">
<label appearance="header">Paperfold for Inkscape</label>

View File

@ -17,7 +17,7 @@ Paperfold is another flattener for triangle mesh files, heavily based on paperfo
Author: Mario Voigt / FabLab Chemnitz
Mail: mario.voigt@stadtfabrikanten.org
Date: 13.09.2020
Last patch: 13.09.2020
Last patch: 06.05.2021
License: GNU GPL v3
To run this you need to install OpenMesh with python pip.
@ -39,12 +39,11 @@ ToDos:
- Fix bug with canvas resizing. bounding box of paperfoldMainGroup returns unexplainable wrong results. How to update the view to get correct values here?
- Print statistics about
- groups
- triagle count
- edge count per type (valley cut, mountain cut, valley fold, mountain fold)
- remove unrequired extra folding edges on plane surfaces (compare the output from osresearch/papercraft and paperfoldmodels) which should be removed before printing/cutting.
For example take a pentagon - it's face gets divided into three triangles if we put it into a mesh triangulation tool. Means we receive two fold edges which we don't need.
This would create more convenient output like osresearch/papercraft and dxf2papercraft do.
See https://github.com/osresearch/papercraft/blob/master/unfold.c > coplanar_check() method
- remove unrequired extra folding edges on plane surfaces (compare the output from osresearch/papercraft and paperfoldmodels) which should be removed before printing/cutting.
For example take a pentagon - it's face gets divided into three triangles if we put it into a mesh triangulation tool. Means we receive two fold edges which we don't need.
This would create more convenient output like osresearch/papercraft and dxf2papercraft do.
See https://github.com/osresearch/papercraft/blob/master/unfold.c > coplanar_check() method
"""
@ -258,12 +257,24 @@ def unfoldSpanningTree(mesh, spanningTree):
return [unfoldedMesh, isFoldingEdge, connections, glueNumber, foldingDirection]
def unfold(mesh):
def unfold(mesh, maxNumFaces, printStats):
# Calculate the number of surfaces, edges and corners, as well as the length of the longest shortest edge
numEdges = mesh.n_edges()
numVertices = mesh.n_vertices()
numFaces = mesh.n_faces()
if numFaces > maxNumFaces:
inkex.utils.debug("Aborted. Target STL file has " + str(numFaces) + " faces, but " + str(maxNumFaces) + " are allowed.")
exit(1)
if printStats is True:
inkex.utils.debug("Input STL mesh stats:")
inkex.utils.debug("* Number of edges: " + str(numEdges))
inkex.utils.debug("* Number of vertices: " + str(numVertices))
inkex.utils.debug("* Number of faces: " + str(numFaces))
inkex.utils.debug("-----------------------------------------------------------")
# Generate the dual graph of the mesh and calculate the weights
dualGraph = nx.Graph()
@ -423,6 +434,13 @@ def writeSVG(self, unfolding, size, printNumbers):
glueNumber = unfolding[3]
foldingDirection = unfolding[4]
#statistic values
gluePairs = 0
mountainCuts = 0
valleyCuts = 0
mountainPerforations = 0
valleyPerforations = 0
# Calculate the bounding box
[xmin, ymin, boxSize] = findBoundingBox(unfolding[0])
@ -459,10 +477,12 @@ def writeSVG(self, unfolding, size, printNumbers):
if foldingDirection[edge.idx()] > 0:
lineStyle.update({"stroke": self.options.color_mountain_cut})
line.set("id", self.svg.get_unique_id("mountain-cut-"))
mountainCuts += 1
elif foldingDirection[edge.idx()] < 0:
lineStyle.update({"stroke": self.options.color_valley_cut})
line.set("id", self.svg.get_unique_id("valley-cut-"))
valleyCuts += 1
lineStyle.update({"stroke-width":str(strokewidth)})
lineStyle.update({"stroke-linecap":"butt"})
lineStyle.update({"stroke-linejoin":"miter"})
@ -474,9 +494,11 @@ def writeSVG(self, unfolding, size, printNumbers):
if foldingDirection[edge.idx()] > 0:
lineStyle.update({"stroke": self.options.color_mountain_perforate})
line.set("id", self.svg.get_unique_id("mountain-perforate-"))
mountainPerforations += 1
if foldingDirection[edge.idx()] < 0:
lineStyle.update({"stroke": self.options.color_valley_perforate})
line.set("id", self.svg.get_unique_id("valley-perforate-"))
line.set("id", self.svg.get_unique_id("valley-perforate-"))
valleyPerforations += 1
else:
lineStyle.update({"stroke-dasharray":"none"})
@ -513,7 +535,18 @@ def writeSVG(self, unfolding, size, printNumbers):
tspan.set("x", str(position[0]))
tspan.set("y", str(position[1]))
tspan.set("style", "stroke-width:" + str(textStrokewidth))
tspan.text = str(glueNumber[edge.idx()])
tspan.text = str(glueNumber[edge.idx()])
gluePairs += 1
if self.options.printStats is True:
inkex.utils.debug("Folding edges stats: ")
inkex.utils.debug(" * Number of mountain cuts: " + str(mountainCuts))
inkex.utils.debug(" * Number of valley cuts: " + str(valleyCuts))
inkex.utils.debug(" * Number of mountain perforations: " + str(mountainPerforations))
inkex.utils.debug(" * Number of valley perforations: " + str(valleyPerforations))
inkex.utils.debug("-----------------------------------------------------------")
inkex.utils.debug("Number of glue pairs: " + str(gluePairs))
return paperfoldPageGroup
class Unfold(inkex.EffectExtension):
@ -521,6 +554,7 @@ class Unfold(inkex.EffectExtension):
def add_arguments(self, pars):
pars.add_argument("--tab")
pars.add_argument("--inputfile")
pars.add_argument("--maxNumFaces", type=int, default=200, help="If the STL file has too much detail it contains a large number of faces. This will make unfolding extremely slow. So we can limit it.")
pars.add_argument("--printNumbers", type=inkex.Boolean, default=False, help="Print numbers on the cut edges")
pars.add_argument("--scalefactor", type=float, default=1.0, help="Manual scale factor")
pars.add_argument("--resizetoimport", type=inkex.Boolean, default=True, help="Resize the canvas to the imported drawing's bounding box")
@ -530,10 +564,14 @@ class Unfold(inkex.EffectExtension):
pars.add_argument("--color_mountain_cut", type=Color, default='1968208895', help="Color for mountain cuts")
pars.add_argument("--color_valley_perforate", type=Color, default='3422552319', help="Color for valley perforations")
pars.add_argument("--color_mountain_perforate", type=Color, default='879076607', help="Color for mountain perforations")
pars.add_argument("--printStats", type=inkex.Boolean, default=True, help="Show some unfold statistics")
def effect(self):
if not os.path.exists(self.options.inputfile):
inkex.utils.debug("The input file does not exist. Please select a proper file and try again.")
exit(1)
mesh = om.read_trimesh(self.options.inputfile)
fullUnfolded, unfoldedComponents = unfold(mesh)
fullUnfolded, unfoldedComponents = unfold(mesh, self.options.maxNumFaces, self.options.printStats)
# Compute maxSize of the components
# All components must be scaled to the same size as the largest component
maxSize = 0