From 7562d3ee0616486e33c77afe6260a159fde8fa5a Mon Sep 17 00:00:00 2001
From: mehtank <mehtank@mehtank.com>
Date: Sat, 16 May 2020 02:02:01 +0000
Subject: [PATCH] Revert "Removed legacy Joint code"

This reverts commit 3eb8a0e81d1ba8818a944e915482a162066f0902.
---
 svggen/api/composables/GraphComposable.py |  2 +
 svggen/api/composables/graph/Drawing.py   |  2 +
 svggen/api/composables/graph/Face.py      | 28 +++++--
 svggen/api/composables/graph/Graph.py     | 18 ++++-
 svggen/api/composables/graph/HyperEdge.py | 25 +++++-
 svggen/api/composables/graph/Joint.py     | 96 +++++++++++++++++++++++
 6 files changed, 160 insertions(+), 11 deletions(-)
 create mode 100644 svggen/api/composables/graph/Joint.py

diff --git a/svggen/api/composables/GraphComposable.py b/svggen/api/composables/GraphComposable.py
index 8f38db7..d8502d9 100644
--- a/svggen/api/composables/GraphComposable.py
+++ b/svggen/api/composables/GraphComposable.py
@@ -88,6 +88,8 @@ class Graph(Composable, BaseGraph):
         from svggen.utils.tabs import BeamTabs, BeamTabDecoration, BeamSlotDecoration
         self.tabify(kw("tabFace", BeamTabs), kw("tabDecoration", BeamTabDecoration),
                     kw("slotFace", None), kw("slotDecoration", BeamSlotDecoration))
