//----------------------------------------------------------------------------- // Sample distances to the mesh in the entire bounding box void ImplicitMesh::Initialize() { // First, delete old data grid delete mData; mData = NULL; // Create new grid Vector3<float> dim = (mBox.pMax - mBox.pMin) / mMeshSampling; mData = new Volume<float>(ceil(dim[0]), ceil(dim[1]), ceil(dim[2])); // Setup progress bar unsigned int totalSamples = mData->GetDimX()*mData->GetDimY()*mData->GetDimZ(); unsigned int currentSample = 0; unsigned int reportFreq = totalSamples / 30; // Start sampling... std::cerr << "Computing distances to mesh ["; int i, j, k; i = 0; for(float x = mBox.pMin[0]; x < mBox.pMax[0]-0.5*mMeshSampling; x += mMeshSampling, i++) { j = 0; for(float y = mBox.pMin[1]; y < mBox.pMax[1]-0.5*mMeshSampling; y += mMeshSampling, j++) { k = 0; for(float z = mBox.pMin[2]; z < mBox.pMax[2]-0.5*mMeshSampling; z += mMeshSampling, k++) { mData->SetValue(i,j,k, DistanceToPoint(x,y,z, *mSourceMesh)); currentSample++; if (currentSample % reportFreq == 0) std::cerr << "="; } } } std::cerr << "] done" << std::endl; SimpleMesh dilatedMesh = *mSourceMesh; dilatedMesh.Initialize(); dilatedMesh.Dilate(0.0001); std::cerr << "Determining inside/outside ["; i = 0; currentSample = 0; for(float x = mBox.pMin[0]; x < mBox.pMax[0]-0.5*mMeshSampling; x += mMeshSampling, i++) { j = 0; for(float y = mBox.pMin[1]; y < mBox.pMax[1]-0.5*mMeshSampling; y += mMeshSampling, j++) { k = 0; for(float z = mBox.pMin[2]; z < mBox.pMax[2]-0.5*mMeshSampling; z += mMeshSampling, k++) { float distance = DistanceToPoint(x,y,z, dilatedMesh); if (mData->GetValue(i,j,k) - distance < 0) mData->SetValue(i,j,k, -mData->GetValue(i,j,k)); currentSample++; if (currentSample % reportFreq == 0) std::cerr << "="; } } } std::cerr << "] done" << std::endl; Implicit::Update(); }
bool readObjFile(SimpleMesh<Vector, Face3>& mesh, const std::string& fileName) { // Attempt to read file. std::ifstream file(fileName.c_str()); if(!file) { std::cerr << "Error reading file!" << std::endl; return false; } // Clear the mesh data structure. mesh = SimpleMesh<Vector, Face3>(); // Fill the mesh data structure. std::string line; while ( std::getline(file, line) ) { std::stringstream ss; ss << line; char type; ss >> type; if(type=='v') { double x, y, z; ss >> x >> y >> z; mesh.vertices().push_back(Vector(x, y, z)); } if(type=='f') { size_t a, b, c; ss >> a >> b >> c; mesh.faces().push_back(Face3(a-1, b-1, c-1)); }
static void SC_drawSimpleMeshRange(RsSimpleMesh vsm, uint32_t start, uint32_t len) { GET_TLS(); SimpleMesh *sm = static_cast<SimpleMesh *>(vsm); rsc->setupCheck(); sm->renderRange(rsc, start, len); }
static void SC_drawSimpleMesh(RsSimpleMesh vsm) { GET_TLS(); SimpleMesh *sm = static_cast<SimpleMesh *>(vsm); rsc->setupCheck(); sm->render(rsc); }
float ImplicitMesh::DistanceToPoint(float x, float y, float z, const SimpleMesh & mesh) const{ // just loop over all faces and take the min distance. // uses normals to determine direction and resulting sign (negative inside) std::pair<float, bool> pr((std::numeric_limits<float>::max)(), true); const std::vector<SimpleMesh::Vertex>& verts = mesh.GetVerts(); const std::vector<SimpleMesh::Face>& faces = mesh.GetFaces(); Vector3<float> p(x,y,z); for(unsigned int i=0; i<faces.size(); i++){ const SimpleMesh::Vertex &v1 = verts.at(faces.at(i).v1); const SimpleMesh::Vertex &v2 = verts.at(faces.at(i).v2); const SimpleMesh::Vertex &v3 = verts.at(faces.at(i).v3); std::pair<float, bool> pt = DistanceSquared(p, v1.pos, v2.pos, v3.pos); if(pt.first < pr.first) pr = pt; } pr.first = std::sqrt(pr.first); return pr.first; //pr.second ? pr.first : -pr.first; }
void Implicit::Update() { if (mVisualizationMode == Curvature) { if(typeid(*mMesh) == typeid(SimpleMesh)) { SimpleMesh * ptr = static_cast<SimpleMesh*>(mMesh); std::vector<SimpleMesh::Vertex>& verts = ptr->GetVerts(); Matrix4x4<float> M = GetTransform().Transpose(); // Compute curvature of implicit geometry and assign to the vertex property for(unsigned int i=0; i < verts.size(); i++){ const Vector3<float> vObject = verts.at(i).pos; // Transform vertex position to world space Vector4<float> vWorld = GetTransform() * Vector4<float>(vObject[0],vObject[1],vObject[2],1); // Get curvature in world space verts.at(i).curvature = GetCurvature(vWorld[0], vWorld[1], vWorld[2]); // Get gradient in world space (used for lighting) Vector3<float> nWorld = GetGradient(vWorld[0], vWorld[1], vWorld[2]); // Transform gradient to object space Vector4<float> nObject = M * Vector4<float>(nWorld[0],nWorld[1],nWorld[2],0); verts.at(i).normal = Vector3<float>(nObject[0], nObject[1], nObject[2]).Normalize(); } ptr->mAutoMinMax = mAutoMinMax; ptr->mMinCMap = mMinCMap; ptr->mMaxCMap = mMaxCMap; ptr->SetVisualizationMode(Mesh::CurvatureVertex); ptr->Update(); } else { std::cerr << "No Curvature visualization mode implemented for mesh type: " << typeid(*mMesh).name() << std::endl; } } }
bool ManualSegmentationTools::segmentMeshWitAABox(GenericIndexedMesh* origMesh, GenericIndexedCloudPersist* origVertices, MeshCutterParams& ioParams, GenericProgressCallback* progressCb/*=0*/) { if (!origMesh || !origVertices || origMesh->size() == 0 || origVertices->size() < 3 || ioParams.bbMin.x >= ioParams.bbMax.x || ioParams.bbMin.y >= ioParams.bbMax.y || ioParams.bbMin.z >= ioParams.bbMax.z) { //invalid input parameters return false; } if (origMesh->size() > c_realIndexMask) { //too many triangles! return false; } const double& epsilon = ioParams.epsilon; const CCVector3d& bbMin = ioParams.bbMin; const CCVector3d& bbMax = ioParams.bbMax; //indexes of original triangle that are not modified bt copied "as is" std::vector<unsigned> preservedTrianglesInside1; //insde (1) std::vector<unsigned> preservedTrianglesInside2; //insde (2) std::vector<unsigned> preservedTrianglesOutside; //outside //inside meshes (swapped for each dimension) ChunkedPointCloud* insideVertices1 = new ChunkedPointCloud; SimpleMesh* insideMesh1 = new SimpleMesh(insideVertices1, true); ChunkedPointCloud* insideVertices2 = new ChunkedPointCloud; SimpleMesh* insideMesh2 = new SimpleMesh(insideVertices2, true); //outside mesh (output) ChunkedPointCloud* outsideVertices = 0; SimpleMesh* outsideMesh = 0; if (ioParams.generateOutsideMesh) { outsideVertices = new ChunkedPointCloud; outsideMesh = new SimpleMesh(outsideVertices, true); } //pointers on input and output structures (will change for each dimension) std::vector<unsigned>* preservedTrianglesInside = &preservedTrianglesInside1; std::vector<unsigned>* formerPreservedTriangles = &preservedTrianglesInside2; ChunkedPointCloud* insideVertices = insideVertices1; SimpleMesh* insideMesh = insideMesh1; GenericIndexedMesh* sourceMesh = origMesh; GenericIndexedCloudPersist* sourceVertices = origVertices; CCVector3d boxCenter = (ioParams.bbMin + ioParams.bbMax) / 2; CCVector3d boxHalfSize = (ioParams.bbMax - ioParams.bbMin) / 2; bool error = false; //for each triangle try { //for each plane for (unsigned d = 0; d < 6; ++d) { //Extract the 'plane' information corresponding to the input box faces //-X,+X,-Y,+Y,-Z,+Z unsigned char Z = static_cast<unsigned char>(d / 2); double planeCoord = ((d & 1) ? bbMax : bbMin).u[Z]; bool keepBelow = ((d & 1) ? true : false); assert(preservedTrianglesInside && formerPreservedTriangles); assert(insideVertices && insideMesh); assert(sourceVertices && sourceMesh); s_edgePoint.clear(); std::vector<unsigned> origTriIndexesMapInsideBackup; if (ioParams.trackOrigIndexes) { origTriIndexesMapInsideBackup = ioParams.origTriIndexesMapInside; ioParams.origTriIndexesMapInside.clear(); } //look for original triangles //(the first time they only come from the original mesh but afterwards // they can come from the original mesh through the 'preserved' list // or from the previous 'inside' mesh as we have to test those triangles // against the new plane) unsigned sourceTriCount = sourceMesh ? sourceMesh->size() : 0; //source: previous/original mesh unsigned formerPreservedTriCount = static_cast<unsigned>(formerPreservedTriangles->size()); unsigned triCount = sourceTriCount + formerPreservedTriCount; for (unsigned i = 0; i < triCount; ++i) { bool triangleIsOriginal = false; unsigned souceTriIndex = 0; const VerticesIndexes* tsi = 0; if (i < sourceTriCount) { souceTriIndex = i; triangleIsOriginal = (sourceMesh == origMesh); tsi = sourceMesh->getTriangleVertIndexes(souceTriIndex); } else { souceTriIndex = (*formerPreservedTriangles)[i - sourceTriCount]; triangleIsOriginal = true; tsi = origMesh->getTriangleVertIndexes(souceTriIndex); } //vertices indexes unsigned vertIndexes[3] = { tsi->i1, tsi->i2, tsi->i3 }; if (triangleIsOriginal) { //we flag the vertices indexes as referring to the 'original' mesh vertIndexes[0] |= c_origIndexFlag; vertIndexes[1] |= c_origIndexFlag; vertIndexes[2] |= c_origIndexFlag; } else { //we flag the vertices indexes as referring to the 'source' mesh if ((vertIndexes[0] & c_origIndexFlag) == 0) vertIndexes[0] |= c_srcIndexFlag; if ((vertIndexes[1] & c_origIndexFlag) == 0) vertIndexes[1] |= c_srcIndexFlag; if ((vertIndexes[2] & c_origIndexFlag) == 0) vertIndexes[2] |= c_srcIndexFlag; } //get the vertices (from the right source!) CCVector3d V[3] = { CCVector3d::fromArray(( (vertIndexes[0] & c_origIndexFlag) ? origVertices : sourceVertices)->getPoint(vertIndexes[0] & c_realIndexMask)->u), CCVector3d::fromArray(( (vertIndexes[1] & c_origIndexFlag) ? origVertices : sourceVertices)->getPoint(vertIndexes[1] & c_realIndexMask)->u), CCVector3d::fromArray(( (vertIndexes[2] & c_origIndexFlag) ? origVertices : sourceVertices)->getPoint(vertIndexes[2] & c_realIndexMask)->u) }; if (d == 0) { //perform a triangle-box overlap test the first time! if (!CCMiscTools::TriBoxOverlapd(boxCenter, boxHalfSize, V)) { if (ioParams.generateOutsideMesh) preservedTrianglesOutside.push_back(i); continue; } } //test the position of each vertex relatively to the current plane //char relativePos[3] = { 1, 1, 1 }; //bool insideXY[3] = { false, false, false }; std::vector<unsigned char> insideLocalVertIndexes, outsideLocalVertIndexes; for (unsigned char j = 0; j < 3; ++j) { const CCVector3d& v = V[j]; if (fabs(v.u[Z] - planeCoord) < epsilon) { //relativePos[j] = 0; } else { if (v.u[Z] < planeCoord) { insideLocalVertIndexes.push_back(j); //relativePos[j] = -1; } else { //relativePos is already equal to 1 //relativePos[j] = 1; outsideLocalVertIndexes.push_back(j); } } } //depending on the number of entities on the plane //we'll process the triangles differently bool isFullyInside = false; bool isFullyOutside = false; switch (insideLocalVertIndexes.size() + outsideLocalVertIndexes.size()) { case 0: //all vertices 'in' the plane { //we arbitrarily decide that the triangle is inside! isFullyInside = true; } break; case 1: //2 vertices 'in' the plane { //the triangle is either on one side or another ;) if (insideLocalVertIndexes.empty()) { //the only vertex far from the plane is on the 'otuside' isFullyOutside = true; } else { //the only vertex far from the plane is on the 'inside' isFullyInside = true; } } break; case 2: //1 vertex 'in' the plane { //3 cases: if (insideLocalVertIndexes.empty()) { //the two vertices far from the plane are 'outside' isFullyOutside = true; } else if (outsideLocalVertIndexes.empty()) { //the two vertices far from the plane are 'inside' isFullyInside = true; } else { //the two vertices far from the plane are on both sides //the plane will cut through the edge connecting those two vertices unsigned char iInside = insideLocalVertIndexes.front(); unsigned char iOuside = outsideLocalVertIndexes.front(); unsigned char iCenter = 3 - iInside - iOuside; unsigned iCoutside, iCinside; //we can now create one vertex and two new triangles if (!ComputeEdgePoint( V[iInside], vertIndexes[iInside], V[iOuside], vertIndexes[iOuside], iCoutside, iCinside, planeCoord, Z, outsideVertices, insideVertices) || !AddTriangle( vertIndexes[iCenter], vertIndexes[iInside], keepBelow ? iCinside : iCoutside, keepBelow ? insideMesh : outsideMesh, ((iCenter + 1) % 3) == iInside) || !AddTriangle( vertIndexes[iCenter], vertIndexes[iOuside], keepBelow ? iCoutside : iCinside, keepBelow ? outsideMesh : insideMesh, ((iCenter + 1) % 3) == iOuside)) { //early stop i = triCount; error = true; break; } //remember (origin) source triangle index if (ioParams.trackOrigIndexes) { assert(triangleIsOriginal || souceTriIndex < origTriIndexesMapInsideBackup.size()); unsigned origTriIndex = triangleIsOriginal ? souceTriIndex : origTriIndexesMapInsideBackup[souceTriIndex]; //the source triangle is split in two so each side get one new triangle ioParams.origTriIndexesMapInside.push_back(origTriIndex); if (ioParams.generateOutsideMesh) ioParams.origTriIndexesMapOutside.push_back(origTriIndex); } } } break; case 3: //no vertex 'in' the plane { if (insideLocalVertIndexes.empty()) { //all vertices are 'outside' isFullyOutside = true; } else if (outsideLocalVertIndexes.empty()) { //all vertices are 'inside' isFullyInside = true; } else { //we have one vertex on one side and two on the other side unsigned char iLeft, iRight1, iRight2; bool leftIsInside = true; if (insideLocalVertIndexes.size() == 1) { assert(outsideLocalVertIndexes.size() == 2); iLeft = insideLocalVertIndexes.front(); iRight1 = outsideLocalVertIndexes[0]; iRight2 = outsideLocalVertIndexes[1]; leftIsInside = keepBelow; } else { assert(insideLocalVertIndexes.size() == 2); iLeft = outsideLocalVertIndexes.front(); iRight1 = insideLocalVertIndexes[0]; iRight2 = insideLocalVertIndexes[1]; leftIsInside = !keepBelow; } //the plane cuts through the two edges having the 'single' vertex in common //we are going to create 3 triangles unsigned i1outside, i1inside; unsigned i2outside, i2inside; if ( !ComputeEdgePoint( V[iRight1], vertIndexes[iRight1], V[iLeft], vertIndexes[iLeft], i1outside, i1inside, planeCoord, Z, outsideVertices, insideVertices) || !ComputeEdgePoint( V[iRight2], vertIndexes[iRight2], V[iLeft], vertIndexes[iLeft], i2outside, i2inside, planeCoord, Z, outsideVertices, insideVertices) || !AddTriangle( vertIndexes[iLeft], leftIsInside ? i1inside : i1outside, leftIsInside ? i2inside : i2outside, leftIsInside ? insideMesh : outsideMesh, ((iLeft + 1) % 3) == iRight1) || !AddTriangle( leftIsInside ? i1outside : i1inside, leftIsInside ? i2outside : i2inside, vertIndexes[iRight1], leftIsInside ? outsideMesh : insideMesh, ((iRight2 + 1) % 3) == iRight1) || !AddTriangle( vertIndexes[iRight1], leftIsInside ? i2outside : i2inside, vertIndexes[iRight2], leftIsInside ? outsideMesh : insideMesh, ((iRight2 + 1) % 3) == iRight1) ) { //early stop i = triCount; error = true; break; } //remember (origin) source triangle index if (ioParams.trackOrigIndexes) { assert(triangleIsOriginal || souceTriIndex < origTriIndexesMapInsideBackup.size()); unsigned origTriIndex = triangleIsOriginal ? souceTriIndex : origTriIndexesMapInsideBackup[souceTriIndex]; //each side gets at least one new triangle ioParams.origTriIndexesMapInside.push_back(origTriIndex); if (ioParams.generateOutsideMesh) ioParams.origTriIndexesMapOutside.push_back(origTriIndex); //the third triangle has been added either to the 'inside' or to the 'outside' mesh if (!leftIsInside) ioParams.origTriIndexesMapInside.push_back(origTriIndex); else if (ioParams.generateOutsideMesh) ioParams.origTriIndexesMapOutside.push_back(origTriIndex); } } } break; } if (isFullyInside || isFullyOutside) { //inverted selection? if (!keepBelow) std::swap(isFullyInside, isFullyOutside); if (triangleIsOriginal) { if (isFullyInside) preservedTrianglesInside->push_back(souceTriIndex); else if (ioParams.generateOutsideMesh) preservedTrianglesOutside.push_back(souceTriIndex); } else { //we import the former triangle if (!AddTriangle(vertIndexes[0], vertIndexes[1], vertIndexes[2], isFullyInside ? insideMesh : outsideMesh, true)) { //early stop error = true; break; } if (ioParams.trackOrigIndexes) { assert(souceTriIndex < origTriIndexesMapInsideBackup.size()); unsigned origTriIndex = origTriIndexesMapInsideBackup[souceTriIndex]; if (isFullyInside) ioParams.origTriIndexesMapInside.push_back(origTriIndex); else if (ioParams.generateOutsideMesh) ioParams.origTriIndexesMapOutside.push_back(origTriIndex); } } } } //end for each triangle if ( !ImportSourceVertices(sourceVertices, insideMesh, insideVertices) || (ioParams.generateOutsideMesh && !ImportSourceVertices(sourceVertices, outsideMesh, outsideVertices)) ) { //early stop error = true; break; } if (insideMesh->size() == 0 && preservedTrianglesInside->empty()) { //no triangle inside! break; } if (d < 5) { //clear the source mesh and swap the buffers if (insideMesh == insideMesh1) { assert(sourceMesh == insideMesh2 || sourceMesh == origMesh); insideMesh2->clear(false); insideVertices2->clear(); sourceMesh = insideMesh1; sourceVertices = insideVertices1; insideMesh = insideMesh2; insideVertices = insideVertices2; preservedTrianglesInside2.clear(); preservedTrianglesInside = &preservedTrianglesInside2; formerPreservedTriangles = &preservedTrianglesInside1; } else { assert(sourceMesh == insideMesh1 || sourceMesh == origMesh); insideMesh1->clear(false); insideVertices1->clear(); sourceMesh = insideMesh2; sourceVertices = insideVertices2; insideMesh = insideMesh1; insideVertices = insideVertices1; preservedTrianglesInside1.clear(); preservedTrianglesInside = &preservedTrianglesInside1; formerPreservedTriangles = &preservedTrianglesInside2; } } } //end for each plane //now add the remaining triangles } catch (const std::bad_alloc&) { //not enough memory error = true; } //free some memory s_edgePoint.clear(); formerPreservedTriangles->clear(); if (!error) { //import the 'preserved' (original) triangles if ( !MergeOldTriangles( origMesh, origVertices, insideMesh, insideVertices, *preservedTrianglesInside, ioParams.trackOrigIndexes ? &ioParams.origTriIndexesMapInside : 0) || ( ioParams.generateOutsideMesh && !MergeOldTriangles( origMesh, origVertices, outsideMesh, outsideVertices, preservedTrianglesOutside, ioParams.trackOrigIndexes ? &ioParams.origTriIndexesMapOutside : 0)) ) { error = true; } } if (insideMesh == insideMesh1) { delete insideMesh2; insideMesh2 = 0; insideVertices2 = 0; } else { delete insideMesh1; insideMesh1 = 0; insideVertices1 = 0; } if (error) { delete insideMesh; if (outsideMesh) delete outsideMesh; return false; } if (insideMesh) { insideMesh->resize(insideMesh->size()); } if (outsideMesh) { outsideMesh->resize(outsideMesh->size()); } ioParams.insideMesh = insideMesh; ioParams.outsideMesh = outsideMesh; return true; }
GenericIndexedMesh* ManualSegmentationTools::segmentMesh(GenericIndexedMesh* theMesh, ReferenceCloud* pointIndexes, bool pointsWillBeInside, GenericProgressCallback* progressCb, GenericIndexedCloud* destCloud, unsigned indexShift) { if (!theMesh || !pointIndexes || !pointIndexes->getAssociatedCloud()) return 0; //by default we try a fast process (but with a higher memory consumption) unsigned numberOfPoints = pointIndexes->getAssociatedCloud()->size(); unsigned numberOfIndexes = pointIndexes->size(); //we determine for each point if it is used in the output mesh or not //(and we compute its new index by the way: 0 means that the point is not used, otherwise its index will be newPointIndexes-1) std::vector<unsigned> newPointIndexes; { try { newPointIndexes.resize(numberOfPoints,0); } catch (const std::bad_alloc&) { return 0; //not enough memory } for (unsigned i=0; i<numberOfIndexes; ++i) { assert(pointIndexes->getPointGlobalIndex(i) < numberOfPoints); newPointIndexes[pointIndexes->getPointGlobalIndex(i)] = i+1; } } //negative array for the case where input points are "outside" if (!pointsWillBeInside) { unsigned newIndex = 0; for (unsigned i=0;i<numberOfPoints;++i) newPointIndexes[i] = (newPointIndexes[i] == 0 ? ++newIndex : 0); } //create resulting mesh SimpleMesh* newMesh = 0; { unsigned numberOfTriangles = theMesh->size(); //progress notification NormalizedProgress* nprogress = 0; if (progressCb) { progressCb->reset(); progressCb->setMethodTitle("Extract mesh"); char buffer[256]; sprintf(buffer,"New vertex number: %u",numberOfIndexes); nprogress = new NormalizedProgress(progressCb,numberOfTriangles); progressCb->setInfo(buffer); progressCb->start(); } newMesh = new SimpleMesh(destCloud ? destCloud : pointIndexes->getAssociatedCloud()); unsigned count = 0; theMesh->placeIteratorAtBegining(); for (unsigned i=0; i<numberOfTriangles; ++i) { bool triangleIsOnTheRightSide = true; const VerticesIndexes* tsi = theMesh->getNextTriangleVertIndexes(); //DGM: getNextTriangleVertIndexes is faster for mesh groups! int newVertexIndexes[3]; //VERSION: WE KEEP THE TRIANGLE ONLY IF ITS 3 VERTICES ARE INSIDE for (uchar j=0;j <3; ++j) { const unsigned& currentVertexFlag = newPointIndexes[tsi->i[j]]; //if the vertex is rejected, we discard this triangle if (currentVertexFlag == 0) { triangleIsOnTheRightSide = false; break; } newVertexIndexes[j] = currentVertexFlag-1; } //if we keep the triangle if (triangleIsOnTheRightSide) { if (count == newMesh->size() && !newMesh->reserve(newMesh->size() + 1000)) //auto expand mesh size { //stop process delete newMesh; newMesh = 0; break; } ++count; newMesh->addTriangle( indexShift + newVertexIndexes[0], indexShift + newVertexIndexes[1], indexShift + newVertexIndexes[2] ); } if (nprogress && !nprogress->oneStep()) { //cancel process break; } } if (nprogress) { delete nprogress; nprogress = 0; } if (newMesh) { if (newMesh->size() == 0) { delete newMesh; newMesh = 0; } else if (count < newMesh->size()) { newMesh->resize(count); //should always be ok as count<maxNumberOfTriangles } } } return newMesh; }
GenericIndexedMesh* Neighbourhood::triangulateFromQuadric(unsigned nStepX, unsigned nStepY) { if (nStepX<2 || nStepY<2) return 0; //qaudric fit const PointCoordinateType* Q = getQuadric(); //Q: Z = a + b.X + c.Y + d.X^2 + e.X.Y + f.Y^2 if (!Q) return 0; const PointCoordinateType& a = Q[0]; const PointCoordinateType& b = Q[1]; const PointCoordinateType& c = Q[2]; const PointCoordinateType& d = Q[3]; const PointCoordinateType& e = Q[4]; const PointCoordinateType& f = Q[5]; const uchar X = m_quadricEquationDirections.x; const uchar Y = m_quadricEquationDirections.y; const uchar Z = m_quadricEquationDirections.z; //gravity center (should be ok if the quadric is ok) const CCVector3* G = getGravityCenter(); assert(G); //bounding box CCVector3 bbMin, bbMax; m_associatedCloud->getBoundingBox(bbMin,bbMax); CCVector3 bboxDiag = bbMax - bbMin; //Sample points on Quadric and triangulate them! PointCoordinateType spanX = bboxDiag.u[X]; PointCoordinateType spanY = bboxDiag.u[Y]; PointCoordinateType stepX = spanX/(nStepX-1); PointCoordinateType stepY = spanY/(nStepY-1); ChunkedPointCloud* vertices = new ChunkedPointCloud(); if (!vertices->reserve(nStepX*nStepY)) { delete vertices; return 0; } SimpleMesh* quadMesh = new SimpleMesh(vertices,true); if (!quadMesh->reserve((nStepX-1)*(nStepY-1)*2)) { delete quadMesh; return 0; } for (unsigned x=0; x<nStepX; ++x) { CCVector3 P; P.x = bbMin[X] + stepX * x - G->u[X]; for (unsigned y=0; y<nStepY; ++y) { P.y = bbMin[Y] + stepY * y - G->u[Y]; P.z = a+b*P.x+c*P.y+d*P.x*P.x+e*P.x*P.y+f*P.y*P.y; CCVector3 Pc; Pc.u[X] = P.x; Pc.u[Y] = P.y; Pc.u[Z] = P.z; Pc += *G; vertices->addPoint(Pc); if (x>0 && y>0) { unsigned iA = (x-1) * nStepY + y-1; unsigned iB = iA+1; unsigned iC = iA+nStepY; unsigned iD = iB+nStepY; quadMesh->addTriangle(iA,iC,iB); quadMesh->addTriangle(iB,iC,iD); } } } return quadMesh; }
void Implicit::Render() { // Draw bounding box for debugging Bbox b = GetBoundingBox(); Vector3<float> & v0 = b.pMin; Vector3<float> & v1 = b.pMax; if(mSelected) { glLineWidth(2.0f); glColor3f(0.8f,0.8f,0.8f); } else glColor3f(0.1f,0.1f,0.1f); glBegin(GL_LINE_STRIP); glVertex3f(v0[0], v0[1], v0[2]); glVertex3f(v1[0], v0[1], v0[2]); glVertex3f(v1[0], v1[1], v0[2]); glVertex3f(v0[0], v1[1], v0[2]); glVertex3f(v0[0], v0[1], v0[2]); glEnd(); glBegin(GL_LINE_STRIP); glVertex3f(v0[0], v0[1], v1[2]); glVertex3f(v1[0], v0[1], v1[2]); glVertex3f(v1[0], v1[1], v1[2]); glVertex3f(v0[0], v1[1], v1[2]); glVertex3f(v0[0], v0[1], v1[2]); glEnd(); glBegin(GL_LINES); glVertex3f(v0[0], v0[1], v0[2]); glVertex3f(v0[0], v0[1], v1[2]); glVertex3f(v1[0], v0[1], v0[2]); glVertex3f(v1[0], v0[1], v1[2]); glVertex3f(v0[0], v1[1], v0[2]); glVertex3f(v0[0], v1[1], v1[2]); glVertex3f(v1[0], v1[1], v0[2]); glVertex3f(v1[0], v1[1], v1[2]); glEnd(); glLineWidth(1.0f); glPushMatrix(); glMultMatrixf(mTransform.ToGLMatrix().GetArrayPtr()); Geometry * mesh = dynamic_cast<Geometry *>(mMesh); if (mesh == NULL) std::cerr << "Error: implicit geometry not triangulated, add call to triangulate()" << std::endl; else { mesh->SetShowNormals(mShowNormals); mesh->SetWireframe(mWireframe); mesh->SetOpacity(mOpacity); mesh->Render(); } if (mVisualizationMode == Gradients) { if(typeid(*mMesh) == typeid(SimpleMesh)){ SimpleMesh * ptr = static_cast<SimpleMesh*>(mMesh); const std::vector<SimpleMesh::Vertex>& verts = ptr->GetVerts(); glDisable(GL_LIGHTING); Matrix4x4<float> M = GetTransform().Transpose(); glColor3f(0, 0, 1); glBegin(GL_LINES); for(unsigned int i=0; i < verts.size(); i++){ const Vector3<float> vObject = verts.at(i).pos; // Transform vertex position to world space Vector4<float> vWorld = GetTransform() * Vector4<float>(vObject[0],vObject[1],vObject[2],1); // Get gradient in world space Vector3<float> nWorld = GetGradient(vWorld[0], vWorld[1], vWorld[2]); // Transform gradient to object space Vector4<float> nObject = M * Vector4<float>(nWorld[0],nWorld[1],nWorld[2],0); Vector3<float> n = Vector3<float>(nObject[0], nObject[1], nObject[2]); glVertex3fv(vObject.GetArrayPtr()); glVertex3fv((vObject + n*0.1).GetArrayPtr()); } glEnd(); } else { std::cerr << "No Gradient visualization mode implemented for mesh type: " << typeid(*mMesh).name() << std::endl; } } glPopMatrix(); GLObject::Render(); }
static void SC_updateSimpleMesh(RsSimpleMesh mesh) { GET_TLS(); SimpleMesh *sm = static_cast<SimpleMesh *>(mesh); sm->uploadAll(rsc); }