diff options
-rw-r--r-- | curve_tools/Curves.py | 16 | ||||
-rw-r--r-- | curve_tools/Operators.py | 124 | ||||
-rw-r--r-- | curve_tools/Properties.py | 15 | ||||
-rw-r--r-- | curve_tools/Surfaces.py | 24 | ||||
-rw-r--r-- | curve_tools/__init__.py | 132 | ||||
-rw-r--r-- | curve_tools/auto_loft.py | 17 | ||||
-rw-r--r-- | curve_tools/cad.py | 77 | ||||
-rw-r--r-- | curve_tools/curve_outline.py | 112 | ||||
-rw-r--r-- | curve_tools/curve_remove_doubles.py | 110 | ||||
-rw-r--r-- | curve_tools/exports.py | 11 | ||||
-rw-r--r-- | curve_tools/fillet.py | 143 | ||||
-rw-r--r-- | curve_tools/internal.py | 19 | ||||
-rw-r--r-- | curve_tools/intersections.py (renamed from curve_tools/CurveIntersections.py) | 54 | ||||
-rw-r--r-- | curve_tools/mathematics.py (renamed from curve_tools/Math.py) | 0 | ||||
-rw-r--r-- | curve_tools/outline.py | 118 | ||||
-rw-r--r-- | curve_tools/path_finder.py (renamed from curve_tools/PathFinder.py) | 28 | ||||
-rw-r--r-- | curve_tools/remove_doubles.py | 135 | ||||
-rw-r--r-- | curve_tools/show_resolution.py (renamed from curve_tools/ShowCurveResolution.py) | 19 | ||||
-rw-r--r-- | curve_tools/splines_sequence.py (renamed from curve_tools/SplinesSequence.py) | 17 | ||||
-rw-r--r-- | curve_tools/toolpath.py | 23 |
20 files changed, 760 insertions, 434 deletions
diff --git a/curve_tools/Curves.py b/curve_tools/Curves.py index d5608e3c..da0b1398 100644 --- a/curve_tools/Curves.py +++ b/curve_tools/Curves.py @@ -1,4 +1,4 @@ -from . import Math +from . import mathematics import bpy @@ -390,7 +390,7 @@ class BezierSpline: self.segments.append(BezierSegment(self.segments[-1].bezierPoint2, spline2.segments[0].bezierPoint1)) for seg2 in spline2.segments: self.segments.append(seg2) - self.resolution += spline2.resolution # extra segment will usually be short -- impact on resolution negligible + self.resolution += spline2.resolution # extra segment will usually be short -- impact on resolution negligable self.isCyclic = False # is this ok? @@ -559,11 +559,11 @@ class Curve: currEndPoint = currentSpline.segments[-1].bezierPoint2.co nextStartPoint = nextSpline.segments[0].bezierPoint1.co - if Math.IsSamePoint(currEndPoint, nextStartPoint, threshold): return [currentSpline, nextSpline] + if mathematics.IsSamePoint(currEndPoint, nextStartPoint, threshold): return [currentSpline, nextSpline] nextEndPoint = nextSpline.segments[-1].bezierPoint2.co currStartPoint = currentSpline.segments[0].bezierPoint1.co - if Math.IsSamePoint(nextEndPoint, currStartPoint, threshold): return [nextSpline, currentSpline] + if mathematics.IsSamePoint(nextEndPoint, currStartPoint, threshold): return [nextSpline, currentSpline] return None else: @@ -575,18 +575,18 @@ class Curve: currEndPoint = currentSpline.segments[-1].bezierPoint2.co nextStartPoint = nextSpline.segments[0].bezierPoint1.co - if Math.IsSamePoint(currEndPoint, nextStartPoint, threshold): return [currentSpline, nextSpline] + if mathematics.IsSamePoint(currEndPoint, nextStartPoint, threshold): return [currentSpline, nextSpline] nextEndPoint = nextSpline.segments[-1].bezierPoint2.co currStartPoint = currentSpline.segments[0].bezierPoint1.co - if Math.IsSamePoint(nextEndPoint, currStartPoint, threshold): return [nextSpline, currentSpline] + if mathematics.IsSamePoint(nextEndPoint, currStartPoint, threshold): return [nextSpline, currentSpline] - if Math.IsSamePoint(currEndPoint, nextEndPoint, threshold): + if mathematics.IsSamePoint(currEndPoint, nextEndPoint, threshold): nextSpline.Reverse() #print("## ", "nextSpline.Reverse()") return [currentSpline, nextSpline] - if Math.IsSamePoint(currStartPoint, nextStartPoint, threshold): + if mathematics.IsSamePoint(currStartPoint, nextStartPoint, threshold): currentSpline.Reverse() #print("## ", "currentSpline.Reverse()") return [currentSpline, nextSpline] diff --git a/curve_tools/Operators.py b/curve_tools/Operators.py index edf16ab1..e4fe24dd 100644 --- a/curve_tools/Operators.py +++ b/curve_tools/Operators.py @@ -7,12 +7,12 @@ from bpy_extras import object_utils, view3d_utils from mathutils import * from math import * -from . import Properties -from . import Curves -from . import CurveIntersections -from . import Util -from . import Surfaces -from . import Math +from . import properties +from . import curves +from . import intersections +from . import util +from . import surfaces +from . import mathematics # 1 CURVE SELECTED # ################ @@ -24,11 +24,11 @@ class OperatorCurveInfo(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1Curve() + return util.Selected1Curve() def execute(self, context): - curve = Curves.Curve(context.active_object) + curve = curves.Curve(context.active_object) nrSplines = len(curve.splines) nrSegments = 0 @@ -52,11 +52,11 @@ class OperatorCurveLength(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1Curve() + return util.Selected1Curve() def execute(self, context): - curve = Curves.Curve(context.active_object) + curve = curves.Curve(context.active_object) context.scene.curvetools.CurveLength = curve.length @@ -72,11 +72,11 @@ class OperatorSplinesInfo(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1Curve() + return util.Selected1Curve() def execute(self, context): - curve = Curves.Curve(context.active_object) + curve = curves.Curve(context.active_object) nrSplines = len(curve.splines) print("") @@ -105,11 +105,11 @@ class OperatorSegmentsInfo(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1Curve() + return util.Selected1Curve() def execute(self, context): - curve = Curves.Curve(context.active_object) + curve = curves.Curve(context.active_object) nrSplines = len(curve.splines) nrSegments = 0 @@ -146,7 +146,7 @@ class OperatorOriginToSpline0Start(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1Curve() + return util.Selected1Curve() def execute(self, context): @@ -183,11 +183,11 @@ class OperatorIntersectCurves(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected2OrMoreCurves() + return util.Selected2OrMoreCurves() def execute(self, context): - print("### TODO: OperatorIntersectCurves.execute()") + print("### TODO: OperatorIntersectcurves.execute()") algo = context.scene.curvetools.IntersectCurvesAlgorithm print("-- algo:", algo) @@ -213,7 +213,7 @@ class OperatorIntersectCurves(bpy.types.Operator): selected_objects[j].select_set(True) if selected_objects[i].type == 'CURVE' and selected_objects[j].type == 'CURVE': - curveIntersector = CurveIntersections.CurvesIntersector.FromSelection() + curveIntersector = intersections.CurvesIntersector.FromSelection() rvIntersectionNrs = curveIntersector.CalcAndApplyIntersections() self.report({'INFO'}, "Active curve points: %d; other curve points: %d" % (rvIntersectionNrs[0], rvIntersectionNrs[1])) @@ -234,16 +234,16 @@ class OperatorLoftCurves(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected2Curves() + return util.Selected2Curves() def execute(self, context): - #print("### TODO: OperatorLoftCurves.execute()") + #print("### TODO: OperatorLoftcurves.execute()") - loftedSurface = Surfaces.LoftedSurface.FromSelection() + loftedSurface = surfaces.LoftedSurface.FromSelection() loftedSurface.AddToScene() - self.report({'INFO'}, "OperatorLoftCurves.execute()") + self.report({'INFO'}, "OperatorLoftcurves.execute()") return {'FINISHED'} @@ -259,16 +259,16 @@ class OperatorSweepCurves(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected2Curves() + return util.Selected2Curves() def execute(self, context): - #print("### TODO: OperatorSweepCurves.execute()") + #print("### TODO: OperatorSweepcurves.execute()") - sweptSurface = Surfaces.SweptSurface.FromSelection() + sweptSurface = surfaces.SweptSurface.FromSelection() sweptSurface.AddToScene() - self.report({'INFO'}, "OperatorSweepCurves.execute()") + self.report({'INFO'}, "OperatorSweepcurves.execute()") return {'FINISHED'} @@ -284,11 +284,11 @@ class OperatorBirail(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected3Curves() + return util.Selected3Curves() def execute(self, context): - birailedSurface = Surfaces.BirailedSurface.FromSelection() + birailedSurface = surfaces.BirailedSurface.FromSelection() birailedSurface.AddToScene() self.report({'INFO'}, "OperatorBirail.execute()") @@ -307,12 +307,12 @@ class OperatorSplinesSetResolution(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): splRes = context.scene.curvetools.SplineResolution - selCurves = Util.GetSelectedCurves() + selCurves = util.GetSelectedCurves() for blCurve in selCurves: for spline in blCurve.data.splines: @@ -331,14 +331,14 @@ class OperatorSplinesRemoveZeroSegment(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): - selCurves = Util.GetSelectedCurves() + selCurves = util.GetSelectedCurves() for blCurve in selCurves: - curve = Curves.Curve(blCurve) + curve = curves.Curve(blCurve) nrSplines = curve.nrSplines splinesToRemove = [] @@ -365,15 +365,15 @@ class OperatorSplinesRemoveShort(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): threshold = context.scene.curvetools.SplineRemoveLength - selCurves = Util.GetSelectedCurves() + selCurves = util.GetSelectedCurves() for blCurve in selCurves: - curve = Curves.Curve(blCurve) + curve = curves.Curve(blCurve) nrSplines = curve.nrSplines nrRemovedSplines = curve.RemoveShortSplines(threshold) @@ -394,14 +394,14 @@ class OperatorSplinesJoinNeighbouring(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): - selCurves = Util.GetSelectedCurves() + selCurves = util.GetSelectedCurves() for blCurve in selCurves: - curve = Curves.Curve(blCurve) + curve = curves.Curve(blCurve) nrSplines = curve.nrSplines threshold = context.scene.curvetools.SplineJoinDistance @@ -423,7 +423,7 @@ def SurfaceFromBezier(surfacedata, points, center): len_points = len(points) - 1 if len_points % 2 == 0: - h = Math.subdivide_cubic_bezier( + h = mathematics.subdivide_cubic_bezier( points[len_points].co, points[len_points].handle_right, points[0].handle_left, points[0].co, 0.5 ) @@ -550,7 +550,7 @@ class ConvertSelectedFacesToBezier(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1Mesh() + return util.Selected1Mesh() def execute(self, context): # main function @@ -620,7 +620,7 @@ class ConvertBezierToSurface(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): # main function @@ -686,7 +686,7 @@ class BezierPointsFillet(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): # main function @@ -798,7 +798,7 @@ class BezierDivide(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): # main function @@ -834,7 +834,7 @@ class BezierDivide(bpy.types.Operator): if (j in ii) and (j + 1 in ii): bezier_points[j + jn].select_control_point = True bezier_points[j + 1 + jn].select_control_point = True - h = Math.subdivide_cubic_bezier( + h = mathematics.subdivide_cubic_bezier( bezier_points[j + jn].co, bezier_points[j + jn].handle_right, bezier_points[j + 1 + jn].handle_left, bezier_points[j + 1 + jn].co, self.Bezier_t / 100 ) @@ -853,7 +853,7 @@ class BezierDivide(bpy.types.Operator): if j == n - 1 and (0 in ii) and spline.use_cyclic_u: bezier_points[j + jn].select_control_point = True bezier_points[0].select_control_point = True - h = Math.subdivide_cubic_bezier( + h = mathematics.subdivide_cubic_bezier( bezier_points[j + jn].co, bezier_points[j + jn].handle_right, bezier_points[0].handle_left, bezier_points[0].co, self.Bezier_t / 100 ) @@ -922,10 +922,10 @@ class Split(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): - selected_Curves = Util.GetSelectedCurves() + selected_Curves = util.GetSelectedCurves() for curve in selected_Curves: spline_points = [] @@ -1004,6 +1004,33 @@ class Split(bpy.types.Operator): num=i return {'FINISHED'} + +class SeparateOutline(bpy.types.Operator): + bl_idname = "curvetools.sep_outline" + bl_label = "Separate Outline" + bl_options = {'REGISTER', 'UNDO'} + bl_description = "Makes 'Outline' separate mesh" + + @classmethod + def poll(cls, context): + return util.Selected1OrMoreCurves() + + def execute(self, context): + bpy.ops.object.mode_set(mode = 'EDIT') + bpy.ops.curve.separate() + + return {'FINISHED'} + +def register(): + for cls in classes: + bpy.utils.register_class(operators) + +def unregister(): + for cls in classes: + bpy.utils.unregister_class(operators) + +if __name__ == "__main__": + register() operators = [ OperatorCurveInfo, @@ -1025,4 +1052,5 @@ operators = [ BezierDivide, CurveScaleReset, Split, + SeparateOutline, ] diff --git a/curve_tools/Properties.py b/curve_tools/Properties.py index 415b3c8b..d6fe9e0f 100644 --- a/curve_tools/Properties.py +++ b/curve_tools/Properties.py @@ -87,3 +87,18 @@ class curvetoolsSelectedObject(bpy.types.PropertyGroup): for blObject in blenderSelectedObjects: rvNames.append(blObject.name) return rvNames + +def register(): + for cls in classes: + bpy.utils.register_class(operators) + +def unregister(): + for cls in classes: + bpy.utils.unregister_class(operators) + +if __name__ == "__main__": + register() + +operators = [ + curvetoolsSelectedObject, + ] diff --git a/curve_tools/Surfaces.py b/curve_tools/Surfaces.py index 22b5119c..cfae7040 100644 --- a/curve_tools/Surfaces.py +++ b/curve_tools/Surfaces.py @@ -1,8 +1,8 @@ import bpy import bmesh -from . import Math -from . import Curves +from . import mathematics +from . import curves @@ -62,8 +62,8 @@ class LoftedSurface: blenderOtherCurve = selObjects[0] if blenderActiveCurve == blenderOtherCurve: blenderOtherCurve = selObjects[1] - aCurve = Curves.Curve(blenderActiveCurve) - oCurve = Curves.Curve(blenderOtherCurve) + aCurve = curves.Curve(blenderActiveCurve) + oCurve = curves.Curve(blenderOtherCurve) name = "TODO: autoname" @@ -162,7 +162,7 @@ class SweptSplineSurface: prevDerivativeO = localDerivativesO[0] for iO in range(self.resolutionO): currDerivativeO = localDerivativesO[iO] - localRotMatO = Math.CalcRotationMatrix(prevDerivativeO, currDerivativeO) + localRotMatO = mathematics.CalcRotationMatrix(prevDerivativeO, currDerivativeO) currLocalAToLocalO = worldMatrixOInv @ currWorldMatrixA worldPointsA = [] @@ -210,8 +210,8 @@ class SweptSurface: blenderOtherCurve = selObjects[0] if blenderActiveCurve == blenderOtherCurve: blenderOtherCurve = selObjects[1] - aCurve = Curves.Curve(blenderActiveCurve) - oCurve = Curves.Curve(blenderOtherCurve) + aCurve = curves.Curve(blenderActiveCurve) + oCurve = curves.Curve(blenderOtherCurve) name = "TODO: autoname" @@ -315,7 +315,7 @@ class BirailedSplineSurface: prevDerivativeRail1 = localDerivativesRail1[0] for iRail in range(self.resolutionRails): currDerivativeRail1 = localDerivativesRail1[iRail] - localRotMatRail1 = Math.CalcRotationMatrix(prevDerivativeRail1, currDerivativeRail1) + localRotMatRail1 = mathematics.CalcRotationMatrix(prevDerivativeRail1, currDerivativeRail1) currLocalProfileToLocalRail1 = worldMatrixRail1Inv @ currWorldMatrixProfile worldPointsProfileRail1 = [] @@ -336,7 +336,7 @@ class BirailedSplineSurface: scaleFactorRail2 = v3To.magnitude / v3From.magnitude else: scaleFactorRail2 = 1 - rotMatRail2 = Math.CalcRotationMatrix(v3From, v3To) + rotMatRail2 = mathematics.CalcRotationMatrix(v3From, v3To) worldOffsetsProfileRail2 = [] for iProfile in range(self.resolutionProfile): @@ -397,9 +397,9 @@ class BirailedSurface: if profileBlenderCurve is None: raise Exception("profileBlenderCurve is None") - rail1Curve = Curves.Curve(rail1BlenderCurve) - rail2Curve = Curves.Curve(rail2BlenderCurve) - profileCurve = Curves.Curve(profileBlenderCurve) + rail1Curve = curves.Curve(rail1BlenderCurve) + rail2Curve = curves.Curve(rail2BlenderCurve) + profileCurve = curves.Curve(profileBlenderCurve) name = "TODO: autoname" diff --git a/curve_tools/__init__.py b/curve_tools/__init__.py index e38f854e..736e60fb 100644 --- a/curve_tools/__init__.py +++ b/curve_tools/__init__.py @@ -25,13 +25,12 @@ bl_info = { "name": "Curve Tools", "description": "Adds some functionality for bezier/nurbs curve/surface modeling", "author": "Mackraken", - "version": (0, 3, 3), + "version": (0, 4, 0), "blender": (2, 80, 0), "location": "View3D > Tool Shelf > Edit Tab", "warning": "WIP", - "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/" - "Scripts/Curve/Curve_Tools", - "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/", + "wiki_url": "", + "tracker_url": "", "category": "Add Curve"} @@ -50,22 +49,25 @@ from bpy.props import ( StringProperty, FloatVectorProperty, ) -from . import Properties -from . import Operators -from . import auto_loft -from . import curve_outline -from . import PathFinder -from . import ShowCurveResolution -from . import SplinesSequence +from . import properties, operators, auto_loft, outline, remove_doubles +from . import path_finder, show_resolution, splines_sequence, fillet from . import internal, cad, toolpath, exports -if 'internal' in locals(): +if 'bpy' in locals(): + importlib.reload(properties) + importlib.reload(operators) + importlib.reload(auto_loft) + importlib.reload(outline) + importlib.reload(remove_doubles) + importlib.reload(path_finder) + importlib.reload(show_resolution) + importlib.reload(splines_sequence) + importlib.reload(fillet) importlib.reload(internal) importlib.reload(cad) importlib.reload(toolpath) importlib.reload(exports) - from bpy.types import ( AddonPreferences, ) @@ -81,28 +83,10 @@ def UpdateDummy(object, context): UTILSDROP = scene.UTUtilsDrop -class SeparateOutline(Operator): - bl_idname = "object.sep_outline" - bl_label = "Separate Outline" - bl_options = {'REGISTER', 'UNDO'} - bl_description = "Makes 'Outline' separate mesh" - - @classmethod - def poll(cls, context): - return (context.object is not None and - context.object.type == 'CURVE') - - def execute(self, context): - bpy.ops.object.mode_set(mode = 'EDIT') - bpy.ops.curve.separate() - - return {'FINISHED'} - - class curvetoolsSettings(PropertyGroup): # selection SelectedObjects: CollectionProperty( - type=Properties.curvetoolsSelectedObject + type=properties.curvetoolsSelectedObject ) NrSelectedObjects: IntProperty( name="NrSelectedObjects", @@ -308,7 +292,6 @@ class VIEW3D_PT_CurvePanel(Panel): row = col.row(align=True) row.prop(context.scene.curvetools, "LimitDistance", text="LimitDistance") - # row.active = (context.scene.curvetools.IntersectCurvesAlgorithm == '3D') row = col.row(align=True) row.prop(context.scene.curvetools, "IntersectCurvesAlgorithm", text="Algorithm") @@ -346,12 +329,14 @@ class VIEW3D_PT_CurvePanel(Panel): if ADVANCEDDROP: # C. 3 curves row = col.row(align=True) - row.operator("object._curve_outline", text="Curve Outline") + row.operator("curvetools.outline", text="Curve Outline") row = col.row(align=True) - row.operator("object.sep_outline", text="Separate Outline or selected") + row.operator("curvetools.sep_outline", text="Separate Outline or selected") row = col.row(align=True) row.operator("curvetools.bezier_points_fillet", text='Fillet') row = col.row(align=True) + row.operator("curvetools.bezier_cad_handle_projection", text='Handle Projection') + row = col.row(align=True) row.operator("curvetools.bezier_spline_divide", text='Divide') row = col.row(align=True) row.operator("curvetools.scale_reset", text='Scale Reset') @@ -369,17 +354,19 @@ class VIEW3D_PT_CurvePanel(Panel): row.prop(scene, "UTExtendedDrop", icon="TRIA_DOWN") if EXTENDEDDROP: row = col.row(align=True) - row.operator("curve.add_toolpath_offset_curve", text="Offset Curve") + row.operator("curvetools.add_toolpath_offset_curve", text="Offset Curve") row = col.row(align=True) - row.operator("curve.bezier_cad_boolean", text="Boolean 2 selected spline") + row.operator("curvetools.bezier_cad_boolean", text="Boolean 2 selected spline") row = col.row(align=True) - row.operator("curve.bezier_cad_subdivide", text="Multi Subdivide") + row.operator("curvetools.bezier_cad_subdivide", text="Multi Subdivide") row = col.row(align=True) row.operator("curvetools.split", text='Split by selected points') row = col.row(align=True) - row.operator("curve.add_toolpath_discretize_curve", text="Discretize Curve") + row.operator("curvetools.remove_doubles", text='Remove Doubles') + row = col.row(align=True) + row.operator("curvetools.add_toolpath_discretize_curve", text="Discretize Curve") row = col.row(align=True) - row.operator("curve.bezier_cad_array", text="Array selected spline") + row.operator("curvetools.bezier_cad_array", text="Array selected spline") # Utils Curve options box1 = self.layout.box() @@ -396,7 +383,7 @@ class VIEW3D_PT_CurvePanel(Panel): row = col.row(align=True) row.prop(context.scene.curvetools, "curve_vertcolor", text="") row = col.row(align=True) - row.operator("curve.show_resolution", text="Run [ESC]") + row.operator("curvetools.show_resolution", text="Run [ESC]") # D.1 set spline sequence row = col.row(align=True) @@ -406,12 +393,12 @@ class VIEW3D_PT_CurvePanel(Panel): row.prop(context.scene.curvetools, "font_thickness", text="") row.prop(context.scene.curvetools, "font_size", text="") row = col.row(align=True) - oper = row.operator("curve.rearrange_spline", text="<") + oper = row.operator("curvetools.rearrange_spline", text="<") oper.command = 'PREV' - oper = row.operator("curve.rearrange_spline", text=">") + oper = row.operator("curvetools.rearrange_spline", text=">") oper.command = 'NEXT' row = col.row(align=True) - row.operator("curve.show_splines_sequence", text="Run [ESC]") + row.operator("curvetools.show_splines_sequence", text="Run [ESC]") # D.2 remove splines row = col.row(align=True) @@ -455,7 +442,6 @@ class VIEW3D_PT_CurvePanel(Panel): row = col.row(align=True) row.label(text="A - deselect all") - # Add-ons Preferences Update Panel # Define Panel classes for updating @@ -500,6 +486,27 @@ class CurveAddonPreferences(AddonPreferences): col.label(text="Tab Category:") col.prop(self, "category", text="") +# Context MENU +def curve_tools_context_menu(self, context): + bl_label = 'Curve tools' + + self.layout.operator("curvetools.bezier_points_fillet", text="Fillet") + self.layout.operator("curvetools.bezier_cad_handle_projection", text='Handle Projection') + self.layout.operator("curvetools.bezier_spline_divide", text="Divide") + self.layout.operator("curvetools.add_toolpath_offset_curve", text="Offset Curve") + self.layout.operator("curvetools.remove_doubles", text='Remove Doubles') + self.layout.separator() + +def curve_tools_object_context_menu(self, context): + bl_label = 'Curve tools' + + if context.active_object.type == "CURVE": + self.layout.operator("curvetools.scale_reset", text="Scale Reset") + self.layout.operator("curvetools.add_toolpath_offset_curve", text="Offset Curve") + self.layout.operator("curvetools.remove_doubles", text='Remove Doubles') + self.layout.separator() + +# Import-export 2d svg def menu_file_export(self, context): for operator in exports.operators: self.layout.operator(operator.bl_idname) @@ -509,16 +516,21 @@ def menu_file_import(self, context): self.layout.operator(operator.bl_idname) # REGISTER -classes = cad.operators + toolpath.operators + exports.operators + Operators.operators + [ - Properties.curvetoolsSelectedObject, - CurveAddonPreferences, - curvetoolsSettings, - SeparateOutline, - PathFinder.PathFinder, - ShowCurveResolution.ShowCurveResolution, - SplinesSequence.ShowSplinesSequence, - SplinesSequence.RearrangeSpline, - ] +classes = cad.operators + \ + toolpath.operators + \ + exports.operators + \ + operators.operators + \ + properties.operators + \ + path_finder.operators + \ + show_resolution.operators + \ + splines_sequence.operators + \ + outline.operators + \ + fillet.operators + \ + remove_doubles.operators + \ + [ + CurveAddonPreferences, + curvetoolsSettings, + ] def register(): bpy.types.Scene.UTSingleDrop = BoolProperty( @@ -560,13 +572,14 @@ def register(): auto_loft.register() - curve_outline.register() - bpy.types.TOPBAR_MT_file_export.append(menu_file_export) bpy.types.Scene.curvetools = bpy.props.PointerProperty(type=curvetoolsSettings) update_panel(None, bpy.context) + + bpy.types.VIEW3D_MT_edit_curve_context_menu.prepend(curve_tools_context_menu) + bpy.types.VIEW3D_MT_object_context_menu.prepend(curve_tools_object_context_menu) def unregister(): @@ -579,10 +592,11 @@ def unregister(): auto_loft.unregister() - curve_outline.unregister() - bpy.types.TOPBAR_MT_file_export.remove(menu_file_export) + bpy.types.VIEW3D_MT_edit_curve_context_menu.remove(curve_tools_context_menu) + bpy.types.VIEW3D_MT_object_context_menu.remove(curve_tools_object_context_menu) + for panel in panels: bpy.utils.unregister_class(panel) diff --git a/curve_tools/auto_loft.py b/curve_tools/auto_loft.py index 6675aaf1..c0711196 100644 --- a/curve_tools/auto_loft.py +++ b/curve_tools/auto_loft.py @@ -1,9 +1,9 @@ import bpy from bpy.props import BoolProperty from bpy.types import Operator, Panel -from curve_tools.Surfaces import LoftedSurface -from curve_tools.Curves import Curve -from curve_tools import Util +from . import surfaces +from . import curves +from . import util class OperatorAutoLoftCurves(Operator): @@ -13,16 +13,16 @@ class OperatorAutoLoftCurves(Operator): @classmethod def poll(cls, context): - return Util.Selected2Curves() + return util.Selected2Curves() def execute(self, context): - #print("### TODO: OperatorLoftCurves.execute()") + #print("### TODO: OperatorLoftcurves.execute()") mesh = bpy.data.meshes.new("LoftMesh") curve0 = context.selected_objects[0] curve1 = context.selected_objects[1] - ls = LoftedSurface(Curve(curve0), Curve(curve1), "AutoLoft") + ls = surfaces.LoftedSurface(curves.Curve(curve0), curves.Curve(curve1), "AutoLoft") ls.bMesh.to_mesh(mesh) @@ -37,8 +37,6 @@ class OperatorAutoLoftCurves(Operator): "description": "Auto loft from %s to %s" % (curve0.name, curve1.name), "curve0": curve0.name, "curve1": curve1.name} - #print(loftobj['_RNA_UI'].to_dict()) - #self.report({'INFO'}, "OperatorAutoLoftCurves.execute()") return {'FINISHED'} @@ -61,12 +59,11 @@ class AutoLoftModalOperator(Operator): #print("TIMER", lofters) for loftmesh in lofters: - #loftmesh.hide_select = True rna = loftmesh['_RNA_UI']["autoloft"].to_dict() curve0 = scene.objects.get(rna["curve0"]) curve1 = scene.objects.get(rna["curve1"]) if curve0 and curve1: - ls = LoftedSurface(Curve(curve0), Curve(curve1), loftmesh.name) + ls = surfaces.LoftedSurface(curves.Curve(curve0), curves.Curve(curve1), loftmesh.name) ls.bMesh.to_mesh(loftmesh.data) return {'FINISHED'} diff --git a/curve_tools/cad.py b/curve_tools/cad.py index 288f9149..49ccf171 100644 --- a/curve_tools/cad.py +++ b/curve_tools/cad.py @@ -28,20 +28,20 @@ bl_info = { import bpy from . import internal -from . import Util +from . import util class Fillet(bpy.types.Operator): - bl_idname = 'curve.bezier_cad_fillet' + bl_idname = 'curvetools.bezier_cad_fillet' bl_description = bl_label = 'Fillet' bl_options = {'REGISTER', 'UNDO'} radius: bpy.props.FloatProperty(name='Radius', description='Radius of the rounded corners', unit='LENGTH', min=0.0, default=0.1) chamfer_mode: bpy.props.BoolProperty(name='Chamfer', description='Cut off sharp without rounding', default=False) - limit_half_way: bpy.props.BoolProperty(name='Limit Half Way', description='Limits the segments to half their length in order to prevent collisions', default=False) + limit_half_way: bpy.props.BoolProperty(name='Limit Half Way', description='Limits the segements to half their length in order to prevent collisions', default=False) @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): splines = internal.getSelectedSplines(True, True, True) @@ -54,7 +54,7 @@ class Fillet(bpy.types.Operator): return {'FINISHED'} class Boolean(bpy.types.Operator): - bl_idname = 'curve.bezier_cad_boolean' + bl_idname = 'curvetools.bezier_cad_boolean' bl_description = bl_label = 'Boolean' bl_options = {'REGISTER', 'UNDO'} @@ -66,7 +66,7 @@ class Boolean(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): current_mode = bpy.context.object.mode @@ -80,7 +80,7 @@ class Boolean(bpy.types.Operator): if len(splines) != 2: self.report({'WARNING'}, 'Invalid selection. Only work to selected two spline.') return {'CANCELLED'} - bpy.ops.curve.spline_type_set(type='BEZIER') + bpy.ops.curvetools.spline_type_set(type='BEZIER') splineA = bpy.context.object.data.splines.active splineB = splines[0] if (splines[1] == splineA) else splines[1] if not internal.bezierBooleanGeometry(splineA, splineB, self.operation): @@ -92,13 +92,13 @@ class Boolean(bpy.types.Operator): return {'FINISHED'} class Intersection(bpy.types.Operator): - bl_idname = 'curve.bezier_cad_intersection' + bl_idname = 'curvetools.bezier_cad_intersection' bl_description = bl_label = 'Intersection' bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): segments = internal.bezierSegments(bpy.context.object.data.splines, True) @@ -108,15 +108,33 @@ class Intersection(bpy.types.Operator): internal.bezierMultiIntersection(segments) return {'FINISHED'} + +class HandleProjection(bpy.types.Operator): + bl_idname = 'curvetools.bezier_cad_handle_projection' + bl_description = bl_label = 'Handle Projection' + bl_options = {'REGISTER', 'UNDO'} + + @classmethod + def poll(cls, context): + return internal.curveObject() + + def execute(self, context): + segments = internal.bezierSegments(bpy.context.object.data.splines, True) + if len(segments) < 1: + self.report({'WARNING'}, 'Nothing selected') + return {'CANCELLED'} + + internal.bezierProjectHandles(segments) + return {'FINISHED'} class MergeEnds(bpy.types.Operator): - bl_idname = 'curve.bezier_cad_merge_ends' + bl_idname = 'curvetools.bezier_cad_merge_ends' bl_description = bl_label = 'Merge Ends' bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): points = [] @@ -151,17 +169,17 @@ class MergeEnds(bpy.types.Operator): points[0].handle_left = handle points[0].co = new_co - bpy.ops.curve.select_all(action='DESELECT') + bpy.ops.curvetools.select_all(action='DESELECT') points[1].select_control_point = True - bpy.ops.curve.delete() + bpy.ops.curvetools.delete() selected_splines[0].bezier_points[-1 if is_last_point[0] else 0].select_control_point = True selected_splines[1].bezier_points[-1 if is_last_point[1] else 0].select_control_point = True - bpy.ops.curve.make_segment() - bpy.ops.curve.select_all(action='DESELECT') + bpy.ops.curvetools.make_segment() + bpy.ops.curvetools.select_all(action='DESELECT') return {'FINISHED'} class Subdivide(bpy.types.Operator): - bl_idname = 'curve.bezier_cad_subdivide' + bl_idname = 'curvetools.bezier_cad_subdivide' bl_description = bl_label = 'Subdivide' bl_options = {'REGISTER', 'UNDO'} @@ -169,7 +187,7 @@ class Subdivide(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): current_mode = bpy.context.object.mode @@ -193,7 +211,7 @@ class Subdivide(bpy.types.Operator): return {'FINISHED'} class Array(bpy.types.Operator): - bl_idname = 'curve.bezier_cad_array' + bl_idname = 'curvetools.bezier_cad_array' bl_description = bl_label = 'Array' bl_options = {'REGISTER', 'UNDO'} @@ -204,7 +222,7 @@ class Array(bpy.types.Operator): @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): splines = internal.getSelectedSplines(True, True) @@ -215,13 +233,13 @@ class Array(bpy.types.Operator): return {'FINISHED'} class Circle(bpy.types.Operator): - bl_idname = 'curve.bezier_cad_circle' + bl_idname = 'curvetools.bezier_cad_circle' bl_description = bl_label = 'Circle' bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): segments = internal.bezierSegments(bpy.context.object.data.splines, True) @@ -240,12 +258,12 @@ class Circle(bpy.types.Operator): return {'FINISHED'} class Length(bpy.types.Operator): - bl_idname = 'curve.bezier_cad_length' + bl_idname = 'curvetools.bezier_cad_length' bl_description = bl_label = 'Length' @classmethod def poll(cls, context): - return Util.Selected1OrMoreCurves() + return util.Selected1OrMoreCurves() def execute(self, context): segments = internal.bezierSegments(bpy.context.object.data.splines, True) @@ -259,4 +277,15 @@ class Length(bpy.types.Operator): self.report({'INFO'}, bpy.utils.units.to_string(bpy.context.scene.unit_settings.system, 'LENGTH', length)) return {'FINISHED'} -operators = [Fillet, Boolean, Intersection, MergeEnds, Subdivide, Array, Circle, Length] +def register(): + for cls in classes: + bpy.utils.register_class(operators) + +def unregister(): + for cls in classes: + bpy.utils.unregister_class(operators) + +if __name__ == "__main__": + register() + +operators = [Fillet, Boolean, Intersection, HandleProjection, MergeEnds, Subdivide, Array, Circle, Length] diff --git a/curve_tools/curve_outline.py b/curve_tools/curve_outline.py deleted file mode 100644 index 6847e3c5..00000000 --- a/curve_tools/curve_outline.py +++ /dev/null @@ -1,112 +0,0 @@ -''' -by Yann Bertrand, january 2014. - -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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -END GPL LICENCE BLOCK -''' - -bl_info = { - "name": "Curve Outline", - "description": "creates an Outline", - "category": "Object", - "author": "Yann Bertrand (jimflim)", - "version": (0, 4), - "blender": (2, 69, 0), -} - -import bpy -from mathutils import Vector -from mathutils.geometry import intersect_line_line - - -def createOutline(curve, outline): - - for spline in curve.data.splines[:]: - p = spline.bezier_points - out = [] - - n = ((p[0].handle_right-p[0].co).normalized()-(p[0].handle_left-p[0].co).normalized()).normalized() - n = Vector((-n[1], n[0], n[2])) - o = p[0].co+outline*n - out.append(o) - - for i in range(1,len(p)): - n = ((p[i].handle_right-p[i].co).normalized()-(p[i].handle_left-p[i].co).normalized()).normalized() - n = Vector((-n[1], n[0], n[2])) - o = intersect_line_line(out[-1], (out[-1]+p[i].co-p[i-1].co), p[i].co, p[i].co+n)[0] - out.append(o) - - curve.data.splines.new('BEZIER') - if spline.use_cyclic_u: - curve.data.splines[-1].use_cyclic_u = True - p_out = curve.data.splines[-1].bezier_points - p_out.add(len(out)-1) - - for i in range(len(out)): - p_out[i].handle_left_type = 'FREE' - p_out[i].handle_right_type = 'FREE' - - p_out[i].co = out[i] - - if i<len(out)-1: - l = (p[i+1].co-p[i].co).length - l2 = (out[i]-out[i+1]).length - - if i==0: - p_out[i].handle_left = out[i] + ((p[i].handle_left-p[i].co)*l2/l) - if i<len(out)-1: - p_out[i+1].handle_left = out[i+1] + ((p[i+1].handle_left-p[i+1].co)*l2/l) - p_out[i].handle_right = out[i] + ((p[i].handle_right-p[i].co)*l2/l) - - for i in range(len(p)): - p_out[i].handle_left_type = p[i].handle_left_type - p_out[i].handle_right_type = p[i].handle_right_type - - return - - -class CurveOutline(bpy.types.Operator): - """Curve Outliner""" - bl_idname = "object._curve_outline" - bl_label = "Create Outline" - bl_options = {'REGISTER', 'UNDO'} - outline: bpy.props.FloatProperty(name="Amount", default=0.1) - - @classmethod - def poll(cls, context): - return (context.object is not None and - context.object.type == 'CURVE') - - def execute(self, context): - createOutline(context.object, self.outline) - return {'FINISHED'} - - def invoke(self, context, event): - return context.window_manager.invoke_props_popup(self, event) - -def menu_func(self, context): - self.layout.operator(CurveOutline.bl_idname) - -def register(): - bpy.utils.register_class(CurveOutline) - -def unregister(): - bpy.utils.unregister_class(CurveOutline) - -if __name__ == "__main__": - register() diff --git a/curve_tools/curve_remove_doubles.py b/curve_tools/curve_remove_doubles.py deleted file mode 100644 index 373b69c9..00000000 --- a/curve_tools/curve_remove_doubles.py +++ /dev/null @@ -1,110 +0,0 @@ -import bpy, mathutils - - -bl_info = { - 'name': 'Curve Remove Doubles', - 'author': 'Michael Soluyanov', - 'version': (1, 1), - 'blender': (2, 80, 0), - 'location': 'View3D > Context menu (W/RMB) > Remove Doubles', - 'description': 'Adds command "Remove Doubles" for curves', - 'category': 'Object' -} - -def main(context, distance = 0.01): - - obj = context.active_object - dellist = [] - - if bpy.ops.object.mode_set.poll(): - bpy.ops.object.mode_set(mode='EDIT') - - for spline in obj.data.splines: - if len(spline.bezier_points) > 1: - for i in range(0, len(spline.bezier_points)): - - if i == 0: - ii = len(spline.bezier_points) - 1 - else: - ii = i - 1 - - dot = spline.bezier_points[i]; - dot1 = spline.bezier_points[ii]; - - while dot1 in dellist and i != ii: - ii -= 1 - if ii < 0: - ii = len(spline.bezier_points)-1 - dot1 = spline.bezier_points[ii] - - if dot.select_control_point and dot1.select_control_point and (i!=0 or spline.use_cyclic_u): - - if (dot.co-dot1.co).length < distance: - # remove points and recreate hangles - dot1.handle_right_type = "FREE" - dot1.handle_right = dot.handle_right - dot1.co = (dot.co + dot1.co) / 2 - dellist.append(dot) - - else: - # Handles that are on main point position converts to vector, - # if next handle are also vector - if dot.handle_left_type == 'VECTOR' and (dot1.handle_right - dot1.co).length < distance: - dot1.handle_right_type = "VECTOR" - if dot1.handle_right_type == 'VECTOR' and (dot.handle_left - dot.co).length < distance: - dot.handle_left_type = "VECTOR" - - - - bpy.ops.curve.select_all(action = 'DESELECT') - - for dot in dellist: - dot.select_control_point = True - - count = len(dellist) - - bpy.ops.curve.delete(type = 'VERT') - - bpy.ops.curve.select_all(action = 'SELECT') - - return count - - - -class CurveRemvDbs(bpy.types.Operator): - """Merge consecutive points that are near to each other""" - bl_idname = 'curve.remove_doubles' - bl_label = 'Remove Doubles' - bl_options = {'REGISTER', 'UNDO'} - - distance: bpy.props.FloatProperty(name = 'Distance', default = 0.01) - - @classmethod - def poll(cls, context): - obj = context.active_object - return (obj and obj.type == 'CURVE') - - def execute(self, context): - removed=main(context, self.distance) - self.report({'INFO'}, "Removed %d bezier points" % removed) - return {'FINISHED'} - - - - -def menu_func(self, context): - self.layout.operator(CurveRemvDbs.bl_idname, text='Remove Doubles') - -def register(): - bpy.utils.register_class(CurveRemvDbs) - bpy.types.VIEW3D_MT_edit_curve_context_menu.append(menu_func) - -def unregister(): - bpy.utils.unregister_class(CurveRemvDbs) - bpy.types.VIEW3D_MT_edit_curve_context_menu.remove(menu_func) - -if __name__ == "__main__": - register() - - - diff --git a/curve_tools/exports.py b/curve_tools/exports.py index b3b7d900..130fb2a7 100644 --- a/curve_tools/exports.py +++ b/curve_tools/exports.py @@ -224,4 +224,15 @@ class GCodeExport(bpy.types.Operator, ExportHelper): f.write(speed_code+' X{:.3f} Y{:.3f} Z{:.3f}\n'.format(position[0], position[1], position[2])) return {'FINISHED'} +def register(): + for cls in classes: + bpy.utils.register_class(operators) + +def unregister(): + for cls in classes: + bpy.utils.unregister_class(operators) + +if __name__ == "__main__": + register() + operators = [SvgExport, GCodeExport] diff --git a/curve_tools/fillet.py b/curve_tools/fillet.py new file mode 100644 index 00000000..3bb3e492 --- /dev/null +++ b/curve_tools/fillet.py @@ -0,0 +1,143 @@ +# ##### 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 ##### + +bl_info = { + 'name': 'Curve Fillet', + 'author': 'Spivak Vladimir (cwolf3d)', + 'version': (0, 0, 1), + 'blender': (2, 80, 0), + 'location': 'Curve Tools addon. (N) Panel', + 'description': 'Various types of fillet (chamfering)', + 'warning': '', # used for warning icon and text in addons panel + 'wiki_url': '', + 'tracker_url': '', + 'category': 'Curve'} + + +import bpy +from bpy.props import * +from bpy_extras import object_utils, view3d_utils +from mathutils import * +from math import * + +def click(self, context, event): + bpy.ops.object.mode_set(mode = 'EDIT') + bpy.context.view_layer.update() + + +def remove_handler(handlers): + for handler in handlers: + try: + bpy.types.SpaceView3D.draw_handler_remove(handler, 'WINDOW') + except: + pass + for handler in handlers: + handlers.remove(handler) + + +class Fillet(bpy.types.Operator): + bl_idname = "curvetools.fillet" + bl_label = "Curve Fillet" + bl_description = "Curve Fillet" + bl_options = {'REGISTER', 'UNDO'} + + x: IntProperty(name="x", description="x") + y: IntProperty(name="y", description="y") + location3D: FloatVectorProperty(name = "", + description = "Start location", + default = (0.0, 0.0, 0.0), + subtype = 'XYZ') + + handlers = [] + + def execute(self, context): + self.report({'INFO'}, "ESC or TAB - cancel") + bpy.ops.object.mode_set(mode = 'EDIT') + + # color change in the panel + self.path_color = bpy.context.scene.curvetools.path_color + self.path_thickness = bpy.context.scene.curvetools.path_thickness + + def modal(self, context, event): + context.area.tag_redraw() + + if event.type in {'ESC', 'TAB'}: # Cancel + remove_handler(self.handlers) + return {'CANCELLED'} + + if event.type in {'X', 'DEL'}: # Cancel + remove_handler(self.handlers) + bpy.ops.curve.delete(type='VERT') + return {'RUNNING_MODAL'} + + elif event.alt and event.shift and event.type == 'LEFTMOUSE': + click(self, context, event) + + elif event.alt and not event.shift and event.type == 'LEFTMOUSE': + remove_handler(self.handlers) + bpy.ops.curve.select_all(action='DESELECT') + click(self, context, event) + + elif event.alt and event.type == 'RIGHTMOUSE': + remove_handler(self.handlers) + bpy.ops.curve.select_all(action='DESELECT') + click(self, context, event) + + elif event.alt and not event.shift and event.shift and event.type == 'RIGHTMOUSE': + click(self, context, event) + + elif event.type == 'A': + remove_handler(self.handlers) + bpy.ops.curve.select_all(action='DESELECT') + + elif event.type == 'MOUSEMOVE': # + self.x = event.mouse_x + self.y = event.mouse_y + region = bpy.context.region + rv3d = bpy.context.space_data.region_3d + self.location3D = view3d_utils.region_2d_to_location_3d( + region, + rv3d, + (event.mouse_region_x, event.mouse_region_y), + (0.0, 0.0, 0.0) + ) + + return {'PASS_THROUGH'} + + def invoke(self, context, event): + self.execute(context) + context.window_manager.modal_handler_add(self) + return {'RUNNING_MODAL'} + + @classmethod + def poll(cls, context): + return (context.object is not None and + context.object.type == 'CURVE') + +def register(): + for cls in classes: + bpy.utils.register_class(operators) + +def unregister(): + for cls in classes: + bpy.utils.unregister_class(operators) + +if __name__ == "__main__": + register() + +operators = [Fillet] diff --git a/curve_tools/internal.py b/curve_tools/internal.py index 6741bb22..e967fc6e 100644 --- a/curve_tools/internal.py +++ b/curve_tools/internal.py @@ -408,6 +408,25 @@ def bezierMultiIntersection(segments): prepareSegmentIntersections(segments) subdivideBezierSegments(segments) +def bezierProjectHandles(segments): + insertions = [] + index_offset = 0 + for segment in segments: + if len(insertions) > 0 and insertions[-1][0] != segment['spline']: + index_offset = 0 + points = bezierSegmentPoints(segment['beginPoint'], segment['endPoint']) + paramA, paramB, pointA, pointB = nearestPointOfLines(points[0], points[1]-points[0], points[3], points[2]-points[3]) + if pointA and pointB: + segment['cuts'].append({'param': 0.5}) + insertions.append((segment['spline'], segment['beginIndex']+1+index_offset, (pointA+pointB)*0.5)) + index_offset += 1 + subdivideBezierSegments(segments) + for insertion in insertions: + bezier_point = insertion[0].bezier_points[insertion[1]] + bezier_point.co = insertion[2] + bezier_point.handle_left_type = 'VECTOR' + bezier_point.handle_right_type = 'VECTOR' + def bezierSubivideAt(points, params): if len(params) == 0: return [] diff --git a/curve_tools/CurveIntersections.py b/curve_tools/intersections.py index 06254701..77f19861 100644 --- a/curve_tools/CurveIntersections.py +++ b/curve_tools/intersections.py @@ -1,7 +1,7 @@ import bpy -from . import Math -from . import Curves -from . import Util +from . import mathematics +from . import curves +from . import util from mathutils import Vector @@ -58,7 +58,7 @@ class BezierSegmentsIntersector: Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20) Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21) - intersectionPointData = Math.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance) + intersectionPointData = mathematics.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance) if intersectionPointData is None: continue @@ -94,15 +94,15 @@ class BezierSegmentsIntersector: Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20) Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21) - intersectionPointData = Math.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance) + intersectionPointData = mathematics.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance) if intersectionPointData is None: continue # intersection point can't be an existing point intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / (fltNrSamples1)) worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter) - if (Math.IsSamePoint(P0, worldPoint1, limitDistance)) or \ - (Math.IsSamePoint(P1, worldPoint1, limitDistance)): + if (mathematics.IsSamePoint(P0, worldPoint1, limitDistance)) or \ + (mathematics.IsSamePoint(P1, worldPoint1, limitDistance)): intersectionPoint1 = None else: @@ -112,8 +112,8 @@ class BezierSegmentsIntersector: intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / (fltNrSamples2)) worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter) - if (Math.IsSamePoint(Q0, worldPoint2, limitDistance)) or \ - (Math.IsSamePoint(Q1, worldPoint2, limitDistance)): + if (mathematics.IsSamePoint(Q0, worldPoint2, limitDistance)) or \ + (mathematics.IsSamePoint(Q1, worldPoint2, limitDistance)): intersectionPoint2 = None else: @@ -143,7 +143,7 @@ class BezierSegmentsIntersector: Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20) Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21) - intersectionPointData = Math.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR) + intersectionPointData = mathematics.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR) if intersectionPointData is None: continue @@ -183,15 +183,15 @@ class BezierSegmentsIntersector: Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20) Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21) - intersectionPointData = Math.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR) + intersectionPointData = mathematics.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR) if intersectionPointData is None: continue # intersection point can't be an existing point intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / (fltNrSamples1)) worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter) - if (Math.IsSamePoint(P0, worldPoint1, limitDistance)) or \ - (Math.IsSamePoint(P1, worldPoint1, limitDistance)): + if (mathematics.IsSamePoint(P0, worldPoint1, limitDistance)) or \ + (mathematics.IsSamePoint(P1, worldPoint1, limitDistance)): intersectionPoint1 = None else: @@ -201,8 +201,8 @@ class BezierSegmentsIntersector: intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / (fltNrSamples2)) worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter) - if (Math.IsSamePoint(Q0, worldPoint2, limitDistance)) or \ - (Math.IsSamePoint(Q1, worldPoint2, limitDistance)): + if (mathematics.IsSamePoint(Q0, worldPoint2, limitDistance)) or \ + (mathematics.IsSamePoint(Q1, worldPoint2, limitDistance)): intersectionPoint2 = None else: @@ -232,7 +232,7 @@ class BezierSegmentsIntersector: Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20) Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21) - intersectionPointData = Math.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV) + intersectionPointData = mathematics.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV) if intersectionPointData is None: continue @@ -272,15 +272,15 @@ class BezierSegmentsIntersector: Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20) Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21) - intersectionPointData = Math.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV) + intersectionPointData = mathematics.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV) if intersectionPointData is None: continue # intersection point can't be an existing point intersectionSegment1Parameter = segPar10 + (intersectionPointData[0] / fltNrSamples1) worldPoint1 = self.worldMatrix1 @ self.segment1.CalcPoint(parameter=intersectionSegment1Parameter) - if (Math.IsSamePoint(P0, worldPoint1, limitDistance)) or \ - (Math.IsSamePoint(P1, worldPoint1, limitDistance)): + if (mathematics.IsSamePoint(P0, worldPoint1, limitDistance)) or \ + (mathematics.IsSamePoint(P1, worldPoint1, limitDistance)): intersectionPoint1 = None else: @@ -290,8 +290,8 @@ class BezierSegmentsIntersector: intersectionSegment2Parameter = segPar20 + (intersectionPointData[1] / fltNrSamples2) worldPoint2 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=intersectionSegment2Parameter) - if (Math.IsSamePoint(Q0, worldPoint2, limitDistance)) or \ - (Math.IsSamePoint(Q1, worldPoint2, limitDistance)): + if (mathematics.IsSamePoint(Q0, worldPoint2, limitDistance)) or \ + (mathematics.IsSamePoint(Q1, worldPoint2, limitDistance)): intersectionPoint2 = None else: @@ -341,7 +341,7 @@ class BezierSegmentsIntersector: Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20) Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21) - intersectionPointData = Math.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance) + intersectionPointData = mathematics.CalcIntersectionPointLineSegments(P0, P1, Q0, Q1, limitDistance) if intersectionPointData is None: continue @@ -382,7 +382,7 @@ class BezierSegmentsIntersector: Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20) Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21) - intersectionPointData = Math.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR) + intersectionPointData = mathematics.CalcIntersectionPointsLineSegmentsDIR(P0, P1, Q0, Q1, algoDIR) if intersectionPointData is None: continue @@ -423,7 +423,7 @@ class BezierSegmentsIntersector: Q0 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar20) Q1 = self.worldMatrix2 @ self.segment2.CalcPoint(parameter=segPar21) - intersectionPointData = Math.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV) + intersectionPointData = mathematics.CalcIntersectionPointsLineSegmentsPOV(P0, P1, Q0, Q1, algoPOV) if intersectionPointData is None: continue @@ -508,8 +508,8 @@ class CurvesIntersector: if blenderActiveCurve == blenderOtherCurve: blenderOtherCurve = selObjects[1] - aCurve = Curves.Curve(blenderActiveCurve) - oCurve = Curves.Curve(blenderOtherCurve) + aCurve = curves.Curve(blenderActiveCurve) + oCurve = curves.Curve(blenderOtherCurve) return CurvesIntersector(aCurve, oCurve) @@ -528,7 +528,7 @@ class CurvesIntersector: algo = bpy.context.scene.curvetools.IntersectCurvesAlgorithm if algo == 'From View': - regionView3D = Util.GetFirstRegionView3D() + regionView3D = util.GetFirstRegionView3D() if regionView3D is None: print("### ERROR: regionView3D is None. Stopping.") return diff --git a/curve_tools/Math.py b/curve_tools/mathematics.py index 4a61af4d..4a61af4d 100644 --- a/curve_tools/Math.py +++ b/curve_tools/mathematics.py diff --git a/curve_tools/outline.py b/curve_tools/outline.py new file mode 100644 index 00000000..66cc29e4 --- /dev/null +++ b/curve_tools/outline.py @@ -0,0 +1,118 @@ +''' +by Yann Bertrand, january 2014. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +END GPL LICENCE BLOCK +''' + +bl_info = { + "name": "Curve Outline", + "description": "creates an Outline", + "category": "Object", + "author": "Yann Bertrand (jimflim)", + "version": (0, 4), + "blender": (2, 69, 0), +} + +import bpy +from mathutils import Vector +from mathutils.geometry import intersect_line_line + +from . import util + + +def createOutline(curve, outline): + + for spline in curve.data.splines[:]: + if spline.type == 'BEZIER': + p = spline.bezier_points + out = [] + + n = ((p[0].handle_right-p[0].co).normalized()-(p[0].handle_left-p[0].co).normalized()).normalized() + n = Vector((-n[1], n[0], n[2])) + o = p[0].co+outline*n + out.append(o) + + for i in range(1,len(p)): + n = ((p[i].handle_right-p[i].co).normalized()-(p[i].handle_left-p[i].co).normalized()).normalized() + n = Vector((-n[1], n[0], n[2])) + o = intersect_line_line(out[-1], (out[-1]+p[i].co-p[i-1].co), p[i].co, p[i].co+n)[0] + out.append(o) + + curve.data.splines.new('BEZIER') + if spline.use_cyclic_u: + curve.data.splines[-1].use_cyclic_u = True + p_out = curve.data.splines[-1].bezier_points + p_out.add(len(out)-1) + + for i in range(len(out)): + p_out[i].handle_left_type = 'FREE' + p_out[i].handle_right_type = 'FREE' + + p_out[i].co = out[i] + + if i<len(out)-1: + l = (p[i+1].co-p[i].co).length + l2 = (out[i]-out[i+1]).length + + if i==0: + p_out[i].handle_left = out[i] + ((p[i].handle_left-p[i].co)*l2/l) + if i<len(out)-1: + p_out[i+1].handle_left = out[i+1] + ((p[i+1].handle_left-p[i+1].co)*l2/l) + p_out[i].handle_right = out[i] + ((p[i].handle_right-p[i].co)*l2/l) + + for i in range(len(p)): + p_out[i].handle_left_type = p[i].handle_left_type + p_out[i].handle_right_type = p[i].handle_right_type + + return + + +class CurveOutline(bpy.types.Operator): + """Curve Outliner""" + bl_idname = "curvetools.outline" + bl_label = "Create Outline" + bl_options = {'REGISTER', 'UNDO'} + outline: bpy.props.FloatProperty(name="Amount", default=0.1) + + @classmethod + def poll(cls, context): + return util.Selected1OrMoreCurves() + + def execute(self, context): + createOutline(context.object, self.outline) + return {'FINISHED'} + + def invoke(self, context, event): + return context.window_manager.invoke_props_popup(self, event) + +def menu_func(self, context): + self.layout.operator(CurveOutline.bl_idname) + +def register(): + for cls in classes: + bpy.utils.register_class(operators) + +def unregister(): + for cls in classes: + bpy.utils.unregister_class(operators) + +if __name__ == "__main__": + register() + +operators = [CurveOutline] diff --git a/curve_tools/PathFinder.py b/curve_tools/path_finder.py index ab11a4e7..366f9bcc 100644 --- a/curve_tools/PathFinder.py +++ b/curve_tools/path_finder.py @@ -41,12 +41,8 @@ from bpy_extras import object_utils, view3d_utils from mathutils import * from math import * -from . import Properties -from . import Curves -from . import CurveIntersections -from . import Util -from . import Surfaces -from . import Math +from . import mathematics +from . import util def get_bezier_points(spline, matrix_world): point_list = [] @@ -55,7 +51,7 @@ def get_bezier_points(spline, matrix_world): for i in range(0, len_bezier_points - 1): point_list.extend([matrix_world @ spline.bezier_points[i].co]) for t in range(0, 100, 2): - h = Math.subdivide_cubic_bezier(spline.bezier_points[i].co, + h = mathematics.subdivide_cubic_bezier(spline.bezier_points[i].co, spline.bezier_points[i].handle_right, spline.bezier_points[i + 1].handle_left, spline.bezier_points[i + 1].co, @@ -64,7 +60,7 @@ def get_bezier_points(spline, matrix_world): if spline.use_cyclic_u and len_bezier_points > 2: point_list.extend([matrix_world @ spline.bezier_points[len_bezier_points - 1].co]) for t in range(0, 100, 2): - h = Math.subdivide_cubic_bezier(spline.bezier_points[len_bezier_points - 1].co, + h = mathematics.subdivide_cubic_bezier(spline.bezier_points[len_bezier_points - 1].co, spline.bezier_points[len_bezier_points - 1].handle_right, spline.bezier_points[0].handle_left, spline.bezier_points[0].co, @@ -160,7 +156,7 @@ def click(self, context, event): if i < len_bezier_points - 1: for t in range(0, 100, 2): - h = Math.subdivide_cubic_bezier(spline.bezier_points[i].co, + h = mathematics.subdivide_cubic_bezier(spline.bezier_points[i].co, spline.bezier_points[i].handle_right, spline.bezier_points[i + 1].handle_left, spline.bezier_points[i + 1].co, @@ -172,7 +168,7 @@ def click(self, context, event): if spline.use_cyclic_u and len_bezier_points > 2: for t in range(0, 100, 2): - h = Math.subdivide_cubic_bezier(spline.bezier_points[len_bezier_points - 1].co, + h = mathematics.subdivide_cubic_bezier(spline.bezier_points[len_bezier_points - 1].co, spline.bezier_points[len_bezier_points - 1].handle_right, spline.bezier_points[0].handle_left, spline.bezier_points[0].co, @@ -312,14 +308,18 @@ class PathFinder(bpy.types.Operator): @classmethod def poll(cls, context): - return (context.object is not None and - context.object.type == 'CURVE') + return util.Selected1OrMoreCurves() def register(): - bpy.utils.register_class(PathFinder) + for cls in classes: + bpy.utils.register_class(operators) def unregister(): - bpy.utils.unregister_class(PathFinder) + for cls in classes: + bpy.utils.unregister_class(operators) if __name__ == "__main__": register() + + +operators = [PathFinder] diff --git a/curve_tools/remove_doubles.py b/curve_tools/remove_doubles.py new file mode 100644 index 00000000..151b19b0 --- /dev/null +++ b/curve_tools/remove_doubles.py @@ -0,0 +1,135 @@ +import bpy, mathutils +from . import util + +bl_info = { + 'name': 'Curve Remove Doubles', + 'author': 'Michael Soluyanov', + 'version': (1, 1), + 'blender': (2, 80, 0), + 'location': 'View3D > Context menu (W/RMB) > Remove Doubles', + 'description': 'Adds comand "Remove Doubles" for curves', + 'category': 'Add Curve' +} + +def main(context, distance = 0.01): + + selected_Curves = util.GetSelectedCurves() + if bpy.ops.object.mode_set.poll(): + bpy.ops.object.mode_set(mode='EDIT') + + for curve in selected_Curves: + bezier_dellist = [] + dellist = [] + + for spline in curve.data.splines: + if spline.type == 'BEZIER': + if len(spline.bezier_points) > 1: + for i in range(0, len(spline.bezier_points)): + + if i == 0: + ii = len(spline.bezier_points) - 1 + else: + ii = i - 1 + + dot = spline.bezier_points[i]; + dot1 = spline.bezier_points[ii]; + + while dot1 in bezier_dellist and i != ii: + ii -= 1 + if ii < 0: + ii = len(spline.bezier_points)-1 + dot1 = spline.bezier_points[ii] + + if dot.select_control_point and dot1.select_control_point and (i!=0 or spline.use_cyclic_u): + + if (dot.co-dot1.co).length < distance: + # remove points and recreate hangles + dot1.handle_right_type = "FREE" + dot1.handle_right = dot.handle_right + dot1.co = (dot.co + dot1.co) / 2 + bezier_dellist.append(dot) + + else: + # Handles that are on main point position converts to vector, + # if next handle are also vector + if dot.handle_left_type == 'VECTOR' and (dot1.handle_right - dot1.co).length < distance: + dot1.handle_right_type = "VECTOR" + if dot1.handle_right_type == 'VECTOR' and (dot.handle_left - dot.co).length < distance: + dot.handle_left_type = "VECTOR" + else: + if len(spline.points) > 1: + for i in range(0, len(spline.points)): + + if i == 0: + ii = len(spline.points) - 1 + else: + ii = i - 1 + + dot = spline.points[i]; + dot1 = spline.points[ii]; + + while dot1 in dellist and i != ii: + ii -= 1 + if ii < 0: + ii = len(spline.points)-1 + dot1 = spline.points[ii] + + if dot.select and dot1.select and (i!=0 or spline.use_cyclic_u): + + if (dot.co-dot1.co).length < distance: + dot1.co = (dot.co + dot1.co) / 2 + dellist.append(dot) + + bpy.ops.curve.select_all(action = 'DESELECT') + + for dot in bezier_dellist: + dot.select_control_point = True + + for dot in dellist: + dot.select = True + + bezier_count = len(bezier_dellist) + count = len(dellist) + + bpy.ops.curve.delete(type = 'VERT') + + bpy.ops.curve.select_all(action = 'DESELECT') + + return bezier_count + count + + + +class CurveRemvDbs(bpy.types.Operator): + """Merge consecutive points that are near to each other""" + bl_idname = 'curvetools.remove_doubles' + bl_label = 'Remove Doubles' + bl_options = {'REGISTER', 'UNDO'} + + distance: bpy.props.FloatProperty(name = 'Distance', default = 0.01) + + @classmethod + def poll(cls, context): + return util.Selected1Curve() + + def execute(self, context): + removed=main(context, self.distance) + self.report({'INFO'}, "Removed %d bezier points" % removed) + return {'FINISHED'} + + + +def menu_func(self, context): + self.layout.operator(CurveRemvDbs.bl_idname, text='Remove Doubles') + +def register(): + bpy.utils.register_class(CurveRemvDbs) + bpy.types.VIEW3D_MT_edit_curve_context_menu.append(menu_func) + +def unregister(): + bpy.utils.unregister_class(CurveRemvDbs) + bpy.types.VIEW3D_MT_edit_curve_context_menu.remove(menu_func) + +if __name__ == "__main__": + register() + +operators = [CurveRemvDbs] diff --git a/curve_tools/ShowCurveResolution.py b/curve_tools/show_resolution.py index 6386fe4d..78acc1e3 100644 --- a/curve_tools/ShowCurveResolution.py +++ b/curve_tools/show_resolution.py @@ -18,7 +18,7 @@ # -# LOAD MODULE # +# LOAD MODUL # import bpy from bpy import * from bpy.props import * @@ -79,7 +79,7 @@ def draw(self, context, splines, curve_vertcolor, matrix_world): class ShowCurveResolution(bpy.types.Operator): - bl_idname = "curve.show_resolution" + bl_idname = "curvetools.show_resolution" bl_label = "Show Curve Resolution" bl_description = "Show curve Resolution / [ESC] - remove" @@ -129,3 +129,18 @@ class ShowCurveResolution(bpy.types.Operator): def poll(cls, context): return (context.object is not None and context.object.type == 'CURVE') + +def register(): + for cls in classes: + bpy.utils.register_class(operators) + +def unregister(): + for cls in classes: + bpy.utils.unregister_class(operators) + +if __name__ == "__main__": + register() + +operators = [ + ShowCurveResolution, + ] diff --git a/curve_tools/SplinesSequence.py b/curve_tools/splines_sequence.py index c64ceec1..5d11aedf 100644 --- a/curve_tools/SplinesSequence.py +++ b/curve_tools/splines_sequence.py @@ -89,7 +89,7 @@ def draw(self, context, splines, sequence_color, font_thickness, font_size, matr i += font_size + font_size * 0.5 class ShowSplinesSequence(bpy.types.Operator): - bl_idname = "curve.show_splines_sequence" + bl_idname = "curvetools.show_splines_sequence" bl_label = "Show Splines Sequence" bl_description = "Show Splines Sequence / [ESC] - remove" @@ -229,7 +229,7 @@ def rearrange(dataCurve, select_spline, command): rearrangesplines(dataCurve, select_spline, select_spline - 1) class RearrangeSpline(bpy.types.Operator): - bl_idname = "curve.rearrange_spline" + bl_idname = "curvetools.rearrange_spline" bl_label = "Rearrange Spline" bl_description = "Rearrange Spline" @@ -273,3 +273,16 @@ class RearrangeSpline(bpy.types.Operator): def poll(cls, context): return (context.object is not None and context.object.type == 'CURVE') + +def register(): + for cls in classes: + bpy.utils.register_class(operators) + +def unregister(): + for cls in classes: + bpy.utils.unregister_class(operators) + +if __name__ == "__main__": + register() + +operators = [ShowSplinesSequence, RearrangeSpline] diff --git a/curve_tools/toolpath.py b/curve_tools/toolpath.py index 8353f7ac..2b422280 100644 --- a/curve_tools/toolpath.py +++ b/curve_tools/toolpath.py @@ -21,7 +21,7 @@ from mathutils import Vector, Matrix from . import internal class OffsetCurve(bpy.types.Operator): - bl_idname = 'curve.add_toolpath_offset_curve' + bl_idname = 'curvetools.add_toolpath_offset_curve' bl_description = bl_label = 'Offset Curve' bl_options = {'REGISTER', 'UNDO'} @@ -64,7 +64,7 @@ class OffsetCurve(bpy.types.Operator): return {'FINISHED'} class SliceMesh(bpy.types.Operator): - bl_idname = 'curve.add_toolpath_slice_mesh' + bl_idname = 'curvetools.add_toolpath_slice_mesh' bl_description = bl_label = 'Slice Mesh' bl_options = {'REGISTER', 'UNDO'} @@ -116,7 +116,7 @@ class SliceMesh(bpy.types.Operator): return {'FINISHED'} class DiscretizeCurve(bpy.types.Operator): - bl_idname = 'curve.add_toolpath_discretize_curve' + bl_idname = 'curvetools.add_toolpath_discretize_curve' bl_description = bl_label = 'Discretize Curve' bl_options = {'REGISTER', 'UNDO'} @@ -151,7 +151,7 @@ class DiscretizeCurve(bpy.types.Operator): return {'FINISHED'} class Truncate(bpy.types.Operator): - bl_idname = 'curve.add_toolpath_truncate' + bl_idname = 'curvetools.add_toolpath_truncate' bl_description = bl_label = 'Truncate' bl_options = {'REGISTER', 'UNDO'} @@ -197,7 +197,7 @@ class Truncate(bpy.types.Operator): return {'FINISHED'} class RectMacro(bpy.types.Operator): - bl_idname = 'curve.add_toolpath_rect_macro' + bl_idname = 'curvetools.add_toolpath_rect_macro' bl_description = bl_label = 'Rect Macro' bl_options = {'REGISTER', 'UNDO'} @@ -233,7 +233,7 @@ class RectMacro(bpy.types.Operator): return {'FINISHED'} class DrillMacro(bpy.types.Operator): - bl_idname = 'curve.add_toolpath_drill_macro' + bl_idname = 'curvetools.add_toolpath_drill_macro' bl_description = bl_label = 'Drill Macro' bl_options = {'REGISTER', 'UNDO'} @@ -284,4 +284,15 @@ class DrillMacro(bpy.types.Operator): internal.addPolygonSpline(bpy.context.object, False, vertices, weights) return {'FINISHED'} +def register(): + for cls in classes: + bpy.utils.register_class(operators) + +def unregister(): + for cls in classes: + bpy.utils.unregister_class(operators) + +if __name__ == "__main__": + register() + operators = [OffsetCurve, SliceMesh, DiscretizeCurve, Truncate, RectMacro, DrillMacro] |