public XbimPackedNormal Transform(XbimQuaternion q)
        {
            XbimVector3D v1 = Normal;
            XbimVector3D v2;

            XbimQuaternion.Transform(ref v1, ref q, out v2);
            return(new XbimPackedNormal(v2));
        }
 public XbimFaceTriangulation Transform(XbimQuaternion q)
 {
     var result = new XbimFaceTriangulation(_indices.Count, _normals.Count);
     foreach (var normal in _normals)
          result.AddNormal(normal.Transform(q));
     foreach (var index in _indices)
         result.AddIndex(index);
     return result;
 }
        public void QuaternionTests()
        {
            var q = new XbimQuaternion();
            Assert.AreEqual(true, q.IsIdentity(), "Uninitialised quaternion should be identity.");

            q = new XbimQuaternion(0.0f, 0.0f, 0.0f, 1.0f);
            Assert.AreEqual(true, q.IsIdentity(), "Should be identity when initialised with floats.");

            var mat = new XbimMatrix3D();
            q = mat.GetRotationQuaternion();
            Assert.AreEqual(true, q.IsIdentity(), "Quaternion from identity matrix shold be identity.");
        }
Beispiel #4
0
        /// <summary>
        /// Decomposes a matrix into a scale, rotation, and translation.
        /// </summary>
        /// <param name="scale">When the method completes, contains the scaling component of the decomposed matrix.</param>
        /// <param name="rotation">When the method completes, contains the rtoation component of the decomposed matrix.</param>
        /// <param name="translation">When the method completes, contains the translation component of the decomposed matrix.</param>
        /// <remarks>
        /// This method is designed to decompose an SRT transformation matrix only.
        /// </remarks>
        public bool Decompose(out XbimVector3D scale, out XbimQuaternion rotation, out XbimVector3D translation)
        {
            //Source: Unknown
            // References: http://www.gamedev.net/community/forums/topic.asp?topic_id=441695
            // via https://code.google.com/p/sharpdx/source/browse/Source/SharpDX/Matrix.cs?r=9f9e209b1be04f06f294bc6d72b06055ad6abdcc

            //Get the translation.
            translation   = new XbimVector3D();
            translation.X = this._offsetX;
            translation.Y = this._offsetY;
            translation.Z = this._offsetZ;

            //Scaling is the length of the rows.
            scale   = new XbimVector3D();
            scale.X = Math.Sqrt((M11 * M11) + (M12 * M12) + (M13 * M13));
            scale.Y = Math.Sqrt((M21 * M21) + (M22 * M22) + (M23 * M23));
            scale.Z = Math.Sqrt((M31 * M31) + (M32 * M32) + (M33 * M33));

            //If any of the scaling factors are zero, than the rotation matrix can not exist.
            //

            double ZeroTolerance = 0.000003;

            if (Math.Abs(scale.X) < ZeroTolerance ||
                Math.Abs(scale.Y) < ZeroTolerance ||
                Math.Abs(scale.Z) < ZeroTolerance)
            {
                rotation = new XbimQuaternion(); // defaults to identity
                return(false);
            }

            //The rotation is the left over matrix after dividing out the scaling.
            XbimMatrix3D rotationmatrix = new XbimMatrix3D();

            rotationmatrix.M11 = M11 / scale.X;
            rotationmatrix.M12 = M12 / scale.X;
            rotationmatrix.M13 = M13 / scale.X;

            rotationmatrix.M21 = M21 / scale.Y;
            rotationmatrix.M22 = M22 / scale.Y;
            rotationmatrix.M23 = M23 / scale.Y;

            rotationmatrix.M31 = M31 / scale.Z;
            rotationmatrix.M32 = M32 / scale.Z;
            rotationmatrix.M33 = M33 / scale.Z;

            rotationmatrix.M44 = 1;

            XbimQuaternion.RotationMatrix(ref rotationmatrix, out rotation);
            return(true);
        }
        public XbimFaceTriangulation Transform(XbimQuaternion q)
        {
            var result = new XbimFaceTriangulation(_indices.Count, _normals.Count);

            foreach (var normal in _normals)
            {
                result.AddNormal(normal.Transform(q));
            }
            foreach (var index in _indices)
            {
                result.AddIndex(index);
            }
            return(result);
        }
        /// <summary>
        /// Creates a quaternion given a rotation matrix.
        /// </summary>
        /// <param name="matrix">The rotation matrix.</param>
        /// <param name="result">When the method completes, contains the newly created quaternion.</param>
        public static void RotationMatrix(ref XbimMatrix3D matrix, out XbimQuaternion result)
        {
            double sqrt;
            double half;
            double scale = matrix.M11 + matrix.M22 + matrix.M33;

            result = new XbimQuaternion();

            if (scale > 0.0f)
            {
                sqrt     = Math.Sqrt(scale + 1.0f);
                result.W = sqrt * 0.5f;
                sqrt     = 0.5f / sqrt;

                result.X = (matrix.M23 - matrix.M32) * sqrt;
                result.Y = (matrix.M31 - matrix.M13) * sqrt;
                result.Z = (matrix.M12 - matrix.M21) * sqrt;
            }
            else if ((matrix.M11 >= matrix.M22) && (matrix.M11 >= matrix.M33))
            {
                sqrt = Math.Sqrt(1.0f + matrix.M11 - matrix.M22 - matrix.M33);
                half = 0.5f / sqrt;

                result.X = 0.5f * sqrt;
                result.Y = (matrix.M12 + matrix.M21) * half;
                result.Z = (matrix.M13 + matrix.M31) * half;
                result.W = (matrix.M23 - matrix.M32) * half;
            }
            else if (matrix.M22 > matrix.M33)
            {
                sqrt = Math.Sqrt(1.0f + matrix.M22 - matrix.M11 - matrix.M33);
                half = 0.5f / sqrt;

                result.X = (matrix.M21 + matrix.M12) * half;
                result.Y = 0.5f * sqrt;
                result.Z = (matrix.M32 + matrix.M23) * half;
                result.W = (matrix.M31 - matrix.M13) * half;
            }
            else
            {
                sqrt = Math.Sqrt(1.0f + matrix.M33 - matrix.M11 - matrix.M22);
                half = 0.5f / sqrt;

                result.X = (matrix.M31 + matrix.M13) * half;
                result.Y = (matrix.M32 + matrix.M23) * half;
                result.Z = 0.5f * sqrt;
                result.W = (matrix.M12 - matrix.M21) * half;
            }
        }
        /// <summary>
        /// Transforms a 3D vector by the given <see cref="SharpDX.Quaternion"/> rotation.
        /// </summary>
        /// <param name="vector">The vector to rotate.</param>
        /// <param name="rotation">The <see cref="SharpDX.Quaternion"/> rotation to apply.</param>
        /// <param name="result">When the method completes, contains the transformed <see cref="SharpDX.Vector4"/>.</param>
        public static void Transform(ref XbimVector3D vector, ref XbimQuaternion rotation, out XbimVector3D result)
        {
            double x  = rotation.X + rotation.X;
            double y  = rotation.Y + rotation.Y;
            double z  = rotation.Z + rotation.Z;
            double wx = rotation.W * x;
            double wy = rotation.W * y;
            double wz = rotation.W * z;
            double xx = rotation.X * x;
            double xy = rotation.X * y;
            double xz = rotation.X * z;
            double yy = rotation.Y * y;
            double yz = rotation.Y * z;
            double zz = rotation.Z * z;

            result = new XbimVector3D(
                ((vector.X * ((1.0f - yy) - zz)) + (vector.Y * (xy - wz))) + (vector.Z * (xz + wy)),
                ((vector.X * (xy + wz)) + (vector.Y * ((1.0f - xx) - zz))) + (vector.Z * (yz - wx)),
                ((vector.X * (xz - wy)) + (vector.Y * (yz + wx))) + (vector.Z * ((1.0f - xx) - yy))
                );
        }
        public static void Read(this XbimMeshGeometry3D m3D, byte[] mesh, XbimMatrix3D? transform = null)
        {
            var indexBase = m3D.Positions.Count;
            var qrd = new XbimQuaternion();

            XbimMatrix3D? matrix3D = null;
            if (transform.HasValue)
            {
                qrd = transform.Value.GetRotationQuaternion();
                matrix3D = transform.Value;
            }
            using (var ms = new MemoryStream(mesh))
            {
                using (var br = new BinaryReader(ms))
                {
                    // ReSharper disable once UnusedVariable
                    var version = br.ReadByte(); //stream format version
                    var numVertices = br.ReadInt32();
                    var numTriangles = br.ReadInt32();

                    var uniqueVertices = new List<XbimPoint3D>(numVertices);
                    var vertices = new List<XbimPoint3D>(numVertices * 4); //approx the size
                    var triangleIndices = new List<int>(numTriangles * 3);
                    var normals = new List<XbimVector3D>(numVertices * 4);
                    for (var i = 0; i < numVertices; i++)
                    {
                        double x = br.ReadSingle();
                        double y = br.ReadSingle();
                        double z = br.ReadSingle();
                        var p = new XbimPoint3D(x, y, z);
                        if (matrix3D.HasValue)
                            p = matrix3D.Value.Transform(p);
                        uniqueVertices.Add(p);
                    }
                    var numFaces = br.ReadInt32();

                    for (var i = 0; i < numFaces; i++)
                    {
                        var numTrianglesInFace = br.ReadInt32();
                        if (numTrianglesInFace == 0) continue;
                        var isPlanar = numTrianglesInFace > 0;
                        numTrianglesInFace = Math.Abs(numTrianglesInFace);
                        if (isPlanar)
                        {
                            var normal = br.ReadPackedNormal().Normal;
                            if (!qrd.IsIdentity())
                            {
                                var baseVal = new XbimVector3D(normal.X, normal.Y, normal.Z);
                                XbimQuaternion.Transform(ref baseVal, ref qrd, out normal);
                            }
                            var uniqueIndices = new Dictionary<int, int>();
                            for (var j = 0; j < numTrianglesInFace; j++)
                            {
                                for (var k = 0; k < 3; k++)
                                {
                                    var idx = ReadIndex(br, numVertices);
                                    int writtenIdx;
                                    if (!uniqueIndices.TryGetValue(idx, out writtenIdx)) //we haven't got it, so add it
                                    {
                                        writtenIdx = vertices.Count;
                                        vertices.Add(uniqueVertices[idx]);
                                        uniqueIndices.Add(idx, writtenIdx);
                                        //add a matching normal
                                        normals.Add(normal);
                                    }
                                    triangleIndices.Add(indexBase + writtenIdx);
                                }
                            }
                        }
                        else
                        {
                            var uniqueIndices = new Dictionary<int, int>();
                            for (var j = 0; j < numTrianglesInFace; j++)
                            {
                                for (var k = 0; k < 3; k++)
                                {
                                    var idx = ReadIndex(br, numVertices);
                                    var normal = br.ReadPackedNormal().Normal;
                                    int writtenIdx;
                                    if (!uniqueIndices.TryGetValue(idx, out writtenIdx)) //we haven't got it, so add it
                                    {
                                        writtenIdx = vertices.Count;
                                        vertices.Add(uniqueVertices[idx]);
                                        uniqueIndices.Add(idx, writtenIdx);

                                        if (!qrd.IsIdentity())
                                        {
                                            var baseVal = new XbimVector3D(normal.X, normal.Y, normal.Z);
                                            XbimQuaternion.Transform(ref baseVal, ref qrd, out normal);
                                        }
                                        normals.Add(normal);
                                    }
                                    triangleIndices.Add(indexBase + writtenIdx);
                                }
                            }
                        }
                    }

                    m3D.Positions = m3D.Positions.Concat(vertices).ToList();
                    m3D.TriangleIndices = m3D.TriangleIndices.Concat(triangleIndices).ToList();
                    m3D.Normals = m3D.Normals.Concat(normals).ToList();
                }
            }
        }
        /// <summary>
        /// Reads an ascii string of Xbim mesh geometry data
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public bool Read(String data, XbimMatrix3D? trans = null)
        {
            var version = 2; //we are at at least verson 2 now
            var q = new XbimQuaternion();
            if (trans.HasValue)
                q = trans.Value.GetRotationQuaternion();
            using (var sr = new StringReader(data))
            {

                var vertexList = new List<XbimPoint3D>(); //holds the actual positions of the vertices in this data set in the mesh
                var normalList = new List<XbimVector3D>(); //holds the actual normals of the vertices in this data set in the mesh
                String line;
                // Read and display lines from the data until the end of
                // the data is reached.

                while ((line = sr.ReadLine()) != null)
                {

                    var tokens = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    if (tokens.Length > 1) //we need a command and some data
                    {
                        var command = tokens[0].Trim().ToUpper();
                        switch (command)
                        {
                            case "P":
                                version = Int32.Parse(tokens[1]);
                                var pointCount = 512;
                                //var faceCount = 128;
                                //var triangleCount = 256;
                                var normalCount = 512;
                                if (tokens.Length > 1) pointCount = Int32.Parse(tokens[2]);
                               // if (tokens.Length > 2) faceCount = Int32.Parse(tokens[3]);
                               // if (tokens.Length > 3) triangleCount = Int32.Parse(tokens[4]);
                                //version 2 of the string format uses packed normals
                                if (version < 2 && tokens.Length > 4) normalCount = Int32.Parse(tokens[5]);
                                vertexList = new List<XbimPoint3D>(pointCount);
                                normalList = new List<XbimVector3D>(normalCount);
                                break;
                            case "V": //process vertices
                                for (var i = 1; i < tokens.Length; i++)
                                {
                                    var xyz = tokens[i].Split(',');
                                    var p = new XbimPoint3D(Convert.ToDouble(xyz[0], CultureInfo.InvariantCulture),
                                                                      Convert.ToDouble(xyz[1], CultureInfo.InvariantCulture),
                                                                      Convert.ToDouble(xyz[2], CultureInfo.InvariantCulture));
                                    if (trans.HasValue)
                                        p = trans.Value.Transform(p);
                                    vertexList.Add(p);
                                }
                                break;
                            case "N": //processes normals
                                for (var i = 1; i < tokens.Length; i++)
                                {
                                    var xyz = tokens[i].Split(',');
                                    var v = new XbimVector3D(Convert.ToDouble(xyz[0], CultureInfo.InvariantCulture),
                                                                       Convert.ToDouble(xyz[1], CultureInfo.InvariantCulture),
                                                                       Convert.ToDouble(xyz[2], CultureInfo.InvariantCulture));
                                    normalList.Add(v);
                                }
                                break;
                            case "T": //process triangulated meshes
                                var currentNormal = XbimVector3D.Zero;
                                //each time we start a new mesh face we have to duplicate the vertices to ensure that we get correct shading of planar and non planar faces
                                var writtenVertices = new Dictionary<int, int>();

                                for (var i = 1; i < tokens.Length; i++)
                                {
                                    var triangleIndices = tokens[i].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                                    if (triangleIndices.Length != 3) throw new Exception("Invalid triangle definition");
                                    for (var t = 0; t < 3; t++)
                                    {
                                        var indexNormalPair = triangleIndices[t].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

                                        if (indexNormalPair.Length > 1) //we have a normal defined
                                        {
                                            var normalStr = indexNormalPair[1].Trim();
                                            if (version < 2)
                                            {
                                                switch (normalStr)
                                                {
                                                    case "F": //Front
                                                        currentNormal = new XbimVector3D(0, -1, 0);
                                                        break;
                                                    case "B": //Back
                                                        currentNormal = new XbimVector3D(0, 1, 0);
                                                        break;
                                                    case "L": //Left
                                                        currentNormal = new XbimVector3D(-1, 0, 0);
                                                        break;
                                                    case "R": //Right
                                                        currentNormal = new XbimVector3D(1, 0, 0);
                                                        break;
                                                    case "U": //Up
                                                        currentNormal = new XbimVector3D(0, 0, 1);
                                                        break;
                                                    case "D": //Down
                                                        currentNormal = new XbimVector3D(0, 0, -1);
                                                        break;
                                                    default: //it is an index number
                                                        var normalIndex = int.Parse(indexNormalPair[1]);
                                                        currentNormal = normalList[normalIndex];
                                                        break;
                                                }
                                            }
                                            else
                                            {
                                                var normalIndex = ushort.Parse(indexNormalPair[1]);
                                                var packedNormal = new XbimPackedNormal(normalIndex);
                                                currentNormal = packedNormal.Normal;
                                            }
                                            if (trans.HasValue)
                                            {
                                                XbimVector3D v;
                                                XbimQuaternion.Transform(ref currentNormal, ref q, out v);
                                                currentNormal = v;

                                            }
                                        }

                                        //now add the index
                                        var index = int.Parse(indexNormalPair[0]);

                                        int alreadyWrittenAt;
                                        if (!writtenVertices.TryGetValue(index, out alreadyWrittenAt)) //if we haven't  written it in this mesh pass, add it again unless it is the first one which we know has been written
                                        {
                                            //all vertices will be unique and have only one normal
                                            writtenVertices.Add(index, PositionCount);
                                            TriangleIndices.Add(PositionCount);
                                            Positions.Add(vertexList[index]);
                                            Normals.Add(currentNormal);
                                        }
                                        else //just add the index reference
                                        {
                                            TriangleIndices.Add(alreadyWrittenAt);
                                        }
                                    }
                                }

                                break;
                            case "F":
                                break;
                            default:
                                throw new Exception("Invalid Geometry Command");

                        }
                    }
                }
            }
            return true;
        }
