/** * Test Case for the In Circle Test! double pa[3] = {1,0,0}; double pb[3] = {0,0,1}; double pc[3] = {0,1,0}; double pp[3] = {0.25,0.25,0.5}; double ppout1[3] = {-5,0.25,0.5}; double ppout2[3] = {5.0,0.25,0.5}; double ppout3[3] = {0.25,5.0,0.5}; bool isIn1 = IsInPlanarTriangle(pa,pb,pc,ppout1); bool isIn2 = IsInPlanarTriangle(pa,pb,pc,ppout2); bool isIn3 = IsInPlanarTriangle(pa,pb,pc,ppout3); bool isIn = IsInPlanarTriangle(pa,pb,pc,pp); */ bool IsInPlanarTriangle(double *pa, double *pb, double *pc, double *pp) { if ( orient2d(pa,pb,pp)<0&& orient2d(pb,pc,pp)<0 && orient2d(pc,pa,pp)<0) { return false; } return true; }
bool pointIntersectsTriangle(const P2 &p, const P2vec &tri) { int orient = isAnticlockwise(tri) ? +1 : -1; if (orient2d(tri[0], tri[1], p) * orient < 0) return false; if (orient2d(tri[1], tri[2], p) * orient < 0) return false; if (orient2d(tri[2], tri[0], p) * orient < 0) return false; return true; }
void DepthBuffer::drawTriangle(BinnedTriangle& tri,vec2i tilePos) { vec2i v0(tri.v[0].x,tri.v[0].y); vec2i v1(tri.v[1].x,tri.v[1].y); vec2i v2(tri.v[2].x,tri.v[2].y); float zz[3] = { tri.z[0],tri.z[1],tri.z[2] }; int32 minx = std::min(v0.x,std::min(v1.x,v2.x)); int32 miny = std::min(v0.y,std::min(v1.y,v2.y)); int32 maxx = std::max(v0.x,std::max(v1.x,v2.x)); int32 maxy = std::max(v0.y,std::max(v1.y,v2.y)); minx = std::max(minx,tilePos.x); miny = std::max(miny,tilePos.y); maxx = std::min(maxx,tilePos.x+tileSize_.x-1); maxy = std::min(maxy,tilePos.y+tileSize_.y-1); int32 a01 = v0.y - v1.y; int32 b01 = v1.x - v0.x; int32 a12 = v1.y - v2.y; int32 b12 = v2.x - v1.x; int32 a20 = v2.y - v0.y; int32 b20 = v0.x - v2.x; vec2i p(minx,miny); auto w0_row = orient2d(v1,v2,p); auto w1_row = orient2d(v2,v0,p); auto w2_row = orient2d(v0,v1,p); float* tilePixels = data_ + tilePos.x*tileSize_.y + (tilePos.y*tileSize_.x)*tileCount_.x; int32 idx2 = minx-tilePos.x + (miny - tilePos.y)*tileSize_.x; int32 spanx = maxx-minx; for(int32 endIdx2 = idx2+(tileSize_.x)*(maxy-miny);idx2<=endIdx2;idx2+=tileSize_.x){ auto w0 = w0_row; auto w1 = w1_row; auto w2 = w2_row; //float betaf = float(w1); //float gamaf = float(w2); //float depth = zz[0] + betaf*zz[1] + gamaf*zz[2]; //float depthInc = float(a20)*zz[1] + float(a01)*zz[2]; auto idx = idx2; for(int32 endIdx = idx+spanx;idx<=endIdx;++idx){ if((w0|w1|w2) >= 0){ float betaf = float(w1); float gamaf = float(w2); float depth = zz[0] + betaf*zz[1] + gamaf*zz[2]; auto d = tilePixels[idx]; d = depth<d?depth:d; tilePixels[idx] = d; } w0+=a12; w1+=a20; w2+=a01; //depth+=depthInc; } w0_row += b12; w1_row += b20; w2_row += b01; } }
/*! * The polylines must be different. * * \param globalverts global vertices vector * \param v1 the first polyline * \param v2 * \param p1 the second polyline * \param p2 * * \return 0 if they don't intersect <BR> * 1 if they do <BR> */ int SimplePolygon::doIntersect( DCTPVec2dvector &globalverts, int v1, int v2, int p1, int p2 ) const { // check if they share vertices if ( v1 == p1 || v1 == p2 || v2 == p1 || v2 == p2 ) return 0; double pa[ 2 ]; double pb[ 2 ]; double pc[ 2 ]; double pd[ 2 ]; const int vv1 = vertices[ v1 ]; const int vv2 = vertices[ v2 ]; const int vp1 = vertices[ p1 ]; const int vp2 = vertices[ p2 ]; pa[ 0 ] = globalverts[ vv1 ][0]; pa[ 1 ] = globalverts[ vv1 ][1]; pb[ 0 ] = globalverts[ vv2 ][0]; pb[ 1 ] = globalverts[ vv2 ][1]; pc[ 0 ] = globalverts[ vp1 ][0]; pc[ 1 ] = globalverts[ vp1 ][1]; pd[ 0 ] = globalverts[ vp2 ][0]; pd[ 1 ] = globalverts[ vp2 ][1]; const double r1 = orient2d(pa, pc, pd); const double r2 = orient2d(pb, pc, pd); if( ( r1 < 0.0 ) && ( r2 < 0.0 ) ) { return 0; } if( ( r1 > 0.0 ) && ( r2 > 0.0 ) ) { return 0; } const double r3 = orient2d(pc, pa, pb); const double r4 = orient2d(pd, pa, pb); if( ( r3 < 0.0 ) && ( r4 < 0.0 ) ) { return 0; } if( ( r3 > 0.0 ) && ( r4 > 0.0 ) ) { return 0; } return 1; // do intersect?? /* * r1 and r2 must have different signs ( <0, >0, =0 ) AND * r3 and r4 must also have different signs in suffice intersection of * the two lines. */ /* bool s1 = ( !(( r1 < 0 && r2 < 0 ) || ( r1 > 0 && r2 > 0 )) ); bool s2 = ( !(( r3 < 0 && r4 < 0 ) || ( r3 > 0 && r4 > 0 )) ); if ( s1 && s2 ) return 1; else return 0;*/ }
int triangleLineOrientation(const P2 &p1, const P2 &p2, const P2vec &tri) { double lo, hi, tmp; lo = hi = orient2d(p1, p2, tri[0]); tmp = orient2d(p1, p2, tri[1]); lo = std::min(lo, tmp); hi = std::max(hi, tmp); tmp = orient2d(p1, p2, tri[2]); lo = std::min(lo, tmp); hi = std::max(hi, tmp); if (hi < 0.0) return -1; if (lo > 0.0) return +1; return 0; }
void tricircumcenter3d(double*a, double*b, double*c, double*circumcenter,double*cond) { double xba, yba, zba, xca, yca, zca; double balength, calength; double xcrossbc, ycrossbc, zcrossbc; double denominator; double xcirca, ycirca, zcirca; #ifdef EXACT double ta[2],tb[2],tc[2]; #endif /* Use coordinates relative to point `a' of the triangle. */ xba = b[0] - a[0]; yba = b[1] - a[1]; zba = b[2] - a[2]; xca = c[0] - a[0]; yca = c[1] - a[1]; zca = c[2] - a[2]; /* Squares of lengths of the edges incident to `a'. */ balength = xba * xba + yba * yba + zba * zba; calength = xca * xca + yca * yca + zca * zca; /* Cross product of these edges. */ #ifdef EXACT /* Use orient2d() from http://www.cs.cmu.edu/~quake/robust.html */ /* to ensure a correctly signed (and reasonably accurate) result, */ /* avoiding any possibility of division by zero. */ ta[0]=b[1];ta[1]=b[2];tb[0]=c[1];tb[1]=c[2];tc[0]=a[1];tc[1]=a[2]; xcrossbc = orient2d(ta,tb,tc); ta[0]=b[2];ta[1]=b[0];tb[0]=c[2];tb[1]=c[0];tc[0]=a[2];tc[1]=a[0]; ycrossbc = orient2d(ta,tb,tc); ta[0]=b[0];ta[1]=b[1];tb[0]=c[0];tb[1]=c[1];tc[0]=a[0];tc[1]=a[1]; zcrossbc = orient2d(ta,tb,tc); #else /* Take your chances with floating-point roundoff. */ xcrossbc = yba * zca - yca * zba; ycrossbc = zba * xca - zca * xba; zcrossbc = xba * yca - xca * yba; #endif /* Calculate the denominator of the formulae. */ denominator = 0.5 / (xcrossbc * xcrossbc + ycrossbc * ycrossbc + zcrossbc * zcrossbc); /* Calculate offset (from `a') of circumcenter. */ xcirca = ((balength * yca - calength * yba) * zcrossbc - (balength * zca - calength * zba) * ycrossbc) * denominator; ycirca = ((balength * zca - calength * zba) * xcrossbc - (balength * xca - calength * xba) * zcrossbc) * denominator; zcirca = ((balength * xca - calength * xba) * ycrossbc - (balength * yca - calength * yba) * xcrossbc) * denominator; circumcenter[0] = xcirca; circumcenter[1] = ycirca; circumcenter[2] = zcirca; }
/** * \brief Determine whether p is internal to the anticlockwise * angle abc, where b is the apex of the angle. * * @param[in] a * @param[in] b * @param[in] c * @param[in] p * * @return true, if p is contained in the anticlockwise angle from * b->a to b->c. Reflex angles contain p if p lies * on b->a or on b->c. Acute angles do not contain p * if p lies on b->a or on b->c. This is so that * internalToAngle(a,b,c,p) = !internalToAngle(c,b,a,p) */ inline bool internalToAngle(const P2 &a, const P2 &b, const P2 &c, const P2 &p) { bool reflex = (a < c) ? orient2d(b, a, c) <= 0.0 : orient2d(b, c, a) > 0.0; double d1 = orient2d(b, a, p); double d2 = orient2d(b, c, p); if (reflex) { return d1 >= 0.0 || d2 <= 0.0; } else { return d1 > 0.0 && d2 < 0.0; } }
/*! * \param globalverts global vertices vector * \param v1 first vertex * \param v2 second vertex * \param v3 third vertex * \param p the point * \return 0 if not inside <BR> * 1 if inside <BR> */ int SimplePolygon::isInsideCircumCircle( DCTPVec2dvector &globalverts, int v1, int v2, int v3, int p ) const { double pa[2], pb[2], pc[2], pd[2]; pa [ 0 ] = globalverts[ vertices[ v1 ] ][0]; pa [ 1 ] = globalverts[ vertices[ v1 ] ][1]; pb [ 0 ] = globalverts[ vertices[ v2 ] ][0]; pb [ 1 ] = globalverts[ vertices[ v2 ] ][1]; pc [ 0 ] = globalverts[ vertices[ v3 ] ][0]; pc [ 1 ] = globalverts[ vertices[ v3 ] ][1]; pd [ 0 ] = globalverts[ vertices[ p ] ][0]; pd [ 1 ] = globalverts[ vertices[ p ] ][1]; // check for order of (pa, pb, pc) they must be in counterclockwise order double order = orient2d( pa, pb, pc ); double dres; if ( order < 0.0 ) // clockwise order -> change order dres = incircle( pa, pc, pb, pd ); else dres = incircle( pa, pb, pc, pd ); //std::cerr << pa[ 0 ] << "," << pa[ 1 ] << " "; //std::cerr << pb[ 0 ] << "," << pb[ 1 ] << " "; //std::cerr << pc[ 0 ] << "," << pc[ 1 ] << " "; //std::cerr << pd[ 0 ] << "," << pd[ 1 ] << std::endl; //std::cerr << "Inside Circumcircle: " << dres << std::endl; // >0 if inside if ( dres <= 0 ) return 0; else return 1; }
bool SimplePolygon::isReversed( DCTPVec2dvector &globalverts ) { unsigned int ui_vertex; unsigned int ui_upperleft; const unsigned int cui_vertex_cnt = vertices.size( ); double ad_p[ 2 ]; double ad_v[ 2 ]; double ad_n[ 2 ]; ui_upperleft = 0; for( ui_vertex = 1; ui_vertex < cui_vertex_cnt; ++ui_vertex ) { if( globalverts[ vertices[ ui_vertex ] ][1] < globalverts[ vertices[ ui_upperleft ] ][1] ) { ui_upperleft = ui_vertex; } else if( ( globalverts[ vertices[ ui_vertex ] ][1] == globalverts[ vertices[ ui_upperleft ] ][1] ) && ( globalverts[ vertices[ ui_vertex ] ][0] < globalverts[ vertices[ ui_upperleft ] ][0] ) ) { ui_upperleft = ui_vertex; } } ad_p[ 0 ] = globalverts[ vertices[ ( ui_upperleft + cui_vertex_cnt - 1 ) % cui_vertex_cnt ] ][0]; ad_p[ 1 ] = globalverts[ vertices[ ( ui_upperleft + cui_vertex_cnt - 1 ) % cui_vertex_cnt ] ][1]; ad_v[ 0 ] = globalverts[ vertices[ ui_upperleft ] ][0]; ad_v[ 1 ] = globalverts[ vertices[ ui_upperleft ] ][1]; ad_n[ 0 ] = globalverts[ vertices[ ( ui_upperleft + 1 ) % cui_vertex_cnt ] ][0]; ad_n[ 1 ] = globalverts[ vertices[ ( ui_upperleft + 1 ) % cui_vertex_cnt ] ][1]; return ( orient2d( ad_p, ad_v, ad_n ) <= 0.0 ); }
Exact_adaptive_kernel::Oriented_side Exact_adaptive_kernel::oriented_side (Point2 const& pa, Point2 const& pb, Point2 const& test) { double r = orient2d(pa.coord(), pb.coord(), test.coord()); if (r > 0.0) return ON_POSITIVE_SIDE; else if (r < 0.0) return ON_NEGATIVE_SIDE; else return ON_ORIENTED_BOUNDARY; }
bool lineIntersectsTriangle(const P2 &p1, const P2 &p2, const P2vec &tri) { double s[3]; // does tri lie on one side or the other of p1-p2? s[0] = orient2d(p1, p2, tri[0]); s[1] = orient2d(p1, p2, tri[1]); s[2] = orient2d(p1, p2, tri[2]); if (*std::max_element(s, s+3) < 0) return false; if (*std::min_element(s, s+3) > 0) return false; // does line lie entirely to the right of a triangle edge? int orient = isAnticlockwise(tri) ? +1 : -1; if (orient2d(tri[0], tri[1], p1) * orient < 0 && orient2d(tri[0], tri[1], p2) * orient < 0) return false; if (orient2d(tri[1], tri[2], p1) * orient < 0 && orient2d(tri[1], tri[2], p2) * orient < 0) return false; if (orient2d(tri[2], tri[0], p1) * orient < 0 && orient2d(tri[2], tri[0], p2) * orient < 0) return false; return true; }
bool lineSegmentIntersection_simple(const P2 &l1v1, const P2 &l1v2, const P2 &l2v1, const P2 &l2v2) { geom::aabb<2> l1_aabb, l2_aabb; l1_aabb.fit(l1v1, l1v2); l2_aabb.fit(l2v1, l2v2); if (l1_aabb.maxAxisSeparation(l2_aabb) > 0.0) { return false; } double l1v1_side = orient2d(l2v1, l2v2, l1v1); double l1v2_side = orient2d(l2v1, l2v2, l1v2); double l2v1_side = orient2d(l1v1, l1v2, l2v1); double l2v2_side = orient2d(l1v1, l1v2, l2v2); if (l1v1_side * l1v2_side > 0.0 || l2v1_side * l2v2_side > 0.0) { return false; } return true; }
// returns true if the ray cast from p along positive z axis hits triangle in // exactly one spot, with edge cases handled appropriately static bool tri_zcast(const Vec3d& p, const Vec3d& q, const Vec3d& r, const Vec3d& s) { // robustly find orientation of qrs in 2D xy projection double qrs=orient2d(q.v, r.v, s.v); if(qrs>0) return tri_zcast_inner(p, qrs, q, r, s); else if(qrs<0) return tri_zcast_inner(p, -qrs, q, s, r); // flip triangle to reorient else return false; // triangle is degenerate in 2D projection - ignore }
Oriented_side Exact_adaptive_kernel::oriented_side( Point2 const& pa, Point2 const& pb, Point2 const& test ) { double r = orient2d( pa.data(), pb.data(), test.data() ); if ( r > 0.0 ) { return ON_POSITIVE_SIDE; } if ( r < 0.0 ) { return ON_NEGATIVE_SIDE; } return ON_ORIENTED_BOUNDARY; }
void triorthocenter(double a[], double b[], double c[], double orthocenter[], double* cnum) { double xba, yba, wba, xca, yca, wca; double balength, calength; double denominator; double xcirca, ycirca; /* Use coordinates relative to point `a' of the triangle. */ xba = b[0] - a[0]; yba = b[1] - a[1]; wba = b[2] - a[2]; xca = c[0] - a[0]; yca = c[1] - a[1]; wca = b[2] - a[2]; /* Squares of lengths of the edges incident to `a'. */ balength = xba * xba + yba * yba - wba; calength = xca * xca + yca * yca - wca; /* Calculate the denominator of the formulae. */ #ifdef EXACT /* Use orient2d() from http://www.cs.cmu.edu/~quake/robust.html */ /* to ensure a correctly signed (and reasonably accurate) result, */ /* avoiding any possibility of division by zero. */ *cnum = orient2d(b, c, a); denominator = 0.5 / (*cnum); #else /* Take your chances with floating-point roundoff. */ denominator = 0.5 / (xba * yca - yba * xca); *cnum = 1.0; // a value !=0 #endif /* Calculate offset (from `a') of circumcenter. */ xcirca = (yca * balength - yba * calength) * denominator; ycirca = (xba * calength - xca * balength) * denominator; orthocenter[0] = xcirca; orthocenter[1] = ycirca; }
bool SimplePolygon::isConvex( DCTPVec2dvector &globalverts ) { unsigned int ui_next; const unsigned int cui_vertex_cnt = vertices.size( ); double ad_p[ 2 ]; double ad_v[ 2 ]; double ad_n[ 2 ]; ad_p[ 0 ] = globalverts[ vertices[ cui_vertex_cnt - 2 ] ][0]; ad_p[ 1 ] = globalverts[ vertices[ cui_vertex_cnt - 2 ] ][1]; ad_v[ 0 ] = globalverts[ vertices[ cui_vertex_cnt - 1 ] ][0]; ad_v[ 1 ] = globalverts[ vertices[ cui_vertex_cnt - 1 ] ][1]; for( ui_next = 0; ui_next < cui_vertex_cnt; ++ui_next ) { // std::cerr <<"ui_next:" << ui_next << std::endl; ad_n[ 0 ] = globalverts[ vertices[ ui_next ] ][0]; ad_n[ 1 ] = globalverts[ vertices[ ui_next ] ][1]; // previous, current, and next vertices must be in // counterclockwise order for the polygon to be convex // (because our tessellator always gives CCW polygons) if( orient2d( ad_p, ad_v, ad_n ) < 0.0 ) { // std::cerr << ad_p[ 0 ] << " " << ad_p[ 1 ] << std::endl; // std::cerr << ad_v[ 0 ] << " " << ad_v[ 1 ] << std::endl; // std::cerr << ad_n[ 0 ] << " " << ad_n[ 1 ] << std::endl << std::endl; // not convex return false; } ad_p[ 0 ] = ad_v[ 0 ]; ad_p[ 1 ] = ad_v[ 1 ]; ad_v[ 0 ] = ad_n[ 0 ]; ad_v[ 1 ] = ad_n[ 1 ]; } // std::cerr << "convex" << std::endl; return true; }
double Exact_adaptive_kernel::signed_area( Point2 const& pa, Point2 const& pb, Point2 const& pc ) { return 0.5 * orient2d( pa.data(), pb.data(), pc.data() ); }
inline double LeftTurn(const double a[2], const double b[2], const double c[2]){ extern double orient2d(double*, double*, double*); return orient2d((double*)a, (double*)b, (double*)c); }
bool n3d_prepare( n3d_rasterizer_t::triangle_t& tri, const n3d_vertex_t& v0, const n3d_vertex_t& v1, const n3d_vertex_t& v2, const uint32_t flags) { const vec4f_t& vp0 = v0.p_; const vec4f_t& vp1 = v1.p_; const vec4f_t& vp2 = v2.p_; // the signed triangle area const float t_area = (vp1.x - vp0.x) * (vp2.y - vp0.y) - (vp2.x - vp0.x) * (vp1.y - vp0.y); // check for back face if (t_area <= 0.f) return false; // reciprocal of area for normalization const float rt_area = 1.f / t_area; // find normalized barycentric coordinates tri.v_ [e_attr_b0] = orient2d(vp1, vp2) * rt_area; tri.sx_[e_attr_b0] = (vp1.y - vp2.y) * rt_area; tri.sy_[e_attr_b0] = (vp2.x - vp1.x) * rt_area; tri.v_ [e_attr_b1] = orient2d(vp2, vp0) * rt_area; tri.sx_[e_attr_b1] = (vp2.y - vp0.y) * rt_area; tri.sy_[e_attr_b1] = (vp0.x - vp2.x) * rt_area; tri.v_ [e_attr_b2] = orient2d(vp0, vp1) * rt_area; tri.sx_[e_attr_b2] = (vp0.y - vp1.y) * rt_area; tri.sy_[e_attr_b2] = (vp1.x - vp0.x) * rt_area; // calculate 1 / w for vertices const float v0w = 1.f / v0.p_.w; const float v1w = 1.f / v1.p_.w; const float v2w = 1.f / v2.p_.w; //(todo) update all of this to use SSE // find triangle bounds tri.min_.x = min3(vp0.x, vp1.x, vp2.x); tri.min_.y = min3(vp0.y, vp1.y, vp2.y); tri.max_.x = max3(vp0.x, vp1.x, vp2.x) + 1.f; tri.max_.y = max3(vp0.y, vp1.y, vp2.y) + 1.f; // barycenteric interpolate 1 param #define BLERPW(B) ((tri.B[0] * v0w) + \ (tri.B[1] * v1w) + \ (tri.B[2] * v2w)) // barycentric interpolate 3 param #define BLERPA(B, A) ((tri.B[0] * v0.attr_[A] * v0w) + \ (tri.B[1] * v1.attr_[A] * v1w) + \ (tri.B[2] * v2.attr_[A] * v2w)) // interplate 1 / w tri.v_ [e_attr_w] = BLERPW(v_); tri.sx_[e_attr_w] = BLERPW(sx_); tri.sy_[e_attr_w] = BLERPW(sy_); #if 0 for (uint32_t i = 0; i < v0.attr_.size(); ++i) { tri.v_ [e_attr_custom + i] = BLERPA(v_, i); tri.sx_[e_attr_custom + i] = BLERPA(sx_, i); tri.sy_[e_attr_custom + i] = BLERPA(sy_, i); } #endif #undef BLERPW #undef BLERPA return true; }
// helper function for tri_zcast below... // Here we are given a robust 2d orientation of qrs in xy projection, which // must be positive. static bool tri_zcast_inner(const Vec3d& p, double qrs, const Vec3d& q, const Vec3d& r, const Vec3d& s) { assert(qrs>0); // first check if point is above or below triangle in z double pqrs=orient3d(p.v, q.v, r.v, s.v); if(pqrs>=0) return false; // point is on or above triangle - no intersection // then check if point lies outside triangle in 2D xy projection double pqr=orient2d(p.v, q.v, r.v); if(pqr<0) return false; double prs=orient2d(p.v, r.v, s.v); if(prs<0) return false; double psq=orient2d(p.v, s.v, q.v); if(psq<0) return false; // note: the following tests are somewhat redundant, but it's a pretty // tiny optimization to eliminate the redundancy compared to the loss in // clarity. // check if point is strictly inside the triangle in xy if(pqr>0 && prs>0 && psq>0) return true; // check if point is strictly on edge qr if(pqr==0 && prs>0 && psq>0){ if(q[1]<r[1]) return false; if(q[1]>r[1]) return true; if(q[0]<r[0]) return true; assert(q[0]>r[0]); // q!=r because triangle is not degenerate return false; } // check if point is strictly on edge rs if(prs==0 && pqr>0 && psq>0){ if(r[1]<s[1]) return false; if(r[1]>s[1]) return true; if(r[0]<s[0]) return true; assert(r[0]>s[0]); // r!=s because triangle is not degenerate return false; } // check if point is strictly on edge sq if(psq==0 && pqr>0 && prs>0){ if(s[1]<q[1]) return false; if(s[1]>q[1]) return true; if(s[0]<q[0]) return true; assert(s[0]>q[0]); // r!=s because triangle is not degenerate return false; } // check if point is on vertex q if(p[0]==q[0] && p[1]==q[1]){ return q[1]>=r[1] && q[1]<s[1]; } // check if point is on vertex r if(p[0]==r[0] && p[1]==r[1]){ return r[1]>=s[1] && r[1]<q[1]; } // check if point is on vertex s if(p[0]==s[0] && p[1]==s[1]){ return s[1]>=q[1] && s[1]<r[1]; } assert(false); // we should have covered all cases at this point return false; // just to quiet compiler warnings }
bool isAnticlockwise(const P2vec &tri) { return orient2d(tri[0], tri[1], tri[2]) > 0.0; }
/*Type of Cut Strategy is defined as: * (useAltCut, useVertical) = (true, true) => Alternating Cuts * (useAltCut, useVertical) = (true, false) => Horizontal Cuts* * (useAltCut, useVertical) = (false, true) => Vertical Cuts * */ void delaunay(Vertex **ppVertices, long numVertices, Edge **ppLe, Edge **ppRe, bool useAltCuts, bool useVertical) { NOT_NULL(ppVertices); if(numVertices == 2) { Edge *pA = Edge::makeEdge(); if(*ppVertices[0] > *ppVertices[1]) { ELEM_SWAP(ppVertices[0], ppVertices[1]); } pA->setOrg(ppVertices[0]); pA->setDest(ppVertices[1]); *ppLe = pA; *ppRe = pA->Sym(); } else if(numVertices == 3) { Edge *pA = Edge::makeEdge(), *pB = Edge::makeEdge(), *pC = 0; if(*ppVertices[0] > *ppVertices[1]) { ELEM_SWAP(ppVertices[0], ppVertices[1]); } if(*ppVertices[1] > *ppVertices[2]) { ELEM_SWAP(ppVertices[1], ppVertices[2]); } Edge::splice(pA->Sym(), pB); pA->setOrg(ppVertices[0]); pA->setDest(ppVertices[1]); pB->setOrg(ppVertices[1]); pB->setDest(ppVertices[2]); REAL ccw = orient2d(ppVertices[0]->Pos(), ppVertices[1]->Pos(), ppVertices[2]->Pos()); if(ccw > 0) { pC = Edge::connect(pB, pA); *ppLe = pA; *ppRe = pB->Sym(); } else if(ccw < 0) { pC = Edge::connect(pB, pA); *ppLe = pC->Sym(); *ppRe = pC; } else { *ppLe = pA; *ppRe = pB->Sym(); } } else { long middle = std::floor(numVertices/2); Edge *pLdo = 0, *pLdi = 0, *pRdi = 0, *pRdo = 0; //These vertices are used for merging a horizontal cut Vertex *pBotMax = 0, //highest vertex of bottom half *pTopMin = 0, //lowest vertex of top half *pMin = 0, //Lexicographically max vertex *pMax = 0; //Lexicographically min vertex //Find median partition by X or Y, depending on whether we're using a vertical cut std::nth_element(ppVertices, ppVertices+middle, ppVertices+numVertices, useVertical ? Vertex::lessX : Vertex::lessY); //Recursive calls delaunay(ppVertices, middle, &pLdo, &pLdi, useAltCuts, useAltCuts ? !useVertical : useVertical); delaunay(ppVertices+middle, numVertices - middle, &pRdi, &pRdo, useAltCuts, useAltCuts ? !useVertical : useVertical); //Modify ldi be highest in bottom half and rdi to be lowest in top half if(!useVertical) { pBotMax = ppVertices[0]; pTopMin = ppVertices[middle]; pMin = (*ppVertices[0] < *ppVertices[middle]) ? ppVertices[0] : ppVertices[middle]; pMax = (*ppVertices[0] > *ppVertices[middle]) ? ppVertices[0] : ppVertices[middle];; for(long i=1; i < middle; i++) { if(*ppVertices[i] < *pMin) { pMin = ppVertices[i]; } else if(*ppVertices[i] > *pMax) { pMax = ppVertices[i]; } if(ppVertices[i]->gtY(*pBotMax)) { pBotMax = ppVertices[i]; } } for(long i=middle+1; i < numVertices; i++) { if(*ppVertices[i] < *pMin) { pMin = ppVertices[i]; } else if(*ppVertices[i] > *pMax) { pMax = ppVertices[i]; } if(ppVertices[i]->ltY(*pTopMin)) { pTopMin = ppVertices[i]; } } pLdi = pBotMax->getCWHullEdge(); pRdi = pTopMin->getCCWHullEdge(); } //Compute the lower common tangent of two sets of vertices while (1) { if(pLdi->leftOf(pRdi->Org())) { pLdi = pLdi->Lnext(); } else if(pRdi->rightOf(pLdi->Org())) { pRdi = pRdi->Rprev(); } else { break; } } // Create a first cross edge pBasel from pRdi.origin to pLdi.origin Edge *pBasel = Edge::connect(pRdi->Sym(), pLdi); if(pLdi->Org() == pLdo->Org()) { pLdo = pBasel->Sym(); } if(pRdi->Org() == pRdo->Org()) { pRdo = pBasel; } //Merging two halves while(1) { //Locate the first Left point pLcand to be encou Edge *pLcand = pBasel->Sym()->Onext(); bool leftFinished = !pLcand->valid(pBasel); if(!leftFinished) { while(incircle(pBasel->Dest()->Pos(), pBasel->Org()->Pos(), pLcand->Dest()->Pos(), pLcand->Onext()->Dest()->Pos()) > 0) { Edge *pT = pLcand->Onext(); Edge::deleteEdge(pLcand); pLcand = pT; } } //Symmetrically locate the first R point to be hit Edge *pRcand = pBasel->Oprev(); bool rightFinished = !pRcand->valid(pBasel); if(!rightFinished) { while(incircle(pBasel->Dest()->Pos(), pBasel->Org()->Pos(), pRcand->Dest()->Pos(), pRcand->Oprev()->Dest()->Pos()) > 0) { Edge *pT = pRcand->Oprev(); Edge::deleteEdge(pRcand); pRcand = pT; } } //both are invalid, pBasel is upper common tangent if(leftFinished && rightFinished) { break; } //the next cross edge is to be connected to either pLcand.dest or pRcand.dest if(leftFinished || (!rightFinished && incircle(pLcand->Dest()->Pos(), pLcand->Org()->Pos(), pRcand->Org()->Pos(), pRcand->Dest()->Pos()) > 0)) { pBasel = Edge::connect(pRcand, pBasel->Sym()); } else { pBasel = Edge::connect(pBasel->Sym(), pLcand->Sym()); } } //Modify pLdo and pRdo if we merging a horizontal cut if(!useVertical) { pLdo = pMin->getCCWHullEdge(); pRdo = pMax->getCWHullEdge(); } *ppLe = pLdo; *ppRe = pRdo; } return; }
int SimplePolygon::intersectPolygon( DCTPVec2dvector &globalverts, simplepolygonvector &polylist ) { int oldNum = vertices.size(); int i1, i2; Vec2d min, max; Vec2d p3, p4; unsigned char test, ptest; // std::cerr << "Removing intersections... " << oldNum << std::endl; for( i2 = 2; i2 < oldNum; ++i2 ) { const Vec2d &p1 = globalverts[ vertices[ i2 ] ]; const Vec2d &p2 = globalverts[ vertices[ ( i2 + 1 ) % oldNum ] ]; min = max = p1; if( min[0] > p2[0] ) min[0] = p2[0]; else if( max[0] < p2[0] ) max[0] = p2[0]; if( min[1] > p2[1] ) min[1] = p2[1]; else if( max[1] < p2[1] ) max[1] = p2[1]; const unsigned int start = ( i2 == oldNum - 1 ) ? 1 : 0; p4 = globalverts[ vertices[ start ] ]; test = 0; if( p4[0] - max[0] > DCTP_EPS ) test |= 0x01; if( min[0] - p4[0] > DCTP_EPS ) test |= 0x02; if( p4[1] - max[1] > DCTP_EPS ) test |= 0x04; if( min[1] - p4[1] > DCTP_EPS ) test |= 0x08; for( i1 = start; i1 < i2 - 1; ++i1 ) { p3 = p4; p4 = globalverts[ vertices[ i1 + 1 ] ]; ptest = test; test = 0; if( p4[0] - max[0] > DCTP_EPS ) test |= 0x01; if( min[0] - p4[0] > DCTP_EPS ) test |= 0x02; if( p4[1] - max[1] > DCTP_EPS ) test |= 0x04; if( min[1] - p4[1] > DCTP_EPS ) test |= 0x08; if( ( test & ptest ) == 0 ) { // std::cerr << i1 << "," << i1 + 1 << " overlaps " << i2 << "," << i2 + 1 << std::endl; // the bounding boxes overlap int iip = -1; bool intersect = false; double d1[ 2 ] = { p1[0], p1[1] }; double d2[ 2 ] = { p2[0], p2[1] }; double d3[ 2 ] = { p3[0], p3[1] }; double d4[ 2 ] = { p4[0], p4[1] }; if( ( orient2d( d1, d2, d3 ) == 0.0 ) && ( orient2d( d1, d2, d4 ) == 0.0 ) ) { // the lines are colinear => ... p1 p4 ... ; p2 ... p3 intersect = true; } else { if( doIntersect( globalverts, i1, i1 + 1, i2, ( i2 + 1 ) % oldNum ) ) { // the lines intersect => ... p1 ip p4 ... ; ip p2 ... p3 Vec2d v1 = p2 - p1; Vec2d v2 = p4 - p3; Vec2d pp = p3 - p1; double a = pp[0] * v2[1] - pp[1] * v2[0]; double b = v1[0] * v2[1] - v1[1] * v2[0]; Vec2d ip = p1 + v1 * ( a / b ); if( DCTPVecIsEqual( ip , p1 ) ) { iip = vertices[ i1 ]; } else if( DCTPVecIsEqual( ip , p2 ) ) { iip = vertices[ i1 + 1 ]; } else if( DCTPVecIsEqual( ip , p3 ) ) { iip = vertices[ i2 ]; } else if( DCTPVecIsEqual( ip , p4 ) ) { iip = vertices[ ( i2 + 1 ) % oldNum ]; } else { iip = globalverts.size(); globalverts.resize( iip + 1 ); globalverts[ iip ] = ip; } // std::cerr << p1[0] << "," << p1[1] << " - " << p2[0] << "," << p2[1] << std::endl; // std::cerr << p3[0] << "," << p3[1] << " - " << p4[0] << "," << p4[1] << std::endl; // std::cerr << globalverts[ iip ][0] << "," << globalverts[ iip ][1] << " - " << std::endl; intersect = true; } } if( intersect ) { int i; int newNum; DCTPivector newPoints( oldNum ); SimplePolygon poly; // std::cerr << i1 << "," << i1 + 1 << " intersects " << i2 << "," << i2 + 1 << std::endl; // copy points 0 ... i1 for( i = 0; i <= i1; ++i ) { newPoints[ i ] = vertices[ i ]; } newNum = i; // copy iip's if( iip >= 0 ) { if( ( iip != vertices[ i1 ] ) && ( iip != vertices[ ( i2 + 1 ) % oldNum ] ) ) { newPoints[ newNum ] = iip; ++newNum; } if( ( iip != vertices[ i2 ] ) && ( iip != vertices[ i1 + 1 ] ) ) { poly.vertices.resize( i2 + 1 - i1 ); poly.vertices[ i2 - i1 ] = iip; } else { poly.vertices.resize( i2 - i1 ); } } else { poly.vertices.resize( i2 - i1 ); } // copy i1+1 ... i2 for( i = 0; i < i2 - i1; ++i ) { poly.vertices[ i ] = vertices[ i1 + i + 1 ]; } // copy i2+1 ... n for( i = i2 + 1; i < oldNum; ++i ) { newPoints[ newNum ] = vertices[ i ]; ++newNum; } // copy new points back to polygon vertices.resize( newNum ); for( i2 = 0; i2 < newNum; ++i2 ) { vertices[ i2 ] = newPoints[ i2 ]; } // std::cerr << "split in " << newNum << "," << poly.vertices.size() << std::endl; // triangulate the new polygon while( poly.intersectPolygon( globalverts, polylist ) ) { } if( poly.isReversed( globalverts ) ) { // std::cerr << "Ignoring reversed polygon." << std::endl; } else { // Ok, we have a valid polygon, so triangulate it. poly.triangulate( globalverts, polylist ); } // check if there are other intersections return 1; } } } } // polygon had no intersections so we are finished return 0; }
/*! * Note that this has complexity O(n). * * \param globalverts the global vertices vector * \return zero on success, and a negative integer if some error occured. */ int SimplePolygon::removeLinearPoints( DCTPVec2dvector &globalverts, const Vec2d min, const Vec2d max ) { int oldNum = vertices.size( ); int newNum = 0; DCTPivector newPoints( oldNum ); // waste some memory to have linear time int i; int last = oldNum - 1; // std::cerr << "Removing linear points... " << oldNum << std::endl; // insert nonlienaer points in new array for( i = 0; i < oldNum; ++i ) { Vec2d p = globalverts[ vertices[ i ] ]; // check for double vertices if( DCTPVecIsNotEqual( p , globalverts[ vertices[ last ] ] ) ) { Vec2d pp = globalverts[ vertices[ last ] ]; Vec2d pn = globalverts[ vertices[ ( i + 1 ) % oldNum ] ]; if( ( ( p[0] - min[0] < DCTP_EPS ) && ( pn[0] - min[0] < DCTP_EPS ) ) || ( ( p[1] - min[1] < DCTP_EPS ) && ( pn[1] - min[1] < DCTP_EPS ) ) || ( ( max[0] - p[0] < DCTP_EPS ) && ( max[0] - pn[0] < DCTP_EPS ) ) || ( ( max[1] - p[1] < DCTP_EPS ) && ( max[1] - pn[1] < DCTP_EPS ) ) ) { newPoints[ newNum ] = vertices[ i ]; ++newNum; last = i; } else { double d1[ 2 ], d2[ 2 ], d3[ 2 ]; d1[ 0 ] = pp[0]; d1[ 1 ] = pp[1]; d2[ 0 ] = p[0]; d2[ 1 ] = p[1]; d3[ 0 ] = pn[0]; d3[ 1 ] = pn[1]; if( orient2d( d1, d2, d3 ) != 0 ) { newPoints[ newNum ] = vertices[ i ]; ++newNum; last = i; } /* else if( ( pp[1] != pn[1] ) && ( pp[0] != pn[0] ) ) { std::cerr << "removing point " <<std::endl; std::cerr << pp[0] << "," << pp[1] << std::endl; std::cerr << "(" << p[0] << "," << p[1] << ")" << std::endl; std::cerr << pn[0] << "," << pn[1] << std::endl; char x[ 256 ]; gets( x ); }*/ } } } // std::cerr << newNum << " points left." << std::endl; // copy new points if( newNum != oldNum ) { vertices.resize( newNum ); for( i = 0; i < newNum; ++i ) { vertices[ i ] = newPoints[ i ]; } return 1; } return 0; }
/*! * Note that the resulting triangulation will not necessarily be complex, * since it's constrained by the polygon's edges. * * Besides triangulating the polygon this method also does: * - insertion of the new polygons (triangles) at the end of * the polygon list. * - setting up marking information for the new polygons. * * \param polylist the global list of polygons * \param selfindex the index of this polygon in the global list * \return zero on success, and a negative integer if some error occured. */ int SimplePolygon::triangulate( DCTPVec2dvector &globalverts, simplepolygonvector &polylist) { #ifdef OSG_TRIANGULATE_CONVEX if( ( !is_marked ) && ( m_bConvex ) ) { // std::cerr <<"triangulating convex: " <<vertices.size() << std::endl; switch( vertices.size( ) ) { case 0: case 1: case 2: return 0; case 3: { polylist.push_back( *this ); } return 0; } unsigned int ui_prev; unsigned int ui_mid; unsigned int ui_next; const unsigned int cui_vertex_cnt = vertices.size( ); SimplePolygon cl_poly; ui_mid = 0; for( ui_prev = 1; ui_prev < cui_vertex_cnt; ++ui_prev ) { if( globalverts[ vertices[ ui_prev ] ][1] < globalverts[ vertices[ ui_mid ] ][1] ) { ui_mid = ui_prev; } else if( ( globalverts[ vertices[ ui_prev ] ][1] == globalverts[ vertices[ ui_mid ] ][1] ) && ( globalverts[ vertices[ ui_prev ] ][0] < globalverts[ vertices[ ui_mid ] ][0] ) ) { ui_mid = ui_prev; } } ui_prev = ( ui_mid + cui_vertex_cnt - 1 ) % cui_vertex_cnt; ui_next = ( ui_mid + 1 ) % cui_vertex_cnt; cl_poly.vertices.resize( 3 ); cl_poly.is_marked = is_marked; cl_poly.vertices[ 0 ] = vertices[ ui_mid ]; cl_poly.vertices[ 1 ] = vertices[ ui_next ]; cl_poly.vertices[ 2 ] = vertices[ ui_prev ]; ui_prev = ( ui_prev + cui_vertex_cnt - 1 ) % cui_vertex_cnt; ui_next = ( ui_next + 1 ) % cui_vertex_cnt; while( cl_poly.vertices[ 1 ] != cl_poly.vertices[ 2 ] ) { polylist.push_back( cl_poly ); if( globalverts[ vertices[ ui_prev ] ][1] < globalverts[ vertices[ ui_next ] ][1] ) { cl_poly.vertices[ 0 ] = cl_poly.vertices[ 2 ]; cl_poly.vertices[ 2 ] = vertices[ ui_prev ]; ui_prev = ( ui_prev + cui_vertex_cnt - 1 ) % cui_vertex_cnt; } else if( ( globalverts[ vertices[ ui_prev ] ][1] == globalverts[ vertices[ ui_next ] ][1] ) && ( globalverts[ vertices[ ui_prev ] ][0] < globalverts[ vertices[ ui_next ] ][0] ) ) { cl_poly.vertices[ 0 ] = cl_poly.vertices[ 2 ]; cl_poly.vertices[ 2 ] = vertices[ ui_prev ]; ui_prev = ( ui_prev + cui_vertex_cnt - 1 ) % cui_vertex_cnt; } else { cl_poly.vertices[ 0 ] = cl_poly.vertices[ 1 ]; cl_poly.vertices[ 1 ] = vertices[ ui_next ]; ui_next = ( ui_next + 1 ) % cui_vertex_cnt; } } return 0; } #endif // std::cerr << " triangulate in, size: " << vertices.size() << std::endl; switch( vertices.size( ) ) { case 0: case 1: case 2: return 0; case 3: { polylist.push_back( *this ); // SimplePolygon p; // p.vertices = vertices; // p.is_marked = is_marked; // std::cerr << "adding polygon of 3 vertices into the list..." << std::endl; // polylist.push_back( p ); // FIXME, this is not too elegant // std::cerr << "triangulate out!!!" << std::endl; } return 0; case 4: { const int ci_v1 = vertices[ 0 ]; const int ci_v2 = vertices[ 1 ]; const int ci_v3 = vertices[ 2 ]; const int ci_v4 = vertices[ 3 ]; const double cd_sdist1 = ( globalverts[ ci_v1 ] - globalverts[ ci_v3 ] ).squareLength( ); const double cd_sdist2 = ( globalverts[ ci_v2 ] - globalverts[ ci_v4 ] ).squareLength( ); double ad_pa[ 2 ]; double ad_pb[ 2 ]; double ad_pc[ 2 ]; double ad_pd[ 2 ]; SimplePolygon p; p.vertices.resize( 3 ); p.is_marked = is_marked; ad_pa[ 0 ] = globalverts[ ci_v1 ][0]; ad_pa[ 1 ] = globalverts[ ci_v1 ][1]; ad_pb[ 0 ] = globalverts[ ci_v2 ][0]; ad_pb[ 1 ] = globalverts[ ci_v2 ][1]; ad_pc[ 0 ] = globalverts[ ci_v3 ][0]; ad_pc[ 1 ] = globalverts[ ci_v3 ][1]; ad_pd[ 0 ] = globalverts[ ci_v4 ][0]; ad_pd[ 1 ] = globalverts[ ci_v4 ][1]; if( cd_sdist1 - cd_sdist2 < DCTP_EPS ) { /* const double cd_r1 = orient2d( ad_pa, ad_pb, ad_pc ); const double cd_r2 = orient2d( ad_pa, ad_pb, ad_pd ); if( ( ( cd_r1 <= 0.0 ) && ( cd_r2 <= 0.0 ) ) || ( ( cd_r1 >= 0.0 ) && ( cd_r2 >= 0.0 ) ) )*/ if( ( orient2d( ad_pa, ad_pb, ad_pc ) <= 0.0 ) || ( orient2d( ad_pa, ad_pd, ad_pc ) >= 0.0 ) || ( incircle( ad_pa, ad_pb, ad_pc, ad_pd ) > 0.0 ) ) { p.vertices[ 0 ] = ci_v1; p.vertices[ 1 ] = ci_v2; p.vertices[ 2 ] = ci_v4; polylist.push_back( p ); p.vertices[ 0 ] = ci_v2; p.vertices[ 1 ] = ci_v3; p.vertices[ 2 ] = ci_v4; polylist.push_back( p ); // std::cerr << globalverts[ ci_v1 ] << globalverts[ ci_v2 ] << globalverts[ ci_v3 ] << globalverts[ ci_v4 ] << std::endl; } else { p.vertices[ 0 ] = ci_v1; p.vertices[ 1 ] = ci_v2; p.vertices[ 2 ] = ci_v3; polylist.push_back( p ); p.vertices[ 0 ] = ci_v1; p.vertices[ 1 ] = ci_v3; p.vertices[ 2 ] = ci_v4; polylist.push_back( p ); } } else { // const double cd_r1 = orient2d( ad_pc, ad_pd, ad_pa ); // const double cd_r2 = orient2d( ad_pc, ad_pd, ad_pb ); // if( ( ( cd_r1 <= 0.0 ) && ( cd_r2 <= 0.0 ) ) || // ( ( cd_r1 >= 0.0 ) && ( cd_r2 >= 0.0 ) ) ) if( ( orient2d( ad_pb, ad_pc, ad_pd ) <= 0.0 ) || ( orient2d( ad_pb, ad_pa, ad_pd ) >= 0.0 ) || ( incircle( ad_pa, ad_pb, ad_pd, ad_pc ) > 0.0 ) ) { p.vertices[ 0 ] = ci_v1; p.vertices[ 1 ] = ci_v2; p.vertices[ 2 ] = ci_v3; polylist.push_back( p ); p.vertices[ 0 ] = ci_v1; p.vertices[ 1 ] = ci_v3; p.vertices[ 2 ] = ci_v4; polylist.push_back( p ); // std::cerr << globalverts[ ci_v1 ] << globalverts[ ci_v2 ] << globalverts[ ci_v3 ] << globalverts[ ci_v4 ] << std::endl; } else { p.vertices[ 0 ] = ci_v1; p.vertices[ 1 ] = ci_v2; p.vertices[ 2 ] = ci_v4; polylist.push_back( p ); p.vertices[ 0 ] = ci_v2; p.vertices[ 1 ] = ci_v3; p.vertices[ 2 ] = ci_v4; polylist.push_back( p ); } } } return 0; } // recalc valid third points! v1tp = -1; validThirdPoints.resize( vertices.size( ) ); SimplePolygon poly; int i2, i3; // this is an index into the vertices[] vector int err; DCTPivector verts; //p1verts, p2verts, p3verts; int i; int j; // pseudo random (reproduces same triangulation) int offs = ( int( globalverts[ vertices[ 0 ] ][0] * vertices.size( ) ) ) % vertices.size( ); /* for( i = 0; i < vertices.size( ); ++i ) { std::cerr << globalverts[ vertices[ i ] ][0] << ","; std::cerr << globalverts[ vertices[ i ] ][1] << std::endl; }*/ for( j = 0; j < int(vertices.size()); j++ ) { i = ( j + offs ) % vertices.size( ); // v1 = vertices[ i ]; if ( i == int(vertices.size()) - 1 ) i2 = 0; //v2 = vertices [ 0 ]; else i2 = i + 1; //v2 = vertices[ i + 1 ]; err = findThirdPoint( globalverts, i, i2, i3 ); if ( err ) return err; if ( i3 >= 0 ) { // build p1 int k = i2; // !!! verts.resize( 0 ); while ( k != i3 ) { // std::cerr << " k: " << k; verts.push_back( vertices[ k ] ); k++; if ( k == int(vertices.size()) ) k = 0; } // while k verts.push_back( vertices[ k ] ); // record the last one aswell // std::cerr << " k: " << k << std::endl; poly.vertices = verts; poly.is_marked = is_marked; // std::cerr << "calling p1... " << std::endl; err = poly.triangulate( globalverts, polylist); if ( err ) return err; // build p2 verts.resize( 3 ); verts[ 0 ] = vertices[ i ]; verts[ 1 ] = vertices[ i2 ]; verts[ 2 ] = vertices[ i3 ]; poly.vertices = verts; poly.is_marked = is_marked; // std::cerr << "adding p2 to the list..." << std::endl; polylist.push_back( poly ); // build p3 k = i3; verts.resize( 0 ); while ( k != i ) { verts.push_back( vertices[ k ] ); k++; if ( k == int(vertices.size()) ) k = 0; } // while k verts.push_back( vertices[ k ] ); // record the last one aswell poly.vertices = verts; poly.is_marked = is_marked; // std::cerr << "calling p3... " << std::endl; err = poly.triangulate( globalverts, polylist ); if ( err ) return err; // std::cerr << "triangulate out!!!" << std::endl; return 0; } // if } // for i /* SWARNING << "triangulate out WITH ERROR!!!" << endLog; for( i = 0; i < vertices.size( ); ++i ) { std::cerr << globalverts[ vertices[ i ] ][0] << ","; std::cerr << globalverts[ vertices[ i ] ][1] << std::endl; }*/ // char x[ 256 ]; // gets( x ); return -1; }
/*! * `i1' and `i2' must already be an edge of the polygon, and the third point `i3' * be a point of the polygon different from `i1' and `i2'. The polygon's lines * must not cross each other. * * \param globalverts global vertices vector * \param i1 first point * \param i2 second point (must form an edge with the first point) * \param i3 third point * \return 1 if not inside <BR> * 0 if inside <BR> * and a negative value if an error happened. */ int SimplePolygon::isInsidePolygon( DCTPVec2dvector &globalverts, int i1, int i2, int i3 ) const { double dres; const int size = vertices.size( ); const int vi1 = vertices[ i1 ]; const int vi2 = vertices[ i2 ]; const int vi3 = vertices[ i3 ]; const int prev = vertices[ ( size + i1 - 1 ) % size ]; const int next = vertices[ ( i2 + 1 ) % size ]; // the third (i3) point must lie to the left of the edge (i2, next) // (NOT! on the edge) to be inside double p2[ 2 ], p3[ 2 ], pn[ 2 ]; p3 [ 0 ] = globalverts[ vi3 ][0]; p3 [ 1 ] = globalverts[ vi3 ][1]; p2 [ 0 ] = globalverts[ vi2 ][0]; p2 [ 1 ] = globalverts[ vi2 ][1]; pn [ 0 ] = globalverts[ next ][0]; pn [ 1 ] = globalverts[ next ][1]; if( vi3 != next ) { dres = orient2d( p3, p2, pn ); // std::cerr << "next edge test: " << dres << std::endl; if ( dres < 0.0 ) return 1; } // the third (i3) point must also lie to the left of the edge (prev, i1) // (NOT! on the edge) to be inside double p1[ 2 ], pp[ 2 ]; pp [ 0 ] = globalverts[ prev ][0]; pp [ 1 ] = globalverts[ prev ][1]; p1 [ 0 ] = globalverts[ vi1 ][0]; p1 [ 1 ] = globalverts[ vi1 ][1]; if( vi3 != prev ) { dres = orient2d( p3, pp, p1 ); // std::cerr << "prev edge test: " << dres << std::endl; if ( dres < 0.0 ) return 1; } // the third (i3) point must also lie to the left of the edge (i1, i2) // (NOT! on the edge) to be inside dres = orient2d( p3, p1, p2 ); // std::cerr << "actual edge test: " << dres << std::endl; if ( dres <= 0.0 ) return 1; // if( m_bConvex ) return 0; // don't need intersection test for convex polygons // the triangle is not completely outside the polygon, we have to // go for the intersection test. // FIXME/TODO: use bounding boxes to speed up testing: // only test with those edges that are at least partially in the // bounding box of the triangle to be tested int res; int j = size - 1; Vec2d min, max; unsigned char test, ptest; min = max = globalverts[ vi1 ]; if( min[0] > globalverts[ vi2 ][0] ) min[0] = globalverts[ vi2 ][0]; else if( max[0] < globalverts[ vi2 ][0] ) max[0] = globalverts[ vi2 ][0]; if( min[1] > globalverts[ vi2 ][1] ) min[1] = globalverts[ vi2 ][1]; else if( max[1] < globalverts[ vi2 ][1] ) max[1] = globalverts[ vi2 ][1]; if( min[0] > globalverts[ vi3 ][0] ) min[0] = globalverts[ vi3 ][0]; else if( max[0] < globalverts[ vi3 ][0] ) max[0] = globalverts[ vi3 ][0]; if( min[1] > globalverts[ vi3 ][1] ) min[1] = globalverts[ vi3 ][1]; else if( max[1] < globalverts[ vi3 ][1] ) max[1] = globalverts[ vi3 ][1]; const Vec2d &pj = globalverts[ vertices[ j ] ]; test = 0; if( pj[0] - max[0] > DCTP_EPS ) test |= 0x01; if( min[0] - pj[0] > DCTP_EPS ) test |= 0x02; if( pj[1] - max[1] > DCTP_EPS ) test |= 0x04; if( min[1] - pj[1] > DCTP_EPS ) test |= 0x08; for ( int i = 0; i < size; i++ ) { ptest = test; test = 0; const Vec2d &pi = globalverts[ vertices[ i ] ]; if( pi[0] - max[0] > DCTP_EPS ) test |= 0x01; if( min[0] - pi[0] > DCTP_EPS ) test |= 0x02; if( pi[1] - max[1] > DCTP_EPS ) test |= 0x04; if( min[1] - pi[1] > DCTP_EPS ) test |= 0x08; if( ( test & ptest ) == 0 ) { // std::cerr << "checking: " << v1 << " " << v3 << " and i: " << i << std::endl; res = doIntersect( globalverts, i1, i3, j, i ); if ( res ) return res; // either intersection or error res = doIntersect( globalverts, i2, i3, j, i ); if ( res ) return res; // see above } j = i; } return 0; }
void CalcPixels2(double Edges[3][2], int **Pixels, int *counter) { int i; double minX=10000000,maxX=-10000000,minY=100000000,maxY=-100000000; for (i=0;i<3;i++){ Edges[i][0] = round(Edges[i][0]); Edges[i][1] = round(Edges[i][1]); } for (i=0;i<3;i++){ if (Edges[i][0]<minX){ minX = Edges[i][0]; } if (Edges[i][0]>maxX){ maxX = Edges[i][0]; } if (Edges[i][1]<minY){ minY = Edges[i][1]; } if (Edges[i][1]>maxY){ maxY = Edges[i][1]; } } *counter = 0; int A01 = Edges[0][1] - Edges[1][1], B01 = Edges[1][0] - Edges[0][0]; int A12 = Edges[1][1] - Edges[2][1], B12 = Edges[2][0] - Edges[1][0]; int A20 = Edges[2][1] - Edges[0][1], B20 = Edges[0][0] - Edges[2][0]; struct Point2D p = { minX, minY }; struct Point2D v0 = { Edges[0][0], Edges[0][1]}; struct Point2D v1 = { Edges[1][0], Edges[1][1]}; struct Point2D v2 = { Edges[2][0], Edges[2][1]}; int w0_row = orient2d(v1, v2, p); int w1_row = orient2d(v2, v0, p); int w2_row = orient2d(v0, v1, p); for (p.y = minY; p.y <= maxY; p.y++) { int w0 = w0_row; int w1 = w1_row; int w2 = w2_row; for (p.x = minX; p.x <= maxX; p.x++) { if (w0 >= 0 && w1 >= 0 && w2 >= 0){ Pixels[*counter][0] = p.x; Pixels[*counter][1] = p.y; *counter+=1; } else if(len2d(v1,v2,p)<0.99){ Pixels[*counter][0] = p.x; Pixels[*counter][1] = p.y; *counter+=1; } else if(len2d(v2,v0,p)<0.99){ Pixels[*counter][0] = p.x; Pixels[*counter][1] = p.y; *counter+=1; } else if(len2d(v0,v1,p)<0.99){ Pixels[*counter][0] = p.x; Pixels[*counter][1] = p.y; *counter+=1; } w0 += A12; w1 += A20; w2 += A01; } w0_row += B12; w1_row += B20; w2_row += B01; } }
Orient PredWrapper::doOrient3DSoSOnly ( const RealType* p0, const RealType* p1, const RealType* p2, const RealType* p3, int v0, int v1, int v2, int v3 ) const { //// // Sort points using vertex as key, also note their sorted order //// const int DIM = 3; const int NUM = DIM + 1; const RealType* p[NUM] = { p0, p1, p2, p3 }; int v[NUM] = { v0, v1, v2, v3 }; int pn = 1; for ( int i = 0; i < 3; ++i ) { int minI = i; for ( int j = i + 1; j < 4; ++j ) if ( v[j] < v[minI] ) minI = j; if ( minI != i ) { int tempI = v[minI]; v[minI] = v[i]; v[i] = tempI; pn = -pn; //cuSwap( p[minI], p[i] ); std::swap( p[minI], p[i] ); } } RealType result = 0; RealType pa2[2], pb2[2], pc2[2]; int depth; for ( depth = 0; depth < 14; ++depth ) { switch ( depth ) { case 0: pa2[0] = p[1][0]; pa2[1] = p[1][1]; pb2[0] = p[2][0]; pb2[1] = p[2][1]; pc2[0] = p[3][0]; pc2[1] = p[3][1]; break; case 1: pa2[0] = p[1][0]; pa2[1] = p[1][2]; pb2[0] = p[2][0]; pb2[1] = p[2][2]; pc2[0] = p[3][0]; pc2[1] = p[3][2]; break; case 2: pa2[0] = p[1][1]; pa2[1] = p[1][2]; pb2[0] = p[2][1]; pb2[1] = p[2][2]; pc2[0] = p[3][1]; pc2[1] = p[3][2]; break; case 3: pa2[0] = p[0][0]; pa2[1] = p[0][1]; pb2[0] = p[2][0]; pb2[1] = p[2][1]; pc2[0] = p[3][0]; pc2[1] = p[3][1]; break; case 4: result = p[2][0] - p[3][0]; break; case 5: result = p[2][1] - p[3][1]; break; case 6: pa2[0] = p[0][0]; pa2[1] = p[0][2]; pb2[0] = p[2][0]; pb2[1] = p[2][2]; pc2[0] = p[3][0]; pc2[1] = p[3][2]; break; case 7: result = p[2][2] - p[3][2]; break; case 8: pa2[0] = p[0][1]; pa2[1] = p[0][2]; pb2[0] = p[2][1]; pb2[1] = p[2][2]; pc2[0] = p[3][1]; pc2[1] = p[3][2]; break; case 9: pa2[0] = p[0][0]; pa2[1] = p[0][1]; pb2[0] = p[1][0]; pb2[1] = p[1][1]; pc2[0] = p[3][0]; pc2[1] = p[3][1]; break; case 10: result = p[1][0] - p[3][0]; break; case 11: result = p[1][1] - p[3][1]; break; case 12: result = p[0][0] - p[3][0]; break; default: result = 1.0; break; } switch ( depth ) { case 0: case 1: case 2: case 3: case 6: case 8: case 9: result = orient2d( pa2, pb2, pc2 ); } if ( result != 0 ) break; } switch ( depth ) { case 1: case 3: case 5: case 8: case 10: result = -result; } const RealType det = result * pn; return ortToOrient( det ); }