#include #include #include "nurbs_plugin_global.h" #include "nurbs_plugin.h" #include "NanoKdTree.h" #include "StructureGraph.h" #include "BoundaryFitting.h" #include "interfaces/ModePluginDockWidget.h" QVector randColors; //#include "LSCM.h" //#include "LinABF.h" QString groupID = ""; SurfaceMesh::SurfaceMeshModel * m = NULL; RichParameterSet * mcf_params = NULL; PointSoup pps,pps2; SphereSoup spheres; VectorSoup vs; LineSegments lseg; #include "PCA.h" #include "SimilarSampling.h" #include "GenericGraph.h" #include "StructureGraph.h" #define RADIANS(deg) ((deg)/180.0 * M_PI) void nurbs_plugin::create() { if(widget) return; if(mesh()->name == "empty"){ document()->deleteModel(document()->getModel("empty")); } drawArea()->setRenderer( mesh(), "Transparent"); drawArea()->camera()->setType(qglviewer::Camera::PERSPECTIVE); entireMesh = (SurfaceMeshModel*)document()->selectedModel(); entirePoints = entireMesh->vertex_property("v:point"); for(int i = 0; i < 10; i++) randColors.push_back(qRandomColor()); loadGroupsFromOBJ(); m = mesh(); points = m->vertex_property("v:point"); graph = new Structure::Graph; ModePluginDockWidget * dockwidget = new ModePluginDockWidget("NURBS plugin", mainWindow()); widget = new NURBSTools(this); dockwidget->setWidget(widget); dockwidget->setWindowTitle(widget->windowTitle()); mainWindow()->addDockWidget(Qt::RightDockWidgetArea,dockwidget); widget->fillList(); mainWindow()->showMaximized(); //buildSamples(); } void nurbs_plugin::decorate() { // Draw OBB //mesh_obb.draw(); for(int i = 0; i < (int)curves.size(); i++) { NURBS::CurveDraw::draw( &curves[i], randColors[i%randColors.size()], true ); } for(int i = 0; i < (int)rects.size(); i++) { NURBS::SurfaceDraw::draw( &rects[i], randColors[i%randColors.size()], true ); } if(graph) graph->draw( this->drawArea() ); ps.draw(); vs.draw(); lseg.draw(); pps.draw(); pps2.draw(); spheres.draw(); } void nurbs_plugin::clearAll() { curves.clear(); rects.clear(); } void nurbs_plugin::saveAll() { foreach(Structure::Node * n, graph->nodes) { QString nodeID = n->id; SurfaceMeshModel * nodeMesh = extractMesh( nodeID ); // Assign sub-mesh to node n->property["mesh_filename"] = entireMesh->name + "/" + nodeID + ".obj"; n->property["mesh"].setValue( QSharedPointer(nodeMesh) ); } QString folderPath = QFileDialog::getExistingDirectory(); QDir::setCurrent( folderPath ); QString filename = folderPath + "/" + entireMesh->name + ".xml"; graph->saveToFile( filename ); } bool nurbs_plugin::keyPressEvent( QKeyEvent* event ) { bool used = false; if(event->key() == Qt::Key_E) { NURBS::NURBSCurved & c = curves.back(); NURBS::NURBSCurved newCurve = NURBS::NURBSCurved::createCurveFromPoints( c.simpleRefine(1) ); if(curves.size() == 1) curves.push_back( newCurve ); else c = newCurve; used = true; } if(event->key() == Qt::Key_R) { NURBS::NURBSCurved & c = curves.back(); c = NURBS::NURBSCurved::createCurveFromPoints( c.removeKnots(2) ) ; used = true; } if(event->key() == Qt::Key_Q) { NURBS::NURBSRectangled & r = rects.back(); r = NURBS::NURBSRectangled::createSheetFromPoints( r.midPointRefined() ); used = true; } if(event->key() == Qt::Key_W) { //QElapsedTimer timer; timer.start(); //LinABF linabf(m); //mainWindow()->setStatusBarMessage(QString("LinABF time = %1 ms").arg(timer.elapsed()),512); //linabf.applyUVTom; //used = true; } if(event->key() == Qt::Key_Z) { NURBS::NURBSRectangled & r = rects.back(); r = NURBS::NURBSRectangled::createSheetFromPoints( r.simpleRefine(1,0) ); used = true; } if(event->key() == Qt::Key_X) { NURBS::NURBSRectangled & r = rects.back(); r = NURBS::NURBSRectangled::createSheetFromPoints( r.simpleRefine(1,1) ); used = true; } if(event->key() == Qt::Key_C) { NURBS::NURBSRectangled & r = rects.back(); r = NURBS::NURBSRectangled::createSheetFromPoints( r.simpleRemove(r.mNumUCtrlPoints * 0.5,0) ); used = true; } if(event->key() == Qt::Key_V) { NURBS::NURBSRectangled & r = rects.back(); r = NURBS::NURBSRectangled::createSheetFromPoints( r.simpleRemove(r.mNumVCtrlPoints * 0.5,1) ); used = true; } if(event->key() == Qt::Key_Space) { buildSamples(); used = true; } drawArea()->updateGL(); return used; } void nurbs_plugin::buildSamples() { // Curve example int degree = 3; std::vector cps; int steps = 10; double theta = M_PI * 5 / steps; double r = M_PI; for(int i = 0; i <= steps; i++){ double x = (double(i) / steps) * r; double y = sin(i * theta) * r * 0.25; cps.push_back(Vector3d(x - r * 0.5, y, cos(i*theta))); } std::vector weight(cps.size(), 1.0); curves.push_back(NURBS::NURBSCurved(cps, weight, degree, false, true)); // Rectangular surface double w = 1; double l = 2; int width = w * 5; int length = l * 5; std::vector< std::vector > cpts( width, std::vector(length) ); std::vector< std::vector > weights( width, std::vector(length) ); double omega = M_PI * 3 / qMin(width, length); Vector3d surface_pos(0,1,0); for(int i = 0; i < width; i++) for(int j = 0; j < length; j++){ double x = double(i) / width; double y = double(j) / length; double delta = sqrt(x*x + y*y) * 0.5; cpts[i][j] = Vector3d(surface_pos.x() + x * w, surface_pos.y() + y * l, delta + sin(j * omega) * qMin(width, length) * 0.02); } rects.push_back( NURBS::NURBSRectangled(cpts, weights, degree, degree, false, false, true, true) ); } void nurbs_plugin::prepareSkeletonize() { // Remove visualization ps.clear(); m->update_face_normals(); m->update_vertex_normals(); m->updateBoundingBox(); drawArea()->setRenderer( m, "Wireframe"); document()->setSelectedModel( m ); // Voxelize if( widget->isVoxelize() ) { FilterPlugin * voxResamplePlugin = pluginManager()->getFilter("Voxel Resampler"); RichParameterSet * resample_params = new RichParameterSet; voxResamplePlugin->initParameters( resample_params ); resample_params->setValue("voxel_scale", float( widget->voxelParamter() )); voxResamplePlugin->applyFilter( resample_params ); } // Remesh if( widget->isRemesh() ) { FilterPlugin * remeshPlugin = pluginManager()->getFilter("Isotropic Remesher"); RichParameterSet * remesh_params = new RichParameterSet; remeshPlugin->initParameters( remesh_params ); float edge_threshold = float(widget->remeshParamter() * m->bbox().diagonal().norm()); if(widget->isProtectSmallFeatures()){ remesh_params->setValue("keep_shortedges", true); edge_threshold *= 0.5; } remesh_params->setValue("edgelength_TH", edge_threshold); remeshPlugin->applyFilter( remesh_params ); } // Compute MAT FilterPlugin * matPlugin = pluginManager()->getFilter("Voronoi based MAT"); RichParameterSet * mat_params = new RichParameterSet; matPlugin->initParameters( mat_params ); matPlugin->applyFilter( mat_params ); } void nurbs_plugin::stepSkeletonizeMesh() { FilterPlugin * mcfPlugin = pluginManager()->getFilter("MCF Skeletonization"); if(!mcf_params){ mcf_params = new RichParameterSet; mcfPlugin->initParameters( mcf_params ); // Custom MCF parameters if( !widget->isUseMedial() ) mcf_params->setValue("omega_P_0", 0.0f); } mcfPlugin->applyFilter( mcf_params ); //drawArea()->setRenderer(m,"Flat Wire"); //drawArea()->updateGL(); // may cause crashing of OpenGL } void nurbs_plugin::drawWithNames() { // Faces foreach( const Face f, entireMesh->faces() ) { // Collect points QVector pnts; Surface_mesh::Vertex_around_face_circulator vit = entireMesh->vertices(f),vend=vit; do{ pnts.push_back(entirePoints[vit]); } while(++vit != vend); glPushName(f.idx()); glBegin(GL_TRIANGLES); foreach(Vector3 p, pnts) glVector3(p); glEnd(); glPopName(); } } SurfaceMeshModel * nurbs_plugin::extractMesh( QString gid ) { SurfaceMeshModel * subMesh = NULL; QVector part = groupFaces[gid]; // Create copy of sub-part subMesh = new SurfaceMeshModel(groupID + ".obj", groupID); QSet vertSet; QMap vmap; foreach(int fidx, part){ Surface_mesh::Vertex_around_face_circulator vit = entireMesh->vertices(Face(fidx)),vend=vit; do{ vertSet.insert(Vertex(vit).idx()); } while(++vit != vend); } foreach(int vidx, vertSet){ vmap[Vertex(vidx)] = Vertex(vmap.size()); subMesh->add_vertex( entirePoints[Vertex(vidx)] ); } foreach(int fidx, part){ std::vector pnts; Surface_mesh::Vertex_around_face_circulator vit = entireMesh->vertices(Face(fidx)),vend=vit; do{ pnts.push_back(vmap[vit]); } while(++vit != vend); subMesh->add_face(pnts); } subMesh->updateBoundingBox(); subMesh->isVisible = true; return subMesh; } bool nurbs_plugin::postSelection( const QPoint& point ) { Q_UNUSED(point); int selectedID = drawArea()->selectedName(); if (selectedID == -1){ ps.clear(); document()->setSelectedModel(entireMesh); return false; } qDebug() << "Selected ID is " << selectedID; Vertex selectedVertex = entireMesh->vertices( Surface_mesh::Face(selectedID) ); QString gid = faceGroup[entireMesh->face(entireMesh->halfedge(selectedVertex)).idx()]; selectGroup(gid); return true; } void nurbs_plugin::selectGroup(QString gid) { groupID = gid; m = extractMesh( groupID ); QVector part = groupFaces[gid]; // Draw selection ps.clear(); foreach(int fidx, part) { // Collect points QVector pnts; Surface_mesh::Vertex_around_face_circulator vit = entireMesh->vertices(Face(fidx)),vend=vit; do{ pnts.push_back(entirePoints[vit]); } while(++vit != vend); ps.addPoly(pnts, QColor(255,0,0,100)); } } void nurbs_plugin::loadGroupsFromOBJ() { // Read obj file QFile file(mesh()->path); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return; QTextStream inF(&file); int fidx = 0; while( !inF.atEnd() ){ QString line = inF.readLine(); if(!line.size()) continue; if(line.at(0).toAscii() == 'g'){ QStringList groupLine = line.split(" "); QString gid = QString::number(groupFaces.size()); if(groupLine.size()) gid = groupLine.at(1); while(true){ QString line = inF.readLine(); if(!line.startsWith("f")) break; groupFaces[gid].push_back(fidx); faceGroup[fidx] = gid; fidx++; } } } } Vector3d nurbs_plugin::pole( Vector3d center, double radius, SurfaceMeshModel * part ) { Vector3VertexProperty partPoints = part->vertex_property("v:point"); std::vector samples; QVector ifaces; Vector3d p; // intersect sphere with part, collect faces foreach( Face f, part->faces() ){ QVector pnts; Surface_mesh::Vertex_around_face_circulator vit = part->vertices(Face(f)),vend=vit; do{ pnts.push_back(partPoints[vit]); } while(++vit != vend); if(TestSphereTriangle(center, radius, pnts[0], pnts[1], pnts[2], p)){ ifaces.push_back(f); foreach(Vector3d s, sampleEdgeTri(pnts[0], pnts[1], pnts[2])) samples.push_back(s); } } Vector3d a,b,c; return PCA::mainAxis(samples,a,b,c).normalized(); } std::vector nurbs_plugin::sampleEdgeTri( Vector3d a, Vector3d b, Vector3d c ) { std::vector samples; samples.push_back(a);samples.push_back(b);samples.push_back(c); samples.push_back((a+b) * 0.5); samples.push_back((b+c) * 0.5); samples.push_back((c+a) * 0.5); return samples; } double nurbs_plugin::minAngle(Face f, SurfaceMeshModel * ofMesh) { double minAngle(DBL_MAX); Vector3VertexProperty pts = ofMesh->vertex_property("v:point"); SurfaceMesh::Model::Halfedge_around_face_circulator h(ofMesh, f), eend = h; do{ Vector3 a = pts[ofMesh->to_vertex(h)]; Vector3 b = pts[ofMesh->from_vertex(h)]; Vector3 c = pts[ofMesh->to_vertex(ofMesh->next_halfedge(h))]; double d = dot((b-a).normalized(), (c-a).normalized()); double angle = acos(qRanged(-1.0, d, 1.0)); minAngle = qMin(angle, minAngle); } while(++h != eend); return minAngle; } void nurbs_plugin::convertToCurve() { if(!m) return; document()->addModel( m ); prepareSkeletonize(); double theta = 15.0; // degrees for(int i = 0; i < 30; i++){ stepSkeletonizeMesh(); // Decide weather or not to keep contracting based on angle of faces bool isDone = true; foreach( Face f, m->faces() ){ if( minAngle(f, m) > RADIANS(theta) ) isDone = false; } if(isDone) break; } // Clear parameters mcf_params = NULL; foreach(Vertex v, m->vertices()) if(m->is_isolated(v)) m->remove_vertex(v); m->garbage_collection(); // Overwrite any existing extracted nodes for selected part if(graph->getNode(groupID)) graph->removeNode(graph->getNode(groupID)->id); graph->addNode( new Structure::Curve(curveFit( m ), groupID) ); // Clean up ps.clear(); document()->setSelectedModel(entireMesh); document()->deleteModel(m); drawArea()->clear(); m = NULL; drawArea()->updateGL(); } void nurbs_plugin::convertToSheet() { if(!m) return; document()->addModel( m ); prepareSkeletonize(); for(int i = 0; i < widget->contractIterations(); i++) { stepSkeletonizeMesh(); } // Clear parameters mcf_params = NULL; // Clean up foreach(Vertex v, m->vertices()) if(m->is_isolated(v)) m->remove_vertex(v); m->garbage_collection(); // Overwrite any existing extracted nodes for selected part if(graph->getNode(groupID)) graph->removeNode(graph->getNode(groupID)->id); graph->addNode( new Structure::Sheet(surfaceFit( m ), groupID) ); document()->setSelectedModel( entireMesh ); document()->deleteModel(m); drawArea()->clear(); m = NULL; drawArea()->updateGL(); } NURBS::NURBSCurved nurbs_plugin::curveFit( SurfaceMeshModel * part ) { NURBS::NURBSCurved fittedCurve; Vector3VertexProperty partPoints = part->vertex_property("v:point"); GenericGraphs::Graph g; SurfaceMeshHelper h(part); ScalarEdgeProperty elen = h.computeEdgeLengths(); foreach(Edge e, part->edges()){ Vertex v0 = part->vertex(e, 0); Vertex v1 = part->vertex(e, 1); g.AddEdge(v0.idx(), v1.idx(), elen[e]); } // Find initial furthest point g.DijkstraComputePaths(0); double max_dist = -DBL_MAX; int idxA = 0; for(int i = 0; i < (int)part->n_vertices(); i++){ if(g.min_distance[i] > max_dist){ max_dist = qMax(max_dist, g.min_distance[i]); idxA = i; } } // Find two furthest points g.DijkstraComputePaths(idxA); max_dist = -DBL_MAX; int idxB = 0; for(int i = 0; i < (int)part->n_vertices(); i++){ if(g.min_distance[i] > max_dist){ max_dist = qMax(max_dist, g.min_distance[i]); idxB = i; } } std::list path = g.DijkstraShortestPath(idxA,idxB); // Check for loop case double r = 0.025 * part->bbox().diagonal().norm(); QVector pathA, pathB; foreach(int vi, path) pathA.push_back(vi); Vertex centerPath ( pathA[pathA.size() / 2] ); foreach( Face f, part->faces() ){ QVector vidx; Surface_mesh::Vertex_around_face_circulator vit = part->vertices(Face(f)),vend=vit; do{ vidx.push_back(vit); } while(++vit != vend); Vector3d cp(0,0,0); if( TestSphereTriangle(partPoints[centerPath], r, partPoints[vidx[0]], partPoints[vidx[1]], partPoints[vidx[2]], cp) ){ int v0 = vidx[0].idx(); int v1 = vidx[1].idx(); int v2 = vidx[2].idx(); g.SetEdgeWeight(v0,v1,DBL_MAX); g.SetEdgeWeight(v1,v2,DBL_MAX); g.SetEdgeWeight(v2,v0,DBL_MAX); } } foreach(int vi, g.DijkstraShortestPath(idxB,idxA)) pathB.push_back(vi); QVector finalPath = pathA; // We have a loop if(pathB.size() > 0.1 * pathA.size()) finalPath += pathB; std::vector polyLine; for(int i = 0; i < (int)finalPath.size(); i++) polyLine.push_back( partPoints[Vertex(finalPath[i])] ); polyLine = refineByResolution(polyLine, r); //polyLine = smoothPolyline(polyLine, 1); return NURBS::NURBSCurved::createCurveFromPoints(polyLine); } std::vector nurbs_plugin::collectRings(SurfaceMeshModel * part, Vertex v, size_t min_nb) { std::vector all; std::vector current_ring, next_ring; SurfaceMeshModel::Vertex_property visited_map = part->vertex_property("v:visit_map",-1); //initialize visited_map[v] = 0; current_ring.push_back(v); all.push_back(v); int i = 1; while ( (all.size() < min_nb) && (current_ring.size() != 0) ){ // collect i-th ring std::vector::iterator it = current_ring.begin(), ite = current_ring.end(); for(;it != ite; it++){ // push neighbors of SurfaceMeshModel::Halfedge_around_vertex_circulator hedgeb = part->halfedges(*it), hedgee = hedgeb; do{ Vertex vj = part->to_vertex(hedgeb); if (visited_map[vj] == -1){ visited_map[vj] = i; next_ring.push_back(vj); all.push_back(vj); } ++hedgeb; } while(hedgeb != hedgee); } //next round must be launched from p_next_ring... current_ring = next_ring; next_ring.clear(); i++; } //clean up part->remove_vertex_property(visited_map); return all; } NURBS::NURBSRectangled nurbs_plugin::surfaceFit( SurfaceMeshModel * part ) { points = part->vertex_property("v:point"); /// Pick a side by clustering normals // 1) Find edge with flat dihedral angle SurfaceMeshModel::Vertex_property vals = part->vertex_property("v:vals",0); foreach(Vertex v, part->vertices()){ double sum = 0.0; foreach(Vertex v, collectRings(part,v,12)){ foreach(Halfedge h, part->onering_hedges(v)){ sum += abs(calc_dihedral_angle( part, h )); } } vals[v] = sum; } double minSum = DBL_MAX; Vertex minVert; foreach(Vertex v, part->vertices()){ if(vals[v] < minSum){ minSum = vals[v]; minVert = v; } } Halfedge startEdge = part->halfedge(minVert); // 2) Grow region by comparing difference of adjacent dihedral angles double angleThreshold = deg_to_rad( 40.0 ); SurfaceMesh::Model::Vertex_property vvisited = part->add_vertex_property("v:visited", false); QStack to_visit; to_visit.push( part->to_vertex(startEdge) ); while(!to_visit.empty()) { Vertex cur_v = to_visit.pop(); if( vvisited[cur_v] ) continue; vvisited[cur_v] = true; // Sum of angles around double sumAngles = 0.0; foreach(Halfedge hj, part->onering_hedges(cur_v)){ sumAngles += abs(calc_dihedral_angle( part, hj )); } foreach(Halfedge hj, part->onering_hedges(cur_v)) { Vertex vj = part->to_vertex(hj); if(sumAngles < angleThreshold) to_visit.push(vj); else vvisited[vj]; } } // Get filtered inner vertices of selected side int shrink_count = 2; std::set inner; std::set border; for(int i = 0; i < shrink_count; i++) { std::set all_points; foreach(Vertex v, part->vertices()) if(vvisited[v]) all_points.insert(v); border.clear(); foreach(Vertex v, part->vertices()){ if(vvisited[v]){ foreach(Halfedge hj, part->onering_hedges(v)){ Vertex vj = part->to_vertex(hj); if(!vvisited[vj]) border.insert(vj); } } } inner.clear(); std::set_difference(all_points.begin(), all_points.end(), border.begin(), border.end(), std::inserter(inner, inner.end())); // Shrink one level foreach(Vertex vv, border){ foreach(Halfedge hj, part->onering_hedges(vv)) vvisited[ part->to_vertex(hj) ] = false; } } SurfaceMesh::Model * submesh = NULL; bool isOpen = false; foreach(Vertex v, part->vertices()){ if(part->is_boundary(v)){ isOpen = true; break; } } if(!isOpen) { // Collect inner faces std::set innerFaces; std::set inFacesVerts; foreach(Vertex v, inner) { foreach(Halfedge hj, part->onering_hedges(v)){ Face f = part->face(hj); innerFaces.insert(f); Surface_mesh::Vertex_around_face_circulator vit = part->vertices(f),vend=vit; do{ inFacesVerts.insert( Vertex(vit) ); } while(++vit != vend); } } // Create sub-mesh submesh = new SurfaceMesh::Model("SideFlat.obj","SideFlat"); // Add vertices std::map vmap; foreach(Vertex v, inFacesVerts){ vmap[ v ] = Vertex(vmap.size()); submesh->add_vertex( points[v] ); } // Add faces foreach(Face f, innerFaces){ std::vector verts; Surface_mesh::Vertex_around_face_circulator vit = part->vertices(f),vend=vit; do{ verts.push_back( Vertex(vit) ); } while(++vit != vend); submesh->add_triangle( vmap[verts[0]], vmap[verts[1]], vmap[verts[2]] ); } } else { submesh = part; } { //ModifiedButterfly subdiv; //subdiv.subdivide((*(Surface_mesh*)submesh),1); } submesh->isVisible = false; if(part != submesh) document()->addModel( submesh ); Vector3VertexProperty sub_points = submesh->vertex_property("v:point"); // Smoothing { int numIteration = 3; bool protectBorders = true; Surface_mesh::Vertex_property newPositions = submesh->vertex_property("v:new_point",Vector3(0,0,0)); Surface_mesh::Vertex_around_vertex_circulator vvit, vvend; // This method uses the basic equal weights Laplacian operator for(int iteration = 0; iteration < numIteration; iteration++) { Surface_mesh::Vertex_iterator vit, vend = submesh->vertices_end(); // Original positions, for boundary for(vit = submesh->vertices_begin(); vit != vend; ++vit) newPositions[vit] = sub_points[vit]; // Compute Laplacian for(vit = submesh->vertices_begin(); vit != vend; ++vit) { if(!protectBorders || (protectBorders && !submesh->is_boundary(vit))) { newPositions[vit] = Point(0,0,0); // Sum up neighbors vvit = vvend = submesh->vertices(vit); do{ newPositions[vit] += sub_points[vvit]; } while(++vvit != vvend); // Average it newPositions[vit] /= submesh->valence(vit); } } // Set vertices to final position for(vit = submesh->vertices_begin(); vit != vend; ++vit) sub_points[vit] = newPositions[vit]; } submesh->remove_vertex_property(newPositions); } /// ================== // Fit rectangle BoundaryFitting bf( (SurfaceMeshModel*)submesh, widget->uCount(), widget->vCount() ); /// ================== // Debug fitting if( false ) { PointSoup * ps = new PointSoup; foreach(Vertex v, submesh->vertices()) { //if(submesh->is_boundary(v)) // ps->addPoint( sub_points[v], qtJetColorMap(bf.vals[v]) ); } drawArea()->addRenderObject(ps); FaceBarycenterHelper helper(submesh); Vector3FaceProperty fcenter = helper.compute(); foreach(Face f, submesh->faces()){ //if(submesh->is_boundary(f)) vs.addVector(fcenter[f],bf.fgradient[f]); } drawArea()->addRenderObject( new LineSegments(bf.ls) ); foreach(Vertex v, submesh->vertices()){ //if(submesh->is_boundary(v)) // vs.addVector(sub_points[v],bf.vdirection[v]); //vs.addVector(sub_points[v],bf.vgradient[v]); } for(int i = 0; i < (int)bf.debugPoints2.size(); i++) { double t = double(i) / (bf.debugPoints2.size()-1); pps.addPoint(bf.debugPoints2[i], QColor(0,255 * t,50)); } for(int i = 0; i < (int)bf.debugPoints.size(); i++) { //double t = double(i) / (bf.debugPoints.size()-1); //pps.addPoint(bf.debugPoints[i], QColor(255 * t,0,0)); } for(int i = 1; i < (int)bf.debugPoints.size(); i++) { lseg.addLine( bf.debugPoints[i-1], bf.debugPoints[i], QColor(255,255,255,100) ); } if(bf.corners.size()) { PointSoup * ppp = new PointSoup(20); ppp->addPoint(bf.corners[0], QColor(255,0,0)); ppp->addPoint(bf.corners[1], QColor(0,255,0)); ppp->addPoint(bf.corners[2], QColor(0,0,255)); ppp->addPoint(bf.corners[3], QColor(0,255,255)); drawArea()->addRenderObject(ppp); } if(bf.main_edges.size()) { PointSoup * ppe = new PointSoup(10); foreach(Vector3d p, bf.main_edges[0]) ppe->addPoint(p, QColor(255,0,0)); foreach(Vector3d p, bf.main_edges[1]) ppe->addPoint(p, QColor(0,255,0)); foreach(Vector3d p, bf.main_edges[2]) ppe->addPoint(p, QColor(0,0,255)); foreach(Vector3d p, bf.main_edges[3]) ppe->addPoint(p, QColor(0,255,255)); drawArea()->addRenderObject(ppe); } } /// ================== Array2D_Vector3 cp = bf.lines; //cp.clear(); // debug if(!cp.size()) return NURBS::NURBSRectangled::createSheet(Vector3d(0,0,0),Vector3d(0.01)); Array2D_Real cw(cp.size(), Array1D_Real(cp.front().size(), 1.0)); int degree = 3; return NURBS::NURBSRectangled(cp,cw,degree,degree,false,false,true,true); document()->deleteModel(m); // debug //return NURBS::NURBSRectangled::createSheet(Vector3d(0,0,0),Vector3d(0.01)); } void nurbs_plugin::experiment() { NanoKdTree tree; Vector3VertexProperty mesh_points = mesh()->get_vertex_property(VPOINT); foreach(Vertex v, mesh()->vertices()) { tree.addPoint( mesh_points[v] ); } tree.build(); KDResults matches; tree.ball_search(Vector3d(0,0,0), 0.1, matches); drawArea()->deleteAllRenderObjects(); foreach(KDResultPair r, matches) { drawArea()->drawPoint(mesh_points[Vertex(r.first)]); } } void nurbs_plugin::updateDrawArea() { drawArea()->update(); } void nurbs_plugin::loadGraph() { QStringList fileNames = QFileDialog::getOpenFileNames(0, "Open Model", mainWindow()->settings()->getString("lastUsedDirectory"), "Model Files (*.xml)"); if(fileNames.isEmpty()) return; graph = new Structure::Graph(fileNames.front()); } Q_EXPORT_PLUGIN (nurbs_plugin)