Exemple #1
0
//Static methods
    //L2   L3   L4  L5  L6  L7  L8  Ldash D   Mdash F   xsin      xsint xcos    xcost ysin   ysint ycos     ycost zsin   zsint zcos    zcost


    //////////////////////////////// Implementation ///////////////////////////////

    public static C3D EarthVelocity(double JD)
    {
        double T     = (JD - 2451545) / 36525;
        double L2    = 3.1761467 + 1021.3285546 * T;
        double L3    = 1.7534703 + 628.3075849 * T;
        double L4    = 6.2034809 + 334.0612431 * T;
        double L5    = 0.5995465 + 52.9690965 * T;
        double L6    = 0.8740168 + 21.3299095 * T;
        double L7    = 5.4812939 + 7.4781599 * T;
        double L8    = 5.3118863 + 3.8133036 * T;
        double Ldash = 3.8103444 + 8399.6847337 * T;
        double D     = 5.1984667 + 7771.3771486 * T;
        double Mdash = 2.3555559 + 8328.6914289 * T;
        double F     = 1.6279052 + 8433.4661601 * T;

        C3D velocity = new C3D();

        int nAberrationCoefficients = GFX.g_ACft.Length;

        for (int i = 0; i < nAberrationCoefficients; i++)
        {
            double Argument = GFX.g_ACft[i].L2 * L2 + GFX.g_ACft[i].L3 * L3 + GFX.g_ACft[i].L4 * L4 + GFX.g_ACft[i].L5 * L5 + GFX.g_ACft[i].L6 * L6 + GFX.g_ACft[i].L7 * L7 + GFX.g_ACft[i].L8 * L8 + GFX.g_ACft[i].Ldash * Ldash + GFX.g_ACft[i].D * D + GFX.g_ACft[i].Mdash * Mdash + GFX.g_ACft[i].F * F;
            velocity.X += (GFX.g_ACft[i].xsin + GFX.g_ACft[i].xsint * T) * Math.Sin(Argument);
            velocity.X += (GFX.g_ACft[i].xcos + GFX.g_ACft[i].xcost * T) * Math.Cos(Argument);

            velocity.Y += (GFX.g_ACft[i].ysin + GFX.g_ACft[i].ysint * T) * Math.Sin(Argument);
            velocity.Y += (GFX.g_ACft[i].ycos + GFX.g_ACft[i].ycost * T) * Math.Cos(Argument);

            velocity.Z += (GFX.g_ACft[i].zsin + GFX.g_ACft[i].zsint * T) * Math.Sin(Argument);
            velocity.Z += (GFX.g_ACft[i].zcos + GFX.g_ACft[i].zcost * T) * Math.Cos(Argument);
        }

        return(velocity);
    }
    //Static methods
    //L2   L3   L4  L5  L6  L7  L8  Ldash D   Mdash F   xsin      xsint xcos    xcost ysin   ysint ycos     ycost zsin   zsint zcos    zcost
    //////////////////////////////// Implementation ///////////////////////////////
    public static C3D EarthVelocity(double JD)
    {
        double T = (JD - 2451545) / 36525;
        double L2 = 3.1761467 + 1021.3285546 * T;
        double L3 = 1.7534703 + 628.3075849 * T;
        double L4 = 6.2034809 + 334.0612431 * T;
        double L5 = 0.5995465 + 52.9690965 * T;
        double L6 = 0.8740168 + 21.3299095 * T;
        double L7 = 5.4812939 + 7.4781599 * T;
        double L8 = 5.3118863 + 3.8133036 * T;
        double Ldash = 3.8103444 + 8399.6847337 * T;
        double D = 5.1984667 + 7771.3771486 * T;
        double Mdash = 2.3555559 + 8328.6914289 * T;
        double F = 1.6279052 + 8433.4661601 * T;

        C3D velocity = new C3D();

        int nAberrationCoefficients = GFX.g_ACft.Length;
        for (int i =0; i<nAberrationCoefficients; i++)
        {
          double Argument = GFX.g_ACft[i].L2 *L2 + GFX.g_ACft[i].L3 *L3 + GFX.g_ACft[i].L4 *L4 + GFX.g_ACft[i].L5 *L5 + GFX.g_ACft[i].L6 *L6 + GFX.g_ACft[i].L7 *L7 + GFX.g_ACft[i].L8 *L8 + GFX.g_ACft[i].Ldash *Ldash + GFX.g_ACft[i].D *D + GFX.g_ACft[i].Mdash *Mdash + GFX.g_ACft[i].F *F;
          velocity.X += (GFX.g_ACft[i].xsin + GFX.g_ACft[i].xsint * T) * Math.Sin(Argument);
          velocity.X += (GFX.g_ACft[i].xcos + GFX.g_ACft[i].xcost * T) * Math.Cos(Argument);

          velocity.Y += (GFX.g_ACft[i].ysin + GFX.g_ACft[i].ysint * T) * Math.Sin(Argument);
          velocity.Y += (GFX.g_ACft[i].ycos + GFX.g_ACft[i].ycost * T) * Math.Cos(Argument);

          velocity.Z += (GFX.g_ACft[i].zsin + GFX.g_ACft[i].zsint * T) * Math.Sin(Argument);
          velocity.Z += (GFX.g_ACft[i].zcos + GFX.g_ACft[i].zcost * T) * Math.Cos(Argument);
        }

        return velocity;
    }
    public static C3D EquatorialRectangularCoordinatesAnyEquinox(double JD, double JDEquinox)
    {
        C3D @value = EquatorialRectangularCoordinatesJ2000(JD);

        @value = CAAFK5.ConvertVSOPToFK5AnyEquinox(@value, JDEquinox);

        return(@value);
    }
    public static C3D EquatorialRectangularCoordinatesB1950(double JD)
    {
        C3D @value = EclipticRectangularCoordinatesJ2000(JD);

        @value = CAAFK5.ConvertVSOPToFK5B1950(@value);

        return(@value);
    }
Exemple #5
0
    public static C3D ConvertVSOPToFK5J2000(C3D @value)
    {
        C3D result = new C3D();
        result.X = @value.X + 0.000000440360 * @value.Y - 0.000000190919 * @value.Z;
        result.Y = -0.000000479966 * @value.X + 0.917482137087 * @value.Y - 0.397776982902 * @value.Z;
        result.Z = 0.397776982902 * @value.Y + 0.917482137087 * @value.Z;

        return result;
    }
    public static C3D Create(double x, double y, double z)
    {
        C3D item = new C3D();

        item.X = x;
        item.Y = y;
        item.Z = z;
        return(item);
    }
    public static C3D Create(double x, double y, double z)
    {
        C3D item = new C3D();

        item.X = x;
        item.Y = y;
        item.Z = z;
        return item;
    }
Exemple #8
0
    public static C3D ConvertVSOPToFK5B1950(C3D @value)
    {
        C3D result = new C3D();
        result.X = 0.999925702634 * @value.X + 0.012189716217 * @value.Y + 0.000011134016 * @value.Z;
        result.Y = -0.011179418036 * @value.X + 0.917413998946 * @value.Y - 0.397777041885 * @value.Z;
        result.Z = -0.004859003787 * @value.X + 0.397747363646 * @value.Y + 0.917482111428 * @value.Z;

        return result;
    }
Exemple #9
0
    public static C3D ConvertVSOPToFK5B1950(C3D @value)
    {
        C3D result = new C3D();

        result.X = 0.999925702634 * @value.X + 0.012189716217 * @value.Y + 0.000011134016 * @value.Z;
        result.Y = -0.011179418036 * @value.X + 0.917413998946 * @value.Y - 0.397777041885 * @value.Z;
        result.Z = -0.004859003787 * @value.X + 0.397747363646 * @value.Y + 0.917482111428 * @value.Z;

        return(result);
    }
Exemple #10
0
    public static C3D ConvertVSOPToFK5J2000(C3D @value)
    {
        C3D result = new C3D();

        result.X = @value.X + 0.000000440360 * @value.Y - 0.000000190919 * @value.Z;
        result.Y = -0.000000479966 * @value.X + 0.917482137087 * @value.Y - 0.397776982902 * @value.Z;
        result.Z = 0.397776982902 * @value.Y + 0.917482137087 * @value.Z;

        return(result);
    }
Exemple #11
0
    public static C3D EclipticRectangularCoordinatesMeanEquinox(double JD)
    {
        double Longitude = CT.D2R(GeometricFK5EclipticLongitude(JD));
        double Latitude = CT.D2R(GeometricFK5EclipticLatitude(JD));
        double R = CAAEarth.RadiusVector(JD);
        double epsilon = CT.D2R(CAANutation.MeanObliquityOfEcliptic(JD));

        C3D @value = new C3D();
        @value.X = R * Math.Cos(Latitude) * Math.Cos(Longitude);
        @value.Y = R * (Math.Cos(Latitude) * Math.Sin(Longitude) * Math.Cos(epsilon) - Math.Sin(Latitude) * Math.Sin(epsilon));
        @value.Z = R * (Math.Cos(Latitude) * Math.Sin(Longitude) * Math.Sin(epsilon) + Math.Sin(Latitude) * Math.Cos(epsilon));

        return @value;
    }
    public static C3D EclipticRectangularCoordinatesMeanEquinox(double JD)
    {
        double Longitude = CT.D2R(GeometricFK5EclipticLongitude(JD));
        double Latitude  = CT.D2R(GeometricFK5EclipticLatitude(JD));
        double R         = CAAEarth.RadiusVector(JD);
        double epsilon   = CT.D2R(CAANutation.MeanObliquityOfEcliptic(JD));

        C3D @value = new C3D();

        @value.X = R * Math.Cos(Latitude) * Math.Cos(Longitude);
        @value.Y = R * (Math.Cos(Latitude) * Math.Sin(Longitude) * Math.Cos(epsilon) - Math.Sin(Latitude) * Math.Sin(epsilon));
        @value.Z = R * (Math.Cos(Latitude) * Math.Sin(Longitude) * Math.Sin(epsilon) + Math.Sin(Latitude) * Math.Cos(epsilon));

        return(@value);
    }
Exemple #13
0
    public static C3D EclipticRectangularCoordinatesJ2000(double JD)
    {
        double Longitude = GeometricEclipticLongitudeJ2000(JD);
        Longitude = CT.D2R(Longitude);
        double Latitude = GeometricEclipticLatitudeJ2000(JD);
        Latitude = CT.D2R(Latitude);
        double R = CAAEarth.RadiusVector(JD);

        C3D @value = new C3D();
        double coslatitude = Math.Cos(Latitude);
        @value.X = R * coslatitude * Math.Cos(Longitude);
        @value.Y = R * coslatitude * Math.Sin(Longitude);
        @value.Z = R * Math.Sin(Latitude);

        return @value;
    }
Exemple #14
0
    public static C3D ConvertVSOPToFK5AnyEquinox(C3D @value, double JDEquinox)
    {
        double t        = (JDEquinox - 2451545.0) / 36525;
        double tsquared = t * t;
        double tcubed   = tsquared * t;

        double sigma = 2306.2181 * t + 0.30188 * tsquared + 0.017988 * tcubed;

        sigma = CT.D2R(CT.DMS2D(0, 0, sigma));

        double zeta = 2306.2181 * t + 1.09468 * tsquared + 0.018203 * tcubed;

        zeta = CT.D2R(CT.DMS2D(0, 0, zeta));

        double phi = 2004.3109 * t - 0.42665 * tsquared - 0.041833 * tcubed;

        phi = CT.D2R(CT.DMS2D(0, 0, phi));

        double cossigma = Math.Cos(sigma);
        double coszeta  = Math.Cos(zeta);
        double cosphi   = Math.Cos(phi);
        double sinsigma = Math.Sin(sigma);
        double sinzeta  = Math.Sin(zeta);
        double sinphi   = Math.Sin(phi);

        double xx = cossigma * coszeta * cosphi - sinsigma * sinzeta;
        double xy = sinsigma * coszeta + cossigma * sinzeta * cosphi;
        double xz = cossigma * sinphi;
        double yx = -cossigma * sinzeta - sinsigma * coszeta * cosphi;
        double yy = cossigma * coszeta - sinsigma * sinzeta * cosphi;
        double yz = -sinsigma * sinphi;
        double zx = -coszeta * sinphi;
        double zy = -sinzeta * sinphi;
        double zz = cosphi;

        C3D result = new C3D();

        result.X = xx * @value.X + yx * @value.Y + zx * @value.Z;
        result.Y = xy * @value.X + yy * @value.Y + zy * @value.Z;
        result.Z = xz * @value.X + yz * @value.Y + zz * @value.Z;

        return(result);
    }
    public static C3D EclipticRectangularCoordinatesJ2000(double JD)
    {
        double Longitude = GeometricEclipticLongitudeJ2000(JD);

        Longitude = CT.D2R(Longitude);
        double Latitude = GeometricEclipticLatitudeJ2000(JD);

        Latitude = CT.D2R(Latitude);
        double R = CAAEarth.RadiusVector(JD);

        C3D    @value      = new C3D();
        double coslatitude = Math.Cos(Latitude);

        @value.X = R * coslatitude * Math.Cos(Longitude);
        @value.Y = R * coslatitude * Math.Sin(Longitude);
        @value.Z = R * Math.Sin(Latitude);

        return(@value);
    }
