//helper: computes a facet horizontal and vertical extensions void ComputeFacetExtensions(CCVector3& N, ccPolyline* facetContour, double& horizExt, double& vertExt) { //horizontal and vertical extensions horizExt = vertExt = 0; CCLib::GenericIndexedCloudPersist* vertCloud = facetContour->getAssociatedCloud(); if (vertCloud) { //oriRotMat.applyRotation(N); //DGM: oriRotMat is only for display! //we assume that at this point the "up" direction is always (0,0,1) CCVector3 Xf(1,0,0), Yf(0,1,0); //we get the horizontal vector on the plane CCVector3 D = CCVector3(0,0,1).cross(N); if (D.norm2() > ZERO_TOLERANCE) //otherwise the facet is horizontal! { Yf = D; Yf.normalize(); Xf = N.cross(Yf); } const CCVector3* G = CCLib::Neighbourhood(vertCloud).getGravityCenter(); ccBBox box; for (unsigned i=0; i<vertCloud->size(); ++i) { const CCVector3 P = *(vertCloud->getPoint(i)) - *G; CCVector3 p( P.dot(Xf), P.dot(Yf), 0 ); box.add(p); } vertExt = box.getDiagVec().x; horizExt = box.getDiagVec().y; } }
void CCMiscTools::ComputeBaseVectors(const CCVector3 &N, CCVector3& X, CCVector3& Y) { CCVector3 Nunit = N; Nunit.normalize(); //we create a first vector orthogonal to the input one X = Nunit.orthogonal(); //X is also normalized //we deduce the orthogonal vector to the input one and X Y = N.cross(X); //Y.normalize(); //should already be normalized! }
SimpleCloud* MeshSamplingTools::samplePointsOnMesh(GenericMesh* theMesh, double samplingDensity, unsigned theoricNumberOfPoints, GenericProgressCallback* progressCb, GenericChunkedArray<1,unsigned>* triIndices/*=0*/) { assert(theMesh); unsigned triCount = (theMesh ? theMesh->size() : 0); if (triCount==0) return 0; if (theoricNumberOfPoints < 1) return 0; SimpleCloud* sampledCloud = new SimpleCloud(); if (!sampledCloud->reserve(theoricNumberOfPoints)) //not enough memory { delete sampledCloud; return 0; } if (triIndices) { triIndices->clear(); //not enough memory? DGM TODO: we should warn the caller if (!triIndices->reserve(theoricNumberOfPoints) || triIndices->capacity() < theoricNumberOfPoints) { delete sampledCloud; triIndices->clear(); return 0; } } NormalizedProgress* normProgress=0; if(progressCb) { normProgress = new NormalizedProgress(progressCb,triCount); progressCb->setMethodTitle("Mesh sampling"); char buffer[256]; sprintf(buffer,"Triangles: %i\nPoints: %i",triCount,theoricNumberOfPoints); progressCb->setInfo(buffer); progressCb->reset(); progressCb->start(); } unsigned addedPoints=0; //for each triangle theMesh->placeIteratorAtBegining(); for (unsigned n=0;n<triCount;++n) { const GenericTriangle* tri = theMesh->_getNextTriangle(); //summits (OAB) const CCVector3 *O = tri->_getA(); const CCVector3 *A = tri->_getB(); const CCVector3 *B = tri->_getC(); //edges (OA and OB) CCVector3 u = *A - *O; CCVector3 v = *B - *O; //we compute the (twice) the triangle area CCVector3 N = u.cross(v); double S = N.norm()/2.0; //we deduce the number of points to generate on this face double fPointsToAdd = S*samplingDensity; unsigned pointsToAdd = static_cast<unsigned>(fPointsToAdd); //if the face area is smaller than the surface/random point if (pointsToAdd == 0) { //we add a point with the same probability as its (relative) area if (static_cast<double>(rand()) <= fPointsToAdd * static_cast<double>(RAND_MAX)) pointsToAdd = 1; } if (pointsToAdd) { if (addedPoints + pointsToAdd >= theoricNumberOfPoints) { theoricNumberOfPoints+=pointsToAdd; if (!sampledCloud->reserve(theoricNumberOfPoints) || (triIndices && triIndices->capacity() < theoricNumberOfPoints && !triIndices->reserve(theoricNumberOfPoints))) //not enough memory { delete sampledCloud; sampledCloud = 0; triIndices->clear(); break; } } for (unsigned i=0; i<pointsToAdd; ++i) { //we generates random points as in: //'Greg Turk. Generating random points in triangles. In A. S. Glassner, editor,Graphics Gems, pages 24-28. Academic Press, 1990.' double x = static_cast<double>(rand())/static_cast<double>(RAND_MAX); double y = static_cast<double>(rand())/static_cast<double>(RAND_MAX); //we test if the generated point lies on the right side of (AB) if (x+y > 1.0) { x = 1.0-x; y = 1.0-y; } CCVector3 P = (*O) + static_cast<PointCoordinateType>(x) * u + static_cast<PointCoordinateType>(y) * v; sampledCloud->addPoint(P); if (triIndices) triIndices->addElement(n); ++addedPoints; } } if (normProgress && !normProgress->oneStep()) break; } if (normProgress) { delete normProgress; normProgress = 0; } if (sampledCloud) //can be in case of memory overflow! { if (addedPoints) { sampledCloud->resize(addedPoints); //should always be ok as addedPoints<theoricNumberOfPoints if (triIndices) triIndices->resize(addedPoints); } else { delete sampledCloud; sampledCloud = 0; if (triIndices) triIndices->clear(); } } return sampledCloud; }
ccGLMatrix ccGLMatrix::FromToRotation(const CCVector3& from, const CCVector3& to) { float e = from.dot(to); float f = (e < 0 ? -e : e); ccGLMatrix result; float* mat = result.data(); if (f > 1.0-ZERO_TOLERANCE) //"from" and "to"-vector almost parallel { CCVector3 x; // vector most nearly orthogonal to "from" x.x = (from.x > 0 ? from.x : -from.x); x.y = (from.y > 0 ? from.y : -from.y); x.z = (from.z > 0 ? from.z : -from.z); if (x.x < x.y) { if (x.x < x.z) { x.x = 1.0f; x.y = x.z = 0; } else { x.z = 1.0f; x.x = x.y = 0; } } else { if (x.y < x.z) { x.y = 1.0f; x.x = x.z = 0; } else { x.z = 1.0f; x.x = x.y = 0; } } CCVector3 u(x.x-from.x, x.y-from.y, x.z-from.z); CCVector3 v(x.x-to.x, x.y-to.y, x.z-to.z); float c1 = 2.0f / u.dot(u); float c2 = 2.0f / v.dot(v); float c3 = c1 * c2 * u.dot(v); for (unsigned i = 0; i < 3; i++) { for (unsigned j = 0; j < 3; j++) { mat[i*4+j]= c3 * v.u[i] * u.u[j] - c2 * v.u[i] * v.u[j] - c1 * u.u[i] * u.u[j]; } mat[i*4+i] += 1.0f; } } else // the most common case, unless "from"="to", or "from"=-"to" { //hand optimized version (9 mults less) CCVector3 v = from.cross(to); float h = 1.0f/(1.0f + e); float hvx = h * v.x; float hvz = h * v.z; float hvxy = hvx * v.y; float hvxz = hvx * v.z; float hvyz = hvz * v.y; mat[0] = e + hvx * v.x; mat[1] = hvxy - v.z; mat[2] = hvxz + v.y; mat[4] = hvxy + v.z; mat[5] = e + h * v.y * v.y; mat[6] = hvyz - v.x; mat[8] = hvxz - v.y; mat[9] = hvyz + v.x; mat[10] = e + hvz * v.z; } return result; }
bool ccClipBox::move3D(const CCVector3& uInput) { if (m_activeComponent == NONE || !m_box.isValid()) return false; CCVector3 u = uInput; //Arrows if (m_activeComponent >= X_MINUS_ARROW && m_activeComponent <= CROSS) { if (m_glTransEnabled) m_glTrans.inverse().applyRotation(u); switch(m_activeComponent) { case X_MINUS_ARROW: m_box.minCorner().x += u.x; if (m_box.minCorner().x > m_box.maxCorner().x) m_box.minCorner().x = m_box.maxCorner().x; break; case X_PLUS_ARROW: m_box.maxCorner().x += u.x; if (m_box.minCorner().x > m_box.maxCorner().x) m_box.maxCorner().x = m_box.minCorner().x; break; case Y_MINUS_ARROW: m_box.minCorner().y += u.y; if (m_box.minCorner().y > m_box.maxCorner().y) m_box.minCorner().y = m_box.maxCorner().y; break; case Y_PLUS_ARROW: m_box.maxCorner().y += u.y; if (m_box.minCorner().y > m_box.maxCorner().y) m_box.maxCorner().y = m_box.minCorner().y; break; case Z_MINUS_ARROW: m_box.minCorner().z += u.z; if (m_box.minCorner().z > m_box.maxCorner().z) m_box.minCorner().z = m_box.maxCorner().z; break; case Z_PLUS_ARROW: m_box.maxCorner().z += u.z; if (m_box.minCorner().z > m_box.maxCorner().z) m_box.maxCorner().z = m_box.minCorner().z; break; case CROSS: m_box.minCorner() += u; m_box.maxCorner() += u; break; default: assert(false); return false; } //send 'modified' signal emit boxModified(&m_box); } else if (m_activeComponent == SPHERE) { //handled by move2D! return false; } else if (m_activeComponent >= X_MINUS_TORUS && m_activeComponent <= Z_PLUS_TORUS) { //we guess the rotation order by comparing the current screen 'normal' //and the vector prod of u and the current rotation axis CCVector3 Rb(0.0,0.0,0.0); switch(m_activeComponent) { case X_MINUS_TORUS: Rb.x = -1.0; break; case X_PLUS_TORUS: Rb.x = 1.0; break; case Y_MINUS_TORUS: Rb.y = -1.0; break; case Y_PLUS_TORUS: Rb.y = 1.0; break; case Z_MINUS_TORUS: Rb.z = -1.0; break; case Z_PLUS_TORUS: Rb.z = 1.0; break; default: assert(false); return false; } CCVector3 R = Rb; if (m_glTransEnabled) m_glTrans.applyRotation(R); CCVector3 RxU = R.cross(u); //look for the most parallel dimension int minDim = 0; PointCoordinateType maxDot = CCVector3(m_viewMatrix.getColumn(0)).dot(RxU); for (int i=1;i<3;++i) { PointCoordinateType dot = CCVector3(m_viewMatrix.getColumn(i)).dot(RxU); if (fabs(dot) > fabs(maxDot)) { maxDot = dot; minDim = i; } } //angle is proportional to absolute displacement PointCoordinateType angle_rad = u.norm()/m_box.getDiagNorm() * M_PI; if (maxDot < 0.0) angle_rad = -angle_rad; ccGLMatrix rotMat; rotMat.initFromParameters(angle_rad,Rb,CCVector3(0.0,0.0,0.0)); CCVector3 C = m_box.getCenter(); ccGLMatrix transMat; transMat.setTranslation(-C); transMat = rotMat * transMat; transMat.setTranslation(CCVector3(transMat.getTranslation())+C); m_glTrans = m_glTrans * transMat.inverse(); enableGLTransformation(true); } else { assert(false); return false; } update(); return true; }