// wrapper to simplify the doIntersect call int diw(double* s1, double* s2) { double x1, y1, x2, y2, x3, y3, x4, y4; int res; x1 = s1[0]; y1 = s1[1]; x2 = s1[2]; y2 = s1[3]; x3 = s2[0]; y3 = s2[1]; x4 = s2[2]; y4 = s2[3]; // printf("\tchecking:\n\t%f\t%f\t%f\t%f\n\t%f\t%f\t%f\t%f\n",x1, y1, x2, y2, x3, y3, x4, y4); // return 0; res=doIntersect(x1, y1, x2, y2, x3, y3, x4, y4); if (res==1) { printf("intersecting points:\n"); printf("\t%f\t%f\t%f\t%f\n\t%f\t%f\t%f\t%f\n",x1, y1, x2, y2, x3, y3, x4, y4); } // printf("\tresult: %d\n",res); return res; }
static void testOneOffs(skiatest::Reporter* reporter) { bool flipped = false; for (size_t index = 0; index < oneOffs_count; ++index) { const SkDConic& conic = oneOffs[index].conic; SkASSERT(ValidConic(conic)); const SkDLine& line = oneOffs[index].line; SkASSERT(ValidLine(line)); SkIntersections intersections; int result = doIntersect(intersections, conic, line, flipped); for (int inner = 0; inner < result; ++inner) { double conicT = intersections[0][inner]; SkDPoint conicXY = conic.ptAtT(conicT); double lineT = intersections[1][inner]; SkDPoint lineXY = line.ptAtT(lineT); if (!conicXY.approximatelyEqual(lineXY)) { conicXY.approximatelyEqual(lineXY); SkDebugf(""); } REPORTER_ASSERT(reporter, conicXY.approximatelyEqual(lineXY)); } } }
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; }
/*! * `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; }
/* inline float getAxisElem4( cl_float4 vec, int axis ) { if( axis == 0 ) return vec.x; else if( axis == 1 ) return vec.y; else if( axis == 2 ) return vec.z; else return -1; } bool checkRange( const cl_float4 intersect, const cl_float4 range, const int axis ) { bool result = false; switch( axis ) { case 0: // X axis range if( intersect.y >= range.x && intersect.y <= range.y && intersect.z >= range.z && intersect.z <= range.w ) result = true; break; case 1: // Y axis range if( intersect.x >= range.x && intersect.x <= range.y && intersect.z >= range.z && intersect.z <= range.w ) result = true; break; case 2: // Z axis range if( intersect.x >= range.x && intersect.x <= range.y && intersect.y >= range.z && intersect.y <= range.w ) result = true; break; default: break; } return result; } float dot( cl_float3 f1, cl_float3 f2 ) { return f1.x*f2.x + f1.y*f2.y + f1.z*f2.z; } float doIntersectPlane( cl_float3 point, cl_float3 norm, cl_float4 eyePos, cl_float4 d) { float t = -1; float denominator = (norm.x*d.x+norm.y*d.y+norm.z*d.z); if(fabs(denominator)>EPSILON) { cl_float3 eye3; eye3.x =eyePos.x; eye3.y = eyePos.y; eye3.z = eyePos.z; t = (dot(norm, point)-dot(norm, eye3))/(denominator); } return t; } void doIntersectRayKdBox2( const cl_float4 eyePos, const cl_float4 d, float* near, float* far, const cl_float3 boxStart, const cl_float3 boxSize ) { *near = -1; *far = -1; cl_float3 start = boxStart; cl_float3 end; end .x = boxStart.x + boxSize.x; end .y = boxStart.y + boxSize.y; end .z = boxStart.z + boxSize.z; cl_float3 norm[3]; // = {(cl_float3)(1,0,0), (cl_float3)(0,1,0), (cl_float3)(0,0,1) }; norm[0].x = 1, norm[0].y = 0, norm[0].z = 0; norm[1].x = 0, norm[1].y = 1, norm[1].z = 0; norm[2].x = 0, norm[2].y = 0, norm[2].z = 1; cl_float4 range[3]; range[0].x = start.y, range[0].y = end.y, range[0].z = start.z, range[0].w = end.z; range[1].x = start.x, range[1].y = end.x, range[1].z = start.z, range[1].w = end.z; range[2].x = start.x, range[2].y = end.x, range[2].z = start.y, range[2].w = end.y; float t[6]; t[0] = doIntersectPlane( start, norm[0], eyePos, d ); t[1] = doIntersectPlane( end, norm[0], eyePos, d ); t[2] = doIntersectPlane( start, norm[1], eyePos, d ); t[3] = doIntersectPlane( end, norm[1], eyePos, d ); t[4] = doIntersectPlane( start, norm[2], eyePos, d ); t[5] = doIntersectPlane( end, norm[2], eyePos, d ); cl_float4 intersectPoint[6]; float min = POS_INF; float max = -POS_INF; for( int i = 0; i < 6; i++ ) { intersectPoint[i].x = eyePos.x + t[i]*d.x; intersectPoint[i].y = eyePos.y + t[i]*d.y; intersectPoint[i].z = eyePos.z + t[i]*d.z; intersectPoint[i].w = eyePos.w + t[i]*d.w; if( t[i] > 0 && checkRange( intersectPoint[i], range[i/2], i/2 ) && min > t[i] ) { min = t[i]; *near = t[i]; } if( t[i] > 0 && checkRange( intersectPoint[i], range[i/2], i/2 ) && max < t[i] ) { max = t[i]; *far = t[i]; } } } bool boxContain( const cl_float3 start, const cl_float3 size, const cl_float3 pos ) { cl_float3 v1 = start; cl_float3 v2; v2.x = start.x + size.x; v2.y = start.y + size.y; v2.z = start.z + size.z; return ((pos.x >= v1.x) && (pos.x <= v2.x) && (pos.y >= v1.y) && (pos.y <= v2.y) && (pos.z >= v1.z) && (pos.z <= v2.z)); } cl_float4 add4( cl_float4 v1, cl_float4 v2 ) { cl_float4 result; result.x = v1.x + v2.x; result.y = v1.y + v2.y; result.z = v1.z + v2.z; result.w = v1.w + v2.w; return result; } cl_float3 add3( cl_float3 v1, cl_float3 v2 ) { cl_float3 result; result.x = v1.x + v2.x; result.y = v1.y + v2.y; result.z = v1.z + v2.z; return result; } cl_float3 mult3( float s, cl_float3 v ) { cl_float3 result; result.x = s*v.x; result.y = s*v.y; result.z = s*v.z; return result; } cl_float4 mult4( float s, cl_float4 v ) { cl_float4 result; result.x = s*v.x; result.y = s*v.y; result.z = s*v.z; result.w = s*v.w; return result; } */ REAL intersect( const Vector4& eyePos, const QVector<SceneObject>& objects, const Vector4& d, int& objectIndex, int& faceIndex, KdTree* tree, AABB extends, bool refract ) { REAL minT = POS_INF; REAL resultT = -1; int tempFaceIndex = -1; if( settings.useKdTree && tree && !refract ) { assert( EQ( eyePos.w, 1) && EQ(d.w, 0) ); REAL near, far; doIntersectRayKdBox( eyePos, d, near, far, extends ); if( near <= 0&&far <= 0 ) return -1; QVector<KdTreeNode*> nodeStack; KdTreeNode* current = tree->getRoot(); while( current ) { while( !current->isLeaf() ) { AABB curBox = current->getAABB(); REAL near, far; doIntersectRayKdBox( eyePos, d, near, far, curBox ); int axis = current->getAxis(); float splitPos = current->getSplitPos(); if( near == far ) // inside the box near = 0; Vector4 nearPos = eyePos + d*near; Vector4 farPos = eyePos + d*far; if( nearPos.data[axis] <= splitPos ) { if( farPos.data[axis] <= splitPos ) { current = current->getLeft(); continue; } KdTreeNode* right = current->getRight(); current = current->getLeft(); // Preserve the right nodeStack.push_back( right ); } else { if( farPos.data[axis] > splitPos ) { current=current->getRight(); continue; } KdTreeNode* left = current->getLeft(); current = current->getRight(); nodeStack.push_back( left ); } } // Then we found an near leaf, find if there is intersect ObjectNode* objList = current->getObjectList(); minT = POS_INF; while( objList ) { SceneObject* curObj =objList->getObject(); Matrix4x4 invCompMat = (*curObj).m_invTransform; Vector4 eyePosObjSpace = invCompMat*eyePos; Vector4 dObjSpace = invCompMat*d; REAL t = doIntersect( *curObj, eyePosObjSpace, dObjSpace, tempFaceIndex); if( t>0 && t < minT ) { minT = t; objectIndex = curObj->m_arrayID; faceIndex = tempFaceIndex; } objList = objList->getNext(); } Vector4 dst = (eyePos + minT*d); // Here we need to enlarge the bounding box a little bit AABB curBox = AABB( current->getAABB().getPos() - Vector3( EPSILON, EPSILON, EPSILON ), current->getAABB().getSize() + 2*Vector3( EPSILON, EPSILON, EPSILON )); if( minT != POS_INF && curBox.contains(Vector3(dst.x, dst.y, dst.z ) ) ) { resultT = minT; break; } // Else we need to get one node from the stack if( nodeStack.empty() ) { // No more nodes, meaning there is no intersect break; } else { current = nodeStack.at(nodeStack.size()-1); nodeStack.pop_back(); } } /** GPU code, preserve for future test **/ /* float near, far; KdTreeNodeHost root = kdnode_test[0]; cl_float4 eye4; eye4.x = eyePos.x; eye4.y = eyePos.y; eye4.z = eyePos.z; eye4.w = eyePos.w; cl_float4 d4; d4.x = d.x; d4.y = d.y; d4.z = d.z; d4.w = d.w; doIntersectRayKdBox2( eye4, d4, &near, &far, root.boxBegin, root.boxSize ); if( near <= 0 && far <= 0 ) return -1; // else // return 1; int nodeStack[1024]; int stackTop = 0; int nextIndex = 0; while( nextIndex != -1 ) { KdTreeNodeHost current = kdnode_test[nextIndex]; while( !current.leaf ) { cl_float3 curBoxStart = current.boxBegin; cl_float3 curBoxSize = current.boxSize; float near, far; doIntersectRayKdBox2( eye4, d4, &near, &far, curBoxStart, curBoxSize ); int axis = current.axis; float splitPos = current.split; if( near == far ) // inside the box near = 0; cl_float4 nearPos = add4(eye4, mult4(near, d4)); cl_float4 farPos = add4(eye4, mult4(far, d4)); if( getAxisElem4(nearPos, axis) <= splitPos ) { if( getAxisElem4(farPos, axis) <= splitPos ) { //nextIndex = current.leftIndex; current = kdnode_test[current.leftIndex]; continue; } nodeStack[stackTop++] = current.rightIndex; current = kdnode_test[current.leftIndex]; // Preserve the right } else { if( getAxisElem4(farPos, axis) > splitPos ) { // nextIndex = current.rightIndex; current = kdnode_test[current.rightIndex]; continue; } //KdTreeNodeHost left = kdnode_test[current.leftIndex]; nodeStack[stackTop++] = current.leftIndex; current = kdnode_test[current.rightIndex]; } } // Then we found an near leaf, find if there is intersect int objIndex = current.objIndex; minT = POS_INF; while( objIndex != -1 ) { ObjectNodeHost objList = objnode_test[objIndex]; int sceneObjIndex = objList.objectIndex; const SceneObject& curSceneObj = objects[sceneObjIndex]; Matrix4x4 invCompMat = curSceneObj.m_invTransform; Vector4 eyePosObjSpace = invCompMat*eyePos; Vector4 dObjSpace = invCompMat*d; REAL t = doIntersect( curSceneObj, eyePosObjSpace, dObjSpace, tempFaceIndex); if( t>0 && t < minT ) { minT = t; objectIndex = sceneObjIndex; faceIndex = tempFaceIndex; } objIndex = objList.nextNodeIndex; } //cl_float4 dst = add4(eye4, mult4(minT, d4)); Vector4 dst = eyePos + minT*d; // Here we need to enlarge the bounding box a little bit cl_float3 ep1; ep1.x = -EPSILON; ep1.y = -EPSILON; ep1.z = -EPSILON; cl_float3 ep2; ep2.x = 2*EPSILON; ep2.y = 2*EPSILON; ep2.z = 2*EPSILON; cl_float3 boxStart = add3(current.boxBegin , ep1); cl_float3 boxSize = add3(current.boxSize, ep2 ); cl_float3 dst3; dst3.x = dst.x; dst3.y = dst.y; dst3.z = dst.z; if( minT != POS_INF && boxContain( boxStart, boxSize, dst3 ) ) { resultT = minT; //resultT = 1; break; } // Else we need to get one node from the stack if( stackTop == 0 ) { // No more nodes, meaning there is no intersect int a = 0; break; } else { nextIndex = nodeStack[--stackTop]; } }*/ } else { for( int i = 0; i < objects.size(); i++ ) { const SceneObject& curObj = objects[i]; Matrix4x4 invCompMat = curObj.m_invTransform; Vector4 eyePosObjSpace = invCompMat*eyePos; Vector4 dObjSpace = invCompMat*d; REAL t = doIntersect( curObj, eyePosObjSpace, dObjSpace, tempFaceIndex); if( t>0 && t < minT ) { minT = t; objectIndex = i; faceIndex = tempFaceIndex; } } if( minT != POS_INF ) { resultT = minT; } } return resultT; }