示例#1
0
        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);
        }
示例#2
0
        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));
        }
示例#3
0
        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);
        }
示例#4
0
        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)));
        }
示例#5
0
        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)));
        }