Community
Fusion API and Scripts
Got a new add-in to share? Need something specialized to be scripted? Ask questions or share what you’ve discovered with the community.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Vector3d.transformBy(RotationMatrix) does not change vector

3 REPLIES 3
Reply
Message 1 of 4
nnamfoh
794 Views, 3 Replies

Vector3d.transformBy(RotationMatrix) does not change vector

    assert(theta >0.0001 and theta < (2.0*math.pi))
    assert(normal.length ==1)
    assert(axis.length ==1)
    r1 = adsk.core.Matrix3D.create()
    r2 = adsk.core.Matrix3D.create()
    r1.setToRotation(theta/2.0, normal, origin)
    ui.messageBox("r1:"+str(r1.asArray()))
    r2.setToRotation(math.pi*2.0 - theta/2.0, normal, origin)
    c1 = axis
    assert(c1.transformBy(r1))
    assert(c1.length >0.0001 or c1.length<-0.0001)
    assert(c1.isPerpendicularTo(normal))

I'm trying to rotate a vector by a user specified angle about a normal to a given plane. Using the rotation matrix functions available.

However this seems to fail because c1 results in the same vector at axis. I'm testing with theta == math.radians(45), a normal of (0,1,0) (y axis) and an axis of (-1,0,0) (reverse x axis)

 

I would expect the Vector3D.transformBy(Matrix3D) function to compute M*v in and then set v based on homogenized coordinates. Is this not true


Is there an alternative way to compute a vector rotated about an arbitrary axis. 

3 REPLIES 3
Message 2 of 4
ekinsb
in reply to: nnamfoh

I had a hard time following what you were trying to do in the sample code. Here's a simple example that creates a vector in the X direction and then uses a matrix to rotate it 90 degrees around the Z axis and it returns the correct result.

 

def vectorTransform():
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface

        vec = adsk.core.Vector3D.create(1,0,0)
        mat = adsk.core.Matrix3D.create()
        mat.setToRotation(math.pi/2, adsk.core.Vector3D.create(0,0,1), adsk.core.Point3D.create(0,0,0))
        ui.messageBox(str(vec.asArray()))            
        vec.transformBy(mat)
        ui.messageBox(str(vec.asArray()))            
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

Brian Ekins
Inventor and Fusion 360 API Expert
Mod the Machine blog
Message 3 of 4
simon.trendel
in reply to: ekinsb

It seems the transformBy function does not apply the translational part of the matrix when using Vector3D instead of Point3D, checkout the following simple example:

 

 

import adsk.core

def run(context):
    
    m = adsk.core.Matrix3D.create()
    m.translation = adsk.core.Vector3D.create(0,0,1)
    print(m.asArray()) # (1.0, 0.0, 0.0, 0.0, 
                       #  0.0, 1.0, 0.0, 0.0, 
                       #  0.0, 0.0, 1.0, 1.0, 
                       #  0.0, 0.0, 0.0, 1.0)
    
    v = adsk.core.Vector3D.create(0,0,0)    
    v.transformBy(m)
    print(v.asArray()) # (0.0, 0.0, 0.0)
    
    v = adsk.core.Point3D.create(0,0,0)
    v.transformBy(m)
    print(v.asArray()) # (0.0, 0.0, 1.0)

Looks like a serious bug to me...

Message 4 of 4
ross.korsky
in reply to: simon.trendel

The Matrix implementation exposed by Fusion is fully functional and correct - just very non standard IMO - speaking as someone who is used to graphical Matrix operations such as HTML's canvas or GDI/GDI+

 

I've written a wrapper over the Matrix class which makes it behave how I expect/need. Feel free to use it as a base for your own or as-is. This code contains a few other choice helpers as well. I call this file "better_types.py" 😉

 

__all__ = ['Point3D', 'format_point', 'points_eq', 'Matrix', 'ObjectCollectionFromList', 'ObjectCollectionToList', 'ConcatenateObjectCollections']
import adsk.core, adsk.fusion
from numbers import Number

def format_point(point, fmt='{:}'):
  s = '('
  s += fmt.format(point.x)
  s += ', '
  s += fmt.format(point.y)
  if point.z:
    s += ', ' + fmt.format(point.z)
  s += ')'
  return s

def points_eq(p1, p2, epsilon=1e-8):
  if p1 is p2: return True
  if isinstance(p1, adsk.fusion.SketchPoint):
    p1 = p1.geometry
  if isinstance(p2, adsk.fusion.SketchPoint):
    p2 = p2.geometry
  dx = (p1.x - p2.x)**2
  dy = (p1.y - p2.y)**2
  dz = (p1.z - p2.z)**2
  return (dx + dy + dz) <= epsilon**2

