Пример #1
0
std::vector<float> getComboItemAsStdFloatVector(ComboItemDescriptor desc, const ccPointCloud* cloud)
{
    int n = cloud->size();
    std::vector<float> v;
    v.resize(n);
    v.reserve(n);
    if (desc.type == ComboItemDescriptor::COORDINATE)
    {
        CCVector3 point;
        for (int i = 0; i < n; i++)
        {
            cloud->getPoint(i, point);
            v[i] = point[desc.index_in_cloud];
        }
    }
    else if (desc.type == ComboItemDescriptor::SCALAR)
    {
        CCLib::ScalarField * field = cloud->getScalarField(desc.index_in_cloud);
        for (int i = 0; i < n; i++)
            v[i] = field->getValue(i);

    }



    return v;
}
Пример #2
0
void copyScalarFields(const ccPointCloud *inCloud, ccPointCloud *outCloud, pcl::PointIndicesPtr &in2outMapping, bool overwrite = true)
{
    int n_in = inCloud->size();
    int n_out = outCloud->size();
    assert(in2outMapping->indices.size() == outCloud->size());

    int n_scalars = inCloud->getNumberOfScalarFields();
    for (int i = 0; i < n_scalars; ++i)
      {
        CCLib::ScalarField * field = inCloud->getScalarField(i);
        const char * name = field->getName();

        //we need to verify no scalar field with the same name exists in the output cloud
        int id = outCloud->getScalarFieldIndexByName(name);
        ccScalarField * new_field = new ccScalarField;

        //resize the scalar field to the outcloud size
        new_field->reserve(outCloud->size());
        new_field->setName(name);

        if (id >= 0) //a scalar field with the same name exists
          {
           if (overwrite)
               outCloud->deleteScalarField(id);
           else
              break;
          }


        //now perform point to point copy
        for (unsigned int j = 0; j < outCloud->size(); ++j)
          {
            new_field->setValue(j, field->getValue(in2outMapping->indices.at(j)));
          }


        //recompute stats
        new_field->computeMinAndMax();
        ccScalarField * casted_field = static_cast<ccScalarField *> (new_field);
        casted_field->computeMinAndMax();



        //now put back the scalar field to the outCloud
        if (id < 0)
          outCloud->addScalarField(casted_field);


      }
}
Пример #3
0
static int scalar_cb(p_ply_argument argument)
{
	CCLib::ScalarField* sf = 0;
	ply_get_argument_user_data(argument, (void**)(&sf), NULL);

	p_ply_element element;
	long instance_index;
	ply_get_argument_element(argument, &element, &instance_index);

	ScalarType scal = static_cast<ScalarType>(ply_get_argument_value(argument));
	sf->setValue(instance_index,scal);

	if ((++s_totalScalarCount % PROCESS_EVENTS_FREQ) == 0)
		QCoreApplication::processEvents();

	return 1;
}
Пример #4
0
bool cc2Point5DimEditor::RasterGrid::fillWith(	ccGenericPointCloud* cloud,
												unsigned char projectionDimension,
												cc2Point5DimEditor::ProjectionType projectionType,
												bool interpolateEmptyCells,
												cc2Point5DimEditor::ProjectionType sfInterpolation/*=INVALID_PROJECTION_TYPE*/,
												ccProgressDialog* progressDialog/*=0*/)
{
	if (!cloud)
	{
		assert(false);
		return false;
	}

	//current parameters
	unsigned gridTotalSize = width * height;
	
	//vertical dimension
	const unsigned char Z = projectionDimension;
	assert(Z >= 0 && Z <= 2);
	const unsigned char X = Z == 2 ? 0 : Z +1;
	const unsigned char Y = X == 2 ? 0 : X +1;

	//do we need to interpolate scalar fields?
	ccPointCloud* pc = cloud->isA(CC_TYPES::POINT_CLOUD) ? static_cast<ccPointCloud*>(cloud) : 0;
	bool interpolateSF = (sfInterpolation != INVALID_PROJECTION_TYPE);
	interpolateSF &= (pc && pc->hasScalarFields());
	if (interpolateSF)
	{
		unsigned sfCount = pc->getNumberOfScalarFields();

		bool memoryError = false;
		size_t previousCount = scalarFields.size();
		if (sfCount > previousCount)
		{
			try
			{
				scalarFields.resize(sfCount,0);
			}
			catch (const std::bad_alloc&)
			{
				//not enough memory
				memoryError = true;
			}
		}

		for (size_t i=previousCount; i<sfCount; ++i)
		{
			assert(scalarFields[i] == 0);
			scalarFields[i] = new double[gridTotalSize];
			if (!scalarFields[i])
			{
				//not enough memory
				memoryError = true;
				break;
			}
		}

		if (memoryError)
		{
			ccLog::Warning(QString("[Rasterize] Failed to allocate memory for scalar fields!"));
		}
	}

	//filling the grid
	unsigned pointCount = cloud->size();

	double gridMaxX = gridStep * width;
	double gridMaxY = gridStep * height;

	if (progressDialog)
	{
		progressDialog->setMethodTitle("Grid generation");
		progressDialog->setInfo(qPrintable(QString("Points: %1\nCells: %2 x %3").arg(pointCount).arg(width).arg(height)));
		progressDialog->start();
		progressDialog->show();
		QCoreApplication::processEvents();
	}
	CCLib::NormalizedProgress nProgress(progressDialog,pointCount);

	for (unsigned n=0; n<pointCount; ++n)
	{
		const CCVector3* P = cloud->getPoint(n);

		CCVector3d relativePos = CCVector3d::fromArray(P->u) - minCorner;
		int i = static_cast<int>(relativePos.u[X]/gridStep);
		int j = static_cast<int>(relativePos.u[Y]/gridStep);

		//specific case: if we fall exactly on the max corner of the grid box
		if (i == static_cast<int>(width) && relativePos.u[X] == gridMaxX)
			--i;
		if (j == static_cast<int>(height) && relativePos.u[Y] == gridMaxY)
			--j;

		//we skip points outside the box!
		if (	i < 0 || i >= static_cast<int>(width)
			||	j < 0 || j >= static_cast<int>(height) )
			continue;

		assert(i >= 0 && j >= 0);

		RasterCell* aCell = data[j]+i;
		unsigned& pointsInCell = aCell->nbPoints;
		if (pointsInCell)
		{
			if (P->u[Z] < aCell->minHeight)
			{
				aCell->minHeight = P->u[Z];
				if (projectionType == PROJ_MINIMUM_VALUE)
					aCell->pointIndex = n;
			}
			else if (P->u[Z] > aCell->maxHeight)
			{
				aCell->maxHeight = P->u[Z];
				if (projectionType == PROJ_MAXIMUM_VALUE)
					aCell->pointIndex = n;
			}
		}
		else
		{
			aCell->minHeight = aCell->maxHeight = P->u[Z];
			aCell->pointIndex = n;
		}
		// Sum the points heights
		aCell->avgHeight += P->u[Z];
		aCell->stdDevHeight += static_cast<double>(P->u[Z])*P->u[Z];

		//scalar fields
		if (interpolateSF)
		{
			int pos = j*static_cast<int>(width)+i; //pos in 2D SF grid(s)
			assert(pos < static_cast<int>(gridTotalSize));
			for (size_t k=0; k<scalarFields.size(); ++k)
			{
				if (scalarFields[k])
				{
					CCLib::ScalarField* sf = pc->getScalarField(static_cast<unsigned>(k));
					assert(sf);
					ScalarType sfValue = sf->getValue(n);
					ScalarType formerValue = static_cast<ScalarType>(scalarFields[k][pos]);

					if (pointsInCell && ccScalarField::ValidValue(formerValue))
					{
						if (ccScalarField::ValidValue(sfValue))
						{
							switch (sfInterpolation)
							{
							case PROJ_MINIMUM_VALUE:
								// keep the minimum value
								scalarFields[k][pos] = std::min<double>(formerValue,sfValue);
								break;
							case PROJ_AVERAGE_VALUE:
								//we sum all values (we will divide them later)
								scalarFields[k][pos] += sfValue;
								break;
							case PROJ_MAXIMUM_VALUE:
								// keep the maximum value
								scalarFields[k][pos] = std::max<double>(formerValue,sfValue);
								break;
							default:
								assert(false);
								break;
							}
						}
					}
					else
					{
						//for the first (vaild) point, we simply have to store its SF value (in any case)
						scalarFields[k][pos] = sfValue;
					}
				}
			}
		}

		pointsInCell++;

		if (!nProgress.oneStep())
		{
			//process cancelled by user
			return false;
		}
	}

	//update SF grids for 'average' cases
	if (sfInterpolation == PROJ_AVERAGE_VALUE)
	{
		for (size_t k=0; k<scalarFields.size(); ++k)
		{
			if (scalarFields[k])
			{
				double* _gridSF = scalarFields[k];
				for (unsigned j=0;j<height;++j)
				{
					RasterCell* cell = data[j];
					for (unsigned i=0; i<width; ++i,++cell,++_gridSF)
					{
						if (cell->nbPoints > 1)
						{
							ScalarType s = static_cast<ScalarType>(*_gridSF);
							if (ccScalarField::ValidValue(s)) //valid SF value
							{
								*_gridSF /= cell->nbPoints;
							}
						}
					}
				}
			}
		}
	}

	//update the main grid (average height and std.dev. computation + current 'height' value)
	{
		for (unsigned j=0; j<height; ++j)
		{
			RasterCell* cell = data[j];
			for (unsigned i=0; i<width; ++i,++cell)
			{
				if (cell->nbPoints > 1)
				{
					cell->avgHeight /= cell->nbPoints;
					cell->stdDevHeight = sqrt(fabs(cell->stdDevHeight/cell->nbPoints - cell->avgHeight*cell->avgHeight));
				}
				else
				{
					cell->stdDevHeight = 0;
				}

				if (cell->nbPoints != 0)
				{
					//set the right 'height' value
					switch (projectionType)
					{
					case PROJ_MINIMUM_VALUE:
						cell->h = cell->minHeight;
						break;
					case PROJ_AVERAGE_VALUE:
						cell->h = cell->avgHeight;
						break;
					case PROJ_MAXIMUM_VALUE:
						cell->h = cell->maxHeight;
						break;
					default:
						assert(false);
						break;
					}
				}
			}
		}
	}

	//compute the number of non empty cells
	nonEmptyCellCount = 0;
	{
		for (unsigned i=0; i<height; ++i)
			for (unsigned j=0; j<width; ++j)
				if (data[i][j].nbPoints)
					++nonEmptyCellCount;
	}

	//specific case: interpolate the empty cells
	if (interpolateEmptyCells)
	{
		std::vector<CCVector2> the2DPoints;
		if (nonEmptyCellCount < 3)
		{
			ccLog::Warning("[Rasterize] Not enough non-empty cells to interpolate!");
		}
		else if (nonEmptyCellCount < width * height) //otherwise it's useless!
		{
			try
			{
				the2DPoints.resize(nonEmptyCellCount);
			}
			catch (const std::bad_alloc&)
			{
				//out of memory
				ccLog::Warning("[Rasterize] Not enough memory to interpolate empty cells!");
			}
		}

		//fill 2D vector with non-empty cell indexes
		if (!the2DPoints.empty())
		{
			unsigned index = 0;
			for (unsigned j=0; j<height; ++j)
			{
				const RasterCell* cell = data[j];
				for (unsigned i=0; i<width; ++i, ++cell)
				{
					if (cell->nbPoints)
					{
						//we only use the non-empty cells to interpolate
						the2DPoints[index++] = CCVector2(static_cast<PointCoordinateType>(i),static_cast<PointCoordinateType>(j));
					}
				}
			}
			assert(index == nonEmptyCellCount);

			//mesh the '2D' points
			CCLib::Delaunay2dMesh delaunayMesh;
			char errorStr[1024];
			if (delaunayMesh.buildMesh(the2DPoints,0,errorStr))
			{
				unsigned triNum = delaunayMesh.size();
				//now we are going to 'project' all triangles on the grid
				delaunayMesh.placeIteratorAtBegining();
				for (unsigned k=0; k<triNum; ++k)
				{
					const CCLib::VerticesIndexes* tsi = delaunayMesh.getNextTriangleVertIndexes();
					//get the triangle bounding box (in grid coordinates)
					int P[3][2];
					int xMin = 0, yMin = 0, xMax = 0, yMax = 0;
					{
						for (unsigned j=0; j<3; ++j)
						{
							const CCVector2& P2D = the2DPoints[tsi->i[j]];
							P[j][0] = static_cast<int>(P2D.x);
							P[j][1] = static_cast<int>(P2D.y);
						}
						xMin = std::min(std::min(P[0][0],P[1][0]),P[2][0]);
						yMin = std::min(std::min(P[0][1],P[1][1]),P[2][1]);
						xMax = std::max(std::max(P[0][0],P[1][0]),P[2][0]);
						yMax = std::max(std::max(P[0][1],P[1][1]),P[2][1]);
					}
					//now scan the cells
					{
						//pre-computation for barycentric coordinates
						const double& valA = data[ P[0][1] ][ P[0][0] ].h;
						const double& valB = data[ P[1][1] ][ P[1][0] ].h;
						const double& valC = data[ P[2][1] ][ P[2][0] ].h;

						int det = (P[1][1]-P[2][1])*(P[0][0]-P[2][0]) + (P[2][0]-P[1][0])*(P[0][1]-P[2][1]);

						for (int j=yMin; j<=yMax; ++j)
						{
							RasterCell* cell = data[static_cast<unsigned>(j)];

							for (int i=xMin; i<=xMax; ++i)
							{
								//if the cell is empty
								if (!cell[i].nbPoints)
								{
									//we test if it's included or not in the current triangle
									//Point Inclusion in Polygon Test (inspired from W. Randolph Franklin - WRF)
									bool inside = false;
									for (int ti=0; ti<3; ++ti)
									{
										const int* P1 = P[ti];
										const int* P2 = P[(ti+1)%3];
										if ((P2[1] <= j &&j < P1[1]) || (P1[1] <= j && j < P2[1]))
										{
											int t = (i-P2[0])*(P1[1]-P2[1])-(P1[0]-P2[0])*(j-P2[1]);
											if (P1[1] < P2[1])
												t = -t;
											if (t < 0)
												inside = !inside;
										}
									}
									//can we interpolate?
									if (inside)
									{
										double l1 = static_cast<double>((P[1][1]-P[2][1])*(i-P[2][0])+(P[2][0]-P[1][0])*(j-P[2][1]))/det;
										double l2 = static_cast<double>((P[2][1]-P[0][1])*(i-P[2][0])+(P[0][0]-P[2][0])*(j-P[2][1]))/det;
										double l3 = 1.0-l1-l2;

										cell[i].h = l1 * valA + l2 * valB + l3 * valC;
										assert(cell[i].h == cell[i].h);

										//interpolate SFs as well!
										for (size_t sfIndex=0; sfIndex<scalarFields.size(); ++sfIndex)
										{
											if (scalarFields[sfIndex])
											{
												double* gridSF = scalarFields[sfIndex];
												const double& sfValA = gridSF[ P[0][0] + P[0][1]*width ];
												const double& sfValB = gridSF[ P[1][0] + P[1][1]*width ];
												const double& sfValC = gridSF[ P[2][0] + P[2][1]*width ];
												gridSF[i + j*width] = l1 * sfValA + l2 * sfValB + l3 * sfValC;
											}
										}
									}
								}
							}
						}
					}
				}
			}
			else
			{
				ccLog::Warning(QString("[Rasterize] Empty cells interpolation failed: Triangle lib. said '%1'").arg(errorStr));
			}
		}
	}

	//computation of the average and extreme height values in the grid
	{
		minHeight = 0;
		maxHeight = 0;
		meanHeight = 0;
		validCellCount = 0;

		for (unsigned i=0; i<height; ++i)
		{
			for (unsigned j=0; j<width; ++j)
			{
				if (data[i][j].h == data[i][j].h) //valid height
				{
					double h = data[i][j].h;

					if (validCellCount)
					{
						if (h < minHeight)
							minHeight = h;
						else if (h > maxHeight)
							maxHeight = h;
						
						meanHeight += h;
					}
					else
					{
						//first valid cell
						meanHeight = minHeight = maxHeight = h;
					}
					++validCellCount;
				}
			}
		}
		meanHeight /= validCellCount;
	}

	setValid(true);

	return true;
}
Пример #5
0
CC_FILE_ERROR LASFilter::saveToFile(ccHObject* entity, const char* filename)
{
	if (!entity || !filename)
		return CC_FERR_BAD_ARGUMENT;

	ccHObject::Container clouds;
	if (entity->isKindOf(CC_POINT_CLOUD))
		clouds.push_back(entity);
	else
		entity->filterChildren(clouds, true, CC_POINT_CLOUD);

	if (clouds.empty())
	{
		ccConsole::Error("No point cloud in input selection!");
		return CC_FERR_BAD_ENTITY_TYPE;
	}
	else if (clouds.size()>1)
	{
		ccConsole::Error("Can't save more than one cloud per LAS file!");
		return CC_FERR_BAD_ENTITY_TYPE;
	}

	//the cloud to save
	ccGenericPointCloud* theCloud = static_cast<ccGenericPointCloud*>(clouds[0]);
	unsigned numberOfPoints = theCloud->size();

	if (numberOfPoints==0)
	{
		ccConsole::Error("Cloud is empty!");
		return CC_FERR_BAD_ENTITY_TYPE;
	}

	//colors
	bool hasColor = theCloud->hasColors();

	//additional fields (as scalar fields)
	CCLib::ScalarField* classifSF = 0;
	CCLib::ScalarField* intensitySF = 0;
	CCLib::ScalarField* timeSF = 0;
	CCLib::ScalarField* returnNumberSF = 0;

	if (theCloud->isA(CC_POINT_CLOUD))
	{
		ccPointCloud* pc = static_cast<ccPointCloud*>(theCloud);

		//Classification
		{
			int sfIdx = pc->getScalarFieldIndexByName(CC_LAS_CLASSIFICATION_FIELD_NAME);
			if (sfIdx>=0)
			{
				classifSF = pc->getScalarField(sfIdx);
				assert(classifSF);
				if ((int)classifSF->getMin()<0 || (int)classifSF->getMax()>255) //outbounds unsigned char?
				{
					ccConsole::Warning("[LASFilter] Found a 'Classification' scalar field, but its values outbound LAS specifications (0-255)...");
					classifSF = 0;
				}
			}
		}
		//Classification end

		//intensity (as a scalar field)
		{
			int sfIdx = pc->getScalarFieldIndexByName(CC_SCAN_INTENSITY_FIELD_NAME);
			if (sfIdx>=0)
			{
				intensitySF = pc->getScalarField(sfIdx);
				assert(intensitySF);
				if ((int)intensitySF->getMin()<0 || (int)intensitySF->getMax()>65535) //outbounds unsigned short?
				{
					ccConsole::Warning("[LASFilter] Found a 'Intensity' scalar field, but its values outbound LAS specifications (0-65535)...");
					intensitySF = 0;
				}
			}
		}
		//Intensity end

		//Time (as a scalar field)
		{
			int sfIdx = pc->getScalarFieldIndexByName(CC_SCAN_TIME_FIELD_NAME);
			if (sfIdx>=0)
			{
				timeSF = pc->getScalarField(sfIdx);
				assert(timeSF);
			}
		}
		//Time end

		//Return number (as a scalar field)
		{
			int sfIdx = pc->getScalarFieldIndexByName(CC_SCAN_RETURN_INDEX_FIELD_NAME);
			if (sfIdx>=0)
			{
				returnNumberSF = pc->getScalarField(sfIdx);
				assert(returnNumberSF);
				if ((int)returnNumberSF->getMin()<0 || (int)returnNumberSF->getMax()>7) //outbounds 3 bits?
				{
					ccConsole::Warning("[LASFilter] Found a 'Return number' scalar field, but its values outbound LAS specifications (0-7)...");
					returnNumberSF = 0;
				}
			}
		}
		//Return number end
	}

	//open binary file for writing
	std::ofstream ofs;
	ofs.open(filename, std::ios::out | std::ios::binary);

	if (ofs.fail())
		return CC_FERR_WRITING;

	const double* shift = theCloud->getOriginalShift();

	liblas::Writer* writer = 0;
	try
	{
		liblas::Header header;

		//LAZ support based on extension!
		if (QFileInfo(filename).suffix().toUpper() == "LAZ")
		{
			header.SetCompressed(true);
		}

		//header.SetDataFormatId(liblas::ePointFormat3);
		ccBBox bBox = theCloud->getBB();
		if (bBox.isValid())
		{
			header.SetMin(-shift[0]+(double)bBox.minCorner().x,-shift[1]+(double)bBox.minCorner().y,-shift[2]+(double)bBox.minCorner().z);
			header.SetMax(-shift[0]+(double)bBox.maxCorner().x,-shift[1]+(double)bBox.maxCorner().y,-shift[2]+(double)bBox.maxCorner().z);
			CCVector3 diag = bBox.getDiagVec();

			//Set offset & scale, as points will be stored as boost::int32_t values (between 0 and 4294967296)
			//int_value = (double_value-offset)/scale
			header.SetOffset(-shift[0]+(double)bBox.minCorner().x,-shift[1]+(double)bBox.minCorner().y,-shift[2]+(double)bBox.minCorner().z);
			header.SetScale(1.0e-9*std::max<double>(diag.x,ZERO_TOLERANCE), //result must fit in 32bits?!
				1.0e-9*std::max<double>(diag.y,ZERO_TOLERANCE),
				1.0e-9*std::max<double>(diag.z,ZERO_TOLERANCE));
		}
		header.SetPointRecordsCount(numberOfPoints);
		//header.SetDataFormatId(Header::ePointFormat1);

		writer = new liblas::Writer(ofs, header);
	}
	catch (...)
	{
		return CC_FERR_WRITING;
	}

	//progress dialog
	ccProgressDialog pdlg(true); //cancel available
	CCLib::NormalizedProgress nprogress(&pdlg,numberOfPoints);
	pdlg.setMethodTitle("Save LAS file");
	char buffer[256];
	sprintf(buffer,"Points: %i",numberOfPoints);
	pdlg.setInfo(buffer);
	pdlg.start();

	//liblas::Point point(boost::shared_ptr<liblas::Header>(new liblas::Header(writer->GetHeader())));
	liblas::Point point(&writer->GetHeader());

	for (unsigned i=0; i<numberOfPoints; i++)
	{
		const CCVector3* P = theCloud->getPoint(i);
		{
			double x=-shift[0]+(double)P->x;
			double y=-shift[1]+(double)P->y;
			double z=-shift[2]+(double)P->z;
			point.SetCoordinates(x, y, z);
		}
		if (hasColor)
		{
			const colorType* rgb = theCloud->getPointColor(i);
			point.SetColor(liblas::Color(rgb[0]<<8,rgb[1]<<8,rgb[2]<<8)); //DGM: LAS colors are stored on 16 bits!
		}

		if (classifSF)
		{
			liblas::Classification classif;
			classif.SetClass((boost::uint32_t)classifSF->getValue(i));
			point.SetClassification(classif);
		}

		if (intensitySF)
		{
			point.SetIntensity((boost::uint16_t)intensitySF->getValue(i));
		}

		if (timeSF)
		{
			point.SetTime((double)timeSF->getValue(i));
		}

		if (returnNumberSF)
		{
			point.SetReturnNumber((boost::uint16_t)returnNumberSF->getValue(i));
			point.SetNumberOfReturns((boost::uint16_t)returnNumberSF->getMax());
		}

		writer->WritePoint(point);

		if (!nprogress.oneStep())
			break;
	}

	delete writer;
	//ofs.close();

	return CC_FERR_NO_ERROR;
}
Пример #6
0
CC_FILE_ERROR PVFilter::loadFile(QString filename, ccHObject& container, LoadParameters& parameters)
{
	//opening file
	QFile in(filename);
	if (!in.open(QIODevice::ReadOnly))
		return CC_FERR_READING;

	//we deduce the points number from the file size
	qint64 fileSize = in.size();
	qint64 singlePointSize = 4*sizeof(float);
	//check that size is ok
	if (fileSize == 0)
		return CC_FERR_NO_LOAD;
	if ((fileSize % singlePointSize) != 0)
		return CC_FERR_MALFORMED_FILE;
	unsigned numberOfPoints = static_cast<unsigned>(fileSize  / singlePointSize);

	//progress dialog
	ccProgressDialog pdlg(true); //cancel available
	CCLib::NormalizedProgress nprogress(&pdlg,numberOfPoints);
	pdlg.setMethodTitle("Open PV file");
	pdlg.setInfo(qPrintable(QString("Points: %1").arg(numberOfPoints)));
	pdlg.start();

	ccPointCloud* loadedCloud = 0;
	//if the file is too big, it will be chuncked in multiple parts
	unsigned chunkIndex = 0;
	unsigned fileChunkPos = 0;
	unsigned fileChunkSize = 0;
	//number of points read for the current cloud part
	unsigned pointsRead = 0;
	CC_FILE_ERROR result = CC_FERR_NO_ERROR;

	for (unsigned i=0;i<numberOfPoints;i++)
	{
		//if we reach the max. cloud size limit, we cerate a new chunk
		if (pointsRead == fileChunkPos+fileChunkSize)
		{
			if (loadedCloud)
			{
				int sfIdx = loadedCloud->getCurrentInScalarFieldIndex();
				if (sfIdx>=0)
				{
					CCLib::ScalarField* sf = loadedCloud->getScalarField(sfIdx);
					sf->computeMinAndMax();
					loadedCloud->setCurrentDisplayedScalarField(sfIdx);
					loadedCloud->showSF(true);
				}
				container.addChild(loadedCloud);
			}
			fileChunkPos = pointsRead;
			fileChunkSize = std::min<unsigned>(numberOfPoints-pointsRead,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD);
			loadedCloud = new ccPointCloud(QString("unnamed - Cloud #%1").arg(++chunkIndex));
			if (!loadedCloud || !loadedCloud->reserveThePointsTable(fileChunkSize) || !loadedCloud->enableScalarField())
			{
				result = CC_FERR_NOT_ENOUGH_MEMORY;
				if (loadedCloud)
					delete loadedCloud;
				loadedCloud=0;
				break;
			}
		}

		//we read the 3 coordinates of the point
		float rBuff[3];
		if (in.read((char*)rBuff,3*sizeof(float))>=0)
		{
			//conversion to CCVector3
			CCVector3 P((PointCoordinateType)rBuff[0],
						(PointCoordinateType)rBuff[1],
						(PointCoordinateType)rBuff[2]);
			loadedCloud->addPoint(P);
		}
		else
		{
			result = CC_FERR_READING;
			break;
		}

		//then the scalar value
		if (in.read((char*)rBuff,sizeof(float))>=0)
		{
			loadedCloud->setPointScalarValue(pointsRead,(ScalarType)rBuff[0]);
		}
		else
		{
			//add fake scalar value for consistency then break
			loadedCloud->setPointScalarValue(pointsRead,0);
			result = CC_FERR_READING;
			break;
		}

		++pointsRead;

		if (!nprogress.oneStep())
		{
			result = CC_FERR_CANCELED_BY_USER;
			break;
		}
	}

	in.close();

	if (loadedCloud)
	{
		if (loadedCloud->size() < loadedCloud->capacity())
			loadedCloud->resize(loadedCloud->size());
		int sfIdx = loadedCloud->getCurrentInScalarFieldIndex();
		if (sfIdx>=0)
		{
			CCLib::ScalarField* sf = loadedCloud->getScalarField(sfIdx);
			sf->computeMinAndMax();
			loadedCloud->setCurrentDisplayedScalarField(sfIdx);
			loadedCloud->showSF(true);
		}
		container.addChild(loadedCloud);
	}

	return result;
}
Пример #7
0
CC_FILE_ERROR PlyFilter::loadFile(const char* filename, ccHObject& container, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, double* coordinatesShift/*=0*/)
{
	//reset statics!
	s_triCount = 0;
	s_unsupportedPolygonType = false;
	s_scalarCount=0;
	s_IntensityCount=0;
	s_ColorCount=0;
	s_NormalCount=0;
	s_PointCount=0;
	s_PointDataCorrupted=false;
	s_AlwaysDisplayLoadDialog=alwaysDisplayLoadDialog;
	s_ShiftApplyAll=false;
	s_ShiftAlreadyEnabled = (coordinatesShiftEnabled && *coordinatesShiftEnabled && coordinatesShift);
	if (s_ShiftAlreadyEnabled)
		memcpy(s_Pshift,coordinatesShift,sizeof(double)*3);
	else
		memset(s_Pshift,0,sizeof(double)*3);

    /****************/
	/***  Header  ***/
    /****************/

	//open a PLY file for reading
        p_ply ply = ply_open(filename,NULL, 0, NULL);
	if (!ply)
        return CC_FERR_READING;

	ccConsole::PrintDebug("[PLY] Opening file '%s' ...",filename);

	if (!ply_read_header(ply))
	{
	    ply_close(ply);
	    return CC_FERR_WRONG_FILE_TYPE;
	}

    //storage mode: little/big endian
	e_ply_storage_mode storage_mode;
	get_plystorage_mode(ply,&storage_mode);

    /******************/
	/***  Comments  ***/
    /******************/

	//display comments
	const char* lastComment = NULL;
	while ((lastComment = ply_get_next_comment(ply, lastComment)))
		ccConsole::Print("[PLY][Comment] %s",lastComment);

    /*******************************/
	/***  Elements & properties  ***/
    /*******************************/

	//Point-based elements (points, colors, normals, etc.)
	std::vector<plyElement> pointElements;
	//Mesh-based elements (vertices, etc.)
	std::vector<plyElement> meshElements;

	//Point-based element properties (coordinates, color components, etc.)
	std::vector<plyProperty> stdProperties;
	//Mesh-based element properties (vertex indexes, etc.)
	std::vector<plyProperty> listProperties;

    unsigned i=0;

    //last read element
	plyElement lastElement;
	lastElement.elem = 0;
	while ((lastElement.elem = ply_get_next_element(ply, lastElement.elem)))
	{
	    //we get next element info
		ply_get_element_info(lastElement.elem, &lastElement.elementName, &lastElement.elementInstances);

		if (lastElement.elementInstances == 0)
		{
			ccConsole::Warning("[PLY] Element '%s' was ignored as it has 0 instance!",lastElement.elementName);
			continue;
		}

		lastElement.properties.clear();
		lastElement.propertiesCount=0;
		lastElement.isList=false;
		//printf("Element: %s\n",lastElement.elementName);

        //last read property
        plyProperty lastProperty;
		lastProperty.prop = 0;
		lastProperty.elemIndex = 0;

		while ((lastProperty.prop = ply_get_next_property(lastElement.elem,lastProperty.prop)))
		{
		    //we get next property info
			ply_get_property_info(lastProperty.prop, &lastProperty.propName, &lastProperty.type, &lastProperty.length_type, &lastProperty.value_type);
            //printf("\tProperty: %s (%s)\n",lastProperty.propName,e_ply_type_names[lastProperty.type]);

            if (lastProperty.type == 16) //PLY_LIST
                lastElement.isList = true;

			lastElement.properties.push_back(lastProperty);
			++lastElement.propertiesCount;
		}

        //if we have a "mesh-like" element
        if (lastElement.isList)
        {
            //we store its properties in 'listProperties'
            for (i=0;i<lastElement.properties.size();++i)
            {
                plyProperty& prop = lastElement.properties[i];
                prop.elemIndex = meshElements.size();

                //we only keep track of lists (we can't handle per triangle scalars)
                if (prop.type == 16)
                    listProperties.push_back(prop);
                else
                {
                    ccConsole::Warning("[PLY] Unhandled property: [%s:%s] (%s)",
                                    lastElement.elementName,
                                    prop.propName,
                                    e_ply_type_names[prop.type]);
                }
            }
            meshElements.push_back(lastElement);
        }
        else    //else if we have a "point-like" element
        {
            //we store its properties in 'stdProperties'
            for (i=0;i<lastElement.properties.size();++i)
            {
                plyProperty& prop = lastElement.properties[i];
                prop.elemIndex = pointElements.size();
                stdProperties.push_back(prop);
            }
            pointElements.push_back(lastElement);
        }
	}

    //We need some points at least!
	if (pointElements.empty())
	{
		ply_close(ply);
		return CC_FERR_NO_LOAD;
	}

    /**********************/
	/***  Objects info  ***/
    /**********************/

	const char* lastObjInfo = NULL;
	while ((lastObjInfo = ply_get_next_obj_info(ply, lastObjInfo)))
		ccConsole::Print("[PLY][Info] %s",lastObjInfo);

    /****************/
	/***  Dialog  ***/
    /****************/

	//properties indexes (0=unassigned)
	static const unsigned nStdProp=11;
	int stdPropIndexes[nStdProp]={0,0,0,0,0,0,0,0,0,0,0};
	int& xIndex = stdPropIndexes[0];
	int& yIndex = stdPropIndexes[1];
	int& zIndex = stdPropIndexes[2];
	int& nxIndex = stdPropIndexes[3];
	int& nyIndex = stdPropIndexes[4];
	int& nzIndex = stdPropIndexes[5];
	int& rIndex = stdPropIndexes[6];
	int& gIndex = stdPropIndexes[7];
	int& bIndex = stdPropIndexes[8];
	int& iIndex = stdPropIndexes[9];
	int& sfIndex = stdPropIndexes[10];

	static const unsigned nListProp=1;
	int listPropIndexes[nListProp]={0};
	int& facesIndex = listPropIndexes[0];

	//Combo box items for standard properties (coordinates, color components, etc.)
	QStringList stdPropsText;
	stdPropsText << QString("None");
    for (i=1; i<=stdProperties.size(); ++i)
    {
        plyProperty& pp = stdProperties[i-1];
        QString itemText = QString("%1 - %2 [%3]").arg(pointElements[pp.elemIndex].elementName).arg(pp.propName).arg(e_ply_type_names[pp.type]);
        assert(pp.type!=16); //we don't want any PLY_LIST here
        stdPropsText << itemText;

		QString elementName = QString(pointElements[pp.elemIndex].elementName).toUpper();
		QString propName = QString(pp.propName).toUpper();

		if (nxIndex == 0 && (propName.contains("NX") || (elementName.contains("NORM") && propName.endsWith("X"))))
			nxIndex = i;
		else if (nyIndex == 0 && (propName.contains("NY") || (elementName.contains("NORM") && propName.endsWith("Y"))))
			nyIndex = i;
		else if (nzIndex == 0 && (propName.contains("NZ") || (elementName.contains("NORM") && propName.endsWith("Z"))))
			nzIndex = i;
		else if (rIndex == 0 && (propName.contains("RED") || (elementName.contains("COL") && propName.endsWith("R"))))
			rIndex = i;
		else if (gIndex == 0 && (propName.contains("GREEN") || (elementName.contains("COL") && propName.endsWith("G"))))
			gIndex = i;
		else if (bIndex == 0 && (propName.contains("BLUE") || (elementName.contains("COL") && propName.endsWith("B"))))
			bIndex = i;
		else if (iIndex == 0 && (propName.contains("INTENSITY") || propName.contains("GRAY") || propName.contains("GREY") || (elementName.contains("COL") && propName.endsWith("I"))))
			iIndex = i;
		else if (elementName.contains("VERT") || elementName.contains("POINT"))
		{
			if (sfIndex == 0 && propName.contains("SCAL"))
				sfIndex = i;
			else if (xIndex == 0 && propName.endsWith("X"))
				xIndex = i;
			else if (yIndex == 0 && propName.endsWith("Y"))
				yIndex = i;
			else if (zIndex == 0 && propName.endsWith("Z"))
				zIndex = i;
		}
		else if (sfIndex == 0 && (propName.contains("SCAL") || propName.contains("VAL")))
			sfIndex = i;
    }

	//Combo box items for list properties (vertex indexes, etc.)
	QStringList listPropsText;
	listPropsText << QString("None");
    for (i=0; i<listProperties.size(); ++i)
    {
        plyProperty& pp = listProperties[i];
        QString itemText = QString("%0 - %1 [%2]").arg(meshElements[pp.elemIndex].elementName).arg(pp.propName).arg(e_ply_type_names[pp.type]);
        assert(pp.type==16); //we only want PLY_LIST here
        listPropsText << itemText;

		QString elementName = QString(meshElements[pp.elemIndex].elementName).toUpper();
		QString propName = QString(pp.propName).toUpper();

		if (facesIndex == 0 && (elementName.contains("FACE") || elementName.contains("TRI")) && propName.contains("IND"))
			facesIndex = i+1;
    }

    //combo-box max visible items
    int stdPropsCount = stdPropsText.count();
    int listPropsCount = listPropsText.count();

	//we need at least 2 coordinates!
	if (stdPropsCount<2)
	{
		return CC_FERR_BAD_ENTITY_TYPE;
	}
	else if (stdPropsCount<4 && !alwaysDisplayLoadDialog)
	{
		//brute force heuristic
		xIndex = 1;
		yIndex = 2;
		zIndex = (stdPropsCount>3 ? 3 : 0);
		facesIndex = (listPropsCount>1 ? 1 : 0);
	}
	else
	{
		//we count all assigned properties
		int assignedStdProperties = 0;
		for (i=0;i<nStdProp;++i)
			if (stdPropIndexes[i]>0)
				++assignedStdProperties;

		int assignedListProperties = 0;
		for (i=0;i<nListProp;++i)
			if (listPropIndexes[i]>0)
				++assignedListProperties;

		if (alwaysDisplayLoadDialog ||
			stdPropsCount > assignedStdProperties+1 ||	//+1 because of the first item in the combo box ('none')
			listPropsCount > assignedListProperties+1)	//+1 because of the first item in the combo box ('none')
		{
			PlyOpenDlg pod/*(MainWindow::TheInstance())*/;
			pod.plyTypeEdit->setText(e_ply_storage_mode_names[storage_mode]);
			pod.elementsEdit->setText(QString::number(pointElements.size()));
			pod.propertiesEdit->setText(QString::number(listProperties.size()+stdProperties.size()));

			//we fill every combo box
			pod.xComboBox->addItems(stdPropsText);
			pod.xComboBox->setCurrentIndex(xIndex);
			pod.xComboBox->setMaxVisibleItems(stdPropsCount);
			pod.yComboBox->addItems(stdPropsText);
			pod.yComboBox->setCurrentIndex(yIndex);
			pod.yComboBox->setMaxVisibleItems(stdPropsCount);
			pod.zComboBox->addItems(stdPropsText);
			pod.zComboBox->setCurrentIndex(zIndex);
			pod.zComboBox->setMaxVisibleItems(stdPropsCount);

			pod.rComboBox->addItems(stdPropsText);
			pod.rComboBox->setCurrentIndex(rIndex);
			pod.rComboBox->setMaxVisibleItems(stdPropsCount);
			pod.gComboBox->addItems(stdPropsText);
			pod.gComboBox->setCurrentIndex(gIndex);
			pod.gComboBox->setMaxVisibleItems(stdPropsCount);
			pod.bComboBox->addItems(stdPropsText);
			pod.bComboBox->setCurrentIndex(bIndex);
			pod.bComboBox->setMaxVisibleItems(stdPropsCount);

			pod.iComboBox->addItems(stdPropsText);
			pod.iComboBox->setCurrentIndex(iIndex);
			pod.iComboBox->setMaxVisibleItems(stdPropsCount);

			pod.sfComboBox->addItems(stdPropsText);
			pod.sfComboBox->setCurrentIndex(sfIndex);
			pod.sfComboBox->setMaxVisibleItems(stdPropsCount);
			
			pod.nxComboBox->addItems(stdPropsText);
			pod.nxComboBox->setCurrentIndex(nxIndex);
			pod.nxComboBox->setMaxVisibleItems(stdPropsCount);
			pod.nyComboBox->addItems(stdPropsText);
			pod.nyComboBox->setCurrentIndex(nyIndex);
			pod.nyComboBox->setMaxVisibleItems(stdPropsCount);
			pod.nzComboBox->addItems(stdPropsText);
			pod.nzComboBox->setCurrentIndex(nzIndex);
			pod.nzComboBox->setMaxVisibleItems(stdPropsCount);

			pod.facesComboBox->addItems(listPropsText);
			pod.facesComboBox->setCurrentIndex(facesIndex);
			pod.facesComboBox->setMaxVisibleItems(listPropsCount);

			//We execute dialog
			if (!pod.exec())
			{
				ply_close(ply);
				return CC_FERR_CANCELED_BY_USER;
			}

			//Force events processing (to hide dialog)
			QCoreApplication::processEvents();

			xIndex = pod.xComboBox->currentIndex();
			yIndex = pod.yComboBox->currentIndex();
			zIndex = pod.zComboBox->currentIndex();
			nxIndex = pod.nxComboBox->currentIndex();
			nyIndex = pod.nyComboBox->currentIndex();
			nzIndex = pod.nzComboBox->currentIndex();
			rIndex = pod.rComboBox->currentIndex();
			gIndex = pod.gComboBox->currentIndex();
			bIndex = pod.bComboBox->currentIndex();
			iIndex = pod.iComboBox->currentIndex();
			facesIndex = pod.facesComboBox->currentIndex();
			sfIndex = pod.sfComboBox->currentIndex();
		}
	}

    /*************************/
	/***  Callbacks setup  ***/
    /*************************/

    //Main point cloud
	ccPointCloud* cloud = new ccPointCloud("unnamed - Cloud");

	/* POINTS (X,Y,Z) */

	unsigned numberOfPoints=0;

    assert(xIndex != yIndex && xIndex != zIndex && yIndex != zIndex);

	//POINTS (X)
	if (xIndex>0)
	{
		long flags = ELEM_POS_0; //X coordinate
		if (xIndex > yIndex && xIndex > zIndex)
            flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[xIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, vertex_cb, cloud, flags);

		numberOfPoints = pointElements[pp.elemIndex].elementInstances;
	}

	//POINTS (Y)
	if (yIndex>0)
	{
		long flags = ELEM_POS_1; //Y coordinate
		if (yIndex > xIndex && yIndex > zIndex)
            flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[yIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, vertex_cb, cloud, flags);

		if (numberOfPoints > 0)
		{
            if ((long)numberOfPoints != pointElements[pp.elemIndex].elementInstances)
            {
                ccConsole::Warning("[PLY] Bad/uncompatible assignation of point properties!");
                delete cloud;
                ply_close(ply);
                return CC_FERR_BAD_ENTITY_TYPE;
            }
		}
		else numberOfPoints = pointElements[pp.elemIndex].elementInstances;
	}

	//POINTS (Z)
	if (zIndex>0)
	{
		long flags = ELEM_POS_2; //Z coordinate
		if (zIndex > xIndex && zIndex > yIndex)
            flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[zIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, vertex_cb, cloud, flags);

		if (numberOfPoints > 0)
		{
            if ((long)numberOfPoints != pointElements[pp.elemIndex].elementInstances)
            {
                ccConsole::Warning("[PLY] Bad/uncompatible assignation of point properties!");
                delete cloud;
                ply_close(ply);
                return CC_FERR_BAD_ENTITY_TYPE;
            }
		}
		else numberOfPoints = pointElements[pp.elemIndex].elementInstances;
	}

    if (numberOfPoints == 0 || !cloud->reserveThePointsTable(numberOfPoints))
    {
        delete cloud;
        ply_close(ply);
        return CC_FERR_NOT_ENOUGH_MEMORY;
    }

	/* NORMALS (X,Y,Z) */

	unsigned numberOfNormals=0;

    assert(nxIndex == 0 || (nxIndex != nyIndex && nxIndex != nzIndex));
    assert(nyIndex == 0 || (nyIndex != nxIndex && nyIndex != nzIndex));
    assert(nzIndex == 0 || (nzIndex != nxIndex && nzIndex != nyIndex));

    //NORMALS (X)
	if (nxIndex>0)
	{
		long flags = ELEM_POS_0; //Nx
		if (nxIndex > nyIndex && nxIndex > nzIndex)
            flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[nxIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, normal_cb, cloud, flags);

		numberOfNormals = pointElements[pp.elemIndex].elementInstances;
	}

    //NORMALS (Y)
	if (nyIndex>0)
	{
		long flags = ELEM_POS_1; //Ny
		if (nyIndex > nxIndex && nyIndex > nzIndex)
            flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[nyIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, normal_cb, cloud, flags);

		numberOfNormals = ccMax(numberOfNormals, (unsigned)pointElements[pp.elemIndex].elementInstances);
	}

    //NORMALS (Z)
	if (nzIndex>0)
	{
		long flags = ELEM_POS_2; //Nz
		if (nzIndex > nxIndex && nzIndex > nyIndex)
            flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[nzIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, normal_cb, cloud, flags);

		numberOfNormals = ccMax(numberOfNormals, (unsigned)pointElements[pp.elemIndex].elementInstances);
	}

    //We check that the number of normals corresponds to the number of points
	if (numberOfNormals > 0)
	{
        if (numberOfPoints != numberOfNormals)
        {
            ccConsole::Warning("[PLY] The number of normals doesn't match the number of points!");
            delete cloud;
            ply_close(ply);
            return CC_FERR_BAD_ENTITY_TYPE;
        }
		if (!cloud->reserveTheNormsTable())
		{
            delete cloud;
            ply_close(ply);
            return CC_FERR_NOT_ENOUGH_MEMORY;
		}
		cloud->showNormals(true);
    }

	/* COLORS (R,G,B) */

	unsigned numberOfColors=0;

    assert(rIndex == 0 || (rIndex != gIndex && rIndex != bIndex));
    assert(gIndex == 0 || (gIndex != rIndex && gIndex != bIndex));
    assert(bIndex == 0 || (bIndex != rIndex && bIndex != gIndex));

	if (rIndex>0)
	{
		long flags = ELEM_POS_0; //R
		if (rIndex > gIndex && rIndex > bIndex)
            flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[rIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, rgb_cb, cloud, flags);

		numberOfColors = pointElements[pp.elemIndex].elementInstances;
	}

	if (gIndex>0)
	{
		long flags = ELEM_POS_1; //G
		if (gIndex > rIndex && gIndex > bIndex)
            flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[gIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, rgb_cb, cloud, flags);

		numberOfColors = ccMax(numberOfColors, (unsigned)pointElements[pp.elemIndex].elementInstances);
	}

	if (bIndex>0)
	{
		long flags = ELEM_POS_2; //B
		if (bIndex > rIndex && bIndex > gIndex)
            flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[bIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, rgb_cb, cloud, flags);

		numberOfColors = ccMax(numberOfColors, (unsigned)pointElements[pp.elemIndex].elementInstances);
	}

	/* Intensity (I) */

	//INTENSITE (G)
	if (iIndex>0)
	{
        if (numberOfColors>0)
        {
            ccConsole::Error("Can't import colors AND intensity (intensities will be ignored)!");
            ccConsole::Warning("[PLY] intensities will be ignored");
        }
        else
        {
			plyProperty pp = stdProperties[iIndex-1];
			ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, grey_cb, cloud, 0);

			numberOfColors = pointElements[pp.elemIndex].elementInstances;
		}
	}

    //We check that the number of colors corresponds to the number of points
    if (numberOfColors > 0)
    {
        if (numberOfPoints != numberOfColors)
        {
            ccConsole::Warning("The number of colors doesn't match the number of points!");
            delete cloud;
            ply_close(ply);
            return CC_FERR_BAD_ENTITY_TYPE;
        }
		if (!cloud->reserveTheRGBTable())
		{
            delete cloud;
            ply_close(ply);
            return CC_FERR_NOT_ENOUGH_MEMORY;
		}
		cloud->showColors(true);
    }

	/* SCALAR FIELD (SF) */

	unsigned numberOfScalars=0;

	if (sfIndex>0)
	{
		plyProperty& pp = stdProperties[sfIndex-1];
        numberOfScalars = pointElements[pp.elemIndex].elementInstances;

		//does the number of scalars matches the number of points?
		if (numberOfPoints != numberOfScalars)
		{
            ccConsole::Error("The number of scalars doesn't match the number of points (they will be ignored)!");
            ccConsole::Warning("[PLY] Scalar field ignored!");
            numberOfScalars = 0;
        }
        else if (!cloud->enableScalarField())
        {
            ccConsole::Error("Not enough memory to load scalar field (they will be ignored)!");
            ccConsole::Warning("[PLY] Scalar field ignored!");
            numberOfScalars = 0;
        }
        else
        {
			CCLib::ScalarField* sf = cloud->getCurrentInScalarField();
			if (sf)
			{
				QString qPropName(pp.propName);
				if (qPropName.startsWith("scalar_") && qPropName.length()>7)
				{
					//remove the 'scalar_' prefix added when saving SF with CC!
					qPropName = qPropName.mid(7).replace('_',' ');
					sf->setName(qPrintable(qPropName));
				}
				else
				{
					sf->setName(pp.propName);
				}
			}
            ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, scalar_cb, cloud, 1);
        }
		cloud->showSF(true);
	}

	/* MESH FACETS (TRI) */

	ccMesh* mesh = 0;
	unsigned numberOfFacets=0;

	if (facesIndex>0)
	{
		plyProperty& pp = listProperties[facesIndex-1];
		assert(pp.type==16); //we only accept PLY_LIST here!

        mesh = new ccMesh(cloud);

        numberOfFacets = meshElements[pp.elemIndex].elementInstances;

        if (!mesh->reserve(numberOfFacets))
        {
            ccConsole::Error("Not enough memory to load facets (they will be ignored)!");
            ccConsole::Warning("[PLY] Mesh ignored!");
            delete mesh;
            mesh = 0;
            numberOfFacets = 0;
        }
        else
        {
            ply_set_read_cb(ply, meshElements[pp.elemIndex].elementName, pp.propName, face_cb, mesh, 0);
        }
	}

    QProgressDialog progressDlg(QString("Loading in progress..."),0,0,0,0,Qt::Popup);
    progressDlg.setMinimumDuration(0);
	progressDlg.setModal(true);
	progressDlg.show();
	QApplication::processEvents();

    int success = ply_read(ply);

    progressDlg.close();
	ply_close(ply);

	if (success<1)
	{
		if (mesh)
            delete mesh;
        delete cloud;
		return CC_FERR_READING;
	}

    //we check mesh
    if (mesh && mesh->size()==0)
    {
		if (s_unsupportedPolygonType)
			ccConsole::Error("Mesh is not triangular! (unsupported)");
		else
	        ccConsole::Error("Mesh is empty!");
		delete mesh;
		mesh=0;
    }

	//we save coordinates shift information
	if (s_ShiftApplyAll && coordinatesShiftEnabled && coordinatesShift)
	{
		*coordinatesShiftEnabled = true;
		coordinatesShift[0] = s_Pshift[0];
		coordinatesShift[1] = s_Pshift[1];
		coordinatesShift[2] = s_Pshift[2];
	}

    //we update scalar field
	CCLib::ScalarField* sf = cloud->getCurrentInScalarField();
    if (sf)
    {
        sf->setPositive(!s_negSF);
        sf->computeMinAndMax();
		int sfIdx = cloud->getCurrentInScalarFieldIndex();
        cloud->setCurrentDisplayedScalarField(sfIdx);
		cloud->showSF(sfIdx>=0);
    }

    if (mesh)
	{
		assert(s_triCount > 0);
		//check number of loaded facets against 'theoretical' number
		if (s_triCount<numberOfFacets)
		{
			mesh->resize(s_triCount);
			ccConsole::Warning("[PLY] Missing vertex indexes!");
		}

		//check that vertex indices start at 0
		unsigned minVertIndex=numberOfPoints,maxVertIndex=0;
		for (unsigned i=0;i<s_triCount;++i)
		{
			const CCLib::TriangleSummitsIndexes* tri = mesh->getTriangleIndexes(i);
			if (tri->i1 < minVertIndex)
				minVertIndex = tri->i1;
			else if (tri->i1 > maxVertIndex)
				maxVertIndex = tri->i1;
			if (tri->i2 < minVertIndex)
				minVertIndex = tri->i2;
			else if (tri->i2 > maxVertIndex)
				maxVertIndex = tri->i2;
			if (tri->i3 < minVertIndex)
				minVertIndex = tri->i3;
			else if (tri->i3 > maxVertIndex)
				maxVertIndex = tri->i3;
		}

		if (maxVertIndex>=numberOfPoints)
		{
			if (maxVertIndex == numberOfPoints && minVertIndex > 0)
			{
				ccLog::Warning("[PLY] Vertex indices seem to be shifted (+1)! We will try to 'unshift' indices (otherwise file is corrupted...)");
				for (unsigned i=0;i<s_triCount;++i)
				{
					CCLib::TriangleSummitsIndexes* tri = mesh->getTriangleIndexes(i);
					--tri->i1;
					--tri->i2;
					--tri->i3;
				}
			}
			else //file is definitely corrupted!
			{
				ccLog::Warning("[PLY] Invalid vertex indices!");
				delete mesh;
				delete cloud;
				return CC_FERR_MALFORMED_FILE;
			}
		}

        mesh->addChild(cloud);
        cloud->setEnabled(false);
        cloud->setName("Vertices");
		//cloud->setLocked(true); //DGM: no need to lock it as it is only used by one mesh!

        if (cloud->hasColors())
            mesh->showColors(true);
        if (cloud->hasDisplayedScalarField())
            mesh->showSF(true);
        if (cloud->hasNormals())
            mesh->showNormals(true);
        else
            mesh->computeNormals();

        container.addChild(mesh);
    }
    else
    {
        container.addChild(cloud);
    }

	return CC_FERR_NO_ERROR;
}
Пример #8
0
CC_FILE_ERROR VTKFilter::saveToFile(ccHObject* entity, QString filename, SaveParameters& parameters)
{
	if (!entity || filename.isEmpty())
		return CC_FERR_BAD_ARGUMENT;

	//look for either a cloud or a mesh
	ccMesh* mesh = ccHObjectCaster::ToMesh(entity);
	unsigned triCount = 0;
	ccGenericPointCloud* vertices = 0;
	if (mesh)
	{
		//input entity is a mesh
		triCount = mesh->size();
		if (triCount == 0)
		{
			ccLog::Warning("[VTK] Input mesh has no triangle?!");
			return CC_FERR_NO_SAVE;
		}
		vertices = mesh->getAssociatedCloud();
	}
	else
	{
		//no mesh? maybe the input entity is a cloud?
		vertices = ccHObjectCaster::ToGenericPointCloud(entity);
	}

	//in any case, we must have a valid 'vertices' entity now
	if (!vertices)
	{
		ccLog::Warning("[VTK] No point cloud nor mesh in input selection!");
		return CC_FERR_BAD_ENTITY_TYPE;
	}
	unsigned ptsCount = vertices->size();
	if (!ptsCount)
	{
		ccLog::Warning("[VTK] No point/vertex to save?!");
		return CC_FERR_NO_SAVE;
	}

	//open ASCII file for writing
	QFile file(filename);
	if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
		return CC_FERR_WRITING;

	QTextStream outFile(&file);
	outFile.setRealNumberPrecision(sizeof(PointCoordinateType) == 4 ? 8 : 12);

	//write header
	outFile << "# vtk DataFile Version 3.0" << endl;
	outFile << "vtk output" << endl;
	outFile << "ASCII" << endl;
	outFile << "DATASET " << (mesh ? "POLYDATA" : "UNSTRUCTURED_GRID") << endl;

	//data type
	QString floatType = (sizeof(PointCoordinateType) == 4 ? "float" : "double");

	/*** what shall we save now? ***/

	// write the points
	{
		outFile << "POINTS " << ptsCount << " " << floatType << endl;
		for (unsigned i=0; i<ptsCount; ++i)
		{
			const CCVector3* P = vertices->getPoint(i);
			CCVector3d Pglobal = vertices->toGlobal3d<PointCoordinateType>(*P);
			outFile << Pglobal.x << " "
					<< Pglobal.y << " "
					<< Pglobal.z << endl;
		}
	}

	// write triangles
	if (mesh)
	{
		outFile << "POLYGONS " << triCount << " " <<  4*triCount << endl;
		mesh->placeIteratorAtBegining();
		for (unsigned i=0; i<triCount; ++i)
		{
			const CCLib::VerticesIndexes* tsi = mesh->getNextTriangleVertIndexes(); //DGM: getNextTriangleVertIndexes is faster for mesh groups!
			outFile << "3 " << tsi->i1 << " " << tsi->i2  << " " << tsi->i3 << endl;
		}
	}
	else
	{
		// write cell data
		outFile << "CELLS " << ptsCount << " " <<  2*ptsCount << endl;
		for (unsigned i=0; i<ptsCount; ++i)
			outFile << "1 " << i << endl;

		outFile << "CELL_TYPES " << ptsCount  << endl;
		for (unsigned i=0; i<ptsCount; ++i)
			outFile << "1 " << endl;
	}

	outFile << "POINT_DATA " << ptsCount << endl;

	// write normals
	if (vertices->hasNormals())
	{
		outFile << "NORMALS Normals "<< floatType << endl;
		for (unsigned i=0; i<ptsCount; ++i)
		{
			const CCVector3& N = vertices->getPointNormal(i);
			outFile << N.x << " " << N.y << " "  << N.z << endl;
		}
	}

	// write colors
	if (vertices->hasColors())
	{
		outFile << "COLOR_SCALARS RGB 3" << endl;
		for (unsigned i=0; i<ptsCount; ++i)
		{
			const colorType* C = vertices->getPointColor(i);
			outFile << static_cast<float>(C[0])/ccColor::MAX << " " << static_cast<float>(C[1])/ccColor::MAX << " "  << static_cast<float>(C[2])/ccColor::MAX << endl;
		}
	}

	// write scalar field(s)?
	if (vertices->isA(CC_TYPES::POINT_CLOUD))
	{
		ccPointCloud* pointCloud = static_cast<ccPointCloud*>(vertices);
		unsigned sfCount = pointCloud->getNumberOfScalarFields();
		for (unsigned i=0;i<sfCount;++i)
		{
			CCLib::ScalarField* sf = pointCloud->getScalarField(i);

			outFile << "SCALARS " << QString(sf->getName()).replace(" ","_") << (sizeof(ScalarType)==4 ? " float" : " double") << " 1" << endl;
			outFile << "LOOKUP_TABLE default" << endl;

			for (unsigned j=0;j<ptsCount; ++j)
				outFile << sf->getValue(j) << endl;
		}
	}
	else //virtual point cloud, we only have access to its currently displayed scalar field
	{
		if (vertices->hasScalarFields())
		{
			outFile << "SCALARS ScalarField" << (sizeof(ScalarType)==4 ? " float" : " double") << " 1" << endl;
			outFile << "LOOKUP_TABLE default" << endl;

			for (unsigned j=0;j<ptsCount; ++j)
				outFile << vertices->getPointDisplayedDistance(j) << endl;
		}
	}

	file.close();

	return CC_FERR_NO_ERROR;
}
Пример #9
0
CC_FILE_ERROR VTKFilter::saveToFile(ccHObject* entity, const char* filename)
{
	if (!entity || !filename)
		return CC_FERR_BAD_ARGUMENT;

	//look for either a cloud or a mesh
	ccHObject::Container clouds,meshes;
	if (entity->isA(CC_TYPES::POINT_CLOUD))
		clouds.push_back(entity);
	else if (entity->isKindOf(CC_TYPES::MESH))
		meshes.push_back(entity);
	else //group?
	{
		for (unsigned i=0; i<entity->getChildrenNumber(); ++i)
		{
			ccHObject* child = entity->getChild(i);
			if (child->isKindOf(CC_TYPES::POINT_CLOUD))
				clouds.push_back(child);
			else if (child->isKindOf(CC_TYPES::MESH))
				meshes.push_back(child);
		}
	}

	if (clouds.empty() && meshes.empty())
	{
		ccLog::Error("No point cloud nor mesh in input selection!");
		return CC_FERR_BAD_ENTITY_TYPE;
	}
	else if (clouds.size()+meshes.size()>1)
	{
		ccLog::Error("Can't save more than one entity per VTK file!");
		return CC_FERR_BAD_ENTITY_TYPE;
	}

	//the cloud to save
	ccGenericPointCloud* vertices = 0;
	ccMesh* mesh = 0;
	unsigned triCount = 0;
	if (!clouds.empty()) //1 cloud, no mesh
	{
		vertices = ccHObjectCaster::ToGenericPointCloud(clouds[0]);
	}
	else //1 mesh, with vertices as cloud
	{
		mesh = static_cast<ccMesh*>(meshes[0]);
		triCount = mesh->size();
		if (triCount == 0)
		{
			ccLog::Error("Mesh has no triangle?!");
			return CC_FERR_NO_SAVE;
		}
		vertices = mesh->getAssociatedCloud();
	}

	assert(vertices);
	unsigned ptsCount = vertices->size();
	if (!ptsCount)
	{
		ccLog::Error("No point/vertex to save?!");
		return CC_FERR_NO_SAVE;
	}

	//open ASCII file for writing
	QFile file(filename);
	if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
		return CC_FERR_WRITING;

	QTextStream outFile(&file);
	outFile.setRealNumberPrecision(sizeof(PointCoordinateType) == 4 ? 8 : 12);

	//write header
	outFile << "# vtk DataFile Version 3.0" << endl;
	outFile << "vtk output" << endl;
	outFile << "ASCII" << endl;
	outFile << "DATASET " << (mesh ? "POLYDATA" : "UNSTRUCTURED_GRID") << endl;

	//data type
	QString floatType = (sizeof(PointCoordinateType) == 4 ? "float" : "double");

	/*** what shall we save now? ***/

	// write the points
	{
		outFile << "POINTS " << ptsCount << " " << floatType << endl;
		for (unsigned i=0; i<ptsCount; ++i)
		{
			const CCVector3* P = vertices->getPoint(i);
			CCVector3d Pglobal = vertices->toGlobal3d<PointCoordinateType>(*P);
			outFile << Pglobal.x << " "
					<< Pglobal.y << " "
					<< Pglobal.z << endl;
		}
	}

	// write triangles
	if (mesh)
	{
		outFile << "POLYGONS " << triCount << " " <<  4*triCount << endl;
		mesh->placeIteratorAtBegining();
		for (unsigned i=0; i<triCount; ++i)
		{
			const CCLib::TriangleSummitsIndexes* tsi = mesh->getNextTriangleIndexes(); //DGM: getNextTriangleIndexes is faster for mesh groups!
			outFile << "3 " << tsi->i1 << " " << tsi->i2  << " " << tsi->i3 << endl;
		}
	}
	else
	{
		// write cell data
		outFile << "CELLS " << ptsCount << " " <<  2*ptsCount << endl;
		for (unsigned i=0; i<ptsCount; ++i)
			outFile << "1 " << i << endl;

		outFile << "CELL_TYPES " << ptsCount  << endl;
		for (unsigned i=0; i<ptsCount; ++i)
			outFile << "1 " << endl;
	}

	outFile << "POINT_DATA " << ptsCount << endl;

	// write normals
	if (vertices->hasNormals())
	{
		outFile << "NORMALS Normals "<< floatType << endl;
		for (unsigned i=0; i<ptsCount; ++i)
		{
			const CCVector3& N = vertices->getPointNormal(i);
			outFile << N.x << " " << N.y << " "  << N.z << endl;
		}
	}

	// write colors
	if (vertices->hasColors())
	{
		outFile << "COLOR_SCALARS RGB 3" << endl;
		for (unsigned i=0; i<ptsCount; ++i)
		{
			const colorType* C = vertices->getPointColor(i);
			outFile << (float)C[0]/(float)MAX_COLOR_COMP << " " << (float)C[1]/(float)MAX_COLOR_COMP << " "  << (float)C[2]/(float)MAX_COLOR_COMP << endl;
		}
	}

	// write scalar field(s)?
	if (vertices->isA(CC_TYPES::POINT_CLOUD))
	{
		ccPointCloud* pointCloud = static_cast<ccPointCloud*>(vertices);
		unsigned sfCount = pointCloud->getNumberOfScalarFields();
		for (unsigned i=0;i<sfCount;++i)
		{
			CCLib::ScalarField* sf = pointCloud->getScalarField(i);

			outFile << "SCALARS " << QString(sf->getName()).replace(" ","_") << (sizeof(ScalarType)==4 ? " float" : " double") << " 1" << endl;
			outFile << "LOOKUP_TABLE default" << endl;

			for (unsigned j=0;j<ptsCount; ++j)
				outFile << sf->getValue(j) << endl;
		}
	}
	else //virtual point cloud, we only have access to its currently displayed scalar field
	{
		if (vertices->hasScalarFields())
		{
			outFile << "SCALARS ScalarField" << (sizeof(ScalarType)==4 ? " float" : " double") << " 1" << endl;
			outFile << "LOOKUP_TABLE default" << endl;

			for (unsigned j=0;j<ptsCount; ++j)
				outFile << vertices->getPointDisplayedDistance(j) << endl;
		}
	}

	file.close();

	return CC_FERR_NO_ERROR;
}
Пример #10
0
CC_FILE_ERROR PVFilter::saveToFile(ccHObject* entity, const char* filename)
{
	if (!entity || !filename)
        return CC_FERR_BAD_ARGUMENT;

	ccHObject::Container clouds;
	if (entity->isKindOf(CC_POINT_CLOUD))
        clouds.push_back(entity);
    else
        entity->filterChildren(clouds, true, CC_POINT_CLOUD);

    if (clouds.empty())
    {
        ccConsole::Error("No point cloud in input selection!");
        return CC_FERR_BAD_ENTITY_TYPE;
    }
    else if (clouds.size()>1)
    {
        ccConsole::Error("Can't save more than one cloud per PV file!");
        return CC_FERR_BAD_ENTITY_TYPE;
    }

    //the cloud to save
    ccGenericPointCloud* theCloud = static_cast<ccGenericPointCloud*>(clouds[0]);
    //and its scalar field
	CCLib::ScalarField* sf = 0;
	if (theCloud->isA(CC_POINT_CLOUD))
	    sf = static_cast<ccPointCloud*>(theCloud)->getCurrentDisplayedScalarField();

    if (!sf)
        ccConsole::Warning("No displayed scalar field! Values will all be 0!\n");

    unsigned numberOfPoints = theCloud->size();
	if (numberOfPoints==0)
	{
        ccConsole::Error("Cloud is empty!");
        return CC_FERR_BAD_ENTITY_TYPE;
	}

    //open binary file for writing
	FILE* theFile = fopen(filename , "wb");
	if (!theFile)
        return CC_FERR_WRITING;

    //Has the cloud been recentered?
	const double* shift = theCloud->getOriginalShift();
	if (fabs(shift[0])+fabs(shift[0])+fabs(shift[0])>0.0)
        ccConsole::Warning(QString("[PVFilter::save] Can't recenter cloud %1 on PV file save!").arg(theCloud->getName()));

	//progress dialog
	ccProgressDialog pdlg(true); //cancel available
	CCLib::NormalizedProgress nprogress(&pdlg,numberOfPoints);
	pdlg.setMethodTitle("Save PV file");
	char buffer[256];
	sprintf(buffer,"Points: %i",numberOfPoints);
	pdlg.setInfo(buffer);
	pdlg.start();

	float wBuff[3];
	float val=0.0;

	for (unsigned i=0;i<numberOfPoints;i++)
	{
	    //conversion to float
	    const CCVector3* P = theCloud->getPoint(i);
	    wBuff[0]=float(P->x);
	    wBuff[1]=float(P->y);
	    wBuff[2]=float(P->z);

		if (fwrite(wBuff,sizeof(float),3,theFile) < 0)
			{fclose(theFile);return CC_FERR_WRITING;}

		if (sf)
            val = (float)sf->getValue(i);

        if (fwrite(&val,sizeof(float),1,theFile) < 0)
            {fclose(theFile);return CC_FERR_WRITING;}

		if (!nprogress.oneStep())
			break;
	}

	fclose(theFile);

	return CC_FERR_NO_ERROR;
}
Пример #11
0
CC_FILE_ERROR ShpFilter::loadFile(QString filename, ccHObject& container, LoadParameters& parameters)
{
	QFile file(filename);
	if (!file.open(QIODevice::ReadOnly))
		return CC_FERR_READING;

	//global shift
	CCVector3d Pshift(0,0,0);

	//read header (refer to ESRI Shapefile Technical Description)
	if (file.size() < 100)
		return CC_FERR_MALFORMED_FILE;
	char header[100];
	file.read(header,100);
	int32_t fileLength = 0;
	{
		/*** WARNING: the beginning of the header is written with big endianness! ***/
		const char* _header = header;
		
		//Byte 0: SHP code
		const int32_t code = qFromBigEndian<int32_t>(*reinterpret_cast<const int32_t*>(_header));
		if (code != 9994)
		{
			return CC_FERR_MALFORMED_FILE;
		}
		_header += 4;

		//Byte 4: unused (20 bytes)
		_header += 20;

		//Byte 24: file length (will be written... later ;)
		fileLength = qFromBigEndian<int32_t>(*reinterpret_cast<const int32_t*>(_header));
		fileLength *= 2; //fileLength is measured in 16-bit words

		_header += 4;

		/*** WARNING: from now on, we only read data with little endianness! ***/

		//Byte 28: file verion
		const int32_t version = qFromLittleEndian<int32_t>(*reinterpret_cast<const int32_t*>(_header));
		_header += 4;

		//Byte 32: shape type
		int32_t shapeTypeInt = qFromLittleEndian<int32_t>(*reinterpret_cast<const int32_t*>(_header));
		_header += 4;

		ccLog::Print(QString("[SHP] Version: %1 - type: %2").arg(version).arg(ToString(static_cast<ESRI_SHAPE_TYPE>(shapeTypeInt))));

		//X and Y bounaries
		//Byte 36: box X min
		double xMin = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header));
		_header += 8;
		//Byte 44: box Y min
		double xMax = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header));
		_header += 8;
		//Byte 52: box X max
		double yMin = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header));
		_header += 8;
		//Byte 60: box Y max
		double yMax = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header));
		_header += 8;

		//Z bounaries
		//Unused, with value 0.0, if not Measured or Z type
		//Byte 68: box Z min
		double zMin = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header));
		_header += 8;
		//Byte 76: box Z max
		double zMax = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header));
		_header += 8;

		CCVector3d Pmin(xMin,yMin,zMin);
		if (HandleGlobalShift(Pmin,Pshift,parameters))
		{
			ccLog::Warning("[SHP] Entities will be recentered! Translation: (%.2f,%.2f,%.2f)",Pshift.x,Pshift.y,Pshift.z);
		}

		//M bounaries (M = measures)
		//Byte 84: M min
		double mMin = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header));
		_header += 8;
		//Byte 92: M max
		double mMax = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header));
		_header += 8;
	}
	assert(fileLength >= 100);
	if (fileLength < 100)
	{
		assert(false);
		return CC_FERR_MALFORMED_FILE;
	}
	fileLength -= 100;

	if (fileLength == 0)
	{
		return CC_FERR_NO_LOAD;
	}

	//load shapes
	CC_FILE_ERROR error = CC_FERR_NO_ERROR;
	ccPointCloud* singlePoints = 0;
	qint64 pos = file.pos();
	while (fileLength >= 12)
	{
		file.seek(pos);
		assert(pos + fileLength == file.size());
		//load shape record in main SHP file
		{
			file.read(header,8);
			//Byte 0: Record Number
			int32_t recordNumber = qFromBigEndian<int32_t>(*reinterpret_cast<const int32_t*>(header)); //Record numbers begin at 1
			//Byte 4: Content Length
			int32_t recordSize = qFromBigEndian<int32_t>(*reinterpret_cast<const int32_t*>(header+4)); //Record numbers begin at 1
			recordSize *= 2; //recordSize is measured in 16-bit words
			fileLength -= 8;
			pos += 8;
			
			if (fileLength < recordSize)
			{
				assert(false);
				error = CC_FERR_MALFORMED_FILE;
				break;
			}
			fileLength -= recordSize;
			pos += recordSize;

			//Record start (byte 0): Shape Type
			if (recordSize < 4)
			{
				assert(false);
				error = CC_FERR_MALFORMED_FILE;
				break;
			}
			file.read(header,4);
			recordSize -= 4;
			int32_t shapeTypeInt = qToLittleEndian<int32_t>(*reinterpret_cast<const int32_t*>(header));
			ccLog::Print(QString("[SHP] Record #%1 - type: %2 (%3 bytes)").arg(recordNumber).arg(ToString(static_cast<ESRI_SHAPE_TYPE>(shapeTypeInt))).arg(recordSize));

			switch (shapeTypeInt)
			{
			case SHP_POLYLINE:
			case SHP_POLYLINE_Z:
			case SHP_POLYGON:
			case SHP_POLYGON_Z:
				error = LoadPolyline(file,container,recordNumber,static_cast<ESRI_SHAPE_TYPE>(shapeTypeInt),Pshift);
				break;
			case SHP_MULTI_POINT:
			case SHP_MULTI_POINT_Z:
			case SHP_MULTI_POINT_M:
				error = LoadCloud(file,container,recordNumber,static_cast<ESRI_SHAPE_TYPE>(shapeTypeInt),Pshift);
				break;
			case SHP_POINT:
			case SHP_POINT_Z:
			case SHP_POINT_M:
				error = LoadSinglePoint(file,singlePoints,static_cast<ESRI_SHAPE_TYPE>(shapeTypeInt),Pshift);
				break;
			//case SHP_MULTI_PATCH:
			//	error = LoadMesh(file,recordSize);
			//	break;
			case SHP_NULL_SHAPE:
				//ignored
				break;
			default:
				//unhandled entity
				ccLog::Warning("[SHP] Unhandled type!");
				break;
			}
		}

		if (error != CC_FERR_NO_ERROR)
			break;
	}

	if (singlePoints)
	{
		if (singlePoints->size() == 0)
		{
			delete singlePoints;
			singlePoints = 0;
		}
		else
		{
			CCLib::ScalarField* sf = singlePoints->getScalarField(0);
			if (sf)
			{
				sf->computeMinAndMax();
				singlePoints->showSF(true);
			}
			container.addChild(singlePoints);
		}
	}

	return error;
}
Пример #12
0
CC_FILE_ERROR UltFilter::loadFile(const char* filename, ccHObject& container, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, double* coordinatesShift/*=0*/)
{
	//ccConsole::Print("[BinFilter::loadFile] Opening binary file '%s'...\n",filename);

	assert(filename);

    //file size
    long size = QFileInfo(filename).size();

    if ( size == 0 || ((size % sizeof(MarkersFrame)) != 0))
		return CC_FERR_MALFORMED_FILE;

    //number of transformations in file
    long count = size / sizeof(MarkersFrame);
	ccConsole::Print("[TransBuffer] Found %i trans. in file '%s'",count,filename);
	if (count<1)
		return CC_FERR_NO_LOAD;

	ccPointCloud* cloud = new ccPointCloud();
	if (!cloud->reserve(count) || !cloud->enableScalarField())
	{
		delete cloud;
		return CC_FERR_NOT_ENOUGH_MEMORY;
	}

    ccProgressDialog pdlg(true);
    pdlg.setMethodTitle("Open Ult File");
	CCLib::NormalizedProgress nprogress(&pdlg,count);
	pdlg.reset();
	pdlg.setInfo(qPrintable(QString("Transformations: %1").arg(count)));
	pdlg.start();
	QApplication::processEvents();

    FILE* fp = fopen(filename,"rb");
    if (!fp)
	{
		delete cloud;
        return CC_FERR_READING;
	}

	//which marker is the reference?
	QMessageBox::StandardButton tibiaIsRef = QMessageBox::question(0, "Choose reference", "Tibia as reference (yes)? Or femur (no)? Or none (no to all)", QMessageBox::Yes | QMessageBox::No | QMessageBox::NoToAll, QMessageBox::Yes );
	MARKER_ROLE referenceRole = MARKER_LOCALIZER;
	if (tibiaIsRef == QMessageBox::Yes)
		referenceRole = MARKER_TIBIA;
	else if (tibiaIsRef == QMessageBox::No)
		referenceRole = MARKER_FEMUR;

	//To apply a predefined pointer tip
	//CCVector3 tip(0,0,0);
	CCVector3 tip(-90.07f, -17.68f, 18.29f);

	MarkersFrame currentframe;
	MarkerState& currentMarker = currentframe.states[MARKER_POINTER];
	MarkerState* referenceMarker = 0;
	if (referenceRole != MARKER_LOCALIZER)
		referenceMarker = currentframe.states+referenceRole;

	unsigned MarkersFrameSize = sizeof(MarkersFrame);
	unsigned realCount=0;
	for (long i=0;i<count;++i)
	{
		if (fread(&currentframe,MarkersFrameSize,1,fp)==0)
		{
			fclose(fp);
			delete cloud;
			return CC_FERR_READING;
		}

		if (currentMarker.visible && (!referenceMarker || referenceMarker->visible))
		{
			CCVector3 P(tip);
			ccGLMatrix trans = currentMarker.pos;
			if (referenceMarker)
				trans = referenceMarker->pos.inverse() * trans;
			trans.apply(P);

			cloud->addPoint(P);
			cloud->setPointScalarValue(realCount,currentMarker.pos.timestamp);
			++realCount;
		}

		if (!nprogress.oneStep())
			break;
	}

	fclose(fp);

	if (realCount==0)
	{
		delete cloud;
		return CC_FERR_NO_LOAD;
	}

	cloud->resize(realCount);
    //we update scalar field
	CCLib::ScalarField* sf = cloud->getCurrentInScalarField();
    if (sf)
    {
        sf->setPositive(true);
        sf->computeMinAndMax();
        cloud->setCurrentDisplayedScalarField(cloud->getCurrentInScalarFieldIndex());
    }

	container.addChild(cloud);

	return CC_FERR_NO_ERROR;
}
Пример #13
0
void ccRasterizeTool::generateRaster() const
{
#ifdef CC_GDAL_SUPPORT

	if (!m_cloud || !m_grid.isValid())
		return;

	GDALAllRegister();
	ccLog::PrintDebug("(GDAL drivers: %i)", GetGDALDriverManager()->GetDriverCount());

	const char *pszFormat = "GTiff";
	GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
	if (!poDriver)
	{
		ccLog::Error("[GDAL] Driver %s is not supported", pszFormat);
		return;
	}

	char** papszMetadata = poDriver->GetMetadata();
	if( !CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATE, FALSE ) )
	{
		ccLog::Error("[GDAL] Driver %s doesn't support Create() method", pszFormat);
		return;
	}

	//which (and how many) bands shall we create?
	bool heightBand = true; //height by default
	bool densityBand = false;
	bool allSFBands = false;
	int sfBandIndex = -1; //scalar field index
	int totalBands = 0;

	bool interpolateSF = (getTypeOfSFInterpolation() != INVALID_PROJECTION_TYPE);
	ccPointCloud* pc = m_cloud->isA(CC_TYPES::POINT_CLOUD) ? static_cast<ccPointCloud*>(m_cloud) : 0;

	bool hasSF =  interpolateSF && pc && !m_grid.scalarFields.empty();
	
	RasterExportOptionsDlg reoDlg;
	reoDlg.dimensionsLabel->setText(QString("%1 x %2").arg(m_grid.width).arg(m_grid.height));
	reoDlg.exportHeightsCheckBox->setChecked(heightBand);
	reoDlg.exportDensityCheckBox->setChecked(densityBand);
	reoDlg.exportDisplayedSFCheckBox->setEnabled(hasSF);
	reoDlg.exportAllSFCheckBox->setEnabled(hasSF);
	reoDlg.exportAllSFCheckBox->setChecked(allSFBands);

	if (!reoDlg.exec())
		return;

	//we ask the output filename AFTER displaying the export parameters ;)
	QString outputFilename;
	{
		QSettings settings;
		settings.beginGroup(ccPS::HeightGridGeneration());
		QString imageSavePath = settings.value("savePathImage",QApplication::applicationDirPath()).toString();
		outputFilename = QFileDialog::getSaveFileName(0,"Save height grid raster",imageSavePath+QString("/raster.tif"),"geotiff (*.tif)");

		if (outputFilename.isNull())
			return;

		//save current export path to persistent settings
		settings.setValue("savePathImage",QFileInfo(outputFilename).absolutePath());
	}

	heightBand = reoDlg.exportHeightsCheckBox->isChecked();
	densityBand = reoDlg.exportDensityCheckBox->isChecked();
	if (hasSF)
	{
		assert(pc);
		allSFBands = reoDlg.exportAllSFCheckBox->isChecked() && hasSF;
		if (!allSFBands && reoDlg.exportDisplayedSFCheckBox->isChecked())
		{
			sfBandIndex = pc->getCurrentDisplayedScalarFieldIndex();
			if (sfBandIndex < 0)
				ccLog::Warning("[Rasterize] Cloud has no active (displayed) SF!");
		}
	}

	totalBands = heightBand ? 1 : 0;
	if (densityBand)
	{
		++totalBands;
	}
	if (allSFBands)
	{
		assert(hasSF);
		for (size_t i=0; i<m_grid.scalarFields.size(); ++i)
			if (m_grid.scalarFields[i])
				++totalBands;
	}
	else if (sfBandIndex >= 0)
	{
		++totalBands;
	}
	
	if (totalBands == 0)
	{
		ccLog::Warning("[Rasterize] Warning, can't output a raster with no band! (check export parameters)");
		return;
	}

	//data type
	GDALDataType dataType = (std::max(sizeof(PointCoordinateType),sizeof(ScalarType)) > 4 ? GDT_Float64 : GDT_Float32);

	char **papszOptions = NULL;
	GDALDataset* poDstDS = poDriver->Create(qPrintable(outputFilename),
											static_cast<int>(m_grid.width),
											static_cast<int>(m_grid.height),
											totalBands,
											dataType, 
											papszOptions);

	if (!poDstDS)
	{
		ccLog::Error("[GDAL] Failed to create output raster (not enough memory?)");
		return;
	}

	ccBBox box = getCustomBBox();
	assert(box.isValid());

	//vertical dimension
	const unsigned char Z = getProjectionDimension();
	assert(Z >= 0 && Z <= 2);
	const unsigned char X = Z == 2 ? 0 : Z +1;
	const unsigned char Y = X == 2 ? 0 : X +1;

	double shiftX = box.minCorner().u[X];
	double shiftY = box.minCorner().u[Y];

	double stepX = m_grid.gridStep;
	double stepY = m_grid.gridStep;
	if (pc)
	{
		const CCVector3d& shift = pc->getGlobalShift();
		shiftX -= shift.u[X];
		shiftY -= shift.u[Y];

		double scale = pc->getGlobalScale();
		assert(scale != 0);
		stepX /= scale;
		stepY /= scale;
	}

	double adfGeoTransform[6] = {	shiftX,		//top left x
									stepX,		//w-e pixel resolution (can be negative)
									0,			//0
									shiftY,		//top left y
									0,			//0
									stepY		//n-s pixel resolution (can be negative)
	};

	poDstDS->SetGeoTransform( adfGeoTransform );

	//OGRSpatialReference oSRS;
	//oSRS.SetUTM( 11, TRUE );
	//oSRS.SetWellKnownGeogCS( "NAD27" );
	//char *pszSRS_WKT = NULL;
	//oSRS.exportToWkt( &pszSRS_WKT );
	//poDstDS->SetProjection( pszSRS_WKT );
	//CPLFree( pszSRS_WKT );

	double* scanline = (double*) CPLMalloc(sizeof(double)*m_grid.width);
	int currentBand = 0;

	//exort height band?
	if (heightBand)
	{
		GDALRasterBand* poBand = poDstDS->GetRasterBand(++currentBand);
		assert(poBand);
		poBand->SetColorInterpretation(GCI_Undefined);

		EmptyCellFillOption fillEmptyCellsStrategy = getFillEmptyCellsStrategy(fillEmptyCellsComboBox);

		double emptyCellHeight = 0;
		switch (fillEmptyCellsStrategy)
		{
		case LEAVE_EMPTY:
			emptyCellHeight = m_grid.minHeight-1.0;
			poBand->SetNoDataValue(emptyCellHeight); //should be transparent!
			break;
		case FILL_MINIMUM_HEIGHT:
			emptyCellHeight = m_grid.minHeight;
			break;
		case FILL_MAXIMUM_HEIGHT:
			emptyCellHeight = m_grid.maxHeight;
			break;
		case FILL_CUSTOM_HEIGHT:
			emptyCellHeight = getCustomHeightForEmptyCells();
			break;
		case FILL_AVERAGE_HEIGHT:
			emptyCellHeight = m_grid.meanHeight;
			break;
		default:
			assert(false);
		}

		for (unsigned j=0; j<m_grid.height; ++j)
		{
			const RasterCell* aCell = m_grid.data[j];
			for (unsigned i=0; i<m_grid.width; ++i,++aCell)
			{
				scanline[i] = aCell->h == aCell->h ? aCell->h : emptyCellHeight;
			}

			if (poBand->RasterIO( GF_Write, 0, static_cast<int>(j), static_cast<int>(m_grid.width), 1, scanline, static_cast<int>(m_grid.width), 1, GDT_Float64, 0, 0 ) != CE_None)
			{
				ccLog::Error("[GDAL] An error occurred while writing the height band!");
				if (scanline)
					CPLFree(scanline);
				GDALClose( (GDALDatasetH) poDstDS );
				return;
			}
		}
	}

	//export density band
	if (densityBand)
	{
		GDALRasterBand* poBand = poDstDS->GetRasterBand(++currentBand);
		assert(poBand);
		poBand->SetColorInterpretation(GCI_Undefined);
		for (unsigned j=0; j<m_grid.height; ++j)
		{
			const RasterCell* aCell = m_grid.data[j];
			for (unsigned i=0; i<m_grid.width; ++i,++aCell)
			{
				scanline[i] = aCell->nbPoints;
			}

			if (poBand->RasterIO( GF_Write, 0, static_cast<int>(j), static_cast<int>(m_grid.width), 1, scanline, static_cast<int>(m_grid.width), 1, GDT_Float64, 0, 0 ) != CE_None)
			{
				ccLog::Error("[GDAL] An error occurred while writing the height band!");
				if (scanline)
					CPLFree(scanline);
				GDALClose( (GDALDatasetH) poDstDS );
				return;
			}
		}
	}

	//export SF bands
	if (allSFBands || sfBandIndex >= 0)
	{
		for (size_t k=0; k<m_grid.scalarFields.size(); ++k)
		{
			double* _sfGrid = m_grid.scalarFields[k];
			if (_sfGrid && (allSFBands || sfBandIndex == static_cast<int>(k))) //valid SF grid
			{
				GDALRasterBand* poBand = poDstDS->GetRasterBand(++currentBand);

				double sfNanValue = static_cast<double>(CCLib::ScalarField::NaN());
				poBand->SetNoDataValue(sfNanValue); //should be transparent!
				assert(poBand);
				poBand->SetColorInterpretation(GCI_Undefined);

				for (unsigned j=0; j<m_grid.height; ++j)
				{
					const RasterCell* aCell = m_grid.data[j];
					for (unsigned i=0; i<m_grid.width; ++i,++_sfGrid,++aCell)
					{
						scanline[i] = aCell->nbPoints ? *_sfGrid : sfNanValue;
					}

					if (poBand->RasterIO( GF_Write, 0, static_cast<int>(j), static_cast<int>(m_grid.width), 1, scanline, static_cast<int>(m_grid.width), 1, GDT_Float64, 0, 0 ) != CE_None)
					{
						//the corresponding SF should exist on the input cloud
						CCLib::ScalarField* formerSf = pc->getScalarField(static_cast<int>(k));
						assert(formerSf);
						ccLog::Error(QString("[GDAL] An error occurred while writing the '%1' scalar field band!").arg(formerSf->getName()));
						k = m_grid.scalarFields.size(); //quick stop
						break;
					}
				}
			}
		}
	}

	if (scanline)
		CPLFree(scanline);
	scanline = 0;

	/* Once we're done, close properly the dataset */
	GDALClose( (GDALDatasetH) poDstDS );

	ccLog::Print(QString("[Rasterize] Raster '%1' succesfully saved").arg(outputFilename));

