/// <summary> /// Decomposes the given matrix to translation, scale, /// and rotation and set them to given Transformable node. /// </summary> public static void SetTransform(ITransformable xform, Matrix4F mtrx) { xform.Translation = mtrx.Translation; xform.Scale = mtrx.GetScale(); Vec3F rot = new Vec3F(); mtrx.GetEulerAngles(out rot.X, out rot.Y, out rot.Z); xform.Rotation = rot; xform.UpdateTransform(); }
private void SetTransform(ITransformable xform, Matrix4F mtrx) { xform.Translation = mtrx.Translation; xform.Scale = mtrx.GetScale(); Vec3F rot = new Vec3F(); mtrx.GetEulerAngles(out rot.X, out rot.Y, out rot.Z); xform.Rotation = rot; }
/// <summary> /// Adjusts child transform, making it the concatenation with its parent's transform. /// Is recursive, looking for parents that also implement IRenderableNode.</summary> /// <param name="parent">Parent node</param> /// <param name="child">Child node</param> public static void RemoveChild(ITransformable parent, ITransformable child) { Path <DomNode> path = new Path <DomNode>(parent.Cast <DomNode>().GetPath()); Matrix4F parentMatrix = TransformUtils.CalcPathTransform(path, path.Count - 1); Matrix4F childMatrix = child.Transform; Matrix4F newChildMatrix = Matrix4F.Multiply(childMatrix, parentMatrix); Vec3F newTranslation = child.Translation; parentMatrix.Transform(ref newTranslation); Vec3F newRotation = new Vec3F(); newChildMatrix.GetEulerAngles(out newRotation.X, out newRotation.Y, out newRotation.Z); child.Rotation = newRotation; Vec3F newScale = newChildMatrix.GetScale(); child.Scale = newScale; // We can compose together all of the separate transformations now. Matrix4F newTransform = CalcTransform( newTranslation, newRotation, newScale, child.ScalePivot, child.ScalePivotTranslation, child.RotatePivot, child.RotatePivotTranslation); // However, the composed matrix may not equal newChildMatrix due to rotating // or scaling around a pivot. In the general case, it may be impossible to // decompose newChildMatrix into all of these separate components. For example, // a sheer transformation cannot be reproduced by a single rotation and scale. // But for common cases, only the translation is out-of-sync now, so apply a fix. Vec3F desiredTranslation = newChildMatrix.Translation; Vec3F currentTranslation = newTransform.Translation; Vec3F fixupTranslation = desiredTranslation - currentTranslation; Matrix4F fixupTransform = new Matrix4F(fixupTranslation); newTransform.Mul(newTransform, fixupTransform); // Save the fix and the final transform. child.Translation = newTranslation + fixupTranslation; child.Transform = newTransform; }
public override void OnDragging(ViewControl vc, Point scrPt) { if (m_hitRegion == HitRegion.None || m_activeOp == null || m_activeOp.NodeList.Count == 0) return; Camera cam = vc.Camera; Matrix4F view = cam.ViewMatrix; Matrix4F proj = cam.ProjectionMatrix; Matrix4F axisMtrx = HitMatrix * view; Ray3F hitRay = HitRayV; Ray3F dragRay = vc.GetRay(scrPt, proj); Vec3F xAxis = axisMtrx.XAxis; Vec3F yAxis = axisMtrx.YAxis; Vec3F zAxis = axisMtrx.ZAxis; Vec3F origin = axisMtrx.Translation; Vec3F rotAxis = new Vec3F(); float theta = 0; float snapAngle = ((ISnapSettings)DesignView).SnapAngle; switch (m_hitRegion) { case HitRegion.XAxis: { Plane3F xplane = new Plane3F(xAxis, origin); theta = CalcAngle(origin, xplane, hitRay, dragRay, snapAngle); rotAxis = HitMatrix.XAxis; } break; case HitRegion.YAxis: { Plane3F yplane = new Plane3F(yAxis, origin); theta = CalcAngle(origin, yplane, hitRay, dragRay, snapAngle); rotAxis = HitMatrix.YAxis; } break; case HitRegion.ZAxis: { Plane3F zplane = new Plane3F(zAxis, origin); theta = CalcAngle(origin, zplane, hitRay, dragRay, snapAngle); rotAxis = HitMatrix.ZAxis; } break; case HitRegion.LookAxis: { // for billboard objects the look vector is object's negative position in viewspace. Vec3F lookAxis = Vec3F.Normalize(-origin); Plane3F plane = new Plane3F(lookAxis, origin); theta = CalcAngle(origin, plane, hitRay, dragRay, snapAngle); rotAxis = m_lookAxisHitMtrx.ZAxis; } break; default: throw new ArgumentOutOfRangeException(); } AngleAxisF axf = new AngleAxisF(-theta, rotAxis); Matrix4F deltaMtrx = new Matrix4F(axf); Matrix4F rotMtrx = new Matrix4F(); for (int i = 0; i < m_activeOp.NodeList.Count; i++) { ITransformable node = m_activeOp.NodeList[i]; rotMtrx.Mul(m_rotations[i], deltaMtrx); float ax, ay, az; rotMtrx.GetEulerAngles(out ax, out ay, out az); node.Rotation = new Vec3F(ax, ay, az); } }
public override void OnDragging(ViewControl vc, Point scrPt) { if (m_hitRegion == HitRegion.None || NodeList.Count == 0) return; Camera cam = vc.Camera; Matrix4F view = cam.ViewMatrix; Matrix4F mtrx = cam.ProjectionMatrix; Matrix4F axisMtrx = HitMatrix * view; Ray3F hitRay = HitRayV; Ray3F dragRay = vc.GetRay(scrPt, mtrx); Vec3F xAxis = axisMtrx.XAxis; Vec3F yAxis = axisMtrx.YAxis; Vec3F zAxis = axisMtrx.ZAxis; Vec3F origin = axisMtrx.Translation; Vec3F rotAxis = new Vec3F(); float theta = 0; switch (m_hitRegion) { case HitRegion.XAxis: { Plane3F xplane = new Plane3F(xAxis, origin); theta = CalcAngle(origin, xplane, hitRay, dragRay); rotAxis = HitMatrix.XAxis; } break; case HitRegion.YAxis: { Plane3F yplane = new Plane3F(yAxis, origin); theta = CalcAngle(origin, yplane, hitRay, dragRay); rotAxis = HitMatrix.YAxis; } break; case HitRegion.ZAxis: { Plane3F zplane = new Plane3F(zAxis, origin); theta = CalcAngle(origin, zplane, hitRay, dragRay); rotAxis = HitMatrix.ZAxis; } break; default: throw new ArgumentOutOfRangeException(); } AngleAxisF axf = new AngleAxisF(-theta, rotAxis); Matrix4F deltaMtrx = new Matrix4F(axf); Matrix4F rotMtrx = new Matrix4F(); for (int i = 0; i < NodeList.Count; i++) { ITransformable node = NodeList[i]; rotMtrx.Set(m_rotations[i]); rotMtrx.Mul(rotMtrx, deltaMtrx); float ax, ay, az; rotMtrx.GetEulerAngles(out ax, out ay, out az); node.Rotation = new Vec3F(ax,ay,az); } }
public override void OnDragging(ViewControl vc, Point scrPt) { if (m_hitRegion == HitRegion.None || NodeList.Count == 0) { return; } Camera cam = vc.Camera; Matrix4F view = cam.ViewMatrix; Matrix4F mtrx = cam.ProjectionMatrix; Matrix4F axisMtrx = HitMatrix * view; Ray3F hitRay = HitRayV; Ray3F dragRay = vc.GetRay(scrPt, mtrx); Vec3F xAxis = axisMtrx.XAxis; Vec3F yAxis = axisMtrx.YAxis; Vec3F zAxis = axisMtrx.ZAxis; Vec3F origin = axisMtrx.Translation; Vec3F rotAxis = new Vec3F(); float theta = 0; float snapAngle = ((ISnapSettings)DesignView).SnapAngle; switch (m_hitRegion) { case HitRegion.XAxis: { Plane3F xplane = new Plane3F(xAxis, origin); theta = CalcAngle(origin, xplane, hitRay, dragRay, snapAngle); rotAxis = HitMatrix.XAxis; } break; case HitRegion.YAxis: { Plane3F yplane = new Plane3F(yAxis, origin); theta = CalcAngle(origin, yplane, hitRay, dragRay, snapAngle); rotAxis = HitMatrix.YAxis; } break; case HitRegion.ZAxis: { Plane3F zplane = new Plane3F(zAxis, origin); theta = CalcAngle(origin, zplane, hitRay, dragRay, snapAngle); rotAxis = HitMatrix.ZAxis; } break; default: throw new ArgumentOutOfRangeException(); } AngleAxisF axf = new AngleAxisF(-theta, rotAxis); Matrix4F deltaMtrx = new Matrix4F(axf); Matrix4F rotMtrx = new Matrix4F(); for (int i = 0; i < NodeList.Count; i++) { ITransformable node = NodeList[i]; rotMtrx.Mul(m_rotations[i], deltaMtrx); float ax, ay, az; rotMtrx.GetEulerAngles(out ax, out ay, out az); node.Rotation = new Vec3F(ax, ay, az); } }
/// <summary> /// Adjusts child transform, making it relative to new parent node's transform. /// Is recursive, looking for parents that also implement IRenderableNode.</summary> /// <param name="parent">Parent node</param> /// <param name="child">Child node</param> public static void AddChild(ITransformable parent, ITransformable child) { Path <DomNode> path = new Path <DomNode>(parent.Cast <DomNode>().GetPath()); Matrix4F parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 1); // We want 'child' to appear in the same place in the world after adding to 'parent'. // local-point * original-local-to-world = world-point // new-local-point * new-local-to-parent * parent-to-world = world-point // ==> new-local-to-parent * parent-to-world = original-local-to-world // (multiply both sides by inverse of parent-to-world; call it world-to-parent) // ==> new-local-to-parent = original-local-to-world * world-to-parent Matrix4F worldToParent = new Matrix4F(); worldToParent.Invert(parentToWorld); Matrix4F originalLocalToWorld = child.Transform; Matrix4F newLocalToParent = Matrix4F.Multiply(originalLocalToWorld, worldToParent); // The translation component of newLocalToParent consists of pivot translation // as well as the child.Translation. So, start with the original child.Translation // and transform it into our new space. Vec3F newTranslation = child.Translation; worldToParent.Transform(ref newTranslation); // There's only one way of getting rotation info, so get it straight from matrix. Vec3F newRotation = new Vec3F(); newLocalToParent.GetEulerAngles(out newRotation.X, out newRotation.Y, out newRotation.Z); child.Rotation = newRotation; // Likewise with scale. Vec3F newScale = newLocalToParent.GetScale(); child.Scale = newScale; // We can compose together all of the separate transformations now. Matrix4F newTransform = CalcTransform( newTranslation, newRotation, newScale, child.ScalePivot, child.ScalePivotTranslation, child.RotatePivot, child.RotatePivotTranslation); // However, the composed matrix may not equal newLocalToParent due to rotating // or scaling around a pivot. In the general case, it may be impossible to // decompose newLocalToParent into all of these separate components. For example, // a sheer transformation cannot be reproduced by a single rotation and scale. // But for common cases, only the translation is out-of-sync now, so apply a fix. Vec3F desiredTranslation = newLocalToParent.Translation; Vec3F currentTranslation = newTransform.Translation; Vec3F fixupTranslation = desiredTranslation - currentTranslation; Matrix4F fixupTransform = new Matrix4F(fixupTranslation); newTransform.Mul(newTransform, fixupTransform); // Save the fix and the final transform. Storing the fix in RotatePivotTranslation // is done elsewhere, as well. child.Translation = newTranslation + fixupTranslation; child.Transform = newTransform; }