diff --git a/src/blenderbim/blenderbim/bim/module/cad/__init__.py b/src/blenderbim/blenderbim/bim/module/cad/__init__.py index dd7efcb577..6a32d53c5a 100644 --- a/src/blenderbim/blenderbim/bim/module/cad/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/cad/__init__.py @@ -20,6 +20,7 @@ import bpy from . import operator, workspace classes = ( + operator.AddIfcCircle, operator.CadArcFrom2Points, operator.CadArcFrom3Points, operator.CadFillet, diff --git a/src/blenderbim/blenderbim/bim/module/cad/operator.py b/src/blenderbim/blenderbim/bim/module/cad/operator.py index c380cd3175..fff04a17da 100644 --- a/src/blenderbim/blenderbim/bim/module/cad/operator.py +++ b/src/blenderbim/blenderbim/bim/module/cad/operator.py @@ -343,3 +343,35 @@ class CadArcFrom3Points(bpy.types.Operator): bmesh.update_edit_mesh(mesh) mesh.update() return {"FINISHED"} + + +class AddIfcCircle(bpy.types.Operator): + bl_idname = "bim.add_ifccircle" + bl_label = "Add IfcCircle" + + @classmethod + def poll(cls, context): + obj = context.active_object + return bool(obj) and obj.type == "MESH" + + def execute(self, context): + obj = context.active_object + bpy.ops.object.mode_set(mode="EDIT") + + bm = bmesh.from_edit_mesh(obj.data) + + center = obj.matrix_world.inverted() @ context.scene.cursor.location + radius = 0.5 + + v1 = bm.verts.new((center[0], center[1] + radius, 0.0)) + v2 = bm.verts.new((center[0], center[1] - radius, 0.0)) + bm.verts.index_update() + indices = [v1.index, v2.index] + bm.edges.new((v1, v2)) + bmesh.update_edit_mesh(obj.data) + + bpy.ops.object.mode_set(mode="OBJECT") + group = obj.vertex_groups.new(name="IFCCIRCLE") + group.add(indices, 1, "REPLACE") + bpy.ops.object.mode_set(mode="EDIT") + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/cad/workspace.py b/src/blenderbim/blenderbim/bim/module/cad/workspace.py index f1a39648bb..48322062b2 100644 --- a/src/blenderbim/blenderbim/bim/module/cad/workspace.py +++ b/src/blenderbim/blenderbim/bim/module/cad/workspace.py @@ -41,12 +41,13 @@ class CadTool(WorkSpaceTool): ("bim.cad_fillet", {"type": "F", "value": "PRESS", "shift": True}, {"properties": []}), # Enable Mesh Tools add-on to get this amazing tool ("mesh.offset_edges", {"type": "O", "value": "PRESS", "shift": True}, {"properties": []}), - ("bim.cad_arc_from_2_points", {"type": "C", "value": "PRESS", "shift": True}, {"properties": []}), + ("bim.cad_hotkey", {"type": "C", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_C")]}), ("bim.cad_hotkey", {"type": "V", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_V")]}), ) def draw_settings(context, layout, tool): - if context.active_object.data.BIMMeshProperties.is_profile: + obj = context.active_object + if obj and obj.data and hasattr(obj.data, "BIMMeshProperties") and obj.data.BIMMeshProperties.is_profile: row = layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_Q") @@ -58,6 +59,11 @@ class CadTool(WorkSpaceTool): row.label(text="", icon="EVENT_E") row.operator("bim.hotkey", text="Extend").hotkey = "S_E" + row = layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="", icon="EVENT_C") + row.operator("bim.add_ifccircle", text="Circle") + row = layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_V") @@ -105,6 +111,12 @@ class CadHotkey(bpy.types.Operator): getattr(self, f"hotkey_{self.hotkey}")() return {"FINISHED"} + def hotkey_S_C(self): + if self.is_profile(): + bpy.ops.bim.add_ifccircle() + else: + bpy.ops.bim.cad_arc_from_2_points() + def hotkey_S_E(self): bpy.ops.bim.cad_trim_extend() @@ -115,7 +127,11 @@ class CadHotkey(bpy.types.Operator): bpy.ops.bim.cad_mitre() def hotkey_S_V(self): - if bpy.context.active_object.data.BIMMeshProperties.is_profile: + if self.is_profile(): bpy.ops.bim.set_arc_index() else: bpy.ops.bim.cad_arc_from_3_points() + + def is_profile(self): + obj = bpy.context.active_object + return obj and obj.data and hasattr(obj.data, "BIMMeshProperties") and obj.data.BIMMeshProperties.is_profile diff --git a/src/blenderbim/blenderbim/bim/module/geometry/helper.py b/src/blenderbim/blenderbim/bim/module/geometry/helper.py index 433825fe30..ca00ce06ce 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/helper.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/helper.py @@ -21,7 +21,7 @@ import bmesh import mathutils import ifcopenshell import ifcopenshell.util.unit -from math import pi +from math import pi, pow from mathutils import Vector, Matrix, geometry @@ -113,34 +113,52 @@ class Helper: return {"profile": profile, "extrusion": extrusion} def auto_detect_arbitrary_profile_with_voids(self, obj, mesh): - arc_groups = [] + groups = {"IFCARCINDEX": [], "IFCCIRCLE": []} for i, group in enumerate(obj.vertex_groups): if "IFCARCINDEX" in group.name: - arc_groups.append(i) + groups["IFCARCINDEX"].append(i) + elif "IFCCIRCLE" in group.name: + groups["IFCCIRCLE"].append(i) bm = bmesh.new() bm.from_mesh(mesh) bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=1e-5) + bmesh.ops.delete(bm, geom=bm.faces, context="FACES_ONLY") # https://docs.blender.org/api/blender_python_api_2_63_8/bmesh.html#CustomDataAccess # This is how we access vertex groups via bmesh, apparently, it's not very intuitive deform_layer = bm.verts.layers.deform.active # Sanity check - group_verts = {} + group_verts = {"IFCARCINDEX": {}, "IFCCIRCLE": {}} for vert in bm.verts: - if len(vert.link_edges) != 2: # Unclosed loop or forked loop - return (False, "UNCLOSED_LOOP") total_groups = 0 - for group_index in arc_groups: - if group_index in vert[deform_layer]: - group_verts.setdefault(group_index, []).append(vert) - total_groups += 0 - if total_groups > 1: # A vert can only belong to one arc - return (False, "AMBIGUOUS_ARC") - for verts in group_verts.values(): - if len(verts) != 3: # Each arc needs 3 verts - return (False, "3POINT_ARC") + is_circle = False + for group_type, group_indices in groups.items(): + for group_index in group_indices: + if group_index in vert[deform_layer]: + if group_type == "IFCCIRCLE": + is_circle = True + print('it is a circle') + group_verts[group_type].setdefault(group_index, 0) + group_verts[group_type][group_index] += 1 + total_groups += 0 + if total_groups > 1: # A vert can only belong to one group + return (False, "AMBIGUOUS_SPECIAL_VERTEX") + elif is_circle: + pass # Circles are allowed to be unclosed + elif total_groups == 0 and len(vert.link_edges) != 2: # Unclosed loop or forked loop + return (False, "UNCLOSED_LOOP") + + for group_type, group_counts in group_verts.items(): + if group_type == "IFCARCINDEX": + for group_count in group_counts.values(): + if group_count != 3: # Each arc needs 3 verts + return (False, "3POINT_ARC") + elif group_type == "IFCCIRCLE": + for group_count in group_counts.values(): + if group_count != 2: # Each circle needs 2 verts + return (False, "CIRCLE") loop_edges = set(bm.edges) @@ -172,20 +190,31 @@ class Helper: for loop in loops: loop_vertices = [] total_edges = len(loop) - for i, edge in enumerate(loop): - if i + 1 == total_edges and edge.verts[0] in loop[i - 1].verts: - loop_vertices.append(edge.verts[0]) - elif i + 1 == total_edges and edge.verts[1] in loop[i - 1].verts: - loop_vertices.append(edge.verts[1]) - elif edge.verts[0] in loop[i + 1].verts: - loop_vertices.append(edge.verts[1]) - elif edge.verts[1] in loop[i + 1].verts: - loop_vertices.append(edge.verts[0]) - loop_bm = bmesh.new() - for vert in loop_vertices: - loop_bm.verts.new(vert.co) - face = loop_bm.faces.new(loop_bm.verts) + if total_edges == 1: + loop_vertices = [loop[0].verts[0], loop[0].verts[1]] + else: + for i, edge in enumerate(loop): + if i + 1 == total_edges and edge.verts[0] in loop[i - 1].verts: + loop_vertices.append(edge.verts[0]) + elif i + 1 == total_edges and edge.verts[1] in loop[i - 1].verts: + loop_vertices.append(edge.verts[1]) + elif edge.verts[0] in loop[i + 1].verts: + loop_vertices.append(edge.verts[1]) + elif edge.verts[1] in loop[i + 1].verts: + loop_vertices.append(edge.verts[0]) + + if len(loop_vertices) == 2: + # Unofficial convention right now that a loop of 2 verts always is a circle + radius = (loop_vertices[0].co - loop_vertices[1].co).length / 2 + face_area = pi * pow(radius, 2) + else: + loop_bm = bmesh.new() + for vert in loop_vertices: + loop_bm.verts.new(vert.co) + face = loop_bm.faces.new(loop_bm.verts) + face_area = face.calc_area() + loop_bm.free() loop_vertex_indices = [] active_arc_id = None @@ -203,7 +232,7 @@ class Helper: active_arc_id = None is_arc = False - for group_index in arc_groups: + for group_index in groups["IFCARCINDEX"]: if group_index in v[deform_layer]: if active_arc_id is not None and active_arc_id != group_index: incomplete_arc = arc_stack @@ -229,14 +258,11 @@ class Helper: loop_vertex_indices.append(arc_stack) loop_vertex_indices.append((loop_vertex_indices[-1][-1], loop_vertex_indices[0][0])) - # loop_vertex_indices = [v.index for v in loop_vertices] - face_area = face.calc_area() if face_area > max_area: max_area = face_area outer_loop = loop_vertex_indices inner_loops.append(loop_vertex_indices) - loop_bm.free() inner_loops.remove(outer_loop) diff --git a/src/blenderbim/blenderbim/bim/module/model/handler.py b/src/blenderbim/blenderbim/bim/module/model/handler.py index 0dd862471b..3ec10c120e 100644 --- a/src/blenderbim/blenderbim/bim/module/model/handler.py +++ b/src/blenderbim/blenderbim/bim/module/model/handler.py @@ -58,7 +58,6 @@ def load_post(*args): IfcStore.add_element_listener(opening.element_listener) IfcStore.add_element_listener(wall.element_listener) - IfcStore.add_element_listener(slab.element_listener) IfcStore.add_element_listener(profile.element_listener) ifcopenshell.api.add_post_listener( diff --git a/src/blenderbim/blenderbim/bim/module/model/slab.py b/src/blenderbim/blenderbim/bim/module/model/slab.py index cca0a960b7..127a736ea1 100644 --- a/src/blenderbim/blenderbim/bim/module/model/slab.py +++ b/src/blenderbim/blenderbim/bim/module/model/slab.py @@ -34,7 +34,7 @@ import blenderbim.core.geometry import blenderbim.tool as tool from bpy.types import SpaceView3D from blenderbim.bim.ifc import IfcStore -from math import pi, degrees +from math import pi, degrees, sin, cos, radians from mathutils import Vector, Matrix from ifcopenshell.api.pset.data import Data as PsetData from ifcopenshell.api.material.data import Data as MaterialData @@ -43,71 +43,6 @@ from gpu.types import GPUShader, GPUBatch, GPUIndexBuf, GPUVertBuf, GPUVertForma from gpu_extras.batch import batch_for_shader -def element_listener(element, obj): - blenderbim.bim.handler.subscribe_to(obj, "mode", mode_callback) - - -def mode_callback(obj, data): - for obj in set(bpy.context.selected_objects + [bpy.context.active_object]): - if ( - not obj.data - or not isinstance(obj.data, (bpy.types.Mesh, bpy.types.Curve, bpy.types.TextCurve)) - or not obj.BIMObjectProperties.ifc_definition_id - or not bpy.context.scene.BIMProjectProperties.is_authoring - ): - return - product = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id) - parametric = ifcopenshell.util.element.get_psets(product).get("EPset_Parametric") - if not parametric or parametric["Engine"] != "BlenderBIM.DumbLayer3": - return - if obj.mode == "EDIT": - IfcStore.edited_objs.add(obj) - ensure_solidify_modifier(obj) - else: - new_origin = obj.matrix_world @ Vector(obj.bound_box[0]) - obj.data.transform( - Matrix.Translation( - (obj.matrix_world.inverted().to_quaternion() @ (obj.matrix_world.translation - new_origin)) - ) - ) - obj.matrix_world.translation = new_origin - - -def ensure_solidify_modifier(obj): - modifier = [m for m in obj.modifiers if m.type == "SOLIDIFY"] - if modifier: - return modifier[0] - depth = obj.dimensions.z - - if obj.mode == "EDIT": - bm = bmesh.from_edit_mesh(obj.data) - else: - bm = bmesh.new() - bm.from_mesh(obj.data) - - bmesh.ops.dissolve_limit(bm, angle_limit=pi / 180 * 1, verts=bm.verts, edges=bm.edges) - bm.faces.ensure_lookup_table() - non_bottom_faces = [] - for face in bm.faces: - if face.normal.z > -0.9: - non_bottom_faces.append(face) - else: - face.normal_flip() - bmesh.ops.delete(bm, geom=non_bottom_faces, context="FACES") - - if obj.mode == "EDIT": - bmesh.update_edit_mesh(obj.data) - else: - bm.to_mesh(obj.data) - - bm.free() - modifier = obj.modifiers.new("Slab Depth", "SOLIDIFY") - modifier.use_even_offset = True - modifier.offset = 1 - modifier.thickness = depth - return modifier - - def generate_footprint(usecase_path, ifc_file, settings): footprint_context = ifcopenshell.util.representation.get_context(ifc_file, "Plan", "FootPrint", "SKETCH_VIEW") if not footprint_context: @@ -566,24 +501,21 @@ class EnableEditingExtrusionProfile(bpy.types.Operator): body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW") extrusion = self.get_extrusion(body) - profile = extrusion.SweptArea position = Matrix(ifcopenshell.util.placement.get_axis2placement(extrusion.Position).tolist()) position[0][3] *= self.unit_scale position[1][3] *= self.unit_scale position[2][3] *= self.unit_scale - print('converted', position) z_values = [v[2] for v in obj.bound_box] - - element = tool.Ifc.get_entity(obj) - origin = obj.matrix_world @ Vector((0, 0, max(z_values))) normal = obj.matrix_world.to_quaternion() self.vertices = [] self.edges = [] self.arcs = [] + self.circles = [] + profile = extrusion.SweptArea if profile.is_a("IfcArbitraryClosedProfileDef"): self.process_curve(obj, position, profile.OuterCurve) if profile.is_a("IfcArbitraryProfileDefWithVoids"): @@ -599,8 +531,12 @@ class EnableEditingExtrusionProfile(bpy.types.Operator): group = obj.vertex_groups.new(name="IFCARCINDEX") group.add(arc, 1, "REPLACE") + for circle in self.circles: + group = obj.vertex_groups.new(name="IFCCIRCLE") + group.add(circle, 1, "REPLACE") + bpy.ops.object.mode_set(mode="EDIT") - DecorationsHandler.install(bpy.context) + DecorationsHandler.install(context) bpy.ops.wm.tool_set_by_id(name="bim.cad_tool") return {"FINISHED"} @@ -625,6 +561,8 @@ class EnableEditingExtrusionProfile(bpy.types.Operator): continue global_point = position @ Vector(self.convert_unit_to_si(point.Coordinates)).to_3d() self.vertices.append(global_point) + self.edges.extend([(i, i + 1) for i in range(offset, len(self.vertices))]) + self.edges[-1] = (len(self.vertices) - 1, offset) # Close the loop elif curve.is_a("IfcIndexedPolyCurve"): is_arc = False if curve.Segments: @@ -650,11 +588,26 @@ class EnableEditingExtrusionProfile(bpy.types.Operator): global_point = position @ Vector(self.convert_unit_to_si(local_point)).to_3d() self.vertices.append(global_point) - self.edges.extend([(i, i + 1) for i in range(offset, len(self.vertices))]) - self.edges[-1] = (len(self.vertices) - 1, offset) + self.edges.extend([(i, i + 1) for i in range(offset, len(self.vertices))]) + self.edges[-1] = (len(self.vertices) - 1, offset) # Close the loop + elif curve.is_a("IfcCircle"): + center = self.convert_unit_to_si( + Matrix(ifcopenshell.util.placement.get_axis2placement(curve.Position).tolist()).col[3].to_3d() + ) + radius = self.convert_unit_to_si(curve.Radius) + self.vertices.extend( + [ + position @ Vector((center[0], center[1] - curve.Radius, 0.0)), + position @ Vector((center[0], center[1] + curve.Radius, 0.0)), + ] + ) + self.circles.append([offset, offset + 1]) + self.edges.append((offset, offset + 1)) def convert_unit_to_si(self, value): - return [v * self.unit_scale for v in value] + if isinstance(value, (tuple, list)): + return [v * self.unit_scale for v in value] + return value * self.unit_scale class EditExtrusionProfile(bpy.types.Operator): @@ -686,10 +639,10 @@ class EditExtrusionProfile(bpy.types.Operator): bpy.ops.object.mode_set(mode="EDIT") return {"CANCELLED"} - bm = bmesh.new() - bm.from_mesh(obj.data) - bm.verts.ensure_lookup_table() - bm.edges.ensure_lookup_table() + self.bm = bmesh.new() + self.bm.from_mesh(obj.data) + self.bm.verts.ensure_lookup_table() + self.bm.edges.ensure_lookup_table() if indices["inner_curves"]: profile = tool.Ifc.get().createIfcArbitraryProfileDefWithVoids("AREA") @@ -706,7 +659,7 @@ class EditExtrusionProfile(bpy.types.Operator): results.append(self.create_curve(position, inner_curve)) profile.InnerCurves = results - bm.free() + self.bm.free() extrusion.SweptArea = profile @@ -731,10 +684,19 @@ class EditExtrusionProfile(bpy.types.Operator): def create_curve(self, position, edge_indices, points=None): position_i = position.inverted() + if len(edge_indices) == 2: + diameter = edge_indices[0] + p1 = self.bm.verts[diameter[0]].co + p2 = self.bm.verts[diameter[1]].co + center = self.convert_si_to_unit(list(position_i @ p1.lerp(p2, 0.5))) + radius = self.convert_si_to_unit((p1 - p2).length / 2) + return tool.Ifc.get().createIfcCircle( + tool.Ifc.get().createIfcAxis2Placement2D(tool.Ifc.get().createIfcCartesianPoint(center)), radius + ) if tool.Ifc.get().schema == "IFC2X3": points = [] for edge in edge_indices: - local_point = (position_i @ Vector(bm.verts[edge[0]].co)).to_2d() + local_point = (position_i @ Vector(self.bm.verts[edge[0]].co)).to_2d() points.append(tool.Ifc.get().createIfcCartesianPoint(self.convert_si_to_unit(local_point))) points.append(points[0]) return tool.Ifc.get().createIfcPolyline(points) @@ -757,7 +719,9 @@ class EditExtrusionProfile(bpy.types.Operator): break def convert_si_to_unit(self, value): - return [v / self.unit_scale for v in value] + if isinstance(value, (tuple, list)): + return [v / self.unit_scale for v in value] + return value / self.unit_scale class SetArcIndex(bpy.types.Operator): @@ -807,12 +771,13 @@ class DecorationsHandler: def __call__(self, context): obj = context.active_object + if obj.mode != "EDIT": + return + bgl.glLineWidth(2) bgl.glPointSize(6) bgl.glEnable(bgl.GL_BLEND) bgl.glEnable(bgl.GL_LINE_SMOOTH) - if not obj.data.is_editmode: - return all_vertices = [] error_vertices = [] @@ -825,11 +790,15 @@ class DecorationsHandler: special_edges = [] arc_groups = [] + circle_groups = [] for i, group in enumerate(obj.vertex_groups): if "IFCARCINDEX" in group.name: arc_groups.append(i) + elif "IFCCIRCLE" in group.name: + circle_groups.append(i) arcs = {} + circles = {} bm = bmesh.from_edit_mesh(obj.data) @@ -852,6 +821,15 @@ class DecorationsHandler: arcs.setdefault(group_index, []).append(vertex) special_vertex_indices[vertex.index] = group_index + is_circle = False + for group_index in circle_groups: + if group_index in vertex[deform_layer]: + is_circle = True + break + if is_circle: + circles.setdefault(group_index, []).append(vertex) + special_vertex_indices[vertex.index] = group_index + if vertex.select: selected_vertices.append(co) else: @@ -913,6 +891,8 @@ class DecorationsHandler: self.shader.uniform_float("color", green) batch.draw(self.shader) + # Draw arcs + arc_centroids = [] arc_segments = [] for arc in arcs.values(): @@ -933,7 +913,7 @@ class DecorationsHandler: centroid = tool.Cad.get_center_of_arc(points) if centroid: arc_centroids.append(tuple(centroid)) - arc_segments.append(self.generate_3PT_mode_1(pts=points, num_verts=17, make_edges=True)) + arc_segments.append(self.create_arc_segments(pts=points, num_verts=17, make_edges=True)) batch = batch_for_shader(self.shader, "POINTS", {"pos": arc_centroids}) self.shader.uniform_float("color", (0.2, 0.2, 0.2, 1)) @@ -944,10 +924,74 @@ class DecorationsHandler: self.shader.uniform_float("color", (0.157, 0.565, 1, 1)) batch.draw(self.shader) + # Draw circles + + circle_centroids = [] + circle_segments = [] + for circle in circles.values(): + if len(circle) != 2: + continue + p1 = obj.matrix_world @ circle[0].co + p2 = obj.matrix_world @ circle[1].co + radius = (p2 - p1).length / 2 + centroid = p1.lerp(p2, 0.5) + circle_centroids.append(tuple(centroid)) + segments = self.create_circle_segments(360, 20, radius) + matrix = obj.matrix_world.copy() + matrix.col[3] = centroid.to_4d() + segments = [[list(matrix @ Vector(v)) for v in segments[0]], segments[1]] + circle_segments.append(segments) + + batch = batch_for_shader(self.shader, "POINTS", {"pos": circle_centroids}) + self.shader.uniform_float("color", (0.2, 0.2, 0.2, 1)) + batch.draw(self.shader) + + for verts, edges in circle_segments: + batch = batch_for_shader(self.shader, "LINES", {"pos": verts}, indices=edges) + self.shader.uniform_float("color", (0.157, 0.565, 1, 1)) + batch.draw(self.shader) + + def create_matrix(self, p, x, y, z): + return Matrix([x, y, z, p]).to_4x4().transposed() + # https://github.com/nortikin/sverchok/blob/master/nodes/generator/basic_3pt_arc.py - # This generate_3PT_mode_1 function is taken from Sverchok, licensed under GPL v2-or-later. + # This function is taken from Sverchok, licensed under GPL v2-or-later. + # This is a combination of the make_verts and make_edges function. + def create_circle_segments(self, Angle, Vertices, Radius): + if Angle < 360: + theta = Angle / (Vertices - 1) + else: + theta = Angle / Vertices + listVertX = [] + listVertY = [] + for i in range(Vertices): + listVertX.append(Radius * cos(radians(theta * i))) + listVertY.append(Radius * sin(radians(theta * i))) + + if Angle < 360 and self.mode_ == 0: + sigma = radians(Angle) + listVertX[-1] = Radius * cos(sigma) + listVertY[-1] = Radius * sin(sigma) + elif Angle < 360 and self.mode_ == 1: + listVertX.append(0.0) + listVertY.append(0.0) + + points = list((x, y, 0) for x, y in zip(listVertX, listVertY)) + + listEdg = [(i, i + 1) for i in range(Vertices - 1)] + + if Angle < 360 and self.mode_ == 1: + listEdg.append((0, Vertices)) + listEdg.append((Vertices - 1, Vertices)) + else: + listEdg.append((Vertices - 1, 0)) + + return points, listEdg + + # https://github.com/nortikin/sverchok/blob/master/nodes/generator/basic_3pt_arc.py + # This function is taken from Sverchok's generate_3PT_mode_1 function, licensed under GPL v2-or-later. # No functional modifications have been made. - def generate_3PT_mode_1(self, pts=None, num_verts=20, make_edges=False): + def create_arc_segments(self, pts=None, num_verts=20, make_edges=False): """ Arc from [start - through - end] - call this function only if you have 3 pts,