void Exporter::exportToFile(const QString& filename, const vector<PtrPrimitive>& primitive_tab, VRenderParams& vparams) { QFile file(filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { QMessageBox::warning(NULL, QGLViewer::tr("Exporter error", "Message box window title"), QGLViewer::tr("Unable to open file %1.").arg(filename)); return; } QTextStream out(&file); writeHeader(out) ; unsigned int N = primitive_tab.size()/200 + 1 ; for(unsigned int i=0;i<primitive_tab.size();++i) { Point *p = dynamic_cast<Point *>(primitive_tab[i]) ; Segment *s = dynamic_cast<Segment *>(primitive_tab[i]) ; Polygone *P = dynamic_cast<Polygone *>(primitive_tab[i]) ; if(p != NULL) spewPoint(p,out) ; if(s != NULL) spewSegment(s,out) ; if(P != NULL) spewPolygone(P,out) ; if(i%N == 0) vparams.progress(i/(float)primitive_tab.size(),QGLViewer::tr("Exporting to file %1").arg(filename)) ; } writeFooter(out) ; file.close(); }
void BSPSortMethod::sortPrimitives(std::vector<PtrPrimitive>& primitive_tab,VRenderParams& vparams) { // 1 - build BSP using polygons only BSPTree tree; Polygone *P; int N = primitive_tab.size()/200 +1; int nbinserted = 0; vector<PtrPrimitive> segments_and_points; // Store segments and points for pass 2, because polygons are deleted // by the insertion and can not be dynamic_casted anymore. for(unsigned int i=0;i<primitive_tab.size();++i,++nbinserted) { if((P = dynamic_cast<Polygone *>(primitive_tab[i])) != NULL) tree.insert(P); else segments_and_points.push_back(primitive_tab[i]); if(nbinserted%N==0) vparams.progress(nbinserted/(float)primitive_tab.size(), QGLViewer::tr("BSP Construction")); } // 2 - insert points and segments into the BSP Segment *S; Point *p; for(unsigned int j=0;j<segments_and_points.size();++j,++nbinserted) { if((S = dynamic_cast<Segment *>(segments_and_points[j])) != NULL) tree.insert(S); else if((p = dynamic_cast<Point *>(segments_and_points[j])) != NULL) tree.insert(p); if(nbinserted%N==0) vparams.progress(nbinserted/(float)primitive_tab.size(), QGLViewer::tr("BSP Construction")); } // 3 - refill the array with the content of the BSP primitive_tab.resize(0); tree.recursFillPrimitiveArray(primitive_tab); }
void TopologicalSortUtils::recursTopologicalSort( vector< vector<int> >& precedence_graph, vector<PtrPrimitive>& primitive_tab, vector<bool>& already_rendered, vector<bool>& already_visited, vector<PtrPrimitive>& new_pr_tab, int indx, int& nb_cycles, VRenderParams& vparams, int info_cnt,int& nbrendered) { // One must first render the primitives indicated by the precedence graph, // then render the current primitive. Skews are detected, but and treated. already_visited[indx] = true ; for(unsigned int j=0;j<precedence_graph[indx].size();++j) { // Both tests are important. If we ommit the second one, the recursion is // always performed down to the next cycle, although this is useless if // the current primitive was rendered already. if(!already_visited[precedence_graph[indx][j]]) { if(!already_rendered[precedence_graph[indx][j]]) recursTopologicalSort( precedence_graph,primitive_tab,already_rendered,already_visited, new_pr_tab,precedence_graph[indx][j],nb_cycles,vparams,info_cnt,nbrendered) ; } else // A cycle is detected, but in this version, it is not broken. ++nb_cycles ; } if(!already_rendered[indx]) { new_pr_tab.push_back(primitive_tab[indx]) ; if((++nbrendered)%info_cnt==0) vparams.progress(nbrendered/(float)primitive_tab.size(), QGLViewer::tr("Topological sort")) ; } already_rendered[indx] = true ; already_visited[indx] = false ; }
void ParserGL::parseFeedbackBuffer( GLfloat *buffer,int size, std::vector<PtrPrimitive>& primitive_tab, VRenderParams& vparams) { int token; int nvertices = 0 ; nb_lines = 0 ; nb_polys = 0 ; nb_points = 0 ; nb_degenerated_lines = 0 ; nb_degenerated_polys = 0 ; nb_degenerated_points = 0 ; // pre-treatment of coordinates so as to get something more consistent _xmin = FLT_MAX ; _ymin = FLT_MAX ; _zmin = FLT_MAX ; _xmax = -FLT_MAX ; _ymax = -FLT_MAX ; _zmax = -FLT_MAX ; ParserUtils::ComputeBufferBB(size, buffer, _xmin,_xmax,_ymin,_ymax,_zmin,_zmax) ; #ifdef DEBUGEPSRENDER printf("Buffer bounding box: %f %f %f %f %f %f\n",xmin,xmax,ymin,ymax,zmin,zmax) ; #endif float Zdepth = max(_ymax-_ymin,_xmax-_xmin) ; ParserUtils::NormalizeBufferCoordinates(size,buffer,Zdepth,_zmin,_zmax) ; // now, read buffer GLfloat *end = buffer + size; GLfloat *loc = buffer ; int next_step = 0 ; int N = size/200 + 1 ; while (loc < end) { token = int(0.5f + *loc) ; loc++; if((end-loc)/N >= next_step) vparams.progress((end-loc)/(float)size, QGLViewer::tr("Parsing feedback buffer.")), ++next_step ; switch (token) { case GL_LINE_TOKEN: case GL_LINE_RESET_TOKEN: { Segment *S = new Segment(Feedback3DColor(loc),Feedback3DColor(loc+Feedback3DColor::sizeInBuffer())) ; primitive_tab.push_back(ParserUtils::checkSegment(S)) ; if(S == NULL) nb_degenerated_lines++ ; nb_lines++ ; loc += 2*Feedback3DColor::sizeInBuffer(); } break; case GL_POLYGON_TOKEN: { nvertices = int(0.5f + *loc) ; loc++; std::vector<Feedback3DColor> verts ; for(int i=0;i<nvertices;++i) verts.push_back(Feedback3DColor(loc)),loc+=Feedback3DColor::sizeInBuffer() ; Polygone *P = new Polygone(verts) ; primitive_tab.push_back(ParserUtils::checkPolygon(P)) ; if(P == NULL) nb_degenerated_polys++ ; nb_polys++ ; } break ; case GL_POINT_TOKEN: { Point *Pt = new Point(Feedback3DColor(loc)) ; primitive_tab.push_back(Pt);//ParserUtils::checkPoint(Pt)) ; if(Pt == NULL) nb_degenerated_points++ ; nb_points++ ; loc += Feedback3DColor::sizeInBuffer(); } break; default: break; } } }
void vrender::VectorialRender(RenderCB render_callback, void *callback_params, VRenderParams& vparams) { GLfloat *feedbackBuffer = NULL ; SortMethod *sort_method = NULL ; Exporter *exporter = NULL ; try { GLint returned = -1 ; vparams.error() = 0 ; int nb_renders = 0 ; vparams.progress(0.0, QGLViewer::tr("Rendering...")) ; while(returned < 0) { if(feedbackBuffer != NULL) delete[] feedbackBuffer ; feedbackBuffer = new GLfloat[vparams.size()] ; if(feedbackBuffer == NULL) throw std::runtime_error("Out of memory during feedback buffer allocation.") ; glFeedbackBuffer(vparams.size(), GL_3D_COLOR, feedbackBuffer); glRenderMode(GL_FEEDBACK); render_callback(callback_params); returned = glRenderMode(GL_RENDER); nb_renders++ ; if(returned < 0) vparams.size() *= 2 ; } #ifdef A_VOIR if(SortMethod != EPS_DONT_SORT) { GLint depth_bits ; glGetIntegerv(GL_DEPTH_BITS, &depth_bits) ; EGALITY_EPS = 2.0/(1 << depth_bits) ; LINE_EGALITY_EPS = 2.0/(1 << depth_bits) ; } #endif if (returned > vparams.size()) vparams.size() = returned; #ifdef _VRENDER_DEBUG cout << "Size = " << vparams.size() << ", returned=" << returned << endl ; #endif // On a un beau feedback buffer tout plein de saloperies. Faut aller // defricher tout ca. Ouaiiiis ! vector<PtrPrimitive> primitive_tab ; ParserGL parserGL ; parserGL.parseFeedbackBuffer(feedbackBuffer,returned,primitive_tab,vparams) ; if(feedbackBuffer != NULL) { delete[] feedbackBuffer ; feedbackBuffer = NULL ; } if(vparams.isEnabled(VRenderParams::OptimizeBackFaceCulling)) { BackFaceCullingOptimizer bfopt ; bfopt.optimize(primitive_tab,vparams) ; } // Lance la methode de sorting switch(vparams.sortMethod()) { case VRenderParams::AdvancedTopologicalSort: case VRenderParams::TopologicalSort: { TopologicalSortMethod *tsm = new TopologicalSortMethod() ; tsm->setBreakCycles(vparams.sortMethod() == VRenderParams::AdvancedTopologicalSort) ; sort_method = tsm ; } break ; case VRenderParams::BSPSort: sort_method = new BSPSortMethod() ; break ; case VRenderParams::NoSorting: sort_method = new DontSortMethod() ; break ; default: throw std::runtime_error("Unknown sorting method.") ; } sort_method->sortPrimitives(primitive_tab,vparams) ; // Lance les optimisations. L'ordre est important. if(vparams.isEnabled(VRenderParams::CullHiddenFaces)) { VisibilityOptimizer vopt ; vopt.optimize(primitive_tab,vparams) ; } #ifdef A_FAIRE if(vparams.isEnabled(VRenderParams::OptimizePrimitiveSplit)) { PrimitiveSplitOptimizer psopt ; psopt.optimize(primitive_tab) ; } #endif // Ecrit le fichier switch(vparams.format()) { case VRenderParams::EPS: exporter = new EPSExporter() ; break ; case VRenderParams::PS: exporter = new PSExporter() ; break ; case VRenderParams::XFIG: exporter = new FIGExporter() ; break ; #ifdef A_FAIRE case VRenderParams::SVG: exporter = new SVGExporter() ; break ; #endif default: throw std::runtime_error("Sorry, this output format is not handled now. Only EPS and PS are currently supported.") ; } // sets background and black & white options GLfloat viewport[4],clearColor[4],lineWidth,pointSize ; glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor); glGetFloatv(GL_LINE_WIDTH, &lineWidth); glGetFloatv(GL_POINT_SIZE, &pointSize); glGetFloatv(GL_VIEWPORT, viewport); lineWidth /= (float)max(viewport[2] - viewport[0],viewport[3]-viewport[1]) ; // Sets which bounding box to use. if(vparams.isEnabled(VRenderParams::TightenBoundingBox)) exporter->setBoundingBox(parserGL.xmin(),parserGL.ymin(),parserGL.xmax(),parserGL.ymax()) ; else exporter->setBoundingBox(viewport[0],viewport[1],viewport[0]+viewport[2],viewport[1]+viewport[3]) ; exporter->setBlackAndWhite(vparams.isEnabled(VRenderParams::RenderBlackAndWhite)) ; exporter->setClearBackground(vparams.isEnabled(VRenderParams::AddBackground)) ; exporter->setClearColor(clearColor[0],clearColor[1],clearColor[2]) ; exporter->exportToFile(vparams.filename(),primitive_tab,vparams) ; // deletes primitives for(unsigned int i=0; i<primitive_tab.size(); ++i) delete primitive_tab[i] ; if(exporter != NULL) delete exporter ; if(sort_method != NULL) delete sort_method ; } catch(exception& e) { cout << "Render aborted: " << e.what() << endl ; if(exporter != NULL) delete exporter ; if(sort_method != NULL) delete sort_method ; if(feedbackBuffer != NULL) delete[] feedbackBuffer ; throw e ; } }
void TopologicalSortUtils::recursTopologicalSort( vector< vector<int> >& precedence_graph, vector<PtrPrimitive>& primitive_tab, vector<bool>& already_rendered, vector<bool>& already_visited, vector<PtrPrimitive>& new_pr_tab, int indx, vector<int>& ancestors, int& ancestors_backward_index, int& nb_cycles, VRenderParams& vparams, int info_cnt,int& nbrendered) { // One must first render the primitives indicated by the precedence graph, // then render the current primitive. Skews are detected, but and treated. already_visited[indx] = true ; ancestors.push_back(indx) ; for(unsigned int j=0;j<precedence_graph[indx].size();++j) { // Both tests are important. If we ommit the second one, the recursion is // always performed down to the next cycle, although this is useless if // the current primitive was rendered already. if(!already_visited[precedence_graph[indx][j]]) { if(!already_rendered[precedence_graph[indx][j]]) { recursTopologicalSort( precedence_graph,primitive_tab,already_rendered,already_visited, new_pr_tab,precedence_graph[indx][j],ancestors,ancestors_backward_index,nb_cycles,vparams,info_cnt,nbrendered) ; if(ancestors_backward_index != INT_MAX && ancestors.size() > (unsigned int)(ancestors_backward_index+1)) { #ifdef DEBUG_TS cout << "Returning early" << endl ; #endif already_visited[indx] = false ; ancestors.pop_back() ; return; } if(ancestors_backward_index != INT_MAX) // we are returning from emergency. j must be re-tried --j ; } } else { // A cycle is detected. It must be broken. The algorithm is the following: primitives of the cycle // are successively split by a chosen splitting plane and the precendence graph is updated // at the same time by re-computing primitive precedence. As soon as the cycle is broken, // the algorithm stops and calls recursively calls on the new precedence graph. This necessarily // happens because of the BSP-node nature of the current set of primitives. // 0 - stats ++nb_cycles ; // 0.5 - determine cycle beginning int cycle_beginning_index = -1 ; for(int i=(int)(ancestors.size())-1; i >= 0 && cycle_beginning_index < 0;--i) if(ancestors[i] == precedence_graph[indx][j]) cycle_beginning_index = i ; #ifdef DEBUG_TS cout << "Unbreaking cycle : " ; for(unsigned int i=0;i<ancestors.size();++i) cout << ancestors[i] << " " ; cout << precedence_graph[indx][j] << endl ; #endif #ifdef DEBUG_TS assert(cycle_beginning_index >= 0) ; #endif // 1 - determine splitting plane int split_prim_ancestor_indx = -1 ; int split_prim_indx = -1 ; // Go down ancestors tab, starting from the skewing primitive, and stopping at it. for(unsigned int i2=cycle_beginning_index;i2<ancestors.size() && split_prim_ancestor_indx < 0;++i2) if(primitive_tab[ancestors[i2]]->nbVertices() > 2) { split_prim_ancestor_indx = i2 ; split_prim_indx = ancestors[i2] ; } #ifdef DEBUG_TS cout << "Split primitive index = " << split_prim_ancestor_indx << "(primitive = " << split_prim_indx << ")" << endl ; #endif if(split_prim_indx < 0) // no need to unskew cycles between segments and points continue ; // 2 - split all necessary primitives const Polygone *P = dynamic_cast<const Polygone *>(primitive_tab[split_prim_indx]) ; const NVector3& normal = NVector3(P->normal()) ; double c(P->c()) ; ancestors.push_back(precedence_graph[indx][j]) ; // sentinel ancestors.push_back(ancestors[cycle_beginning_index+1]) ; // sentinel bool cycle_broken = false ; for(unsigned int i3=cycle_beginning_index+1;i3<ancestors.size()-1 && !cycle_broken;++i3) if(ancestors[i3] != split_prim_indx) { bool prim_lower_ante_contains_im1 = false ; bool prim_upper_ante_contains_im1 = false ; bool prim_lower_prec_contains_ip1 = false ; bool prim_upper_prec_contains_ip1 = false ; Primitive *prim_upper = NULL ; Primitive *prim_lower = NULL ; PrimitivePositioning::splitPrimitive(primitive_tab[ancestors[i3]],normal,c,prim_upper,prim_lower) ; if(prim_upper == NULL || prim_lower == NULL) continue ; #ifdef DEBUG_TS cout << "Splitted primitive " << ancestors[i3] << endl ; #endif vector<int> prim_upper_prec ; vector<int> prim_lower_prec ; vector<int> old_prec = vector<int>(precedence_graph[ancestors[i3]]) ; unsigned int upper_indx = precedence_graph.size() ; int lower_indx = ancestors[i3] ; // Updates the precedence graph downwards. for(unsigned int k=0;k<old_prec.size();++k) { int prp1 = PrimitivePositioning::computeRelativePosition(prim_upper,primitive_tab[old_prec[k]]) ; #ifdef DEBUG_TS cout << "Compariing " << upper_indx << " and " << old_prec[k] << ": " ; #endif // It can not be Upper, because it was lower from the original primitive, but it is not // necessary lower any longer because of the split. if(prp1 & PrimitivePositioning::Lower) { #ifdef DEBUG_TS cout << " > " << endl ; #endif prim_upper_prec.push_back(old_prec[k]) ; if(old_prec[k] == ancestors[i3+1]) prim_upper_prec_contains_ip1 = true ; } #ifdef DEBUG_TS else cout << " I " << endl ; #endif int prp2 = PrimitivePositioning::computeRelativePosition(prim_lower,primitive_tab[old_prec[k]]) ; #ifdef DEBUG_TS cout << "Compariing " << lower_indx << " and " << old_prec[k] << ": " ; #endif if(prp2 & PrimitivePositioning::Lower) { #ifdef DEBUG_TS cout << " > " << endl ; #endif prim_lower_prec.push_back(old_prec[k]) ; if(old_prec[k] == ancestors[i3+1]) prim_lower_prec_contains_ip1 = true ; } #ifdef DEBUG_TS else cout << " I " << endl ; #endif } // We also have to update the primitives which are upper to the // current one, because some of them may not be upper anymore. // This would requires either a O(n^2) algorithm, or to store an // dual precedence graph. For now it's O(n^2). This test can not // be skipped because upper can still be lower to ancestors[i-1]. for(unsigned int l=0;l<precedence_graph.size();++l) if(l != (unsigned int)lower_indx) for(int k=0;k<(int)precedence_graph[l].size();++k) if(precedence_graph[l][k] == ancestors[i3]) { int prp1 = PrimitivePositioning::computeRelativePosition(prim_upper,primitive_tab[l]) ; // It can not be Lower, because it was upper from the original primitive, but it is not // necessary upper any longer because of the split. if(prp1 & PrimitivePositioning::Upper) { // Still upper. Add the new index at end of the array precedence_graph[l].push_back(upper_indx) ; if(l == (unsigned int)ancestors[i3-1]) prim_upper_ante_contains_im1 = true ; } // If the primitive is not upper anymore there is // nothing to change since the index has changed. int prp2 = PrimitivePositioning::computeRelativePosition(prim_lower,primitive_tab[l]) ; #ifdef DEBUG_TS cout << "Compariing " << l << " and " << lower_indx << ": " ; #endif if(prp2 & PrimitivePositioning::Upper) { #ifdef DEBUG_TS cout << " > " << endl ; #endif if(l == (unsigned int)ancestors[i3-1]) // The index is the same => nothing to change. prim_lower_ante_contains_im1 = true ; } else { #ifdef DEBUG_TS cout << " I " << endl ; #endif // Not upper anymore. We have to suppress this entry from the tab. precedence_graph[l][k] = precedence_graph[l][precedence_graph[l].size()-1] ; precedence_graph[l].pop_back() ; --k ; } break ; // each entry is present only once. } // setup recorded new info primitive_tab.push_back(prim_upper) ; delete primitive_tab[lower_indx] ; primitive_tab[lower_indx] = prim_lower ; // Adds the info to the precedence graph precedence_graph.push_back(prim_upper_prec) ; precedence_graph[lower_indx] = prim_lower_prec ; // Adds new entries to the 'already_rendered' and 'already_visited' vectors already_visited.push_back(false) ; already_rendered.push_back(false) ; #ifdef DEBUG_TS cout << "New precedence graph: " << endl ; printPrecedenceGraph(precedence_graph,primitive_tab) ; #endif // Checks if the cycle is broken. Because the graph is only // updated downwards, we check wether lower (which still is // lower to ancestors[i-1]) is upper to ancestors[i+1], or // if upper is still . if(( !(prim_lower_ante_contains_im1 && prim_lower_prec_contains_ip1)) &&(!(prim_upper_ante_contains_im1 && prim_upper_prec_contains_ip1))) cycle_broken = true ; } ancestors.pop_back() ; ancestors.pop_back() ; // 3 - recurs call if(cycle_broken) { ancestors_backward_index = cycle_beginning_index ; #ifdef DEBUG_TS cout << "Cycle broken. Jumping back to rank " << ancestors_backward_index << endl ; #endif already_visited[indx] = false ; ancestors.pop_back() ; return; } #ifdef DEBUG_TS else cout << "Cycle could not be broken !!" << endl ; #endif } } if(!already_rendered[indx]) { #ifdef DEBUG_TS cout << "Returning ok. Rendered primitive " << indx << endl ; #endif new_pr_tab.push_back(primitive_tab[indx]) ; if((++nbrendered)%info_cnt==0) vparams.progress(nbrendered/(float)primitive_tab.size(), QGLViewer::tr("Advanced topological sort")) ; } already_rendered[indx] = true ; ancestors_backward_index = INT_MAX ; already_visited[indx] = false ; ancestors.pop_back() ; }
void VisibilityOptimizer::optimize(vector<PtrPrimitive>& primitives,VRenderParams& vparams) #endif { #ifdef DEBUG_VO cout << "Optimizing visibility." << endl ; #endif int N = primitives.size()/200 + 1 ; #ifdef DEBUG_EPSRENDER__SHOW1 // cout << "Showing viewer." << endl ; // myViewer viewer ; // viewer.show(); double minx = FLT_MAX ; double miny = FLT_MAX ; double maxx = -FLT_MAX ; double maxy = -FLT_MAX ; for(unsigned int i=0;i<primitives.size();++i) for(int j=0;j<primitives[i]->nbVertices();++j) { if(maxx < primitives[i]->vertex(j).x()) maxx = primitives[i]->vertex(j).x() ; if(maxy < primitives[i]->vertex(j).y()) maxy = primitives[i]->vertex(j).y() ; if(minx > primitives[i]->vertex(j).x()) minx = primitives[i]->vertex(j).x() ; if(miny > primitives[i]->vertex(j).y()) miny = primitives[i]->vertex(j).y() ; } glMatrixMode(GL_PROJECTION) ; glLoadIdentity() ; glOrtho(minx,maxx,miny,maxy,-1,1) ; glMatrixMode(GL_MODELVIEW) ; glLoadIdentity() ; cout << "Window set to " << minx << " " << maxx << " " << miny << " " << maxy << endl ; glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT) ; glLineWidth(3.0) ; #endif int nb_culled = 0 ; // Ca serait pas mal mieux avec une interface c++... gpc_polygon cumulated_union ; cumulated_union.num_contours = 0 ; cumulated_union.hole = NULL ; cumulated_union.contour = NULL ; int nboptimised = 0 ; for(int pindex = primitives.size() - 1; pindex >= 0;--pindex,++nboptimised) if(primitives[pindex] != NULL) { #ifdef A_FAIRE percentage_finished = pindex / (float)primitives.size() ; #endif if(primitives[pindex]->nbVertices() > 1) { #ifdef DEBUG_VO if(pindex%50==0) { char buff[500] ; sprintf(buff,"Left: % 6ld - Culled: % 6ld", (long)pindex,(long)nb_culled) ; fprintf(stdout,buff); for(unsigned int j=0;j<strlen(buff);++j) fprintf(stdout,"\b") ; fflush(stdout) ; } #endif try { PtrPrimitive p(primitives[pindex]) ; gpc_polygon difference ; gpc_polygon new_poly ; gpc_polygon new_poly_reduced ; new_poly.num_contours = 0 ; new_poly.hole = NULL ; new_poly.contour = NULL ; new_poly_reduced.num_contours = 0 ; new_poly_reduced.hole = NULL ; new_poly_reduced.contour = NULL ; // 1 - creates a gpc_polygon corresponding to the current primitive gpc_vertex_list *new_poly_verts = new gpc_vertex_list ; gpc_vertex_list *new_poly_reduced_verts = new gpc_vertex_list ; double mx = 0.0 ; double my = 0.0 ; if(p->nbVertices() == 2) { new_poly_verts->num_vertices = 4 ; new_poly_verts->vertex = new gpc_vertex[4] ; new_poly_reduced_verts->num_vertices = 4 ; new_poly_reduced_verts->vertex = new gpc_vertex[4] ; double deps = 0.001 ; double du = p->vertex(1).y()-p->vertex(0).y() ; double dv = p->vertex(1).x()-p->vertex(0).x() ; double n = sqrt(du*du+dv*dv) ; du *= deps/n ; dv *= deps/n ; new_poly_verts->vertex[0].x = p->vertex(0).x() + du ; new_poly_verts->vertex[0].y = p->vertex(0).y() + dv ; new_poly_verts->vertex[1].x = p->vertex(1).x() + du ; new_poly_verts->vertex[1].y = p->vertex(1).y() + dv ; new_poly_verts->vertex[2].x = p->vertex(1).x() - du ; new_poly_verts->vertex[2].y = p->vertex(1).y() - dv ; new_poly_verts->vertex[3].x = p->vertex(0).x() - du ; new_poly_verts->vertex[3].y = p->vertex(0).y() - dv ; new_poly_reduced_verts->vertex[0].x = p->vertex(0).x() + du ; new_poly_reduced_verts->vertex[0].y = p->vertex(0).y() + dv ; new_poly_reduced_verts->vertex[1].x = p->vertex(1).x() + du ; new_poly_reduced_verts->vertex[1].y = p->vertex(1).y() + dv ; new_poly_reduced_verts->vertex[2].x = p->vertex(1).x() - du ; new_poly_reduced_verts->vertex[2].y = p->vertex(1).y() - dv ; new_poly_reduced_verts->vertex[3].x = p->vertex(0).x() - du ; new_poly_reduced_verts->vertex[3].y = p->vertex(0).y() - dv ; } else { new_poly_verts->num_vertices = p->nbVertices() ; new_poly_verts->vertex = new gpc_vertex[p->nbVertices()] ; for(int i=0;i<p->nbVertices();++i) { new_poly_verts->vertex[i].x = p->vertex(i).x() ; new_poly_verts->vertex[i].y = p->vertex(i).y() ; mx += p->vertex(i).x() ; my += p->vertex(i).y() ; } mx /= p->nbVertices() ; my /= p->nbVertices() ; new_poly_reduced_verts->num_vertices = p->nbVertices() ; new_poly_reduced_verts->vertex = new gpc_vertex[p->nbVertices()] ; for(int j=0;j<p->nbVertices();++j) { new_poly_reduced_verts->vertex[j].x = mx + (p->vertex(j).x() - mx)*0.999 ; new_poly_reduced_verts->vertex[j].y = my + (p->vertex(j).y() - my)*0.999 ; } } gpc_add_contour(&new_poly,new_poly_verts,false) ; gpc_add_contour(&new_poly_reduced,new_poly_reduced_verts,false) ; // 2 - computes the difference between this polygon, and the union of the // preceeding ones. gpc_polygon_clip(GPC_DIFF,&new_poly_reduced,&cumulated_union,&difference) ; // 3 - checks the difference. If void, the primitive is not visible: skip it // and go to next primitive. if(difference.num_contours == 0) { ++nb_culled ; delete p ; primitives[pindex] = NULL ; continue ; } // 4 - The primitive is visible. Let's add it to the cumulated union of // primitives. if(p->nbVertices() > 2) { gpc_polygon cumulated_union_tmp ; cumulated_union_tmp.num_contours = 0 ; cumulated_union_tmp.hole = NULL ; cumulated_union_tmp.contour = NULL ; gpc_polygon_clip(GPC_UNION,&new_poly,&cumulated_union,&cumulated_union_tmp) ; gpc_free_polygon(&cumulated_union) ; cumulated_union = cumulated_union_tmp ; } gpc_free_polygon(&new_poly) ; gpc_free_polygon(&new_poly_reduced) ; gpc_free_polygon(&difference) ; #ifdef DEBUG_EPSRENDER__SHOW1 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT) ; glColor3f(1.0,0.0,0.0) ; for(int i=0;i<cumulated_union.num_contours;++i) { glBegin(GL_LINE_LOOP) ; for(int j=0;j<cumulated_union.contour[i].num_vertices;++j) glVertex2f(cumulated_union.contour[i].vertex[j].x,cumulated_union.contour[i].vertex[j].y) ; glEnd() ; } glFlush() ; glXSwapBuffers(glXGetCurrentDisplay(),glXGetCurrentDrawable()) ; #endif } catch(exception& ) { ; // std::cout << "Could not treat primitive " << pindex << ": internal gpc error." << endl ; } } if(nboptimised%N==0) vparams.progress(nboptimised/(float)primitives.size(), QGLViewer::tr("Visibility optimization")) ; } #ifdef DEBUG_VO cout << nb_culled << " primitives culled over " << primitives.size() << "." << endl ; #endif gpc_free_polygon(&cumulated_union) ; }