bool EdgeHash::operator==(const EdgeHash& rhs) { // return true for any edge that has vertices in equivilant positions return ( fuzzyEq( vertices + indices[0], rhs.vertices + rhs.indices[0] ) && fuzzyEq( vertices + indices[1], rhs.vertices + rhs.indices[1] ) ) || ( fuzzyEq( vertices + indices[0], rhs.vertices + rhs.indices[1] ) && fuzzyEq( vertices + indices[1], rhs.vertices + rhs.indices[0] ) ); }
Vector2 LineSegment2D::closestPoint(const Vector2& Q) const { // Two constants that appear in the result const Vector2 k1(m_origin - Q); const Vector2& k2 = m_direction; if (fuzzyEq(m_length, 0)) { // This line segment has no length return m_origin; } // Time [0, 1] at which we hit the closest point travelling from p0 to p1. // Derivation can be obtained by minimizing the expression // ||P0 + (P1 - P0)t - Q||. const float t = -k1.dot(k2) / (m_length * m_length); if (t < 0) { // Clipped to low end point return m_origin; } else if (t > 1) { // Clipped to high end point return m_origin + m_direction; } else { // Subsitute into the line equation to find // the point on the segment. return m_origin + k2 * t; } }
void MeshAlg::identifyBackfaces( const Array<Vector3>& vertexArray, const Array<MeshAlg::Face>& faceArray, const Vector4& HP, Array<bool>& backface, const Array<Vector3>& faceNormals) { Vector3 P = HP.xyz(); backface.resize(faceArray.size()); if (fuzzyEq(HP.w, 0.0)) { // Infinite case for (int f = faceArray.size() - 1; f >= 0; --f) { const Vector3& N = faceNormals[f]; backface[f] = N.dot(P) < 0; } } else { // Finite case for (int f = faceArray.size() - 1; f >= 0; --f) { const MeshAlg::Face& face = faceArray[f]; const Vector3& v0 = vertexArray[face.vertexIndex[0]]; const Vector3& N = faceNormals[f]; backface[f] = N.dot(P - v0) < 0; } } }
static void testCast() { { Any a(3); int x = int(a.number()); testAssert(x == 3); } { Any a(3); int x = a; testAssert(x == 3); } { Any a(3.1); double x = a; testAssert(x == 3.1); } { Any a(3.1f); float x = a; testAssert(fuzzyEq(x, 3.1f)); } { Any a(true); bool x = a; testAssert(x == true); } { Any a("hello"); String x = a; testAssert(x == "hello"); } }
Welder::Welder( const Array<Vector3>& _oldVertexArray, Array<Vector3>& _newVertexArray, Array<int>& _toNew, Array<int>& _toOld, double _radius) : oldVertexArray(_oldVertexArray), newVertexArray(_newVertexArray), toNew(_toNew), toOld(_toOld), radius(_radius) { // Compute a scale factor that moves the range // of all ordinates to [0, 1] Vector3 minBound = Vector3::inf(); Vector3 maxBound = -minBound; for (int i = 0; i < oldVertexArray.size(); ++i) { minBound = minBound.min(oldVertexArray[i]); maxBound = maxBound.max(oldVertexArray[i]); } offset = minBound; scale = maxBound - minBound; for (int i = 0; i < 3; ++i) { // The model might have zero extent along some axis if (fuzzyEq(scale[i], 0.0)) { scale[i] = 1.0; } else { scale[i] = 1.0 / scale[i]; } } }
static void testEuler() { float x = 1; float y = 2; float z = -3; float x2, y2, z2; Matrix3 rX = Matrix3::fromAxisAngle(Vector3::unitX(), x); Matrix3 rY = Matrix3::fromAxisAngle(Vector3::unitY(), y); Matrix3 rZ = Matrix3::fromAxisAngle(Vector3::unitZ(), z); Matrix3 rot = rZ * rX * rY; rot.toEulerAnglesZXY(x2, y2, z2); debugAssert(fuzzyEq(x, x2)); debugAssert(fuzzyEq(y, y2)); debugAssert(fuzzyEq(z, z2)); }
Edge* Geometry::getEdges(void) { if( !_numVertices ) return NULL; if( _edges.size() ) return &_edges[0]; Table<EdgeHash,int> edgeTable; for( int i=0; i<_numTriangles; i++ ) { // make sure this is not a degenerate triangle // (ie the vertices are so close the triangle is extremely small) assert( !fuzzyEq( _vertices + _triangles[i].vertexId[0], _vertices + _triangles[i].vertexId[1] ) ); assert( !fuzzyEq( _vertices + _triangles[i].vertexId[1], _vertices + _triangles[i].vertexId[2] ) ); assert( !fuzzyEq( _vertices + _triangles[i].vertexId[0], _vertices + _triangles[i].vertexId[2] ) ); // add three edges for each face addEdge( edgeTable, _edges, _triangles[i].vertexId[0], _triangles[i].vertexId[1], i ); addEdge( edgeTable, _edges, _triangles[i].vertexId[1], _triangles[i].vertexId[2], i ); addEdge( edgeTable, _edges, _triangles[i].vertexId[0], _triangles[i].vertexId[2], i ); } return &_edges[0]; }
void Geometry::addEdge(Table<EdgeHash,int>& edgeTable, std::vector<Edge>& edgeVector, int v0, int v1, int face) { EdgeHash edgeKey( v0, v1, _vertices ); if( edgeTable.containsKey(edgeKey) ) { // if this is the second face referencing this edge int edgeIndex = edgeTable[edgeKey]; Edge& existingEdge = edgeVector[edgeIndex]; // make sure the vertices are wound correctly // (ie in opposite directions for the two different faces) assert( fuzzyEq( _vertices + existingEdge.vertexId[0], _vertices + v1 ) ); assert( fuzzyEq( _vertices + existingEdge.vertexId[1], _vertices + v0 ) ); // make sure this is only the second face to reference this edge assert( existingEdge.triangleId[0] >= 0 ); assert( existingEdge.triangleId[0] != face ); assert( existingEdge.triangleId[1] == -1 ); // set second face existingEdge.triangleId[1] = face; } else { // if this is the first face referencing this edge Edge newEdge; newEdge.vertexId[0] = v0; newEdge.vertexId[1] = v1; newEdge.triangleId[0] = face; newEdge.triangleId[1] = -1; // add edge to lookup table and array edgeTable.set( edgeKey, edgeVector.size() ); edgeVector.push_back(newEdge); } }
void testGChunk() { printf("GChunk "); enum {HEADER, NAME, BODY, NUM, DATA}; { BinaryOutput b("file.dat", G3D_LITTLE_ENDIAN); { GChunk c(b, HEADER); { GChunk c(b, NAME, STRING_BINFMT); b.writeString("abcdefg"); c.finish(b); } c.finish(b); } { GChunk c(b, BODY); { GChunk c(b, NUM, INT32_BINFMT); b.writeInt32(10); c.finish(b); } { GChunk c(b, DATA, FLOAT32_BINFMT); for (int i = 0; i < 10; ++i) { b.writeFloat32(sqrt((double)i)); } c.finish(b); } c.finish(b); } b.commit(); } { BinaryInput b("file.dat", G3D_LITTLE_ENDIAN); { GChunk c(b, HEADER); { GChunk c(b, NAME, STRING_BINFMT); debugAssert(c.count == -1); alwaysAssertM(b.readString() == "abcdefg", ""); c.finish(b); } c.finish(b); } { GChunk c(b, BODY); { GChunk c(b, NUM, INT32_BINFMT); debugAssert(c.count == 1); alwaysAssertM(b.readInt32() == 10, ""); c.finish(b); } { GChunk c(b, DATA, FLOAT32_BINFMT); debugAssert(c.count == 10); for (int i = 0; i < 10; ++i) { alwaysAssertM(fuzzyEq(b.readFloat32(), sqrt((double)i)), "Data in chunk corrupted"); } c.finish(b); } c.finish(b); } } printf("passed\n"); }
void testMatrix() { printf("Matrix "); // Zeros { Matrix M(3, 4); debugAssert(M.rows() == 3); debugAssert(M.cols() == 4); debugAssert(M.get(0, 0) == 0); debugAssert(M.get(1, 1) == 0); } // Identity { Matrix M = Matrix::identity(4); debugAssert(M.rows() == 4); debugAssert(M.cols() == 4); debugAssert(M.get(0, 0) == 1); debugAssert(M.get(0, 1) == 0); } // Add { Matrix A = Matrix::random(2, 3); Matrix B = Matrix::random(2, 3); Matrix C = A + B; for (int r = 0; r < 2; ++r) { for (int c = 0; c < 3; ++c) { debugAssert(fuzzyEq(C.get(r, c), A.get(r, c) + B.get(r, c))); } } } // Matrix multiply { Matrix A(2, 2); Matrix B(2, 2); A.set(0, 0, 1); A.set(0, 1, 3); A.set(1, 0, 4); A.set(1, 1, 2); B.set(0, 0, -6); B.set(0, 1, 9); B.set(1, 0, 1); B.set(1, 1, 7); Matrix C = A * B; debugAssert(fuzzyEq(C.get(0, 0), -3)); debugAssert(fuzzyEq(C.get(0, 1), 30)); debugAssert(fuzzyEq(C.get(1, 0), -22)); debugAssert(fuzzyEq(C.get(1, 1), 50)); } // Transpose { Matrix A(2, 2); A.set(0, 0, 1); A.set(0, 1, 3); A.set(1, 0, 4); A.set(1, 1, 2); Matrix C = A.transpose(); debugAssert(fuzzyEq(C.get(0, 0), 1)); debugAssert(fuzzyEq(C.get(0, 1), 4)); debugAssert(fuzzyEq(C.get(1, 0), 3)); debugAssert(fuzzyEq(C.get(1, 1), 2)); A = Matrix::random(3, 4); A = A.transpose(); debugAssert(A.rows() == 4); debugAssert(A.cols() == 3); } // Copy-on-mutate { Matrix::debugNumCopyOps = Matrix::debugNumAllocOps = 0; Matrix A = Matrix::identity(2); debugAssert(Matrix::debugNumAllocOps == 1); debugAssert(Matrix::debugNumCopyOps == 0); Matrix B = A; debugAssert(Matrix::debugNumAllocOps == 1); debugAssert(Matrix::debugNumCopyOps == 0); B.set(0,0,4); debugAssert(B.get(0,0) == 4); debugAssert(A.get(0,0) == 1); debugAssert(Matrix::debugNumAllocOps == 2); debugAssert(Matrix::debugNumCopyOps == 1); } // Inverse { Matrix A(2, 2); A.set(0, 0, 1); A.set(0, 1, 3); A.set(1, 0, 4); A.set(1, 1, 2); Matrix C = A.inverse(); debugAssert(fuzzyEq(C.get(0, 0), -0.2)); debugAssert(fuzzyEq(C.get(0, 1), 0.3)); debugAssert(fuzzyEq(C.get(1, 0), 0.4)); debugAssert(fuzzyEq(C.get(1, 1), -0.1)); } { Matrix A = Matrix::random(10, 10); Matrix B = A.inverse(); B = B * A; for (int r = 0; r < B.rows(); ++r) { for (int c = 0; c < B.cols(); ++c) { float v = B.get(r, c); // The precision isn't great on our inverse, so be tolerant if (r == c) { debugAssert(abs(v - 1) < 1e-4); } else { debugAssert(abs(v) < 1e-4); } (void)v; } } } // Negate { Matrix A = Matrix::random(2, 2); Matrix B = -A; for (int r = 0; r < A.rows(); ++r) { for (int c = 0; c < A.cols(); ++c) { debugAssert(B.get(r, c) == -A.get(r, c)); } } } // Transpose { Matrix A = Matrix::random(3,2); Matrix B = A.transpose(); debugAssert(B.rows() == A.cols()); debugAssert(B.cols() == A.rows()); for (int r = 0; r < A.rows(); ++r) { for (int c = 0; c < A.cols(); ++c) { debugAssert(B.get(c, r) == A.get(r, c)); } } } // SVD { Matrix A = Matrix(3, 3); A.set(0, 0, 1.0); A.set(0, 1, 2.0); A.set(0, 2, 1.0); A.set(1, 0, -3.0); A.set(1, 1, 7.0); A.set(1, 2, -6.0); A.set(2, 0, 4.0); A.set(2, 1, -4.0); A.set(2, 2, 10.0); A = Matrix::random(27, 15); Array<float> D; Matrix U, V; A.svd(U, D, V); // Verify that we can reconstruct Matrix B = U * Matrix::fromDiagonal(D) * V.transpose(); Matrix test = abs(A - B) < 0.1f; // A.debugPrint("A"); // U.debugPrint("U"); // D.debugPrint("D"); // V.debugPrint("V"); // (U * D * V.transpose()).debugPrint("UDV'"); debugAssert(test.allNonZero()); float m = (A - B).norm() / A.norm(); debugAssert(m < 0.01f); (void)m; } /* Matrix a(3, 5); a.set(0,0, 1); a.set(0,1, 2); a.set(0,2, 3); a.set(0,3, 4); a.set(0,4, 5); a.set(1,0, 3); a.set(1,1, 5); a.set(1,2, 3); a.set(1,3, 1); a.set(1,4, 2); a.set(2,0, 1); a.set(2,1, 1); a.set(2,2, 1); a.set(2,3, 1); a.set(2,4, 1); Matrix b = a; b.set(0,0, 1.8124); b.set(0,1, 0.5341); b.set(0,2, 2.8930); b.set(0,3, 5.2519); b.set(0,4, 4.8829); b.set(1,0, 2.5930); b.set(1,1, 2.6022); b.set(1,2, 4.2760); b.set(1,3, 5.9497); b.set(1,4, 6.3751); a.debugPrint("a"); a.debugPrint("b"); Matrix H = b * a.pseudoInverse(); H.debugPrint("H"); */ printf("passed\n"); }