public void AlignTextureWithFace(Face face) { // Get reference values for the axes var refU = face.Texture.UAxis; var refV = face.Texture.VAxis; // Reference points in the texture plane to use for shifting later on var refX = face.Texture.UAxis * face.Texture.XShift * face.Texture.XScale; var refY = face.Texture.VAxis * face.Texture.YShift * face.Texture.YScale; // Two non-parallel planes intersect at an edge. We want the textures on this face // to line up with the textures on the provided face. To do this, we rotate the texture // normal on the provided face around the intersection edge to get the new texture axes. // Then we rotate the texture reference point around this edge as well to get the new shift values. // The scale values on both faces will always end up being the same value. // Find the intersection edge vector var intersectionEdge = face.Plane.Normal.Cross(Plane.Normal); // Create a plane using the intersection edge as the normal var intersectionPlane = new Plane(intersectionEdge, 0); // If the planes are parallel, the texture doesn't need any rotation - just different shift values. var intersect = Plane.Intersect(face.Plane, Plane, intersectionPlane); if (intersect != null) { var texNormal = face.Texture.GetNormal(); // Since the intersection plane is perpendicular to both face planes, we can find the angle // between the two planes (the original texture plane and the plane of this face) by projecting // the normals of the planes onto the perpendicular plane and taking the cross product. // Project the two normals onto the perpendicular plane var ptNormal = intersectionPlane.Project(texNormal).Normalise(); var ppNormal = intersectionPlane.Project(Plane.Normal).Normalise(); // Get the angle between the projected normals var dot = Math.Round(ptNormal.Dot(ppNormal), 4); var angle = DMath.Acos(dot); // A.B = cos(angle) // Rotate the texture axis by the angle around the intersection edge var transform = new UnitRotate(angle, new Line(Coordinate.Zero, intersectionEdge)); refU = transform.Transform(refU); refV = transform.Transform(refV); // Rotate the texture reference points as well, but around the intersection line, not the origin refX = transform.Transform(refX + intersect) - intersect; refY = transform.Transform(refY + intersect) - intersect; } // Convert the reference points back to get the final values Texture.Rotation = 0; Texture.UAxis = refU; Texture.VAxis = refV; Texture.XShift = refU.Dot(refX) / face.Texture.XScale; Texture.YShift = refV.Dot(refY) / face.Texture.YScale; Texture.XScale = face.Texture.XScale; Texture.YScale = face.Texture.YScale; CalculateTextureCoordinates(true); }
public Tuple <Coordinate, decimal> GetAxisAngle() { var q = W > 1 ? Normalise() : this; var angle = 2 * DMath.Acos(q.W); var denom = DMath.Sqrt(1 - q.W * q.W); var coord = denom <= 0.0001m ? Coordinate.UnitX : q.Vector / denom; return(Tuple.Create(coord, angle)); }
public static Quaternion Slerp(Quaternion start, Quaternion end, decimal blend) { // Clone to avoid modifying the parameters var q1 = start.Clone(); var q2 = end.Clone(); // if either input is zero, return the other. if (q1.Magnitude() == 0) { return(q2.Magnitude() == 0 ? Identity : q2); } if (q2.Magnitude() == 0) { return(q1); } var cosHalfAngle = q1.Dot(q2); if (cosHalfAngle >= 1 || cosHalfAngle <= -1) { return(q1); } if (cosHalfAngle < 0) { q2.Vector = -q2.Vector; q2.Scalar = -q2.Scalar; cosHalfAngle = -cosHalfAngle; } decimal blendA; decimal blendB; if (cosHalfAngle < 0.99m) { // do proper slerp for big angles var halfAngle = DMath.Acos(cosHalfAngle); var sinHalfAngle = DMath.Sin(halfAngle); var oneOverSinHalfAngle = 1 / sinHalfAngle; blendA = DMath.Sin(halfAngle * (1 - blend)) * oneOverSinHalfAngle; blendB = DMath.Sin(halfAngle * blend) * oneOverSinHalfAngle; } else { // do lerp if angle is really small. blendA = 1 - blend; blendB = blend; } var result = new Quaternion(blendA * q1.Vector + blendB * q2.Vector, blendA * q1.W + blendB * q2.W); return(result.Magnitude() > 0 ? result.Normalise() : Identity); }
public override Matrix4?GetTransformationMatrix(Viewport2D viewport, ViewportEvent e, BaseBoxTool.BoxState state, Document doc, IEnumerable <Widget> activeWidgets) { var origin = viewport.ZeroUnusedCoordinate((state.PreTransformBoxStart + state.PreTransformBoxEnd) / 2); var rw = activeWidgets.OfType <RotationWidget>().FirstOrDefault(); if (rw != null) { origin = rw.GetPivotPoint(); } var forigin = viewport.Flatten(origin); var origv = (state.MoveStart - forigin).Normalise(); var newv = (viewport.ScreenToWorld(e.X, viewport.Height - e.Y) - forigin).Normalise(); var angle = DMath.Acos(Math.Max(-1, Math.Min(1, origv.Dot(newv)))); if ((origv.Cross(newv).Z < 0)) { angle = 2 * DMath.PI - angle; } var shf = KeyboardState.Shift; var def = Select.RotationStyle; var snap = (def == RotationStyle.SnapOnShift && shf) || (def == RotationStyle.SnapOffShift && !shf); if (snap) { var deg = angle * (180 / DMath.PI); var rnd = Math.Round(deg / 15) * 15; angle = rnd * (DMath.PI / 180); } Matrix4 rotm; if (viewport.Direction == Viewport2D.ViewDirection.Top) { rotm = Matrix4.CreateRotationZ((float)angle); } else if (viewport.Direction == Viewport2D.ViewDirection.Front) { rotm = Matrix4.CreateRotationX((float)angle); } else { rotm = Matrix4.CreateRotationY((float)-angle); // The Y axis rotation goes in the reverse direction for whatever reason } var mov = Matrix4.CreateTranslation((float)-origin.X, (float)-origin.Y, (float)-origin.Z); var rot = Matrix4.Mult(mov, rotm); return(Matrix4.Mult(rot, Matrix4.Invert(mov))); }
private Matrix4?GetTransformationMatrix(Viewport3D viewport) { if (_mouseMovePoint == null || _mouseDownPoint == null || _pivotPoint == null) { return(null); } var originPoint = viewport.WorldToScreen(_pivotPoint); var origv = (_mouseDownPoint - originPoint).Normalise(); var newv = (_mouseMovePoint - originPoint).Normalise(); var angle = DMath.Acos(Math.Max(-1, Math.Min(1, origv.Dot(newv)))); if ((origv.Cross(newv).Z < 0)) { angle = 2 * DMath.PI - angle; } var shf = KeyboardState.Shift; var def = Select.RotationStyle; var snap = (def == RotationStyle.SnapOnShift && shf) || (def == RotationStyle.SnapOffShift && !shf); if (snap) { var deg = angle * (180 / DMath.PI); var rnd = Math.Round(deg / 15) * 15; angle = rnd * (DMath.PI / 180); } Vector3 axis; var dir = (viewport.Camera.Location - _pivotPoint.ToVector3()).Normalized(); switch (_mouseDown) { case CircleType.Outer: axis = dir; break; case CircleType.X: axis = Vector3.UnitX; break; case CircleType.Y: axis = Vector3.UnitY; break; case CircleType.Z: axis = Vector3.UnitZ; break; default: return(null); } var dirAng = Math.Acos(Vector3.Dot(dir, axis)) * 180 / Math.PI; if (dirAng > 90) { angle = -angle; } var rotm = Matrix4.CreateFromAxisAngle(axis, (float)angle); var mov = Matrix4.CreateTranslation(-_pivotPoint.ToVector3()); var rot = Matrix4.Mult(mov, rotm); return(Matrix4.Mult(rot, Matrix4.Invert(mov))); }