void qFacets::exportFacets() { assert(m_app); if (!m_app) return; //disclaimer accepted? if (!ShowDisclaimer(m_app)) return; //Retrive selected facets std::set<ccFacet*> 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 (std::set<ccFacet*>::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 (std::set<ccFacet*>::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 (std::set<ccFacet*>::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); } } }
CCLib::ReferenceCloud* qHPR::removeHiddenPoints(CCLib::GenericIndexedCloudPersist* theCloud, const CCVector3& viewPoint, float fParam) { assert(theCloud); unsigned nbPoints = theCloud->size(); if (nbPoints == 0) return 0; //less than 4 points? no need for calculation, we return the whole cloud if (nbPoints < 4) { CCLib::ReferenceCloud* visiblePoints = new CCLib::ReferenceCloud(theCloud); if (!visiblePoints->addPointIndex(0,nbPoints)) //well even for less than 4 points we never know ;) { //not enough memory! delete visiblePoints; visiblePoints = 0; } return visiblePoints; } PointCoordinateType maxRadius = 0; //convert point cloud to an array of double triplets (for qHull) coordT* pt_array = new coordT[(nbPoints+1)*3]; { coordT* _pt_array = pt_array; for (unsigned i=0; i<nbPoints; ++i) { CCVector3 P = *theCloud->getPoint(i) - viewPoint; *_pt_array++ = (coordT)P.x; *_pt_array++ = (coordT)P.y; *_pt_array++ = (coordT)P.z; //we keep track of the highest 'radius' PointCoordinateType r2 = P.norm2(); if (maxRadius < r2) maxRadius = r2; } //we add the view point (Cf. HPR) *_pt_array++ = 0; *_pt_array++ = 0; *_pt_array++ = 0; maxRadius = sqrt(maxRadius); } //apply spherical flipping { maxRadius *= 2.0f*pow(10.0f,fParam); coordT* _pt_array = pt_array; for (unsigned i=0; i<nbPoints; ++i) { CCVector3 P = *theCloud->getPoint(i) - viewPoint; double r = (double)(maxRadius/P.norm()) - 1.0; *_pt_array++ *= r; *_pt_array++ *= r; *_pt_array++ *= r; } } //array to flag points on the convex hull std::vector<bool> pointBelongsToCvxHull; if (!qh_new_qhull(3,nbPoints+1,pt_array,False,(char*)"qhull QJ Qci",0,stderr)) { try { pointBelongsToCvxHull.resize(nbPoints+1,false); } catch(std::bad_alloc) { //not enough memory! delete[] pt_array; return 0; } vertexT *vertex = 0,**vertexp = 0; facetT *facet = 0; FORALLfacets { //if (!facet->simplicial) // error("convhulln: non-simplicial facet"); // should never happen with QJ setT* vertices = qh_facet3vertex(facet); FOREACHvertex_(vertices) { pointBelongsToCvxHull[qh_pointid(vertex->point)] = true; } qh_settempfree(&vertices); } } delete[] pt_array; pt_array=0; qh_freeqhull(!qh_ALL); //free long memory int curlong, totlong; qh_memfreeshort (&curlong, &totlong); //free short memory and memory allocator if (!pointBelongsToCvxHull.empty()) { //compute the number of points belonging to the convex hull unsigned cvxHullSize = 0; { for (unsigned i=0; i<nbPoints; ++i) if (pointBelongsToCvxHull[i]) ++cvxHullSize; } CCLib::ReferenceCloud* visiblePoints = new CCLib::ReferenceCloud(theCloud); if (cvxHullSize!=0 && visiblePoints->reserve(cvxHullSize)) { for (unsigned i=0; i<nbPoints; ++i) if (pointBelongsToCvxHull[i]) visiblePoints->addPointIndex(i); //can't fail, see above return visiblePoints; } else //not enough memory { delete visiblePoints; visiblePoints=0; } } return 0; }