Rotate face to be perpendicular to a vector

I have created a 1 sq.ft face along the XY plane using the eye of a camera as its centroid:

  model = Sketchup.active_model
  entities = model.active_entities
  view = model.active_view
  cam = view.camera
  eye = cam.eye
  target = cam.target

  pts = [
    Geom::Point3d.new(eye[0] - 0.5.feet, eye[1] - 0.5.feet, eye[2]),
    Geom::Point3d.new(eye[0] + 0.5.feet, eye[1] - 0.5.feet, eye[2]),
    Geom::Point3d.new(eye[0] + 0.5.feet, eye[1] + 0.5.feet, eye[2]),
    Geom::Point3d.new(eye[0] - 0.5.feet, eye[1] + 0.5.feet, eye[2])
  ]

  gr = entities.add_group
  square = gr.entities.add_face ( pts )

I want the square to be perpendicular to the eye-target vector, i.e., rotating the square so the eye-target vector is a normal to its plane. I’ve tried the following geometry equations with no success:

  n = [0, 0, 1] # Current normal vector to the square
  v = [target[0] - eye[0], target[1] - eye[1], target[2] - eye[2]]  # eye-target vector
  axis = [v[1], -v[0], 0] # Axis of rotation given by vectorial product (v x n)
  magnitude = Math.sqrt( axis[0]**2 + axis[1]**2 + axis[2]**2 ) # Magnitude of axis
  u = [axis[0]/magnitude , axis[1]/magnitude , axis[2]/magnitude ] # Normalized axis
  theta = -Math.acos( v[2] / Math.sqrt(v[0]**2 + v[1]**2 + v[2]**2) ) # Angle of rotation given by scalar product (v · n)

The current normal vector to the square is n = [0,0,1] since it is generated along the XY plane. To calculate the new axis of rotation, a vectorial product (v x n) is needed, and then the axis is normalized. In the same way, I calculate the angle of rotation theta by the scalar product (v · n).

Having the point, the axis, and the angle, I can set the transformation:

  tr = Geom::Transformation.rotation( eye, u, theta )
  gr.transform!(tr)

But the result is not the expected. Could you help me to localize my mistake? Any other idea to solve the issue will be very welcomed too.

You might try something like this:

    model = Sketchup.active_model
    entities = model.active_entities
    view = model.active_view
    cam = view.camera
    eye = cam.eye
    target = cam.target
    pts = [
      Geom::Point3d.new(eye.x - 0.5.feet, eye.y - 0.5.feet, eye.z),
      Geom::Point3d.new(eye.x + 0.5.feet, eye.y - 0.5.feet, eye.z),
      Geom::Point3d.new(eye.x + 0.5.feet, eye.y + 0.5.feet, eye.z),
      Geom::Point3d.new(eye.x - 0.5.feet, eye.y + 0.5.feet, eye.z)
    ]
    gr = entities.add_group
    square = gr.entities.add_face ( pts )
    v1 = Geom::Vector3d.new(target.x - eye.x,target.y - eye.y,target.z - eye.z)
    v2 = square.normal
    angle = v1.angle_between(v2)
    v3 = v1 * v2
    if(v3.length != 0)
      rot = Geom::Transformation.rotation(eye,v3,-angle)
      gr.transform!(rot)
    end

Note that the square is nominally not displayed since the eye point is in the centroid of the square. Resizing the view will fix this.

2 Likes

Thank you. Actually I realized that my equations are ok, but Geom::Transformation is only working if eye and u are Point3D and Vector3D types respectively, and not if they are standard arrays as I was using.