Exemple #16
0
    public static COR EquatorialAberration(double Alpha, double Delta, double JD)
    {
        //Convert to radians
        Alpha = CT.D2R(Alpha * 15);
        Delta = CT.D2R(Delta);

        double cosAlpha = Math.Cos(Alpha);
        double sinAlpha = Math.Sin(Alpha);
        double cosDelta = Math.Cos(Delta);
        double sinDelta = Math.Sin(Delta);

        C3D velocity = EarthVelocity(JD);

        //What is the return value
        COR aberration = new COR();

        aberration.X = CT.R2H((velocity.Y * cosAlpha - velocity.X * sinAlpha) / (17314463350.0 * cosDelta));
        aberration.Y = CT.R2D(-(((velocity.X * cosAlpha + velocity.Y * sinAlpha) * sinDelta - velocity.Z * cosDelta) / 17314463350.0));

        return(aberration);
    }
Exemple #17
0
    public static C3D ConvertVSOPToFK5AnyEquinox(C3D @value, double JDEquinox)
    {
        double t = (JDEquinox - 2451545.0) / 36525;
        double tsquared = t *t;
        double tcubed = tsquared * t;

        double sigma = 2306.2181 *t + 0.30188 *tsquared + 0.017988 *tcubed;
        sigma = CT.D2R(CT.DMS2D(0, 0, sigma));

        double zeta = 2306.2181 *t + 1.09468 *tsquared + 0.018203 *tcubed;
        zeta = CT.D2R(CT.DMS2D(0, 0, zeta));

        double phi = 2004.3109 *t - 0.42665 *tsquared - 0.041833 *tcubed;
        phi = CT.D2R(CT.DMS2D(0, 0, phi));

        double cossigma = Math.Cos(sigma);
        double coszeta = Math.Cos(zeta);
        double cosphi = Math.Cos(phi);
        double sinsigma = Math.Sin(sigma);
        double sinzeta = Math.Sin(zeta);
        double sinphi = Math.Sin(phi);

        double xx = cossigma * coszeta * cosphi -sinsigma *sinzeta;
        double xy = sinsigma * coszeta + cossigma * sinzeta * cosphi;
        double xz = cossigma * sinphi;
        double yx = -cossigma * sinzeta - sinsigma * coszeta * cosphi;
        double yy = cossigma * coszeta - sinsigma * sinzeta * cosphi;
        double yz = -sinsigma * sinphi;
        double zx = -coszeta * sinphi;
        double zy = -sinzeta * sinphi;
        double zz = cosphi;

        C3D result = new C3D();
        result.X = xx * @value.X + yx * @value.Y + zx * @value.Z;
        result.Y = xy * @value.X + yy * @value.Y + zy * @value.Z;
        result.Z = xz * @value.X + yz * @value.Y + zz * @value.Z;

        return result;
    }
Exemple #18
0
            // ReSharper disable once InconsistentNaming
            // data is object[] { bool exportAttachments, string materialReference, string modelName, bool onlyOneLOD, bool skipCollision }
            public void Write(ICLIFlags flags, Chunked chunked, Stream output, List <byte> LODs, object[] data, FindLogic.Combo.ModelInfoNew modelInfo)
            {
                byte?flagLOD = null;

                if (flags is ExtractFlags extractFlags)
                {
                    flagLOD = extractFlags.LOD;
                }

                IChunk chunk = chunked.FindNextChunk("MNRM").Value;

                if (chunk == null)
                {
                    return;
                }
                MNRM model = (MNRM)chunk;

                chunk = chunked.FindNextChunk("CLDM").Value;
                CLDM materials = null;

                if (chunk != null)
                {
                    materials = (CLDM)chunk;
                }
                chunk = chunked.FindNextChunk("lksm").Value;
                lksm skeleton = null;

                if (chunk != null)
                {
                    skeleton = (lksm)chunk;
                }
                chunk = chunked.FindNextChunk("PRHM").Value;
                PRHM hardpoints = null;

                if (chunk != null)
                {
                    hardpoints = (PRHM)chunk;
                }
                HTLC cloth = chunked.FindNextChunk("HTLC").Value as HTLC;

                short[] hierarchy = (short[])skeleton?.Hierarchy.Clone();
                Dictionary <int, HTLC.ClothNode> nodeMap = new Dictionary <int, HTLC.ClothNode>();

                if (cloth != null)
                {
                    uint clothIndex = 0;
                    foreach (HTLC.ClothNode[] nodeCollection in cloth.Nodes)
                    {
                        if (nodeCollection == null)
                        {
                            continue;
                        }
                        int nodeIndex = 0;
                        foreach (HTLC.ClothNode node in nodeCollection)
                        {
                            int parentRaw = node.VerticalParent;
                            if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex) &&
                                cloth.NodeBones[clothIndex].ContainsKey(parentRaw))
                            {
                                if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                                {
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] =
                                        cloth.NodeBones[clothIndex][parentRaw];
                                    if (cloth.NodeBones[clothIndex][parentRaw] == -1)
                                    {
                                        HTLC.ClothNodeWeight weightedBone =
                                            node.Bones.Aggregate((i1, i2) => i1.Weight > i2.Weight ? i1 : i2);
                                        hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = weightedBone.Bone;
                                    }
                                }
                            }
                            else
                            {
                                if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex))
                                {
                                    if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                                    {
                                        hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = -1;
                                        HTLC.ClothNodeWeight weightedBone =
                                            node.Bones.Aggregate((i1, i2) => i1.Weight > i2.Weight ? i1 : i2);
                                        hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = weightedBone.Bone;
                                    }
                                }
                            }
                            if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex))
                            {
                                if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                                {
                                    nodeMap[cloth.NodeBones[clothIndex][nodeIndex]] = node;
                                }
                            }

                            nodeIndex++;
                        }
                        clothIndex++;
                    }
                }

                using (BinaryWriter writer = new BinaryWriter(output)) {
                    writer.Write((ushort)1);  // version major
                    writer.Write((ushort)5);  // version minor

                    if (data.Length > 1 && data[1] is string && ((string)data[1]).Length > 0)
                    {
                        writer.Write((string)data[1]);
                    }
                    else
                    {
                        writer.Write((byte)0);
                    }

                    if (data.Length > 2 && data[2] is string && ((string)data[2]).Length > 0)
                    {
                        writer.Write((string)data[2]);
                    }
                    else
                    {
                        writer.Write((byte)0);
                    }

                    if (skeleton == null)
                    {
                        writer.Write((ushort)0);  // number of bones
                    }
                    else
                    {
                        writer.Write(skeleton.Data.bonesAbs);
                    }

                    // ReSharper disable once InconsistentNaming
                    Dictionary <byte, List <int> > LODMap = new Dictionary <byte, List <int> >();
                    uint sz         = 0;
                    uint lookForLod = 0;

                    if (model.Submeshes.Any(x => x.lod == flagLOD))
                    {
                        lookForLod = (byte)flagLOD;
                    }
                    else if (flagLOD != null)
                    {
                        SubmeshDescriptor nextLowest = model.Submeshes.Where(p => p.lod < flagLOD).OrderBy(x => x.lod).LastOrDefault();
                        if (nextLowest.verticesToDraw == 0 && nextLowest.indexCount == 0)   // not real mesh
                        {
                            SubmeshDescriptor nextHighest = model.Submeshes.Where(p => p.lod > flagLOD).OrderBy(x => x.lod).FirstOrDefault();
                            lookForLod = nextHighest.lod;
                        }
                        else
                        {
                            lookForLod = nextLowest.lod;
                        }
                    }

                    for (int i = 0; i < model.Submeshes.Length; ++i)
                    {
                        SubmeshDescriptor submesh = model.Submeshes[i];
                        if (data.Length > 4 && data[4] is bool && (bool)data[4])
                        {
                            if (submesh.flags == SubmeshFlags.COLLISION_MESH)
                            {
                                continue;
                            }
                        }
                        if (lookForLod > 0 && submesh.lod != lookForLod && submesh.lod != 255)
                        {
                            continue;
                        }

                        if (!LODMap.ContainsKey(submesh.lod))
                        {
                            LODMap.Add(submesh.lod, new List <int>());
                        }
                        sz++;
                        LODMap[submesh.lod].Add(i);
                    }

                    writer.Write(sz);
                    writer.Write(hardpoints?.HardPoints.Length ?? 0);

                    if (skeleton != null)
                    {
                        for (int i = 0; i < skeleton.Data.bonesAbs; ++i)
                        {
                            writer.Write(IdToString("bone", skeleton.IDs[i]));
                            short parent = hierarchy[i];
                            if (parent == -1)
                            {
                                parent = (short)i;
                            }
                            writer.Write(parent);

                            Matrix3x4  bone = skeleton.Matrices34[i];
                            Quaternion rot  = new Quaternion(bone[0, 0], bone[0, 1], bone[0, 2], bone[0, 3]);
                            Vector3    scl  = new Vector3(bone[1, 0], bone[1, 1], bone[1, 2]);
                            Vector3    pos  = new Vector3(bone[2, 0], bone[2, 1], bone[2, 2]);
                            if (nodeMap.ContainsKey(i))
                            {
                                HTLC.ClothNode thisNode = nodeMap[i];
                                pos.X = thisNode.X;
                                pos.Y = thisNode.Y;
                                pos.Z = thisNode.Z;
                            }
                            writer.Write(pos.X);
                            writer.Write(pos.Y);
                            writer.Write(pos.Z);
                            writer.Write(scl.X);
                            writer.Write(scl.Y);
                            writer.Write(scl.Z);
                            writer.Write(rot.X);
                            writer.Write(rot.Y);
                            writer.Write(rot.Z);
                            writer.Write(rot.W);
                        }
                    }

                    foreach (KeyValuePair <byte, List <int> > kv in LODMap)
                    {
                        foreach (int i in kv.Value)
                        {
                            SubmeshDescriptor submesh = model.Submeshes[i];
                            ModelVertex[]     vertex  = model.Vertices[i];
                            ModelVertex[]     normal  = model.Normals[i];
                            ModelUV[][]       uv      = model.TextureCoordinates[i];
                            ModelIndice[]     index   = model.Indices[i];

                            ModelBoneData[] bones = model.Bones[i];
                            writer.Write($"Submesh_{i}.{kv.Key}.{materials.Materials[submesh.material]:X16}");
                            writer.Write(materials.Materials[submesh.material]);
                            writer.Write((byte)uv.Length);

                            writer.Write(vertex.Length);
                            writer.Write(index.Length);
                            for (int j = 0; j < vertex.Length; ++j)
                            {
                                writer.Write(vertex[j].x);
                                writer.Write(vertex[j].y);
                                writer.Write(vertex[j].z);
                                writer.Write(-normal[j].x);
                                writer.Write(-normal[j].y);
                                writer.Write(-normal[j].z);
                                foreach (ModelUV[] t in uv)
                                {
                                    writer.Write(t[j].u);
                                    writer.Write(t[j].v);
                                }
                                if (skeleton != null && bones != null && bones[j].boneIndex != null &&
                                    bones[j].boneWeight != null)
                                {
                                    writer.Write((byte)4);
                                    writer.Write(skeleton.Lookup[bones[j].boneIndex[0]]);
                                    writer.Write(skeleton.Lookup[bones[j].boneIndex[1]]);
                                    writer.Write(skeleton.Lookup[bones[j].boneIndex[2]]);
                                    writer.Write(skeleton.Lookup[bones[j].boneIndex[3]]);
                                    writer.Write(bones[j].boneWeight[0]);
                                    writer.Write(bones[j].boneWeight[1]);
                                    writer.Write(bones[j].boneWeight[2]);
                                    writer.Write(bones[j].boneWeight[3]);
                                }
                                else
                                {
                                    // bone -> size + index + weight
                                    writer.Write((byte)0);
                                }
                            }
                            List <ModelIndiceModifiable> indexNew = new List <ModelIndiceModifiable>();
                            foreach (ModelIndice indice in index)
                            {
                                indexNew.Add(new ModelIndiceModifiable {
                                    v1 = indice.v1,
                                    v2 = indice.v2,
                                    v3 = indice.v3
                                });
                            }
                            foreach (ModelIndiceModifiable indice in indexNew)
                            {
                                writer.Write((byte)3);
                                writer.Write(indice.v1);
                                writer.Write(indice.v2);
                                writer.Write(indice.v3);
                            }
                        }
                    }

                    if (hardpoints != null)
                    {
                        // attachments
                        foreach (PRHM.HardPoint hp in hardpoints.HardPoints)
                        {
                            writer.Write(IdToString("hardpoint", GUID.Index(hp.HardPointGUID)));
                            Matrix4 mat = hp.Matrix.ToOpenTK();

                            Vector3    pos = mat.ExtractTranslation();
                            Quaternion rot = mat.ExtractRotation();

                            writer.Write(pos.X);
                            writer.Write(pos.Y);
                            writer.Write(pos.Z);
                            writer.Write(rot.X);
                            writer.Write(rot.Y);
                            writer.Write(rot.Z);
                            writer.Write(rot.W);
                        }
                        // extension 1.1
                        foreach (PRHM.HardPoint hp in hardpoints.HardPoints)
                        {
                            writer.Write(IdToString("bone", GUID.Index(hp.GUIDx012)));
                        }
                    }

                    // ext 1.3: cloth
                    writer.Write(0);

                    // ext 1.4: embedded refpose
                    if (skeleton != null)
                    {
                        for (int i = 0; i < skeleton.Data.bonesAbs; ++i)
                        {
                            writer.Write(IdToString("bone", skeleton.IDs[i]));
                            short parent = hierarchy[i];
                            writer.Write(parent);

                            Matrix3x4 bone = skeleton.Matrices34Inverted[i];

                            Quaternion3D quat = new Quaternion3D(bone[0, 3], bone[0, 0], bone[0, 1], bone[0, 2]);

                            Vector3D rot = C3D.ToEulerAngles(quat);
                            // ReSharper disable CompareOfFloatsByEqualityOperator
                            if (rot.X == -3.14159274f && rot.Y == 0 && rot.Z == 0)
                            {
                                rot = new Vector3D(0, 3.14159274f, 3.14159274f);
                                // effectively the same but you know, eulers.
                            }
                            // ReSharper restore CompareOfFloatsByEqualityOperator
                            Vector3 scl = new Vector3(bone[1, 0], bone[1, 1], bone[1, 2]);
                            Vector3 pos = new Vector3(bone[2, 0], bone[2, 1], bone[2, 2]);
                            writer.Write(pos.X);
                            writer.Write(pos.Y);
                            writer.Write(pos.Z);
                            writer.Write(scl.X);
                            writer.Write(scl.Y);
                            writer.Write(scl.Z);
                            writer.Write(rot.X);
                            writer.Write(rot.Y);
                            writer.Write(rot.Z);
                        }
                    }

                    // ext 1.5: guid
                    writer.Write(GUID.Index(modelInfo.GUID));

                    // ext 1.6: cloth 2.0
                    if (cloth == null)
                    {
                        writer.Write(0);
                    }
                    else
                    {
                        writer.Write(cloth.Descriptors.Length);

                        for (int i = 0; i < cloth.Descriptors.Length; i++)
                        {
                            var desc = cloth.Descriptors[i];

                            writer.Write(desc.Name);
                            writer.Write(cloth.Nodes[i].Length);
                            foreach (HTLC.ClothNode clothNode in cloth.Nodes[i])
                            {
                                writer.Write(clothNode.Bones.Length);

                                foreach (HTLC.ClothNodeWeight clothNodeWeight in clothNode.Bones)
                                {
                                    writer.Write(clothNodeWeight.Bone);
                                    writer.Write(clothNodeWeight.Weight);
                                }
                            }
                        }
                    }
                }
            }
