diff --git a/extensions/fablabchemnitz/paperfold/paperfold.inx b/extensions/fablabchemnitz/paperfold/paperfold.inx
index d7c4aab3..fbcf899c 100644
--- a/extensions/fablabchemnitz/paperfold/paperfold.inx
+++ b/extensions/fablabchemnitz/paperfold/paperfold.inx
@@ -38,6 +38,7 @@
15
false
true
+ true
diff --git a/extensions/fablabchemnitz/paperfold/paperfold.py b/extensions/fablabchemnitz/paperfold/paperfold.py
index 42ce9f7e..1026981b 100644
--- a/extensions/fablabchemnitz/paperfold/paperfold.py
+++ b/extensions/fablabchemnitz/paperfold/paperfold.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import math
import inkex
+from inkex import Transform, TextElement, Tspan, Color, Circle, PathElement, CubicSuperPath
import tempfile
import os
import random
@@ -8,7 +9,7 @@ import numpy as np
import openmesh as om
import networkx as nx
from lxml import etree
-from inkex import Transform, TextElement, Tspan, Color, Circle
+import copy
"""
Extension for InkScape 1.0
@@ -68,6 +69,8 @@ class Paperfold(inkex.EffectExtension):
# Check if two lines intersect
+
+
def lineIntersection(self, v1, v2, v3, v4, epsilon):
d = (v4[1] - v3[1]) * (v2[0] - v1[0]) - (v4[0] - v3[0]) * (v2[1] - v1[1])
u = (v4[0] - v3[0]) * (v1[1] - v3[1]) - (v4[1] - v3[1]) * (v1[0] - v3[0])
@@ -77,6 +80,8 @@ class Paperfold(inkex.EffectExtension):
return ((0 + epsilon) <= u <= (d - epsilon)) and ((0 + epsilon) <= v <= (d - epsilon))
# Check if a point lies inside a triangle
+
+
def pointInTriangle(self, A, B, C, P, epsilon):
v0 = [C[0] - A[0], C[1] - A[1]]
v1 = [B[0] - A[0], B[1] - A[1]]
@@ -91,6 +96,8 @@ class Paperfold(inkex.EffectExtension):
# Check if two triangles intersect
+
+
def triangleIntersection(self, t1, t2, epsilon):
if self.lineIntersection(t1[0], t1[1], t2[0], t2[1], epsilon): return True
if self.lineIntersection(t1[0], t1[1], t2[0], t2[2], epsilon): return True
@@ -115,6 +122,8 @@ class Paperfold(inkex.EffectExtension):
# Functions for visualisation and output
+
+
def addVisualisationData(self, mesh, unfoldedMesh, originalHalfedges, unfoldedHalfedges, glueNumber, dihedralAngles):
for i in range(3):
dihedralAngles[unfoldedMesh.edge_handle(unfoldedHalfedges[i]).idx()] = round(math.degrees(mesh.calc_dihedral_angle(originalHalfedges[i])), self.options.roundingDigits)
@@ -549,7 +558,7 @@ class Paperfold(inkex.EffectExtension):
vertex1 = mesh.point(mesh.to_vertex_handle(he))
# Write a straight line between the two corners
- line = edgesGroup.add(inkex.PathElement())
+ line = edgesGroup.add(PathElement())
line.set('d', "M {:0.6f},{:0.6f} {:0.6f},{:0.6f}".format(vertex0[0], vertex0[1], vertex1[0], vertex1[1]))
# Colour depending on folding direction
lineStyle = {"fill": "none"}
@@ -656,6 +665,56 @@ class Paperfold(inkex.EffectExtension):
text.delete()
tspan.delete()
+ '''
+ merge cutting edges to single contour. code ripped off from "join path" extension
+ '''
+ if self.options.merge_cut_lines is True:
+ cutEdges = []
+
+ #find all cutting edges - they have to be sorted to build up a clean continuous line
+ for edge in edgesGroup:
+ edge_id = edge.get('id')
+ if "cut-edge-" in edge_id:
+ cutEdges.append(edge)
+
+ #find the cutting edge which starts at the previous cutting edge end point
+ paths = {p.get('id'): self.getPartsFromCubicSuper(CubicSuperPath(p.get('d'))) for p in cutEdges }
+ pathIds = [p.get('id') for p in cutEdges]
+
+ startPathId = pathIds[0]
+ pathIds = self.getArrangedIds(paths, startPathId)
+
+ newParts = []
+ firstElem = None
+ for key in pathIds:
+ parts = paths[key]
+ # ~ parts = getPartsFromCubicSuper(cspath)
+ start = parts[0][0][0]
+ elem = self.svg.getElementById(key)
+
+ if(len(newParts) == 0):
+ newParts += parts[:]
+ firstElem = elem
+ else:
+ if(self.vectCmpWithMargin(start, newParts[-1][-1][-1], margin = .01)):
+ newParts[-1] += parts[0]
+ else:
+ newSeg = [newParts[-1][-1][-1], newParts[-1][-1][-1], start, start]
+ newParts[-1].append(newSeg)
+ newParts[-1] += parts[0]
+
+ if(len(parts) > 1):
+ newParts += parts[1:]
+
+ parent = elem.getparent()
+ parent.remove(elem)
+
+ newElem = copy.copy(firstElem)
+ oldId = firstElem.get('id')
+ newElem.set('d', CubicSuperPath(self.getCubicSuperFromParts(newParts)))
+ newElem.set('id', oldId + '_joined')
+ parent.append(newElem) #insert at the end
+
if len(textFacesGroup) == 0:
textFacesGroup.delete() #delete if empty set
@@ -676,6 +735,90 @@ class Paperfold(inkex.EffectExtension):
inkex.utils.debug(" * Edge angle range: {:0.2f}".format(self.angleRange))
return paperfoldPageGroup
+
+
+ def floatCmpWithMargin(self, float1, float2, margin):
+ return abs(float1 - float2) < margin
+
+
+ def vectCmpWithMargin(self, vect1, vect2, margin):
+ return all(self.floatCmpWithMargin(vect2[i], vect1[i], margin) for i in range(0, len(vect1)))
+
+
+ def getPartsFromCubicSuper(self, cspath):
+ parts = []
+ for subpath in cspath:
+ part = []
+ prevBezPt = None
+ for i, bezierPt in enumerate(subpath):
+ if(prevBezPt != None):
+ seg = [prevBezPt[1], prevBezPt[2], bezierPt[0], bezierPt[1]]
+ part.append(seg)
+ prevBezPt = bezierPt
+ parts.append(part)
+ return parts
+
+
+ def getCubicSuperFromParts(self, parts):
+ cbsuper = []
+ for part in parts:
+ subpath = []
+ lastPt = None
+ pt = None
+ for seg in part:
+ if(pt == None):
+ ptLeft = seg[0]
+ pt = seg[0]
+ ptRight = seg[1]
+ subpath.append([ptLeft, pt, ptRight])
+ ptLeft = seg[2]
+ pt = seg[3]
+ subpath.append([ptLeft, pt, pt])
+ cbsuper.append(subpath)
+ return cbsuper
+
+
+ def getArrangedIds(self, pathMap, startPathId):
+ nextPathId = startPathId
+ orderPathIds = [nextPathId]
+
+ #Arrange in order
+ while(len(orderPathIds) < len(pathMap)):
+ minDist = 9e+100 #A large float
+ closestId = None
+ np = pathMap[nextPathId]
+ npPts = [np[-1][-1][-1]]
+ if(len(orderPathIds) == 1):#compare both the ends for the first path
+ npPts.append(np[0][0][0])
+
+ for key in pathMap:
+ if(key in orderPathIds):
+ continue
+ parts = pathMap[key]
+ start = parts[0][0][0]
+ end = parts[-1][-1][-1]
+
+ for i, npPt in enumerate(npPts):
+ dist = abs(start[0] - npPt[0]) + abs(start[1] - npPt[1])
+ if(dist < minDist):
+ minDist = dist
+ closestId = key
+ dist = abs(end[0] - npPt[0]) + abs(end[1] - npPt[1])
+ if(dist < minDist):
+ minDist = dist
+ pathMap[key] = [[[pts for pts in reversed(seg)] for seg in \
+ reversed(part)] for part in reversed(parts)]
+ closestId = key
+
+ #If start point of the first path is closer reverse its direction
+ if(i > 0 and closestId == key):
+ pathMap[nextPathId] = [[[pts for pts in reversed(seg)] for seg in \
+ reversed(part)] for part in reversed(np)]
+
+ orderPathIds.append(closestId)
+ nextPathId = closestId
+ return orderPathIds
+
def add_arguments(self, pars):
pars.add_argument("--tab")
@@ -704,6 +847,7 @@ class Paperfold(inkex.EffectExtension):
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("--dashes", type=inkex.Boolean, default=True, help="Dashes for cut/coplanar edges")
+ pars.add_argument("--merge_cut_lines", type=inkex.Boolean, default=True, help="Merge cut lines")
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("--colorCutEdges", type=Color, default='255', help="Cut edges")
@@ -714,6 +858,7 @@ class Paperfold(inkex.EffectExtension):
#Post Processing
pars.add_argument("--joineryMode", type=inkex.Boolean, default=False, help="Enable joinery mode")
pars.add_argument("--origamiSimulatorMode", type=inkex.Boolean, default=False, help="Enable origami simulator mode")
+
def effect(self):
if not os.path.exists(self.options.inputfile):
diff --git a/extensions/fablabchemnitz/tab_generator/tab_generator.py b/extensions/fablabchemnitz/tab_generator/tab_generator.py
index fe233d2b..3f93fe29 100644
--- a/extensions/fablabchemnitz/tab_generator/tab_generator.py
+++ b/extensions/fablabchemnitz/tab_generator/tab_generator.py
@@ -531,8 +531,10 @@ class Tabgen(inkex.EffectExtension):
last_letter = 'Z'
savid = elem.get_id()
idmod = 0
- elementPath = Path(elem.path.to_absolute().transform(elem.getparent().composed_transform()))
-
+ parent = elem.getparent()
+ #if parent != self.svg.root:
+ # elem.path.transform = elem.path.transform(parent.composed_transform())
+ elementPath = elem.path.to_non_shorthand().to_absolute()
isClosed = False
raw = elementPath.to_arrays()
if raw[-1][0] == 'Z' or \