# Demo of an external defiend tool which accesses the functionality # of Geometry Sketcher # In order to use the script make sure Geometry Sketcher is installed and enabled # and the python module "scipy" is available. # The script converts freehand strokes of the acive Grease Pencil object on # the X-Z Plane to Geometry Sketcher lines and constrains them to be vertical # or horizontal if the angle is below some threshold. # If your're using the script on a new blend file make sure you've run the "Add Sketch" # operator at least once, otherwise the required workplane isn't initialized. # To use it simply draw some GP lines and hit "Run Script" import bpy from mathutils import Vector from scipy.optimize import curve_fit def linear_func(x, m, b): return m * x + b def linear_func_inv(y, m, b): return (y - b) / m def get_closest_match(x, y, m, b): p = Vector((x, y)) y1 = linear_func(x, m, b) p1 = Vector((x, y1)) l1 = (p1 - p).length x2 = linear_func_inv(y, m, b) p2 = Vector((x2, y)) l2 = (p2 - p).length if l1 < l2: return p1 else: return p2 context=bpy.context ob = context.active_object if not ob.type == 'GPENCIL': pass else: bgs = context.scene.sketcher sketch = bgs.entities.sketches.get(ob.name) if not sketch: wp = bgs.entities.workplanes[1] sketch = bgs.entities.add_sketch(wp) sketch.name = ob.name frame = ob.data.layers['Lines'].active_frame while frame.strokes: s = frame.strokes[0] # TODO: Get the drawing plane xdata = [p.co.x for p in s.points] zdata = [p.co.z for p in s.points] popt, _ = curve_fit(linear_func, xdata, zdata) m, b = popt start = s.points[0] vec1 = Vector(get_closest_match(start.co.x, start.co.z, m, b)) end = s.points[-1] vec2 = Vector(get_closest_match(end.co.x, end.co.z, m, b)) # Check if an existing point is nearby p1, p2 = None, None threshold = 1 for point in bgs.entities.points2D: if (vec1 - point.co).length < threshold: p1 = point continue if (vec2 - point.co).length < threshold: p2 = point continue # Create new points if nothing is closeby if not p1: p1 = bgs.entities.add_point_2d(vec1, sketch) if not p2: p2 = bgs.entities.add_point_2d(vec2, sketch) line = bgs.entities.add_line_2d(p1, p2, sketch) c = None if abs(m) < 0.2: c = bgs.constraints.new_from_type("HORIZONTAL") elif abs(m) > 6: c = bgs.constraints.new_from_type("VERTICAL") if c: c.entity1 = line c.sketch = sketch # Delete Stroke frame.strokes.remove(s) sketch.solve(context)