Exemple #19
0
    public static CAAParabolicObjectDetails Calculate(double JD, CAAParabolicObjectElements elements)
    {
        double Epsilon = CAANutation.MeanObliquityOfEcliptic(elements.JDEquinox);

        double JD0 = JD;

        //What will be the return value
        CAAParabolicObjectDetails details = new CAAParabolicObjectDetails();

        Epsilon = CT.D2R(Epsilon);
        double omega = CT.D2R(elements.omega);
        double w     = CT.D2R(elements.w);
        double i     = CT.D2R(elements.i);

        double sinEpsilon = Math.Sin(Epsilon);
        double cosEpsilon = Math.Cos(Epsilon);
        double sinOmega   = Math.Sin(omega);
        double cosOmega   = Math.Cos(omega);
        double cosi       = Math.Cos(i);
        double sini       = Math.Sin(i);

        double F = cosOmega;
        double G = sinOmega * cosEpsilon;
        double H = sinOmega * sinEpsilon;
        double P = -sinOmega * cosi;
        double Q = cosOmega * cosi * cosEpsilon - sini * sinEpsilon;
        double R = cosOmega * cosi * sinEpsilon + sini * cosEpsilon;
        double a = Math.Sqrt(F * F + P * P);
        double b = Math.Sqrt(G * G + Q * Q);
        double c = Math.Sqrt(H * H + R * R);
        double A = Math.Atan2(F, P);
        double B = Math.Atan2(G, Q);
        double C = Math.Atan2(H, R);

        C3D SunCoord = CAASun.EquatorialRectangularCoordinatesAnyEquinox(JD, elements.JDEquinox);

        for (int j = 0; j < 2; j++)
        {
            double W = 0.03649116245 / (elements.q * Math.Sqrt(elements.q)) * (JD0 - elements.T);
            double s = CalculateBarkers(W);
            double v = 2 * Math.Atan(s);
            double r = elements.q * (1 + s * s);
            double x = r * a * Math.Sin(A + w + v);
            double y = r * b * Math.Sin(B + w + v);
            double z = r * c * Math.Sin(C + w + v);

            if (j == 0)
            {
                details.HeliocentricRectangularEquatorial.X = x;
                details.HeliocentricRectangularEquatorial.Y = y;
                details.HeliocentricRectangularEquatorial.Z = z;

                //Calculate the heliocentric ecliptic coordinates also
                double u    = omega + v;
                double cosu = Math.Cos(u);
                double sinu = Math.Sin(u);

                details.HeliocentricRectangularEcliptical.X = r * (cosOmega * cosu - sinOmega * sinu * cosi);
                details.HeliocentricRectangularEcliptical.Y = r * (sinOmega * cosu + cosOmega * sinu * cosi);
                details.HeliocentricRectangularEcliptical.Z = r * sini * sinu;

                details.HeliocentricEclipticLongitude = Math.Atan2(y, x);
                details.HeliocentricEclipticLongitude = CT.M24(CT.R2D(details.HeliocentricEclipticLongitude) / 15);
                details.HeliocentricEclipticLatitude  = Math.Asin(z / r);
                details.HeliocentricEclipticLatitude  = CT.R2D(details.HeliocentricEclipticLatitude);
            }

            double psi   = SunCoord.X + x;
            double nu    = SunCoord.Y + y;
            double sigma = SunCoord.Z + z;

            double Alpha = Math.Atan2(nu, psi);
            Alpha = CT.R2D(Alpha);
            double Delta = Math.Atan2(sigma, Math.Sqrt(psi * psi + nu * nu));
            Delta = CT.R2D(Delta);
            double Distance = Math.Sqrt(psi * psi + nu * nu + sigma * sigma);

            if (j == 0)
            {
                details.TrueGeocentricRA          = CT.M24(Alpha / 15);
                details.TrueGeocentricDeclination = Delta;
                details.TrueGeocentricDistance    = Distance;
                details.TrueGeocentricLightTime   = ELL.DistanceToLightTime(Distance);
            }
            else
            {
                details.AstrometricGeocenticRA           = CT.M24(Alpha / 15);
                details.AstrometricGeocentricDeclination = Delta;
                details.AstrometricGeocentricDistance    = Distance;
                details.AstrometricGeocentricLightTime   = ELL.DistanceToLightTime(Distance);

                double RES = Math.Sqrt(SunCoord.X * SunCoord.X + SunCoord.Y * SunCoord.Y + SunCoord.Z * SunCoord.Z);

                details.Elongation = CT.R2D(Math.Acos((RES * RES + Distance * Distance - r * r) / (2 * RES * Distance)));
                details.PhaseAngle = CT.R2D(Math.Acos((r * r + Distance * Distance - RES * RES) / (2 * r * Distance)));
            }

            if (j == 0) //Prepare for the next loop around
            {
                JD0 = JD - details.TrueGeocentricLightTime;
            }
        }

        return(details);
    }