Beispiel #10
0
        /// <summary>
        /// Decomposes a matrix into a scale, rotation, and translation.
        /// </summary>
        /// <param name="scale">When the method completes, contains the scaling component of the decomposed matrix.</param>
        /// <param name="rotation">When the method completes, contains the rtoation component of the decomposed matrix.</param>
        /// <param name="translation">When the method completes, contains the translation component of the decomposed matrix.</param>
        /// <remarks>
        /// This method is designed to decompose an SRT transformation matrix only.
        /// </remarks>
        public bool Decompose(out XbimVector3D scale, out XbimQuaternion rotation, out XbimVector3D translation)
        {
            //Source: Unknown
            // References: http://www.gamedev.net/community/forums/topic.asp?topic_id=441695
            // via https://code.google.com/p/sharpdx/source/browse/Source/SharpDX/Matrix.cs?r=9f9e209b1be04f06f294bc6d72b06055ad6abdcc

            //Get the translation.
            translation = new XbimVector3D();
            translation.X = this._offsetX;
            translation.Y = this._offsetY;
            translation.Z = this._offsetZ;

            //Scaling is the length of the rows.
            scale = new XbimVector3D();
            scale.X = Math.Sqrt((M11 * M11) + (M12 * M12) + (M13 * M13));
            scale.Y = Math.Sqrt((M21 * M21) + (M22 * M22) + (M23 * M23));
            scale.Z = Math.Sqrt((M31 * M31) + (M32 * M32) + (M33 * M33));

            //If any of the scaling factors are zero, than the rotation matrix can not exist.
            // 

            double ZeroTolerance = 0.000003;
            if (Math.Abs(scale.X) < ZeroTolerance ||
                Math.Abs(scale.Y) < ZeroTolerance ||
                Math.Abs(scale.Z) < ZeroTolerance)
            {
                rotation = new XbimQuaternion(); // defaults to identity
                return false;
            }

            //The rotation is the left over matrix after dividing out the scaling.
            XbimMatrix3D rotationmatrix = new XbimMatrix3D();
            rotationmatrix.M11 = M11 / scale.X;
            rotationmatrix.M12 = M12 / scale.X;
            rotationmatrix.M13 = M13 / scale.X;

            rotationmatrix.M21 = M21 / scale.Y;
            rotationmatrix.M22 = M22 / scale.Y;
            rotationmatrix.M23 = M23 / scale.Y;

            rotationmatrix.M31 = M31 / scale.Z;
            rotationmatrix.M32 = M32 / scale.Z;
            rotationmatrix.M33 = M33 / scale.Z;

            rotationmatrix.M44 = 1;

            XbimQuaternion.RotationMatrix(ref rotationmatrix, out rotation);
            return true;
        }
 static XbimQuaternion()
 {
     _identity = new XbimQuaternion(0.0, 0.0, 0.0, 1.0);
     _identity._isNotDefaultInitialised = true;
 }
        /// <summary>
        /// Creates a quaternion given a rotation matrix.
        /// </summary>
        /// <param name="matrix">The rotation matrix.</param>
        /// <param name="result">When the method completes, contains the newly created quaternion.</param>
        public static void RotationMatrix(ref XbimMatrix3D matrix, out XbimQuaternion result)
        {
            double sqrt;
            double half;
            double scale = matrix.M11 + matrix.M22 + matrix.M33;
            result = new XbimQuaternion();

            if (scale > 0.0f)
            {
                sqrt = Math.Sqrt(scale + 1.0f);
                result.W = sqrt * 0.5f;
                sqrt = 0.5f / sqrt;

                result.X = (matrix.M23 - matrix.M32) * sqrt;
                result.Y = (matrix.M31 - matrix.M13) * sqrt;
                result.Z = (matrix.M12 - matrix.M21) * sqrt;
            }
            else if ((matrix.M11 >= matrix.M22) && (matrix.M11 >= matrix.M33))
            {
                sqrt = Math.Sqrt(1.0f + matrix.M11 - matrix.M22 - matrix.M33);
                half = 0.5f / sqrt;

                result.X = 0.5f * sqrt;
                result.Y = (matrix.M12 + matrix.M21) * half;
                result.Z = (matrix.M13 + matrix.M31) * half;
                result.W = (matrix.M23 - matrix.M32) * half;
            }
            else if (matrix.M22 > matrix.M33)
            {
                sqrt = Math.Sqrt(1.0f + matrix.M22 - matrix.M11 - matrix.M33);
                half = 0.5f / sqrt;

                result.X = (matrix.M21 + matrix.M12) * half;
                result.Y = 0.5f * sqrt;
                result.Z = (matrix.M32 + matrix.M23) * half;
                result.W = (matrix.M31 - matrix.M13) * half;
            }
            else
            {
                sqrt = Math.Sqrt(1.0f + matrix.M33 - matrix.M11 - matrix.M22);
                half = 0.5f / sqrt;

                result.X = (matrix.M31 + matrix.M13) * half;
                result.Y = (matrix.M32 + matrix.M23) * half;
                result.Z = 0.5f * sqrt;
                result.W = (matrix.M12 - matrix.M21) * half;
            }
        }
 static XbimQuaternion()
 {
     _identity = new XbimQuaternion(0.0, 0.0, 0.0, 1.0);
     _identity._isNotDefaultInitialised = true;
 }
        /// <summary>
        /// Transforms a 3D vector by the given <see cref="SharpDX.Quaternion"/> rotation.
        /// </summary>
        /// <param name="vector">The vector to rotate.</param>
        /// <param name="rotation">The <see cref="SharpDX.Quaternion"/> rotation to apply.</param>
        /// <param name="result">When the method completes, contains the transformed <see cref="SharpDX.Vector4"/>.</param>
        public static void Transform(ref XbimVector3D vector, ref XbimQuaternion rotation, out XbimVector3D result)
        {
            double x = rotation.X + rotation.X;
            double y = rotation.Y + rotation.Y;
            double z = rotation.Z + rotation.Z;
            double wx = rotation.W * x;
            double wy = rotation.W * y;
            double wz = rotation.W * z;
            double xx = rotation.X * x;
            double xy = rotation.X * y;
            double xz = rotation.X * z;
            double yy = rotation.Y * y;
            double yz = rotation.Y * z;
            double zz = rotation.Z * z;

            result = new XbimVector3D(
                ((vector.X * ((1.0f - yy) - zz)) + (vector.Y * (xy - wz))) + (vector.Z * (xz + wy)),
                ((vector.X * (xy + wz)) + (vector.Y * ((1.0f - xx) - zz))) + (vector.Z * (yz - wx)),
                ((vector.X * (xz - wy)) + (vector.Y * (yz + wx))) + (vector.Z * ((1.0f - xx) - yy))
                );
        }
 public XbimPackedNormal Transform(XbimQuaternion q)
 {
     XbimVector3D v1 = Normal;
     XbimVector3D v2;
     XbimQuaternion.Transform(ref v1, ref q, out v2);
     return new XbimPackedNormal(v2);
 }