def from_blender_bezier_curve(self, bez_points, count=10): # Get a list of points distributed along the curve. points_on_curve = interpolate_bezier(bez_points[0].co, bez_points[0].handle_right, bez_points[1].handle_left, bez_points[1].co, count) return points_on_curve
def divide(self, number_of_segments): m, l, r = self.control_point_coordinates() points = [ list(i) for i in interpolate_bezier(m[0], r[0], l[1], m[1], number_of_segments + 1) ] return [add_vectors(self.location, point) for point in points]
def get_points(spline, clean=True, res=False): cyclic = True knots = spline.bezier_points if len(knots) < 2: return r = (res if res else spline.resolution_u) + 1 segments = len(knots) if not spline.use_cyclic_u: cyclic = False segments -= 1 master_point_list = [] for i in range(segments): inext = (i + 1) % len(knots) knot1 = knots[i].co handle1 = knots[i].handle_right handle2 = knots[inext].handle_left knot2 = knots[inext].co bezier = knot1, handle1, handle2, knot2, r points = interpolate_bezier(*bezier) master_point_list.extend(points) # some clean up to remove consecutive doubles, this could be smarter... if clean: old = master_point_list good = [v for i, v in enumerate(old[:-1]) if not old[i] == old[i+1]] good.append(old[-1]) return good, cyclic return master_point_list, cyclic
def get_points(spline, matrix_world): bezier_points = spline.bezier_points if len(bezier_points) < 2: return [] r = spline.resolution_u + 1 if r < 2: return [] segments = len(bezier_points) if not spline.use_cyclic_u: segments -= 1 point_list = [] for i in range(segments): inext = (i + 1) % len(bezier_points) bezier_points1 = matrix_world @ bezier_points[i].co handle1 = matrix_world @ bezier_points[i].handle_right handle2 = matrix_world @ bezier_points[inext].handle_left bezier_points2 = matrix_world @ bezier_points[inext].co bezier = bezier_points1, handle1, handle2, bezier_points2, r points = interpolate_bezier(*bezier) point_list.extend(points) return point_list
def divide(self, number_of_segments): middle, left, right = self.handles() n = number_of_segments + 1 points = [ list(i) for i in interpolate_bezier(middle[0], right[0], left[1], middle[1], n) ] return [add_vectors(self.xyz, point) for point in points]
def getSplinePoints(self,spline,scale): knots = spline.bezier_points if len(knots) < 2: return # verts per segment r = spline.resolution_u + 1 # segments in spline segments = len(knots) if not spline.use_cyclic_u: segments -= 1 master_point_list = [] for i in range(segments): inext = (i + 1) % len(knots) knot1 = knots[i].co handle1 = knots[i].handle_right handle2 = knots[inext].handle_left knot2 = knots[inext].co bezier = knot1, handle1, handle2, knot2, r points = interpolate_bezier(*bezier) master_point_list.extend(points) #scaling for i in range(len(master_point_list)): p = master_point_list[i] p.x *= scale p.y *= scale p.z *= scale master_point_list[i]=p # some clean up to remove consecutive doubles, this could be smarter... old = master_point_list good = [v for i, v in enumerate(old[:-1]) if not old[i] == old[i+1]] good.append(old[-1]) #remove points too close to each other (distance<treshold) i = 0 while i < len(good): if i==len(good)-1: j = 0 else: j = i+1 if (good[j]-good[i]).length<0.1: del good[j] else: i += 1 #remove last index if equal to first one if good[0]==good[len(good)-1]: good = good[:len(good)-1] return good
def test_bezier_blender(): degree = 3 ctrl_points = [ Vector(tuple(sample(range(100), 3))) for _ in range(degree + 1) ] value = interpolate_bezier(ctrl_points[0], ctrl_points[1], ctrl_points[2], ctrl_points[3], 10001)[5000] for i in range(3): assert fit_curve.bezier_ii(degree, ctrl_points, .5)[i] == pytest.approx(value[i], 0.001)
def calc_curve_geo(self): self.curve_geo.clear() for p, po in enumerate(self.points): if p > 0: prev_po = self.points[p-1] seg_pos = interpolate_bezier( prev_po.co, prev_po.handle_right, po.handle_left, po.co, self.resolution) self.curve_geo += seg_pos return
def interpolate_curve_segment(self, i, resolution): n_points = len(self.curve_points) p0h = self.curve_points[(i - 1) % n_points] p0 = self.curve_points[i] p1 = self.curve_points[(i + 1) % n_points] p1h = self.curve_points[(i + 2) % n_points] weight1 = p0["weight"] weight2 = p1["weight"] knot1 = p0["2d"] knot2 = p1["2d"] if max(weight1, weight2) <= 1e-6: return [knot1, knot2] if self.round_corners: handle1 = p0h["2d"] handle2 = p1h["2d"] #r1 = min(weight1, self.max_radius(handle1, knot1, knot2)) #r2 = min(weight2, self.max_radius(knot1, knot2, handle2)) r1 = p0["r"] r2 = p1["r"] vertices = [] n = resolution // 2 if r1 <= 1e-6: vertices.append(p0["2d"]) else: vertices.extend( self.interpolate_arc(handle1, knot1, knot2, r1, n)) if n == 0: vertices = vertices[1:] if r2 <= 1e-6: vertices.append(p1["2d"]) else: vertices.extend( self.interpolate_arc(handle2, knot2, knot1, r2, n, reverse=True)) return vertices else: handle1 = knot1 + (knot2 - p0h["2d"]) * (weight1 * 0.5) handle2 = knot2 + (knot1 - p1h["2d"]) * (weight2 * 0.5) return interpolate_bezier(knot1, handle1, handle2, knot2, max(resolution, 2))
def bezier_curve_interpolate(curve, number=3): """Interpolate points along a Bezier curve object. Parameters: curve (obj): Bezier curve object. number (int): Number of interpolation points. Returns: list: Interpolated points [x, y, z.] """ co, left, right = bezier_curve_points(curve) vectors = interpolate_bezier(co[0], right[0], left[1], co[1], number) points = [list(point) for point in vectors] return points
def make_curve_splines(data, ob): context = bpy.context mat = ob.matrix_world if data.coordinate == 'active': ''' v * mat * actob.matrix_world.inverted() == \ v * (actob.matrix_world.inverted() * mat) ''' actob = data.actob if actob: quat = actob.matrix_world.to_3x3().to_quaternion() m4 = quat.to_matrix().to_4x4() mat = m4.inverted() * mat pysplines = data.pysplines_dict[ob.name] = [] curve = ob.data for spline in curve.splines: if spline.hide or spline.type not in ('POLY', 'BEZIER'): # hide:objectModeでも隠れたまま continue if not spline.points and not spline.bezier_points: continue cyclic = spline.use_cyclic_u if spline.type == 'POLY': pysp = PySpline('POLY', cyclic) for p in spline.points: pysp.points.append(p.co * mat) pysplines.append(pysp) elif spline.type == 'BEZIER': pysp = PySpline('BEZIER', cyclic) bezier_points = spline.bezier_points for bp in bezier_points: pysp.bpoints.append([bp.handle_left * mat, bp.co * mat, bp.handle_right * mat]) pysp.handletypes.append([bp.handle_left_type, bp.handle_right_type]) # cacl point (for calc_document_size()) if len(bezier_points) == 1: pysp.points.append(bezier_points[0].co * mat) elif len(bezier_points) >= 2: bps = bezier_points[:] if cyclic: bps.append(bps[0]) for bp1, bp2 in zip(bps, bps[1:]): ps = interpolate_bezier(bp1.co * mat, bp1.handle_right * mat, bp2.co * mat, bp2.handle_left * mat, BEZIER_SUBDIVIDE) pysp.points.extend(ps) pysplines.append(pysp)
def interpolate_spline(spline_ob): ''' > spline_ob: bezier spline object < returns segments as lists of vectors ''' point_range = len(spline_ob.bezier_points) segments = [] for i in range (0, point_range-1+spline_ob.use_cyclic_u): segments.append(interpolate_bezier(spline_ob.bezier_points[i%point_range].co, spline_ob.bezier_points[i%point_range].handle_right, spline_ob.bezier_points[(i+1)%point_range].handle_left, spline_ob.bezier_points[(i+1)%point_range].co, spline_ob.resolution_u+1)) return segments
def doConstant(): res = max(resolution - 1, 1) for i in range(len(points) - 1): p1 = points[i] p2 = points[i + 1] cords = interpolate_bezier(p1.co, p1.handle_right, p2.handle_left, p2.co, resolution + 1) for j in range(resolution): c1 = cords[j] c2 = cords[j + 1] yield c1, c2, i, j / res
def interp_bezier(p0, p1, segs, resolution): """ Bezier curve approximation """ if (resolution == 0 or (p0.handle_right_type == 'VECTOR' and p1.handle_left_type == 'VECTOR')): segs.append(p0.co[0:3]) else: seg = interpolate_bezier(p0.co, p0.handle_right, p1.handle_left, p1.co, resolution + 1) segs.extend([p[0:3] for p in seg[:-2]])
def get_points(spline, clean=True): ''' usage: spline = bpy.data.curves[0].splines[0] points = get_points(spline) ''' knots = spline.bezier_points if len(knots) < 2: return # verts per segment r = spline.resolution_u + 1 # segments in spline segments = len(knots) if not spline.use_cyclic_u: segments -= 1 master_point_list = [] for i in range(segments): inext = (i + 1) % len(knots) knot1 = knots[i].co handle1 = knots[i].handle_right handle2 = knots[inext].handle_left knot2 = knots[inext].co bezier = knot1, handle1, handle2, knot2, r points = interpolate_bezier(*bezier) master_point_list.extend(points) # some clean up to remove consecutive doubles, this could be smarter... if clean: old = master_point_list good = [v for i, v in enumerate(old[:-1]) if not old[i] == old[i + 1]] good.append(old[-1]) return good # makes edge keys, ensure cyclic Edges = [[i, i + 1] for i in range(n_verts - 1)] if spline.use_cyclic_u: Edges.append([i, 0]) return master_point_list, Edges
def bezier_error(self, error_max=-1.0, test_count=8): from mathutils.geometry import interpolate_bezier test_points = interpolate_bezier( self.points[0].co, self.handle_left, self.handle_right, self.points[-1].co, test_count, ) from mathutils.geometry import intersect_point_line error = 0.0 # this is a rough method measuring the error but should be ok # TODO. dont test against every single point. for co in test_points: # initial values co_best = self.points[0].co length_best = (co - co_best).length for p in self.points[1:]: # dist to point length = (co - p.co).length if length < length_best: length_best = length co_best = p.co p_ix, fac = intersect_point_line(co, p.co, p.prev.co) p_ix = p_ix if fac >= 0.0 and fac <= 1.0: length = (co - p_ix).length if length < length_best: length_best = length co_best = p_ix error += length_best / test_count if error_max != -1.0 and error > error_max: return True if error_max != -1.0: return False else: return error
def bezier_error(self, error_max=-1.0, test_count=8): from mathutils.geometry import interpolate_bezier test_points = interpolate_bezier(self.points[0].co, self.handle_left, self.handle_right, self.points[-1].co, test_count, ) from mathutils.geometry import intersect_point_line error = 0.0 # this is a rough method measuring the error but should be ok # TODO. dont test against every single point. for co in test_points: # initial values co_best = self.points[0].co length_best = (co - co_best).length for p in self.points[1:]: # dist to point length = (co - p.co).length if length < length_best: length_best = length co_best = p.co p_ix, fac = intersect_point_line(co, p.co, p.prev.co) p_ix = p_ix if fac >= 0.0 and fac <= 1.0: length = (co - p_ix).length if length < length_best: length_best = length co_best = p_ix error += length_best / test_count if error_max != -1.0 and error > error_max: return True if error_max != -1.0: return False else: return error
def ratio_to_segment(x, p1, p2, p3, p4, res): ''' > x: intersection point > p1,p2,p3,p4: cubic bezier control points < ratio of x to length of the segment ''' seg = interpolate_bezier(p1, p2, p3, p4, res + 1) seg_length = length = ratio = 0 for i in range(len(seg) - 1): seg_length += (seg[i + 1] - seg[i]).length for i in range(len(seg) - 1): if is_between(x, seg[i], seg[i + 1]): length += (x - seg[i].to_2d()).length return length / seg_length else: length += (seg[i + 1] - seg[i]).length
def interpolate_all_segments(spline_ob): ''' > spline_ob: bezier spline object < returns interpolated splinepoints ''' point_range = len(spline_ob.bezier_points) pl = [] for i in range (0, point_range-1+spline_ob.use_cyclic_u): if len(pl) > 0: pl.pop() seg = (interpolate_bezier(spline_ob.bezier_points[i%point_range].co, spline_ob.bezier_points[i%point_range].handle_right, spline_ob.bezier_points[(i+1)%point_range].handle_left, spline_ob.bezier_points[(i+1)%point_range].co, spline_ob.resolution_u+1)) pl += seg return pl
def interpolate_bezier(self, pts, wM, p0, p1, resolution): # straight segment, worth testing here # since this can lower points count by a resolution factor # use normalized to handle non linear t if resolution == 0: pts.append(wM @ p0.co.to_3d()) else: v = (p1.co - p0.co).normalized() d1 = (p0.handle_right - p0.co).normalized() d2 = (p1.co - p1.handle_left).normalized() if d1 == v and d2 == v: pts.append(wM @ p0.co.to_3d()) else: seg = interpolate_bezier(wM @ p0.co, wM @ p0.handle_right, wM @ p1.handle_left, wM @ p1.co, resolution + 1) for i in range(resolution): pts.append(seg[i].to_3d())
def ratio_to_segment(x, p1, p2, p3, p4, res): ''' > x: intersection point > p1,p2,p3,p4: cubic bezier control points < ratio of x to length of the segment ''' seg = interpolate_bezier(p1, p2, p3, p4, res+1) seg_length = length = ratio = 0 for i in range (len(seg)-1): seg_length += (seg[i+1] - seg[i]).length for i in range (len(seg)-1): if is_between(x, seg[i], seg[i+1]): length += (x - seg[i].to_2d()).length return length/seg_length else: length += (seg[i+1] - seg[i]).length
def interpolate_bezier(self, pts, wM, p0, p1, resolution): """ Bezier curve approximation """ if (resolution == 0 or (p0.handle_right_type == 'VECTOR' and p1.handle_left_type == 'VECTOR')): pts.append(wM * p0.co.to_3d()) else: v = (p1.co - p0.co).normalized() d1 = (p0.handle_right - p0.co).normalized() d2 = (p1.co - p1.handle_left).normalized() if d1 == v and d2 == v: pts.append(wM * p0.co.to_3d()) else: seg = interpolate_bezier(wM * p0.co, wM * p0.handle_right, wM * p1.handle_left, wM * p1.co, resolution + 1) for i in range(resolution): pts.append(seg[i].to_3d())
def interpolate_bezier(curve): spline = curve.splines[0] if len(spline.bezier_points) >= 2: r = spline.resolution_u + 1 segments = len(spline.bezier_points) if not spline.use_cyclic_u: segments -= 1 points = [] for i in range(segments): inext = (i + 1) % len(spline.bezier_points) knot1 = spline.bezier_points[i].co handle1 = spline.bezier_points[i].handle_right handle2 = spline.bezier_points[inext].handle_left knot2 = spline.bezier_points[inext].co _points = interpolate_bezier(knot1, handle1, handle2, knot2, r) points.extend(_points) return points return None
def perform_CurveTo(self): ''' expects 5 params: C x1,y1 x2,y2 x3,y3 num bool [z] example: C control1 control2 knot2 10 0 [z] C control1 control2 knot2 20 1 [z] ''' tempstr = self.stripped_line.split(' ') if not len(tempstr) == 5: print('error on line CurveTo: ', self.stripped_line) return ''' fully defined ''' vec = lambda v: Vector((v[0], v[1], 0)) knot1 = [self.posxy[0], self.posxy[1]] if self.section_type == 'bezier_curve_to_absolute': handle1 = self.get_2vec(tempstr[0]) handle2 = self.get_2vec(tempstr[1]) knot2 = self.get_2vec(tempstr[2]) else: points = [] for j in range(3): point_pre = self.get_2vec(tempstr[j]) point = self.relative(self.posxy, point_pre) points.append(point) self.posxy = tuple(point) handle1, handle2, knot2 = points r = self.get_typed(tempstr[3], int) s = self.get_typed(tempstr[4], int) # not used yet bezier = vec(knot1), vec(handle1), vec(handle2), vec(knot2), r points = interpolate_bezier(*bezier) # parse down to 2d points = [[v[0], v[1]] for v in points] return self.find_right_index_and_make_edges(points)
def get_points_bezier(spline, clean=True, calc_radii=False): knots = spline.bezier_points cyclic = spline.use_cyclic_u if len(knots) < 2: return radii = [] # verts per segment r = spline.resolution_u + 1 # segments in spline segments = len(knots) if not cyclic: segments -= 1 print("segments:", segments) master_point_list = [] for i in range(segments): inext = (i + 1) % len(knots) knot1, knot2 = knots[i].co, knots[inext].co handle1, handle2 = knots[i].handle_right, knots[inext].handle_left bezier = knot1, handle1, handle2, knot2, r points = interpolate_bezier(*bezier) if segments == 1 and not cyclic: pass elif cyclic or (i < segments-1): points.pop() master_point_list.extend([v[:] for v in points]) edges = generate_edges(n_verts=len(master_point_list), cyclic=cyclic) return master_point_list, edges, radii
def backdrop(self, context): # calculate the view frame in world coordinates # (i.e. the far plane of the view frustum) scene = context.scene cam_ob = scene.camera cam = bpy.data.cameras[cam_ob.name] # camera in scene is object type, not a camera type cam_mat = cam_ob.matrix_world view_frame = cam.view_frame(scene) # without a scene the aspect ratio of the camera is not taken into account view_frame = [cam_mat * v for v in view_frame] cam_pos = cam_mat * Vector((0,0,0)) view_center = sum(view_frame, Vector((0,0,0)))/len(view_frame) view_normal = (view_center - cam_pos).normalized() # enlarge the view frame beyond the actual cam boundaries if requested if self.margin != 0.0: view_frame = [((v - view_center)*(1+self.margin))+view_center for v in view_frame] # calculate the intersection with a horizontal plane below the camera # the top edge is intersected with an artificially offset ground plane # so it will intersected with the lifted far end of our backdrop overts = [] refz = cam_pos.z if self.zero else self.distance for n,vf in enumerate(view_frame): v = (vf - cam_pos).normalized() d = 0.0 if n in (1,2) else self.lift zf = (d - refz) / v.z if zf <= 0.0 : break overts.append(zf * v) # create two edge loops (the right and left side of the intersection # of the view frustum with the backdrop). We curve it downward we a # bezier interpolation. This curvature can be controlled somewhat # with a rotation angle but this is far from ideal yet verts = [] edges = [] vs = Vector(overts[2]) ve = Vector(overts[3]) rotaxis = (vs - ve).cross(Vector((0,0,-1))).normalized() rot = Quaternion(rotaxis, self.angle) handle2 = ve + rot * Vector((0,0,-self.lift)) handle1 = vs + (vs - ve).normalized() points = interpolate_bezier(vs, handle1, handle2, ve, self.subdivisions+1) verts.extend(points) edges.extend((i,i+1) for i in range(len(points)-1)) vs = Vector(overts[0]) ve = Vector(overts[1]) rotaxis = (ve - vs).cross(Vector((0,0,-1))).normalized() rot = Quaternion(rotaxis, self.angle) handle2 = ve + (ve - vs).normalized() handle1 = vs + rot * Vector((0,0,-self.lift)) points = interpolate_bezier(ve, handle2, handle1, vs, self.subdivisions+1) points.reverse() offset = len(verts) verts.extend(points) edges.extend((offset+i,offset+i+1) for i in range(len(points)-1)) return verts, edges
def def_track_1(): pts=[] #pts.append([ 0.0, 0.0 , 0.0 , 30.0 , 20.0]) # x,y,z,turn0,turn1 #pts.append([ 0.0, 160.0 , 0.0 , 20.0 , 20.0]) #pts.append([ 100.0, 200.0 , 0.0 , 20.0 , 20.0]) #pts.append([ 180.0, 0.0 , 5.0 , 20.0 , 10.0]) #pts.append([-180.0, -50.0 , 5.0 , 10.0 , 10.0]) #pts.append([-180.0, -160.0 , 0.0 , 10.0 , 20.0]) #pts.append([ 0.0, -200.0 , 0.0 , 10.0 , 30.0]) #Circuit ellipse #first cadran pts.append([ 270.0, 0.0 , 0.0 , 20.0 , 20.0]) pts.append([ 250.0, 50.0 , 0.0 , 20.0 , 20.0]) pts.append([ 150.0, 90.0 , 0.0 , 20.0 , 20.0]) pts.append([ 0.0, 100.0 , 0.0 , 20.0 , 20.0]) #second one pts.append([ -150.0, 90.0 , 0.0 , 20.0 , 20.0]) pts.append([ -250.0, 50.0 , 0.0 , 20.0 , 20.0]) pts.append([ -270.0, 0.0 , 0.0 , 20.0 , 20.0]) #third pts.append([ -250.0, -50.0 , 0.0 , 20.0 , 20.0]) pts.append([ -150.0, -90.0 , 0.0 , 20.0 , 20.0]) pts.append([ 0.0, -100.0 , 0.0 , 20.0 , 20.0]) #fourth pts.append([ 150.0, -90.0 , 0.0 , 20.0 , 20.0]) pts.append([ 250.0, -50.0 , 0.0 , 20.0 , 20.0]) # define the number of basis points fro the circular bezier curve # ncut is the number of subdivision n0=len(pts) ncut = 1 over_sample = 4 # define over sampling factor to have a smoother curve while True: npt_bez = 4*(ncut+1) # compute the number of beziers points if npt_bez > over_sample*n0: break # exit if subdivision is enough ncut += 1 npt = npt_bez # each side of the polygon is reduce at its beginning and at its end to let space for the curves # a vertex of the polygon is defined by 5 values : xv,yv,zv,turn0,turn1 # (xv,yv,zv) are the coordinates of the vertex, # turn0 is the place left for the curve before reaching the vertex # turn1 is the place left for the curve after passing the vertex # we compute points (x,y,z) at the begining and at the end of each curve # also compute the left (xhl,yhl,zhl) and right (xhr,yhr,zhr) handlers to define the tangent to the bezier curve x,y,z,xhl,yhl,zhl,xhr,yhr,zhr = def_track_curves(pts) # define how many points are on each segment of the track t_cnt = def_points_in_segments(npt,x,y) # compute all points that will define the bezier curve of the track lpts = [] n = len(x) for i0 in range(n): i1 = (i0+1) % n new_pts = geometry.interpolate_bezier( (x[i0],y[i0],z[i0]), (xhr[i0],yhr[i0],zhr[i0]), (xhl[i1],yhl[i1],zhl[i1]), (x[i1],y[i1],z[i1]), t_cnt[i0]+1) # trick : compute one more points to avoid duplicate of the first for ipt in range(len(new_pts)-1): pt =new_pts[ipt+1] lpts.append([pt.x,pt.y,pt.z]) nptl = len(lpts) return ncut,nptl,lpts
def execute(self, context): bpy.ops.object.editmode_toggle() bm = bmesh.new() bm.from_mesh(bpy.context.active_object.data) bEdges = bm.edges bVerts = bm.verts seg = self.segments edges = [] verts = [] for e in bEdges: if e.select: edges.append(e) for v in range(4): verts.append(edges[v // 2].verts[v % 2]) if self.flip1: v1 = verts[1] p1_co = verts[1].co p1_dir = verts[1].co - verts[0].co else: v1 = verts[0] p1_co = verts[0].co p1_dir = verts[0].co - verts[1].co p1_dir.length = self.ten1 if self.flip2: v2 = verts[3] p2_co = verts[3].co p2_dir = verts[2].co - verts[3].co else: v2 = verts[2] p2_co = verts[2].co p2_dir = verts[3].co - verts[2].co p2_dir.length = self.ten2 # Get the interploted coordinates: if self.alg == 'Blender': pieces = interpolate_bezier(p1_co, p1_dir, p2_dir, p2_co, self.segments) elif self.alg == 'Hermite': pieces = interpolate_line_line(p1_co, p1_dir, p2_co, p2_dir, self.segments, 1, 'HERMITE') elif self.alg == 'Bezier': pieces = interpolate_line_line(p1_co, p1_dir, p2_co, p2_dir, self.segments, 1, 'BEZIER') elif self.alg == 'B-Spline': pieces = interpolate_line_line(p1_co, p1_dir, p2_co, p2_dir, self.segments, 1, 'BSPLINE') verts = [] verts.append(v1) # Add vertices and set the points: for i in range(seg - 1): v = bVerts.new() v.co = pieces[i] verts.append(v) verts.append(v2) # Connect vertices: for i in range(seg): e = bEdges.new((verts[i], verts[i + 1])) bm.to_mesh(bpy.context.active_object.data) bpy.ops.object.editmode_toggle() return {'FINISHED'}
def get_mats_for_segment(self, context, segment, splinetype): ''' Creates the Matrizies for a spline segment. ''' #printd('Creating transforms for segment', splinetype) mats = [] p1 = segment[0] p2 = segment[1] count = self.leafs_per_segment if self.bvh: count *= 2 ### TRANSLATION ################# if splinetype == 'BEZIER': coordsb = interpolate_bezier(p1.co, p1.handle_right, p2.handle_left, p2.co, count+1) coords = [coordsb[i].lerp(coordsb[i+1], random()*self.loc_random) for i in range(len(coordsb)-1)] elif splinetype == 'POLY': if count > 1: positions = [i / count for i in range(count)] else: positions = [0.5] #printd('POLY-segment: Lerp-positions', positions) coords = [p1.co.lerp(p2.co, positions[i]+(random() * self.loc_random)).to_3d() for i in range(count)] mat_locs = [Matrix.Translation(co) for co in coords] ### SCALE ################# mat_scales = [Matrix.Scale(self.scale+(random()*self.scale_random), 4) for i in range(len(mat_locs))] ### ROTATION ################# if splinetype == 'BEZIER': directions = [(coordsb[i+1] - coordsb[i]).normalized() for i in range(len(coordsb)-1)] elif splinetype == 'POLY': directions = [(p2.co - p1.co).to_3d().normalized()]*len(coords) #COLLISION -> align leaves to surface if self.bvh: #printd('COLLISION') mat_rots = get_collider_aligned_rots(self, context, coords[:int(count/2)], directions) #NO COLLISION else: vecs_target = directions.copy() #direction + random for y alignment vecs_target = [vt.lerp(vt+noise.random_unit_vector(), self.rot_random).normalized() for vt in vecs_target] #up versus random for z alignment vecs_alignz = [Vector((0,0,1)).lerp(noise.random_unit_vector(), self.rot_align_normal_random).normalized() for i in range(len(directions))] #return alignz towards the direction vector vecs_alignz = [va.lerp(d, self.rot_align_normal).normalized() for va, d in zip(vecs_alignz, directions)] mat_rots = [align(vt, va) for vt, va in zip(vecs_target, vecs_alignz)] #printd('FREE ROTATION Mats:', len(mat_rots)) #COMBINED mats = [l*s*r for l,s,r in zip(mat_locs, mat_scales, mat_rots)] mats = [m for m in mats if not random() > self.leafs_per_segment_random] #printd('MATS: ', len(mats), len(mat_locs), len(mat_scales), len(mat_rots)) return mats
def backdrop(self, context): # calculate the view frame in world coordinates # (i.e. the far plane of the view frustum) scene = context.scene cam_ob = scene.camera cam = bpy.data.cameras[ cam_ob.name] # camera in scene is object type, not a camera type cam_mat = cam_ob.matrix_world view_frame = cam.view_frame( scene ) # without a scene the aspect ratio of the camera is not taken into account view_frame = [cam_mat * v for v in view_frame] cam_pos = cam_mat * Vector((0, 0, 0)) view_center = sum(view_frame, Vector((0, 0, 0))) / len(view_frame) view_normal = (view_center - cam_pos).normalized() # enlarge the view frame beyond the actual cam boundaries if requested if self.margin != 0.0: view_frame = [((v - view_center) * (1 + self.margin)) + view_center for v in view_frame] # calculate the intersection with a horizontal plane below the camera # the top edge is intersected with an artificially offset ground plane # so it will intersected with the lifted far end of our backdrop overts = [] refz = cam_pos.z if self.zero else self.distance for n, vf in enumerate(view_frame): v = (vf - cam_pos).normalized() d = 0.0 if n in (1, 2) else self.lift zf = (d - refz) / v.z if zf <= 0.0: break overts.append(zf * v) # create two edge loops (the right and left side of the intersection # of the view frustum with the backdrop). We curve it downward we a # bezier interpolation. This curvature can be controlled somewhat # with a rotation angle but this is far from ideal yet verts = [] edges = [] vs = Vector(overts[2]) ve = Vector(overts[3]) rotaxis = (vs - ve).cross(Vector((0, 0, -1))).normalized() rot = Quaternion(rotaxis, self.angle) handle2 = ve + rot * Vector((0, 0, -self.lift)) handle1 = vs + (vs - ve).normalized() points = interpolate_bezier(vs, handle1, handle2, ve, self.subdivisions + 1) verts.extend(points) edges.extend((i, i + 1) for i in range(len(points) - 1)) vs = Vector(overts[0]) ve = Vector(overts[1]) rotaxis = (ve - vs).cross(Vector((0, 0, -1))).normalized() rot = Quaternion(rotaxis, self.angle) handle2 = ve + (ve - vs).normalized() handle1 = vs + rot * Vector((0, 0, -self.lift)) points = interpolate_bezier(ve, handle2, handle1, vs, self.subdivisions + 1) points.reverse() offset = len(verts) verts.extend(points) edges.extend( (offset + i, offset + i + 1) for i in range(len(points) - 1)) return verts, edges
def get_mats_for_segment(self, context, segment, splinetype): ''' Creates the Matrizies for a spline segment. ''' #printd('Creating transforms for segment', splinetype) mats = [] p1 = segment[0] p2 = segment[1] count = self.leafs_per_segment if self.bvh: count *= 2 ### TRANSLATION ################# if splinetype == 'BEZIER': coordsb = interpolate_bezier(p1.co, p1.handle_right, p2.handle_left, p2.co, count + 1) coords = [ coordsb[i].lerp(coordsb[i + 1], random() * self.loc_random) for i in range(len(coordsb) - 1) ] elif splinetype == 'POLY': if count > 1: positions = [i / count for i in range(count)] else: positions = [0.5] #printd('POLY-segment: Lerp-positions', positions) coords = [ p1.co.lerp(p2.co, positions[i] + (random() * self.loc_random)).to_3d() for i in range(count) ] mat_locs = [Matrix.Translation(co) for co in coords] ### SCALE ################# mat_scales = [ Matrix.Scale(self.scale + (random() * self.scale_random), 4) for i in range(len(mat_locs)) ] ### ROTATION ################# if splinetype == 'BEZIER': directions = [(coordsb[i + 1] - coordsb[i]).normalized() for i in range(len(coordsb) - 1)] elif splinetype == 'POLY': directions = [(p2.co - p1.co).to_3d().normalized()] * len(coords) #COLLISION -> align leaves to surface if self.bvh: #printd('COLLISION') mat_rots = get_collider_aligned_rots(self, context, coords[:int(count / 2)], directions) #NO COLLISION else: vecs_target = directions.copy() #direction + random for y alignment vecs_target = [ vt.lerp(vt + noise.random_unit_vector(), self.rot_random).normalized() for vt in vecs_target ] #up versus random for z alignment vecs_alignz = [ Vector((0, 0, 1)).lerp(noise.random_unit_vector(), self.rot_align_normal_random).normalized() for i in range(len(directions)) ] #return alignz towards the direction vector vecs_alignz = [ va.lerp(d, self.rot_align_normal).normalized() for va, d in zip(vecs_alignz, directions) ] mat_rots = [align(vt, va) for vt, va in zip(vecs_target, vecs_alignz)] #printd('FREE ROTATION Mats:', len(mat_rots)) #COMBINED mats = [l * s * r for l, s, r in zip(mat_locs, mat_scales, mat_rots)] mats = [m for m in mats if not random() > self.leafs_per_segment_random] #printd('MATS: ', len(mats), len(mat_locs), len(mat_scales), len(mat_rots)) return mats
def interpret(self, interpreter, variables): vec = lambda v: Vector((v[0], v[1], 0)) interpreter.assert_not_closed() interpreter.start_new_segment() v0 = interpreter.position if interpreter.has_last_vertex: v0_index = interpreter.get_last_vertex() else: v0_index = interpreter.new_vertex(*v0) knot1 = None for i, segment in enumerate(self.segments): # For first segment, knot1 is initial pen position; # for the following, knot1 is knot2 of previous segment. if knot1 is None: knot1 = interpreter.position else: knot1 = knot2 handle1 = interpreter.calc_vertex(self.is_abs, segment.control1[0], segment.control1[1], variables) # In Profile mk2, for "c" handle2 was calculated relative to handle1, # and knot2 was calculated relative to handle2. # But in SVG specification, # >> ... *At the end of the command*, the new current point becomes # >> the final (x,y) coordinate pair used in the polybézier. # This is also behaivour of browsers. #interpreter.position = handle1 handle2 = interpreter.calc_vertex(self.is_abs, segment.control2[0], segment.control2[1], variables) #interpreter.position = handle2 knot2 = interpreter.calc_vertex(self.is_abs, segment.knot2[0], segment.knot2[1], variables) # Judging by the behaivour of Inkscape and Firefox, by "end of command" # SVG spec means "end of segment". interpreter.position = knot2 if self.num_segments is not None: r = interpreter.eval_(self.num_segments, variables) else: r = interpreter.dflt_num_verts points = interpolate_bezier(vec(knot1), vec(handle1), vec(handle2), vec(knot2), r) interpreter.new_knot("C#.{}.h1".format(i), *handle1) interpreter.new_knot("C#.{}.h2".format(i), *handle2) interpreter.new_knot("C#.{}.k".format(i), *knot2) interpreter.prev_bezier_knot = handle2 for point in points[1:]: v1_index = interpreter.new_vertex(point.x, point.y) interpreter.new_edge(v0_index, v1_index) v0_index = v1_index if self.close: interpreter.new_edge(v1_index, interpreter.segment_start_index) interpreter.has_last_vertex = True
def interpret(self, interpreter, variables): vec = lambda v: Vector((v[0], v[1], 0)) interpreter.assert_not_closed() interpreter.start_new_segment() v0 = interpreter.position if interpreter.has_last_vertex: v0_index = interpreter.get_last_vertex() else: v0_index = interpreter.new_vertex(*v0) knot1 = None for i, segment in enumerate(self.segments): # For first segment, knot1 is initial pen position; # for the following, knot1 is knot2 of previous segment. if knot1 is None: knot1 = interpreter.position else: knot1 = knot2 if interpreter.prev_bezier_knot is None: # If there is no previous command or if the previous command was # not an C, c, S or s, assume the first control point is coincident # with the current point. handle1 = knot1 else: # The first control point is assumed to be the reflection of the # second control point on the previous command relative to the # current point. prev_knot_x, prev_knot_y = interpreter.prev_bezier_knot x0, y0 = knot1 dx, dy = x0 - prev_knot_x, y0 - prev_knot_y handle1 = x0 + dx, y0 + dy # I assume that handle2 should be relative to knot1, not to handle1. # interpreter.position = handle1 handle2 = interpreter.calc_vertex(self.is_abs, segment.control2[0], segment.control2[1], variables) # interpreter.position = handle2 knot2 = interpreter.calc_vertex(self.is_abs, segment.knot2[0], segment.knot2[1], variables) interpreter.position = knot2 if self.num_segments is not None: r = interpreter.eval_(self.num_segments, variables) else: r = interpreter.dflt_num_verts points = interpolate_bezier(vec(knot1), vec(handle1), vec(handle2), vec(knot2), r) interpreter.new_knot("S#.{}.h1".format(i), *handle1) interpreter.new_knot("S#.{}.h2".format(i), *handle2) interpreter.new_knot("S#.{}.k".format(i), *knot2) interpreter.prev_bezier_knot = handle2 for point in points[1:]: v1_index = interpreter.new_vertex(point.x, point.y) interpreter.new_edge(v0_index, v1_index) v0_index = v1_index if self.close: interpreter.new_edge(v1_index, interpreter.segment_start_index) interpreter.has_last_vertex = True
from bpy import context, data, ops from mathutils import geometry ops_mesh = ops.mesh count = 16 ops.curve.primitive_bezier_curve_add(enter_editmode=True) ops.transform.vertex_random(offset=1.0, uniform=0.1, normal=0.01, seed=0) ops.object.mode_set(mode='OBJECT') bez_curve = context.active_object bez_points = bez_curve.data.splines[0].bezier_points points_on_curve = geometry.interpolate_bezier( bez_points[0].co, bez_points[0].handle_right, bez_points[1].handle_left, bez_points[1].co, count, ) ops.object.empty_add(type='PLAIN_AXES', location=bez_curve.location) group = context.active_object cube_rad = 0.5 / count for point in points_on_curve: ops_mesh.primitive_cube_add(size=cube_rad, location=point) cube = context.active_object cube.parent = group