Exemple #20
0
        public static void ConvertAnimation(string refpose, string input, string output)
        {
            NumberFormatInfo format = new NumberFormatInfo();

            format.NumberDecimalSeparator = ".";
            StreamReader          refpose_reader    = new StreamReader(refpose);
            int                   refpose_bonecount = Convert.ToInt32(refpose_reader.ReadLine());
            Dictionary <int, int> refpose_parentmap = new Dictionary <int, int>();
            Dictionary <int, int> refpose_indexmap  = new Dictionary <int, int>();

            int[] refpose_bonearray = new int[refpose_bonecount];
            int[] refpose_hierarchy = new int[refpose_bonecount];
            refpose_reader.ReadLine();
            refpose_reader.ReadLine();
            for (int index = 0; index < refpose_bonecount; ++index)
            {
                string[] array = refpose_reader.ReadLine().Replace("\"", string.Empty).Split(' ');
                refpose_bonearray[index] = Convert.ToInt32(array[1].Split('_').Last(), 16);
                refpose_hierarchy[index] = Convert.ToInt32(array[2]);
            }

            for (int index = 0; index < refpose_bonecount; ++index)
            {
                if (refpose_hierarchy[index] != -1)
                {
                    refpose_parentmap.Add(refpose_bonearray[index], refpose_bonearray[refpose_hierarchy[index]]);
                }
                else
                {
                    refpose_parentmap.Add(refpose_bonearray[index], -1);
                }
                refpose_indexmap.Add(refpose_bonearray[index], index);
            }
            refpose_reader.ReadLine();
            refpose_reader.ReadLine();
            refpose_reader.ReadLine();
            Vector3D[] refpose_position = new Vector3D[refpose_bonecount];
            Vector3D[] refpose_rotation = new Vector3D[refpose_bonecount];
            Vector3D[] refpose_scale    = new Vector3D[refpose_bonecount];
            for (int index = 0; index < refpose_bonecount; ++index)
            {
                refpose_position[index] = new Vector3D();
                refpose_rotation[index] = new Vector3D();
                refpose_scale[index]    = new Vector3D(1, 1, 1);
                string[] array = refpose_reader.ReadLine().Replace("\"", string.Empty).Split(' ');
                refpose_position[index].X = Convert.ToSingle(array[2], format);
                refpose_position[index].Y = Convert.ToSingle(array[3], format);
                refpose_position[index].Z = Convert.ToSingle(array[4], format);
                refpose_rotation[index].X = Convert.ToSingle(array[6], format);
                refpose_rotation[index].Y = Convert.ToSingle(array[7], format);
                refpose_rotation[index].Z = Convert.ToSingle(array[8], format);
            }
            refpose_reader.Close();
            FileStream   inputStream  = new FileStream(input, FileMode.Open);
            BinaryReader input_reader = new BinaryReader(inputStream);

            input_reader.ReadInt32();
            float  duration   = input_reader.ReadSingle();
            float  fps        = input_reader.ReadSingle();
            ushort bone_count = input_reader.ReadUInt16();

            input_reader.ReadUInt16();
            int frame_count = (int)(fps * (double)duration) + 1;

            inputStream.Seek(24L, SeekOrigin.Current);
            long offset_bone_list  = input_reader.ReadInt64();
            long offset_info_table = input_reader.ReadInt64();

            inputStream.Seek(24L, SeekOrigin.Current);
            StreamWriter output_writer = new StreamWriter(output);

            output_writer.WriteLine("version 1");
            output_writer.WriteLine("nodes");
            int[] bone_list = new int[bone_count];
            inputStream.Seek(offset_bone_list, SeekOrigin.Begin);
            Dictionary <int, int> bone_translation_map = new Dictionary <int, int>();
            int bone_id;

            for (int index = 0; index < bone_count; ++index)
            {
                bone_id          = input_reader.ReadInt32();
                bone_list[index] = bone_id;
                bone_translation_map.Add(bone_id, index);
            }
            for (int index = 0; index < bone_count; ++index)
            {
                bone_id = bone_list[index];
                int num3 = -1;
                if (refpose_parentmap.ContainsKey(bone_id))
                {
                    int key2 = refpose_parentmap[bone_id];
                    num3 = !bone_translation_map.ContainsKey(key2) ? -1 : bone_translation_map[key2];
                }
                output_writer.WriteLine(index.ToString() + " \"bone_" + bone_id.ToString("X4") + "\" " + num3);
            }
            int last_bone_index = bone_count;
            Dictionary <int, int> secondary_bone_translation_map = new Dictionary <int, int>();

            for (int index = 0; index < refpose_bonecount; ++index)
            {
                if (!bone_translation_map.ContainsKey(refpose_bonearray[index]))
                {
                    secondary_bone_translation_map.Add(refpose_bonearray[index], last_bone_index);
                }
            }

            for (int index = 0; index < refpose_bonecount; ++index)
            {
                if (!bone_translation_map.ContainsKey(refpose_bonearray[index]))
                {
                    int key2 = refpose_parentmap[refpose_bonearray[index]];
                    int num3 = !bone_translation_map.ContainsKey(key2) ? (!secondary_bone_translation_map.ContainsKey(key2) ? -1 : secondary_bone_translation_map[key2]) : bone_translation_map[key2];
                    output_writer.WriteLine(last_bone_index.ToString() + " \"bone_" + refpose_bonearray[index].ToString("X4") + "\" " + num3);
                    ++last_bone_index;
                }
            }
            output_writer.WriteLine("end");
            float[,] x_array           = new float[last_bone_index, frame_count];
            float[,] y_array           = new float[last_bone_index, frame_count];
            float[,] z_array           = new float[last_bone_index, frame_count];
            float[,] sx_array          = new float[last_bone_index, frame_count];
            float[,] sy_array          = new float[last_bone_index, frame_count];
            float[,] sz_array          = new float[last_bone_index, frame_count];
            float[,] rx_array          = new float[last_bone_index, frame_count];
            float[,] ry_array          = new float[last_bone_index, frame_count];
            float[,] rz_array          = new float[last_bone_index, frame_count];
            float[,] rw_array          = new float[last_bone_index, frame_count];
            bool[,] has_rotation_frame = new bool[last_bone_index, frame_count];
            bool[,] has_position_frame = new bool[last_bone_index, frame_count];
            bool[,] has_scale_frame    = new bool[last_bone_index, frame_count];
            output_writer.WriteLine("skeleton");
            output_writer.WriteLine("time 0");
            for (int index = 0; index < bone_count; ++index)
            {
                if (refpose_indexmap.ContainsKey(bone_list[index]))
                {
                    bone_id = refpose_indexmap[bone_list[index]];
                    output_writer.Write(index);
                    output_writer.Write(" " + refpose_position[bone_id].X.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_position[bone_id].Y.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_position[bone_id].Z.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_rotation[bone_id].X.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_rotation[bone_id].Y.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_rotation[bone_id].Z.ToString("0.000000", format));
                    output_writer.WriteLine();
                }
                else
                {
                    output_writer.WriteLine(index.ToString() + " 0 0 0 0 0 0");
                }
            }
            int num4 = bone_count;

            for (int index = 0; index < refpose_bonecount; ++index)
            {
                if (!bone_translation_map.ContainsKey(refpose_bonearray[index]))
                {
                    output_writer.Write(num4++);
                    output_writer.Write(" " + refpose_position[index].X.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_position[index].Y.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_position[index].Z.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_rotation[index].X.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_rotation[index].Y.ToString("0.000000", format));
                    output_writer.Write(" " + refpose_rotation[index].Z.ToString("0.000000", format));
                    output_writer.WriteLine();
                }
            }
            Quaternion3D q        = new Quaternion3D();
            Vector3D     vector3D = new Vector3D();

            inputStream.Seek(offset_info_table, SeekOrigin.Begin);
            for (int index1 = 0; index1 < bone_count; ++index1)
            {
                long  position                = inputStream.Position;
                int   scale_count             = input_reader.ReadInt16();
                int   position_count          = input_reader.ReadInt16();
                int   rotation_count          = input_reader.ReadInt16();
                int   flags                   = input_reader.ReadInt16();
                long  scale_indices_offset    = input_reader.ReadInt32() * 4 + position;
                long  position_indices_offset = input_reader.ReadInt32() * 4 + position;
                long  rotation_indices_offset = input_reader.ReadInt32() * 4 + position;
                long  scale_data_offset       = input_reader.ReadInt32() * 4 + position;
                long  position_data_offset    = input_reader.ReadInt32() * 4 + position;
                long  rotation_data_offset    = input_reader.ReadInt32() * 4 + position;
                int[] scale_indices           = new int[scale_count];
                inputStream.Seek(scale_indices_offset, SeekOrigin.Begin);
                for (int index2 = 0; index2 < scale_count; ++index2)
                {
                    scale_indices[index2] = frame_count > byte.MaxValue ? input_reader.ReadInt16() : input_reader.ReadByte();
                }
                inputStream.Seek(scale_data_offset, SeekOrigin.Begin);
                for (int index2 = 0; index2 < scale_count; ++index2)
                {
                    int index3 = scale_indices[index2];
                    has_scale_frame[index1, index3] = true;
                    float x = input_reader.ReadUInt16() / 1024.0f;
                    sx_array[index1, index3] = x;
                    float y = input_reader.ReadUInt16() / 1024.0f;
                    sy_array[index1, index3] = y;
                    float z = input_reader.ReadUInt16() / 1024.0f;
                    sz_array[index1, index3] = z;
                }
                int[] position_indices = new int[position_count];
                inputStream.Seek(position_indices_offset, SeekOrigin.Begin);
                for (int index2 = 0; index2 < position_count; ++index2)
                {
                    position_indices[index2] = frame_count > byte.MaxValue ? input_reader.ReadInt16() : input_reader.ReadByte();
                }
                inputStream.Seek(position_data_offset, SeekOrigin.Begin);
                for (int index2 = 0; index2 < position_count; ++index2)
                {
                    int index3 = position_indices[index2];
                    has_position_frame[index1, index3] = true;
                    float x = input_reader.ReadSingle();
                    x_array[index1, index3] = x;
                    float y = input_reader.ReadSingle();
                    y_array[index1, index3] = y;
                    float z = input_reader.ReadSingle();
                    z_array[index1, index3] = z;
                }
                int[] rotation_indices = new int[rotation_count];
                inputStream.Seek(rotation_indices_offset, SeekOrigin.Begin);
                for (int index2 = 0; index2 < rotation_count; ++index2)
                {
                    rotation_indices[index2] = frame_count > byte.MaxValue ? input_reader.ReadInt16() : input_reader.ReadByte();
                }
                inputStream.Seek(rotation_data_offset, SeekOrigin.Begin);
                for (int index2 = 0; index2 < rotation_count; ++index2)
                {
                    ushort rot_a  = input_reader.ReadUInt16();
                    ushort rot_b  = input_reader.ReadUInt16();
                    ushort rot_c  = input_reader.ReadUInt16();
                    Vec4d  rot    = Animation.UnpackRotation(rot_a, rot_b, rot_c);
                    int    index3 = rotation_indices[index2];
                    has_rotation_frame[index1, index3] = true;
                    rx_array[index1, index3]           = (float)rot.x;
                    ry_array[index1, index3]           = (float)rot.y;
                    rz_array[index1, index3]           = (float)rot.z;
                    rw_array[index1, index3]           = (float)rot.w;
                }
                inputStream.Seek(position + 32L, SeekOrigin.Begin);
            }
            for (int index1 = 0; index1 < frame_count; ++index1)
            {
                output_writer.WriteLine($"time {index1 + 1}");
                for (int index2 = 0; index2 < last_bone_index; ++index2)
                {
                    if (has_position_frame[index2, index1] || has_rotation_frame[index2, index1] || has_scale_frame[index2, index1])
                    {
                        if (!has_position_frame[index2, index1])
                        {
                            int index3 = index1;
                            int index4 = index1;
                            while (!has_position_frame[index2, index3])
                            {
                                --index3;
                            }
                            while (index4 < frame_count && !has_position_frame[index2, index4])
                            {
                                ++index4;
                            }
                            if (index4 == frame_count)
                            {
                                x_array[index2, index1] = x_array[index2, index3];
                                y_array[index2, index1] = y_array[index2, index3];
                                z_array[index2, index1] = z_array[index2, index3];
                            }
                            else
                            {
                                float num3 = (index1 - index3) / (float)(index4 - index3);
                                x_array[index2, index1] = (x_array[index2, index4] - x_array[index2, index3]) * num3 + x_array[index2, index3];
                                y_array[index2, index1] = (y_array[index2, index4] - y_array[index2, index3]) * num3 + y_array[index2, index3];
                                z_array[index2, index1] = (z_array[index2, index4] - z_array[index2, index3]) * num3 + z_array[index2, index3];
                            }
                        }
                        if (!has_scale_frame[index2, index1])
                        {
                            int index3 = index1;
                            int index4 = index1;
                            while (!has_scale_frame[index2, index3])
                            {
                                --index3;
                            }
                            while (index4 < frame_count && !has_scale_frame[index2, index4])
                            {
                                ++index4;
                            }
                            if (index4 == frame_count)
                            {
                                sx_array[index2, index1] = sx_array[index2, index3];
                                sy_array[index2, index1] = sy_array[index2, index3];
                                sz_array[index2, index1] = sz_array[index2, index3];
                            }
                            else
                            {
                                float num3 = (index1 - index3) / (float)(index4 - index3);
                                sx_array[index2, index1] = (sx_array[index2, index4] - sx_array[index2, index3]) * num3 + sx_array[index2, index3];
                                sy_array[index2, index1] = (sy_array[index2, index4] - sy_array[index2, index3]) * num3 + sy_array[index2, index3];
                                sz_array[index2, index1] = (sz_array[index2, index4] - sz_array[index2, index3]) * num3 + sz_array[index2, index3];
                            }
                        }
                        if (!has_rotation_frame[index2, index1])
                        {
                            int index3 = index1;
                            int index4 = index1;
                            while (!has_rotation_frame[index2, index3])
                            {
                                --index3;
                            }
                            while (index4 < frame_count && !has_rotation_frame[index2, index4])
                            {
                                ++index4;
                            }
                            if (index4 == frame_count)
                            {
                                rx_array[index2, index1] = rx_array[index2, index3];
                                ry_array[index2, index1] = ry_array[index2, index3];
                                rz_array[index2, index1] = rz_array[index2, index3];
                                rw_array[index2, index1] = rw_array[index2, index3];
                            }
                            else
                            {
                                double num3 = rx_array[index2, index4] * (double)rx_array[index2, index3] + ry_array[index2, index4] * (double)ry_array[index2, index3] + rz_array[index2, index4] * (double)rz_array[index2, index3] + rw_array[index2, index4] * (double)rw_array[index2, index3];
                                float  num9 = (index1 - index3) / (float)(index4 - index3);
                                if (num3 < 0.0)
                                {
                                    rx_array[index2, index1] = (-rx_array[index2, index4] - rx_array[index2, index3]) * num9 + rx_array[index2, index3];
                                    ry_array[index2, index1] = (-ry_array[index2, index4] - ry_array[index2, index3]) * num9 + ry_array[index2, index3];
                                    rz_array[index2, index1] = (-rz_array[index2, index4] - rz_array[index2, index3]) * num9 + rz_array[index2, index3];
                                    rw_array[index2, index1] = (-rw_array[index2, index4] - rw_array[index2, index3]) * num9 + rw_array[index2, index3];
                                }
                                else
                                {
                                    rx_array[index2, index1] = (rx_array[index2, index4] - rx_array[index2, index3]) * num9 + rx_array[index2, index3];
                                    ry_array[index2, index1] = (ry_array[index2, index4] - ry_array[index2, index3]) * num9 + ry_array[index2, index3];
                                    rz_array[index2, index1] = (rz_array[index2, index4] - rz_array[index2, index3]) * num9 + rz_array[index2, index3];
                                    rw_array[index2, index1] = (rw_array[index2, index4] - rw_array[index2, index3]) * num9 + rw_array[index2, index3];
                                }
                            }
                        }
                        output_writer.Write(index2);
                        output_writer.Write(" " + x_array[index2, index1].ToString("0.000000", format));
                        output_writer.Write(" " + y_array[index2, index1].ToString("0.000000", format));
                        output_writer.Write(" " + z_array[index2, index1].ToString("0.000000", format));
                        q.i    = rx_array[index2, index1];
                        q.j    = ry_array[index2, index1];
                        q.k    = rz_array[index2, index1];
                        q.real = rw_array[index2, index1];
                        Vector3D eulerAngles = C3D.ToEulerAngles(q);
                        output_writer.Write(" " + eulerAngles.X.ToString("0.000000", format));
                        output_writer.Write(" " + eulerAngles.Y.ToString("0.000000", format));
                        output_writer.Write(" " + eulerAngles.Z.ToString("0.000000", format));
                        output_writer.WriteLine();
                    }
                }
            }
            output_writer.WriteLine("end");
            output_writer.Close();
        }
Exemple #21
0
        // ReSharper disable once InconsistentNaming
        public bool Write(Chunked chunked, Stream output, List <byte> LODs, Dictionary <ulong, List <ImageLayer> > layers, object[] data)
        {
            IChunk chunk = chunked.FindNextChunk("MNRM").Value;

            if (chunk == null)
            {
                return(false);
            }
            MNRM model = (MNRM)chunk;

            chunk = chunked.FindNextChunk("CLDM").Value;
            CLDM materials = null;

            if (chunk != null)
            {
                materials = (CLDM)chunk;
            }
            chunk = chunked.FindNextChunk("lksm").Value;
            lksm skeleton = null;

            if (chunk != null)
            {
                skeleton = (lksm)chunk;
            }
            chunk = chunked.FindNextChunk("PRHM").Value;
            PRHM hardpoints = null;

            if (chunk != null)
            {
                hardpoints = (PRHM)chunk;
            }

            short[] hierarchy = (short[])skeleton?.Hierarchy.Clone();
            Dictionary <int, HTLC.ClothNode> nodeMap = new Dictionary <int, HTLC.ClothNode>();

            if (chunked.FindNextChunk("HTLC").Value is HTLC cloth)
            {
                uint clothIndex = 0;
                foreach (HTLC.ClothNode[] nodeCollection in cloth.Nodes)
                {
                    if (nodeCollection == null)
                    {
                        continue;
                    }
                    int nodeIndex = 0;
                    foreach (HTLC.ClothNode node in nodeCollection)
                    {
                        int parentRaw = node.VerticalParent;
                        if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex) &&
                            cloth.NodeBones[clothIndex].ContainsKey(parentRaw))
                        {
                            if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                            {
                                hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = cloth.NodeBones[clothIndex][parentRaw];
                                if (cloth.NodeBones[clothIndex][parentRaw] == -1)
                                {
                                    HTLC.ClothNodeWeight weightedBone = node.Bones.Aggregate((i1, i2) => i1.Weight > i2.Weight ? i1 : i2);
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = weightedBone.Bone;
                                }
                            }
                        }
                        else
                        {
                            if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex))    // if on main skele
                            {
                                if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                                {
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = -1;
                                    HTLC.ClothNodeWeight weightedBone = node.Bones.Aggregate((i1, i2) => i1.Weight > i2.Weight ? i1 : i2);
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = weightedBone.Bone;
                                }
                            }
                        }
                        if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex))
                        {
                            // good code:
                            if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                            {
                                nodeMap[cloth.NodeBones[clothIndex][nodeIndex]] = node;
                            }
                        }

                        nodeIndex++;
                    }
                    clothIndex++;
                }
            }

            using (BinaryWriter writer = new BinaryWriter(output)) {
                writer.Write((ushort)1); // version major
                writer.Write((ushort)4); // version minor

                if (data.Length > 1 && data[1] is string && ((string)data[1]).Length > 0)
                {
                    writer.Write((string)data[1]);
                }
                else
                {
                    writer.Write((byte)0);
                }

                if (data.Length > 2 && data[2] is string && ((string)data[2]).Length > 0)
                {
                    writer.Write((string)data[2]);
                }
                else
                {
                    writer.Write((byte)0);
                }

                if (skeleton == null)
                {
                    writer.Write((ushort)0); // number of bones
                }
                else
                {
                    writer.Write(skeleton.Data.bonesAbs);
                }

                // ReSharper disable once InconsistentNaming
                Dictionary <byte, List <int> > LODMap = new Dictionary <byte, List <int> >();
                uint sz         = 0;
                uint lookForLod = 0;
                bool lodOnly    = data.Length > 3 && data[3] is bool && (bool)data[3];
                for (int i = 0; i < model.Submeshes.Length; ++i)
                {
                    SubmeshDescriptor submesh = model.Submeshes[i];
                    if (data.Length > 4 && data[4] is bool && (bool)data[4])
                    {
                        if (submesh.flags == SubmeshFlags.COLLISION_MESH)
                        {
                            continue;
                        }
                    }
                    if (LODs != null && !LODs.Contains(submesh.lod))
                    {
                        continue;
                    }
                    if (lodOnly && lookForLod > 0 && submesh.lod != lookForLod)
                    {
                        continue;
                    }
                    if (!LODMap.ContainsKey(submesh.lod))
                    {
                        LODMap.Add(submesh.lod, new List <int>());
                    }
                    lookForLod = submesh.lod;
                    sz++;
                    LODMap[submesh.lod].Add(i);
                }

                //long meshCountPos = writer.BaseStream.Position;
                writer.Write(sz);

                writer.Write(hardpoints?.HardPoints.Length ?? 0);

                if (skeleton != null)
                {
                    for (int i = 0; i < skeleton.Data.bonesAbs; ++i)
                    {
                        writer.Write(IdToString("bone", skeleton.IDs[i]));
                        short parent = hierarchy[i];
                        if (parent == -1)
                        {
                            parent = (short)i;
                        }
                        writer.Write(parent);

                        Matrix3x4  bone = skeleton.Matrices34[i];
                        Quaternion rot  = new Quaternion(bone[0, 0], bone[0, 1], bone[0, 2], bone[0, 3]);
                        Vector3    scl  = new Vector3(bone[1, 0], bone[1, 1], bone[1, 2]);
                        Vector3    pos  = new Vector3(bone[2, 0], bone[2, 1], bone[2, 2]);
                        if (nodeMap.ContainsKey(i))
                        {
                            HTLC.ClothNode thisNode = nodeMap[i];
                            pos.X = thisNode.X;
                            pos.Y = thisNode.Y;
                            pos.Z = thisNode.Z;
                        }
                        writer.Write(pos.X);
                        writer.Write(pos.Y);
                        writer.Write(pos.Z);
                        writer.Write(scl.X);
                        writer.Write(scl.Y);
                        writer.Write(scl.Z);
                        writer.Write(rot.X);
                        writer.Write(rot.Y);
                        writer.Write(rot.Z);
                        writer.Write(rot.W);
                    }
                }

                foreach (KeyValuePair <byte, List <int> > kv in LODMap)
                {
                    foreach (int i in kv.Value)
                    {
                        SubmeshDescriptor submesh = model.Submeshes[i];
                        ModelVertex[]     vertex  = model.Vertices[i];
                        ModelVertex[]     normal  = model.Normals[i];
                        ModelUV[][]       uv      = model.TextureCoordinates[i];
                        ModelIndice[]     index   = model.Indices[i];

                        ModelBoneData[] bones = model.Bones[i];
                        writer.Write($"Submesh_{i}.{kv.Key}.{materials.Materials[submesh.material]:X16}");
                        writer.Write(materials.Materials[submesh.material]);
                        writer.Write((byte)uv.Length);

                        writer.Write(vertex.Length);
                        writer.Write(index.Length);
                        for (int j = 0; j < vertex.Length; ++j)
                        {
                            writer.Write(vertex[j].x);
                            writer.Write(vertex[j].y);
                            writer.Write(vertex[j].z);
                            writer.Write(-normal[j].x);
                            writer.Write(-normal[j].y);
                            writer.Write(-normal[j].z);
                            foreach (ModelUV[] t in uv)
                            {
                                writer.Write(t[j].u);
                                writer.Write(t[j].v);
                            }
                            if (skeleton != null && bones != null && bones[j].boneIndex != null && bones[j].boneWeight != null)
                            {
                                writer.Write((byte)4);
                                writer.Write(skeleton.Lookup[bones[j].boneIndex[0]]);
                                writer.Write(skeleton.Lookup[bones[j].boneIndex[1]]);
                                writer.Write(skeleton.Lookup[bones[j].boneIndex[2]]);
                                writer.Write(skeleton.Lookup[bones[j].boneIndex[3]]);
                                writer.Write(bones[j].boneWeight[0]);
                                writer.Write(bones[j].boneWeight[1]);
                                writer.Write(bones[j].boneWeight[2]);
                                writer.Write(bones[j].boneWeight[3]);
                            }
                            else
                            {
                                // bone -> size + index + weight
                                writer.Write((byte)0);
                            }
                        }
                        List <ModelIndiceModifiable> indexNew = new List <ModelIndiceModifiable>();
                        foreach (ModelIndice indice in index)
                        {
                            indexNew.Add(new ModelIndiceModifiable {
                                v1 = indice.v1, v2 = indice.v2, v3 = indice.v3
                            });
                        }
                        foreach (ModelIndiceModifiable indice in indexNew)
                        {
                            writer.Write((byte)3);
                            writer.Write(indice.v1);
                            writer.Write(indice.v2);
                            writer.Write(indice.v3);
                        }
                    }
                }

                if (hardpoints != null)
                {
                    // attachments
                    foreach (PRHM.HardPoint hp in hardpoints.HardPoints)
                    {
                        writer.Write(IdToString("attachment_", GUID.Index(hp.HardPointGUID)));
                        Matrix4    mat = hp.Matrix.ToOpenTK();
                        Vector3    pos = mat.ExtractTranslation();
                        Quaternion rot = mat.ExtractRotation();
                        writer.Write(pos.X);
                        writer.Write(pos.Y);
                        writer.Write(pos.Z);
                        writer.Write(rot.X);
                        writer.Write(rot.Y);
                        writer.Write(rot.Z);
                        writer.Write(rot.W);
                    }
                    // extension 1.1
                    foreach (PRHM.HardPoint hp in hardpoints.HardPoints)
                    {
                        writer.Write(IdToString("bone", GUID.Index(hp.GUIDx012)));
                    }
                }

                // ext 1.3: cloth
                writer.Write(0);

                // ext 1.4: embedded refpose
                if (skeleton != null)
                {
                    for (int i = 0; i < skeleton.Data.bonesAbs; ++i)
                    {
                        writer.Write(IdToString("bone", skeleton.IDs[i]));
                        short parent = hierarchy[i];
                        // if (parent == -1) {
                        //     parent = (short)i;
                        // }
                        writer.Write(parent);

                        Matrix3x4 bone = skeleton.Matrices34Inverted[i];

                        // Quaternion3D quat = new Quaternion3D(bone[0, 0], bone[0, 1], bone[0, 2], bone[0, 3]);
                        // why are they different
                        Quaternion3D quat = new Quaternion3D(bone[0, 3], bone[0, 0], bone[0, 1], bone[0, 2]);

                        Vector3D rot = C3D.ToEulerAngles(quat);
                        if (rot.X == -3.14159274f && rot.Y == 0 && rot.Z == 0)
                        {
                            rot = new Vector3D(0, 3.14159274f, 3.14159274f); // effectively the same but you know, eulers.
                        }
                        Vector3 scl = new Vector3(bone[1, 0], bone[1, 1], bone[1, 2]);
                        Vector3 pos = new Vector3(bone[2, 0], bone[2, 1], bone[2, 2]);

                        writer.Write(pos.X);
                        writer.Write(pos.Y);
                        writer.Write(pos.Z);
                        writer.Write(scl.X);
                        writer.Write(scl.Y);
                        writer.Write(scl.Z);
                        writer.Write(rot.X);
                        writer.Write(rot.Y);
                        writer.Write(rot.Z);
                    }
                }
            }

            return(true);
        }
Exemple #22
0
    protected static double[] Rotations(double X, double Y, double Z, double I, double psi, double i, double omega, double lambda0, double beta0, C3D eclipticCoord)
    {
        double A6;
        double B6;
        double C6;

        //eclipticCoord = new CAA3DCoordinate();
        double phi = psi - omega;

        //Rotation towards Jupiter's orbital plane
        double A1 = X;
        double B1 = Y * Math.Cos(I) - Z * Math.Sin(I);
        double C1 = Y * Math.Sin(I) + Z * Math.Cos(I);

        //Rotation towards the ascending node of the orbit of jupiter
        double A2 = A1 * Math.Cos(phi) - B1 * Math.Sin(phi);
        double B2 = A1 * Math.Sin(phi) + B1 * Math.Cos(phi);
        double C2 = C1;

        //Rotation towards the plane of the ecliptic
        double A3 = A2;
        double B3 = B2 * Math.Cos(i) - C2 * Math.Sin(i);
        double C3 = B2 * Math.Sin(i) + C2 * Math.Cos(i);

        //Rotation towards the vernal equinox
        double A4 = A3 * Math.Cos(omega) - B3 * Math.Sin(omega);
        double B4 = A3 * Math.Sin(omega) + B3 * Math.Cos(omega);
        double C4 = C3;

        const double JupiterRadiiToAU = 1.0 / 2095.0; // Not exact, but this is the value used elsewhere in the calculation

        eclipticCoord.X = A4 * JupiterRadiiToAU;
        eclipticCoord.Y = B4 * JupiterRadiiToAU;
        eclipticCoord.Z = C4 * JupiterRadiiToAU;

        double A5 = A4 * Math.Sin(lambda0) - B4 * Math.Cos(lambda0);
        double B5 = A4 * Math.Cos(lambda0) + B4 * Math.Sin(lambda0);
        double C5 = C4;

        A6 = A5;
        B6 = C5 * Math.Sin(beta0) + B5 * Math.Cos(beta0);
        C6 = C5 * Math.Cos(beta0) - B5 * Math.Sin(beta0);

        return(new double[] { A6, B6, C6 });
    }
Exemple #23
0
    //////////////////////////////// Implementation ///////////////////////////////

    protected static GMDS CalculateHelper(double JD, double sunlongrad, double betarad, double R)
    {
        //What will be the return value
        GMDS details = new GMDS();

        //Calculate the position of Jupiter decreased by the light travel time from Jupiter to the specified position
        double DELTA = 5;
        double PreviousLightTravelTime = 0;
        double LightTravelTime         = ELL.DistanceToLightTime(DELTA);
        double x        = 0;
        double y        = 0;
        double z        = 0;
        double l        = 0;
        double lrad     = 0;
        double b        = 0;
        double brad     = 0;
        double r        = 0;
        double JD1      = JD - LightTravelTime;
        bool   bIterate = true;

        while (bIterate)
        {
            //Calculate the position of Jupiter
            l    = CAAJupiter.EclipticLongitude(JD1);
            lrad = CT.D2R(l);
            b    = CAAJupiter.EclipticLatitude(JD1);
            brad = CT.D2R(b);
            r    = CAAJupiter.RadiusVector(JD1);

            x               = r * Math.Cos(brad) * Math.Cos(lrad) + R * Math.Cos(sunlongrad);
            y               = r * Math.Cos(brad) * Math.Sin(lrad) + R * Math.Sin(sunlongrad);
            z               = r * Math.Sin(brad) + R * Math.Sin(betarad);
            DELTA           = Math.Sqrt(x * x + y * y + z * z);
            LightTravelTime = ELL.DistanceToLightTime(DELTA);

            //Prepare for the next loop around
            bIterate = (Math.Abs(LightTravelTime - PreviousLightTravelTime) > 2E-6); //2E-6 corresponds to 0.17 of a second
            if (bIterate)
            {
                JD1 = JD - LightTravelTime;
                PreviousLightTravelTime = LightTravelTime;
            }
        }

        //Calculate Jupiter's Longitude and Latitude
        double lambda0 = Math.Atan2(y, x);
        double beta0   = Math.Atan(z / Math.Sqrt(x * x + y * y));

        double t = JD - 2443000.5 - LightTravelTime;

        //Calculate the mean longitudes
        double l1    = 106.07719 + 203.488955790 * t;
        double l1rad = CT.D2R(l1);
        double l2    = 175.73161 + 101.374724735 * t;
        double l2rad = CT.D2R(l2);
        double l3    = 120.55883 + 50.317609207 * t;
        double l3rad = CT.D2R(l3);
        double l4    = 84.44459 + 21.571071177 * t;
        double l4rad = CT.D2R(l4);

        //Calculate the perijoves
        double pi1 = CT.D2R(CT.M360(97.0881 + 0.16138586 * t));
        double pi2 = CT.D2R(CT.M360(154.8663 + 0.04726307 * t));
        double pi3 = CT.D2R(CT.M360(188.1840 + 0.00712734 * t));
        double pi4 = CT.D2R(CT.M360(335.2868 + 0.00184000 * t));

        //Calculate the nodes on the equatorial plane of jupiter
        double w1    = 312.3346 - 0.13279386 * t;
        double w1rad = CT.D2R(w1);
        double w2    = 100.4411 - 0.03263064 * t;
        double w2rad = CT.D2R(w2);
        double w3    = 119.1942 - 0.00717703 * t;
        double w3rad = CT.D2R(w3);
        double w4    = 322.6186 - 0.00175934 * t;
        double w4rad = CT.D2R(w4);

        //Calculate the Principal inequality in the longitude of Jupiter
        double GAMMA = 0.33033 * Math.Sin(CT.D2R(163.679 + 0.0010512 * t)) + 0.03439 * Math.Sin(CT.D2R(34.486 - 0.0161731 * t));

        //Calculate the "phase of free libration"
        double philambda = CT.D2R(199.6766 + 0.17379190 * t);

        //Calculate the longitude of the node of the equator of Jupiter on the ecliptic
        double psi = CT.D2R(316.5182 - 0.00000208 * t);

        //Calculate the mean anomalies of Jupiter and Saturn
        double G     = CT.D2R(30.23756 + 0.0830925701 * t + GAMMA);
        double Gdash = CT.D2R(31.97853 + 0.0334597339 * t);

        //Calculate the longitude of the perihelion of Jupiter
        double PI = CT.D2R(13.469942);

        //Calculate the periodic terms in the longitudes of the satellites
        double Sigma1 = 0.47259 * Math.Sin(2 * (l1rad - l2rad)) + -0.03478 * Math.Sin(pi3 - pi4) + 0.01081 * Math.Sin(l2rad - 2 * l3rad + pi3) + 0.00738 * Math.Sin(philambda) + 0.00713 * Math.Sin(l2rad - 2 * l3rad + pi2) + -0.00674 * Math.Sin(pi1 + pi3 - 2 * PI - 2 * G) + 0.00666 * Math.Sin(l2rad - 2 * l3rad + pi4) + 0.00445 * Math.Sin(l1rad - pi3) + -0.00354 * Math.Sin(l1rad - l2rad) + -0.00317 * Math.Sin(2 * psi - 2 * PI) + 0.00265 * Math.Sin(l1rad - pi4) + -0.00186 * Math.Sin(G) + 0.00162 * Math.Sin(pi2 - pi3) + 0.00158 * Math.Sin(4 * (l1rad - l2rad)) + -0.00155 * Math.Sin(l1rad - l3rad) + -0.00138 * Math.Sin(psi + w3rad - 2 * PI - 2 * G) + -0.00115 * Math.Sin(2 * (l1rad - 2 * l2rad + w2rad)) + 0.00089 * Math.Sin(pi2 - pi4) + 0.00085 * Math.Sin(l1rad + pi3 - 2 * PI - 2 * G) + 0.00083 * Math.Sin(w2rad - w3rad) + 0.00053 * Math.Sin(psi - w2rad);

        double Sigma2 = 1.06476 * Math.Sin(2 * (l2rad - l3rad)) + 0.04256 * Math.Sin(l1rad - 2 * l2rad + pi3) + 0.03581 * Math.Sin(l2rad - pi3) + 0.02395 * Math.Sin(l1rad - 2 * l2rad + pi4) + 0.01984 * Math.Sin(l2rad - pi4) + -0.01778 * Math.Sin(philambda) + 0.01654 * Math.Sin(l2rad - pi2) + 0.01334 * Math.Sin(l2rad - 2 * l3rad + pi2) + 0.01294 * Math.Sin(pi3 - pi4) + -0.01142 * Math.Sin(l2rad - l3rad) + -0.01057 * Math.Sin(G) + -0.00775 * Math.Sin(2 * (psi - PI)) + 0.00524 * Math.Sin(2 * (l1rad - l2rad)) + -0.00460 * Math.Sin(l1rad - l3rad) + 0.00316 * Math.Sin(psi - 2 * G + w3rad - 2 * PI) + -0.00203 * Math.Sin(pi1 + pi3 - 2 * PI - 2 * G) + 0.00146 * Math.Sin(psi - w3rad) + -0.00145 * Math.Sin(2 * G) + 0.00125 * Math.Sin(psi - w4rad) + -0.00115 * Math.Sin(l1rad - 2 * l3rad + pi3) + -0.00094 * Math.Sin(2 * (l2rad - w2rad)) + 0.00086 * Math.Sin(2 * (l1rad - 2 * l2rad + w2rad)) + -0.00086 * Math.Sin(5 * Gdash - 2 * G + CT.D2R(52.225)) + -0.00078 * Math.Sin(l2rad - l4rad) + -0.00064 * Math.Sin(3 * l3rad - 7 * l4rad + 4 * pi4) + 0.00064 * Math.Sin(pi1 - pi4) + -0.00063 * Math.Sin(l1rad - 2 * l3rad + pi4) + 0.00058 * Math.Sin(w3rad - w4rad) + 0.00056 * Math.Sin(2 * (psi - PI - G)) + 0.00056 * Math.Sin(2 * (l2rad - l4rad)) + 0.00055 * Math.Sin(2 * (l1rad - l3rad)) + 0.00052 * Math.Sin(3 * l3rad - 7 * l4rad + pi3 + 3 * pi4) + -0.00043 * Math.Sin(l1rad - pi3) + 0.00041 * Math.Sin(5 * (l2rad - l3rad)) + 0.00041 * Math.Sin(pi4 - PI) + 0.00032 * Math.Sin(w2rad - w3rad) + 0.00032 * Math.Sin(2 * (l3rad - G - PI));

        double Sigma3 = 0.16490 * Math.Sin(l3rad - pi3) + 0.09081 * Math.Sin(l3rad - pi4) + -0.06907 * Math.Sin(l2rad - l3rad) + 0.03784 * Math.Sin(pi3 - pi4) + 0.01846 * Math.Sin(2 * (l3rad - l4rad)) + -0.01340 * Math.Sin(G) + -0.01014 * Math.Sin(2 * (psi - PI)) + 0.00704 * Math.Sin(l2rad - 2 * l3rad + pi3) + -0.00620 * Math.Sin(l2rad - 2 * l3rad + pi2) + -0.00541 * Math.Sin(l3rad - l4rad) + 0.00381 * Math.Sin(l2rad - 2 * l3rad + pi4) + 0.00235 * Math.Sin(psi - w3rad) + 0.00198 * Math.Sin(psi - w4rad) + 0.00176 * Math.Sin(philambda) + 0.00130 * Math.Sin(3 * (l3rad - l4rad)) + 0.00125 * Math.Sin(l1rad - l3rad) + -0.00119 * Math.Sin(5 * Gdash - 2 * G + CT.D2R(52.225)) + 0.00109 * Math.Sin(l1rad - l2rad) + -0.00100 * Math.Sin(3 * l3rad - 7 * l4rad + 4 * pi4) + 0.00091 * Math.Sin(w3rad - w4rad) + 0.00080 * Math.Sin(3 * l3rad - 7 * l4rad + pi3 + 3 * pi4) + -0.00075 * Math.Sin(2 * l2rad - 3 * l3rad + pi3) + 0.00072 * Math.Sin(pi1 + pi3 - 2 * PI - 2 * G) + 0.00069 * Math.Sin(pi4 - PI) + -0.00058 * Math.Sin(2 * l3rad - 3 * l4rad + pi4) + -0.00057 * Math.Sin(l3rad - 2 * l4rad + pi4) + 0.00056 * Math.Sin(l3rad + pi3 - 2 * PI - 2 * G) + -0.00052 * Math.Sin(l2rad - 2 * l3rad + pi1) + -0.00050 * Math.Sin(pi2 - pi3) + 0.00048 * Math.Sin(l3rad - 2 * l4rad + pi3) + -0.00045 * Math.Sin(2 * l2rad - 3 * l3rad + pi4) + -0.00041 * Math.Sin(pi2 - pi4) + -0.00038 * Math.Sin(2 * G) + -0.00037 * Math.Sin(pi3 - pi4 + w3rad - w4rad) + -0.00032 * Math.Sin(3 * l3rad - 7 * l4rad + 2 * pi3 + 2 * pi4) + 0.00030 * Math.Sin(4 * (l3rad - l4rad)) + 0.00029 * Math.Sin(l3rad + pi4 - 2 * PI - 2 * G) + -0.00028 * Math.Sin(w3rad + psi - 2 * PI - 2 * G) + 0.00026 * Math.Sin(l3rad - PI - G) + 0.00024 * Math.Sin(l2rad - 3 * l3rad + 2 * l4rad) + 0.00021 * Math.Sin(l3rad - PI - G) + -0.00021 * Math.Sin(l3rad - pi2) + 0.00017 * Math.Sin(2 * (l3rad - pi3));

        double Sigma4 = 0.84287 * Math.Sin(l4rad - pi4) + 0.03431 * Math.Sin(pi4 - pi3) + -0.03305 * Math.Sin(2 * (psi - PI)) + -0.03211 * Math.Sin(G) + -0.01862 * Math.Sin(l4rad - pi3) + 0.01186 * Math.Sin(psi - w4rad) + 0.00623 * Math.Sin(l4rad + pi4 - 2 * G - 2 * PI) + 0.00387 * Math.Sin(2 * (l4rad - pi4)) + -0.00284 * Math.Sin(5 * Gdash - 2 * G + CT.D2R(52.225)) + -0.00234 * Math.Sin(2 * (psi - pi4)) + -0.00223 * Math.Sin(l3rad - l4rad) + -0.00208 * Math.Sin(l4rad - PI) + 0.00178 * Math.Sin(psi + w4rad - 2 * pi4) + 0.00134 * Math.Sin(pi4 - PI) + 0.00125 * Math.Sin(2 * (l4rad - G - PI)) + -0.00117 * Math.Sin(2 * G) + -0.00112 * Math.Sin(2 * (l3rad - l4rad)) + 0.00107 * Math.Sin(3 * l3rad - 7 * l4rad + 4 * pi4) + 0.00102 * Math.Sin(l4rad - G - PI) + 0.00096 * Math.Sin(2 * l4rad - psi - w4rad) + 0.00087 * Math.Sin(2 * (psi - w4rad)) + -0.00085 * Math.Sin(3 * l3rad - 7 * l4rad + pi3 + 3 * pi4) + 0.00085 * Math.Sin(l3rad - 2 * l4rad + pi4) + -0.00081 * Math.Sin(2 * (l4rad - psi)) + 0.00071 * Math.Sin(l4rad + pi4 - 2 * PI - 3 * G) + 0.00061 * Math.Sin(l1rad - l4rad) + -0.00056 * Math.Sin(psi - w3rad) + -0.00054 * Math.Sin(l3rad - 2 * l4rad + pi3) + 0.00051 * Math.Sin(l2rad - l4rad) + 0.00042 * Math.Sin(2 * (psi - G - PI)) + 0.00039 * Math.Sin(2 * (pi4 - w4rad)) + 0.00036 * Math.Sin(psi + PI - pi4 - w4rad) + 0.00035 * Math.Sin(2 * Gdash - G + CT.D2R(188.37)) + -0.00035 * Math.Sin(l4rad - pi4 + 2 * PI - 2 * psi) + -0.00032 * Math.Sin(l4rad + pi4 - 2 * PI - G) + 0.00030 * Math.Sin(2 * Gdash - 2 * G + CT.D2R(149.15)) + 0.00029 * Math.Sin(3 * l3rad - 7 * l4rad + 2 * pi3 + 2 * pi4) + 0.00028 * Math.Sin(l4rad - pi4 + 2 * psi - 2 * PI) + -0.00028 * Math.Sin(2 * (l4rad - w4rad)) + -0.00027 * Math.Sin(pi3 - pi4 + w3rad - w4rad) + -0.00026 * Math.Sin(5 * Gdash - 3 * G + CT.D2R(188.37)) + 0.00025 * Math.Sin(w4rad - w3rad) + -0.00025 * Math.Sin(l2rad - 3 * l3rad + 2 * l4rad) + -0.00023 * Math.Sin(3 * (l3rad - l4rad)) + 0.00021 * Math.Sin(2 * l4rad - 2 * PI - 3 * G) + -0.00021 * Math.Sin(2 * l3rad - 3 * l4rad + pi4) + 0.00019 * Math.Sin(l4rad - pi4 - G) + -0.00019 * Math.Sin(2 * l4rad - pi3 - pi4) + -0.00018 * Math.Sin(l4rad - pi4 + G) + -0.00016 * Math.Sin(l4rad + pi3 - 2 * PI - 2 * G);

        details.Satellite1.MeanLongitude = CT.M360(l1);
        details.Satellite1.TrueLongitude = CT.M360(l1 + Sigma1);
        double L1 = CT.D2R(details.Satellite1.TrueLongitude);

        details.Satellite2.MeanLongitude = CT.M360(l2);
        details.Satellite2.TrueLongitude = CT.M360(l2 + Sigma2);
        double L2 = CT.D2R(details.Satellite2.TrueLongitude);

        details.Satellite3.MeanLongitude = CT.M360(l3);
        details.Satellite3.TrueLongitude = CT.M360(l3 + Sigma3);
        double L3 = CT.D2R(details.Satellite3.TrueLongitude);

        details.Satellite4.MeanLongitude = CT.M360(l4);
        details.Satellite4.TrueLongitude = CT.M360(l4 + Sigma4);
        double L4 = CT.D2R(details.Satellite4.TrueLongitude);

        //Calculate the periodic terms in the latitudes of the satellites
        double B1 = Math.Atan(0.0006393 * Math.Sin(L1 - w1rad) + 0.0001825 * Math.Sin(L1 - w2rad) + 0.0000329 * Math.Sin(L1 - w3rad) + -0.0000311 * Math.Sin(L1 - psi) + 0.0000093 * Math.Sin(L1 - w4rad) + 0.0000075 * Math.Sin(3 * L1 - 4 * l2rad - 1.9927 * Sigma1 + w2rad) + 0.0000046 * Math.Sin(L1 + psi - 2 * PI - 2 * G));

        details.Satellite1.EquatorialLatitude = CT.R2D(B1);

        double B2 = Math.Atan(0.0081004 * Math.Sin(L2 - w2rad) + 0.0004512 * Math.Sin(L2 - w3rad) + -0.0003284 * Math.Sin(L2 - psi) + 0.0001160 * Math.Sin(L2 - w4rad) + 0.0000272 * Math.Sin(l1rad - 2 * l3rad + 1.0146 * Sigma2 + w2rad) + -0.0000144 * Math.Sin(L2 - w1rad) + 0.0000143 * Math.Sin(L2 + psi - 2 * PI - 2 * G) + 0.0000035 * Math.Sin(L2 - psi + G) + -0.0000028 * Math.Sin(l1rad - 2 * l3rad + 1.0146 * Sigma2 + w3rad));

        details.Satellite2.EquatorialLatitude = CT.R2D(B2);

        double B3 = Math.Atan(0.0032402 * Math.Sin(L3 - w3rad) + -0.0016911 * Math.Sin(L3 - psi) + 0.0006847 * Math.Sin(L3 - w4rad) + -0.0002797 * Math.Sin(L3 - w2rad) + 0.0000321 * Math.Sin(L3 + psi - 2 * PI - 2 * G) + 0.0000051 * Math.Sin(L3 - psi + G) + -0.0000045 * Math.Sin(L3 - psi - G) + -0.0000045 * Math.Sin(L3 + psi - 2 * PI) + 0.0000037 * Math.Sin(L3 + psi - 2 * PI - 3 * G) + 0.0000030 * Math.Sin(2 * l2rad - 3 * L3 + 4.03 * Sigma3 + w2rad) + -0.0000021 * Math.Sin(2 * l2rad - 3 * L3 + 4.03 * Sigma3 + w3rad));

        details.Satellite3.EquatorialLatitude = CT.R2D(B3);

        double B4 = Math.Atan(-0.0076579 * Math.Sin(L4 - psi) + 0.0044134 * Math.Sin(L4 - w4rad) + -0.0005112 * Math.Sin(L4 - w3rad) + 0.0000773 * Math.Sin(L4 + psi - 2 * PI - 2 * G) + 0.0000104 * Math.Sin(L4 - psi + G) + -0.0000102 * Math.Sin(L4 - psi - G) + 0.0000088 * Math.Sin(L4 + psi - 2 * PI - 3 * G) + -0.0000038 * Math.Sin(L4 + psi - 2 * PI - G));

        details.Satellite4.EquatorialLatitude = CT.R2D(B4);

        //Calculate the periodic terms for the radius vector
        details.Satellite1.r = 5.90569 * (1 + (-0.0041339 * Math.Cos(2 * (l1rad - l2rad)) + -0.0000387 * Math.Cos(l1rad - pi3) + -0.0000214 * Math.Cos(l1rad - pi4) + 0.0000170 * Math.Cos(l1rad - l2rad) + -0.0000131 * Math.Cos(4 * (l1rad - l2rad)) + 0.0000106 * Math.Cos(l1rad - l3rad) + -0.0000066 * Math.Cos(l1rad + pi3 - 2 * PI - 2 * G)));

        details.Satellite2.r = 9.39657 * (1 + (0.0093848 * Math.Cos(l1rad - l2rad) + -0.0003116 * Math.Cos(l2rad - pi3) + -0.0001744 * Math.Cos(l2rad - pi4) + -0.0001442 * Math.Cos(l2rad - pi2) + 0.0000553 * Math.Cos(l2rad - l3rad) + 0.0000523 * Math.Cos(l1rad - l3rad) + -0.0000290 * Math.Cos(2 * (l1rad - l2rad)) + 0.0000164 * Math.Cos(2 * (l2rad - w2rad)) + 0.0000107 * Math.Cos(l1rad - 2 * l3rad + pi3) + -0.0000102 * Math.Cos(l2rad - pi1) + -0.0000091 * Math.Cos(2 * (l1rad - l3rad))));

        details.Satellite3.r = 14.98832 * (1 + (-0.0014388 * Math.Cos(l3rad - pi3) + -0.0007919 * Math.Cos(l3rad - pi4) + 0.0006342 * Math.Cos(l2rad - l3rad) + -0.0001761 * Math.Cos(2 * (l3rad - l4rad)) + 0.0000294 * Math.Cos(l3rad - l4rad) + -0.0000156 * Math.Cos(3 * (l3rad - l4rad)) + 0.0000156 * Math.Cos(l1rad - l3rad) + -0.0000153 * Math.Cos(l1rad - l2rad) + 0.0000070 * Math.Cos(2 * l2rad - 3 * l3rad + pi3) + -0.0000051 * Math.Cos(l3rad + pi3 - 2 * PI - 2 * G)));

        details.Satellite4.r = 26.36273 * (1 + (-0.0073546 * Math.Cos(l4rad - pi4) + 0.0001621 * Math.Cos(l4rad - pi3) + 0.0000974 * Math.Cos(l3rad - l4rad) + -0.0000543 * Math.Cos(l4rad + pi4 - 2 * PI - 2 * G) + -0.0000271 * Math.Cos(2 * (l4rad - pi4)) + 0.0000182 * Math.Cos(l4rad - PI) + 0.0000177 * Math.Cos(2 * (l3rad - l4rad)) + -0.0000167 * Math.Cos(2 * l4rad - psi - w4rad) + 0.0000167 * Math.Cos(psi - w4rad) + -0.0000155 * Math.Cos(2 * (l4rad - PI - G)) + 0.0000142 * Math.Cos(2 * (l4rad - psi)) + 0.0000105 * Math.Cos(l1rad - l4rad) + 0.0000092 * Math.Cos(l2rad - l4rad) + -0.0000089 * Math.Cos(l4rad - PI - G) + -0.0000062 * Math.Cos(l4rad + pi4 - 2 * PI - 3 * G) + 0.0000048 * Math.Cos(2 * (l4rad - w4rad))));



        //Calculate T0
        double T0 = (JD - 2433282.423) / 36525;

        //Calculate the precession in longitude from Epoch B1950 to the date
        double P = CT.D2R(1.3966626 * T0 + 0.0003088 * T0 * T0);

        //Add it to L1 - L4 and psi
        L1 += P;
        details.Satellite1.TropicalLongitude = CT.M360(CT.R2D(L1));
        L2 += P;
        details.Satellite2.TropicalLongitude = CT.M360(CT.R2D(L2));
        L3 += P;
        details.Satellite3.TropicalLongitude = CT.M360(CT.R2D(L3));
        L4 += P;
        details.Satellite4.TropicalLongitude = CT.M360(CT.R2D(L4));
        psi += P;

        //Calculate the inclination of Jupiter's axis of rotation on the orbital plane
        double T    = (JD - 2415020.5) / 36525;
        double I    = 3.120262 + 0.0006 * T;
        double Irad = CT.D2R(I);

        double X1 = details.Satellite1.r * Math.Cos(L1 - psi) * Math.Cos(B1);
        double X2 = details.Satellite2.r * Math.Cos(L2 - psi) * Math.Cos(B2);
        double X3 = details.Satellite3.r * Math.Cos(L3 - psi) * Math.Cos(B3);
        double X4 = details.Satellite4.r * Math.Cos(L4 - psi) * Math.Cos(B4);
        double X5 = 0;

        double Y1 = details.Satellite1.r * Math.Sin(L1 - psi) * Math.Cos(B1);
        double Y2 = details.Satellite2.r * Math.Sin(L2 - psi) * Math.Cos(B2);
        double Y3 = details.Satellite3.r * Math.Sin(L3 - psi) * Math.Cos(B3);
        double Y4 = details.Satellite4.r * Math.Sin(L4 - psi) * Math.Cos(B4);
        double Y5 = 0;

        double Z1 = details.Satellite1.r * Math.Sin(B1);
        double Z2 = details.Satellite2.r * Math.Sin(B2);
        double Z3 = details.Satellite3.r * Math.Sin(B3);
        double Z4 = details.Satellite4.r * Math.Sin(B4);
        double Z5 = 1;

        //Now do the rotations, first for the ficticious 5th satellite, so that we can calculate D
        double omega = CT.D2R(EPO.JupiterLongitudeAscendingNode(JD));
        double i     = CT.D2R(EPO.JupiterInclination(JD));
        double A6    = 0;
        double B6    = 0;
        double C6    = 0;
        C3D    north = new C3D();

        double[] abc = Rotations(X5, Y5, Z5, Irad, psi, i, omega, lambda0, beta0, north);

        A6 = abc[0];
        B6 = abc[1];
        C6 = abc[2];

        double D = Math.Atan2(A6, C6);

        //Now calculate the values for satellite 1

        abc = Rotations(X1, Y1, Z1, Irad, psi, i, omega, lambda0, beta0, details.Satellite1.EclipticRectangularCoordinates);

        A6 = abc[0];
        B6 = abc[1];
        C6 = abc[2];

        details.Satellite1.TrueRectangularCoordinates.X = A6 * Math.Cos(D) - C6 * Math.Sin(D);
        details.Satellite1.TrueRectangularCoordinates.Y = A6 * Math.Sin(D) + C6 * Math.Cos(D);
        details.Satellite1.TrueRectangularCoordinates.Z = B6;

        //Now calculate the values for satellite 2
        abc = Rotations(X2, Y2, Z2, Irad, psi, i, omega, lambda0, beta0, details.Satellite2.EclipticRectangularCoordinates);

        A6 = abc[0];
        B6 = abc[1];
        C6 = abc[2];


        details.Satellite2.TrueRectangularCoordinates.X = A6 * Math.Cos(D) - C6 * Math.Sin(D);
        details.Satellite2.TrueRectangularCoordinates.Y = A6 * Math.Sin(D) + C6 * Math.Cos(D);
        details.Satellite2.TrueRectangularCoordinates.Z = B6;

        //Now calculate the values for satellite 3
        abc = Rotations(X3, Y3, Z3, Irad, psi, i, omega, lambda0, beta0, details.Satellite3.EclipticRectangularCoordinates);
        A6  = abc[0];
        B6  = abc[1];
        C6  = abc[2];

        details.Satellite3.TrueRectangularCoordinates.X = A6 * Math.Cos(D) - C6 * Math.Sin(D);
        details.Satellite3.TrueRectangularCoordinates.Y = A6 * Math.Sin(D) + C6 * Math.Cos(D);
        details.Satellite3.TrueRectangularCoordinates.Z = B6;

        //And finally for satellite 4
        abc = Rotations(X4, Y4, Z4, Irad, psi, i, omega, lambda0, beta0, details.Satellite4.EclipticRectangularCoordinates);
        A6  = abc[0];
        B6  = abc[1];
        C6  = abc[2];

        details.Satellite4.TrueRectangularCoordinates.X = A6 * Math.Cos(D) - C6 * Math.Sin(D);
        details.Satellite4.TrueRectangularCoordinates.Y = A6 * Math.Sin(D) + C6 * Math.Cos(D);
        details.Satellite4.TrueRectangularCoordinates.Z = B6;

        //apply the differential light-time correction
        details.Satellite1.ApparentRectangularCoordinates.X = details.Satellite1.TrueRectangularCoordinates.X + Math.Abs(details.Satellite1.TrueRectangularCoordinates.Z) / 17295 * Math.Sqrt(1 - (details.Satellite1.TrueRectangularCoordinates.X / details.Satellite1.r) * (details.Satellite1.TrueRectangularCoordinates.X / details.Satellite1.r));
        details.Satellite1.ApparentRectangularCoordinates.Y = details.Satellite1.TrueRectangularCoordinates.Y;
        details.Satellite1.ApparentRectangularCoordinates.Z = details.Satellite1.TrueRectangularCoordinates.Z;

        details.Satellite2.ApparentRectangularCoordinates.X = details.Satellite2.TrueRectangularCoordinates.X + Math.Abs(details.Satellite2.TrueRectangularCoordinates.Z) / 21819 * Math.Sqrt(1 - (details.Satellite2.TrueRectangularCoordinates.X / details.Satellite2.r) * (details.Satellite2.TrueRectangularCoordinates.X / details.Satellite2.r));
        details.Satellite2.ApparentRectangularCoordinates.Y = details.Satellite2.TrueRectangularCoordinates.Y;
        details.Satellite2.ApparentRectangularCoordinates.Z = details.Satellite2.TrueRectangularCoordinates.Z;

        details.Satellite3.ApparentRectangularCoordinates.X = details.Satellite3.TrueRectangularCoordinates.X + Math.Abs(details.Satellite3.TrueRectangularCoordinates.Z) / 27558 * Math.Sqrt(1 - (details.Satellite3.TrueRectangularCoordinates.X / details.Satellite3.r) * (details.Satellite3.TrueRectangularCoordinates.X / details.Satellite3.r));
        details.Satellite3.ApparentRectangularCoordinates.Y = details.Satellite3.TrueRectangularCoordinates.Y;
        details.Satellite3.ApparentRectangularCoordinates.Z = details.Satellite3.TrueRectangularCoordinates.Z;

        details.Satellite4.ApparentRectangularCoordinates.X = details.Satellite4.TrueRectangularCoordinates.X + Math.Abs(details.Satellite4.TrueRectangularCoordinates.Z) / 36548 * Math.Sqrt(1 - (details.Satellite4.TrueRectangularCoordinates.X / details.Satellite4.r) * (details.Satellite4.TrueRectangularCoordinates.X / details.Satellite4.r));
        details.Satellite4.ApparentRectangularCoordinates.Y = details.Satellite4.TrueRectangularCoordinates.Y;
        details.Satellite4.ApparentRectangularCoordinates.Z = details.Satellite4.TrueRectangularCoordinates.Z;

        //apply the perspective effect correction
        double W = DELTA / (DELTA + details.Satellite1.TrueRectangularCoordinates.Z / 2095);

        details.Satellite1.ApparentRectangularCoordinates.X *= W;
        details.Satellite1.ApparentRectangularCoordinates.Y *= W;

        W = DELTA / (DELTA + details.Satellite2.TrueRectangularCoordinates.Z / 2095);
        details.Satellite2.ApparentRectangularCoordinates.X *= W;
        details.Satellite2.ApparentRectangularCoordinates.Y *= W;

        W = DELTA / (DELTA + details.Satellite3.TrueRectangularCoordinates.Z / 2095);
        details.Satellite3.ApparentRectangularCoordinates.X *= W;
        details.Satellite3.ApparentRectangularCoordinates.Y *= W;

        W = DELTA / (DELTA + details.Satellite4.TrueRectangularCoordinates.Z / 2095);
        details.Satellite4.ApparentRectangularCoordinates.X *= W;
        details.Satellite4.ApparentRectangularCoordinates.Y *= W;

        return(details);
    }
