diff --git a/rocolib/api/composables/GraphComposable.py b/rocolib/api/composables/GraphComposable.py index 43fd99ec5da3162c381c143377dae0dd9628cbc7..6dbd00b2a1a97f21b96b0cfbe4a0442278508141 100644 --- a/rocolib/api/composables/GraphComposable.py +++ b/rocolib/api/composables/GraphComposable.py @@ -47,7 +47,7 @@ class GraphComposable(Composable, BaseGraph): return Composable.makeOutput(self, name, outputs, filedir, widgets, **ka) def to2D(self, fp, **ka): - if ka.get("mode", "") in "Corel print animate".split(): + if ka.get("mode", "") in "printer laser animate".split(): return self.d.toSVG(fp, mode=ka.get("mode")) else: return self.d.toDXF(fp, mode=ka.get("mode", "silhouette")) @@ -61,10 +61,10 @@ class GraphComposable(Composable, BaseGraph): from rocolib.utils.roco2sim.wbo_nodes import wboConverter fp.write(wboConverter(self.meshes)) - corelOut = output("corel.svg", "Corel cut-and-fold pattern", mode="Corel") (to2D) - printOut = output("printer.svg", "cut pattern for printing", mode="print") (to2D) - animOut = output("animate.svg", "input for OrigamiSimulator", mode="animate") (to2D) + printOut = output("printer.svg", "manual cut pattern folding printouts", mode="printer") (to2D) + laserOut = output("laser.svg", "laser cutter cut-and-fold pattern", mode="laser") (to2D) cutOut = output("silhouette.dxf", "Silhouette cut-and-fold pattern", mode="silhouette")(to2D) + animOut = output("animate.svg", "input for OrigamiSimulator", mode="animate") (to2D) autoOut = output("autofold.dxf", "autofolding pattern", mode="autofold") (to2D) stlOut = output("model.stl", "3D STL model", binary=True, format="stl") (to3D) diff --git a/rocolib/api/composables/graph/Drawing.py b/rocolib/api/composables/graph/Drawing.py index 7c5e9ea068701609a3e94358305a3ddc2a3b8063..33e7d421700e31b52873b344e50624222d271ca7 100644 --- a/rocolib/api/composables/graph/Drawing.py +++ b/rocolib/api/composables/graph/Drawing.py @@ -107,8 +107,30 @@ class Drawing: svg = svgwrite.Drawing(None, size=('%fmm' % dx, '%fmm' % dy), viewBox=('%f %f %f %f' % (minx, miny, dx, dy))) + lines = {} for e in list(self.edges.items()): - e[1].toDrawing(svg, e[0] if labels else "", mode) + try: + pts, kwargs = e[1].toDrawing(svg, e[0] if labels else "", mode, drawLine=False) + kw = "".join((f"{k}{v}" for k,v in sorted(kwargs.items()))) + lines[kw] = lines.get(kw, []) + [(pts, kwargs)] + except TypeError: + pass + for line in lines.values(): + pts = [list(x[0]) for x in line] + kwargs = line[0][1] + lp = len(pts) + for j, pt2 in enumerate(reversed(pts)): + for i, pt1 in enumerate(pts): + start = pt1[-1] + end = pt2[0] + dist = (start[0]-end[0])**2 + (start[1]-end[1])**2 + if dist<1e-2 and pt2 != pt1: + pt1.extend(pt2[1:]) + pts.pop(lp-j-1) + break + kwargs["style"] = "fill:none;" + kwargs.get("style", "") + for pt in pts: + svg.add(svg.polyline(pt, **kwargs)) svg.write(fp, pretty=True) def points(self): diff --git a/rocolib/api/composables/graph/DrawingEdge.py b/rocolib/api/composables/graph/DrawingEdge.py index 25d041316de639decd79bda8825845323698d1e2..95bf59323de5ae9a81aada6dd94c0c6c4f843967 100644 --- a/rocolib/api/composables/graph/DrawingEdge.py +++ b/rocolib/api/composables/graph/DrawingEdge.py @@ -5,17 +5,17 @@ class EdgeType: """ Values for the different modes of Edge instances """ - # ( Name, SVG color, DXF color, Layer name ) - TYPENAME, TYPEFOLD, TYPEDISP, TYPESVG, TYPEDXF, TYPELAYER, TYPEDRAW = list(range(7)) TYPEDATA = ( - ( "REGISTRATION", False, "green", "#00ff00", 6, "reg", True), - ( "BOUNDARY_CUT", False, "black", "#000000", 5, "cut", True), - ( "INTERIOR_CUT", False, "gray", "#888888", 5, "cut", True), - ( "FOLD", True, ("blue", "red"), ("#0000ff", "#ff0000"), (1, 3), "xxx", True), - ( "FLEX", True, ("yellow", "cyan"), ("#00ffff", "#ffff00"), (1, 3), "xxx", False), - ( "FLAT", False, "white", "#ffffff", 3, "nan", False), + ( "REGISTRATION", False, True , "#00ff00", "#00ff00" , 6 , "reg"), + ( "BOUNDARY_CUT", False, True , "#ff0000", "#000000" , 5 , "cut"), + ( "INTERIOR_CUT", False, True , "#ff0000", "#888888" , 5 , "cut"), + ( "FOLD" , True , True , "#0000ff", ("#0000ff", "#ff0000"), (1, 3) , "xxx"), + ( "FLEX" , True , False, "#00ffff", ("#00ffff", "#ffff00"), (1, 3) , "xxx"), + ( "FLAT" , False, False, "#ffff00", "#ffffff" , 3 , "nan"), ) + # ( Name, is fold?, needs to be drawn?, SVG color(s), DXF color(s), Layer name ) + TYPENAME, TYPEFOLD, TYPEDRAW, LASERCOLORS, SVGCOLORS, DXFCOLORS, TYPELAYER = list(range(len(TYPEDATA[0]))) ( REGISTRATION, BOUNDARY_CUT, @@ -46,30 +46,21 @@ class EdgeType: def makeLinetypes(cls, drawing, dxf): drawing.add_linetype("DOTTED", pattern=dxf.linepattern([1, 0, -1])) - def dispColor(self, showFlats = True): - if self.edgetype == self.FLAT and not showFlats: - return None - - if self.typedata[self.TYPEFOLD]: - return self.typedata[self.TYPEDISP][self.angle < 0] - else: - return self.typedata[self.TYPEDISP] - def drawArgs(self, name, mode): if not(self.typedata[self.TYPEDRAW]): return coloridx = 0 - if mode in ("silhouette", "print", "animate") and self.angle < 0: + if mode in ("silhouette", "printer", "animate") and self.angle < 0: coloridx = 1 # DXF output if mode in ("dxf", "silhouette", "autofold"): if self.typedata[self.TYPEFOLD]: ret = {"linetype": "DOTTED", - "color": self.typedata[self.TYPEDXF][coloridx]} + "color": self.typedata[self.DXFCOLORS][coloridx]} else: - ret = {"color": self.typedata[self.TYPEDXF]} + ret = {"color": self.typedata[self.DXFCOLORS]} if mode == "autofold": ret["layer"] = self.typedata[self.TYPELAYER] @@ -81,16 +72,18 @@ class EdgeType: else: ret = {"id" : name} - if self.typedata[self.TYPEFOLD]: - ret = {"stroke": self.typedata[self.TYPESVG][coloridx]} - if mode == "print": - ret["stroke-dasharray"] = "2 6" - ret["stroke-dashoffset"] = "5" + if mode == "laser": + ret = {"stroke": self.typedata[self.LASERCOLORS]} + elif self.typedata[self.TYPEFOLD]: + ret = {"stroke": self.typedata[self.SVGCOLORS][coloridx]} + if mode == "printer": + ret["stroke-dasharray"] = ("4 1 1 1", "1 1")[coloridx] elif mode == "animate": angle = self.angle ret["opacity"] = abs(angle) / 180. else: - ret = {"stroke": self.typedata[self.TYPESVG]} + ret = {"stroke": self.typedata[self.SVGCOLORS]} + ret["stroke-width"] = "0.1mm" return ret @@ -300,10 +293,7 @@ class Edge: midpt = ((pt2[0]+pt1[0])/2, (pt2[1]+pt1[1])/2) return midpt - def dispColor(self, showFlats = True): - return self.edgetype.dispColor(showFlats) - - def toDrawing(self, drawing, label="", mode=None, engine=None): + def toDrawing(self, drawing, label="", mode=None, engine=None, drawLine=True): """ Draws an Edge instance to a CAD file. @@ -318,38 +308,20 @@ class Edge: if engine is None: engine = drawing - kwargs = self.edgetype.drawArgs(self.name, mode) - if kwargs: - - dpi = None - - if mode in ( 'Corel'): - dpi = 96 # scale from mm to 96dpi for CorelDraw - elif mode == 'Inkscape': - dpi = 90 # scale from mm to 90dpi for Inkscape - elif mode == 'autofold': - if str(self.edgetype.angle) not in drawing.layers: - drawing.add_layer(str(self.edgetype.angle)) - - if dpi: self.transform(scale=(dpi/25.4)) - drawing.add(engine.line((float(self.x1), float(self.y1)), (float(self.x2), float(self.y2)), **kwargs)) - if dpi: self.transform(scale=(25.4/dpi)) # scale back to mm - if label: r = [int(self.angle(deg=True))]*len(label) t = engine.text(label, insert=((self.x1+self.x2)/2, (self.y1+self.y2)/2))# , rotate=r) # t.rotate=r drawing.add(t) -if __name__ == "__main__": - import svgwrite - e = Edge("e1", (0,0), (1,1), Flex()) - svg = svgwrite.Drawing("testedge.svg") - e.toDrawing(svg, mode="Inkscape") - svg.save() - - from dxfwrite import DXFEngine as dxf - svg = dxf.drawing("testedge.dxf") - e.toDrawing(svg, mode="dxf", engine=dxf) - svg.save() + kwargs = self.edgetype.drawArgs(self.name, mode) + if kwargs: + if mode == 'autofold': + if str(self.edgetype.angle) not in drawing.layers: + drawing.add_layer(str(self.edgetype.angle)) + pt = ((float(self.x1), float(self.y1)), (float(self.x2), float(self.y2))) + if drawLine: + drawing.add(engine.line(*pt, **kwargs)) + else: + return (pt, kwargs) diff --git a/rocolib/utils/display.py b/rocolib/utils/display.py index d696e8f5c5e04b2eee7e40975e2fe93fe930b3a4..355af0ef87342d15eb263472b6ae8403d03837e8 100644 --- a/rocolib/utils/display.py +++ b/rocolib/utils/display.py @@ -65,10 +65,10 @@ def linestyle(e, **kwargs): if e["interior"]: # Interior decorations width = 1 if e["edgeType"] in ( EdgeType.BOUNDARY_CUT, EdgeType.INTERIOR_CUT ): - color = 'blue' + color = 'red' zorder = 30 elif e["edgeType"] in ( EdgeType.FOLD, EdgeType.FLEX ): - color = 'red' + color = 'blue' zorder = 20 elif e["edgeType"] in ( EdgeType.FLAT ): color = 'white' @@ -77,12 +77,12 @@ def linestyle(e, **kwargs): color = 'gray' zorder = 100 elif e["faces"] == 1: # CUT - color = 'blue' + color = 'red' zorder = 30 elif e["faces"] == 2: # FOLD or FLEX or BEND if angle: # FOLD if angle > 0: # mountain fold - color = 'red' + color = 'blue' zorder = 20 else: # valley fold color = 'green'