public static void ConsistentWithMatrixRotationShiftAndScaleTest() => TrafoTesting.GenericTest(rnd => { var trans = rnd.UniformV3d() * 10; var axis = rnd.UniformV3dDirection(); var angle = rnd.UniformDouble() * Constant.PiTimesTwo; var scale = rnd.UniformDouble() * 5; var m = M44d.Translation(trans) * M44d.Rotation(axis, angle) * M44d.Scale(scale, scale, scale); var e = new Similarity3d(scale, Rot3d.Rotation(axis, angle), trans); var p = rnd.UniformV3d() * rnd.UniformInt(1000); var res = m.TransformPos(p); var res2 = e.TransformPos(p); TrafoTesting.AreEqual(res, res2); });
/// <summary> /// Build a geometry transformation from the given parameters as specified in Transform /// http://gun.teipir.gr/VRML-amgem/spec/part1/nodesRef.html#Transform /// </summary> public static Trafo3d BuildVrmlGeometryTrafo(V3d center, V4d rotation, V3d scale, V4d scaleOrientation, V3d translation) { // create composite trafo (naming taken from vrml97 spec) M44d C = M44d.Translation(center), Ci = M44d.Translation(-center); M44d SR = M44d.Rotation(scaleOrientation.XYZ, scaleOrientation.W), SRi = M44d.Rotation(scaleOrientation.XYZ, -scaleOrientation.W); M44d T = M44d.Translation(translation), Ti = M44d.Translation(-translation); //if (m_aveCompatibilityMode) r.W = -r.W; M44d R = M44d.Rotation(rotation.XYZ, rotation.W), Ri = M44d.Rotation(rotation.XYZ, -rotation.W); // in case some axis scales by 0 the best thing for the inverse scale is also 0 var si = new V3d(scale.X.IsTiny() ? 0 : 1 / scale.X, scale.Y.IsTiny() ? 0 : 1 / scale.Y, scale.Z.IsTiny() ? 0 : 1 / scale.Z); M44d S = M44d.Scale(scale), Si = M44d.Scale(si); return(new Trafo3d( T * C * R * SR * S * SRi * Ci, C * SR * Si * SRi * Ri * Ci * Ti)); }
public ISg SetParameters(AbstractTraversal t) { if (!m_isInitialized) { var info = m_instance.PatchFileInfo; var bb = m_instance.PositionsType == PositionsType.V3dPositions ? info.LocalBoundingBox : info.LocalBoundingBox2d; var patch = new StreamingJob( () => { //TaskCombinators.Delay(100); //do importer logic here var patchVg = m_instance.LoadingStrategy.Load(m_instance.PatchFileInfo, m_instance.PatchFilePath, m_instance.PositionsType, true, true, true, m_instance.MaxTriangleSize); if (patchVg == null) { return(EmptyLeaf.Singleton); } var lodColor = Patch.GetLodColor(m_instance.Level, m_instance.MaxLevel); patchVg["LodColor"] = lodColor; for (int i = 0; i < patchVg.Textures.Count; i++) { var key = patchVg.Textures.Keys.ToList()[i]; var source = patchVg.Textures[key].Convertible; Convertible target = null; if (t.Renderer is SlimDx9Renderer) { target = SlimDx9TextureConvertible.Create( new SlimDx9TextureConvertible.SlimDx9TextureParameters() { //SlimDx9Format = SlimDX.Direct3D9.Format., // .Dxt5, Pool = SlimDX.Direct3D9.Pool.Default }); source.ConvertInto(target); } else { // nothing todo in slimdx10renderer (this just loads the texture on demand) // fix this if you are fed up with framerate hick ups target = source; } patchVg.Textures[key] = new Texture(target); } lock (asyncLock) { m_asyncTextures = patchVg.Textures; } return(patchVg.ToVertexGeometrySet()); }, bb, m_instance.MaxLevel - m_instance.Level, true); patch.DestructSideEffects = DisposeSideEffects; var placeHolder = Primitives.WireBox(bb, C4b.Red).ToVertexGeometrySet(); m_returnISg = new AsyncStreamingNode(patch, placeHolder) { DebugName = Path.GetFileName(m_instance.PatchFilePath), }; var local2Global = m_instance.PatchFileInfo.GetLocal2Global(m_instance.PositionsType); if (m_instance.InvertZ) { local2Global = M44d.Scale(1, 1, -1) * local2Global; } var global2Local = local2Global.Inverse; m_returnISg = Rsg.Apply(Rsg.Attribute.PushTrafo3d(new Trafo3d(local2Global, global2Local)), m_returnISg); m_isInitialized = true; } return(m_returnISg); }
public void MatrixInverseTest(int rounds, int count, bool doLuM = true, bool doLuV = true, bool doLu2 = true, bool doGj2 = false, bool doQrI = true, bool doQr2 = true) { bool doMul = true; double luEpsilon = 1e-5; double qrEpsilon = 4e-5; Test.Begin("matrix inverse tests"); Report.Line("epsilon for lu tests: {0:e0}", luEpsilon); Report.Line("epsilon for qr tests: {0:e0}", qrEpsilon); bool showWorst = true; bool showTypes = true; var rnd = new RandomSystem(19680713); var tc = 4; var typeStatsOpt = Stats <M44d> .ComputeCountMaxMean; Stats <M44d>[] luiTypeStats = new Stats <M44d> [tc].Set(typeStatsOpt); Stats <M44d>[] lumTypeStats = new Stats <M44d> [tc].Set(typeStatsOpt); Stats <M44d>[] luvTypeStats = new Stats <M44d> [tc].Set(typeStatsOpt); Stats <M44d>[] lu2TypeStats = new Stats <M44d> [tc].Set(typeStatsOpt); Stats <M44d>[] gj2TypeStats = new Stats <M44d> [tc].Set(typeStatsOpt); Stats <M44d>[] qriTypeStats = new Stats <M44d> [tc].Set(typeStatsOpt); Stats <M44d>[] qr2TypeStats = new Stats <M44d> [tc].Set(typeStatsOpt); string[] typenames = new string[] { "Rotation", "Scale", "Translation", "Mixed" }; var histoStatsOpt = StatsOptions.MaxMean; var luiHistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt); var lumHistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt); var luvHistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt); var lu2HistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt); var gj2HistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt); var qriHistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt); var qr2HistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt); M44d[] mats = new M44d[count]; M44d[] luis = new M44d[count]; M44d[] lums = new M44d[count]; M44d[] luvs = new M44d[count]; M44d[] lu2s = new M44d[count]; M44d[] gj2s = new M44d[count]; M44d[] qris = new M44d[count]; M44d[] qr2s = new M44d[count]; int[] types = new int[count].SetByIndex(i => - 1); bool failedLuM = false, failedLuV = false, failedLu2 = false; bool failedQr2 = false; var chainStats = new Stats <bool>(StatsOptions.MaxMean); for (int j = 0; j < rounds; j++) { using (Report.JobTimed("creating {0} matrices round {1} of {2}", count, j + 1, rounds)) for (int i = 0; i < count; i++) { M44d mat = M44d.Identity; var chainLength = 0; do { int type = rnd.UniformInt(3); if (types[i] == -1) { types[i] = type; } else if (types[i] != type) { types[i] = 3; //mixed type } switch (type) { case 0: V3d axis = V3d.Zero; double squaredLength = 0.0; do { axis = new V3d(2 * rnd.UniformDoubleFullClosed() - 1, 2 * rnd.UniformDoubleFullClosed() - 1, 2 * rnd.UniformDoubleFullClosed() - 1); squaredLength = axis.LengthSquared; }while (squaredLength == 0); axis *= 1.0 / Fun.Sqrt(squaredLength); double alpha = 2 * Constant.Pi * rnd.UniformDoubleFull() - Constant.Pi; M44d rot = M44d.Rotation(axis, alpha); mat = rot * mat; chainLength++; break; case 1: var s0 = rnd.UniformDouble() < 0.5 ? -4.0 : 4.0; var s1 = rnd.UniformDouble() < 0.5 ? -4.0 : 4.0; var s2 = rnd.UniformDouble() < 0.5 ? -4.0 : 4.0; M44d scale = M44d.Scale( s0 * (1.0 - rnd.UniformDoubleFull()), s1 * (1.0 - rnd.UniformDoubleFull()), s2 * (1.0 - rnd.UniformDoubleFull())); mat = scale * mat; chainLength++; break; case 2: M44d shift = M44d.Translation( 32 * rnd.UniformDoubleFullClosed() - 16, 32 * rnd.UniformDoubleFullClosed() - 16, 32 * rnd.UniformDoubleFullClosed() - 16); mat = shift * mat; chainLength++; break; default: break; } }while (rnd.UniformDouble() > 0.25); mats[i] = mat; chainStats.Add(chainLength); } if (doQr2) { using (Report.JobTimed("qr [,] factorization")) for (int i = 0; i < count; i++) { qr2s[i] = mats[i].QrInverse2(); } } if (doQrI) { using (Report.JobTimed("qr factorization")) for (int i = 0; i < count; i++) { qris[i] = mats[i].QrInverse(); } } if (doGj2) { using (Report.JobTimed("gauss jordan")) for (int i = 0; i < count; i++) { gj2s[i] = mats[i].NumericallyInstableGjInverse2(); } } if (doLu2) { using (Report.JobTimed("lu [,] factorization")) for (int i = 0; i < count; i++) { lu2s[i] = mats[i].LuInverse2(); } } if (doLuV) { using (Report.JobTimed("lu vector solve factorization")) for (int i = 0; i < count; i++) { luvs[i] = mats[i].LuInverseV(); } } if (doLuM) { using (Report.JobTimed("lu matrix solve factorization")) for (int i = 0; i < count; i++) { lums[i] = mats[i].LuInverseM(); } } using (Report.JobTimed("lu factorization")) for (int i = 0; i < count; i++) { luis[i] = mats[i].LuInverse(); } Test.Begin("analysis"); for (int i = 0; i < count; i++) { M44d luid = mats[i] * luis[i]; double plErr = M44d.DistanceMax(luid, M44d.Identity); Test.IsTrue(plErr < luEpsilon); luiHistoStats.AddLog10Hist(plErr, mats[i]); luiTypeStats[types[i]].Add(plErr); if (doMul) { var m0 = new Matrix <double>((double[])mats[i], 4, 4); var m1 = new Matrix <double>((double[])luis[i], 4, 4); var id = m0.Multiply(m1); double deltaErr = M44d.Distance1(luid, new M44d(id.Data)); Test.IsTrue(deltaErr == 0.0); } if (doLuM) { M44d msid = mats[i] * lums[i]; double error = M44d.DistanceMax(msid, M44d.Identity); lumHistoStats.AddLog10Hist(error, mats[i]); lumTypeStats[types[i]].Add(error); double deltaErr = M44d.Distance1(luis[i], lums[i]); if (!Test.IsTrue(deltaErr == 0.0)) { failedLuM = true; } } if (doLuV) { M44d vsid = mats[i] * luvs[i]; double error = M44d.DistanceMax(vsid, M44d.Identity); luvHistoStats.AddLog10Hist(error, mats[i]); luvTypeStats[types[i]].Add(error); double deltaErr = M44d.Distance1(luis[i], luvs[i]); if (!Test.IsTrue(deltaErr == 0.0)) { failedLuV = true; } } if (doLu2) { M44d a2id = mats[i] * lu2s[i]; double error = M44d.DistanceMax(a2id, M44d.Identity); lu2HistoStats.AddLog10Hist(error, mats[i]); lu2TypeStats[types[i]].Add(error); double deltaErr = M44d.Distance1(luis[i], lu2s[i]); if (!Test.IsTrue(deltaErr == 0.0)) { failedLu2 = true; } } if (doGj2) { M44d gjid = mats[i] * gj2s[i]; double error = M44d.DistanceMax(gjid, M44d.Identity); gj2HistoStats.AddLog10Hist(error, mats[i]); gj2TypeStats[types[i]].Add(error); } if (doQrI) { M44d qrid = mats[i] * qris[i]; double error = M44d.DistanceMax(qrid, M44d.Identity); qriHistoStats.AddLog10Hist(error, mats[i]); qriTypeStats[types[i]].Add(error); Test.IsTrue(error < qrEpsilon); } if (doQr2) { M44d qrid = mats[i] * qr2s[i]; double error = M44d.DistanceMax(qrid, M44d.Identity); qr2HistoStats.AddLog10Hist(error, mats[i]); qr2TypeStats[types[i]].Add(error); double deltaErr = M44d.Distance1(qris[i], qr2s[i]); if (!Test.IsTrue(deltaErr == 0.0)) { failedQr2 = true; } } } Test.End(); } Report.Value("matrix chain lengths", chainStats); Report.Value("lu factorization error", luiHistoStats.Stats); if (showTypes) { for (int ti = 0; ti < tc; ti++) { Report.Value("lu " + typenames[ti] + " matrix factorization error", luiTypeStats[ti]); } } Report.Value("lu factorization log error histogram", luiHistoStats.Histogram); if (showWorst) { using (Report.Job("worst matrix")) WriteMat(luiHistoStats.Stats.MaxData); using (Report.Job("worst inverse")) WriteMat(luiHistoStats.Stats.MaxData.LuInverse()); using (Report.Job("worst result")) WriteMat(luiHistoStats.Stats.MaxData * luiHistoStats.Stats.MaxData.LuInverse()); } if (failedLuM) { Report.Value("lu matrix solve factorization error", lumHistoStats.Stats); if (showTypes) { for (int ti = 0; ti < tc; ti++) { Report.Value("lu matrix solve " + typenames[ti] + " matrix factorization error", lumTypeStats[ti]); } } Report.Value("lu matrix solve factorization log error histogram", lumHistoStats.Histogram); if (showWorst) { using (Report.Job("worst matrix")) WriteMat(lumHistoStats.Stats.MaxData); using (Report.Job("worst inverse")) WriteMat(lumHistoStats.Stats.MaxData.LuInverseM()); using (Report.Job("worst result")) WriteMat(lumHistoStats.Stats.MaxData * lumHistoStats.Stats.MaxData.LuInverseM()); } } if (failedLuV) { Report.Value("lu vector solve factorization error", luvHistoStats.Stats); if (showTypes) { for (int ti = 0; ti < tc; ti++) { Report.Value("lu vector solve " + typenames[ti] + " matrix factorization error", luvTypeStats[ti]); } } Report.Value("lu vector solve factorization log error histogram", luvHistoStats.Histogram); if (showWorst) { using (Report.Job("worst matrix")) WriteMat(luvHistoStats.Stats.MaxData); using (Report.Job("worst inverse")) WriteMat(luvHistoStats.Stats.MaxData.LuInverseV()); using (Report.Job("worst result")) WriteMat(luvHistoStats.Stats.MaxData * luvHistoStats.Stats.MaxData.LuInverseV()); } } if (failedLu2) { Report.Value("lu [,] factorization error", lu2HistoStats.Stats); if (showTypes) { for (int ti = 0; ti < tc; ti++) { Report.Value("lu [,] " + typenames[ti] + " matrix factorization error", lu2TypeStats[ti]); } } Report.Value("lu [,] factorization log error histogram", lu2HistoStats.Histogram); if (showWorst) { using (Report.Job("worst matrix")) WriteMat(lu2HistoStats.Stats.MaxData); using (Report.Job("worst inverse")) WriteMat(lu2HistoStats.Stats.MaxData.LuInverse2()); using (Report.Job("worst result")) WriteMat(lu2HistoStats.Stats.MaxData * lu2HistoStats.Stats.MaxData.LuInverse2()); } } if (doGj2) { Report.Value("gauss jordan error", gj2HistoStats.Stats); if (showTypes) { for (int ti = 0; ti < tc; ti++) { Report.Value("gj " + typenames[ti] + " matrix factorization error", gj2TypeStats[ti]); } } Report.Value("gauss jordan log error histogram", gj2HistoStats.Histogram); if (showWorst) { using (Report.Job("worst matrix")) WriteMat(gj2HistoStats.Stats.MaxData); using (Report.Job("worst inverse")) WriteMat(gj2HistoStats.Stats.MaxData.NumericallyInstableGjInverse2()); using (Report.Job("worst result")) WriteMat(gj2HistoStats.Stats.MaxData * gj2HistoStats.Stats.MaxData.NumericallyInstableGjInverse2()); } } if (doQrI) { Report.Value("qr factorization error", qr2HistoStats.Stats); if (showTypes) { for (int ti = 0; ti < tc; ti++) { Report.Value("qr " + typenames[ti] + " matrix factorization error", qriTypeStats[ti]); } } Report.Value("qr factorization log error histogram", qriHistoStats.Histogram); if (showWorst) { using (Report.Job("worst matrix")) WriteMat(qriHistoStats.Stats.MaxData); using (Report.Job("worst inverse")) WriteMat(qriHistoStats.Stats.MaxData.QrInverse()); using (Report.Job("worst result")) WriteMat(qriHistoStats.Stats.MaxData * qriHistoStats.Stats.MaxData.QrInverse()); } } if (failedQr2) { Report.Value("qr [,] factorization error", qr2HistoStats.Stats); if (showTypes) { for (int ti = 0; ti < tc; ti++) { Report.Value("qr [,] " + typenames[ti] + " matrix factorization error", qr2TypeStats[ti]); } } Report.Value("qr [,] factorization log error histogram", qr2HistoStats.Histogram); if (showWorst) { using (Report.Job("worst matrix")) WriteMat(qr2HistoStats.Stats.MaxData); using (Report.Job("worst inverse")) WriteMat(qr2HistoStats.Stats.MaxData.QrInverse2()); using (Report.Job("worst result")) WriteMat(qr2HistoStats.Stats.MaxData * qr2HistoStats.Stats.MaxData.QrInverse2()); } } Test.End(); }