Пример #1
0
ccPlane* ccPlane::Fit(CCLib::GenericIndexedCloudPersist *cloud, double* rms/*=0*/)
{
    //number of points
    unsigned count = cloud->size();
    if (count < 3)
    {
        ccLog::Warning("[ccPlane::Fit] Not enough points in input cloud to fit a plane!");
        return 0;
    }

    CCLib::Neighbourhood Yk(cloud);

    //plane equation
    const PointCoordinateType* theLSPlane = Yk.getLSPlane();
    if (!theLSPlane)
    {
        ccLog::Warning("[ccPlane::Fit] Not enough points to fit a plane!");
        return 0;
    }

    //get the centroid
    const CCVector3* G = Yk.getGravityCenter();
    assert(G);

    //and a local base
    CCVector3 N(theLSPlane);
    const CCVector3* X = Yk.getLSPlaneX(); //main direction
    assert(X);
    CCVector3 Y = N * (*X);

    //compute bounding box in 2D plane
    CCVector2 minXY(0,0), maxXY(0,0);
    cloud->placeIteratorAtBegining();
    for (unsigned k=0; k<count; ++k)
    {
        //projection into local 2D plane ref.
        CCVector3 P = *(cloud->getNextPoint()) - *G;

        CCVector2 P2D( P.dot(*X), P.dot(Y) );

        if (k != 0)
        {
            if (minXY.x > P2D.x)
                minXY.x = P2D.x;
            else if (maxXY.x < P2D.x)
                maxXY.x = P2D.x;
            if (minXY.y > P2D.y)
                minXY.y = P2D.y;
            else if (maxXY.y < P2D.y)
                maxXY.y = P2D.y;
        }
        else
        {
            minXY = maxXY = P2D;
        }
    }

    //we recenter the plane
    PointCoordinateType dX = maxXY.x-minXY.x;
    PointCoordinateType dY = maxXY.y-minXY.y;
    CCVector3 Gt = *G + *X * (minXY.x + dX / 2) + Y * (minXY.y + dY / 2);
    ccGLMatrix glMat(*X,Y,N,Gt);

    ccPlane* plane = new ccPlane(dX, dY, &glMat);

    //compute least-square fitting RMS if requested
    if (rms)
    {
        *rms = CCLib::DistanceComputationTools::computeCloud2PlaneDistanceRMS(cloud, theLSPlane);
        plane->setMetaData(QString("RMS"),QVariant(*rms));
    }


    return plane;
}
void ccGraphicalSegmentationTool::segment(bool keepPointsInside)
{
	if (!m_associatedWin)
		return;

	if (!m_segmentationPoly)
	{
		ccLog::Error("No polyline defined!");
		return;
	}

	if (!m_segmentationPoly->isClosed())
	{
		ccLog::Error("Define and/or close the segmentation polygon first! (right click to close)");
		return;
	}

	//viewing parameters
	const double* MM = m_associatedWin->getModelViewMatd(); //viewMat
	const double* MP = m_associatedWin->getProjectionMatd(); //projMat
	const GLdouble half_w = static_cast<GLdouble>(m_associatedWin->width())/2;
	const GLdouble half_h = static_cast<GLdouble>(m_associatedWin->height())/2;

	int VP[4];
	m_associatedWin->getViewportArray(VP);

	//for each selected entity
	for (std::set<ccHObject*>::iterator p = m_toSegment.begin(); p != m_toSegment.end(); ++p)
	{
		ccGenericPointCloud* cloud = ccHObjectCaster::ToGenericPointCloud(*p);
		assert(cloud);

		ccGenericPointCloud::VisibilityTableType* visibilityArray = cloud->getTheVisibilityArray();
		assert(visibilityArray);

		unsigned cloudSize = cloud->size();

		//we project each point and we check if it falls inside the segmentation polyline
		for (unsigned i=0; i<cloudSize; ++i)
		{
			if (visibilityArray->getValue(i) == POINT_VISIBLE)
			{
				CCVector3 P;
				cloud->getPoint(i,P);

				GLdouble xp,yp,zp;
				gluProject(P.x,P.y,P.z,MM,MP,VP,&xp,&yp,&zp);

				CCVector2 P2D(	static_cast<PointCoordinateType>(xp-half_w),
								static_cast<PointCoordinateType>(yp-half_h) );
				bool pointInside = CCLib::ManualSegmentationTools::isPointInsidePoly(P2D,m_segmentationPoly);

				visibilityArray->setValue(i, keepPointsInside != pointInside ? POINT_HIDDEN : POINT_VISIBLE );
			}
		}
	}

	m_somethingHasChanged = true;
	validButton->setEnabled(true);
	validAndDeleteButton->setEnabled(true);
	razButton->setEnabled(true);
	pauseSegmentationMode(true);
}
void ccTracePolylineTool::updatePolyLineTip(int x, int y, Qt::MouseButtons buttons)
{
	if (!m_associatedWin)
	{
		assert(false);
		return;
	}
	
	if (buttons != Qt::NoButton)
	{
		//nothing to do (just hide the tip)
		if (m_polyTip->isEnabled())
		{
			m_polyTip->setEnabled(false);
			m_associatedWin->redraw(true, false);
		}
		return;
	}

	if (!m_poly3DVertices || m_poly3DVertices->size() == 0)
	{
		//there should be at least one point already picked!
		return;
	}

	if (m_done)
	{
		// when it is done do nothing
		return;
	}

	assert(m_polyTip && m_polyTipVertices && m_polyTipVertices->size() == 2);

	//we replace the last point by the new one
	{
		QPointF pos2D = m_associatedWin->toCenteredGLCoordinates(x, y);
		CCVector3 P2D(	static_cast<PointCoordinateType>(pos2D.x()),
						static_cast<PointCoordinateType>(pos2D.y()),
						0);

		CCVector3* lastP = const_cast<CCVector3*>(m_polyTipVertices->getPointPersistentPtr(1));
		*lastP = P2D;
	}

	//just in case (e.g. if the view has been rotated or zoomed)
	//we also update the first vertex position!
	{
		const CCVector3* P3D = m_poly3DVertices->getPoint(m_poly3DVertices->size() - 1);

		ccGLCameraParameters camera;
		m_associatedWin->getGLCameraParameters(camera);

		CCVector3d A2D;
		camera.project(*P3D, A2D);

		CCVector3* firstP = const_cast<CCVector3*>(m_polyTipVertices->getPointPersistentPtr(0));
		*firstP = CCVector3(static_cast<PointCoordinateType>(A2D.x - camera.viewport[2] / 2), //we convert A2D to centered coordinates (no need to apply high DPI scale or anything!)
							static_cast<PointCoordinateType>(A2D.y - camera.viewport[3] / 2),
							0);

	}

	m_polyTip->setEnabled(true);

	m_associatedWin->redraw(true, false);
}
void ccTracePolylineTool::onItemPicked(const PickedItem& pi)
{
	if (!m_associatedWin)
	{
		assert(false);
		return;
	}

	if (!pi.entity)
	{
		//means that the mouse has been clicked but no point was found!
		return;
	}

	//if the 3D polyline doesn't exist yet, we create it
	if (!m_poly3D || !m_poly3DVertices)
	{
		m_poly3DVertices = new ccPointCloud("Vertices");
		m_poly3DVertices->setEnabled(false);
		m_poly3DVertices->setDisplay(m_associatedWin);

		m_poly3D = new ccPolyline(m_poly3DVertices);
		m_poly3D->setTempColor(ccColor::green);
		m_poly3D->set2DMode(false);
		m_poly3D->addChild(m_poly3DVertices);
		m_poly3D->setWidth(widthSpinBox->value() < 2 ? 0 : widthSpinBox->value()); //'1' is equivalent to the default line size

		ccGenericPointCloud* cloud = ccHObjectCaster::ToGenericPointCloud(pi.entity);
		if (cloud)
		{
			//copy the first clicked entity's global shift & scale
			m_poly3D->setGlobalShift(cloud->getGlobalShift());
			m_poly3D->setGlobalScale(cloud->getGlobalScale());
		}

		m_segmentParams.clear(); //just in case

		m_associatedWin->addToOwnDB(m_poly3D);
	}

	//try to add one more point
	if (	!m_poly3DVertices->reserve(m_poly3DVertices->size() + 1)
		||	!m_poly3D->reserve(m_poly3DVertices->size() + 1))
	{
		ccLog::Error("Not enough memory");
		return;
	}

	try
	{
		m_segmentParams.reserve(m_segmentParams.size() + 1);
	}
	catch (const std::bad_alloc&)
	{
		ccLog::Error("Not enough memory");
		return;
	}

	m_poly3DVertices->addPoint(pi.P3D);
	m_poly3D->addPointIndex(m_poly3DVertices->size() - 1);
	m_segmentParams.emplace_back(m_associatedWin, pi.clickPoint.x(), pi.clickPoint.y());

	//we replace the first point of the tip by this new point
	{
		QPointF pos2D = m_associatedWin->toCenteredGLCoordinates(pi.clickPoint.x(), pi.clickPoint.y());
		CCVector3 P2D(	static_cast<PointCoordinateType>(pos2D.x()),
						static_cast<PointCoordinateType>(pos2D.y()),
						0);

		CCVector3* firstTipPoint = const_cast<CCVector3*>(m_polyTipVertices->getPointPersistentPtr(0));
		*firstTipPoint = P2D;
		m_polyTip->setEnabled(false); //don't need to display it for now
	}

	m_associatedWin->redraw(false, false);
}
void ccGraphicalSegmentationTool::segment(bool keepPointsInside)
{
	if (!m_associatedWin)
		return;

	if (!m_segmentationPoly)
	{
		ccLog::Error("No polyline defined!");
		return;
	}

	if (!m_segmentationPoly->isClosed())
	{
		ccLog::Error("Define and/or close the segmentation polygon first! (right click to close)");
		return;
	}

	//viewing parameters
	ccGLCameraParameters camera;
	m_associatedWin->getGLCameraParameters(camera);
	const double half_w = camera.viewport[2] / 2.0;
	const double half_h = camera.viewport[3] / 2.0;

	//for each selected entity
	for (QSet<ccHObject*>::const_iterator p = m_toSegment.begin(); p != m_toSegment.end(); ++p)
	{
		ccGenericPointCloud* cloud = ccHObjectCaster::ToGenericPointCloud(*p);
		assert(cloud);

		ccGenericPointCloud::VisibilityTableType* visibilityArray = cloud->getTheVisibilityArray();
		assert(visibilityArray);

		unsigned cloudSize = cloud->size();

		//we project each point and we check if it falls inside the segmentation polyline
#if defined(_OPENMP)
#pragma omp parallel for
#endif
		for (int i=0; i<static_cast<int>(cloudSize); ++i)
		{
			if (visibilityArray->getValue(i) == POINT_VISIBLE)
			{
				const CCVector3* P3D = cloud->getPoint(i);

				CCVector3d Q2D;
				camera.project(*P3D, Q2D);

				CCVector2 P2D(	static_cast<PointCoordinateType>(Q2D.x-half_w),
								static_cast<PointCoordinateType>(Q2D.y-half_h) );
				
				bool pointInside = CCLib::ManualSegmentationTools::isPointInsidePoly(P2D, m_segmentationPoly);

				visibilityArray->setValue(i, keepPointsInside != pointInside ? POINT_HIDDEN : POINT_VISIBLE );
			}
		}
	}

	m_somethingHasChanged = true;
	validButton->setEnabled(true);
	validAndDeleteButton->setEnabled(true);
	razButton->setEnabled(true);
	pauseSegmentationMode(true);
}