+        if kw("joint", None):
+            self.jointify(**kwargs)
         self.place()
 
     '''
diff --git a/svggen/api/composables/graph/Drawing.py b/svggen/api/composables/graph/Drawing.py
index 0edf901..b132363 100644
--- a/svggen/api/composables/graph/Drawing.py
+++ b/svggen/api/composables/graph/Drawing.py
@@ -49,6 +49,8 @@ class Drawing:
                         angle = angles[1][0] - angles[0][0]
                     if angle == 0:
                         edge = Flat()
+                    elif e.edgeType is "BEND":
+                        edge = Flex(angle=angle)
                     else:
                         edge = Fold(angle=angle)
                 else:
diff --git a/svggen/api/composables/graph/Face.py b/svggen/api/composables/graph/Face.py
index d693661..286183b 100644
--- a/svggen/api/composables/graph/Face.py
+++ b/svggen/api/composables/graph/Face.py
@@ -246,7 +246,8 @@ class Face(object):
     coords2D = self.get2DCoords()
     coords3D = self.get3DCoords()
 
-    for (i, e) in enumerate(self.edges):
+    # Follow all non-joints before joints
+    for (i, e) in sorted(enumerate(self.edges), key=lambda x : x[1].isJoint()):
       # XXX hack: don't follow small edges
       if e is None or e.isTab():
         continue
@@ -280,10 +281,13 @@ class Face(object):
 
         x = RotateXTo(ptb, pta)
 
-        r2d = np.eye(4)
-        r2d = np.dot(x, r2d)
-        r2d = np.dot(MoveOriginTo(pta), r2d)
-        t2d = np.dot(transform2D, r2d)
+        if e.isJoint():
+            t2d = None
+        else:
+            r2d = np.eye(4)
+            r2d = np.dot(x, r2d)
+            r2d = np.dot(MoveOriginTo(pta), r2d)
+            t2d = np.dot(transform2D, r2d)
 
         r3d = RotateX(np.deg2rad(a[0]+da[0]))
         r3d = np.dot(x, r3d)
@@ -293,6 +297,17 @@ class Face(object):
         f.place(e, t2d, t3d, facelists, flind)
         # end for faces.iteritems
 
+    for e in self.edges:
+        if e.isJoint():
+            index = self.edgeIndex(e.name)
+            # print "Jointing ", e.name, "on face", self.name, index
+            newPts, newEdges = e.joint.go(self, e)
+	    self.pts2d[index:index] = newPts                                         
+	    self.edges[index:index+1] = newEdges                                     
+	    for newEdge in newEdges:                                                 
+		newEdge.join(newEdge.length, self)                                   
+            e.remove(self)
+
     self.placeagain()
 
   def getTriangleDict(self):
@@ -330,8 +345,7 @@ class Face(object):
             name = self.name + ".d%d.e%d" % (i,j)
             pt1 = np.dot(self.transform2D, np.array(list(e[0][j-1]) + [0,1]))[0:2]
             pt2 = np.dot(self.transform2D, np.array(list(e[0][j]) + [0,1]))[0:2]
-            # XXX use EdgeType appropriately 
-            # ??? deleted EdgeType
+            # XXX use EdgeType appropriately
             edges.append([name, pt1, pt2, 1])
         else:
           name = self.name + ".d%d" % i
diff --git a/svggen/api/composables/graph/Graph.py b/svggen/api/composables/graph/Graph.py
index 8940286..ffe397e 100644
--- a/svggen/api/composables/graph/Graph.py
+++ b/svggen/api/composables/graph/Graph.py
@@ -83,13 +83,13 @@ class Graph():
     self.rebuildEdges()
     return self
 
-  def attachFace(self, fromEdge, newFace, newEdge, prefix=None, angle=0):
+  def attachFace(self, fromEdge, newFace, newEdge, prefix=None, angle=0, edgeType=None, joints=None):
     # XXX should set angle from a face, not absolute angle of the face
     self.addFace(newFace, prefix)
 
     if fromEdge is not None:
       newEdge = prefixString(prefix, newEdge)
-      self.mergeEdge(fromEdge, newEdge, angle=angle)
+      self.mergeEdge(fromEdge, newEdge, angle=angle, edgeType=edgeType, joints=joints)
 
   def delFace(self, facename):
     for (i, f) in enumerate(self.faces):
@@ -140,7 +140,7 @@ class Graph():
   def addTab(self, edge1, edge2, angle=0, width=10):
     self.mergeEdge(edge1, edge2, angle=angle, tabWidth=width)
 
-  def mergeEdge(self, edge1, edge2, angle=0, tabWidth=None, swap=False):
+  def mergeEdge(self, edge1, edge2, angle=0, tabWidth=None, edgeType=None, joints=None, swap=False):
     e1 = self.getEdge(edge1)
     e2 = self.getEdge(edge2)
     if e1 is None:
@@ -161,6 +161,11 @@ class Graph():
       e2.mergeWith(e1, angle=angle, flip=True, tabWidth=tabWidth)
     self.edges.remove(e1)
     
+    e2.setType(edgeType)
+    if joints:
+        for joint in joints.joints:
+            e2.addJoint(joint)
+
     return self
 
   def splitEdge(self, edge):
@@ -181,6 +186,13 @@ class Graph():
     self.rebuildEdges()
     return new_edges_and_faces
 
+  def jointify(self, **kwargs):
+    for e in self.edges:
+        if e.isNotFlat() and "joint" in kwargs:
+            e.setType("JOINT")
+            e.addJoint(kwargs["joint"])
+            #print "jointing ", e.name
+
   def tabify(self, tabFace=None, tabDecoration=None, slotFace=None, slotDecoration=None, **kwargs):
     for e in self.edges:
       if e.isTab():
diff --git a/svggen/api/composables/graph/HyperEdge.py b/svggen/api/composables/graph/HyperEdge.py
index 1d5e81f..a6c09e8 100644
--- a/svggen/api/composables/graph/HyperEdge.py
+++ b/svggen/api/composables/graph/HyperEdge.py
@@ -3,6 +3,9 @@ from svggen.utils import mymath as np
 
 class HyperEdge:
 
+  #ANDYTODO: transform these into sublclasses of HyperEdge and/or componenet
+  edgeTypes = ["FOLD", "BEND", "JOINT"]
+
   @staticmethod
   def edge(allEdges, name, length, face, angle=0, flip=False):
     if allEdges is not None:
@@ -25,6 +28,8 @@ class HyperEdge:
     self.tabWidth = None
     self.pts2D = None
     self.pts3D = None
+    self.edgeType = "FOLD"
+    self.joint = None
 
     #self.pt1 = pt1
     #self.pt2 = pt2
@@ -45,11 +50,15 @@ class HyperEdge:
     self.name = name
 
   def isNotFlat(self):
-    return any((x[0] for x in self.faces.values()))
+    return self.edgeType is "JOINT" or \
+        (self.edgeType is "FOLD" and any((x[0] for x in self.faces.values())))
 
   def isTab(self):
     return self.tabWidth is not None
 
+  def isJoint(self):
+    return self.edgeType is "JOINT" and self.joint is not None
+
   def setAngle(self, face, angle, flip=False):
     if face in self.faces:
       self.faces[face] = (angle, flip)
@@ -136,6 +145,20 @@ class HyperEdge:
     self.pts2D = pts2D
     self.pts3D = pts3D
     
+  def setType(self, edgeType):
+    if edgeType is None:
+        return # do nothing
+    if edgeType not in self.edgeTypes:
+        raise Exception("Invalid edge type!")
+    self.edgeType = edgeType
+    
+  def addJoint(self, joint):
+    if not self.edgeType is "JOINT":
+        raise Exception("Trying to add joints to a non-joint edge")
+    # if not isinstance(joint, Joint.Joint):
+        # raise Exception("Not a joint!")
+    self.joint = joint
+
   def __eq__(self, other):
     return self.name == other.name
 
diff --git a/svggen/api/composables/graph/Joint.py b/svggen/api/composables/graph/Joint.py
new file mode 100644
index 0000000..3c410a1
--- /dev/null
+++ b/svggen/api/composables/graph/Joint.py
@@ -0,0 +1,96 @@
+from svggen.api.composables.graph.HyperEdge import HyperEdge
+import svggen.utils.mymath as np
+
+class Joint:
+    def __init__(self, **kwargs):
+        self.kwargs = kwargs
+    def go(face, edge):
+        pass
+
+class FingerJoint(Joint):
+    def go(self, face, edge):
+        inset = False
+        edgename = face.name + edge.name
+        index = face.edgeIndex(edge.name)                                       
+        angle, flip = edge.faces[face]
+
+        thickness = self.kwargs["thickness"]
+
+        coords = face.edgeCoords(index)
+        length = face.edgeLength(index) 
+        if inset:
+            length -= thickness
+
+        pt1 = np.array(coords[0])
+        pt2 = np.array(coords[1])
+
+        n = int(max(3, round(length * 1.0 / thickness))) # number of fingers
+        dt = length * 1.0 / n                # actual thickness of fingers
+        dlp = thickness / 2. 
+        dln = thickness / 2. # Only works for 90deg angles; np.sqrt(2) max
+        dl = dlp + dln # actual length of fingers
+
+        flip = flip and (n % 2 == 1)
+
+        dpt = (pt2 - pt1) * 1.0 * dt / face.edgeLength(index)
+        ppt = np.array((dpt[1], -dpt[0])) / dt
+
+        newEdges = []
+        newPts = []
+        newPt = coords[0]
+
+        def addNew(newEdge, newPt):
+            newEdges.append(newEdge)
+            newPts.append(newPt)
+            newEdge.join(newEdge.length, face)
+
+        if inset:
+        # inset from the edge for 3 face corners
+            newPt = newPt - ppt * dln
+            newEdge = HyperEdge(edgename + "fjx1", dln)
+            addNew(newEdge, newPt)
+
+            newPt = newPt + dpt * thickness / dt / 2.0
+            newEdge = HyperEdge(edgename + "fjx2", dt)
+            addNew(newEdge, newPt)
+
+            newPt = newPt + ppt * dln
+            newEdge = HyperEdge(edgename + "fjx3", dln)
+            addNew(newEdge, newPt)
+
+        if flip:
+            newPt = newPt + ppt * dlp
+            newEdge = HyperEdge(edgename + "fj0", dlp)
+        else:
+            newPt = newPt - ppt * dln
+            newEdge = HyperEdge(edgename + "fj0", dln)
+            
+
+        for i in range(int(n)):
+            addNew(newEdge, newPt)
+
+            newPt = newPt + dpt 
+            newEdge = HyperEdge(edgename + "fjd%d" % i, dt)
+            addNew(newEdge, newPt)
+
+            if flip:
+                newPt = newPt - ppt * dl
+            else:
+                newPt = newPt + ppt * dl
+            newEdge = HyperEdge(edgename + "fjp%d" % i, dl)
+            flip = not flip
+
+        if not flip:
+            addNew(newEdge, newPt)
+        else:
+            newPt = newPt - ppt * dl
+
+        if inset:
+            newPt = newPt + dpt * thickness / dt / 2.0
+            newEdge = HyperEdge(edgename + "fjy", dt)
+            addNew(newEdge, newPt)
+
+        newEdge = HyperEdge(edgename + "fjn", dln)
+        newEdges.append(newEdge)
+
+        return newPts, newEdges
-- 
GitLab