/******************************************************************************* * * Initialize Function * *******************************************************************************/ void initialize() { /************************************************** * Setting up for Clock (PLL, M, N1, N2) * for 32 MHz and Fcy = 16 MHz *************************************************/ // Fosc = Fin(M/(N1*N2)) = 8 MHz (32/(2*4)) = 32 MHz PLLFBD = 30; // M = 32 // N1 default is 2 // N2 default is 4 // Fcy = Fosc/2 by default // Setting up RD6 and RD7 _TRISD6 = 1; _TRISD7 = 1; // Set RD6 & 7 to inputs // Initialize LCD Init_LCD(); lcd_cmd(0xD); // Making sure that we are starting at line 1, column 0 home_it(); // Print the LcdData1 puts_lcd(LcdData1, sizeof(LcdData1)-1); // Move to next line line_2(); // Print the LCDData2 puts_lcd(LcdData2, sizeof(LcdData2)-1); }
void LinkStatusWidget::initLines(){ lines.clear(); int lineLeft=this->left_left+this->left_width+this->left_space; int lineRight=this->width()-this->right_right; int centerHeight=this->right_top+this->right_height+this->right_space/2; QPoint p_left_left(lineLeft,centerHeight); QPoint p_left_right(lineRight,centerHeight); QLine line_1(p_left_left,p_left_right); int lineRightRight=this->width()-this->right_right+this->right_space; int lineRightTop=centerHeight- this->right_space/2-this->right_height/2; int lineRightBottom= centerHeight+this->right_space/2+this->right_height/2; QPoint p_right_top_left(lineRightRight,lineRightTop); QPoint p_right_top_right(lineRightRight,lineRightBottom); QLine line_2(p_right_top_left,p_right_top_right); lines.append(line_1); lines.append(line_2); }
bool ParametricCurveTests::testProjectionBasedInterpolation() { bool success = true; // to start with, project a line onto a linear basis shards::CellTopology line_2(shards::getCellTopologyData<shards::Line<2> >() ); /////////////////// TEST LINEAR CURVES RECOVERED ////////////////////// BasisPtr linearBasis = BasisFactory::basisFactory()->getBasis(1, line_2.getKey(), Camellia::FUNCTION_SPACE_HGRAD); double x0=3, y0=-3, x1=5, y1=4; // double dist = sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); double dist = 1; // the length of the parametric space BasisCachePtr basisCache = BasisCache::basisCache1D(0, dist, linearBasis->getDegree()*2); ParametricCurvePtr myLine = ParametricCurve::line(x0, y0, x1, y1); bool useH1 = true; double lengthScale = 1.0; FieldContainer<double> basisCoefficients_x, basisCoefficients_y; myLine->projectionBasedInterpolant(basisCoefficients_x, linearBasis, 0, lengthScale, useH1); myLine->projectionBasedInterpolant(basisCoefficients_y, linearBasis, 1, lengthScale, useH1); if ( ! basisSumInterpolatesCurveEndPoints(basisCoefficients_x,basisCoefficients_y, linearBasis, myLine)) { cout << "testProjectionBasedInterpolation() failed: projection-based interpolant doesn't interpolate line endpoints.\n"; cout << "basisCoefficients_x:\n" << basisCoefficients_x; cout << "basisCoefficients_y:\n" << basisCoefficients_y; success = false; } // in fact, we should recover the line in x and y: if ( !basisSumEqualsFunction(basisCoefficients_x, linearBasis, myLine->x()) ) { cout << "testProjectionBasedInterpolation() failed: projection-based interpolant doesn't recover the line in the x component.\n"; success = false; } if ( !basisSumEqualsFunction(basisCoefficients_y, linearBasis, myLine->y()) ) { cout << "testProjectionBasedInterpolation() failed: projection-based interpolant doesn't recover the line in the y component.\n"; success = false; } /////////////////// TEST CUBIC CURVES RECOVERED ////////////////////// FunctionPtr t = Function::xn(1); // define x and y as functions of t: FunctionPtr x_t = t*t*t-2*t; FunctionPtr y_t = t*t*t+8*t*t; ParametricCurvePtr myCurve = ParametricCurve::curve(x_t,y_t); BasisPtr cubicBasis = BasisFactory::basisFactory()->getBasis(3, line_2.getKey(), Camellia::FUNCTION_SPACE_HGRAD); myCurve->projectionBasedInterpolant(basisCoefficients_x, cubicBasis, 0, lengthScale, useH1); myCurve->projectionBasedInterpolant(basisCoefficients_y, cubicBasis, 1, lengthScale, useH1); // we should again recover the curve exactly: if ( !basisSumEqualsFunction(basisCoefficients_x, cubicBasis, myCurve->x()) ) { cout << "testProjectionBasedInterpolation() failed: projection-based interpolant doesn't recover the cubic curve in the x component.\n"; success = false; } if ( !basisSumEqualsFunction(basisCoefficients_y, cubicBasis, myCurve->y()) ) { cout << "testProjectionBasedInterpolation() failed: projection-based interpolant doesn't recover the cubic curve in the y component.\n"; success = false; } /////////////////// TEST UNRECOVERABLE CURVE INTERPOLATED ////////////////////// // finally, project the cubic curve onto a quadratic basis, and check that it interpolates the endpoints BasisPtr quadraticBasis = BasisFactory::basisFactory()->getBasis(2, line_2.getKey(), Camellia::FUNCTION_SPACE_HGRAD); myCurve->projectionBasedInterpolant(basisCoefficients_x, quadraticBasis, 0, lengthScale, useH1); myCurve->projectionBasedInterpolant(basisCoefficients_y, quadraticBasis, 1, lengthScale, useH1); if ( ! basisSumInterpolatesCurveEndPoints(basisCoefficients_x,basisCoefficients_y, quadraticBasis, myCurve)) { cout << "testProjectionBasedInterpolation() failed: quadratic projection-based interpolant doesn't interpolate cubic curve endpoints.\n"; cout << "basisCoefficients_x:\n" << basisCoefficients_x; cout << "basisCoefficients_y:\n" << basisCoefficients_y; success = false; } return success; }
bool ParametricCurveTests::testCircularArc() { bool success = true; // the arc details are copied from CurvilinearMeshTests -- motivation is to diagnose test failure there with a more granular test here double radius = 1.0; double meshWidth = sqrt(2); ParametricCurvePtr circle = ParametricCurve::circle(radius, meshWidth / 2.0, meshWidth / 2.0); ParametricCurvePtr circularArc = ParametricCurve::subCurve(circle, 5.0/8.0, 7.0/8.0); BasisCachePtr basisCache = BasisCache::parametric1DCache(15); // overintegrate to be safe FunctionPtr cos_part = Teuchos::rcp( new Cos_ax(PI/2, 1.25*PI)); FunctionPtr sin_part = Teuchos::rcp( new Sin_ax(PI/2, 1.25*PI)); FunctionPtr x_t = meshWidth / 2 + cos_part; FunctionPtr y_t = meshWidth / 2 + sin_part; FunctionPtr dx_dt = (- PI / 2) * sin_part; FunctionPtr dy_dt = (PI / 2) * cos_part; double arcIntegral_x = circularArc->x()->integrate(basisCache); double x_t_integral = x_t->integrate(basisCache); // check that we have the right idea for all those functions: if (! x_t->equals(circularArc->x(),basisCache)) { double x1_expected = Function::evaluate(x_t,1); double x1_actual; circularArc->xPart()->value(1,x1_actual); cout << "expected x(0) = " << x1_expected; cout << "; actual = " << x1_actual << endl; cout << "x part of circularArc doesn't match expected.\n"; success = false; } if (! y_t->equals(circularArc->y(),basisCache)) { double y1_actual; circularArc->yPart()->value(1,y1_actual); cout << "expected y(1) = " << Function::evaluate(y_t,1); cout << "; actual = " << y1_actual << endl; cout << "y part of circularArc doesn't match expected.\n"; success = false; } if (! dx_dt->equals(circularArc->dt_parametric()->x(),basisCache)) { cout << "dx/dt of circularArc doesn't match expected.\n"; success = false; } if (! dy_dt->equals(circularArc->dt_parametric()->y(),basisCache)) { cout << "dy/dt of circularArc doesn't match expected.\n"; success = false; } // test exact curve at t=0.5 double tol=1e-14; double t = 0.5; double x_expected = meshWidth / 2; double y_expected = meshWidth / 2 - radius; double x,y,xErr,yErr; // check value circularArc->value(t, x, y); xErr = abs(x-x_expected); yErr = abs(y-y_expected); if (xErr > tol) { cout << "exact arc x at t=0.5 is incorrect.\n"; success = false; } if (yErr > tol) { cout << "exact arc y at t=0.5 is incorrect.\n"; success = false; } // check derivatives // figuring out what the x derivative should be is a bit of work, I think, // but the y value is at a minimum, so its derivative should be zero y_expected = 0; circularArc->dt_parametric()->value(t, x, y); yErr = abs(y-y_expected); if (yErr > tol) { cout << "exact arc dy/dt at t=0.5 is nonzero.\n"; success = false; } shards::CellTopology line_2(shards::getCellTopologyData<shards::Line<2> >() ); BasisPtr quadraticBasis = BasisFactory::basisFactory()->getBasis(2, line_2.getKey(), Camellia::FUNCTION_SPACE_HGRAD); // figure out what the weights for the quadratic "middle node" basis function should be: double expected_H1_weight_x, expected_H1_weight_y; double expected_L2_weight_x, expected_L2_weight_y; FunctionPtr middleBasis; { FunctionPtr t = Function::xn(1); middleBasis = 4 * t * (1-t); } double middleBasisL2_squared = (middleBasis*middleBasis)->integrate(basisCache); double middleBasisH1_squared = ( middleBasis->dx() * middleBasis->dx() )->integrate(basisCache) + middleBasisL2_squared; ParametricCurvePtr circularArcBubble = ParametricCurve::bubble(circularArc); FunctionPtr bubble_x = circularArcBubble->x(); FunctionPtr bubble_y = circularArcBubble->y(); double x_against_middle_L2 = (bubble_x * middleBasis)->integrate(basisCache); double x_against_middle_H1 = (bubble_x->dx() * middleBasis->dx())->integrate(basisCache) + x_against_middle_L2; double y_against_middle_L2 = (bubble_y * middleBasis)->integrate(basisCache); double y_against_middle_H1 = (bubble_y->dx() * middleBasis->dx())->integrate(basisCache) + y_against_middle_L2; expected_L2_weight_x = x_against_middle_L2 / middleBasisL2_squared; expected_H1_weight_x = x_against_middle_H1 / middleBasisH1_squared; expected_L2_weight_y = y_against_middle_L2 / middleBasisL2_squared; expected_H1_weight_y = y_against_middle_H1 / middleBasisH1_squared; int middleBasisOrdinal = quadraticBasis->getDofOrdinal(1,0,0); FieldContainer<double> basisCoefficients_x, basisCoefficients_y; bool useH1 = false; // just trying to diagnose whether the issue is in derivatives or values (most likely derivatives) double lengthScale = 1.0; circularArcBubble->projectionBasedInterpolant(basisCoefficients_x, quadraticBasis, 0, lengthScale, useH1); circularArcBubble->projectionBasedInterpolant(basisCoefficients_y, quadraticBasis, 1, lengthScale, useH1); double weightError_x = abs(expected_L2_weight_x-basisCoefficients_x[middleBasisOrdinal]); double weightError_y = abs(expected_L2_weight_y-basisCoefficients_y[middleBasisOrdinal]); if (weightError_x > tol) { success = false; cout << "testCircularArc(): L2 projection doesn't match expected basis weight in x.\n"; cout << "expected " << expected_L2_weight_x << ", was " << basisCoefficients_x[middleBasisOrdinal] << endl; } if (weightError_y > tol) { success = false; cout << "testCircularArc(): L2 projection doesn't match expected basis weight in y.\n"; cout << "expected " << expected_L2_weight_y << ", was " << basisCoefficients_y[middleBasisOrdinal] << endl; } useH1 = true; circularArcBubble->projectionBasedInterpolant(basisCoefficients_x, quadraticBasis, 0, lengthScale, useH1); circularArcBubble->projectionBasedInterpolant(basisCoefficients_y, quadraticBasis, 1, lengthScale, useH1); weightError_x = abs(expected_H1_weight_x-basisCoefficients_x[middleBasisOrdinal]); weightError_y = abs(expected_H1_weight_y-basisCoefficients_y[middleBasisOrdinal]); if (weightError_x > tol) { success = false; cout << "testCircularArc(): H1 projection doesn't match expected basis weight in x.\n"; cout << "expected " << expected_H1_weight_x << ", was " << basisCoefficients_x[middleBasisOrdinal] << endl; } if (weightError_y > tol) { success = false; cout << "testCircularArc(): H1 projection doesn't match expected basis weight in y.\n"; cout << "expected " << expected_H1_weight_y << ", was " << basisCoefficients_y[middleBasisOrdinal] << endl; } /* FunctionPtr projection_x = BasisSumFunction::basisSumFunction(quadraticBasis, basisCoefficients_x); FunctionPtr projection_y = BasisSumFunction::basisSumFunction(quadraticBasis, basisCoefficients_y); FieldContainer<double> parametricPoint(1,1); parametricPoint[0] = t; FieldContainer<double> refPoint = basisCache->getRefCellPointsForPhysicalPoints(parametricPoint); basisCache->setRefCellPoints(refPoint); FieldContainer<double> value(1,1); projection_x->values(value, basisCache); x = value[0]; projection_y->values(value, basisCache); y = value[0]; // same expectations at the beginning, except of course now we don't expect to nail it. // but we do expect to be closer than the linear interpolation of the vertices x_expected = meshWidth / 2; y_expected = meshWidth / 2 - radius; double linearErr_x = 0; // linear interpolant nails the x value double linearErr_y = abs(y_expected); xErr = abs(x-x_expected); yErr = abs(y-y_expected); if (xErr > linearErr_x + tol) { cout << "quadratic projection-based interpolant has greater error in x than linear interpolant.\n"; success = false; } if (yErr > linearErr_y + tol) { cout << "quadratic projection-based interpolant has greater error in y than linear interpolant.\n"; success = false; }*/ return success; }
/******************************************************************************* * * Main Function * *******************************************************************************/ int main() { // setting up everything initialize(); int LcdCounter = 0; int LcdFlag = 0, LcdLine = 1; /*************** Main Loop ***********************************/ while (1) { // Next press of RD6 = the printing of one char if ((_RD6 == 0) && (LcdFlag == 1)) { if (LcdCounter < (sizeof(LcdData1)-1)) { puts_lcd(&LcdData1[LcdCounter], 1); LcdCounter++; } if (LcdCounter >= (sizeof(LcdData1)- 1)) { if ((LcdCounter == (sizeof(LcdData1) - 1 )) && (LcdLine = 1)) { line_2(); LcdLine = 2; } else if (LcdCounter <= ((sizeof(LcdData1) + sizeof(LcdData2)) -2)) { puts_lcd(&LcdData2[(LcdCounter - sizeof(LcdData1))], 1); LcdCounter++; } } Delay_Us(1000); // Debouncing } // First press of RD6 = clear the screen if ((_RD6 == 0) && (LcdFlag == 0)) { home_clr(); home_it(); LcdFlag = 1; Delay_Us(1000); // Debouncing } // If RD7 was pressed if ((_RD7 == 0)) { if ((LcdCounter == sizeof(LcdData1)) && (LcdLine == 2)) { lcd_cmd(0x8F); puts_lcd(&LcdSpace, 1); lcd_cmd(0x8F); LcdCounter--; // LcdLine = 1; } else { cursor_left(); puts_lcd(&LcdSpace, 1); cursor_left(); LcdCounter--; } Delay_Us(1000); // Debouncing } } // End of the infinite While loop return 1; }
// // removes the given vertex and retriangulates the hole which would be made // // The method returns true if the vertex has been removed and false if the vertex has been retained. // bool MeshEx::removeVertexAndReTriangulateNeighbourhood( Vertex *v ) { std::vector<MeshEx::Edge *> boundaryEdges; // boundary edges which form the polygon which has to be triangulated std::vector<MeshEx::Edge *> criticalEdges; // edges which are not only connected to other vertices of the vertexring through boundary edges std::map<MeshEx::Vertex *, EdgeInfoHelper> boundaryRing; // maps incomming and outgoing edge to each vertex of the boundary vertex-ring // gather and prepare information ------------------------------------------------ for( std::vector<Triangle *>::iterator it = v->triangleRing.begin(); it != v->triangleRing.end(); ++it ) { Triangle *t = (*it); Edge *boundaryEdge = t->getOtherEdge( v ); boundaryRing[boundaryEdge->v1].registerEdge( boundaryEdge ); boundaryRing[boundaryEdge->v2].registerEdge( boundaryEdge ); boundaryEdges.push_back( boundaryEdge ); } // align the edges so that for each vertex e1 is the incomming and e2 is the outgoing edge Vertex *first = boundaryRing.begin()->first; Vertex *current = first; Vertex *next = 0; Vertex *prev = 0; do { // we have to be sure that each boundaryRing Vertex has an incomming and outgoing edge if( !boundaryRing[current].e1 || !boundaryRing[current].e2 ) { printf( "error : edge ring around vertex not closed boundary vertex has less than 2 edges (polygon hole?)\n" ); //++g_iterations; return false; } boundaryRing[current].setVertex( current ); next = boundaryRing[current].next; if( boundaryRing[next].e1 != boundaryRing[current].e2 ) boundaryRing[next].swap(); current = next; }while( current != first ); // we have to collect all edges going out from the vertex-ring vertices which are connected to // other vertices of the vertex ring - these will later be used for consistency check #2 (see chapter 4.4 of the paper) // for each vertex of the vertex Ring V for( std::map<Vertex *, EdgeInfoHelper>::iterator it = boundaryRing.begin(); it != boundaryRing.end(); ++it ) { Vertex *rv = it->first; // current vertex of the vertex ring // for each triangle referencing rv... for( std::vector<Triangle *>::iterator tit = rv->triangleRing.begin(); tit != rv->triangleRing.end(); ++tit ) { Triangle *rv_tri = *tit; // ... which doesnt belong to the triangleRing of v if( std::find( v->triangleRing.begin(), v->triangleRing.end(), rv_tri ) == v->triangleRing.end() ) { // collect the edges containing rv... for( size_t i=0; i<3; ++i ) if( rv_tri->e[i]->contains(rv) ) // ...and dont belong to the edgeRing list if( std::find( boundaryEdges.begin(), boundaryEdges.end(), rv_tri->e[i] ) == boundaryEdges.end() ) // store the edge if the node on the other side references another vertex of the vertex-ring if( boundaryRing.find( rv_tri->e[i]->getOtherVertex(rv) ) != boundaryRing.end() ) criticalEdges.push_back( rv_tri->e[i] ); } } } // remove duplicate entries std::sort( criticalEdges.begin(), criticalEdges.end() ); criticalEdges.erase( std::unique(criticalEdges.begin(), criticalEdges.end()), criticalEdges.end() ); // Now we will project the neighbourhood of v onto a plane so that we can employ the greedy // triangulation. For this we will have to find a projection of the neighbourhood of v so that // no edges intersect on that plane. If they would, then the greedy triangulation would introduce // folds which means that the topology would be destroyed. // Looking for a working projection may lead to a number of projection-trials. For the first try // we will take the plane to be the plane defined by the normal of v and (its distance to the origin). // This will do the job most of the time. math::Vec3f normal; // direction of the projection plane math::Vec3f base1; // base vector which builds the 2d-coordinate system math::Vec3f base2; // base vector which builds the 2d-coordinate system float distance; // distance of the plane to the origin CGAL::Orientation boundaryPolygonOrientation; // orientation (clockwise/counterclockwise of the boundary polyon) distance = -math::dotProduct( v->position, normal ); size_t trialCount = 13; // only one trial for now size_t currentTrial = 0; bool success = true; do { // we assume that we will be successfull success = true; switch(currentTrial) { case 0: // first trial: we take the plane defined by the normal of v normal = v->normal; break; // for all other trials we will try one of 12 different directions case 1:normal = math::normalize( math::Vec3f( .8507f, .4472f, .2764f ));break; case 2:normal = math::normalize( math::Vec3f( -.8507f, .4472f, .2764f ));break; case 3:normal = math::normalize( math::Vec3f( .8507f, -.4472f, -.2764f ));break; case 4:normal = math::normalize( math::Vec3f( -.8507f, -.4472f, -.2764f ));break; case 5:normal = math::normalize( math::Vec3f( .5257f, -.4472f, .7236f ));break; case 6:normal = math::normalize( math::Vec3f( .5257f, .4472f, -.7236f ));break; case 7:normal = math::normalize( math::Vec3f( -.5257f, -.4472f, .7236f ));break; case 8:normal = math::normalize( math::Vec3f( -.5257f, .4472f, -.7236f ));break; case 9:normal = math::normalize( math::Vec3f( .0f, .4472f, .8944f ));break; case 10:normal = math::normalize( math::Vec3f( .0f, -1.0f, .0f ));break; case 11:normal = math::normalize( math::Vec3f( .0f, 1.0f, .0f ));break; case 12:normal = math::normalize( math::Vec3f( .0f, -.4472f, -.8944f ));break; }; // compute the basis of the 2d-coordinate system of the plane defined by current normal base1 = math::normalize( math::projectPointOnPlane( normal, distance, boundaryRing.begin()->first->position ) - v->position ); base2 = math::normalize( math::crossProduct( normal, base1 ) ); // project neighbours into the given plane for( std::map<Vertex *, EdgeInfoHelper>::iterator it = boundaryRing.begin(); it != boundaryRing.end(); ++it ) it->second.projected = _get2d( base1, base2, math::projectPointOnPlane( normal, distance, it->first->position ) ); // topologic constistency check #1 (see chapter 4.4 of the paper) // now do the consistency check: test if all edges dont intersect and dont lie over each other // if any edge between the projected vertices intersect -> success = false // test each projected edge of the edge ring against each other edge for( std::vector<Edge *>::iterator it1 = boundaryEdges.begin(); it1 != boundaryEdges.end() - 1; ++it1 ) { for( std::vector<Edge *>::iterator it2 = it1+1; it2 != boundaryEdges.end(); ++it2 ) { Edge *e1 = *it1; Edge *e2 = *it2; math::Vec3f intersectionPoint; // skip if the 2 lines share a common vertex if( e2->contains(e1->v1) || e2->contains(e1->v2) ) continue; math::Vec2f e1_v1_projected = boundaryRing[e1->v1].projected; math::Vec2f e1_v2_projected = boundaryRing[e1->v2].projected; math::Vec2f e2_v1_projected = boundaryRing[e2->v1].projected; math::Vec2f e2_v2_projected = boundaryRing[e2->v2].projected; CGAL::Segment_2<K> line_1( Point( e1_v1_projected.x, e1_v1_projected.y ), Point(e1_v2_projected.x, e1_v2_projected.y) ); CGAL::Segment_2<K> line_2( Point( e2_v1_projected.x, e2_v1_projected.y ), Point(e2_v2_projected.x, e2_v2_projected.y) ); if( CGAL::do_intersect( line_1, line_2 ) ) { success = false; break; } } if( !success ) break; } if( success ) { // // now we do the topology consistency check #2 (see chapter 4.4 of the paper) // this is done by checking all critical edges whether they cross the interior of the // polygon boundary which is formed by the projected vertex ring vertices // to do this we create the 2 polygongs which can be made by using the edge as a divider // the line crosses the interior if both polgons have a counterclockwise orientation // for( std::vector<Edge *>::iterator it = criticalEdges.begin(); it != criticalEdges.end(); ++it ) { Edge *criticalEdge = *it; // setup left polygon // start from v1 and go to v2 Polygon leftPoly; prev = 0; current = criticalEdge->v1; do { leftPoly.push_back( current, boundaryRing[current].projected ); prev = current; current = boundaryRing[current].next; }while( current != criticalEdge->v2 ); leftPoly.push_back( current, boundaryRing[current].projected ); // setup right polygon // start from v2 and go to v1 Polygon rightPoly; prev = 0; current = criticalEdge->v2; do { rightPoly.push_back( current, boundaryRing[current].projected ); prev = current; current = boundaryRing[current].next; }while( current != criticalEdge->v1 ); rightPoly.push_back( current, boundaryRing[current].projected ); // if orientations of both polygons are the same then the critical edge crosses the bounding polygon interior if( leftPoly.orientation() == rightPoly.orientation() ) { printf( "info : unable to triangulate since critical edge(es) would cross the polygon interior - vertex is not removed\n" ); success = false; break; } } } }while( (++currentTrial < trialCount)&&(!success) ); if( !success ) { // we dont remove the vertex since we didnt managed to find a planar // projection of the neighbourhood which would not destroy the topology printf( "info : unable to find planar projection for vertex remove and retriangulation - vertex is not removed\n" ); //++g_iterations; return false; } boundaryPolygonOrientation = CGAL::orientation( Point_3( v->position ), Point_3( v->position + base1 ), Point_3( v->position + base2 ), Point_3( v->position + normal ) ); // execute the result ------------------------------------------------------------ // remove vertex v and the triangle ring around v removeVertex( v ); // compute squared distances // compute the squared distances of all point pairs std::vector<DistanceHelper> sqDistances; // sorted distances of each pair of points for( std::map<Vertex *, EdgeInfoHelper>::iterator it1 = boundaryRing.begin(); it1 != boundaryRing.end(); ++it1 ) for( std::map<Vertex *, EdgeInfoHelper>::iterator it2 = it1; it2 != boundaryRing.end(); ++it2 ) { Vertex *v1 = it1->first; Vertex *v2 = it2->first; if( v1 == v2 ) continue; // we dont want to add pairs, which would build a boundary edge, since those // already exist -> simply check for next or prev vertex in boundaryRing if( (boundaryRing[v1].next == v2)||(boundaryRing[v1].prev == v2) ) continue; sqDistances.push_back( DistanceHelper( it1->first, it2->first ) ); } // sort std::sort( sqDistances.begin(), sqDistances.end() ); // std::list<Polygon *> polygons; // polygons which have to be triangulated std::vector<Edge *> edges( boundaryEdges.begin(), boundaryEdges.end() ); // created edges // create polygon which is made by the boundary edges and put it on polygon list Polygon *boundaryPolygon = new Polygon(); first = boundaryRing.begin()->first; current = first; prev = 0; do { boundaryPolygon->push_back( current, boundaryRing[current].projected ); prev = current; current = boundaryRing[current].next; }while( current != first ); if( boundaryPolygon->orientation() != boundaryPolygonOrientation ) boundaryPolygon->flip(); polygons.push_back( boundaryPolygon ); // for each entry in the sqDistance list // find the polygon on the polygon list which contains h->v1 and h->v2 // check if edge is outside the polygon by checking the orientations of the left and right sides (build left and right polygons) // check if edge intersects with any other existing edge which dont have a point in h->v1 or h->v2 // if checks pass: // create edge -> assign it to the left and right polygons | add it to the list of edges // split the polygon by removing the polygon from polygon list and putting the left and right polygons on the list if it is not a triangle // // if the any polygon remains on the polygon list, throw an error that the triangulation has created a hole in the mesh //std::vector<Edge *> edges( edgeRing.begin(), edgeRing.end() ); // when the mother polygon is already a triangle, then we have sqDistances.size() == 0 // and we have to handle the polygon if( boundaryPolygon->isTriangle() ) { createTriangle( boundaryPolygon->vertices[0], boundaryPolygon->vertices[1], boundaryPolygon->vertices[2], edges ); polygons.clear(); delete boundaryPolygon; //++g_iterations; return true; } for( std::vector<DistanceHelper>::iterator it=sqDistances.begin(); it != sqDistances.end(); ++it ) { DistanceHelper *h = &(*it); Polygon *poly = 0; // polygon which contains both vertices of h std::list<Polygon *>::iterator pit; // find the polygon which contains both vertices of h for( pit = polygons.begin(); pit != polygons.end(); ++pit ) { Polygon *p = *pit; if( p->contains( h->v1 ) && p->contains( h->v2 ) ) { poly = p; break; } } // if no polygon could be found which contains both vertices of h, then // we can skip this one if( !poly ) continue; // test for intersection with all existing edges bool intersection = false; for( std::vector<Edge *>::iterator eit = edges.begin(); eit != edges.end(); ++eit) { Edge *e = (*eit); math::Vec3f intersectionPoint; // ---- test for intersection of the edges projected into 2d plane using cgal ---- // skip if the 2 lines share a common vertex if( e->contains(h->v1) || e->contains(h->v2) ) continue; CGAL::Segment_2<K> line_1( Point( boundaryRing[e->v1].projected.x, boundaryRing[e->v1].projected.y ), Point(boundaryRing[e->v2].projected.x, boundaryRing[e->v2].projected.y) ); CGAL::Segment_2<K> line_2( Point( boundaryRing[h->v1].projected.x, boundaryRing[h->v1].projected.y ), Point(boundaryRing[h->v2].projected.x, boundaryRing[h->v2].projected.y) ); if( CGAL::do_intersect( line_1, line_2 ) ) { intersection = true; break; } } // if there was an intersection, then we can skip this one // since a non-compatible edge would be introduced if( intersection ) continue; // no intersection, get the 2 polygons which would be created from dividing the mother polyon along the edge Polygon *left, *right; left = right = 0; poly->split( left, right, h->v1, h->v2 ); // if the 2 polygons have the same orientation, then we can be sure that // the edge goes through the interior of the polygon if( left->orientation() == right->orientation() ) { // remove the current polygon from the list of polygons polygons.erase( pit ); delete poly; // create the edge h->v1 -> h->v2 Edge *edge = createEdge( h->v1, h->v2 ); edges.push_back( edge ); // and add the left and righ polygon to the list if they are not triangles if( left->isTriangle() ) { // add triangle to the mesh createTriangle( left->vertices[0], left->vertices[1], left->vertices[2], edges ); // remove polygon helper structure delete left; }else polygons.push_back( left ); if( right->isTriangle() ) { // add triangle to the mesh createTriangle( right->vertices[0], right->vertices[1], right->vertices[2], edges ); // remove polygon helper structure delete right; }else polygons.push_back( right ); }else { delete left; delete right; } } if( !polygons.empty() ) printf( "error : hole created during retriangulation\n" ); for( std::list<Polygon *>::iterator pit = polygons.begin(); pit != polygons.end(); ++pit ) delete *pit; polygons.clear(); //++g_iterations; return true; }