From afe0450dc230ec432d75c260f96f80b8badff22e Mon Sep 17 00:00:00 2001 From: Csaba Nagy Date: Sat, 18 Nov 2017 23:11:58 +0100 Subject: [PATCH 1/5] extrude_along_path: close the generated polyhedron if start and end points are identical --- solid/utils.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/solid/utils.py b/solid/utils.py index 66097960..517cb3f6 100755 --- a/solid/utils.py +++ b/solid/utils.py @@ -1111,6 +1111,9 @@ def extrude_along_path(shape_pts, path_pts, scale_factors=None): src_up = Vector3(*UP_VEC) + closed_path = path_pts[0] == path_pts[len(path_pts) - 1] + if closed_path: + path_pts = path_pts[:-1] for which_loop in range(len(path_pts)): path_pt = path_pts[which_loop] scale = scale_factors[which_loop] @@ -1153,17 +1156,25 @@ def extrude_along_path(shape_pts, path_pts, scale_factors=None): facet_indices.append([i + 1, i + shape_pt_count, i + shape_pt_count + 1]) facet_indices.append([segment_start, segment_end, segment_end + shape_pt_count]) facet_indices.append([segment_start, segment_end + shape_pt_count, segment_start + shape_pt_count]) - - # Cap the start of the polyhedron - for i in range(1, shape_pt_count - 1): - facet_indices.append([0, i, i + 1]) - - # And the end (could be rolled into the earlier loop) - # FIXME: concave cross-sections will cause this end-capping algorithm - # to fail - end_cap_base = len(polyhedron_pts) - shape_pt_count - for i in range(end_cap_base + 1, len(polyhedron_pts) - 1): - facet_indices.append([end_cap_base, i + 1, i]) + elif closed_path: + for i in range(shape_pt_count - 1): + facet_indices.append([segment_start + i, i, segment_start + i + 1]) + facet_indices.append([segment_start + i + 1, i, i + 1]) + facet_indices.append([segment_start, segment_end, shape_pt_count - 1]) + facet_indices.append([segment_start, shape_pt_count - 1, 0]) + + if not closed_path: + # only add caps for non-closed paths + # Cap the start of the polyhedron + for i in range(1, shape_pt_count - 1): + facet_indices.append([0, i, i + 1]) + + # And the end (could be rolled into the earlier loop) + # FIXME: concave cross-sections will cause this end-capping algorithm + # to fail + end_cap_base = len(polyhedron_pts) - shape_pt_count + for i in range(end_cap_base + 1, len(polyhedron_pts) - 1): + facet_indices.append([end_cap_base, i + 1, i]) return polyhedron(points=euc_to_arr(polyhedron_pts), faces=facet_indices) From c9c3915870fd2139bac8a6b0cd25a68c12d4710a Mon Sep 17 00:00:00 2001 From: Csaba Nagy Date: Sat, 18 Nov 2017 23:26:32 +0100 Subject: [PATCH 2/5] workaround for calling included functions --- solid/objects.py | 5 ++++- solid/solidpython.py | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/solid/objects.py b/solid/objects.py index 5149f243..3b3f536b 100644 --- a/solid/objects.py +++ b/solid/objects.py @@ -15,7 +15,10 @@ class polygon(OpenSCADObject): ''' def __init__(self, points, paths=None): if not paths: - paths = [list(range(len(points)))] + if isinstance(points, OpenSCADObject): + paths = [] + else: + paths = [list(range(len(points)))] OpenSCADObject.__init__(self, 'polygon', {'points': points, 'paths': paths}) diff --git a/solid/solidpython.py b/solid/solidpython.py index f7a8fb22..7c184e65 100755 --- a/solid/solidpython.py +++ b/solid/solidpython.py @@ -613,6 +613,8 @@ def _get_include_path(self, include_file_path): from . import objects def py2openscad(o): + if isinstance(o, OpenSCADObject): + return o._render()[:-1] if type(o) == bool: return str(o).lower() if type(o) == float: From 59bd36f1a07d389fd38184cfd0d7a2725136890f Mon Sep 17 00:00:00 2001 From: Csaba Nagy Date: Sat, 18 Nov 2017 23:40:27 +0100 Subject: [PATCH 3/5] added save_python_wrapper function --- solid/objects.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/solid/objects.py b/solid/objects.py index 3b3f536b..e6d72f89 100644 --- a/solid/objects.py +++ b/solid/objects.py @@ -1,6 +1,8 @@ """ Classes for OpenSCAD builtins """ +import sys + from .solidpython import OpenSCADObject from .solidpython import IncludedOpenSCADObject @@ -645,3 +647,35 @@ def use(scad_file_path, use_not_include=True): def include(scad_file_path): return use(scad_file_path, use_not_include=False) + + +def save_python_wrapper(scad_file_path, use_not_include=True, py_file_path=None): + ''' + Opens scad_file_path, parses it for all usable calls, + and saves them to the python file to be imported. + This is mainly useful for generating python interface for external libraries + which won't change too often, and include them statically to support IDE auto-completion. + ''' + # These functions in solidpython are used here and only here; don't pollute + # the global namespace with them + from .solidpython import extract_callable_signatures + from .solidpython import new_openscad_class_str + from .solidpython import calling_module + + try: + with open(scad_file_path) as module: + contents = module.read() + except Exception as e: + raise Exception("Failed to import SCAD module '%(scad_file_path)s' " + "with error: %(e)s " % vars()) + + # Once we have a list of all callables and arguments, save them to a python file to be imported. + symbols_dicts = extract_callable_signatures(scad_file_path) + + out = open(py_file_path, "w") if py_file_path else sys.stdout + out.write("import solid\n") + for sd in symbols_dicts: + class_str = new_openscad_class_str(sd['name'], sd['args'], sd['kwargs'], + scad_file_path, use_not_include) + out.write(class_str.replace("import solid\n", "")) + return True From 9d68870511df7e6e6fca434119f1dee0041e5264 Mon Sep 17 00:00:00 2001 From: Csaba Nagy Date: Sun, 19 Nov 2017 19:35:42 +0100 Subject: [PATCH 4/5] extrude along path: fix tangents when using closed path --- solid/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/solid/utils.py b/solid/utils.py index 517cb3f6..3b08a18f 100755 --- a/solid/utils.py +++ b/solid/utils.py @@ -1126,6 +1126,8 @@ def extrude_along_path(shape_pts, path_pts, scale_factors=None): v_prev = path_pt - prev_pt v_next = next_pt - path_pt tangent = v_prev + v_next + elif closed_path: + tangent = path_pts[(which_loop + 1) % len(path_pts)] - path_pts[(which_loop - 1) % len(path_pts)] elif which_loop == 0: tangent = path_pts[which_loop + 1] - path_pt elif which_loop == len(path_pts) - 1: From 766c3efd1b0dcabcb2576d96ffb45c320b01d6e9 Mon Sep 17 00:00:00 2001 From: Csaba Nagy Date: Thu, 31 Oct 2019 15:14:19 +0100 Subject: [PATCH 5/5] added convexity parameter to utils.py/extrude_along_path --- solid/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/solid/utils.py b/solid/utils.py index 3b08a18f..eec59158 100755 --- a/solid/utils.py +++ b/solid/utils.py @@ -1090,7 +1090,7 @@ def fillet_2d(three_point_sets, orig_poly, fillet_rad, remove_material=True): # = Extrusion along a path = # = ---------------------- = # Possible: twist - def extrude_along_path(shape_pts, path_pts, scale_factors=None): + def extrude_along_path(shape_pts, path_pts, scale_factors=None, convexity=10): # Extrude the convex curve defined by shape_pts along path_pts. # -- For predictable results, shape_pts must be planar, convex, and lie # in the XY plane centered around the origin. @@ -1178,7 +1178,7 @@ def extrude_along_path(shape_pts, path_pts, scale_factors=None): for i in range(end_cap_base + 1, len(polyhedron_pts) - 1): facet_indices.append([end_cap_base, i + 1, i]) - return polyhedron(points=euc_to_arr(polyhedron_pts), faces=facet_indices) + return polyhedron(points=euc_to_arr(polyhedron_pts), faces=facet_indices, convexity=convexity) except Exception as e: