From 91a948562544f2f913b3cdb945b0bbe58fce2591 Mon Sep 17 00:00:00 2001 From: zeffii Date: Wed, 3 May 2017 21:21:10 +0200 Subject: [PATCH] add class version of cm module --- __init__.py | 2 +- nodes/modifier_change/edges_intersect_mk2.py | 29 ++-- utils/cad_module_class.py | 166 +++++++++++++++++++ 3 files changed, 184 insertions(+), 13 deletions(-) create mode 100644 utils/cad_module_class.py diff --git a/__init__.py b/__init__.py index 53ae791e8..bf034d811 100755 --- a/__init__.py +++ b/__init__.py @@ -84,7 +84,7 @@ core_modules = [ utils_modules = [ # non UI tools - "cad_module", "sv_bmesh_utils", "sv_viewer_utils", "sv_curve_utils", + "cad_module", "cad_module_class", "sv_bmesh_utils", "sv_viewer_utils", "sv_curve_utils", "voronoi", "sv_script", "sv_itertools", "script_importhelper", "csg_core", "csg_geom", "geom", "sv_easing_functions", "snlite_utils", "snlite_importhelper", "context_managers", diff --git a/nodes/modifier_change/edges_intersect_mk2.py b/nodes/modifier_change/edges_intersect_mk2.py index b72eb8f59..38ff9a277 100644 --- a/nodes/modifier_change/edges_intersect_mk2.py +++ b/nodes/modifier_change/edges_intersect_mk2.py @@ -25,7 +25,7 @@ from mathutils.geometry import intersect_line_line as LineIntersect from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode -from sverchok.utils import cad_module as cm +from sverchok.utils.cad_module_class import CAD_ops from sverchok.utils.sv_bmesh_utils import bmesh_from_pydata ''' helpers ''' @@ -40,7 +40,7 @@ def order_points(edge, point_list): return [v1] + point_list + [v2] -def remove_permutations_that_share_a_vertex(bm, permutations): +def remove_permutations_that_share_a_vertex(cm, bm, permutations): ''' Get useful Permutations ''' final_permutations = [] @@ -55,13 +55,13 @@ def remove_permutations_that_share_a_vertex(bm, permutations): return final_permutations -def get_valid_permutations(bm, edge_indices): +def get_valid_permutations(cm, bm, edge_indices): raw_permutations = itertools.permutations(edge_indices, 2) permutations = [r for r in raw_permutations if r[0] < r[1]] - return remove_permutations_that_share_a_vertex(bm, permutations) + return remove_permutations_that_share_a_vertex(cm, bm, permutations) -def can_skip(closest_points, vert_vectors): +def can_skip(cm, closest_points, vert_vectors): '''this checks if the intersection lies on both edges, returns True when criteria are not met, and thus this point can be skipped''' if not closest_points: @@ -73,16 +73,15 @@ def can_skip(closest_points, vert_vectors): # if this distance is larger than than VTX_PRECISION, we can skip it. cpa, cpb = closest_points - return (cpa-cpb).length > cm.CAD_prefs.VTX_PRECISION + return (cpa-cpb).length > cm.VTX_PRECISION -def get_intersection_dictionary(bm, edge_indices): - +def get_intersection_dictionary(cm, bm, edge_indices): bm.verts.ensure_lookup_table() bm.edges.ensure_lookup_table() - permutations = get_valid_permutations(bm, edge_indices) + permutations = get_valid_permutations(cm, bm, edge_indices) k = defaultdict(list) d = defaultdict(list) @@ -94,7 +93,7 @@ def get_intersection_dictionary(bm, edge_indices): points = LineIntersect(*vert_vectors) # some can be skipped. (NaN, None, not on both edges) - if can_skip(points, vert_vectors): + if can_skip(cm, points, vert_vectors): continue # reaches this point only when an intersection happens on both edges. @@ -142,7 +141,8 @@ class SvIntersectEdgesNodeMK2(bpy.types.Node, SverchCustomTreeNode): sv_icon = 'SV_XALL' rm_switch = bpy.props.BoolProperty(update=updateNode) - rm_doubles = bpy.props.FloatProperty(min=0.0, default=0.0001, update=updateNode, step=0.1) + rm_doubles = bpy.props.FloatProperty(min=0.0, default=0.0001, step=0.1, update=updateNode) + epsilon = bpy.props.FloatProperty(min=1.0e-5, default=1.0e-5, step=0.02, update=updateNode) def sv_init(self, context): self.inputs.new('VerticesSocket', 'Verts_in') @@ -159,6 +159,9 @@ class SvIntersectEdgesNodeMK2(bpy.types.Node, SverchCustomTreeNode): r2.enabled = self.rm_switch r2.prop(self, 'rm_doubles', text='delta') + def draw_buttons_ext(self, context, layout): + layout.prop(self, 'epsilon') + def process(self): inputs = self.inputs outputs = self.outputs @@ -177,7 +180,9 @@ class SvIntersectEdgesNodeMK2(bpy.types.Node, SverchCustomTreeNode): for edge in bm.edges: edge.select = True - d = get_intersection_dictionary(bm, edge_indices) + cm = CAD_ops(epsilon=self.epsilon) + + d = get_intersection_dictionary(cm, bm, edge_indices) unselect_nonintersecting(bm, d.keys(), edge_indices) # store non_intersecting edge sequencer diff --git a/utils/cad_module_class.py b/utils/cad_module_class.py new file mode 100644 index 000000000..c48ca3389 --- /dev/null +++ b/utils/cad_module_class.py @@ -0,0 +1,166 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +import bmesh + +from mathutils import Vector +from mathutils.geometry import intersect_line_line as LineIntersect +from mathutils.geometry import intersect_point_line as PtLineIntersect + + + +class CAD_ops(): + + + def __init__(self, epsilon=1.0e-5, threshold=0.0001): + self.VTX_PRECISION = epsilon + self.VTX_DOUBLES_THRSHLD = threshold + + + def point_on_edge(self, p, edge): + ''' + > p: vector + > edge: tuple of 2 vectors + < returns: True / False if a point happens to lie on an edge + ''' + pt, _percent = PtLineIntersect(p, *edge) + on_line = (pt-p).length < self.VTX_PRECISION + return on_line and (0.0 <= _percent <= 1.0) + + + def line_from_edge_intersect(self, edge1, edge2): + ''' + > takes 2 tuples, each tuple contains 2 vectors + - prepares input for sending to intersect_line_line + < returns output of intersect_line_line + ''' + [p1, p2], [p3, p4] = edge1, edge2 + return LineIntersect(p1, p2, p3, p4) + + + def get_intersection(self, edge1, edge2): + ''' + > takes 2 tuples, each tuple contains 2 vectors + < returns the point halfway on line. See intersect_line_line + ''' + line = self.line_from_edge_intersect(edge1, edge2) + return (line[0] + line[1]) / 2 + + + def get_intersection_from_idxs(self, bm, idx1, idx2): + ''' + > takes reference to bm and 2 indices + < returns intersection or None + ''' + p1, p2 = self.coords_tuple_from_edge_idx(bm, idx1) + p3, p4 = self.coords_tuple_from_edge_idx(bm, idx2) + a, b = LineIntersect(p1, p2, p3, p4) + if (a-b).length < self.VTX_PRECISION: + return a + + + def test_coplanar(self, edge1, edge2): + ''' + the line that describes the shortest line between the two edges + would be short if the lines intersect mathematically. If this + line is longer than the VTX_PRECISION then they are either + coplanar or parallel. + ''' + line = self.line_from_edge_intersect(edge1, edge2) + return (line[0]-line[1]).length < self.VTX_PRECISION + + + def closest_idx(self, pt, e): + ''' + > pt: vector + > e: bmesh edge + < returns: returns index of vertex closest to pt. + + if both points in e are equally far from pt, then v1 is returned. + ''' + if isinstance(e, bmesh.types.BMEdge): + ev = e.verts + v1 = ev[0].co + v2 = ev[1].co + distance_test = (v1 - pt).length <= (v2 - pt).length + return ev[0].index if distance_test else ev[1].index + + print("received {0}, check expected input in docstring ".format(e)) + + + def closest_vector(self, pt, e): + ''' + > pt: vector + > e: 2 vector tuple + < returns: + pt, 2 vector tuple: returns closest vector to pt + + if both points in e are equally far from pt, then v1 is returned. + ''' + if isinstance(e, tuple) and all([isinstance(co, Vector) for co in e]): + v1, v2 = e + distance_test = (v1 - pt).length <= (v2 - pt).length + return v1 if distance_test else v2 + + print("received {0}, check expected input in docstring ".format(e)) + + + def coords_tuple_from_edge_idx(self, bm, idx): + ''' bm is a bmesh representation ''' + return tuple(v.co for v in bm.edges[idx].verts) + + + def vectors_from_indices(self, bm, raw_vert_indices): + ''' bm is a bmesh representation ''' + return [bm.verts[i].co for i in raw_vert_indices] + + + def vertex_indices_from_edges_tuple(self, bm, edge_tuple): + ''' + > bm: is a bmesh representation + > edge_tuple: contains two edge indices. + < returns the vertex indices of edge_tuple + ''' + k = lambda v, w: bm.edges[edge_tuple[v]].verts[w].index + return [k(i >> 1, i % 2) for i in range(4)] + + + def num_edges_point_lies_on(self, pt, edges): + ''' returns the number of edges that a point lies on. ''' + res = [self.point_on_edge(pt, edge) for edge in [edges[:2], edges[2:]]] + return len([i for i in res if i]) + + + def find_intersecting_edges(self, bm, pt, idx1, idx2): + ''' + > pt: Vector + > idx1, ix2: edge indices, + < returns the list of edge indices where pt is on those edges + ''' + idxs = [idx1, idx2] + edges = [self.coords_tuple_from_edge_idx(bm, idx) for idx in idxs] + return [idx for edge, idx in zip(edges, idxs) if self.point_on_edge(pt, edge)] + + + def duplicates(self, indices): + return len(set(indices)) < 4 + + + def vert_idxs_from_edge_idx(self, bm, idx): + edge = bm.edges[idx] + return edge.verts[0].index, edge.verts[1].index -- GitLab