Exemple #24
0
        public bool Write(Chunked model, Stream output, bool keepOpen = false)
        {
            culture.NumberFormat.NumberDecimalSeparator          = ".";
            System.Threading.Thread.CurrentThread.CurrentCulture = culture;
            IChunk chunk = model.FindNextChunk("lksm").Value;

            if (chunk == null)
            {
                return(false);
            }
            lksm skeleton = (lksm)chunk;

            short[]         hierarchy                = (short[])skeleton.Hierarchy.Clone();
            HashSet <short> weightedParNodes         = new HashSet <short>();
            Dictionary <int, HTLC.ClothNode> nodeMap = new Dictionary <int, HTLC.ClothNode>();
            HTLC cloth = model.FindNextChunk("HTLC").Value as HTLC;

            if (cloth != null)
            {
                uint clothIndex = 0;
                foreach (HTLC.ClothNode[] nodeCollection in cloth.Nodes)
                {
                    if (nodeCollection == null)
                    {
                        continue;
                    }
                    int nodeIndex = 0;
                    foreach (HTLC.ClothNode node in nodeCollection)
                    {
                        int parentRaw = node.VerticalParent;
                        if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex) &&
                            cloth.NodeBones[clothIndex].ContainsKey(parentRaw))
                        {
                            // good code:
                            if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                            {
                                hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = cloth.NodeBones[clothIndex][parentRaw];
                                if (cloth.NodeBones[clothIndex][parentRaw] == -1)
                                {
                                    HTLC.ClothNodeWeight weightedBone = node.Bones.Aggregate((i1, i2) => i1.Weight > i2.Weight ? i1 : i2);
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = weightedBone.Bone;
                                    weightedParNodes.Add(cloth.NodeBones[clothIndex][nodeIndex]);
                                }
                            }
                            // else: on subskele
                            // todo: add subskelebones?
                        }
                        else
                        {
                            if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex))    // if on main skele
                            // good code:
                            {
                                if (cloth.NodeBones[clothIndex][nodeIndex] != -1)
                                {
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = -1;
                                    HTLC.ClothNodeWeight weightedBone = node.Bones.Aggregate((i1, i2) => i1.Weight > i2.Weight ? i1 : i2);
                                    hierarchy[cloth.NodeBones[clothIndex][nodeIndex]] = weightedBone.Bone;
                                    weightedParNodes.Add(cloth.NodeBones[clothIndex][nodeIndex]);
                                }
                                // else: on subskele
                                // todo: add subskelebones?
                            }
                        }
                        if (cloth.NodeBones[clothIndex].ContainsKey(nodeIndex))
                        {
                            // good code:
                            nodeMap[cloth.NodeBones[clothIndex][nodeIndex]] = node;
                        }
                        nodeIndex++;
                    }
                    clothIndex++;
                }
            }
            using (StreamWriter writer = new StreamWriter(output, Encoding.Default, 512, keepOpen)) {
                writer.WriteLine("{0}", skeleton.Data.bonesAbs);
                writer.WriteLine("version 1");
                writer.WriteLine("nodes");
                for (int i = 0; i < skeleton.Data.bonesAbs; ++i)
                {
                    writer.WriteLine("{0} \"bone_{1:X4}\" {2}", i, skeleton.IDs[i], hierarchy[i]);
                }
                writer.WriteLine("end");
                writer.WriteLine("skeleton");
                writer.WriteLine("time 0");
                for (int i = 0; i < skeleton.Data.bonesAbs; ++i)
                {
                    Matrix3x4    bone  = skeleton.Matrices34Inverted[i];
                    Quaternion3D quat  = new Quaternion3D(bone[0, 3], bone[0, 0], bone[0, 1], bone[0, 2]);
                    Vector3D     rot   = C3D.ToEulerAngles(quat);
                    Vector3      scale = new Vector3(bone[1, 0], bone[1, 1], bone[1, 2]);
                    Vector3      pos   = new Vector3(bone[2, 0], bone[2, 1], bone[2, 2]);
                    if (nodeMap.ContainsKey(i))
                    {
                        HTLC.ClothNode thisNode = nodeMap[i];
                        if (weightedParNodes.Contains((short)i))
                        {
                            Vector3 pos2 = GetGlobalPos(skeleton.Matrices34Inverted, hierarchy[i], hierarchy);
                            pos.X = thisNode.X - pos2.X;
                            pos.Y = thisNode.Y - pos2.Y;
                            pos.Z = thisNode.Z - pos2.Z;
                        }
                        else if (nodeMap.ContainsKey(hierarchy[i]))
                        {
                            HTLC.ClothNode parentNode = nodeMap[hierarchy[i]];
                            pos.X = thisNode.X - parentNode.X;
                            pos.Y = thisNode.Y - parentNode.Y;
                            pos.Z = thisNode.Z - parentNode.Z;
                        }
                        else
                        {
                            pos.X = thisNode.X;
                            pos.Y = thisNode.Y;
                            pos.Z = thisNode.Z;
                        }
                    }
                    if (rot.X == -3.14159274f && rot.Y == 0 && rot.Z == 0)
                    {
                        rot = new Vector3D(0, 3.14159274f, 3.14159274f); // effectively the same but you know, eulers.
                    }
                    writer.WriteLine(String.Format(CultureInfo.InvariantCulture, "{0}  {1:0.000000} {2:0.000000} {3:0.000000}  {4:0.000000} {5:0.000000} {6:0.000000}  {7:0.000000} {8:0.000000} {9:0.000000}", i, pos.X, pos.Y, pos.Z, rot.X, rot.Y, rot.Z, scale.X, scale.Y, scale.Z));
                }
            }
            return(true);
        }