void ccGraphicalTransformationTool::clear()
{
	m_toTransform.detatchAllChildren();

	m_rotation.toIdentity();
	m_translation = CCVector3d(0,0,0);
	m_rotationCenter = CCVector3d(0,0,0);
}
void ccGraphicalTransformationTool::reset()
{
	m_rotation.toIdentity();
	m_translation = CCVector3d(0,0,0);

	updateAllGLTransformations();
}
bool ccGraphicalTransformationTool::start()
{
	assert(!m_processing);
	assert(m_associatedWin);
	if (!m_associatedWin)
		return false;

	unsigned childNum = m_toTransform.getChildrenNumber();
	if (childNum == 0)
		return false;

	m_rotation.toIdentity();
	m_translation = CCVector3d(0,0,0);
	m_rotationCenter = CCVector3d::fromArray(m_toTransform.getBB_recursive().getCenter().u); //m_rotation center == selected entities center

	//activate "moving mode" in associated GL window
	m_associatedWin->setInteractionMode(ccGLWindow::TRANSFORM_ENTITY);
	m_associatedWin->setPickingMode(ccGLWindow::NO_PICKING);
	//the user must not close this window!
	m_associatedWin->setUnclosable(true);
	connect(m_associatedWin, SIGNAL(rotation(const ccGLMatrixd&)),		this, SLOT(glRotate(const ccGLMatrixd&)));
	connect(m_associatedWin, SIGNAL(translation(const CCVector3d&)),	this, SLOT(glTranslate(const CCVector3d&)));
	m_associatedWin->displayNewMessage(QString(),ccGLWindow::UPPER_CENTER_MESSAGE); //clear the area
	m_associatedWin->displayNewMessage("[Rotation/Translation mode]",ccGLWindow::UPPER_CENTER_MESSAGE,false,3600,ccGLWindow::MANUAL_TRANSFORMATION_MESSAGE);
	m_associatedWin->redraw(true, false);

	return ccOverlayDialog::start();
}
bool ccGenericPointCloud::isClicked(const CCVector2d& clickPos,
									int& nearestPointIndex,
									double& nearestSquareDist,
									const double* MM,
									const double* MP,
									const int* VP,
									double pickWidth/*=2.0*/,
									double pickHeight/*=2.0*/)
{
	ccGLMatrix trans;
	bool noGLTrans = !getAbsoluteGLTransformation(trans);

	//back project the clicked point in 3D
	CCVector3d clickPosd(clickPos.x, clickPos.y, 0);
	CCVector3d X(0,0,0);
	ccGL::Unproject<double, double>(clickPosd, MM, MP, VP, X);

	nearestPointIndex = -1;
	nearestSquareDist = -1.0;

#if defined(_OPENMP)
#pragma omp parallel for
#endif
	//brute force works quite well in fact?!
	for (unsigned i=0; i<size(); ++i)
	{
		const CCVector3* P = getPoint(i);
		CCVector3d Qs;
		if (noGLTrans)
		{
			ccGL::Project<PointCoordinateType, double>(*P,MM,MP,VP,Qs);
		}
		else
		{
			CCVector3 Q = *P;
			trans.apply(Q);
			ccGL::Project<PointCoordinateType, double>(Q,MM,MP,VP,Qs);
		}

		if (fabs(Qs.x-clickPos.x) <= pickWidth && fabs(Qs.y-clickPos.y) <= pickHeight)
		{
			double squareDist = CCVector3d(X.x-P->x, X.y-P->y, X.z-P->z).norm2d();
			if (nearestPointIndex < 0 || squareDist < nearestSquareDist)
			{
				nearestSquareDist = squareDist;
				nearestPointIndex = static_cast<int>(i);
			}
		}
	}

	return (nearestPointIndex >= 0);
}
Example #5
0
void ccCameraParamEditDlg::cameraCenterChanged()
{
	if (!m_associatedWin)
		return;

	m_associatedWin->blockSignals(true);
	m_associatedWin->setCameraPos( CCVector3d(	exDoubleSpinBox->value(),
												eyDoubleSpinBox->value(),
												ezDoubleSpinBox->value() ));
	m_associatedWin->blockSignals(false);

	m_associatedWin->redraw();
}
//============================================pivotChanged==================================================//
// GLWindow->setPivotPoint(CCVector3d & P);//设置的时候阻塞信号
void ccCameraParamEditDlg::pivotChanged()
{
	if (!m_associatedWin)	return;

	m_associatedWin->blockSignals(true);
	m_associatedWin->setPivotPoint(CCVector3d(rcxDoubleSpinBox->value(),
		                                      rcyDoubleSpinBox->value(),
		                                      rczDoubleSpinBox->value()) );
	m_associatedWin->blockSignals(false);
	
	//重新绘制场景
	m_associatedWin->redraw();
}
CCVector3d ccGlobalShiftManager::BestShift(const CCVector3d& P)
{
	if (!NeedShift(P))
	{
		return CCVector3d(0,0,0);
	}

	CCVector3d shift(	fabs(P[0]) >= MAX_COORDINATE_ABS_VALUE ? -P[0] : 0,
						fabs(P[1]) >= MAX_COORDINATE_ABS_VALUE ? -P[1] : 0,
						fabs(P[2]) >= MAX_COORDINATE_ABS_VALUE ? -P[2] : 0 );

	//round-off to the nearest hundred
	shift.x = static_cast<int>(shift.x / 100) * 100.0;
	shift.y = static_cast<int>(shift.y / 100) * 100.0;
	shift.z = static_cast<int>(shift.z / 100) * 100.0;

	return shift;
}
bool ccPointPairRegistrationDlg::convertToSphereCenter(CCVector3d& P, ccHObject* entity, PointCoordinateType& sphereRadius)
{
	sphereRadius = -PC_ONE;
	if (	!entity
		||	!useSphereToolButton->isChecked()
		||	!entity->isKindOf(CC_TYPES::POINT_CLOUD) ) //only works with cloud right now
	{
		//nothing to do
		return true;
	}

	//we'll now try to detect the sphere
	double searchRadius = radiusDoubleSpinBox->value();
	double maxRMSPercentage = maxRmsSpinBox->value() / 100.0;
	ccGenericPointCloud* cloud = static_cast<ccGenericPointCloud*>(entity);
	assert(cloud);

	//crop points inside a box centered on the current point
	ccBBox box;
	box.add(CCVector3::fromArray((P - CCVector3d(1,1,1)*searchRadius).u));
	box.add(CCVector3::fromArray((P + CCVector3d(1,1,1)*searchRadius).u));
	CCLib::ReferenceCloud* part = cloud->crop(box,true);

	bool success = false;
	if (part && part->size() > 16)
	{
		PointCoordinateType radius;
		CCVector3 C;
		double rms;
		ccProgressDialog pDlg(true, this);
		//first roughly search for the sphere
		if (CCLib::GeometricalAnalysisTools::detectSphereRobust(part,0.5,C,radius,rms,&pDlg,0.9))
		{
			if (radius / searchRadius < 0.5 || radius / searchRadius > 2.0)
			{
				ccLog::Warning(QString("[ccPointPairRegistrationDlg] Detected sphere radius (%1) is too far from search radius!").arg(radius));
			}
			else
			{
				//now look again (more precisely)
				{
					delete part;
					box.clear();
					box.add(C - CCVector3(1,1,1)*radius*static_cast<PointCoordinateType>(1.05)); //add 5%
					box.add(C + CCVector3(1,1,1)*radius*static_cast<PointCoordinateType>(1.05)); //add 5%
					part = cloud->crop(box,true);
					if (part && part->size() > 16)
						CCLib::GeometricalAnalysisTools::detectSphereRobust(part,0.5,C,radius,rms,&pDlg,0.99);
				}
				ccLog::Print(QString("[ccPointPairRegistrationDlg] Detected sphere radius = %1 (rms = %2)").arg(radius).arg(rms));
				if (radius / searchRadius < 0.5 || radius / searchRadius > 2.0)
				{
					ccLog::Warning("[ccPointPairRegistrationDlg] Sphere radius is too far from search radius!");
				}
				else if (rms / searchRadius >= maxRMSPercentage)
				{
					ccLog::Warning("[ccPointPairRegistrationDlg] RMS is too high!");
				}
				else
				{
					sphereRadius = radius;
					P = CCVector3d::fromArray(C.u);
					success = true;
				}
			}
		}
		else
		{
			ccLog::Warning("[ccPointPairRegistrationDlg] Failed to fit a sphere around the picked point!");
		}
	}
	else
	{
		//not enough memory? No points inside the 
		ccLog::Warning("[ccPointPairRegistrationDlg] Failed to crop points around the picked point?!");
	}

	if (part)
		delete part;

	return success;
}
void ccPointListPickingDlg::exportToASCII(ExportFormat format)
{
	if (!m_associatedCloud)
		return;

	//get all labels
	std::vector<cc2DLabel*> labels;
	unsigned count = getPickedPoints(labels);
	if (count == 0)
		return;

	QSettings settings;
	settings.beginGroup("PointListPickingDlg");
	QString filename = settings.value("filename", "picking_list.txt").toString();
	settings.endGroup();

	filename = QFileDialog::getSaveFileName(this,
											"Export to ASCII",
											filename,
											AsciiFilter::GetFileFilter());

	if (filename.isEmpty())
		return;

	settings.beginGroup("PointListPickingDlg");
	settings.setValue("filename", filename);
	settings.endGroup();

	FILE* fp = fopen(qPrintable(filename),"wt");
	if (!fp)
	{
		ccLog::Error(QString("Failed to open file '%1' for saving!").arg(filename));
		return;
	}

	//if a global shift exists, ask the user if it should be applied
	CCVector3d shift = m_associatedCloud->getGlobalShift();
	double scale = m_associatedCloud->getGlobalScale();

	if (shift.norm2() != 0 || scale != 1.0)
	{
		if (QMessageBox::warning(	this,
									"Apply global shift",
									"Do you want to apply global shift/scale to exported points?",
									QMessageBox::Yes | QMessageBox::No,
									QMessageBox::Yes ) == QMessageBox::No)
		{
			//reset shift
			shift = CCVector3d(0,0,0);
			scale = 1.0;
		}
	}

	//starting index
	int startIndex = startIndexSpinBox->value();

	for (unsigned i=0; i<count; ++i)
	{
		assert(labels[i]->size() == 1);
		const cc2DLabel::PickedPoint& PP = labels[i]->getPoint(0);
		const CCVector3* P = PP.cloud->getPoint(PP.index);

		if (format == PLP_ASCII_EXPORT_IXYZ)
			fprintf(fp,"%i,",i+startIndex);

		fprintf(fp,"%.12f,%.12f,%.12f\n",	static_cast<double>(P->x)/scale - shift.x,
											static_cast<double>(P->y)/scale - shift.y,
											static_cast<double>(P->z)/scale - shift.z);
	}

	fclose(fp);

	ccLog::Print(QString("[I/O] File '%1' saved successfully").arg(filename));
}
Example #10
0
bool ccClipBox::move3D(const CCVector3d& uInput)
{
	if (m_activeComponent == NONE || !m_box.isValid())
		return false;

	CCVector3d u = uInput;

	//Arrows
	if (m_activeComponent >= X_MINUS_ARROW && m_activeComponent <= CROSS)
	{
		if (m_glTransEnabled)
			m_glTrans.inverse().applyRotation(u);

		switch(m_activeComponent)
		{
		case X_MINUS_ARROW:
			m_box.minCorner().x += static_cast<PointCoordinateType>(u.x);
			if (m_box.minCorner().x > m_box.maxCorner().x)
				m_box.minCorner().x = m_box.maxCorner().x;
			break;
		case X_PLUS_ARROW:
			m_box.maxCorner().x += static_cast<PointCoordinateType>(u.x);
			if (m_box.minCorner().x > m_box.maxCorner().x)
				m_box.maxCorner().x = m_box.minCorner().x;
			break;
		case Y_MINUS_ARROW:
			m_box.minCorner().y += static_cast<PointCoordinateType>(u.y);
			if (m_box.minCorner().y > m_box.maxCorner().y)
				m_box.minCorner().y = m_box.maxCorner().y;
			break;
		case Y_PLUS_ARROW:
			m_box.maxCorner().y += static_cast<PointCoordinateType>(u.y);
			if (m_box.minCorner().y > m_box.maxCorner().y)
				m_box.maxCorner().y = m_box.minCorner().y;
			break;
		case Z_MINUS_ARROW:
			m_box.minCorner().z += static_cast<PointCoordinateType>(u.z);
			if (m_box.minCorner().z > m_box.maxCorner().z)
				m_box.minCorner().z = m_box.maxCorner().z;
			break;
		case Z_PLUS_ARROW:
			m_box.maxCorner().z += static_cast<PointCoordinateType>(u.z);
			if (m_box.minCorner().z > m_box.maxCorner().z)
				m_box.maxCorner().z = m_box.minCorner().z;
			break;
		case CROSS:
			m_box += CCVector3::fromArray(u.u);
			break;
		default:
			assert(false);
			return false;
		}
		
		//send 'modified' signal
		emit boxModified(&m_box);
	}
	else if (m_activeComponent == SPHERE)
	{
		//handled by move2D!
		return false;
	}
	else if (m_activeComponent >= X_MINUS_TORUS && m_activeComponent <= Z_PLUS_TORUS)
	{
		//we guess the rotation order by comparing the current screen 'normal'
		//and the vector prod of u and the current rotation axis
		CCVector3d Rb(0,0,0);
		switch(m_activeComponent)
		{
		case X_MINUS_TORUS:
			Rb.x = -1;
			break;
		case X_PLUS_TORUS:
			Rb.x = 1;
			break;
		case Y_MINUS_TORUS:
			Rb.y = -1;
			break;
		case Y_PLUS_TORUS:
			Rb.y = 1;
			break;
		case Z_MINUS_TORUS:
			Rb.z = -1;
			break;
		case Z_PLUS_TORUS:
			Rb.z = 1;
			break;
		default:
			assert(false);
			return false;
		}
		
		CCVector3d R = Rb;
		if (m_glTransEnabled)
			m_glTrans.applyRotation(R);

		CCVector3d RxU = R.cross(u);

		//look for the most parallel dimension
		int minDim = 0;
		double maxDot = m_viewMatrix.getColumnAsVec3D(0).dot(RxU);
		for (int i=1; i<3; ++i)
		{
			double dot = m_viewMatrix.getColumnAsVec3D(i).dot(RxU);
			if (fabs(dot) > fabs(maxDot))
			{
				maxDot = dot;
				minDim = i;
			}
		}

		//angle is proportional to absolute displacement
		double angle_rad = u.norm()/m_box.getDiagNorm() * M_PI;
		if (maxDot < 0.0)
			angle_rad = -angle_rad;

		ccGLMatrixd rotMat;
		rotMat.initFromParameters(angle_rad,Rb,CCVector3d(0,0,0));

		CCVector3 C = m_box.getCenter();
		ccGLMatrixd transMat;
		transMat.setTranslation(-C);
		transMat = rotMat * transMat;
		transMat.setTranslation(transMat.getTranslationAsVec3D() + CCVector3d::fromArray(C.u));

		m_glTrans = m_glTrans * ccGLMatrix(transMat.inverse().data());
		enableGLTransformation(true);
	}
	else
	{
		assert(false);
		return false;
	}

	update();

	return true;
}
Example #11
0
bool ccPolyline::fromFile_MeOnly(QFile& in, short dataVersion, int flags)
{
	if (!ccHObject::fromFile_MeOnly(in, dataVersion, flags))
		return false;

	if (dataVersion<28)
		return false;

	//as the associated cloud (=vertices) can't be saved directly (as it may be shared by multiple polylines)
	//we only store its unique ID (dataVersion>=28) --> we hope we will find it at loading time (i.e. this
	//is the responsibility of the caller to make sure that all dependencies are saved together)
	uint32_t vertUniqueID = 0;
	if (in.read((char*)&vertUniqueID,4) < 0)
		return ReadError();
	//[DIRTY] WARNING: temporarily, we set the vertices unique ID in the 'm_associatedCloud' pointer!!!
	*(uint32_t*)(&m_theAssociatedCloud) = vertUniqueID;

	//number of points (references to) (dataVersion>=28)
	uint32_t pointCount = 0;
	if (in.read((char*)&pointCount,4) < 0)
		return ReadError();
	if (!reserve(pointCount))
		return false;

	//points (references to) (dataVersion>=28)
	for (uint32_t i=0; i<pointCount; ++i)
	{
		uint32_t pointIndex = 0;
		if (in.read((char*)&pointIndex,4) < 0)
			return ReadError();
		addPointIndex(pointIndex);
	}

	//'global shift & scale' (dataVersion>=39)
	if (dataVersion >= 39)
	{
		if (!loadShiftInfoFromFile(in))
			return ReadError();
	}
	else
	{
		m_globalScale = 1.0;
		m_globalShift = CCVector3d(0,0,0);
	}

	QDataStream inStream(&in);

	//Closing state (dataVersion>=28)
	inStream >> m_isClosed;

	//RGB Color (dataVersion>=28)
	inStream >> m_rgbColor.r;
	inStream >> m_rgbColor.g;
	inStream >> m_rgbColor.b;

	//2D mode (dataVersion>=28)
	inStream >> m_mode2D;

	//Foreground mode (dataVersion>=28)
	inStream >> m_foreground;

	//Width of the line (dataVersion>=31)
	if (dataVersion >= 31)
		ccSerializationHelper::CoordsFromDataStream(inStream,flags,&m_width,1);
	else
		m_width = 0;

	return true;
}
Example #12
0
bool ccGBLSensor::applyViewport(ccGenericGLDisplay* win/*=0*/)
{
	if (!win)
	{
		win = getDisplay();
		if (!win)
		{
			ccLog::Warning("[ccGBLSensor::applyViewport] No associated display!");
			return false;
		}
	}
	
	ccIndexedTransformation trans;
	if (!getActiveAbsoluteTransformation(trans))
	{
		return false;
	}
	//scanner main directions
	CCVector3d sensorX(trans.data()[0],trans.data()[1],trans.data()[2]);
	CCVector3d sensorY(trans.data()[4],trans.data()[5],trans.data()[6]);
	CCVector3d sensorZ(trans.data()[8],trans.data()[9],trans.data()[10]);

	switch(getRotationOrder())
	{
	case ccGBLSensor::YAW_THEN_PITCH:
		{
			double theta = (getMinYaw() + getMaxYaw())/2;
			ccGLMatrixd rotz; rotz.initFromParameters(theta,sensorZ,CCVector3d(0,0,0));
			rotz.applyRotation(sensorX);
			rotz.applyRotation(sensorY);

			double phi = 0; //(getMinPitch() + getMaxPitch())/2;
			ccGLMatrixd roty; roty.initFromParameters(-phi,sensorY,CCVector3d(0,0,0)); //theta = 0 corresponds to the upward vertical direction!
			roty.applyRotation(sensorX);
			roty.applyRotation(sensorZ);

			break;
		}
	case ccGBLSensor::PITCH_THEN_YAW:
		{
			double phi = (getMinPitch() + getMaxPitch())/2;
			ccGLMatrixd roty; roty.initFromParameters(-phi,sensorY,CCVector3d(0,0,0)); //theta = 0 corresponds to the upward vertical direction!
			roty.applyRotation(sensorX);
			roty.applyRotation(sensorZ);

			double theta = (getMinYaw() + getMaxYaw())/2;
			ccGLMatrixd rotz; rotz.initFromParameters(theta,sensorZ,CCVector3d(0,0,0));
			rotz.applyRotation(sensorX);
			rotz.applyRotation(sensorY);
			break;
		}
	default:
		assert(false);
		break;
	}

	//center camera on sensor
	CCVector3d sensorCenterd = CCVector3d::fromArray(trans.getTranslation());
	ccGLMatrixd viewMat = ccGLMatrixd::FromViewDirAndUpDir(sensorX,sensorZ);
	viewMat.invert();
	viewMat.setTranslation(sensorCenterd);
	//TODO: can we set the right FOV?
	win->setupProjectiveViewport(viewMat,0,1.0f,true,true);

	return true;
}
Example #13
0
void qFacets::exportFacets()
{
	assert(m_app);
	if (!m_app)
		return;

	//disclaimer accepted?
	if (!ShowDisclaimer(m_app))
		return;

	//Retrive selected facets
	FacetSet facets;
	getFacetsInCurrentSelection(facets);

	if (facets.empty())
	{
		m_app->dispToConsole("Couldn't find any facet in the current selection!",ccMainAppInterface::ERR_CONSOLE_MESSAGE);
		return;
	}
	assert(!facets.empty());

	FacetsExportDlg fDlg(FacetsExportDlg::SHAPE_FILE_IO,m_app->getMainWindow());

	//persistent settings (default export path)
	QSettings settings;
	settings.beginGroup("qFacets");
	QString facetsSavePath = settings.value("exportPath",QApplication::applicationDirPath()).toString();
	fDlg.destinationPathLineEdit->setText(facetsSavePath + QString("/facets.shp"));

	if (!fDlg.exec())
		return;

	QString filename = fDlg.destinationPathLineEdit->text();

	//save current export path to persistent settings
	settings.setValue("exportPath",QFileInfo(filename).absolutePath());

	if (QFile(filename).exists())
	{
		//if the file already exists, ask for confirmation!
		if (QMessageBox::warning(m_app->getMainWindow(),"File already exists!","File already exists! Are you sure you want to overwrite it?",QMessageBox::Yes,QMessageBox::No) == QMessageBox::No)
			return;
	}

	//fields (shapefile) - WARNING names must not have more than 10 chars!
	ShpFilter::IntegerField  facetIndex("index");
	ShpFilter::DoubleField   facetSurface("surface");
	ShpFilter::DoubleField   facetRMS("rms");
	ShpFilter::IntegerField  facetDipDir("dip_dir");
	ShpFilter::IntegerField  facetDip("dip");
	ShpFilter::IntegerField  familyIndex("family_ind");
	ShpFilter::IntegerField  subfamilyIndex("subfam_ind");
	ShpFilter::DoubleField3D facetNormal("normal");
	ShpFilter::DoubleField3D facetBarycenter("center");
	ShpFilter::DoubleField   horizExtension("horiz_ext");
	ShpFilter::DoubleField   vertExtension("vert_ext");
	ShpFilter::DoubleField   surfaceExtension("surf_ext");

	size_t facetCount = facets.size();
	assert(facetCount != 0);
	try
	{
		facetIndex.values.reserve(facetCount);
		facetSurface.values.reserve(facetCount);
		facetRMS.values.reserve(facetCount);
		facetDipDir.values.reserve(facetCount);
		facetDip.values.reserve(facetCount);
		familyIndex.values.reserve(facetCount);
		subfamilyIndex.values.reserve(facetCount);
		facetNormal.values.reserve(facetCount);
		facetBarycenter.values.reserve(facetCount);
		horizExtension.values.reserve(facetCount);
		vertExtension.values.reserve(facetCount);
		surfaceExtension.values.reserve(facetCount);
	}
	catch (const std::bad_alloc&)
	{
		m_app->dispToConsole("Not enough memory!",ccMainAppInterface::ERR_CONSOLE_MESSAGE);
		return;
	}

	ccHObject toSave("facets");

	//depending on the 'main orientation', the job is more or less easy ;)
	bool useNativeOrientation = fDlg.nativeOriRadioButton->isChecked();
	bool useGlobalOrientation = fDlg.verticalOriRadioButton->isChecked();
	bool useCustomOrientation = fDlg.customOriRadioButton->isChecked();

	//Default base
	CCVector3 X(1,0,0), Y(0,1,0), Z(0,0,1);

	//'vertical' orientation (potentially specified by the user)
	if (!useNativeOrientation)
	{
		if (useCustomOrientation)
		{
			Z = CCVector3(	static_cast<PointCoordinateType>(fDlg.nXLineEdit->text().toDouble()),
							static_cast<PointCoordinateType>(fDlg.nYLineEdit->text().toDouble()),
							static_cast<PointCoordinateType>(fDlg.nZLineEdit->text().toDouble()) );
			Z.normalize();
		}
		else if (useGlobalOrientation)
		{
			//we compute the mean orientation (weighted by each facet's surface)
			CCVector3d Nsum(0,0,0);
			for (FacetSet::iterator it = facets.begin(); it != facets.end(); ++it)
			{
				double surf = (*it)->getSurface();
				CCVector3 N = (*it)->getNormal();
				Nsum.x += static_cast<double>(N.x) * surf;
				Nsum.y += static_cast<double>(N.y) * surf;
				Nsum.z += static_cast<double>(N.z) * surf;
			}
			Nsum.normalize();

			Z = CCVector3(	static_cast<PointCoordinateType>(Nsum.x),
							static_cast<PointCoordinateType>(Nsum.y),
							static_cast<PointCoordinateType>(Nsum.z) );
		}

		//update X & Y
		CCVector3 D = Z.cross(CCVector3(0,0,1));
		if (D.norm2() > ZERO_TOLERANCE) //otherwise the vertical dir hasn't changed!
		{
			X = -D;
			X.normalize();
			Y = Z.cross(X);
		}
	}

	//we compute the mean center (weighted by each facet's surface)
	CCVector3 C(0,0,0);
	{
		double weightSum = 0;
		for (FacetSet::iterator it = facets.begin(); it != facets.end(); ++it)
		{
			double surf = (*it)->getSurface();
			CCVector3 Ci = (*it)->getCenter();
			C += Ci * static_cast<PointCoordinateType>(surf);
			weightSum += surf;
		}
		if (weightSum)
			C /= static_cast<PointCoordinateType>(weightSum);
	}

	//determine the 'global' orientation matrix
	ccGLMatrix oriRotMat;
	oriRotMat.toIdentity();
	if (!useNativeOrientation)
	{
		oriRotMat.getColumn(0)[0] = static_cast<float>(X.x);
		oriRotMat.getColumn(0)[1] = static_cast<float>(X.y);
		oriRotMat.getColumn(0)[2] = static_cast<float>(X.z);
		oriRotMat.getColumn(1)[0] = static_cast<float>(Y.x);
		oriRotMat.getColumn(1)[1] = static_cast<float>(Y.y);
		oriRotMat.getColumn(1)[2] = static_cast<float>(Y.z);
		oriRotMat.getColumn(2)[0] = static_cast<float>(Z.x);
		oriRotMat.getColumn(2)[1] = static_cast<float>(Z.y);
		oriRotMat.getColumn(2)[2] = static_cast<float>(Z.z);
		oriRotMat.invert();

		ccGLMatrix transMat;
		transMat.setTranslation(-C);
		oriRotMat = oriRotMat * transMat;
		oriRotMat.setTranslation(oriRotMat.getTranslationAsVec3D() + C);
	}

	//for each facet
	for (FacetSet::iterator it=facets.begin(); it!=facets.end(); ++it)
	{
		ccFacet* facet = *it;
		ccPolyline* poly = facet->getContour();

		//if necessary, we create a (temporary) new facet
		if (!useNativeOrientation)
		{
			CCLib::GenericIndexedCloudPersist* vertices = poly->getAssociatedCloud();
			if (!vertices || vertices->size() < 3)
				continue;

			//create (temporary) new polyline
			ccPolyline* newPoly = new ccPolyline(*poly);
			ccPointCloud* pc = (newPoly ? dynamic_cast<ccPointCloud*>(newPoly->getAssociatedCloud()) : 0);
			if (pc)
			{
				pc->applyGLTransformation_recursive(&oriRotMat);
			}
			else
			{
				m_app->dispToConsole(QString("Failed to change the orientation of polyline '%1'! (not enough memory)").arg(poly->getName()),ccMainAppInterface::WRN_CONSOLE_MESSAGE);
				continue;
			}

			newPoly->set2DMode(true);
			poly = newPoly;
		}

		toSave.addChild(poly, useNativeOrientation ? ccHObject::DP_NONE : ccHObject::DP_PARENT_OF_OTHER);

		//save associated meta-data as 'shapefile' fields
		{
			//main parameters
			FacetMetaData data;
			GetFacetMetaData(facet, data);

			//horizontal and vertical extensions
			double horizExt = 0, vertExt = 0;
			ComputeFacetExtensions(data.normal,poly,horizExt,vertExt);

			facetIndex.values.push_back(data.facetIndex);
			facetSurface.values.push_back(data.surface);
			facetRMS.values.push_back(data.rms);
			facetDipDir.values.push_back(data.dipDir_deg);
			facetDip.values.push_back(data.dip_deg);
			familyIndex.values.push_back(data.familyIndex);
			subfamilyIndex.values.push_back(data.subfamilyIndex);
			facetNormal.values.push_back(CCVector3d(data.normal.x,data.normal.y,data.normal.z));
			facetBarycenter.values.push_back(CCVector3d(data.center.x,data.center.y,data.center.z));
			vertExtension.values.push_back(vertExt);
			horizExtension.values.push_back(horizExt);
			surfaceExtension.values.push_back(horizExt*vertExt);
		}
	}

	//save entities
	if (toSave.getChildrenNumber())
	{
		std::vector<ShpFilter::GenericField*> fields;
		fields.push_back(&facetIndex);
		fields.push_back(&facetBarycenter);
		fields.push_back(&facetNormal);
		fields.push_back(&facetRMS);
		fields.push_back(&horizExtension);
		fields.push_back(&vertExtension);
		fields.push_back(&surfaceExtension);
		fields.push_back(&facetSurface);
		fields.push_back(&facetDipDir);
		fields.push_back(&facetDip);
		fields.push_back(&familyIndex);
		fields.push_back(&subfamilyIndex);
		ShpFilter filter;
		filter.treatClosedPolylinesAsPolygons(true);
		ShpFilter::SaveParameters params;
		params.alwaysDisplaySaveDialog = false;
		if (filter.saveToFile(&toSave,fields,filename,params) == CC_FERR_NO_ERROR)
		{
			m_app->dispToConsole(QString("[qFacets] File '%1' successfully saved").arg(filename),ccMainAppInterface::STD_CONSOLE_MESSAGE);
		}
		else
		{
			m_app->dispToConsole(QString("[qFacets] Failed to save file '%1'!").arg(filename),ccMainAppInterface::WRN_CONSOLE_MESSAGE);
		}
	}
}
Example #14
0
bool ccGlobalShiftManager::Handle(	const CCVector3d& P,
									double diagonal,
									Mode mode,
									bool useInputCoordinatesShiftIfPossible,
									CCVector3d& coordinatesShift,
									double* coordinatesScale,
									bool* applyAll/*=0*/)
{
	assert(diagonal >= 0);

	if (applyAll)
	{
		*applyAll = false;
	}

	//default scale
	double scale = (coordinatesScale ? std::max(*coordinatesScale, ZERO_TOLERANCE) : 1.0);

	bool needShift = NeedShift(P);
	bool needRescale = NeedRescale(diagonal);

	//if we can't display a dialog and no usable shift is specified, there's nothing we can do...
	if (mode == NO_DIALOG && !useInputCoordinatesShiftIfPossible)
	{
		coordinatesShift = CCVector3d(0,0,0);
		if (coordinatesScale)
		{
			*coordinatesScale = 1.0;
		}

		if (needShift || needRescale)
		{
			ccLog::Warning("[ccGlobalShiftManager] Entity has very big coordinates: original accuracy may be lost! (you should apply a Global Shift or Scale)");
		}

		return false;
	}

	//is shift necessary?
	if ( needShift || needRescale || mode == ALWAYS_DISPLAY_DIALOG )
	{
		//shift information already provided? (typically from a previous entity)
		if (useInputCoordinatesShiftIfPossible && mode != ALWAYS_DISPLAY_DIALOG)
		{
			//either we are in non interactive mode (which means that shift is 'forced' by caller)
			if (mode == NO_DIALOG
				//or we are in interactive mode and existing shift is pertinent
				|| (!NeedShift(P*scale + coordinatesShift) && !NeedRescale(diagonal*scale)) )
			{
				//user should use the provided shift information
				return true;
			}
			//--> otherwise we (should) ask for a better one
		}

		//let's deduce the right values (AUTO mode)
		if (mode == NO_DIALOG_AUTO_SHIFT)
		{
			//guess best shift & scale info from input point/diagonal
			if (needShift)
			{
				coordinatesShift = BestShift(P);
			}
			if (coordinatesScale && needRescale)
			{
				*coordinatesScale = BestScale(diagonal);
			}
			return true;
		}

		//otherwise let's ask the user for those values
		ccShiftAndScaleCloudDlg sasDlg(P, diagonal);
		if (!applyAll)
		{
			sasDlg.showApplyAllButton(false);
		}
		if (!coordinatesScale)
		{
			sasDlg.showScaleItems(false);
		}

		scale = 1.0;
		CCVector3d shift(0,0,0);
		if (useInputCoordinatesShiftIfPossible)
		{
			//shift on load already provided? (typically from a previous file)
			shift = coordinatesShift;
			if (coordinatesScale)
			{
				scale = *coordinatesScale;
			}
			if (mode != ALWAYS_DISPLAY_DIALOG)
			{
				sasDlg.showWarning(true); //if we are here, it means that the provided shift isn't concordant
			}
		}
		else
		{
			//guess best shift & scale info from input point/diagonal
			if (needShift)
			{
				shift = BestShift(P);
			}
			if (needRescale)
			{
				scale = BestScale(diagonal);
			}
		}

		//add "suggested" entry
		int index = sasDlg.addShiftInfo(ccShiftAndScaleCloudDlg::ShiftInfo("Suggested", shift, scale));
		sasDlg.setCurrentProfile(index);
		//add "last" entry (if available)
		{
			ccShiftAndScaleCloudDlg::ShiftInfo lastInfo;
			if (sasDlg.getLast(lastInfo))
			{
				sasDlg.addShiftInfo(lastInfo);
			}
		}
		//add entries from file (if any)
		sasDlg.addFileInfo();
		//automatically make the first available shift that works
		//(different than the suggested one) active
		{
			for (size_t i=static_cast<size_t>(std::max(0,index+1)); i<sasDlg.infoCount(); ++i)
			{
				ccShiftAndScaleCloudDlg::ShiftInfo info;
				if (sasDlg.getInfo(i,info))
				{
					//check if they work
					if (	!NeedShift((CCVector3d(P) + info.shift) * info.scale )
						&&  !NeedRescale(diagonal*info.scale) )
					{
						sasDlg.setCurrentProfile(static_cast<int>(i));
						break;
					}
				}
			}
		}
		sasDlg.showTitle(needShift || needRescale);
		if (sasDlg.exec())
		{
			coordinatesShift = sasDlg.getShift();
			if (coordinatesScale)
			{
				*coordinatesScale = sasDlg.getScale();
			}
			if (applyAll)
			{
				*applyAll = sasDlg.applyAll();
			}
			return true;
		}
	}

	coordinatesShift = CCVector3d(0,0,0);
	if (coordinatesScale)
	{
		*coordinatesScale = 1.0;
	}

	return false;
}
CCVector3d ccShiftAndScaleCloudDlg::getShift() const
{
	return CCVector3d( m_ui->shiftX->value(), m_ui->shiftY->value(), m_ui->shiftZ->value() );
}