def test(axis, equiv_ang: Py_Angle): for ang in range(0, 360, 15): assert_rot(Matrix.axis_angle(axis, ang), Matrix.from_angle(ang * equiv_ang), f'{axis} * {ang} != {equiv_ang}') # Inverse axis = reversed rotation. assert_rot(Matrix.axis_angle(-axis, ang), Matrix.from_angle(-ang * equiv_ang), f'{-axis} * {ang} != {equiv_ang}')
def res_rotate_inst(inst: Entity, res: Property) -> None: """Rotate the instance around an axis. If `axis` is specified, it should be a normal vector and the instance will be rotated `angle` degrees around it. Otherwise, `angle` is a pitch-yaw-roll angle which is applied. `around` can be a point (local, pre-rotation) which is used as the origin. """ angles = Angle.from_str(inst['angles']) if 'axis' in res: orient = Matrix.axis_angle( Vec.from_str(inst.fixup.substitute(res['axis'])), conv_float(inst.fixup.substitute(res['angle'])), ) else: orient = Matrix.from_angle( Angle.from_str(inst.fixup.substitute(res['angle']))) try: offset = Vec.from_str(inst.fixup.substitute(res['around'])) except NoKeyError: pass else: origin = Vec.from_str(inst['origin']) inst['origin'] = origin + (-offset @ orient + offset) @ angles inst['angles'] = (orient @ angles).to_angle()
def compute_orients(nodes: Iterable[Node]) -> None: """Compute the appropriate orientation for each node.""" # This is based on the info at: # https://janakiev.com/blog/framing-parametric-curves/ tangents: Dict[Node, Vec] = {} all_nodes: Set[Node] = set() for node in nodes: if node.prev is node.next is None: continue node_prev = node.prev if node.prev is not None else node node_next = node.next if node.next is not None else node tangents[node] = (node_next.pos - node_prev.pos).norm() all_nodes.add(node) while all_nodes: node1 = all_nodes.pop() node1 = node1.find_start() tanj1 = tangents[node1] # Start with an arbitrary roll for the first orientation. node1.orient = Matrix.from_angle(tanj1.to_angle()) while node1.next is not None: node2 = node1.next all_nodes.discard(node2) tanj1 = tangents[node1] tanj2 = tangents[node2] b = Vec.cross(tanj1, tanj2) if b.mag_sq() < 0.001: node2.orient = node1.orient.copy() else: b = b.norm() phi = math.acos(Vec.dot(tanj1, tanj2)) up = node1.orient.up() @ Matrix.axis_angle( b, math.degrees(phi)) node2.orient = Matrix.from_basis(x=tanj2, z=up) node1 = node2