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); }