def Point3D(x, y, z=0):
  return adsk.core.Point3D.create(x, y, z)


def ObjectCollectionFromList(l):
  oc = adsk.core.ObjectCollection.create()
  for item in l:
    oc.add(item)
  return oc


def ObjectCollectionToList(oc):
  l = []
  for item in oc:
    l.append(item)
  return l


def ConcatenateObjectCollections(l, r):
  for item in r:
    l.add(item)
  return l


class Matrix(object):
  X_AXIS = adsk.core.Vector3D.create(1, 0, 0)
  Y_AXIS = adsk.core.Vector3D.create(0, 1, 0)
  Z_AXIS = adsk.core.Vector3D.create(0, 0, 1)
  ORIGIN = adsk.core.Point3D.create(0, 0, 0)

  def __init__(self, from_matrix=None):
    if from_matrix is None:
      self._m = adsk.core.Matrix3D.create()
    elif isinstance(from_matrix, Matrix):
      self._m = from_matrix._m.copy()
    elif isinstance(from_matrix, adsk.core.Matrix3D):
      self._m = from_matrix.copy()
    else:
      raise 'Invalid transformation matrix type.'

  def as_fusion_matrix3D(self):
    return self._m.copy()

  def copy(self):
    return Matrix(self)

  def identity(self):
    self._m = adsk.core.Matrix3D.create()
    return self

  def translate(self, x_or_point, y=0, z=0):
    if isinstance(x_or_point, Number):
      x = x_or_point
    else:
      x = x_or_point.x
      y = x_or_point.y
      z = x_or_point.z
    m = adsk.core.Matrix3D.create()
    m.translation = adsk.core.Vector3D.create(x, y, z)
    self._m.transformBy(m)
    return self

  def rotate_about_x_axis(self, angle):
    """Rotates about the x-axis."""
    m = adsk.core.Matrix3D.create()
    m.setToRotation(angle, Matrix.X_AXIS, Matrix.ORIGIN)
    self._m.transformBy(m)
    return self

  def rotate_about_y_axis(self, angle):
    """Rotates about the y-axis."""
    m = adsk.core.Matrix3D.create()
    m.setToRotation(angle, Matrix.Y_AXIS, Matrix.ORIGIN)
    self._m.transformBy(m)
    return self

  def rotate_about_z_axis(self, angle):
    """Rotates about the z-axis."""
    m = adsk.core.Matrix3D.create()
    m.setToRotation(angle, Matrix.Z_AXIS, Matrix.ORIGIN)
    self._m.transformBy(m)
    return self

  def scale(self, x=1, y=1, z=1):
    a = [x, 0, 0, 0,
         0, y, 0, 0,
         0, 0, z, 0,
         0, 0, 0, 1]

    m = adsk.core.Matrix3D.create()
    m.setWithArray(a)
    self.multiply(m)
    return self

  def reflect_about_yz(self):
    """Reflects through the X axis about the YZ plane."""
    return self.scale(-1, 1, 1)

  def reflect_about_xz(self):
    """Reflects through the Y axis about the XZ plane."""
    return self.scale(1, -1, 1)

  def reflect_about_xy(self):
    """Reflects through the Z axis about the XY plane."""
    return self.scale(1, 1, -1)

  def multiply(self, other):
    self._m.transformBy(other)
    return self

  def purify(self):
    a = self._m.asArray();
    b = []
    for i in range(16):
      if abs(a[i]) < 1e-15:
        b.append(0)
      elif abs(abs(a[i]) - 1) < 1e-15:
        if a[i] < 0:
          b.append(-1)
        else:
          b.append(1)
      else:
        b.append(a[i])
    self._m.setWithArray(b)
    return self

  def transform(self, x_or_points, y=0, z=0):
    """Transforms a list of points, a single point, or a literal x,y,z
    and returns a new list of, or single, transformed point(s).

    Args:
      x_or_points: May be a list of points, a single point, or a number representing 'x'.
      y: y cord
      z: z cord
    """
    if isinstance(x_or_points, list):
      new_points = []
      for p in x_or_points:
        b = p.copy()
        b.transformBy(self._m)
        new_points.append(b)
      return new_points

    if isinstance(x_or_points, Number):
      b = Point3D(x_or_points, y, z)
    else:
      assert isinstance(x_or_points, adsk.core.Point3D) or isinstance(x_or_points, adsk.core.Vector3D)
      b = x_or_points.copy()

    b.transformBy(self._m)
    return b

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report