#else
	assert(false);
	ccLog::Error("[Rasterize] GDAL not supported by this version! Can't generate a raster...");
#endif
}
Пример #14
0
//==================================================loadFile=================================================//
CC_FILE_ERROR PlyFilter::loadFile(QString filename, ccHObject& container, LoadParameters& parameters)
{
	//reset statics!
	s_triCount = 0;//三角面片的个数
	s_unsupportedPolygonType = false;//支持多边形类型
	s_texCoordCount = 0;//纹理坐标个数
	s_invalidTexCoordinates = false;//纹理坐标无效
	s_totalScalarCount = 0;//
	s_IntensityCount = 0;//
	s_ColorCount = 0;//颜色个数
	s_NormalCount = 0;//法向量个数
	s_PointCount = 0;//点的个数
	s_PointDataCorrupted = false;
	s_loadParameters = parameters;
	s_Pshift = CCVector3d(0,0,0);

	/****************/
	/***  Header  ***/
	/****************/

	//open a PLY file for reading
	p_ply ply = ply_open(qPrintable(filename), NULL, 0, NULL);
	if (!ply)
		return CC_FERR_READING;

	//ccLog::PrintDebug(QString("[PLY] Opening file '%1' ...").arg(filename));
	ccLog::PrintDebug(QString("[PLY] 打开文件 '%1' ...").arg(filename));

	if (!ply_read_header(ply))
	{
		ply_close(ply);
		return CC_FERR_WRONG_FILE_TYPE;
	}

	//storage mode: little/big endian
	e_ply_storage_mode storage_mode;
	get_plystorage_mode(ply,&storage_mode);

	/*****************/
	/***  Texture  ***/
	/*****************/
	//eventual texture file declared in the comments (keyword: TEXTUREFILE)
	QString textureFileName;
	//texture coordinates
	TextureCoordsContainer* texCoords = 0;

	/******************/
	/***  Comments  ***/
	/******************/
	{
		const char* lastComment = NULL;

		//display comments
		while ((lastComment = ply_get_next_comment(ply, lastComment)))
		{
			ccLog::Print("[PLY][Comment] %s",lastComment);

			//specific case: TextureFile 'filename.ext'
			if (QString(lastComment).toUpper().startsWith("TEXTUREFILE "))
				textureFileName = QString(lastComment).mid(12).trimmed();
		}
	}

	/*******************************/
	/***  Elements & properties  ***/
	/*******************************/

	//Point-based elements (points, colors, normals, etc.)
	std::vector<plyElement> pointElements;
	//Mesh-based elements (vertices, etc.)
	std::vector<plyElement> meshElements;

	//Point-based element properties (coordinates, color components, etc.)
	std::vector<plyProperty> stdProperties;
	//Mesh-based element properties (vertex indexes, etc.)
	std::vector<plyProperty> listProperties;

	//last read element
	plyElement lastElement;
	lastElement.elem = 0;
	while ((lastElement.elem = ply_get_next_element(ply, lastElement.elem)))
	{
		//we get next element info
		ply_get_element_info(lastElement.elem, &lastElement.elementName, &lastElement.elementInstances);

		if (lastElement.elementInstances == 0)
		{
			ccLog::Warning("[PLY] Element '%s' was ignored as it has 0 instance!",lastElement.elementName);
			continue;
		}

		lastElement.properties.clear();
		lastElement.propertiesCount=0;
		lastElement.isList=false;
		//printf("Element: %s\n",lastElement.elementName);

		//last read property
		plyProperty lastProperty;
		lastProperty.prop = 0;
		lastProperty.elemIndex = 0;

		while ((lastProperty.prop = ply_get_next_property(lastElement.elem,lastProperty.prop)))
		{
			//we get next property info
			ply_get_property_info(lastProperty.prop, &lastProperty.propName, &lastProperty.type, &lastProperty.length_type, &lastProperty.value_type);
			//printf("\tProperty: %s (%s)\n",lastProperty.propName,e_ply_type_names[lastProperty.type]);

			if (lastProperty.type == 16) //PLY_LIST
				lastElement.isList = true;

			lastElement.properties.push_back(lastProperty);
			++lastElement.propertiesCount;
		}

		//if we have a "mesh-like" element
		if (lastElement.isList)
		{
			//we store its properties in 'listProperties'
			for (size_t i=0; i<lastElement.properties.size(); ++i)
			{
				plyProperty& prop = lastElement.properties[i];
				prop.elemIndex = (int)meshElements.size();

				//we only keep track of lists (we can't handle per triangle scalars)
				if (prop.type == 16)
					listProperties.push_back(prop);
				else
				{
					ccLog::Warning("[PLY] Unhandled property: [%s:%s] (%s)",
						lastElement.elementName,
						prop.propName,
						e_ply_type_names[prop.type]);
				}
			}
			meshElements.push_back(lastElement);
		}
		else	//else if we have a "point-like" element
		{
			//we store its properties in 'stdProperties'
			for (size_t i=0; i<lastElement.properties.size(); ++i)
			{
				plyProperty& prop = lastElement.properties[i];
				prop.elemIndex = (int)pointElements.size();
				stdProperties.push_back(prop);
			}
			pointElements.push_back(lastElement);
		}
	}

	//We need some points at least!
	if (pointElements.empty())
	{
		ply_close(ply);
		return CC_FERR_NO_LOAD;
	}

	/**********************/
	/***  Objects info  ***/
	/**********************/
	{
		const char* lastObjInfo = NULL;
		while ((lastObjInfo = ply_get_next_obj_info(ply, lastObjInfo)))
			ccLog::Print("[PLY][Info] %s",lastObjInfo);
	}

	/****************/
	/***  Dialog  ***/
	/****************/

	//properties indexes (0 = unassigned)
	static const unsigned nStdProp = 10;
	int stdPropIndexes[nStdProp] = {0,0,0,0,0,0,0,0,0,0};
	int& xIndex = stdPropIndexes[0];
	int& yIndex = stdPropIndexes[1];
	int& zIndex = stdPropIndexes[2];
	int& nxIndex = stdPropIndexes[3];
	int& nyIndex = stdPropIndexes[4];
	int& nzIndex = stdPropIndexes[5];
	int& rIndex = stdPropIndexes[6];
	int& gIndex = stdPropIndexes[7];
	int& bIndex = stdPropIndexes[8];
	int& iIndex = stdPropIndexes[9];

	std::vector<int> sfPropIndexes;
	//int& sfIndex = stdPropIndexes[10];

	static const unsigned nListProp = 2;
	int listPropIndexes[nListProp] = {0,0};
	int& facesIndex = listPropIndexes[0];
	int& texCoordsIndex = listPropIndexes[1];

	//Combo box items for standard properties (coordinates, color components, etc.)
	QStringList stdPropsText;
	stdPropsText << QString("None");
	{
		for (int i=1; i<=static_cast<int>(stdProperties.size()); ++i)
		{
			plyProperty& pp = stdProperties[i-1];
			QString itemText = QString("%1 - %2 [%3]").arg(pointElements[pp.elemIndex].elementName).arg(pp.propName).arg(e_ply_type_names[pp.type]);
			assert(pp.type!=16); //we don't want any PLY_LIST here
			stdPropsText << itemText;

			QString elementName = QString(pointElements[pp.elemIndex].elementName).toUpper();
			QString propName = QString(pp.propName).toUpper();

			if (nxIndex == 0 && (propName.contains("NX") || (elementName.contains("NORM") && propName.endsWith("X"))))
				nxIndex = i;
			else if (nyIndex == 0 && (propName.contains("NY") || (elementName.contains("NORM") && propName.endsWith("Y"))))
				nyIndex = i;
			else if (nzIndex == 0 && (propName.contains("NZ") || (elementName.contains("NORM") && propName.endsWith("Z"))))
				nzIndex = i;
			else if (rIndex == 0 && (propName.contains("RED") || (elementName.contains("COL") && propName.endsWith("R"))))
				rIndex = i;
			else if (gIndex == 0 && (propName.contains("GREEN") || (elementName.contains("COL") && propName.endsWith("G"))))
				gIndex = i;
			else if (bIndex == 0 && (propName.contains("BLUE") || (elementName.contains("COL") && propName.endsWith("B"))))
				bIndex = i;
			else if (iIndex == 0 && (propName.contains("INTENSITY") || propName.contains("GRAY") || propName.contains("GREY") || (elementName.contains("COL") && propName.endsWith("I"))))
				iIndex = i;
			else if (elementName.contains("VERT") || elementName.contains("POINT"))
			{
				if (propName.contains("SCAL"))
					sfPropIndexes.push_back(i);
				else if (xIndex == 0 && propName.endsWith("X"))
					xIndex = i;
				else if (yIndex == 0 && propName.endsWith("Y"))
					yIndex = i;
				else if (zIndex == 0 && propName.endsWith("Z"))
					zIndex = i;
			}
			else if (propName.contains("SCAL") || propName.contains("VAL"))
				sfPropIndexes.push_back(i);
		}
	}

	//Combo box items for list properties (vertex indexes, etc.)
	QStringList listPropsText;
	{
		listPropsText << QString("None");
		for (int i=0; i<static_cast<int>(listProperties.size()); ++i)
		{
			plyProperty& pp = listProperties[i];
			QString itemText = QString("%0 - %1 [%2]").arg(meshElements[pp.elemIndex].elementName).arg(pp.propName).arg(e_ply_type_names[pp.type]);
			assert(pp.type==16); //we only want PLY_LIST here
			listPropsText << itemText;

			QString elementName = QString(meshElements[pp.elemIndex].elementName).toUpper();
			QString propName = QString(pp.propName).toUpper();

			if (elementName.contains("FACE") || elementName.contains("TRI"))
			{
				if (facesIndex == 0 && propName.contains("IND"))
					facesIndex = i+1;
				if (texCoordsIndex == 0 && propName.contains("COORD"))
					texCoordsIndex = i+1;
			}
		}
	}

	//combo-box max visible items
	int stdPropsCount = stdPropsText.count();
	int listPropsCount = listPropsText.count();

	//we need at least 2 coordinates!
	if (stdPropsCount < 2)
	{
		ccLog::Warning("[PLY] This ply file has less than 2 properties defined! (not even X and Y ;)");
		return CC_FERR_MALFORMED_FILE;
	}
	else if (stdPropsCount < 4 && !parameters.alwaysDisplayLoadDialog)
	{
		//brute force heuristic
		xIndex = 1;
		yIndex = 2;
		zIndex = (stdPropsCount > 3 ? 3 : 0);
		facesIndex = (listPropsCount > 1 ? 1 : 0);
	}
	else
	{
		//we count all assigned properties
		int assignedStdProperties = 0;
		{
			for (unsigned i=0; i<nStdProp; ++i)
				if (stdPropIndexes[i] > 0)
					++assignedStdProperties;
		}

		int assignedListProperties = 0;
		{
			for (unsigned i=0; i<nListProp; ++i)
				if (listPropIndexes[i] > 0)
					++assignedListProperties;
		}

		if (	parameters.alwaysDisplayLoadDialog
			||	stdPropsCount > assignedStdProperties+1		//+1 because of the first item in the combo box ('none')
			||	listPropsCount > assignedListProperties+1 )	//+1 because of the first item in the combo box ('none')
		{
			PlyOpenDlg pod/*(MainWindow::TheInstance())*/;

			pod.plyTypeEdit->setText(e_ply_storage_mode_names[storage_mode]);
			pod.elementsEdit->setText(QString::number(pointElements.size()));
			pod.propertiesEdit->setText(QString::number(listProperties.size()+stdProperties.size()));

			//we fill all combo-boxes with all items
			pod.setDefaultComboItems(stdPropsText);
			pod.setListComboItems(listPropsText);

			//try to restore previous context (if any)
			bool hasAPreviousContext = false;
			if (!pod.restorePreviousContext(hasAPreviousContext))
			{
				if (hasAPreviousContext)
					ccLog::Warning("[PLY] Too many differences with the previous file, we reset the dialog.");
				//Set default/guessed element
				pod.xComboBox->setCurrentIndex(xIndex);
				pod.yComboBox->setCurrentIndex(yIndex);
				pod.zComboBox->setCurrentIndex(zIndex);

				pod.rComboBox->setCurrentIndex(rIndex);
				pod.gComboBox->setCurrentIndex(gIndex);
				pod.bComboBox->setCurrentIndex(bIndex);

				pod.iComboBox->setCurrentIndex(iIndex);

				pod.sfComboBox->setCurrentIndex(sfPropIndexes.empty() ? 0 : sfPropIndexes.front());
				for (size_t j=1; j<sfPropIndexes.size(); ++j)
					pod.addSFComboBox(sfPropIndexes[j]);

				pod.nxComboBox->setCurrentIndex(nxIndex);
				pod.nyComboBox->setCurrentIndex(nyIndex);
				pod.nzComboBox->setCurrentIndex(nzIndex);

				pod.facesComboBox->setCurrentIndex(facesIndex);
				pod.textCoordsComboBox->setCurrentIndex(texCoordsIndex);
			}

			//We show the dialog (or we try to skip it ;)
			if (parameters.alwaysDisplayLoadDialog
				&& !pod.canBeSkipped()
				&& !pod.exec())
			{
				ply_close(ply);
				return CC_FERR_CANCELED_BY_USER;
			}

			//Force events processing (to hide dialog)
			QCoreApplication::processEvents();

			xIndex = pod.xComboBox->currentIndex();
			yIndex = pod.yComboBox->currentIndex();
			zIndex = pod.zComboBox->currentIndex();
			nxIndex = pod.nxComboBox->currentIndex();
			nyIndex = pod.nyComboBox->currentIndex();
			nzIndex = pod.nzComboBox->currentIndex();
			rIndex = pod.rComboBox->currentIndex();
			gIndex = pod.gComboBox->currentIndex();
			bIndex = pod.bComboBox->currentIndex();
			iIndex = pod.iComboBox->currentIndex();
			facesIndex = pod.facesComboBox->currentIndex();
			texCoordsIndex = pod.textCoordsComboBox->currentIndex();

			//get (non null) SF properties
			sfPropIndexes.clear();
			{
				for (size_t j=0; j<pod.m_sfCombos.size(); ++j)
					if (pod.m_sfCombos[j]->currentIndex() > 0)
						sfPropIndexes.push_back(pod.m_sfCombos[j]->currentIndex());
			}
		}
	}

	/*************************/
	/***  Callbacks setup  ***/
	/*************************/

	//Main point cloud
	ccPointCloud* cloud = new ccPointCloud("unnamed - Cloud");

	/* POINTS (X,Y,Z) */

	unsigned numberOfPoints = 0;

	assert(xIndex != yIndex && xIndex != zIndex && yIndex != zIndex);

	//POINTS (X)
	if (xIndex > 0)
	{
		long flags = ELEM_POS_0; //X coordinate
		if (xIndex > yIndex && xIndex > zIndex)
			flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[xIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, vertex_cb, cloud, flags);

		numberOfPoints = pointElements[pp.elemIndex].elementInstances;
	}

	//POINTS (Y)
	if (yIndex > 0)
	{
		long flags = ELEM_POS_1; //Y coordinate
		if (yIndex > xIndex && yIndex > zIndex)
			flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[yIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, vertex_cb, cloud, flags);

		if (numberOfPoints > 0)
		{
			if ((long)numberOfPoints != pointElements[pp.elemIndex].elementInstances)
			{
				ccLog::Warning("[PLY] Bad/uncompatible assignation of point properties!");
				delete cloud;
				ply_close(ply);
				return CC_FERR_BAD_ENTITY_TYPE;
			}
		}
		else numberOfPoints = pointElements[pp.elemIndex].elementInstances;
	}

	//POINTS (Z)
	if (zIndex > 0)
	{
		long flags = ELEM_POS_2; //Z coordinate
		if (zIndex > xIndex && zIndex > yIndex)
			flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[zIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, vertex_cb, cloud, flags);

		if (numberOfPoints > 0)
		{
			if ((long)numberOfPoints != pointElements[pp.elemIndex].elementInstances)
			{
				ccLog::Warning("[PLY] Bad/uncompatible assignation of point properties!");
				delete cloud;
				ply_close(ply);
				return CC_FERR_BAD_ENTITY_TYPE;
			}
		}
		else numberOfPoints = pointElements[pp.elemIndex].elementInstances;
	}

	if (numberOfPoints == 0 || !cloud->reserveThePointsTable(numberOfPoints))
	{
		delete cloud;
		ply_close(ply);
		return CC_FERR_NOT_ENOUGH_MEMORY;
	}

	/* NORMALS (X,Y,Z) */

	unsigned numberOfNormals=0;

	assert(nxIndex == 0 || (nxIndex != nyIndex && nxIndex != nzIndex));
	assert(nyIndex == 0 || (nyIndex != nxIndex && nyIndex != nzIndex));
	assert(nzIndex == 0 || (nzIndex != nxIndex && nzIndex != nyIndex));

	//NORMALS (X)
	if (nxIndex > 0)
	{
		long flags = ELEM_POS_0; //Nx
		if (nxIndex > nyIndex && nxIndex > nzIndex)
			flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[nxIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, normal_cb, cloud, flags);

		numberOfNormals = pointElements[pp.elemIndex].elementInstances;
	}

	//NORMALS (Y)
	if (nyIndex > 0)
	{
		long flags = ELEM_POS_1; //Ny
		if (nyIndex > nxIndex && nyIndex > nzIndex)
			flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[nyIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, normal_cb, cloud, flags);

		numberOfNormals = std::max(numberOfNormals, (unsigned)pointElements[pp.elemIndex].elementInstances);
	}

	//NORMALS (Z)
	if (nzIndex > 0)
	{
		long flags = ELEM_POS_2; //Nz
		if (nzIndex > nxIndex && nzIndex > nyIndex)
			flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[nzIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, normal_cb, cloud, flags);

		numberOfNormals = std::max(numberOfNormals, (unsigned)pointElements[pp.elemIndex].elementInstances);
	}

	//We check that the number of normals corresponds to the number of points
	if (numberOfNormals > 0)
	{
		if (numberOfPoints != numberOfNormals)
		{
			ccLog::Warning("[PLY] The number of normals doesn't match the number of points!");
			delete cloud;
			ply_close(ply);
			return CC_FERR_BAD_ENTITY_TYPE;
		}
		if (!cloud->reserveTheNormsTable())
		{
			delete cloud;
			ply_close(ply);
			return CC_FERR_NOT_ENOUGH_MEMORY;
		}
		cloud->showNormals(true);
	}

	/* COLORS (R,G,B) */

	unsigned numberOfColors=0;

	assert(rIndex == 0 || (rIndex != gIndex && rIndex != bIndex));
	assert(gIndex == 0 || (gIndex != rIndex && gIndex != bIndex));
	assert(bIndex == 0 || (bIndex != rIndex && bIndex != gIndex));

	if (rIndex > 0)
	{
		long flags = ELEM_POS_0; //R
		if (rIndex > gIndex && rIndex > bIndex)
			flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[rIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, rgb_cb, cloud, flags);

		numberOfColors = pointElements[pp.elemIndex].elementInstances;
	}

	if (gIndex > 0)
	{
		long flags = ELEM_POS_1; //G
		if (gIndex > rIndex && gIndex > bIndex)
			flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[gIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, rgb_cb, cloud, flags);

		numberOfColors = std::max(numberOfColors, (unsigned)pointElements[pp.elemIndex].elementInstances);
	}

	if (bIndex > 0)
	{
		long flags = ELEM_POS_2; //B
		if (bIndex > rIndex && bIndex > gIndex)
			flags |= ELEM_EOL;

		plyProperty& pp = stdProperties[bIndex-1];
		ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, rgb_cb, cloud, flags);

		numberOfColors = std::max(numberOfColors, (unsigned)pointElements[pp.elemIndex].elementInstances);
	}

	/* Intensity (I) */

	//INTENSITE (G)
	if (iIndex > 0)
	{
		if (numberOfColors > 0)
		{
			ccLog::Error("Can't import colors AND intensity (intensities will be ignored)!");
			ccLog::Warning("[PLY] intensities will be ignored");
		}
		else
		{
			plyProperty pp = stdProperties[iIndex-1];
			ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, grey_cb, cloud, 0);

			numberOfColors = pointElements[pp.elemIndex].elementInstances;
		}
	}

	//We check that the number of colors corresponds to the number of points
	if (numberOfColors > 0)
	{
		if (numberOfPoints != numberOfColors)
		{
			ccLog::Warning("The number of colors doesn't match the number of points!");
			delete cloud;
			ply_close(ply);
			return CC_FERR_BAD_ENTITY_TYPE;
		}
		if (!cloud->reserveTheRGBTable())
		{
			delete cloud;
			ply_close(ply);
			return CC_FERR_NOT_ENOUGH_MEMORY;
		}
		cloud->showColors(true);
	}

	/* SCALAR FIELDS (SF) */
	{
		for (size_t i=0; i<sfPropIndexes.size(); ++i)
		{
			int sfIndex = sfPropIndexes[i];
			plyProperty& pp = stdProperties[sfIndex-1];
			
			unsigned numberOfScalars = pointElements[pp.elemIndex].elementInstances;

			//does the number of scalars matches the number of points?
			if (numberOfPoints != numberOfScalars)
			{
				ccLog::Error(QString("Scalar field #%1: the number of scalars doesn't match the number of points (they will be ignored)!").arg(i+1));
				ccLog::Warning(QString("[PLY] Scalar field #%1 ignored!").arg(i+1));
				numberOfScalars = 0;
			}
			else 
			{
				QString qPropName(pp.propName);
				if (qPropName.startsWith("scalar_") && qPropName.length() > 7)
				{
					//remove the 'scalar_' prefix added when saving SF with CC!
					qPropName = qPropName.mid(7).replace('_',' ');
				}

				int sfIdx = cloud->addScalarField(qPrintable(qPropName));
				if (sfIdx >= 0)
				{
					CCLib::ScalarField* sf = cloud->getScalarField(sfIdx);
					assert(sf);
					if (sf->reserve(numberOfScalars))
					{
						ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, scalar_cb, sf, 1);
					}
					else
					{
						cloud->deleteScalarField(sfIdx);
						sfIdx = -1;
					}
				}
				
				if (sfIdx < 0)
				{
					ccLog::Error(QString("Scalar field #%1: not enough memory to load scalar field (they will be ignored)!").arg(i+1));
					ccLog::Warning(QString("[PLY] Scalar field #%1 ignored!").arg(i+1));
				}
			}
		}
	}

	/* MESH FACETS (TRI) */

	ccMesh* mesh = 0;
	unsigned numberOfFacets = 0;

	if (facesIndex > 0)
	{
		plyProperty& pp = listProperties[facesIndex-1];
		assert(pp.type==16); //we only accept PLY_LIST here!

		mesh = new ccMesh(cloud);

		numberOfFacets = meshElements[pp.elemIndex].elementInstances;

		if (!mesh->reserve(numberOfFacets))
		{
			ccLog::Error("Not enough memory to load facets (they will be ignored)!");
			ccLog::Warning("[PLY] Mesh ignored!");
			delete mesh;
			mesh = 0;
			numberOfFacets = 0;
		}
		else
		{
			ply_set_read_cb(ply, meshElements[pp.elemIndex].elementName, pp.propName, face_cb, mesh, 0);
		}
	}

	if (texCoordsIndex > 0)
	{
		plyProperty& pp = listProperties[texCoordsIndex-1];
		assert(pp.type == 16); //we only accept PLY_LIST here!

		texCoords = new TextureCoordsContainer();
		texCoords->link();

		long numberOfCoordinates = meshElements[pp.elemIndex].elementInstances;
		assert(numberOfCoordinates == numberOfFacets);

		if (!texCoords->reserve(numberOfCoordinates*3))
		{
			ccLog::Error("Not enough memory to load texture coordinates (they will be ignored)!");
			ccLog::Warning("[PLY] Texture coordinates ignored!");
			texCoords->release();
			texCoords = 0;
		}
		else
		{
			ply_set_read_cb(ply, meshElements[pp.elemIndex].elementName, pp.propName, texCoords_cb, texCoords, 0);
		}
	}

	ccProgressDialog pDlg(false);
	if (parameters.alwaysDisplayLoadDialog)
	{
		//pDlg.setInfo("Loading in progress...");
		//pDlg.setMethodTitle("PLY file");
		pDlg.setInfo("正在加载...");
		pDlg.setMethodTitle("PLY 文件");
		pDlg.setRange(0,0);
		pDlg.show();
		QApplication::processEvents();
	}

	//let 'Rply' do the job;)
	int success = 0;
	try
	{
		success = ply_read(ply);
	}
	catch(...)
	{
		success = -1;
	}

	ply_close(ply);

	if (success < 1)
	{
		if (mesh)
			delete mesh;
		delete cloud;
		return CC_FERR_READING;
	}

	//we check mesh
	if (mesh && mesh->size() == 0)
	{
		if (s_unsupportedPolygonType)
			ccLog::Error("Mesh is not triangular! (unsupported)");
		else
			ccLog::Error("Mesh is empty!");
		delete mesh;
		mesh=0;
	}

	if (texCoords && (s_invalidTexCoordinates || s_texCoordCount != 3*mesh->size()))
	{
		ccLog::Error("Invalid texture coordinates! (they will be ignored)");
		texCoords->release();
		texCoords=0;
	}

	//we save parameters
	parameters = s_loadParameters;

	//we update scalar field(s)
	{
		for (unsigned i=0; i<cloud->getNumberOfScalarFields(); ++i)
		{
			CCLib::ScalarField* sf = cloud->getScalarField(i);
			assert(sf);
			sf->computeMinAndMax();
			if (i == 0)
			{
				cloud->setCurrentDisplayedScalarField(0);
				cloud->showSF(true);
			}
		}
	}

	if (mesh)
	{
		assert(s_triCount > 0);
		//check number of loaded facets against 'theoretical' number
		if (s_triCount<numberOfFacets)
		{
			mesh->resize(s_triCount);
			ccLog::Warning("[PLY] Missing vertex indexes!");
		}

		//check that vertex indices start at 0
		unsigned minVertIndex=numberOfPoints,maxVertIndex=0;
		for (unsigned i=0;i<s_triCount;++i)
		{
			const CCLib::TriangleSummitsIndexes* tri = mesh->getTriangleIndexes(i);
			if (tri->i1 < minVertIndex)
				minVertIndex = tri->i1;
			else if (tri->i1 > maxVertIndex)
				maxVertIndex = tri->i1;
			if (tri->i2 < minVertIndex)
				minVertIndex = tri->i2;
			else if (tri->i2 > maxVertIndex)
				maxVertIndex = tri->i2;
			if (tri->i3 < minVertIndex)
				minVertIndex = tri->i3;
			else if (tri->i3 > maxVertIndex)
				maxVertIndex = tri->i3;
		}

		if (maxVertIndex>=numberOfPoints)
		{
			if (maxVertIndex == numberOfPoints && minVertIndex > 0)
			{
				ccLog::Warning("[PLY] Vertex indices seem to be shifted (+1)! We will try to 'unshift' indices (otherwise file is corrupted...)");
				for (unsigned i=0;i<s_triCount;++i)
				{
					CCLib::TriangleSummitsIndexes* tri = mesh->getTriangleIndexes(i);
					--tri->i1;
					--tri->i2;
					--tri->i3;
				}
			}
			else //file is definitely corrupted!
			{
				ccLog::Warning("[PLY] Invalid vertex indices!");
				delete mesh;
				delete cloud;
				return CC_FERR_MALFORMED_FILE;
			}
		}

		mesh->addChild(cloud);
		cloud->setEnabled(false);
		cloud->setName("Vertices");
		//cloud->setLocked(true); //DGM: no need to lock it as it is only used by one mesh!

		//associated texture
		if (texCoords)
		{
			if (!textureFileName.isEmpty())
			{
				QString textureFilePath = QFileInfo(filename).absolutePath() + QString('/') + textureFileName;
				ccMaterial::Shared material(new ccMaterial(textureFileName));
				if (material->loadAndSetTexture(textureFilePath))
				{
					if (mesh->reservePerTriangleTexCoordIndexes() && mesh->reservePerTriangleMtlIndexes())
					{
						const QImage texture = material->getTexture();
						ccLog::Print(QString("[PLY][Texture] Successfully loaded texture '%1' (%2x%3 pixels)").arg(textureFileName).arg(texture.width()).arg(texture.height()));
						//materials
						ccMaterialSet* materials = new ccMaterialSet("materials");
						material->setDiffuse(ccColor::bright);
						material->setSpecular(ccColor::darker);
						material->setAmbient(ccColor::darker);
						materials->push_back(material);
						mesh->setMaterialSet(materials);
						mesh->setTexCoordinatesTable(texCoords);
						for (unsigned i=0;i<mesh->size();++i)
						{
							mesh->addTriangleMtlIndex(0);
							mesh->addTriangleTexCoordIndexes(i*3,i*3+1,i*3+2);
						}
						mesh->showMaterials(true);
					}
					else
					{
						ccLog::Warning("[PLY][Texture] Failed to reserve per-triangle texture coordinates! (not enough memory?)");
					}
				}
				else
				{
					ccLog::Warning(QString("[PLY][Texture] Failed to load texture '%1'").arg(textureFilePath));
				}
			}
			else
			{
				ccLog::Warning("[PLY][Texture] Texture coordinates loaded without an associated image! (we look for the 'TextureFile' keyword in comments)");
			}
		}

		if (cloud->hasColors())
			mesh->showColors(true);
		if (cloud->hasDisplayedScalarField())
			mesh->showSF(true);
		if (cloud->hasNormals())
			mesh->showNormals(true);
		else
		{
			//DGM: normals can be per-vertex or per-triangle so it's better to let the user do it himself later
			//Moreover it's not always good idea if the user doesn't want normals (especially in ccViewer!)
			//mesh->computeNormals();
			ccLog::Warning("[PLY] Mesh has no normal! You can manually compute them (select it then call \"Edit > Normals > Compute\")");
		}

		if (mesh->hasMaterials())
			mesh->showNormals(false);

		container.addChild(mesh);
	}
	else
	{
		container.addChild(cloud);
	}

	if (texCoords)
	{
		texCoords->release();
		texCoords = 0;
	}

	return CC_FERR_NO_ERROR;
}
Пример #15
0
ccPointCloud* cc2Point5DimEditor::convertGridToCloud(	const std::vector<ExportableFields>& exportedFields,
														bool interpolateSF,
														bool resampleInputCloud,
														ccGenericPointCloud* inputCloud,
														bool fillEmptyCells,
														double emptyCellsHeight) const
{
	if (!m_grid.isValid())
		return 0;

	unsigned pointsCount = (fillEmptyCells ? m_grid.width * m_grid.height : m_grid.validCellCount);
	if (pointsCount == 0)
	{
		ccLog::Warning("[Rasterize] Empty grid!");
		return 0;
	}

	ccPointCloud* cloudGrid = 0;
	if (resampleInputCloud)
	{
		CCLib::ReferenceCloud refCloud(inputCloud);
		if (refCloud.reserve(m_grid.nonEmptyCellCount))
		{
			for (unsigned j=0; j<m_grid.height; ++j)
			{
				for (unsigned i=0; i<m_grid.width; ++i)
				{
					const RasterCell& cell = m_grid.data[j][i];
					if (cell.nbPoints) //non empty cell
					{
						refCloud.addPointIndex(cell.pointIndex);
					}
				}
			}

			assert(refCloud.size() != 0);
			cloudGrid = inputCloud->isA(CC_TYPES::POINT_CLOUD) ? static_cast<ccPointCloud*>(inputCloud)->partialClone(&refCloud) : ccPointCloud::From(&refCloud,inputCloud);
			cloudGrid->setPointSize(0); //to avoid display issues

			//even if we have already resampled the original cloud we may have to create new points and/or scalar fields
			//if (!interpolateSF && !fillEmptyCells)
			//	return cloudGrid;
		}
		else
		{
			ccLog::Warning("[Rasterize] Not enough memory!");
			return 0;
		}
	}
	else
	{
		cloudGrid = new ccPointCloud("grid");
	}
	assert(cloudGrid);
	
	//shall we generate per-cell fields as well?
	std::vector<CCLib::ScalarField*> exportedSFs;
	if (!exportedFields.empty())
	{
		exportedSFs.resize(exportedFields.size(),0);
		for (size_t i=0; i<exportedFields.size(); ++i)
		{
			int sfIndex = -1;
			switch (exportedFields[i])
			{
			case PER_CELL_HEIGHT:
			case PER_CELL_COUNT:
			case PER_CELL_MIN_HEIGHT:
			case PER_CELL_MAX_HEIGHT:
			case PER_CELL_AVG_HEIGHT:
			case PER_CELL_HEIGHT_STD_DEV:
			case PER_CELL_HEIGHT_RANGE:
				sfIndex = cloudGrid->addScalarField(qPrintable(GetDefaultFieldName(exportedFields[i])));
				break;
			default:
				assert(false);
				break;
			}
			if (sfIndex < 0)
			{
				ccLog::Warning("[Rasterize] Couldn't allocate scalar field(s)! Try to free some memory ...");
				break;
			}

			exportedSFs[i] = cloudGrid->getScalarField(sfIndex);
			assert(exportedSFs[i]);
		}
	}

	//the resampled cloud already contains the points corresponding to 'filled' cells so we will only
	//need to add the empty ones (if requested)
	if ((!resampleInputCloud || fillEmptyCells) && !cloudGrid->reserve(pointsCount))
	{
		ccLog::Warning("[Rasterize] Not enough memory!");
		delete cloudGrid;
		return 0;
	}

	//vertical dimension
	const unsigned char Z = getProjectionDimension();
	assert(Z >= 0 && Z <= 2);
	const unsigned char X = Z == 2 ? 0 : Z +1;
	const unsigned char Y = X == 2 ? 0 : X +1;

	//cloud bounding-box
	ccBBox box = getCustomBBox();
	assert(box.isValid());

	//we work with doubles as grid step can be much smaller than the cloud coordinates!
	double Py = box.minCorner().u[Y];

	//as the 'non empty cells points' are already in the cloud
	//we must take care of where we put the scalar fields values!
	unsigned nonEmptyCellIndex = 0;

	for (unsigned j=0; j<m_grid.height; ++j)
	{
		const RasterCell* aCell = m_grid.data[j];
		double Px = box.minCorner().u[X];
		for (unsigned i=0; i<m_grid.width; ++i,++aCell)
		{
			if (aCell->h == aCell->h) //valid cell
			{
				//if we haven't resampled the original cloud, we must add the point
				//corresponding to this non-empty cell
				if (!resampleInputCloud || aCell->nbPoints == 0)
				{
					CCVector3 Pf(	static_cast<PointCoordinateType>(Px),
									static_cast<PointCoordinateType>(Py),
									static_cast<PointCoordinateType>(aCell->h) );

					cloudGrid->addPoint(Pf);
				}

				//fill the associated SFs
				assert(exportedSFs.size() >= exportedFields.size());
				assert(!inputCloud || nonEmptyCellIndex < inputCloud->size());
				for (size_t i=0; i<exportedSFs.size(); ++i)
				{
					CCLib::ScalarField* sf = exportedSFs[i];
					ScalarType sVal = NAN_VALUE;
					switch (exportedFields[i])
					{
					case PER_CELL_HEIGHT:
						sVal = static_cast<ScalarType>(aCell->h);
						break;
					case PER_CELL_COUNT:
						sVal = static_cast<ScalarType>(aCell->nbPoints);
						break;
					case PER_CELL_MIN_HEIGHT:
						sVal = static_cast<ScalarType>(aCell->minHeight);
						break;
					case PER_CELL_MAX_HEIGHT:
						sVal = static_cast<ScalarType>(aCell->maxHeight);
						break;
					case PER_CELL_AVG_HEIGHT:
						sVal = static_cast<ScalarType>(aCell->avgHeight);
						break;
					case PER_CELL_HEIGHT_STD_DEV:
						sVal = static_cast<ScalarType>(aCell->stdDevHeight);
						break;
					case PER_CELL_HEIGHT_RANGE:
						sVal = static_cast<ScalarType>(aCell->maxHeight - aCell->minHeight);
						break;
					default:
						assert(false);
						break;
					}
					if (resampleInputCloud)
						sf->setValue(nonEmptyCellIndex,sVal);
					else
						sf->addElement(sVal);
				}
				++nonEmptyCellIndex;
			}
			else if (fillEmptyCells) //empty cell
			{
				//even if we have resampled the original cloud, we must add the point
				//corresponding to this empty cell
				{
					CCVector3 Pf(	static_cast<PointCoordinateType>(Px),
									static_cast<PointCoordinateType>(Py),
									static_cast<PointCoordinateType>(emptyCellsHeight) );
					cloudGrid->addPoint(Pf);
				}

				assert(exportedSFs.size() == exportedFields.size());
				for (size_t i=0; i<exportedSFs.size(); ++i)
				{
					if (!exportedSFs[i])
					{
						continue;
					}
					
					if (exportedFields[i] == PER_CELL_HEIGHT)
					{
						//we set the point height to the default height
						ScalarType s = static_cast<ScalarType>(emptyCellsHeight);
						exportedSFs[i]->addElement(s);
					}
					else
					{
						exportedSFs[i]->addElement(NAN_VALUE);
					}
				}
			}

			Px += m_grid.gridStep;
		}

		Py += m_grid.gridStep;
	}

	assert(exportedSFs.size() == exportedFields.size());
	for (size_t i=0; i<exportedSFs.size(); ++i)
	{
		CCLib::ScalarField* sf = exportedSFs[i];
		if (sf)
		{
			sf->computeMinAndMax();
		}
	}

	//take care of former scalar fields
	if (!resampleInputCloud)
	{
		if (interpolateSF && inputCloud && inputCloud->isA(CC_TYPES::POINT_CLOUD))
		{
			ccPointCloud* pc = static_cast<ccPointCloud*>(inputCloud);
			for (size_t k=0; k<m_grid.scalarFields.size(); ++k)
			{
				double* _sfGrid = m_grid.scalarFields[k];
				if (_sfGrid) //valid SF grid
				{
					//the corresponding SF should exist on the input cloud
					ccScalarField* formerSf = static_cast<ccScalarField*>(pc->getScalarField(static_cast<int>(k)));
					assert(formerSf);

					//we try to create an equivalent SF on the output grid
					int sfIdx = cloudGrid->addScalarField(formerSf->getName());
					if (sfIdx < 0) //if we aren't lucky, the input cloud already had a SF with CC_HEIGHT_GRID_FIELD_NAME as name
						sfIdx = cloudGrid->addScalarField(qPrintable(QString(formerSf->getName()).append(".old")));

					if (sfIdx < 0)
					{
						ccLog::Warning("[Rasterize] Couldn't allocate a new scalar field for storing SF '%s' values! Try to free some memory ...",formerSf->getName());
					}
					else
					{
						ccScalarField* sf = static_cast<ccScalarField*>(cloudGrid->getScalarField(sfIdx));
						assert(sf);
						//set sf values
						unsigned n = 0;
						const ScalarType emptyCellSFValue = CCLib::ScalarField::NaN();
						for (unsigned j=0; j<m_grid.height; ++j)
						{
							const RasterCell* aCell = m_grid.data[j];
							for (unsigned i=0; i<m_grid.width; ++i, ++_sfGrid, ++aCell)
							{
								if (aCell->nbPoints)
								{
									ScalarType s = static_cast<ScalarType>(*_sfGrid);
									sf->setValue(n++,s);
								}
								else if (fillEmptyCells)
								{
									sf->setValue(n++,emptyCellSFValue);
								}
							}
						}
						sf->computeMinAndMax();
						sf->importParametersFrom(formerSf);
						assert(sf->currentSize() == pointsCount);
					}
				}
			}
		}
	}
	else
	{
		for (size_t k=0; k<cloudGrid->getNumberOfScalarFields(); ++k)
		{
			CCLib::ScalarField* sf = cloudGrid->getScalarField(static_cast<int>(k));
			sf->resize(cloudGrid->size(),true,NAN_VALUE);
		}
	}

	QString gridName = QString("raster(%1)").arg(m_grid.gridStep);
	if (inputCloud)
	{
		gridName.prepend(inputCloud->getName() + QString("."));
	}
	cloudGrid->setName(gridName);

	return cloudGrid;
}
Пример #16
0
CC_FILE_ERROR VTKFilter::loadFile(const char* filename, ccHObject& container, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, CCVector3d* coordinatesShift/*=0*/)
{
	//open ASCII file for reading
	QFile file(filename);
	if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
		return CC_FERR_READING;

	QTextStream inFile(&file);

	//read header
	QString nextline = inFile.readLine();
	if (!nextline.startsWith("# vtk"))
		return CC_FERR_MALFORMED_FILE;

	//comment
	nextline = inFile.readLine();
	ccLog::Print(QString("[VTK] ")+nextline);

	ccMesh* mesh = 0;
	ccPointCloud* vertices = 0;
	
	std::vector<int> indexes; //global so as to avoid unnecessary mem. allocations
	QString lastSfName;
	bool acceptLookupTables = true;

	QString fileType = inFile.readLine().toUpper();
	if (fileType.startsWith("BINARY"))
	{
		//binary not supported yet!
		ccLog::Error("VTK binary format not supported yet!");
		return CC_FERR_WRONG_FILE_TYPE;
	}
	else if (fileType.startsWith("ASCII"))
	{
		//allow blank lines
		QString dataType;
		if (!GetNextNonEmptyLine(inFile,dataType))
			return CC_FERR_MALFORMED_FILE;
		if (!dataType.startsWith("DATASET"))
			return CC_FERR_MALFORMED_FILE;
		dataType.remove(0,8);
		if (dataType.startsWith("POLYDATA"))
		{
			vertices = new ccPointCloud("vertices");
			mesh = new ccMesh(vertices);
		}
		else if (dataType.startsWith("UNSTRUCTURED_GRID"))
		{
			vertices = new ccPointCloud("unnamed - VTK unstructured grid");
		}
		else
		{
			ccLog::Error(QString("VTK entity '%1' is not supported!").arg(dataType));
			return CC_FERR_WRONG_FILE_TYPE;
		}
	}

	//loop on keywords/data
	CC_FILE_ERROR error = CC_FERR_NO_ERROR;
	CCVector3d Pshift(0,0,0);
	while (error == CC_FERR_NO_ERROR)
	{
		if (!GetNextNonEmptyLine(inFile,nextline))
			break; //end of file

		assert(!nextline.isEmpty());

		if (nextline.startsWith("POINTS"))
		{
			QStringList parts = nextline.split(" ",QString::SkipEmptyParts);
			if (parts.size() != 3)
			{
				error=CC_FERR_MALFORMED_FILE;
				break;
			}

			bool ok = false;
			unsigned ptsCount = parts[1].toInt(&ok);
			if (!ok)
			{
				error = CC_FERR_MALFORMED_FILE;
				break;
			}

			//QString dataFormat = parts[3].toUpper();
			//char buffer[8];
			//unsigned char datSize = 4;
			//if (dataFormat == "DOUBLE")
			//{
			//	datSize = 8;
			//}
			//else if (dataFormat != "FLOAT")
			//{
			//	ccLog::Error(QString("Non floating point data (%1) is not supported!").arg(dataFormat));
			//	error = CC_FERR_WRONG_FILE_TYPE;
			//	break;
			//}

			if (!vertices->reserve(ptsCount))
			{
				error = CC_FERR_NOT_ENOUGH_MEMORY;
				break;
			}

			for (unsigned i=0; i<ptsCount; ++i)
			{
				nextline = inFile.readLine();
				parts = nextline.split(" ",QString::SkipEmptyParts);
				if (parts.size() != 3)
				{
					error = CC_FERR_MALFORMED_FILE;
					break;
				}

				double Pd[3] = {0,0,0};
				for (unsigned char j=0; j<3; ++j)
				{
					Pd[j] = parts[j].toDouble(&ok);
					if (!ok)
					{
						ccLog::Warning("[VTK] Element #%1 of POINTS data is corrupted!",i);
						error = CC_FERR_MALFORMED_FILE;
						break;
					}
				}

				//first point: check for 'big' coordinates
				if (i == 0)
				{
					bool shiftAlreadyEnabled = (coordinatesShiftEnabled && *coordinatesShiftEnabled && coordinatesShift);
					if (shiftAlreadyEnabled)
						Pshift = *coordinatesShift;
					bool applyAll = false;
					if (	sizeof(PointCoordinateType) < 8
						&&	ccCoordinatesShiftManager::Handle(Pd,0,alwaysDisplayLoadDialog,shiftAlreadyEnabled,Pshift,0,applyAll))
					{
						vertices->setGlobalShift(Pshift);
						ccLog::Warning("[VTKFilter::loadFile] Cloud has been recentered! Translation: (%.2f,%.2f,%.2f)",Pshift.x,Pshift.y,Pshift.z);

						//we save coordinates shift information
						if (applyAll && coordinatesShiftEnabled && coordinatesShift)
						{
							*coordinatesShiftEnabled = true;
							*coordinatesShift = Pshift;
						}
					}
				}

				vertices->addPoint(CCVector3(	static_cast<PointCoordinateType>(Pd[0] + Pshift.x),
												static_cast<PointCoordinateType>(Pd[1] + Pshift.y),
												static_cast<PointCoordinateType>(Pd[2] + Pshift.z)) );
			}
		//end POINTS
		}
		else if (nextline.startsWith("POLYGONS") || nextline.startsWith("TRIANGLE_STRIPS"))
		{
			QStringList parts = nextline.split(" ",QString::SkipEmptyParts);
			if (parts.size() != 3)
			{
				error = CC_FERR_MALFORMED_FILE;
				break;
			}

			//current type name (i.e. POLYGONS or TRIANGLE_STRIPS)
			QString typeName = parts[0];
			bool isPolygon = (typeName == "POLYGONS");

			bool ok = false;
			unsigned elemCount = parts[1].toUInt(&ok);
			if (!ok)
			{
				error = CC_FERR_MALFORMED_FILE;
				break;
			}
			
			unsigned totalElements = parts[2].toUInt(&ok);
			if (!ok)
			{
				error = CC_FERR_MALFORMED_FILE;
				break;
			}

			assert(mesh);
			if (!mesh)
			{
				ccLog::Warning(QString("[VTK] We found %1 data while file is not composed of POLYDATA!").arg(typeName));
				mesh = new ccMesh(vertices); //however, we can still try to load it?
			}

			for (unsigned i=0; i<elemCount; ++i)
			{
				nextline = inFile.readLine();
				parts = nextline.split(" ",QString::SkipEmptyParts);
				if (parts.empty()) 
				{
					error = CC_FERR_MALFORMED_FILE;
					break;
				}

				unsigned vertCount = parts[0].toUInt(&ok);
				if (!ok || static_cast<int>(vertCount) >= parts.size())
				{
					error = CC_FERR_MALFORMED_FILE;
					break;
				}
				else if (vertCount < 3)
				{
					ccLog::Warning(QString("[VTK] Element #%1 of %2 data is corrupted! (not enough indexes)").arg(i).arg(typeName));
				}

				if (isPolygon && (vertCount != 3 && vertCount != 4)) //quads are easy to handle as well!
				{
					ccLog::Warning(QString("[VTK] POLYGON element #%1 has an unhandled size (> 4 vertices)").arg(i));
					continue;
				}

				//reserve mem to. store indexes
				if (indexes.size() < vertCount)
				{
					try
					{
						indexes.resize(vertCount);
					}
					catch (std::bad_alloc)
					{
						error = CC_FERR_NOT_ENOUGH_MEMORY;
						break;
					}
				}
				//decode indexes
				for (unsigned j=0; j<vertCount; ++j)
				{
					indexes[j] = parts[j+1].toUInt(&ok);
					if (!ok)
					{
						ccLog::Warning(QString("[VTK] Element #%1 of %2 data is corrupted! (invalid index value)").arg(i).arg(typeName));
						error = CC_FERR_MALFORMED_FILE;
						break;
					}
				}

				//add the triangles
				{
					assert(vertCount > 2);
					unsigned triCount = vertCount-2;
					if (mesh->size() + triCount > mesh->maxSize())
					{
						if (!mesh->reserve(mesh->size()+triCount+256)) //take some advance to avoid too many allocations
						{
							error = CC_FERR_NOT_ENOUGH_MEMORY;
							break;
						}
					}

					if (isPolygon)
					{
						//triangle or quad
						mesh->addTriangle(indexes[0],indexes[1],indexes[2]);
						if (vertCount == 4)
							mesh->addTriangle(indexes[0],indexes[2],indexes[3]);
					}
					else
					{
						//triangle strip
						for (unsigned j=0; j<triCount; ++j)
							mesh->addTriangle(indexes[j],indexes[j+1],indexes[j+2]);
					}
				}
			}
			
			if (mesh->size() != 0 && mesh->size() < mesh->maxSize())
			{
				mesh->resize(mesh->size());
			}
		//end POLYGONS or TRIANGLE_STRIPS
		}
		else if (nextline.startsWith("NORMALS"))
		{
			unsigned ptsCount = vertices->size();
			if (vertices->size() == 0)
			{
				error = CC_FERR_MALFORMED_FILE;
				break;
			}
			else
			{
				bool loadNormals = vertices->reserveTheNormsTable();
				if (!loadNormals)
					ccLog::Warning("[VTK] Not enough memory to load normals!");
				for (unsigned i=0; i<ptsCount; ++i)
				{
					nextline = inFile.readLine();
					if (loadNormals)
					{
						QStringList parts = nextline.split(" ",QString::SkipEmptyParts);
						if (parts.size() != 3)
						{
							error = CC_FERR_MALFORMED_FILE;
							break;
						}
						CCVector3 N;
						for (unsigned char j=0; j<3; ++j)
						{
							bool ok;
							N.u[j] = (PointCoordinateType)parts[j].toDouble(&ok);
							if (!ok)
							{
								ccLog::Warning("[VTK] Element #%1 of NORMALS data is corrupted!",i);
								error = CC_FERR_MALFORMED_FILE;
								break;
							}
						}
						vertices->addNorm(N);
					}
				}
			}
		//end NORMALS
		}
		else if (nextline.startsWith("COLOR_SCALARS"))
		{
			unsigned ptsCount = vertices->size();
			if (vertices->size() == 0)
			{
				error = CC_FERR_MALFORMED_FILE;
				break;
			}
			else
			{
				bool loadRGBColors = vertices->reserveTheRGBTable();
				if (!loadRGBColors)
					ccLog::Warning("[VTK] Not enough memory to load RGB colors!");
				for (unsigned i=0; i<ptsCount; ++i)
				{
					nextline = inFile.readLine();
					if (loadRGBColors)
					{
						QStringList parts = nextline.split(" ",QString::SkipEmptyParts);
						if (parts.size() != 3)
						{
							error = CC_FERR_MALFORMED_FILE;
							break;
						}
						colorType rgb[3];
						for (unsigned char j=0; j<3; ++j)
						{
							bool ok;
							rgb[j] = (colorType)(parts[j].toDouble(&ok) * (double)MAX_COLOR_COMP);
							if (!ok)
							{
								ccLog::Warning("[VTK] Element #%1 of COLOR_SCALARS data is corrupted!",i);
								error = CC_FERR_MALFORMED_FILE;
								break;
							}
						}
						vertices->addRGBColor(rgb);
					}
				}
			}
		//end COLOR_SCALARS
		}
		else if (nextline.startsWith("SCALARS"))
		{
			QStringList parts = nextline.split(" ",QString::SkipEmptyParts);
			lastSfName = "ScalarField";
			if (parts.size() > 1)
				lastSfName = parts[1].replace("_"," ");

			//SF already exists?
			if (vertices->getScalarFieldIndexByName(qPrintable(lastSfName)) >= 0)
				lastSfName += QString(" (%1)").arg(vertices->getNumberOfScalarFields());
			//end of SCALARS
		}
		else if (nextline.startsWith("LOOKUP_TABLE") || nextline.startsWith("VECTORS"))
		{
			unsigned ptsCount = vertices->size();

			QStringList parts = nextline.split(" ",QString::SkipEmptyParts);
			QString itemName = parts[0];
			if (parts.size() > 2)
			{
				bool ok = false;
				int valCount = parts[2].toUInt(&ok);
				if (ok)
					ptsCount = valCount;
			}

			bool createSF = (vertices->size() == ptsCount && vertices->size() != 0);
			if (acceptLookupTables && !createSF)
			{
				ccLog::Warning(QString("[VTK] field %1 has not the right number of points (will be ignored)").arg(itemName));
			}
			createSF &= acceptLookupTables;
			if (createSF && lastSfName.isNull())
			{
				ccLog::Warning(QString("[VTK] field %1 has no name (will be ignored)").arg(itemName));
				createSF = false;
			}

			//create scalar field?
			int newSFIndex = createSF ? vertices->addScalarField(qPrintable(lastSfName)) : -1;
			CCLib::ScalarField* sf = newSFIndex >= 0 ? vertices->getScalarField(newSFIndex) : 0;
			
			lastSfName.clear(); //name is "consumed"
				
			for (unsigned i=0; i<ptsCount; ++i)
			{
				nextline = inFile.readLine();
				if (sf) //otherwise we simply skip the line
				{
					QStringList parts = nextline.split(" ",QString::SkipEmptyParts);
					if (parts.size() != 1)
					{
						//get rid of the scalar field :(
						vertices->deleteScalarField(newSFIndex);
						sf = 0;

						if (i == 0)
						{
							ccLog::Warning(QString("[VTK] %1 field with more than one element can't be imported as scalar fields!").arg(itemName));
						}
						else
						{
							error = CC_FERR_MALFORMED_FILE;
							break;
						}
					}
					else
					{
						bool ok;
						ScalarType d = static_cast<ScalarType>(nextline.toDouble(&ok));
						sf->setValue(i, ok ? d : NAN_VALUE);
					}
				}
			}

			if (sf)
			{
				sf->computeMinAndMax();
				vertices->setCurrentDisplayedScalarField(newSFIndex);
				vertices->showSF(true);
			}
		//end of SCALARS
		}
		else if (nextline.startsWith("POINT_DATA"))
		{
			//check that the number of 'point_data' match the number of points
			QStringList parts = nextline.split(" ",QString::SkipEmptyParts);
			acceptLookupTables = false;
			if (parts.size() > 1) 
			{
				bool ok;
				unsigned dataCount = parts[1].toUInt(&ok);
				if (ok && vertices && dataCount == vertices->size())
				{
					acceptLookupTables = true;
				}
			}

			if (!acceptLookupTables)
			{
				ccLog::Warning("[VTK] The number of 'POINT_DATA' doesn't match the number of loaded points... lookup tables will be ignored");
			}
		}
		else //unhandled property (CELLS, CELL_TYPES, etc.)
		{
			QStringList parts = nextline.split(" ",QString::SkipEmptyParts);
			if (parts.size() < 2) 
			{
				ccLog::Warning(QString("[VTK] Unhandled element: %1").arg(parts[0]));
				error = CC_FERR_MALFORMED_FILE;
				break;
			}

			bool ok;
			unsigned elements = parts[1].toUInt(&ok);
			if (!ok)
			{
				error = CC_FERR_MALFORMED_FILE;
				break;
			}

			for (unsigned i=0; i<elements; ++i)
			{
				inFile.readLine(); //ignore
			}
		//end unhandled property
		}

		if (error != CC_FERR_NO_ERROR)
			break;
	}

	if (error != CC_FERR_NO_ERROR)
	{
		if (mesh)
			delete mesh;
		if (vertices)
			delete vertices;
		return CC_FERR_MALFORMED_FILE;
	}

	file.close();

	if (mesh && mesh->size() == 0)
	{
		delete mesh;
		mesh = 0;
	}

	if (vertices->size() == 0)
	{
		delete vertices;
		return CC_FERR_NO_LOAD;
	}

	if (mesh)
	{
		container.addChild(mesh);
		mesh->setVisible(true);

		mesh->addChild(vertices);
		vertices->setVisible(false);
		vertices->setEnabled(false);
		vertices->setName("Vertices");
		vertices->setLocked(true); //DGM: no need to lock it as it is only used by one mesh!

		//DGM: normals can be per-vertex or per-triangle so it's better to let the user do it himself later
		//Moreover it's not always good idea if the user doesn't want normals (especially in ccViewer!)
		//if (!mesh->hasNormals())
		//	mesh->computeNormals();
		ccLog::Warning("[VTK] Mesh has no normal! You can manually compute them (select it then call \"Edit > Normals > Compute\")");
		mesh->showNormals(mesh->hasNormals());
		if (vertices->hasScalarFields())
		{
			vertices->setCurrentDisplayedScalarField(0);
			mesh->showSF(true);
		}
		if (vertices->hasColors())
			mesh->showColors(true);
	}
	else
	{
		container.addChild(vertices);
		vertices->setVisible(true);
		if (vertices->hasNormals())
			vertices->showNormals(true);
		if (vertices->hasScalarFields())
		{
			vertices->setCurrentDisplayedScalarField(0);
			vertices->showSF(true);
		}
		if (vertices->hasColors())
			vertices->showColors(true);
	}

	return CC_FERR_NO_ERROR;
}
Пример #17
0
CC_FILE_ERROR BinFilter::LoadFileV1(QFile& in, ccHObject& container, unsigned nbScansTotal, const LoadParameters& parameters)
{
	ccLog::Print("[BIN] Version 1.0");

	if (nbScansTotal > 99)
	{
		if (QMessageBox::question(0, QString("Oups"), QString("Hum, do you really expect %1 point clouds?").arg(nbScansTotal), QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
			return CC_FERR_WRONG_FILE_TYPE;
	}
	else if (nbScansTotal == 0)
	{
		return CC_FERR_NO_LOAD;
	}

	ccProgressDialog pdlg(true, parameters.parentWidget);
	pdlg.setMethodTitle(QObject::tr("Open Bin file (old style)"));

	for (unsigned k=0; k<nbScansTotal; k++)
	{
		HeaderFlags header;
		unsigned nbOfPoints = 0;
		if (ReadEntityHeader(in, nbOfPoints, header) < 0)
		{
			return CC_FERR_READING;
		}

		//Console::print("[BinFilter::loadModelFromBinaryFile] Entity %i : %i points, color=%i, norms=%i, dists=%i\n",k,nbOfPoints,color,norms,distances);

		if (nbOfPoints == 0)
		{
			//Console::print("[BinFilter::loadModelFromBinaryFile] rien a faire !\n");
			continue;
		}

		//progress for this cloud
		CCLib::NormalizedProgress nprogress(&pdlg, nbOfPoints);
		if (parameters.alwaysDisplayLoadDialog)
		{
			pdlg.reset();
			pdlg.setInfo(QObject::tr("cloud %1/%2 (%3 points)").arg(k + 1).arg(nbScansTotal).arg(nbOfPoints));
			pdlg.start();
			QApplication::processEvents();
		}

		//Cloud name
		char cloudName[256] = "unnamed";
		if (header.name)
		{
			for (int i=0; i<256; ++i)
			{
				if (in.read(cloudName+i,1) < 0)
				{
					//Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the cloud name!\n");
					return CC_FERR_READING;
				}
				if (cloudName[i] == 0)
				{
					break;
				}
			}
			//we force the end of the name in case it is too long!
			cloudName[255] = 0;
		}
		else
		{
			sprintf(cloudName,"unnamed - Cloud #%u",k);
		}

		//Cloud name
		char sfName[1024] = "unnamed";
		if (header.sfName)
		{
			for (int i=0; i<1024; ++i)
			{
				if (in.read(sfName+i,1) < 0)
				{
					//Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the cloud name!\n");
					return CC_FERR_READING;
				}
				if (sfName[i] == 0)
					break;
			}
			//we force the end of the name in case it is too long!
			sfName[1023] = 0;
		}
		else
		{
			strcpy(sfName,"Loaded scalar field");
		}
		
		//Creation
		ccPointCloud* loadedCloud = new ccPointCloud(cloudName);
		if (!loadedCloud)
			return CC_FERR_NOT_ENOUGH_MEMORY;

		unsigned fileChunkPos = 0;
		unsigned fileChunkSize = std::min(nbOfPoints,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD);

		loadedCloud->reserveThePointsTable(fileChunkSize);
		if (header.colors)
		{
			loadedCloud->reserveTheRGBTable();
			loadedCloud->showColors(true);
		}
		if (header.normals)
		{
			loadedCloud->reserveTheNormsTable();
			loadedCloud->showNormals(true);
		}
		if (header.scalarField)
			loadedCloud->enableScalarField();

		unsigned lineRead = 0;
		int parts = 0;

		const ScalarType FORMER_HIDDEN_POINTS = (ScalarType)-1.0;

		//lecture du fichier
		for (unsigned i=0; i<nbOfPoints; ++i)
		{
			if (lineRead == fileChunkPos+fileChunkSize)
			{
				if (header.scalarField)
					loadedCloud->getCurrentInScalarField()->computeMinAndMax();

				container.addChild(loadedCloud);
				fileChunkPos = lineRead;
				fileChunkSize = std::min(nbOfPoints-lineRead,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD);
				char partName[64];
				++parts;
				sprintf(partName,"%s.part_%i",cloudName,parts);
				loadedCloud = new ccPointCloud(partName);
				loadedCloud->reserveThePointsTable(fileChunkSize);

				if (header.colors)
				{
					loadedCloud->reserveTheRGBTable();
					loadedCloud->showColors(true);
				}
				if (header.normals)
				{
					loadedCloud->reserveTheNormsTable();
					loadedCloud->showNormals(true);
				}
				if (header.scalarField)
					loadedCloud->enableScalarField();
			}

			float Pf[3];
			if (in.read((char*)Pf,sizeof(float)*3) < 0)
			{
				//Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity point !\n",k);
				return CC_FERR_READING;
			}
			loadedCloud->addPoint(CCVector3::fromArray(Pf));

			if (header.colors)
			{
				unsigned char C[3];
				if (in.read((char*)C,sizeof(ColorCompType)*3) < 0)
				{
					//Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity colors !\n",k);
					return CC_FERR_READING;
				}
				loadedCloud->addRGBColor(C);
			}

			if (header.normals)
			{
				CCVector3 N;
				if (in.read((char*)N.u,sizeof(float)*3) < 0)
				{
					//Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity norms !\n",k);
					return CC_FERR_READING;
				}
				loadedCloud->addNorm(N);
			}

			if (header.scalarField)
			{
				double D;
				if (in.read((char*)&D,sizeof(double)) < 0)
				{
					//Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity distance!\n",k);
					return CC_FERR_READING;
				}
				ScalarType d = static_cast<ScalarType>(D);
				loadedCloud->setPointScalarValue(i,d);
			}

			lineRead++;

			if (parameters.alwaysDisplayLoadDialog && !nprogress.oneStep())
			{
				loadedCloud->resize(i+1-fileChunkPos);
				k=nbScansTotal;
				i=nbOfPoints;
			}
		}

		if (parameters.alwaysDisplayLoadDialog)
		{
			pdlg.stop();
			QApplication::processEvents();
		}

		if (header.scalarField)
		{
			CCLib::ScalarField* sf = loadedCloud->getCurrentInScalarField();
			assert(sf);
			sf->setName(sfName);

			//replace HIDDEN_VALUES by NAN_VALUES
			for (unsigned i=0; i<sf->currentSize(); ++i)
			{
				if (sf->getValue(i) == FORMER_HIDDEN_POINTS)
					sf->setValue(i,NAN_VALUE);
			}
			sf->computeMinAndMax();

			loadedCloud->setCurrentDisplayedScalarField(loadedCloud->getCurrentInScalarFieldIndex());
			loadedCloud->showSF(true);
		}

		container.addChild(loadedCloud);
	}

	return CC_FERR_NO_ERROR;
}
Пример #18
0
CC_FILE_ERROR BinFilter::loadFileV1(QFile& in, ccHObject& container, unsigned nbScansTotal)
{
	if (nbScansTotal>99)
	{
		if (QMessageBox::question(0, QString("Oups"), QString("Hum, do you really expect %1 point clouds?").arg(nbScansTotal))==QMessageBox::No)
			return CC_FERR_WRONG_FILE_TYPE;
	}
	else if (nbScansTotal==0)
	{
		return CC_FERR_NO_LOAD;
	}

	ccProgressDialog pdlg(true);
	pdlg.setMethodTitle("Open Bin file (old style)");

	for (unsigned k=0;k<nbScansTotal;k++)
	{
		HeaderFlags header;
		unsigned nbOfPoints=0;
		if (ReadEntityHeader(in,nbOfPoints,header) < 0)
			return CC_FERR_READING;

		//Console::print("[BinFilter::loadModelFromBinaryFile] Entity %i : %i points, color=%i, norms=%i, dists=%i\n",k,nbOfPoints,color,norms,distances);

		//progress for this cloud
		CCLib::NormalizedProgress nprogress(&pdlg,nbOfPoints);
		pdlg.reset();
		char buffer[256];
		sprintf(buffer,"cloud %i/%i (%i points)",k+1,nbScansTotal,nbOfPoints);
		pdlg.setInfo(buffer);
		pdlg.start();
		QApplication::processEvents();

		if (nbOfPoints==0)
		{
			//Console::print("[BinFilter::loadModelFromBinaryFile] rien a faire !\n");
			continue;
		}

		//Cloud name
		char cloudName[256]="unnamed";
		if (header.name)
		{
			for (int i=0;i<256;++i)
			{
				if (in.read(cloudName+i,1)<0)
				{
					//Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the cloud name!\n");
					return CC_FERR_READING;
				}
				if (cloudName[i]==0)
					break;
			}
			//we force the end of the name in case it is too long!
			cloudName[255]=0;
		}
		else
		{
			sprintf(cloudName,"unnamed - Cloud #%i",k);
		}

		//Cloud name
		char sfName[1024]="unnamed";
		if (header.sfName)
		{
			for (int i=0;i<1024;++i)
			{
				if (in.read(sfName+i,1)<0)
				{
					//Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the cloud name!\n");
					return CC_FERR_READING;
				}
				if (sfName[i]==0)
					break;
			}
			//we force the end of the name in case it is too long!
			sfName[1023]=0;
		}
		else
		{
			strcpy(sfName,"Loaded scalar field");
		}
		//Creation
		ccPointCloud* loadedCloud = new ccPointCloud(cloudName);
		if (!loadedCloud)
			return CC_FERR_NOT_ENOUGH_MEMORY;

		unsigned fileChunkPos = 0;
		unsigned fileChunkSize = ccMin(nbOfPoints,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD);

		loadedCloud->reserveThePointsTable(fileChunkSize);
		if (header.colors)
		{
			loadedCloud->reserveTheRGBTable();
			loadedCloud->showColors(true);
		}
		if (header.normals)
		{
			loadedCloud->reserveTheNormsTable();
			loadedCloud->showNormals(true);
		}
		if (header.scalarField)
			loadedCloud->enableScalarField();

		CCVector3 P;
		unsigned char C[3];
		double D;

		//does the associated scalar field is negative?
		bool negSF = false;

		unsigned lineReaded=0;
		int parts = 0;

		//lecture du fichier
		for (unsigned i=0;i<nbOfPoints;++i)
		{
			if (lineReaded == fileChunkPos+fileChunkSize)
			{
				if (header.scalarField)
					loadedCloud->getCurrentInScalarField()->computeMinAndMax();

				container.addChild(loadedCloud);
				fileChunkPos = lineReaded;
				fileChunkSize = ccMin(nbOfPoints-lineReaded,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD);
				char partName[64];
				++parts;
				sprintf(partName,"%s.part_%i",cloudName,parts);
				loadedCloud = new ccPointCloud(partName);
				loadedCloud->reserveThePointsTable(fileChunkSize);

				if (header.colors)
				{
					loadedCloud->reserveTheRGBTable();
					loadedCloud->showColors(true);
				}
				if (header.normals)
				{
					loadedCloud->reserveTheNormsTable();
					loadedCloud->showNormals(true);
				}
				if (header.scalarField)
					loadedCloud->enableScalarField();
			}

			if (in.read((char*)P.u,sizeof(float)*3)<0)
			{
				//Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity point !\n",k);
				return CC_FERR_READING;
			}
			loadedCloud->addPoint(P);

			if (header.colors)
			{
				if (in.read((char*)C,sizeof(colorType)*3)<0)
				{
					//Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity colors !\n",k);
					return CC_FERR_READING;
				}
				loadedCloud->addRGBColor(C);
			}

			if (header.normals)
			{
				if (in.read((char*)P.u,sizeof(float)*3)<0)
				{
					//Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity norms !\n",k);
					return CC_FERR_READING;
				}
				loadedCloud->addNorm(P.u);
			}

			if (header.scalarField)
			{
				if (in.read((char*)&D,sizeof(double))<0)
				{
					//Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity distance !\n",k);
					return CC_FERR_READING;
				}
				DistanceType d = (DistanceType)D;
				//if there are negative values, we test if they are particular values (HIDDEN_VALUE, etc.)
				//or not particular (in which case we have a non strictly positive SF)
				if (d<0.0 && !negSF)
				{
					//we must test if the value is a particular one
					if (d != HIDDEN_VALUE &&
						d != OUT_VALUE &&
						d != SEGMENTED_VALUE)
						negSF = true;
				}
				loadedCloud->setPointScalarValue(i,d);
			}

			lineReaded++;

			if (!nprogress.oneStep())
			{
				loadedCloud->resize(i+1-fileChunkPos);
				k=nbScansTotal;
				i=nbOfPoints;
			}
		}

		if (header.scalarField)
		{
			CCLib::ScalarField* sf = loadedCloud->getCurrentInScalarField();
			assert(sf);
			sf->setName(sfName);
			sf->setPositive(!negSF);
			sf->computeMinAndMax();

			loadedCloud->setCurrentDisplayedScalarField(loadedCloud->getCurrentInScalarFieldIndex());
			loadedCloud->showSF(true);
		}

		container.addChild(loadedCloud);
	}

	return CC_FERR_NO_ERROR;
}