예제 #1
0
//-----------------------------------------------------------------------------
// 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();
}
예제 #2
0
파일: Mesh.hpp 프로젝트: pmoulon/DO-CV
 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);
}
예제 #5
0
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;
}
예제 #6
0
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;
}
예제 #9
0
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;
}
예제 #10
0
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);
}