/// <summary> /// Computes from a <see cref="V3f"/> point (origin) and /// a <see cref="V3f"/> normal the transformation matrix /// and its inverse. /// </summary> /// <param name="origin">The point which will become the new origin.</param> /// <param name="normal">The normal vector of the new ground plane.</param> /// <param name="local2global">A <see cref="M44f"/>The trafo from local to global system.</param> /// <param name="global2local">A <see cref="M44f"/>The trafofrom global to local system.</param> public static void NormalFrame(V3f origin, V3f normal, out M44f local2global, out M44f global2local ) { V3f min; float x = Fun.Abs(normal.X); float y = Fun.Abs(normal.Y); float z = Fun.Abs(normal.Z); if (x < y) { if (x < z) { min = V3f.XAxis; } else { min = V3f.ZAxis; } } else { if (y < z) { min = V3f.YAxis; } else { min = V3f.ZAxis; } } V3f xVec = Vec.Cross(normal, min); xVec.Normalize(); // this is now guaranteed to be normal to the input normal V3f yVec = Vec.Cross(normal, xVec); yVec.Normalize(); V3f zVec = normal; zVec.Normalize(); local2global = new M44f(xVec.X, yVec.X, zVec.X, origin.X, xVec.Y, yVec.Y, zVec.Y, origin.Y, xVec.Z, yVec.Z, zVec.Z, origin.Z, 0, 0, 0, 1); M44f mat = new M44f(xVec.X, xVec.Y, xVec.Z, 0, yVec.X, yVec.Y, yVec.Z, 0, zVec.X, zVec.Y, zVec.Z, 0, 0, 0, 0, 1); var shift = M44f.Translation(-origin); global2local = mat * shift; }
public void RasterTest(uint raster) { int iraster = (int)raster; V3fCoder coder = new V3fCoder(raster); uint step = 1; bool large = false; if (iraster > 52) { step = 7; large = true; } if (iraster > 591) { step = 63; } if (iraster > 6688) { step = 2039; } int bits = (int)Fun.Ceiling(Fun.Log2(coder.Count)); Test.Begin("normal coder raster {0} ({1} bits)", iraster, bits); /* * Console.WriteLine(" raster = {0}", m_raster); * Console.WriteLine(" rasterMul2Sub1 = {0}", m_r2Sub1); * Console.WriteLine(" doubleRaster = {0}", m_doubleRaster); * Console.WriteLine(" invDoubleRaster = {0}", m_invDoubleRaster); * Console.WriteLine(" edgeBasis = {0}", m_edgeBasis); * Console.WriteLine(" cornerBasis = {0}", m_cornerBasis); */ Test.Begin("testing {0} of {1} codes", 1 + ((long)coder.Count - 1) / (long)step, coder.Count); for (uint code = 0; code < coder.Count; code += step) { V3f dir = coder.Decode(code); uint newCode = coder.Encode(dir); Test.IsTrue(code == newCode); } Test.End(); double minDot = 1.0; float eps = Constant <float> .PositiveTinyValue; float[] factorTable = { 1.0f - eps, 1.0f, 1.0f + eps }; for (int sign = -1; sign < 2; sign += 2) { for (int axis = 0; axis < 3; axis++) { float factor = factorTable[axis]; for (int xi = -2 * iraster; xi <= 2 * iraster; xi++) { if (large && (xi > 3 - 2 * iraster) && (xi < -3)) { continue; } if (large && (xi < 2 * iraster - 3) && (xi > +3)) { continue; } double x = (double)xi * factor / (2 * iraster); #if (!V3FCODER_NO_WARP) x = V3fCoder.SphericalOfBox(x); #endif for (int yi = -2 * iraster; yi <= 2 * iraster; yi++) { if (large && (yi > 3 - 2 * iraster) && (yi < -3)) { continue; } if (large && (yi < 2 * iraster - 3) && (yi > +3)) { continue; } double y = (double)yi * factor / (2 * iraster); #if (!V3FCODER_NO_WARP) y = V3fCoder.SphericalOfBox(y); #endif V3f n = new V3f(0, 0, 0); // init to make compiler h. n[axis] = sign; n[(axis + 1) % 3] = (float)x; n[(axis + 2) % 3] = (float)y; n.Normalize(); uint code = coder.Encode(n); V3f newN = coder.Decode(code); double newDot = V3f.Dot(n, newN); if (newDot < minDot) { minDot = newDot; } } } } } double maxErr = System.Math.Acos(minDot) * 180.0 / System.Math.PI; Report.Line("maximal error {0:g4} degrees", maxErr); Test.End(); }