def slide_update(self, context, eventd, settings): x, y = eventd['mouse'] region = context.region region = eventd['region'] r3d = eventd['r3d'] hit = common_utilities.ray_cast_region2d_bvh(region, r3d, (x, y), self.trg_bvh, self.trg_mx, settings)[1] if hit[2] is None: return pt = invert_matrix(self.trg_mx) * hit[0] def dist(v_index): v = self.trg_bme.verts[v_index] l = (self.trg_mx * v.co) - pt return l.length v_ind = min(self.loopslide.vert_loop_vs, key=dist) #< The closest edgeloop point to the mouse n = self.loopslide.vert_loop_vs.index(v_ind) v_pt = self.trg_bme.verts[v_ind].co p_right, pct_right = intersect_point_line( pt, v_pt, v_pt + self.loopslide.edge_loop_right[n]) p_left, pct_left = intersect_point_line( pt, v_pt, v_pt + self.loopslide.edge_loop_left[n]) if pct_right > 0: self.loopslide.pct = min(1, pct_right) self.loopslide.right = True else: self.loopslide.right = False self.loopslide.pct = min(1, pct_left) self.loopslide.calc_snaps(self.trg_bme, snap=False)
def xsect_spline(sp_a, sp_b, _hubs, precision): pt_a_prev = pt_b_prev = None EPS_SPLINE = min(sp_a.length, sp_b.length) / precision pt_a_prev = sp_a.points[0] for a, pt_a in enumerate(sp_a.points[1:]): pt_b_prev = sp_b.points[0] for b, pt_b in enumerate(sp_b.points[1:]): # Now we have 2 edges # print(pt_a, pt_a_prev, pt_b, pt_b_prev) xsect = intersect_line_line(pt_a, pt_a_prev, pt_b, pt_b_prev) if xsect is not None: if (xsect[0] - xsect[1]).length <= EPS_SPLINE: f = intersect_point_line(xsect[1], pt_a, pt_a_prev)[1] # if f >= 0.0-EPS_SPLINE and f <= 1.0+EPS_SPLINE: # for some reason doesnt work so well, same below if f >= 0.0 and f <= 1.0: f = intersect_point_line(xsect[0], pt_b, pt_b_prev)[1] # if f >= 0.0-EPS_SPLINE and f <= 1.0+EPS_SPLINE: if f >= 0.0 and f <= 1.0: # This wont happen often co = xsect[0].lerp(xsect[1], 0.5) hub = get_hub(co, _hubs, EPS_SPLINE) sp_a.hubs.append((a, hub)) sp_b.hubs.append((b, hub)) pt_b_prev = pt_b pt_a_prev = pt_a
def slide_update(self,context,eventd,settings): x,y = eventd['mouse'] region = context.region region = eventd['region'] r3d = eventd['r3d'] hit = common_utilities.ray_cast_region2d_bvh(region, r3d, (x,y), self.trg_bvh, self.trg_mx, settings)[1] if hit[2] is None: return pt = invert_matrix(self.trg_mx) * hit[0] def dist(v_index): v = self.trg_bme.verts[v_index] l = (self.trg_mx * v.co) - pt return l.length v_ind = min(self.loopslide.vert_loop_vs, key = dist) #< The closest edgeloop point to the mouse n = self.loopslide.vert_loop_vs.index(v_ind) v_pt = self.trg_bme.verts[v_ind].co p_right, pct_right = intersect_point_line(pt, v_pt, v_pt + self.loopslide.edge_loop_right[n]) p_left, pct_left = intersect_point_line(pt, v_pt, v_pt + self.loopslide.edge_loop_left[n]) if pct_right > 0: self.loopslide.pct = min(1, pct_right) self.loopslide.right = True else: self.loopslide.right = False self.loopslide.pct = min(1, pct_left) self.loopslide.calc_snaps(self.trg_bme, snap = False)
def intersect_line(self, l1, l2, reverse=False): """ Spectial kind of intersection, works in 3d on the plane defimed by the points normal and the line. """ from mathutils.geometry import ( intersect_point_line, ) if reverse: p_first = self.points[-1] no = -self.points[-1].no point_iter = reversed(self.points[:-1]) else: p_first = self.points[0] no = self.points[0].no point_iter = self.points[1:] # calculate the line right angles to the line bi_no = (no - no.project(l2 - l1)).normalized() bi_l1 = p_first.co bi_l2 = p_first.co + bi_no for p_apex in point_iter: ix, fac = intersect_point_line(p_apex.co, bi_l1, bi_l2) if fac < 0.0001: if reverse: p_apex_other = p_apex.next else: p_apex_other = p_apex.prev # find the exact point on the line between the apex and # the middle p_test_1 = intersect_point_line(p_apex.co, l1, l2)[0] p_test_2 = intersect_point_line(p_apex_other.co, l1, l2)[0] w1 = (p_test_1 - p_apex.co).length w2 = (p_test_2 - p_apex_other.co).length #assert(w1 + w2 != 0) try: fac = w1 / (w1 + w2) except ZeroDivisionError: fac = 0.5 assert (fac >= 0.0 and fac <= 1.0) p_apex_co = p_apex.co.lerp(p_apex_other.co, fac) p_apex_no = p_apex.no.lerp(p_apex_other.no, fac) p_apex_no.normalize() # visualize_line(p_mid.to_3d(), corner.to_3d()) # visualize_line(p_apex.co.to_3d(), p_apex_co.to_3d()) return p_apex_co, p_apex_no, p_apex # intersection not found return None, None, None
def hover_non_man(self, context, x, y): region = context.region rv3d = context.region_data coord = x, y self.mouse = Vector((x, y)) loc3d_reg2D = view3d_utils.location_3d_to_region_2d view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord) ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord) ray_target = ray_origin + (view_vector * 1000) mx = self.cut_ob.matrix_world imx = mx.inverted() loc, no, face_ind = self.cut_ob.ray_cast(imx * ray_origin, imx * ray_target) if len(self.non_man_points): co3d, index, dist = self.kd.find(mx * loc) #get the actual non man vert from original list close_bmvert = self.bme.verts[self.non_man_bmverts[ index]] #stupid mapping, unreadable, terrible, fix this, because can't keep a list of actual bmverts close_eds = [ ed for ed in close_bmvert.link_edges if not ed.is_manifold ] if len(close_eds) == 2: bm0 = close_eds[0].other_vert(close_bmvert) bm1 = close_eds[1].other_vert(close_bmvert) a0 = bm0.co b = close_bmvert.co a1 = bm1.co inter_0, d0 = intersect_point_line(loc, a0, b) inter_1, d1 = intersect_point_line(loc, a1, b) screen_0 = loc3d_reg2D(region, rv3d, mx * inter_0) screen_1 = loc3d_reg2D(region, rv3d, mx * inter_1) screen_v = loc3d_reg2D(region, rv3d, mx * b) screen_d0 = (self.mouse - screen_0).length screen_d1 = (self.mouse - screen_1).length screen_dv = (self.mouse - screen_v).length if 0 < d0 <= 1 and screen_d0 < 30: self.hovered = ['NON_MAN_ED', (close_eds[0], mx * inter_0)] return elif 0 < d1 <= 1 and screen_d1 < 30: self.hovered = ['NON_MAN_ED', (close_eds[1], mx * inter_1)] return elif screen_dv < 30: if abs(d0) < abs(d1): self.hovered = ['NON_MAN_VERT', (close_eds[0], mx * b)] return else: self.hovered = ['NON_MAN_VERT', (close_eds[1], mx * b)] return
def make_corner_alt(self, bm, verts, fac=0.5): face = get_face_with_verts(verts) if face is not None and len(face.edges) == 6: done = False loop_a = None loop_b = None for vert in verts: face_loops = get_face_loops_for_vert(vert, face) for loop in face_loops: if loop.vert in verts: loop_a = loop if loop.link_loop_next.link_loop_next.vert in verts: loop_b = loop.link_loop_next done = True break if done: break if loop_a is not None and loop_b is not None: edge_a = loop_a.link_loop_prev.link_loop_prev.edge edge_b = loop_b.link_loop_next.link_loop_next.edge vert_a = loop_a.vert vert_b = loop_b.edge.other_vert(loop_b.vert) edge_a_point, _ = intersect_point_line(vert_b.co, edge_a.verts[0].co, edge_a.verts[1].co) edge_b_point, _ = intersect_point_line(vert_a.co, edge_b.verts[0].co, edge_b.verts[1].co) isect_point = intersect_line_line(edge_a_point, vert_b.co, edge_b_point, vert_a.co) if isect_point is not None: center_vert_co = isect_point[0] shared_vert = get_vertex_shared_by_edges( [loop_a.edge, loop_b.edge]) connect_vert = get_vertex_shared_by_edges([edge_a, edge_b]) center_vert_co = center_vert_co.lerp(connect_vert.co, fac) # Make the corner geometry center_vert: BMVert = bmesh.ops.create_vert( bm, co=center_vert_co)["vert"][0] bm.faces.ensure_lookup_table() bm.edges.ensure_lookup_table() bm.verts.ensure_lookup_table() new_edge_a = bm.edges.new([vert_a, center_vert]) new_edge_b = bm.edges.new([vert_b, center_vert]) new_edge_c = bm.edges.new([center_vert, connect_vert]) bmesh.utils.face_split_edgenet( face, [new_edge_a, new_edge_b, new_edge_c])
def get_closest_intersection_point_to_center(self, closest_intersection_point, intersection_point, line_coord): line_coord_vec = ((line_coord[0], line_coord[1]), (line_coord[2], line_coord[3])) intersect_point_proximity = intersect_point_line((intersection_point[0], intersection_point[1]), line_coord_vec[0], line_coord_vec[1])[1] closest_intersection_point_proximity = intersect_point_line((closest_intersection_point[0], closest_intersection_point[1]), line_coord_vec[0], line_coord_vec[1])[1] if intersect_point_proximity > closest_intersection_point_proximity: return closest_intersection_point elif intersect_point_proximity < closest_intersection_point_proximity: return intersection_point else: return closest_intersection_point
def hover_non_man(self,context,x,y): region = context.region rv3d = context.region_data coord = x, y self.mouse = Vector((x, y)) loc3d_reg2D = view3d_utils.location_3d_to_region_2d view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord) ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord) ray_target = ray_origin + (view_vector * 1000) mx = self.cut_ob.matrix_world imx = mx.inverted() loc, no, face_ind = self.cut_ob.ray_cast(imx * ray_origin, imx * ray_target) if len(self.non_man_points): co3d, index, dist = self.kd.find(mx * loc) #get the actual non man vert from original list close_bmvert = self.bme.verts[self.non_man_bmverts[index]] #stupid mapping, unreadable, terrible, fix this, because can't keep a list of actual bmverts close_eds = [ed for ed in close_bmvert.link_edges if not ed.is_manifold] if len(close_eds) == 2: bm0 = close_eds[0].other_vert(close_bmvert) bm1 = close_eds[1].other_vert(close_bmvert) a0 = bm0.co b = close_bmvert.co a1 = bm1.co inter_0, d0 = intersect_point_line(loc, a0, b) inter_1, d1 = intersect_point_line(loc, a1, b) screen_0 = loc3d_reg2D(region, rv3d, mx * inter_0) screen_1 = loc3d_reg2D(region, rv3d, mx * inter_1) screen_v = loc3d_reg2D(region, rv3d, mx * b) screen_d0 = (self.mouse - screen_0).length screen_d1 = (self.mouse - screen_1).length screen_dv = (self.mouse - screen_v).length if 0 < d0 <= 1 and screen_d0 < 30: self.hovered = ['NON_MAN_ED', (close_eds[0], mx*inter_0)] return elif 0 < d1 <= 1 and screen_d1 < 30: self.hovered = ['NON_MAN_ED', (close_eds[1], mx*inter_1)] return elif screen_dv < 30: if abs(d0) < abs(d1): self.hovered = ['NON_MAN_VERT', (close_eds[0], mx*b)] return else: self.hovered = ['NON_MAN_VERT', (close_eds[1], mx*b)] return
def f_1(me, list_0, arg, context, ob_act): cb = context.scene.pt_custom_props.b cen1 = context.scene.pt_custom_props.en1 dict_0 = {} dict_1 = {} if arg == 'x': lp1 = Vector((0, 0, 0)) lp2 = Vector((1, 0, 0)) elif arg == 'y': lp1 = Vector((0, 0, 0)) lp2 = Vector((0, 1, 0)) elif arg == 'z': lp1 = Vector((0, 0, 0)) lp2 = Vector((0, 0, 1)) if cb == False: for vi in list_0: v = (me.vertices[vi].co).copy() if cen1 == 'opt0': p3 = intersect_point_line( v, lp1, lp2)[0] elif cen1 == 'opt1': p1 = ob_act.matrix_world * v p2 = intersect_point_line( p1, lp1, lp2)[0] p3 = (ob_act.matrix_world).inverted() * p2 dict_0[vi] = p3 for j in dict_0: me.vertices[j].co = dict_0[j] elif cb == True: for vi in list_0: v = (me.vertices[vi].co).copy() if cen1 == 'opt0': p3 = intersect_point_line( v, lp1, lp2)[0] elif cen1 == 'opt1': p1 = ob_act.matrix_world * v p2 = intersect_point_line( p1, lp1, lp2)[0] p3 = (ob_act.matrix_world).inverted() * p2 me.vertices.add(1) me.vertices[-1].co = p3 me.vertices[-1].select = False dict_1[vi] = me.vertices[-1].index edge_copy_(me, dict_1) faces_copy_(me, dict_1)
def MatchPairByPerpendicular(self, context, sObj, sID, dObj, dID): #当互相垂直角度不为90度时,使用这个 #我们现在已有一条公共边与两个可能与垂直与公共边的面异面的点,如果两点到公共边上的最小距离坐标很近,说明两个三角形是镜像关系; #这是MatchPair的升级版,但是最好先用MatchPair得到公共边,容易理解 #通过RotateO的判断,我们已经将三对[0-1-2]的[1-2]进行了公共边处理,所以,0是可能是与垂直与公共边的面异面的点。 #所以,几乎可以忽视部分传入参数,eg : ID if len(sID) != 3 or len(dID) != 3: self.report( {'WARNING'}, 'Perpendicular Error in MatchPairByPerpendicular Function!!!') return #两点 wm = sObj.matrix_world.copy() sP0 = wm * (sObj.data.vertices[self.vts[0][sID[0]]].co.copy()) wm = dObj.matrix_world.copy() dP0 = wm * (dObj.data.vertices[self.vts[self.objs.index(dObj)][ dID[0]]].co.copy()) #两点是否重合 if (dP0 - sP0).magnitude < 0.000001: return #公共边 wm = sObj.matrix_world.copy() sP1 = wm * (sObj.data.vertices[self.vts[0][sID[1]]].co.copy()) sP2 = wm * (sObj.data.vertices[self.vts[0][sID[2]]].co.copy()) #映射点,求矢量-角度 from mathutils import geometry sP4 = geometry.intersect_point_line(sP0, sP1, sP2)[0] dP4 = geometry.intersect_point_line(dP0, sP1, sP2)[0] v1, v2 = (sP4 - sP0).normalized(), (dP4 - dP0).normalized() #角度相关 angle = v1.angle(v2) if angle < 0.000001: return cross = v1.cross(v2) if self.BoolRotate1Flip == True: angle += pi angle *= -1 bpy.ops.transform.rotate(value=angle, axis=cross) return
def intersect(pt,bone) : intersection = intersect_point_line(pt,bone['head'],bone['tail']) point_on_line = (pt-intersection[0]).length < 0.001 #print('point_on_line',point_on_line) #distance = True is_in_range = False if intersection[1]<=0.5 : distance = (pt-bone['head']).length #print(distance) if intersection[1]>=0 : is_in_range = True else : is_in_range = distance > -1.5 elif intersection[1]>0.5 : distance = (pt-bone['tail']).length #print(distance) if intersection[1]<=1 : is_in_range = True else : is_in_range = distance < 2.5 #print('is_in_range',is_in_range) #print(bone) #print('intersection',intersection) #print('point_on_line',point_on_line) #print('is_in_range',is_in_range) if point_on_line and is_in_range: return intersection[1]
def e_no_(bme, indx, p, p1): tmp1 = (bme.verts[indx].co).copy() tmp1[0] += 0.1 tmp1[1] += 0.1 tmp1[2] += 0.1 ip1 = intersect_point_line(tmp1, p, p1)[0] return tmp1 - ip1
def get_closest_edge(bm, point, dist): r_edge = None for edge in bm.edges: v1 = edge.verts[0].co v2 = edge.verts[1].co # Test the BVH (AABB) first for i in range(3): if v1[i] <= v2[i]: isect = v1[i] - dist <= point[i] <= v2[i] + dist else: isect = v2[i] - dist <= point[i] <= v1[i] + dist if not isect: break else: ret = intersect_point_line(point, v1, v2) if ret[1] < 0.0: tmp = v1 elif ret[1] > 1.0: tmp = v2 else: tmp = ret[0] new_dist = (point - tmp).length if new_dist <= dist: dist = new_dist r_edge = edge return r_edge
def distance_point_edge(pt, edge): line_p1 = edge.verts[0].co line_p2 = edge.verts[1].co ret = intersect_point_line(pt, line_p1, line_p2) closest_point_on_line = ret[0] distance_vector = closest_point_on_line - pt return distance_vector.length
def handle_mouse_move(self, mouse_pos_2d, mouse_pos_3d, event, context): if self.is_extruding(): dir = self.get_dir() region = context.region rv3d = context.space_data.region_3d mxy = event.mouse_region_x, event.mouse_region_y mpos_3d = region_2d_to_location_3d(region, rv3d, mxy, self._vertices[0]) isect_pt, length = intersect_point_line(mpos_3d, self._vertices[0], self._vertices[0] + dir) self._extrusion = length self.extrude_vertices(context) return True if self._vertex_moving is not None: self._vertices[self._vertex_moving] = mouse_pos_3d return True if self.is_created() and self._is_moving: diff = mouse_pos_3d - self._move_offset self._vertices = [vertex + diff for vertex in self._vertices] self._vertices_extruded = [ vertex + diff for vertex in self._vertices_extruded ] self._move_offset = mouse_pos_3d return True return False
def intersect(pt, bone): intersection = intersect_point_line(pt, bone['head'], bone['tail']) point_on_line = (pt - intersection[0]).length < 0.001 #print('point_on_line',point_on_line) #distance = True is_in_range = False if intersection[1] <= 0.5: distance = (pt - bone['head']).length #print(distance) if intersection[1] >= 0: is_in_range = True else: is_in_range = distance > -1.5 elif intersection[1] > 0.5: distance = (pt - bone['tail']).length #print(distance) if intersection[1] <= 1: is_in_range = True else: is_in_range = distance < 2.5 #print('is_in_range',is_in_range) #print(bone) #print('intersection',intersection) #print('point_on_line',point_on_line) #print('is_in_range',is_in_range) if point_on_line and is_in_range: return intersection[1]
def active_element(self, context, x, y): active_head = self.head.mouse_over(x, y) active_tail = self.tail.mouse_over(x, y) mouse_loc = Vector((x, y, 0)) head_loc = Vector((self.head.x, self.head.y, 0)) tail_loc = Vector((self.tail.x, self.tail.y, 0)) intersect = intersect_point_line(mouse_loc, head_loc, tail_loc) dist = (intersect[0] - mouse_loc).length_squared bound = intersect[1] active_self = (dist < 100) and (bound < 1) and (bound > 0) # TODO: make this a sensitivity setting if active_head and active_tail and active_self: # they are all clustered together print("returning head but tail too") return self.head elif active_tail: print("returning tail") return self.tail elif active_head: print("returning head") return self.head elif active_self: print("returning line") return self else: print("returning None") return None
def slide_snap(self, context, hitobj, hitlocation, hitindex): ''' slide snap to edges of all edit mode objects ''' # get hitface from the cached bmesh hitbm = self.snap_bms[hitobj.name] hitface = hitbm.faces[hitindex] # hit location in hitobj's local space hitmx = hitobj.matrix_world hit = hitmx.inverted() @ hitlocation # get closest edge edge = min([(e, (hit - intersect_point_line(hit, e.verts[0].co, e.verts[1].co)[0]).length, (hit - get_center_between_verts(*e.verts)).length) for e in hitface.edges], key=lambda x: (x[1] * x[2]) / x[0].calc_length())[0] # set snap coords for view3d drawing self.snap_coords = [hitmx @ v.co for v in edge.verts] # get snap coords in active's local space snap_coords = [self.mx.inverted_safe() @ co for co in self.snap_coords] # init proximity and ortho coords for view3d drawing self.snap_proximity_coords = [] self.snap_ortho_coords = [] # get intersection of individual slide dirs and snap coords for v, data in self.verts.items(): init_co = data['co'] target = data['target'] snap_dir = (snap_coords[0] - snap_coords[1]).normalized() slide_dir = (init_co - target.co).normalized() # check for parallel and almost parallel snap edges, do nothing in this case if abs(slide_dir.dot(snap_dir)) > 0.999: v.co = init_co # with a smaller dot product, interseect_line_line will produce a guaranteed hit else: i = intersect_line_line(init_co, target.co, *snap_coords) v.co = i[1 if self.is_diverging else 0] if i else init_co # add coords to draw the slide 'edges' if v.co != target.co: self.coords.extend([v.co, target.co]) # add proximity coords if i[1] != snap_coords[0]: self.snap_proximity_coords.extend([i[1], snap_coords[0]]) # add ortho coords if v.co != i[1]: self.snap_ortho_coords.extend([v.co, i[1]]) self.bm.normal_update() bmesh.update_edit_mesh(self.active.data)
def active_element(self,context,x,y): active_head = self.head.mouse_over(x, y) active_tail = self.tail.mouse_over(x, y) active_tan = self.plane_tan.mouse_over(x, y) mouse_loc = Vector((x,y,0)) head_loc = Vector((self.head.x, self.head.y, 0)) tail_loc = Vector((self.tail.x, self.tail.y, 0)) intersect = intersect_point_line(mouse_loc, head_loc, tail_loc) dist = (intersect[0] - mouse_loc).length_squared bound = intersect[1] active_self = (dist < 100) and (bound < 1) and (bound > 0) #TODO: make this a sensitivity setting if active_head and active_tail and active_self: #they are all clustered together #print('returning head but tail too') return self.head elif active_tail: #print('returning tail') return self.tail elif active_head: #print('returning head') return self.head elif active_tan: return self.plane_tan elif active_self: #print('returning line') return self else: #print('returning None') return None #cut line, a user interactive 2d line which represents a plane in 3d splace #head (type conrol point) #tail (type control points) #target mesh #view_direction (crossed with line to make plane normal for slicing) #draw method #new control point project method #mouse hover line calc #retopo object, surface #colelction of cut lines #collection of countours to loft #n rings (crosses borrowed from looptools) #n follows (borrowed from looptools and or bsurfaces) #method contours from cutlines #method bridge contours
def is_in_segment(v1, v2, point, tolerance=1e-6): closest, percent = intersect_point_line(point, v1, v2) if not (0 <= percent <= 1): return False distance = (point - closest).length if distance > tolerance: return False return True
def MatchPairByPerpendicular(self, context, sObj, sID, dObj, dID): #当互相垂直角度不为90度时,使用这个 #我们现在已有一条公共边与两个可能与垂直与公共边的面异面的点,如果两点到公共边上的最小距离坐标很近,说明两个三角形是镜像关系; #这是MatchPair的升级版,但是最好先用MatchPair得到公共边,容易理解 #通过RotateO的判断,我们已经将三对[0-1-2]的[1-2]进行了公共边处理,所以,0是可能是与垂直与公共边的面异面的点。 #所以,几乎可以忽视部分传入参数,eg : ID if len(sID) != 3 or len(dID) != 3: self.report( {'WARNING'}, 'Perpendicular Error in MatchPairByPerpendicular Function!!!' ) return #两点 wm = sObj.matrix_world.copy() sP0 = wm * (sObj.data.vertices[self.vts[0][sID[0]]].co.copy()) wm = dObj.matrix_world.copy() dP0 = wm * (dObj.data.vertices[self.vts[self.objs.index(dObj)][dID[0]]].co.copy()) #两点是否重合 if (dP0 - sP0).magnitude < 0.000001: return #公共边 wm = sObj.matrix_world.copy() sP1 = wm * (sObj.data.vertices[self.vts[0][sID[1]]].co.copy()) sP2 = wm * (sObj.data.vertices[self.vts[0][sID[2]]].co.copy()) #映射点,求矢量-角度 from mathutils import geometry sP4 = geometry.intersect_point_line(sP0, sP1, sP2)[0] dP4 = geometry.intersect_point_line(dP0, sP1, sP2)[0] v1, v2 = (sP4 - sP0).normalized(), (dP4 - dP0).normalized() #角度相关 angle = v1.angle(v2) if angle < 0.000001: return cross = v1.cross(v2) if self.BoolRotate1Flip == True: angle += pi angle *= -1 bpy.ops.transform.rotate(value=angle, axis=cross) return
def get_data_from_edge_ring(self): edge = self.current_edge edge_ring = self.current_ring flipped = self.flipped found_loop = False first_ring_edge = edge_ring[0] shortest_edge_len = float('INF') edge_start_pos = None edge_end_pos = None is_tri_fan_loop = False if edge_ring[0].edge.index == edge_ring[-1].edge.index: edge_ring.pop() is_tri_fan_loop = True for loop in edge_ring: if loop is None: break vert = loop.vert vert_other = loop.edge.other_vert(vert) dir_len = (vert_other.co - vert.co).length_squared if dir_len < shortest_edge_len: shortest_edge_len = dir_len vert_coords = None if loop.edge.index == edge.index: vert_coords = [vert.co.copy(), vert_other.co.copy()] if vert_coords is not None: if flipped: vert_coords.reverse() edge_start_pos = vert_coords[0] edge_end_pos = vert_coords[1] _, percent = intersect_point_line(self.current_position, vert_coords[0], vert_coords[1]) self.offset = percent if (loop.link_loop_radial_next.link_loop_next.link_loop_next.index == first_ring_edge.index) and not loop.edge.is_boundary: found_loop = True else: found_loop = False distance = (self.current_position - edge_start_pos).length shortest_edge_len = shortest_edge_len**0.5 is_loop = found_loop or is_tri_fan_loop return distance, shortest_edge_len, edge_start_pos, edge_end_pos, is_loop
def distance_point_segment(point, v1, v2): '''Compute distance of a point from a line segment.''' x, d = geometry.intersect_point_line(point, v1, v2) if d <= 0: return v1, (point - v1).magnitude elif d >= 1.0: return v2, (point - v2).magnitude else: return x, (point - x).magnitude
def compute_distance(point, line, line_end, tolerance): '''call to the mathuutils function''' inter_p = intersect_point_line(point, line, line_end) dist = (inter_p[0] - point).length segment_percent = inter_p[1] is_in_line = dist < tolerance closest_in_segment = 0 <= segment_percent <= 1 is_in_segment = is_in_line and closest_in_segment return dist, is_in_segment, is_in_line, list(inter_p[0]), closest_in_segment
def make_corner_straight(bm, verts, p1, p2): v1 = verts[0] v2 = verts[1] face = get_face_with_verts(verts) if face is not None and len(face.edges) == 6: done = False loop_a = None loop_b = None for vert in verts: face_loops = get_face_loops_for_vert(vert, face) for loop in face_loops: if loop.vert in verts: loop_a = loop if loop.link_loop_next.link_loop_next.vert in verts: loop_b = loop.link_loop_next done = True break if done: break if loop_a is not None and loop_b is not None: edge_a = loop_a.link_loop_prev.link_loop_prev.edge edge_b = loop_b.link_loop_next.link_loop_next.edge isect_point = intersect_line_line(p1, p2, edge_b.verts[0].co, edge_b.verts[1].co) if isect_point is not None: isect_point = isect_point[0] else: isect_point = intersect_line_line( p1, p2, edge_a.verts[0].co, edge_a.verts[1].co)[0] center_vert_co, _ = intersect_point_line( v2.co, isect_point, v1.co) #p1.lerp(p2, 0.5) # Make the corner geometry center_vert: BMVert = bm.verts.new( center_vert_co ) #bmesh.ops.create_vert(bm, co=center_vert_co)["vert"][0] connect_vert = get_vertex_shared_by_edges([edge_a, edge_b]) new_edge_a = bm.edges.new([verts[0], center_vert]) new_edge_b = bm.edges.new([verts[1], center_vert]) new_edge_c = bm.edges.new([center_vert, connect_vert]) bmesh.utils.face_split_edgenet( face, [new_edge_a, new_edge_b, new_edge_c]) bm.faces.ensure_lookup_table() bm.edges.ensure_lookup_table() bm.verts.ensure_lookup_table()
def update_radius(self, context, event): pt = self.get_pos3d(context) c = self.arc.c left = self.line_0.lerp(1) p, t = intersect_point_line(pt, c, left) radius = (left - p).length if event.alt: radius = round(radius, 1) self.set_value(context, self.datablock, self.glprovider.prop2_name, radius)
def straighten(self, bm, verts, v_start, v_end): # move all verts but the start and end verts on the vector described by the two verts.remove(v_start) verts.remove(v_end) for v in verts: co, _ = geometry.intersect_point_line(v.co, v_start.co, v_end.co) v.co = co bm.normal_update()
def get_selection_radius(): ob = bpy.context.active_object radius = 0.0 # no use continueing if nothing is selected if contains_selected_item(ob.data.polygons): # Find the center of the selection cent = mathutils.Vector() nr = 0 nonVerts = [] selVerts = [] for p in ob.data.polygons: if p.select: for v in p.vertices: nr += 1 cent += v.co else: nonVerts.extend(p.vertices) cent /= nr chk = 0 # Now that we know the center.. we can figure out how close the nearest point on an outer edge is for e in get_selected_edges(): nonSection = [v for v in e.vertices if v in nonVerts] if len(nonSection): v0 = ob.data.vertices[e.vertices[0]].co v1 = ob.data.vertices[e.vertices[1]].co # If there's more than 1 vert of this edge on the outside... we need the edge length to be long enough too! if len(nonSection) > 1: edge = v0 - v1 edgeRad = edge.length * 0.5 if edgeRad < radius or not chk: radius = edgeRad chk += 1 int = geometry.intersect_point_line(cent, v0, v1) rad = cent - int[0] l = rad.length if l < radius or not chk: radius = l chk += 1 return radius
def calculate_UV(U, V, fx, fy, ft): for i in range(0, U.shape[0]): for j in range(0, U.shape[1]): if fx[i][j] != 0 and fy[i][j] != 0 and ft[i][j] != 0: line = ((-1 * ft[i][j] / fx[i][j], 0), (0, -1 * ft[i][j] / fy[i][j])) point = (0, 0) a, __ = intersect_point_line(point, line[0], line[1]) U[i][j] = a[0] V[i][j] = a[1] return U, V
def update(self, context, event): # 0 1 2 # |_____| # pt = self.get_pos3d(context) pt, t = intersect_point_line(pt, self.line_0.p, self.line_2.p) length = (self.line_0.p - pt).length if event.alt: length = round(length, 1) self.set_value(context, self.datablock, self.glprovider.prop1_name, length)
def grad_f_ed(ed, p, last_face): #walk around non manifold edges if len(ed.link_faces) == 1: minv = min(ed.verts, key = geos.get) return minv.co, minv, None f = [fc for fc in ed.link_faces if fc !=last_face][0] g = gradient_face(f, geos) L = f.calc_perimeter() #test for vert intersection for v in f.verts: v_inter, pct = intersect_point_line(v.co, p, p-L*g) delta = v.co - v_inter if delta.length < epsilon: print('intersect vert') return v.co, v, None tests = [e for e in f.edges if e != ed] for e in tests: v0, v1 = intersect_line_line(e.verts[0].co, e.verts[1].co, p, p-L*g) V = v0 - e.verts[0].co edV = e.verts[1].co - e.verts[0].co Vi = v0 - p if V.length - edV.length > epsilon: #print('intersects outside segment') continue elif V.dot(edV) < 0: #print('intersects behind') continue elif Vi.dot(g) > 0: #remember we watnt to travel DOWN the gradient #print('shoots out the face, not across the face') continue else: #print('regular face edge crossing') return v0, e, f #we didn't intersect across an edge, or on a vert, #therefore, we should travel ALONG the edge vret = min(ed.verts, key = geos.get) return vret.co, vret, None
def makeBonesCollinearFromBoneHeadToBoneTail(armatureName, boneArray): initial_mode = bpy.context.object.mode armature_ob = bpy.context.scene.objects[armatureName] bpy.ops.object.mode_set(mode='OBJECT', toggle=False) armature_ob.select = True bpy.context.scene.objects.active = armature_ob # bpy.ops.object.mode_set(mode='EDIT', toggle=False) # fromBone = armature_ob.data.edit_bones[boneArray[0]] toBone = armature_ob.data.edit_bones[boneArray[-1]] line = (fromBone.head, toBone.tail) for bone in boneArray: if bone == fromBone.name: point = armature_ob.data.edit_bones[bone].tail intersect = intersect_point_line(point, line[0], line[1]) localCo = intersect[0] armature_ob.data.edit_bones[bone].tail = localCo if bone == toBone.name: point = armature_ob.data.edit_bones[bone].head intersect = intersect_point_line(point, line[0], line[1]) localCo = intersect[0] armature_ob.data.edit_bones[bone].head = localCo else: point = armature_ob.data.edit_bones[bone].head intersect = intersect_point_line(point, line[0], line[1]) localCo = intersect[0] armature_ob.data.edit_bones[bone].head = localCo # point = armature_ob.data.edit_bones[bone].tail intersect = intersect_point_line(point, line[0], line[1]) localCo = intersect[0] armature_ob.data.edit_bones[bone].tail = localCo # for index, bone in enumerate(boneArray): if bone == toBone.name: continue else: armature_ob.data.edit_bones[ bone].tail = armature_ob.data.edit_bones[boneArray[index + 1]].head
def get_closest_point_on_line(point, line): """ Given a point get the closest point to the line segment Args: point ([tuple]): [description] line ([list]): [list of list [[x1,y1],[x2,y2]]]] Returns: [type]: [description] """ return intersect_point_line(point, *line)
def grad_f_ed(ed, p, last_face): # walk around non manifold edges if len(ed.link_faces) == 1: minv = min(ed.verts, key=geos.get) return minv.co, minv, None f = [fc for fc in ed.link_faces if fc != last_face][0] g = gradient_face(f, geos) L = f.calc_perimeter() # test for vert intersection for v in f.verts: v_inter, pct = intersect_point_line(v.co, p, p - L * g) delta = v.co - v_inter if delta.length < epsilon: print("intersect vert") return v.co, v, None tests = [e for e in f.edges if e != ed] for e in tests: v0, v1 = intersect_line_line(e.verts[0].co, e.verts[1].co, p, p - L * g) V = v0 - e.verts[0].co edV = e.verts[1].co - e.verts[0].co Vi = v0 - p if V.length - edV.length > epsilon: # print('intersects outside segment') continue elif V.dot(edV) < 0: # print('intersects behind') continue elif Vi.dot(g) > 0: # remember we watnt to travel DOWN the gradient # print('shoots out the face, not across the face') continue else: # print('regular face edge crossing') return v0, e, f # we didn't intersect across an edge, or on a vert, # therefore, we should travel ALONG the edge vret = min(ed.verts, key=geos.get) return vret.co, vret, None
def region_2d_to_location_3d(region, rv3d, coord, depth_location): """ Return a 3d location from the region relative 2d coords, aligned with *depth_location*. :arg region: region of the 3D viewport, typically bpy.context.region. :type region: :class:`bpy.types.Region` :arg rv3d: 3D region data, typically bpy.context.space_data.region_3d. :type rv3d: :class:`bpy.types.RegionView3D` :arg coord: 2d coordinates relative to the region; (event.mouse_region_x, event.mouse_region_y) for example. :type coord: 2d vector :arg depth_location: the returned vectors depth is aligned with this since there is no defined depth with a 2d region input. :type depth_location: 3d vector :return: normalized 3d vector. :rtype: :class:`mathutils.Vector` """ from mathutils import Vector from mathutils.geometry import intersect_point_line persmat = rv3d.perspective_matrix.copy() viewinv = rv3d.view_matrix.inverted() coord_vec = region_2d_to_vector_3d(region, rv3d, coord) depth_location = Vector(depth_location) if rv3d.is_perspective: from mathutils.geometry import intersect_line_plane origin_start = viewinv.translation.copy() origin_end = origin_start + coord_vec view_vec = viewinv.col[2].copy() return intersect_line_plane( origin_start, origin_end, depth_location, view_vec, 1, ) else: dx = (2.0 * coord[0] / region.width) - 1.0 dy = (2.0 * coord[1] / region.height) - 1.0 persinv = persmat.inverted() viewinv = rv3d.view_matrix.inverted() origin_start = ((persinv.col[0].xyz * dx) + (persinv.col[1].xyz * dy) + viewinv.translation) origin_end = origin_start + coord_vec return intersect_point_line( depth_location, origin_start, origin_end, )[0]
def getIKValues(armatureName, bone, boneEnd): armature_ob = bpy.context.scene.objects[armatureName] #armature_data = armature_ob.data bpy.ops.object.mode_set(mode='EDIT', toggle=False) eb_bone = armature_ob.data.edit_bones[bone] eb_boneEnd = armature_ob.data.edit_bones[boneEnd] line = (eb_bone.head, eb_bone.tail) point = eb_boneEnd.head intersect = intersect_point_line(point, line[0], line[1]) distance = (intersect[0] - eb_bone.head).length ikEffector = Vector((distance, 0, 0)) ikHandle = armature_ob.matrix_world * intersect[0] bpy.ops.object.mode_set(mode='OBJECT', toggle=False) return ikEffector, ikHandle
def region_2d_to_location_3d(region, rv3d, coord, depth_location): """ Return a 3d location from the region relative 2d coords, aligned with *depth_location*. :arg region: region of the 3D viewport, typically bpy.context.region. :type region: :class:`bpy.types.Region` :arg rv3d: 3D region data, typically bpy.context.space_data.region_3d. :type rv3d: :class:`bpy.types.RegionView3D` :arg coord: 2d coordinates relative to the region; (event.mouse_region_x, event.mouse_region_y) for example. :type coord: 2d vector :arg depth_location: the returned vectors depth is aligned with this since there is no defined depth with a 2d region input. :type depth_location: 3d vector :return: normalized 3d vector. :rtype: :class:`mathutils.Vector` """ from mathutils import Vector from mathutils.geometry import intersect_point_line persmat = rv3d.perspective_matrix.copy() viewinv = rv3d.view_matrix.inverted() coord_vec = region_2d_to_vector_3d(region, rv3d, coord) depth_location = Vector(depth_location) if rv3d.is_perspective: from mathutils.geometry import intersect_line_plane origin_start = viewinv.translation.copy() origin_end = origin_start + coord_vec view_vec = viewinv.col[2].copy() return intersect_line_plane(origin_start, origin_end, depth_location, view_vec, 1, ) else: dx = (2.0 * coord[0] / region.width) - 1.0 dy = (2.0 * coord[1] / region.height) - 1.0 persinv = persmat.inverted() viewinv = rv3d.view_matrix.inverted() origin_start = ((persinv.col[0].xyz * dx) + (persinv.col[1].xyz * dy) + viewinv.translation) origin_end = origin_start + coord_vec return intersect_point_line(depth_location, origin_start, origin_end, )[0]
def point_on_edge(p, edge): """Find Point on Edge. Args: p: vector edge: tuple containing 2 vectors. Returns: True if point p happens to lie on the edge, False otherwise. """ pt, _percent = intersect_point_line(p, *edge) on_line = (pt - p).length < 1.0e-5 return on_line and (0.0 <= _percent <= 1.0)
def hover(self, context, x, y): ''' hovering happens in screen space, 20 pixels thresh for points, 30 for edges ''' self.mouse = Vector((x, y)) if len(self.pts) == 0: return def dist(v): diff = v - Vector((x, y)) return diff.length loc3d_reg2D = view3d_utils.location_3d_to_region_2d screen_pts = [ loc3d_reg2D(context.region, context.space_data.region_3d, pt) for pt in self.pts ] closest_point = min(screen_pts, key=dist) if (closest_point - Vector((x, y))).length < 20: self.hovered = ['POINT', screen_pts.index(closest_point)] return if len(self.pts) < 2: self.hovered = [None, -1] return for i in range(0, len(self.pts)): a = loc3d_reg2D(context.region, context.space_data.region_3d, self.pts[i]) next = (i + 1) % len(self.pts) b = loc3d_reg2D(context.region, context.space_data.region_3d, self.pts[next]) if b == 0 and not self.cyclic: self.hovered = [None, -1] return if a and b: intersect = intersect_point_line( Vector((x, y)).to_3d(), a.to_3d(), b.to_3d()) if intersect: dist = (intersect[0].to_2d() - Vector( (x, y))).length_squared bound = intersect[1] if (dist < 900) and (bound < 1) and (bound > 0): self.hovered = ['EDGE', i] return self.hovered = [None, -1]
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 hover(self,context,x,y): ''' hovering happens in screen space, 20 pixels thresh for points, 30 for edges ''' self.mouse = Vector((x, y)) if len(self.pts) == 0: return def dist(v): diff = v - Vector((x,y)) return diff.length loc3d_reg2D = view3d_utils.location_3d_to_region_2d screen_pts = [loc3d_reg2D(context.region, context.space_data.region_3d, pt) for pt in self.pts] closest_point = min(screen_pts, key = dist) if (closest_point - Vector((x,y))).length < 20: self.hovered = ['POINT',screen_pts.index(closest_point)] return if len(self.pts) < 2: self.hovered = [None, -1] return for i in range(0,len(self.pts)): a = loc3d_reg2D(context.region, context.space_data.region_3d,self.pts[i]) next = (i + 1) % len(self.pts) b = loc3d_reg2D(context.region, context.space_data.region_3d,self.pts[next]) if b == 0 and not self.cyclic: self.hovered = [None, -1] return if a and b: intersect = intersect_point_line(Vector((x,y)).to_3d(), a.to_3d(),b.to_3d()) if intersect: dist = (intersect[0].to_2d() - Vector((x,y))).length_squared bound = intersect[1] if (dist < 900) and (bound < 1) and (bound > 0): self.hovered = ['EDGE',i] return self.hovered = [None, -1]
def f_4(me, list_e, list_0): dict_1 = {vi: [] for vi in list_0} for i in list_e: lp1 = (me.vertices[i[0]].co).copy() lp2 = (me.vertices[i[1]].co).copy() for vi in list_0: v = (me.vertices[vi].co).copy() p1 = intersect_point_line( v, lp1, lp2)[0] me.vertices.add(1) me.vertices[-1].co = p1 me.vertices[-1].select = False dict_1[vi].append(me.vertices[-1].index) n = len(list_e) edge_copy_1(me, dict_1, n) faces_copy_1(me, dict_1, n)
def start_grad_f(f, p): g = gradient_face(f, geos) L = f.calc_perimeter() # test for vert intersection for v in f.verts: v_inter, pct = intersect_point_line(v.co, p, p - L * g) delta = v.co - v_inter if delta.length < epsilon: print("intersects vert") return v, v.co, None for e in f.edges: v0, v1 = intersect_line_line(e.verts[0].co, e.verts[1].co, p, p - L * g) V = v0 - e.verts[0].co edV = e.verts[1].co - e.verts[0].co Vi = v0 - p if V.length - edV.length > epsilon: # print('intersects outside segment') continue elif V.dot(edV) < 0: # print('intersects behind') continue elif Vi.dot(g) > 0: # remember we watnt to travel DOWN the gradient # print('shoots out the face, not across the face') continue else: # print('regular face edge crossing') return v0, e, f # we didn't intersect across an edge, or on a vert, # therefore, we should travel ALONG the edge vret = min(f.verts, key=geos.get) return vret.co, vret, None
def perp_vector_point_line(pt1, pt2, ptn): ''' Vector bwettn pointn and line between point1 and point2 args: pt1, and pt1 are Vectors representing line segment return Vector pt1 ------------------- pt ^ | | |<-----this vector | ptn ''' pt_on_line = intersect_point_line(ptn, pt1, pt2)[0] alt_vect = pt_on_line - ptn return alt_vect
def testGroundCell(self): #test distance of closest point on poly to cell center, #if it is in range, cell becomes groundcell #if neighbors opposite to each other both are groundcells, cell itself #becomes groundcell too #print ("In testGroundCell") if self.grid.grounds == None: return None for ground in self.grid.grounds: # print ("GROUND/EDGE: ", ground, ground.edges) for edge in ground.edges: closest = geometry.intersect_point_line(Vector(self.center), Vector(edge[0]), Vector(edge[1])) vec = closest[0] percentage = closest[1] # print(vec.to_tuple(), self.center, self.gridPos) if self.isInside(vec.to_tuple(), percentage) and not self.isGroundCell: print("Found Ground Cell: ", self.gridPos, vec, percentage) self.isGroundCell = True
def execute(self, context): edit_mode_out() ob_act = context.active_object me = ob_act.data list_0 = [v.index for v in me.vertices if v.select] if len(va_buf.list_v) != 2: self.report({'INFO'}, 'Two guide vertices must be stored in memory.') edit_mode_in() return {'CANCELLED'} elif len(va_buf.list_v) > 1: if len(list_0) == 0: self.report({'INFO'}, 'No vertices selected') edit_mode_in() return {'CANCELLED'} elif len(list_0) != 0: p1 = (me.vertices[va_buf.list_v[0]].co).copy() p2 = (me.vertices[va_buf.list_v[1]].co).copy() for i in list_0: v = (me.vertices[i].co).copy() me.vertices[i].co = intersect_point_line( v, p1, p2)[0] edit_mode_in() return {'FINISHED'}
def com_line_cross_test(com1, com2, pt, no, factor = 2): ''' test used to make sure a cut is reasoably between 2 other cuts higher factor requires better aligned cuts ''' v = intersect_line_plane(com1,com2,pt,no) if v: #if the distance between the intersection is less than #than 1/factor the distance between the current pair #than this pair is invalide because there is a loop #in between check = intersect_point_line(v,com1,com2) invalid_length = (com2 - com1).length/factor #length beyond which an intersection is invalid test_length = (v - pt).length #this makes sure the plane is between A and B #meaning the test plane is between the two COM's in_between = check[1] >= 0 and check[1] <= 1 if in_between and test_length < invalid_length: return True
def distance_point_line(pt, line_p1, line_p2): int_co = intersect_point_line(pt, line_p1, line_p2) distance_vector = int_co[0] - pt return distance_vector
def process(self): verts = self.inputs['Vertices'].sv_get() if self.inputs['PolyEdge'].is_linked: poly_edge = self.inputs['PolyEdge'].sv_get() poly_in = True else: poly_in = False poly_edge = repeat_last([[]]) verts_out = [] poly_edge_out = [] item_order = [] poly_output = poly_in and self.outputs['PolyEdge'].is_linked order_output = self.outputs['Item order'].is_linked vert_output = self.outputs['Vertices'].is_linked if not any((vert_output, order_output, poly_output)): return if self.mode == 'XYZ': # should be user settable op_order = [(0, False), (1, False), (2, False)] for v, p in zip(verts, poly_edge): s_v = ((e[0], e[1], e[2], i) for i, e in enumerate(v)) for item_index, rev in op_order: s_v = sorted(s_v, key=itemgetter(item_index), reverse=rev) verts_out.append([v[:3] for v in s_v]) if poly_output: v_index = {item[-1]: j for j, item in enumerate(s_v)} poly_edge_out.append([list(map(lambda n:v_index[n], pe)) for pe in p]) if order_output: item_order.append([i[-1] for i in s_v]) if self.mode == 'DIST': if self.inputs['Base Point'].is_linked: base_points = self.inputs['Base Point'].sv_get() bp_iter = repeat_last(base_points[0]) else: bp = [(0, 0, 0)] bp_iter = repeat_last(bp) for v, p, v_base in zip(verts, poly_edge, bp_iter): s_v = sorted(((v_c, i) for i, v_c in enumerate(v)), key=lambda v: distK(v[0], v_base)) verts_out.append([vert[0] for vert in s_v]) if poly_output: v_index = {item[-1]: j for j, item in enumerate(s_v)} poly_edge_out.append([list(map(lambda n:v_index[n], pe)) for pe in p]) if order_output: item_order.append([i[-1] for i in s_v]) if self.mode == 'AXIS': if self.inputs['Mat'].is_linked: mat = Matrix_generate(self.inputs['Mat'].sv_get()) else: mat = [Matrix. Identity(4)] mat_iter = repeat_last(mat) def f(axis, q): if axis.dot(q.axis) > 0: return q.angle else: return -q.angle for v, p, m in zip(Vector_generate(verts), poly_edge, mat_iter): axis = m * Vector((0, 0, 1)) axis_norm = m * Vector((1, 0, 0)) base_point = m * Vector((0, 0, 0)) intersect_d = [intersect_point_line(v_c, base_point, axis) for v_c in v] rotate_d = [f(axis, (axis_norm + v_l[0]).rotation_difference(v_c)) for v_c, v_l in zip(v, intersect_d)] s_v = ((data[0][1], data[1], i) for i, data in enumerate(zip(intersect_d, rotate_d))) s_v = sorted(s_v, key=itemgetter(0, 1)) verts_out.append([v[i[-1]].to_tuple() for i in s_v]) if poly_output: v_index = {item[-1]: j for j, item in enumerate(s_v)} poly_edge_out.append([list(map(lambda n:v_index[n], pe)) for pe in p]) if order_output: item_order.append([i[-1] for i in s_v]) if self.mode == 'USER': if self.inputs['Index Data'].is_linked: index = self.inputs['Index Data'].sv_get() else: return for v, p, i in zip(verts, poly_edge, index): s_v = sorted([(data[0], data[1], i) for i, data in enumerate(zip(i, v))], key=itemgetter(0)) verts_out.append([obj[1] for obj in s_v]) if poly_output: v_index = {item[-1]: j for j, item in enumerate(s_v)} poly_edge_out.append([[v_index[k] for k in pe] for pe in p]) if order_output: item_order.append([i[-1] for i in s_v]) if self.mode == 'CONNEX': if self.inputs['PolyEdge'].is_linked: edges = self.inputs['PolyEdge'].sv_get() for v, p in zip(verts, edges): pols = [] if len(p[0]) > 2: pols = [p[:]] p = pols_edges([p], True)[0] vect_new, pol_edge_new, index_new = sort_vertices_by_connexions(v, p, self.limit_mode) if len(pols) > 0: new_pols = [] for pol in pols[0]: new_pol = [] for i in pol: new_pol.append(index_new.index(i)) new_pols.append(new_pol) pol_edge_new = [new_pols] verts_out.append(vect_new) poly_edge_out.append(pol_edge_new) item_order.append(index_new) if vert_output: self.outputs['Vertices'].sv_set(verts_out) if poly_output: self.outputs['PolyEdge'].sv_set(poly_edge_out) if order_output: self.outputs['Item order'].sv_set(item_order)
def handleManipulator(objs, target): # start move if logic.mouse.events[events.LEFTMOUSE] == inputActivated and target and target.name in ["x", "y", "z", "widget"]: logic.moving = target centerPos = logic.viewCamObject.getScreenPosition(logic.scene.objects["widget"]) logic.mousePosOffset = [logic.mouse.position[0]-centerPos[0], logic.mouse.position[1]-centerPos[1]] logic.undo.append("Moved") elif logic.mouse.events[events.LEFTMOUSE] == inputActivated and target and target.name in ["rx", "ry", "rz"]: logic.rotating = target logic.undo.append("Rotated") logic.rotatingAmount = [0,0,0] # while moving widget elif logic.mouse.events[events.LEFTMOUSE] == inputActive and logic.moving: # setup variables for ray/ray intersect # compute camera pos camPos = logic.viewCamObject.worldPosition v1 = Vector(camPos) # if 'win' in releaseOS: # print("h") #http://projects.blender.org/tracker/index.php?func=detail&aid=33943&group_id=9&atid=306 # compute camera ray end pos offsettedPos = [logic.mouse.position[0]-logic.mousePosOffset[0], logic.mouse.position[1]-logic.mousePosOffset[1]] vec = logic.viewCamObject.getScreenVect(*offsettedPos) camProjPos = list(camPos[:]) camProjPos[0] -= vec[0] * 500 camProjPos[1] -= vec[1] * 500 camProjPos[2] -= vec[2] * 500 v2 = Vector(camProjPos) # compute widget pos widgetPos = logic.widgetObject.worldPosition v3 = Vector(widgetPos) # compute widget ray end pos mat = logic.widgetObject.worldTransform if logic.moving.name == 'x': transMat = Matrix.Translation(Vector((500,0,0))) elif logic.moving.name == 'y': transMat = Matrix.Translation(Vector((0,500,0))) elif logic.moving.name == 'z': transMat = Matrix.Translation(Vector((0,0,500))) else: transMat = Matrix.Translation(Vector((0,0,0))) # merge orientation/scaling with new translation extendedMat = mat*transMat v4 = extendedMat.translation # compute ray/ray interset, return list of tuples # ...for the closest point on each line to each other result = geometry.intersect_line_line(v1, v2, v3, v4) try: widgetTargetPos = result[1] # this is where the widget should be except: pass # special case for moving center widget if logic.moving.name == 'widget': result = geometry.intersect_point_line(widgetPos, v1, v2) widgetTargetPos = list(result[0]) # apply transform logic.pivotObject.worldPosition = widgetTargetPos logic.widgetObject.worldPosition = widgetTargetPos # while rotating widget elif logic.mouse.events[events.LEFTMOUSE] == inputActive and logic.rotating: rot = list(logic.widgetObject.worldOrientation.to_euler()[0:3]) x = logic.mousePosDelta[0] * 10.0 y = logic.mousePosDelta[1] * 10.0 # flip axis camAlignment = 1 widgetAlignment = 1 # compute screenspace mouse position relative to widget centre # i.e. which quadrant the mouse is relative to the widget centre widgetPosXY = list(logic.viewCamObject.getScreenPosition(logic.widgetObject)) mousePosXY = logic.mouse.position diffXY = (widgetPosXY[0]-mousePosXY[0], widgetPosXY[1]-mousePosXY[1]) if logic.rotating.name == "rx": if logic.viewCamObject.worldPosition[0] > 0: camAlignment = -1 if diffXY[1] < 0: widgetAlignment = -1 rot[0] += x*camAlignment*widgetAlignment if diffXY[0] < 0: widgetAlignment = 1 else: widgetAlignment = -1 rot[0] += y*camAlignment*widgetAlignment elif logic.rotating.name == "ry": if logic.viewCamObject.worldPosition[1] > 0: camAlignment = -1 if diffXY[1] < 0: widgetAlignment = -1 rot[1] += x * camAlignment*widgetAlignment if diffXY[0] < 0: widgetAlignment = 1 else: widgetAlignment = -1 rot[1] += y * camAlignment*widgetAlignment elif logic.rotating.name == "rz": rot[2] += x * camAlignment * widgetAlignment # integrate over time (for the duration of the mouse interaction) logic.rotatingAmount[0] += rot[0] logic.rotatingAmount[1] += rot[1] logic.rotatingAmount[2] += rot[2] #apply transform logic.pivotObject.worldOrientation = rot logic.widgetObject.worldOrientation = rot # finish elif logic.mouse.events[events.LEFTMOUSE] == inputDeactivated and (logic.moving or logic.rotating or logic.mouseLock == 0): if logic.moving: logic.pluggable.edit.moved.notify() if logic.rotating: logic.pluggable.edit.rotated.notify() # set manipulation flags to false logic.moving = False logic.rotating = False # saves all keyframe for current slide # do before removing parents logic.mvb.slides[logic.mvb.activeSlide].capture() # unlink obj(s) to pivot for obj in logic.pivotObject.children: obj.removeParent() logic.rotatingAmount = [0,0,0] # set mouseLock state if logic.moving or logic.rotating: logic.mouseLock = 2 else: logic.mouseLock = 0
def modal(self, context, event): if context.area: context.area.tag_redraw() if event.ctrl and event.type == 'Z' and event.value == 'PRESS': bpy.ops.ed.undo() self.vector_constrain = None self.list_verts_co = [] self.list_verts = [] self.list_edges = [] self.list_faces = [] self.obj = bpy.context.active_object self.obj_matrix = self.obj.matrix_world.copy() self.bm = bmesh.from_edit_mesh(self.obj.data) return {'RUNNING_MODAL'} if event.type == 'MOUSEMOVE' or self.bool_update: if self.rv3d.view_matrix != self.rotMat: self.rotMat = self.rv3d.view_matrix.copy() self.bool_update = True else: self.bool_update = False if self.bm.select_history: self.geom = self.bm.select_history[0] else: #See IndexError or AttributeError: self.geom = None x, y = (event.mouse_region_x, event.mouse_region_y) if self.geom: self.geom.select = False self.bm.select_history.clear() bpy.ops.view3d.select(location=(x, y)) if self.list_verts != []: previous_vert = self.list_verts[-1] else: previous_vert = None outer_verts = self.outer_verts and not self.keytab snap_utilities(self, context, self.obj_matrix, self.geom, self.bool_update, (x, y), outer_verts = self.outer_verts, constrain = self.vector_constrain, previous_vert = previous_vert, ignore_obj = self.obj, increment = self.incremental, ) if self.snap_to_grid and self.type == 'OUT': loc = self.location/self.rd self.location = Vector((round(loc.x), round(loc.y), round(loc.z)))*self.rd if self.keyf8 and self.list_verts_co: lloc = self.list_verts_co[-1] orig, view_vec = region_2d_to_orig_and_view_vector(self.region, self.rv3d, (x, y)) location = intersect_point_line(lloc, orig, (orig+view_vec)) vec = (location[0] - lloc) ax, ay, az = abs(vec.x),abs(vec.y),abs(vec.z) vec.x = ax > ay > az or ax > az > ay vec.y = ay > ax > az or ay > az > ax vec.z = az > ay > ax or az > ax > ay if vec == Vector(): self.vector_constrain = None else: vc = lloc+vec try: if vc != self.vector_constrain[1]: type = 'X' if vec.x else 'Y' if vec.y else 'Z' if vec.z else 'shift' self.vector_constrain = [lloc, vc, type] except: type = 'X' if vec.x else 'Y' if vec.y else 'Z' if vec.z else 'shift' self.vector_constrain = [lloc, vc, type] elif event.value == 'PRESS': if event.type in self.constrain_keys: self.bool_update = True if self.vector_constrain and self.vector_constrain[2] == event.type: self.vector_constrain = () else: if event.shift: if isinstance(self.geom, bmesh.types.BMEdge): if self.list_verts: loc = self.list_verts_co[-1] self.vector_constrain = (loc, loc + self.list_verts_co[-1] - self.list_verts_co[0], event.type) else: self.vector_constrain = [self.obj_matrix * v.co for v in self.geom.verts]+[event.type] else: if self.list_verts: loc = self.list_verts_co[-1] else: loc = self.location self.vector_constrain = [loc, loc + self.constrain_keys[event.type]]+[event.type] if self.list_verts_co and (event.ascii in CharMap.ascii or event.type in CharMap.type): CharMap.modal(self, context, event) #print(self.length_entered) elif event.type == 'LEFTMOUSE': # SNAP 2D snap_3d = self.location Lsnap_3d = self.obj_matrix.inverted()*snap_3d Snap_2d = location_3d_to_region_2d(self.region, self.rv3d, snap_3d) if self.vector_constrain and isinstance(self.geom, bmesh.types.BMVert): # SELECT FIRST bpy.ops.view3d.select(location=(int(Snap_2d[0]), int(Snap_2d[1]))) try: geom2 = self.bm.select_history[0] except: # IndexError or AttributeError: geom2 = None else: geom2 = self.geom self.vector_constrain = None self.list_verts_co = draw_line(self, self.obj, self.bm, geom2, Lsnap_3d) bpy.ops.ed.undo_push(message="Undo draw line*") elif event.type == 'TAB': self.keytab = self.keytab == False if self.keytab: context.tool_settings.mesh_select_mode = (False, False, True) else: context.tool_settings.mesh_select_mode = (True, True, True) elif event.type == 'F8': self.vector_constrain = None self.keyf8 = self.keyf8 == False elif event.value == 'RELEASE': if event.type in {'RET', 'NUMPAD_ENTER'}: if self.length_entered != "" and self.list_verts_co: try: text_value = bpy.utils.units.to_value(self.unit_system, 'LENGTH', self.length_entered) vector = (self.location-self.list_verts_co[-1]).normalized() location = (self.list_verts_co[-1]+(vector*text_value)) G_location = self.obj_matrix.inverted()*location self.list_verts_co = draw_line(self, self.obj, self.bm, self.geom, G_location) self.length_entered = "" self.vector_constrain = None except:# ValueError: self.report({'INFO'}, "Operation not supported yet") elif event.type in {'RIGHTMOUSE', 'ESC'}: if self.list_verts_co == [] or event.type == 'ESC': bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') context.tool_settings.mesh_select_mode = self.select_mode context.area.header_text_set() context.user_preferences.view.use_rotate_around_active = self.use_rotate_around_active if not self.is_editmode: bpy.ops.object.editmode_toggle() return {'FINISHED'} else: self.vector_constrain = None self.list_verts = [] self.list_verts_co = [] self.list_faces = [] a = "" if self.list_verts_co: if self.length_entered: pos = self.line_pos a = 'length: '+ self.length_entered[:pos] + '|' + self.length_entered[pos:] else: length = self.len length = convert_distance(length, self.uinfo) a = 'length: '+ length context.area.header_text_set("hit: %.3f %.3f %.3f %s" % (self.location[0], self.location[1], self.location[2], a)) self.modal_navigation(context, event) return {'RUNNING_MODAL'}
def snap_utilities(self, context, obj_matrix_world, bm_geom, bool_update, mcursor, outer_verts = False, constrain = None, previous_vert = None, ignore_obj = None, increment = 0.0): rv3d = context.region_data region = context.region is_increment = False if not hasattr(self, 'snap_cache'): self.snap_cache = True self.type = 'OUT' self.bvert = None self.bedge = None self.bface = None self.hit = False self.out_obj = None if bool_update: #self.bvert = None self.bedge = None #self.bface = None if isinstance(bm_geom, bmesh.types.BMVert): self.type = 'VERT' if self.bvert != bm_geom: self.bvert = bm_geom self.vert = obj_matrix_world * self.bvert.co #self.Pvert = location_3d_to_region_2d(region, rv3d, self.vert) if constrain: #self.location = (self.vert-self.const).project(vector_constrain) + self.const location = intersect_point_line(self.vert, constrain[0], constrain[1]) #factor = location[1] self.location = location[0] else: self.location = self.vert elif isinstance(bm_geom, bmesh.types.BMEdge): if self.bedge != bm_geom: self.bedge = bm_geom self.vert0 = obj_matrix_world*self.bedge.verts[0].co self.vert1 = obj_matrix_world*self.bedge.verts[1].co self.po_cent = (self.vert0+self.vert1)/2 self.Pcent = location_3d_to_region_2d(region, rv3d, self.po_cent) self.Pvert0 = location_3d_to_region_2d(region, rv3d, self.vert0) self.Pvert1 = location_3d_to_region_2d(region, rv3d, self.vert1) if previous_vert and previous_vert not in self.bedge.verts: pvert_co = obj_matrix_world*previous_vert.co point_perpendicular = intersect_point_line(pvert_co, self.vert0, self.vert1) self.po_perp = point_perpendicular[0] #factor = point_perpendicular[1] self.Pperp = location_3d_to_region_2d(region, rv3d, self.po_perp) if constrain: location = intersect_line_line(constrain[0], constrain[1], self.vert0, self.vert1) if location == None: is_increment = True orig, view_vector = region_2d_to_orig_and_view_vector(region, rv3d, mcursor) end = orig + view_vector location = intersect_line_line(constrain[0], constrain[1], orig, end) self.location = location[0] elif hasattr(self, 'Pperp') and abs(self.Pperp[0]-mcursor[0]) < 10 and abs(self.Pperp[1]-mcursor[1]) < 10: self.type = 'PERPENDICULAR' self.location = self.po_perp elif abs(self.Pcent[0]-mcursor[0]) < 10 and abs(self.Pcent[1]-mcursor[1]) < 10: self.type = 'CENTER' self.location = self.po_cent else: if increment and previous_vert in self.bedge.verts: is_increment = True self.type = 'EDGE' orig, view_vector = region_2d_to_orig_and_view_vector(region, rv3d, mcursor) end = orig + view_vector self.location = intersect_line_line(self.vert0, self.vert1, orig, end)[0] elif isinstance(bm_geom, bmesh.types.BMFace): is_increment = True self.type = 'FACE' if self.bface != bm_geom: self.bface = bm_geom self.face_center = obj_matrix_world*bm_geom.calc_center_median() self.face_normal = bm_geom.normal*obj_matrix_world.inverted() orig, view_vector = region_2d_to_orig_and_view_vector(region, rv3d, mcursor) end = orig + view_vector location = intersect_line_plane(orig, end, self.face_center, self.face_normal, False) if constrain: is_increment = False location = intersect_point_line(location, constrain[0], constrain[1])[0] self.location = location else: is_increment = True self.type = 'OUT' orig, view_vector = region_2d_to_orig_and_view_vector(region, rv3d, mcursor) end = orig + view_vector * 1000 if not outer_verts or self.out_obj == None: result, self.out_obj, self.out_mat, self.location, normal = context.scene.ray_cast(orig, end) self.out_mat_inv = self.out_mat.inverted() #print(self.location) if self.out_obj and self.out_obj != ignore_obj: self.type = 'FACE' if outer_verts: # get the ray relative to the self.out_obj ray_origin_obj = self.out_mat_inv * orig ray_target_obj = self.out_mat_inv * end location, normal, face_index = self.out_obj.ray_cast(ray_origin_obj, ray_target_obj) if face_index == -1: self.out_obj = None else: self.location = self.out_mat*location try: verts = self.out_obj.data.polygons[face_index].vertices v_dist = 100 for i in verts: v_co = self.out_mat*self.out_obj.data.vertices[i].co v_2d = location_3d_to_region_2d(region, rv3d, v_co) dist = (Vector(mcursor)-v_2d).length_squared if dist < v_dist: is_increment = False self.type = 'VERT' v_dist = dist self.location = v_co except: print('Fail') if constrain: is_increment = False self.preloc = self.location self.location = intersect_point_line(self.preloc, constrain[0], constrain[1])[0] else: if constrain: self.location = intersect_line_line(constrain[0], constrain[1], orig, end)[0] else: self.location = out_Location(rv3d, region, orig, view_vector) if previous_vert: pvert_co = obj_matrix_world*previous_vert.co vec = self.location - pvert_co if is_increment and increment: pvert_co = obj_matrix_world*previous_vert.co vec = self.location - pvert_co self.len = round((1/increment)*vec.length)*increment self.location = self.len*vec.normalized() + pvert_co else: self.len = vec.length
def intersect_boundbox_threshold(sctx, MVP, ray_origin_local, ray_direction_local, bbmin, bbmax): local_bvmin = Vector() local_bvmax = Vector() tmin = Vector() tmax = Vector() if (ray_direction_local[0] < 0.0): local_bvmin[0] = bbmax[0] local_bvmax[0] = bbmin[0] else: local_bvmin[0] = bbmin[0] local_bvmax[0] = bbmax[0] if (ray_direction_local[1] < 0.0): local_bvmin[1] = bbmax[1] local_bvmax[1] = bbmin[1] else: local_bvmin[1] = bbmin[1] local_bvmax[1] = bbmax[1] if (ray_direction_local[2] < 0.0): local_bvmin[2] = bbmax[2] local_bvmax[2] = bbmin[2] else: local_bvmin[2] = bbmin[2] local_bvmax[2] = bbmax[2] if (ray_direction_local[0]): tmin[0] = (local_bvmin[0] - ray_origin_local[0]) / ray_direction_local[0] tmax[0] = (local_bvmax[0] - ray_origin_local[0]) / ray_direction_local[0] else: tmin[0] = sctx.depth_range[0] tmax[0] = sctx.depth_range[1] if (ray_direction_local[1]): tmin[1] = (local_bvmin[1] - ray_origin_local[1]) / ray_direction_local[1] tmax[1] = (local_bvmax[1] - ray_origin_local[1]) / ray_direction_local[1] else: tmin[1] = sctx.depth_range[0] tmax[1] = sctx.depth_range[1] if (ray_direction_local[2]): tmin[2] = (local_bvmin[2] - ray_origin_local[2]) / ray_direction_local[2] tmax[2] = (local_bvmax[2] - ray_origin_local[2]) / ray_direction_local[2] else: tmin[2] = sctx.depth_range[0] tmax[2] = sctx.depth_range[1] # `va` and `vb` are the coordinates of the AABB edge closest to the ray # va = Vector() vb = Vector() # `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB # if ((tmax[0] <= tmax[1]) and (tmax[0] <= tmax[2])): rtmax = tmax[0] va[0] = vb[0] = local_bvmax[0] main_axis = 3 elif ((tmax[1] <= tmax[0]) and (tmax[1] <= tmax[2])): rtmax = tmax[1] va[1] = vb[1] = local_bvmax[1] main_axis = 2 else: rtmax = tmax[2] va[2] = vb[2] = local_bvmax[2] main_axis = 1 if ((tmin[0] >= tmin[1]) and (tmin[0] >= tmin[2])): rtmin = tmin[0] va[0] = vb[0] = local_bvmin[0] main_axis -= 3 elif ((tmin[1] >= tmin[0]) and (tmin[1] >= tmin[2])): rtmin = tmin[1] va[1] = vb[1] = local_bvmin[1] main_axis -= 1 else: rtmin = tmin[2] va[2] = vb[2] = local_bvmin[2] main_axis -= 2 if (main_axis < 0): main_axis += 3 #ifdef IGNORE_BEHIND_RAY depth_max = depth_get(local_bvmax, ray_origin_local, ray_direction_local) if (depth_max < sctx.depth_range[0]): return False #endif if (rtmin <= rtmax): # if rtmin < rtmax, ray intersect `AABB` # return True if (ray_direction_local[main_axis] < 0.0): va[main_axis] = local_bvmax[main_axis] vb[main_axis] = local_bvmin[main_axis] else: va[main_axis] = local_bvmin[main_axis] vb[main_axis] = local_bvmax[main_axis] win_half = sctx.winsize * 0.5 scale = abs(local_bvmax[main_axis] - local_bvmin[main_axis]) va2d = Vector(( (MVP[0].xyz.dot(va) + MVP[0][3]), (MVP[1].xyz.dot(va) + MVP[1][3]), )) vb2d = Vector(( (va2d[0] + MVP[0][main_axis] * scale), (va2d[1] + MVP[1][main_axis] * scale), )) depth_a = MVP[3].xyz.dot(va) + MVP[3][3] depth_b = depth_a + MVP[3][main_axis] * scale va2d /= depth_a vb2d /= depth_b va2d[0] = (va2d[0] + 1.0) * win_half[0] va2d[1] = (va2d[1] + 1.0) * win_half[1] vb2d[0] = (vb2d[0] + 1.0) * win_half[0] vb2d[1] = (vb2d[1] + 1.0) * win_half[1] p, fac = intersect_point_line(sctx.mval, va2d, vb2d) if fac < 0.0: return (sctx.mval - va2d).length_squared < sctx._dist_px_sq elif fac > 1.0: return (sctx.mval - vb2d).length_squared < sctx._dist_px_sq else: return (sctx.mval - p).length_squared < sctx._dist_px_sq