Edge(1, 5), Edge(5, 5), Edge(1, 7), Edge(7, 1)}); this->checkAddEdge(6, Edge(1, 7), {Edge(0, 5), Edge(5, 0), Edge(1, 7)}, {Edge(0, 1), Edge(0, 0), Edge(0, 4), Edge(0, 6), Edge(1, 5), Edge(5, 5), Edge(7, 1)}); this->checkAddEdge(6, Edge(5, 5), {Edge(0, 5), Edge(5, 0), Edge(1, 7), Edge(5, 5)}, {Edge(0, 1), Edge(0, 0), Edge(0, 4), Edge(0, 6), Edge(1, 5), Edge(7, 1)}); this->checkAddEdge(7, Edge(5, 6), {Edge(0, 5), Edge(5, 0), Edge(1, 7), Edge(5, 5), Edge(5, 6)}, {}); this->checkAddEdge(8, Edge(6, 5), {Edge(0, 5), Edge(5, 0), Edge(1, 7), Edge(5, 5), Edge(5, 6), Edge(6, 5)}, {}); } TYPED_TEST_P(BipartiteGraphTest, addEdge_tooBigIndex) { ASSERT_THROW(this->g.addEdge(Edge(TypeParam::INDEX_LIMIT, 0)), typename TypeParam::exception_t); ASSERT_THROW(this->g.addEdge(Edge(TypeParam::INDEX_LIMIT + 1, 0)), typename TypeParam::exception_t); ASSERT_THROW(this->g.addEdge(Edge(0, TypeParam::INDEX_LIMIT)), typename TypeParam::exception_t); ASSERT_THROW(this->g.addEdge(Edge(0, TypeParam::INDEX_LIMIT + 1)), typename TypeParam::exception_t); ASSERT_THROW( this->g.addEdge(Edge(TypeParam::INDEX_LIMIT, TypeParam::INDEX_LIMIT)), typename TypeParam::exception_t); ASSERT_THROW( this->g.addEdge(Edge(TypeParam::INDEX_LIMIT + 1, TypeParam::INDEX_LIMIT + 1)), typename TypeParam::exception_t); } TYPED_TEST_P(BipartiteGraphTest, simpleMaximumMatching) { this->checkMatching(3, {Edge(0, 0), Edge(1, 1), Edge(2, 2)}); }
inline void addEdge(int u,int v,Type cost){ e[cnt] = Edge(v,cost); int tmp = head[u]; head[u] = cnt; nxt[cnt++] = tmp; }
// edges are given as (edges[i], edges[i+1]) void find_non_manifold_verts(const cvcraw_geometry::cvcgeom_t& geom, std::vector<int>& non_manifold_vertices) { static log4cplus::Logger logger = log4cplus::Logger::getInstance("find_non_manifold_verts"); const vector<Point_3> vertices = sm_vertices(geom); const vector<Triangle> triangles = sm_triangles(geom); const vector<vector<Triangle> > v2t = build_v2t(triangles.begin(), triangles.end()); // set<Edge> non_manifold_edges; // vector<int> non_manifold_vertices; for (int vi = 0; vi < v2t.size(); ++vi) { set<Edge> edges; bool manifold = true; const vector<Triangle>& tris = v2t[vi]; if (!tris.empty()){ set<Triangle> tri_set(tris.begin(), tris.end()); Triangle start_t = *tri_set.begin(); Triangle t = *tri_set.begin(); bool done = false; const int li = t.g2l(vi); const Edge er(t[(li+1)%3], vi); const Edge el(t[(li+2)%3], vi); Edge e = er; //walk right when count = 0 and left when count =1 int count = 0; while (count < 2){ while (!done && manifold && !tri_set.empty() && tri_set.find(t) != tri_set.end()) { tri_set.erase(t); // Local triangle index [012] of vi in triangle t const vector<Triangle> adjs = adj_triangles(e, v2t); if (adjs.size() < 2) { // boundary done = true; } else if (adjs.size() > 2) { // non_manifold edge done = true; manifold = false; } else { Triangle adj = adjs[0]; if (adj == t) { adj = adjs[1]; } t = adj; e = Edge(adj.opposite(e), vi); } } t = start_t; if (count == 0 && !tri_set.empty()){ tri_set.insert(t); //just so it can be removed again } done = false; e = el; count++; } if (!tri_set.empty() || !manifold) { LOG4CPLUS_TRACE(logger, "Non Manifold vert is: " << vi); non_manifold_vertices.push_back(vi); } } } }
TriMesh<FloatType> TriMesh<FloatType>::flatLoopSubdivision(float minEdgeLength) const { struct Edge { Edge(UINT32 _v0, UINT32 _v1) { v0 = std::min(_v0, _v1); v1 = std::max(_v0, _v1); } union { struct { UINT32 v0, v1; }; UINT64 val; }; }; struct edgeCompare { bool operator() (const Edge &a, const Edge &b) { return a.val < b.val; } }; map<Edge, UINT, edgeCompare> edgeToNewVertexMap; TriMesh<FloatType> result; result.m_Vertices = m_Vertices; result.m_Indices.reserve(m_Indices.size() * 4); for (const vec3ui &tri : m_Indices) { /*bool subdivide = true; for (UINT eIndex = 0; eIndex < 3; eIndex++) { const vec3f &v0 = m_Vertices[tri[eIndex]].position; const vec3f &v1 = m_Vertices[tri[(eIndex + 1) % 3]].position; float edgeLength = vec3f::dist(v0, v1); if (edgeLength < minEdgeLength) subdivide = false; }*/ bool subdivide = math::triangleArea(m_Vertices[tri[0]].position, m_Vertices[tri[1]].position, m_Vertices[tri[2]].position) >= (minEdgeLength * minEdgeLength); if (subdivide) { UINT edgeMidpoints[3]; for (UINT eIndex = 0; eIndex < 3; eIndex++) { const UINT v0 = tri[eIndex]; const UINT v1 = tri[(eIndex + 1) % 3]; Edge e = Edge(v0, v1); if (edgeToNewVertexMap.count(e) == 0) { edgeToNewVertexMap[e] = (UINT)result.m_Vertices.size(); result.m_Vertices.push_back((m_Vertices[v0] + m_Vertices[v1]) * (FloatType)0.5); } edgeMidpoints[eIndex] = edgeToNewVertexMap[e]; } result.m_Indices.push_back(vec3ui(tri[0], edgeMidpoints[0], edgeMidpoints[2])); result.m_Indices.push_back(vec3ui(edgeMidpoints[0], tri[1], edgeMidpoints[1])); result.m_Indices.push_back(vec3ui(edgeMidpoints[2], edgeMidpoints[1], tri[2])); result.m_Indices.push_back(vec3ui(edgeMidpoints[2], edgeMidpoints[0], edgeMidpoints[1])); } else { result.m_Indices.push_back(tri); } } return result; }
bool ConvexHull2<Real>::Update (Edge*& rpkHull, int i) { // Locate an edge visible to the input point (if possible). Edge* pkVisible = 0; Edge* pkCurrent = rpkHull; do { if (pkCurrent->GetSign(i,m_pkQuery) > 0) { pkVisible = pkCurrent; break; } pkCurrent = pkCurrent->A[1]; } while (pkCurrent != rpkHull); if (!pkVisible) { // The point is inside the current hull; nothing to do. return true; } // Remove the visible edges. Edge* pkAdj0 = pkVisible->A[0]; assert(pkAdj0); if (!pkAdj0) { return false; } Edge* pkAdj1 = pkVisible->A[1]; assert(pkAdj1); if (!pkAdj1) { return false; } pkVisible->DeleteSelf(); while (pkAdj0->GetSign(i,m_pkQuery) > 0) { rpkHull = pkAdj0; pkAdj0 = pkAdj0->A[0]; assert(pkAdj0); if (!pkAdj0) { return false; } pkAdj0->A[1]->DeleteSelf(); } while (pkAdj1->GetSign(i,m_pkQuery) > 0) { rpkHull = pkAdj1; pkAdj1 = pkAdj1->A[1]; assert(pkAdj1); if (!pkAdj1) { return false; } pkAdj1->A[0]->DeleteSelf(); } // Insert the new edges formed by the input point and the end points of // the polyline of invisible edges. Edge* pkEdge0 = WM4_NEW Edge(pkAdj0->V[1],i); Edge* pkEdge1 = WM4_NEW Edge(i,pkAdj1->V[0]); pkEdge0->Insert(pkAdj0,pkEdge1); pkEdge1->Insert(pkEdge0,pkAdj1); rpkHull = pkEdge0; return true; }
void addEdge(int from, int to, FLOW cost) { edges[from].push_back(Edge(to, cost, size_of(edges[to]))); edges[to].push_back(Edge(from, FLOW(), size_of(edges[from]) - 1)); }
int add_edge(int from, int to, T cost) { adj_[from].push_back(Edge(edgeIndex_++, from, to, cost)); return edgeIndex_; }
Tree::Node* Tree::contructTree_R( IndexVec& idxEdges ) { if ( idxEdges.empty() ) return nullptr; int idx = choiceBestSplitEdge( idxEdges ); Node* node = new Node; node->idxEdge = idx; if ( idx < 0 ) // leaf { node->tag = ~uint32( mLeaves.size() ); node->front = nullptr; node->back = nullptr; mLeaves.push_back( Leaf() ); Leaf& data = mLeaves.back(); data.node = node; data.edges.swap( idxEdges ); return node; } else { node->tag = uint32( mNodes.size() ); mNodes.push_back( node ); } //triList.erase( cIter ); IndexVec idxFronts; IndexVec idxBacks; Plane& plane = mEdges[ idx ].plane; for( IndexVec::iterator iter( idxEdges.begin() ) , itEnd( idxEdges.end() ) ; iter != itEnd ; ++iter ) { int idxTest = *iter; Edge& edgeTest = mEdges[ idxTest ]; Vec2f vSplit[2]; switch ( plane.splice( edgeTest.v , vSplit ) ) { case SIDE_FRONT: case SIDE_IN: idxFronts.push_back( idxTest ); break; case SIDE_BACK: idxBacks.push_back( idxTest ); break; case SIDE_SPLIT: { idxFronts.push_back( idxTest ); idxBacks.push_back( (int)mEdges.size() ); mEdges.push_back( Edge() ); Edge& edge = mEdges.back(); edge.v[0] = vSplit[0]; edge.v[1] = vSplit[1]; edge.plane = edgeTest.plane; edge.idx = edgeTest.idx; } break; } } node->front = contructTree_R( idxFronts ); if ( node->front ) node->front->parent = node; node->back = contructTree_R( idxBacks ); if ( node->back ) node->back->parent = node; node->tag = 0; return node; }
void PolygonPathFinder::setup(const Vector<Vector2>& p_points, const Vector<int>& p_connections) { ERR_FAIL_COND(p_connections.size()&1); points.clear(); edges.clear(); //insert points int point_count=p_points.size(); points.resize(point_count+2); bounds=Rect2(); for(int i=0;i<p_points.size();i++) { points[i].pos=p_points[i]; points[i].penalty=0; outside_point.x = i==0?p_points[0].x:(MAX( p_points[i].x, outside_point.x )); outside_point.y = i==0?p_points[0].y:(MAX( p_points[i].y, outside_point.y )); if (i==0) { bounds.pos=points[i].pos; } else { bounds.expand_to(points[i].pos); } } outside_point.x+=20.451+Math::randf()*10.2039; outside_point.y+=21.193+Math::randf()*12.5412; //insert edges (which are also connetions) for(int i=0;i<p_connections.size();i+=2) { Edge e(p_connections[i],p_connections[i+1]); ERR_FAIL_INDEX(e.points[0],point_count); ERR_FAIL_INDEX(e.points[1],point_count); points[p_connections[i]].connections.insert(p_connections[i+1]); points[p_connections[i+1]].connections.insert(p_connections[i]); edges.insert(e); } //fill the remaining connections based on visibility for(int i=0;i<point_count;i++) { for(int j=i+1;j<point_count;j++) { if (edges.has(Edge(i,j))) continue; //if in edge ignore Vector2 from=points[i].pos; Vector2 to=points[j].pos; if (!_is_point_inside(from*0.5+to*0.5)) //connection between points in inside space continue; bool valid=true; for (Set<Edge>::Element *E=edges.front();E;E=E->next()) { const Edge& e=E->get(); if (e.points[0]==i || e.points[1]==i || e.points[0]==j || e.points[1]==j ) continue; Vector2 a = points[e.points[0]].pos; Vector2 b = points[e.points[1]].pos; if (Geometry::segment_intersects_segment_2d(a,b,from,to,NULL)) { valid=false; break; } } if (valid) { points[i].connections.insert(j); points[j].connections.insert(i); } } } }
void Link(int x, int y, int z){ E[++ tot] = Edge(y, Last[x], z), Last[x] = tot; }
int main() { Vertex v1, v2, v3; std::vector<Edge> v {Edge(v1, v2, 1.0), Edge(v2, v3, 2.0), Edge(v3, v1, 5.0)}; return 0; }
Edge Edge::reversed() const { return Edge(toVertex, fromVertex); }
R2 H(int i) const { ASSERTION(i>=0 && i <3); R2 E=Edge(i);return E.perp()/(2.*this->mesure());} // heigth
TYPED_TEST_P(BipartiteGraphTest, addEdge) { this->checkAddEdge(2, Edge(0, 5), {Edge(0, 5)}, {Edge(5, 0), Edge(0, 1), Edge(0, 0), Edge(0, 4), Edge(0, 6), Edge(1, 5), Edge(5, 5), Edge(1, 7), Edge(7, 1)}); this->checkAddEdge(4, Edge(5, 0), {Edge(0, 5), Edge(5, 0)}, {Edge(0, 1), Edge(0, 0), Edge(0, 4), Edge(0, 6), Edge(1, 5), Edge(5, 5), Edge(1, 7), Edge(7, 1)}); this->checkAddEdge(6, Edge(1, 7), {Edge(0, 5), Edge(5, 0), Edge(1, 7)}, {Edge(0, 1), Edge(0, 0), Edge(0, 4), Edge(0, 6), Edge(1, 5), Edge(5, 5), Edge(7, 1)}); this->checkAddEdge(6, Edge(5, 5), {Edge(0, 5), Edge(5, 0), Edge(1, 7), Edge(5, 5)}, {Edge(0, 1), Edge(0, 0), Edge(0, 4), Edge(0, 6), Edge(1, 5), Edge(7, 1)}); this->checkAddEdge(7, Edge(5, 6), {Edge(0, 5), Edge(5, 0), Edge(1, 7), Edge(5, 5), Edge(5, 6)}, {}); this->checkAddEdge(8, Edge(6, 5), {Edge(0, 5), Edge(5, 0), Edge(1, 7), Edge(5, 5), Edge(5, 6), Edge(6, 5)}, {}); }
//simplified version of divideEdges that accepts only one index => one edge //it is a common case that one edge still goes deeper e.g. an edge between a high leaf in the tree //and a node that goes deeper and deepper. Therefore a lot of effort can be saved by providing //a method that works with just one edge void EdgeHierarchy::divideEdges(TravelIndex t1, TravelIndex t2, int index) { QuadTreeMetaNode* m1 = _quadTree->getMeta(t1.level, t1.index); QuadTreeMetaNode* m2 = _quadTree->getMeta(t2.level, t2.index); if (_quadTree->isLeaf(m1) && _quadTree->isLeaf(m2)) { //both nodes are leafs add the edge as leaf edge and return int depth = t2.level; if (t1.level > t2.level) { depth = t1.level; } Edge tmp(_edges->at(index)); tmp.depth = depth; //leaf edge positive depth addEdge(tmp, depth); } else { int nodeIndexI; int nodeIndexJ; if (t1.level == t2.level && t1.index == t2.index) { //edge start and end point to the same meta node //can't be a leaf (-> if above) Edge e = _edges->at(index); //test where the edge belongs to nodeIndexI = _quadTree->travelSelect(e.x1, e.y1, &t1) - 1; nodeIndexJ = _quadTree->travelSelect(e.x2, e.y2, &t2) - 1; //t1=t2 } else { //different nodes => insert edges Node* n1 = _quadTree->getNode(t1.level, t1.index); Node* n2 = _quadTree->getNode(t2.level, t2.index); int depth = t2.level; if (t1.level > t2.level) { depth = t1.level; } depth = 0 - depth; //inner edge indicated by negative depth float weight = _edges->at(index).weight; addEdge(Edge(n1, n2, depth, weight), abs(depth)); Edge e = _edges->at(index); if (!_quadTree->isLeaf(m1)) { nodeIndexI = _quadTree->travelSelect(e.x1, e.y1, &t1) - 1; } if (!_quadTree->isLeaf(m2)) { nodeIndexJ = _quadTree->travelSelect(e.x2, e.y2, &t2) - 1; } } //recursive calls TravelIndex newT1(t1); TravelIndex newT2(t2); //go on with t1 if (!_quadTree->isLeaf(m1)) { _quadTree->travelDown((nodeIndexI+1), &newT1); } //and with t2 if (!_quadTree->isLeaf(m2)) { _quadTree->travelDown((nodeIndexJ+1), &newT2); } divideEdges(newT1, newT2, index); } }
Edge Traversor2VE<MAP>::end() { return Edge(NIL) ; }
void EdgeHierarchy::divideEdges(TravelIndex t1, TravelIndex t2, vector<int>* indices, float weightSum) { QuadTreeMetaNode* m1 = _quadTree->getMeta(t1.level, t1.index); QuadTreeMetaNode* m2 = _quadTree->getMeta(t2.level, t2.index); if (_quadTree->isLeaf(m1) && _quadTree->isLeaf(m2)) { //both nodes are leafs add the edge as leaf edge and return short depth = t2.level; if (t1.level > t2.level) { depth = t1.level; } Edge tmp(_edges->at(indices->at(0))); tmp.depth = depth; //leaf edge positive depth addEdge(tmp, depth); } else { vector<int>* splitArray[4][4]; float weightArray[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { splitArray[i][j] = NULL; weightArray[i][j] = 0.0f; } } if (t1.level == t2.level && t1.index == t2.index) { //edge start and end point to the same meta node //can't be a leaf (-> if above) for (int index = 0; index < indices->size(); index++) { Edge e = _edges->at(indices->at(index)); //test where the edge belongs to int i = _quadTree->travelSelect(e.x1, e.y1, &t1) - 1; int j = _quadTree->travelSelect(e.x2, e.y2, &t2) - 1; //t1=t2 //insert it into the correct place if (splitArray[i][j] == NULL) { splitArray[i][j] = new vector<int>(); } splitArray[i][j]->push_back(indices->at(index)); weightArray[i][j] += _edges->at(indices->at(index)).weight; } } else { //different nodes => insert edges Node* n1 = _quadTree->getNode(t1.level, t1.index); Node* n2 = _quadTree->getNode(t2.level, t2.index); int depth = t2.level; if (t1.level > t2.level) { depth = t1.level; } depth = 0 - depth; //inner edge indicated by negative depth addEdge(Edge(n1, n2, depth, weightSum), abs(depth)); for (int index = 0; index < indices->size(); index++) { Edge e = _edges->at(indices->at(index)); int i = 0; int j = 0; if (!_quadTree->isLeaf(m1)) { i = _quadTree->travelSelect(e.x1, e.y1, &t1) - 1; } if (!_quadTree->isLeaf(m2)) { j = _quadTree->travelSelect(e.x2, e.y2, &t2) - 1; } //insert it into the correct place if (splitArray[i][j] == NULL) { splitArray[i][j] = new vector<int>(); } splitArray[i][j]->push_back(indices->at(index)); weightArray[i][j] += _edges->at(indices->at(index)).weight; } } //recursive calls for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (splitArray[i][j] != NULL) { TravelIndex newT1(t1); TravelIndex newT2(t2); //go on with t1 if (!_quadTree->isLeaf(m1)) { _quadTree->travelDown((i+1), &newT1); } //and with t2 if (!_quadTree->isLeaf(m2)) { _quadTree->travelDown((j+1), &newT2); } if (splitArray[i][j]->size() > 1) { divideEdges(newT1, newT2, splitArray[i][j], weightArray[i][j]); } else { //speed up for single edges divideEdges(newT1, newT2, splitArray[i][j]->at(0)); } delete splitArray[i][j]; } } } } }
void handleNode() { switch (m_node->op()) { case BitOr: handleCommutativity(); if (m_node->child2()->isInt32Constant() && !m_node->child2()->asInt32()) { convertToIdentityOverChild1(); break; } break; case BitXor: case BitAnd: handleCommutativity(); break; case BitLShift: case BitRShift: case BitURShift: if (m_node->child2()->isInt32Constant() && !(m_node->child2()->asInt32() & 0x1f)) { convertToIdentityOverChild1(); break; } break; case UInt32ToNumber: if (m_node->child1()->op() == BitURShift && m_node->child1()->child2()->isInt32Constant() && (m_node->child1()->child2()->asInt32() & 0x1f) && m_node->arithMode() != Arith::DoOverflow) { m_node->convertToIdentity(); m_changed = true; break; } break; case ArithAdd: handleCommutativity(); if (m_node->child2()->isInt32Constant() && !m_node->child2()->asInt32()) { convertToIdentityOverChild1(); break; } break; case ArithMul: handleCommutativity(); break; case ArithSub: if (m_node->child2()->isInt32Constant() && m_node->isBinaryUseKind(Int32Use)) { int32_t value = m_node->child2()->asInt32(); if (-value != value) { m_node->setOp(ArithAdd); m_node->child2().setNode( m_insertionSet.insertConstant( m_nodeIndex, m_node->origin, jsNumber(-value))); m_changed = true; break; } } break; case GetArrayLength: if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node)) foldTypedArrayPropertyToConstant(view, jsNumber(view->length())); break; case GetTypedArrayByteOffset: if (JSArrayBufferView* view = m_graph.tryGetFoldableView(m_node->child1().node())) foldTypedArrayPropertyToConstant(view, jsNumber(view->byteOffset())); break; case GetIndexedPropertyStorage: if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node)) { if (view->mode() != FastTypedArray) { prepareToFoldTypedArray(view); m_node->convertToConstantStoragePointer(view->vector()); m_changed = true; break; } else { // FIXME: It would be awesome to be able to fold the property storage for // these GC-allocated typed arrays. For now it doesn't matter because the // most common use-cases for constant typed arrays involve large arrays with // aliased buffer views. // https://bugs.webkit.org/show_bug.cgi?id=125425 } } break; case ValueRep: case Int52Rep: case DoubleRep: { // This short-circuits circuitous conversions, like ValueRep(DoubleRep(value)) or // even more complicated things. Like, it can handle a beast like // ValueRep(DoubleRep(Int52Rep(value))). // The only speculation that we would do beyond validating that we have a type that // can be represented a certain way is an Int32 check that would appear on Int52Rep // nodes. For now, if we see this and the final type we want is an Int52, we use it // as an excuse not to fold. The only thing we would need is a Int52RepInt32Use kind. bool hadInt32Check = false; if (m_node->op() == Int52Rep) { if (m_node->child1().useKind() != Int32Use) break; hadInt32Check = true; } for (Node* node = m_node->child1().node(); ; node = node->child1().node()) { if (canonicalResultRepresentation(node->result()) == canonicalResultRepresentation(m_node->result())) { m_insertionSet.insertNode( m_nodeIndex, SpecNone, Phantom, m_node->origin, m_node->child1()); if (hadInt32Check) { // FIXME: Consider adding Int52RepInt32Use or even DoubleRepInt32Use, // which would be super weird. The latter would only arise in some // seriously circuitous conversions. if (canonicalResultRepresentation(node->result()) != NodeResultJS) break; m_insertionSet.insertNode( m_nodeIndex, SpecNone, Phantom, m_node->origin, Edge(node, Int32Use)); } m_node->child1() = node->defaultEdge(); m_node->convertToIdentity(); m_changed = true; break; } switch (node->op()) { case Int52Rep: if (node->child1().useKind() != Int32Use) break; hadInt32Check = true; continue; case DoubleRep: case ValueRep: continue; default: break; } break; } break; } case Flush: { ASSERT(m_graph.m_form != SSA); Node* setLocal = nullptr; VirtualRegister local = m_node->local(); if (m_node->variableAccessData()->isCaptured()) { for (unsigned i = m_nodeIndex; i--;) { Node* node = m_block->at(i); bool done = false; switch (node->op()) { case GetLocal: case Flush: if (node->local() == local) done = true; break; case GetLocalUnlinked: if (node->unlinkedLocal() == local) done = true; break; case SetLocal: { if (node->local() != local) break; setLocal = node; done = true; break; } case Phantom: case Check: case HardPhantom: case MovHint: case JSConstant: case DoubleConstant: case Int52Constant: break; default: done = true; break; } if (done) break; } } else { for (unsigned i = m_nodeIndex; i--;) { Node* node = m_block->at(i); if (node->op() == SetLocal && node->local() == local) { setLocal = node; break; } if (accessesOverlap(m_graph, node, AbstractHeap(Variables, local))) break; } } if (!setLocal) break; m_node->convertToPhantom(); Node* dataNode = setLocal->child1().node(); DFG_ASSERT(m_graph, m_node, dataNode->hasResult()); m_node->child1() = dataNode->defaultEdge(); m_graph.dethread(); m_changed = true; break; } default: break; } }
static Edge DISCONNECTED() { return Edge(MAXFLOAT); }
static bool ResolveNormalsWithMST(ccPointCloud* cloud, const Graph& graph, CCLib::GenericProgressCallback* progressCb = 0) { assert(cloud && cloud->hasNormals()); //#define COLOR_PATCHES #ifdef COLOR_PATCHES //Test: color patches cloud->setRGBColor(ccColor::white); cloud->showColors(true); //Test: arrival time int sfIdx = cloud->getScalarFieldIndexByName("MST arrival time"); if (sfIdx < 0) sfIdx = cloud->addScalarField("MST arrival time"); ccScalarField* sf = static_cast<ccScalarField*>(cloud->getScalarField(sfIdx)); sf->fill(NAN_VALUE); cloud->setCurrentDisplayedScalarField(sfIdx); #endif //reset std::priority_queue<Edge> priorityQueue; std::vector<bool> visited; unsigned visitedCount = 0; size_t vertexCount = graph.vertexCount(); //instantiate the 'visited' table try { visited.resize(vertexCount,false); } catch(std::bad_alloc) { //not enough memory return false; } //progress notification CCLib::NormalizedProgress* nProgress(0); if (progressCb) { progressCb->reset(); progressCb->setMethodTitle("Orient normals (MST)"); progressCb->setInfo(qPrintable(QString("Compute Minimum spanning tree\nPoints: %1\nEdges: %2").arg(vertexCount).arg(graph.edgeCount()))); nProgress = new CCLib::NormalizedProgress(progressCb,static_cast<unsigned>(vertexCount)); progressCb->start(); } //while unvisited vertices remain... size_t firstUnvisitedIndex = 0; size_t patchCount = 0; size_t inversionCount = 0; while (visitedCount < vertexCount) { //find the first not-yet-visited vertex while (visited[firstUnvisitedIndex]) ++firstUnvisitedIndex; //set it as "visited" { visited[firstUnvisitedIndex] = true; ++visitedCount; //add its neighbors to the priority queue const std::set<size_t>& neighbors = graph.getVertexNeighbors(firstUnvisitedIndex); for (std::set<size_t>::const_iterator it = neighbors.begin(); it != neighbors.end(); ++it) priorityQueue.push(Edge(firstUnvisitedIndex, *it, graph.weight(firstUnvisitedIndex, *it))); if (nProgress && !nProgress->oneStep()) break; } #ifdef COLOR_PATCHES colorType patchCol[3]; ccColor::Generator::Random(patchCol); cloud->setPointColor(static_cast<unsigned>(firstUnvisitedIndex), patchCol); sf->setValue(static_cast<unsigned>(firstUnvisitedIndex),static_cast<ScalarType>(visitedCount)); #endif while(!priorityQueue.empty() && visitedCount < vertexCount) { //process next edge (with the lowest 'weight') Edge element = priorityQueue.top(); priorityQueue.pop(); //there should only be (at most) one unvisited vertex in the edge size_t v = 0; if (!visited[element.v1()]) v = element.v1(); else if (!visited[element.v2()]) v = element.v2(); else continue; //invert normal if necessary (DO THIS BEFORE SETTING THE VERTEX AS 'VISITED'!) const CCVector3& N1 = cloud->getPointNormal(static_cast<unsigned>(element.v1())); const CCVector3& N2 = cloud->getPointNormal(static_cast<unsigned>(element.v2())); if (N1.dot(N2) < 0) { if (!visited[element.v1()]) { cloud->setPointNormal(static_cast<unsigned>(v), -N1); } else { cloud->setPointNormal(static_cast<unsigned>(v), -N2); } ++inversionCount; } //set it as "visited" { visited[v] = true; ++visitedCount; //add its neighbors to the priority queue const std::set<size_t>& neighbors = graph.getVertexNeighbors(v); for (std::set<size_t>::const_iterator it = neighbors.begin(); it != neighbors.end(); ++it) priorityQueue.push(Edge(v, *it, graph.weight(v,*it))); } #ifdef COLOR_PATCHES cloud->setPointColor(static_cast<unsigned>(v), patchCol); sf->setValue(static_cast<unsigned>(v),static_cast<ScalarType>(visitedCount)); #endif if (nProgress && !nProgress->oneStep()) { visitedCount = static_cast<unsigned>(vertexCount); //early stop break; } } //new patch ++patchCount; } #ifdef COLOR_PATCHES sf->computeMinAndMax(); cloud->showSF(true); #endif if (nProgress) { delete nProgress; nProgress = 0; progressCb->stop(); } ccLog::Print(QString("[ResolveNormalsWithMST] Patches = %1 / Inversions: %2").arg(patchCount).arg(inversionCount)); return true; }
void add_Edge(int u, int v, Type dist) { edges[m++] = Edge(u, v, dist); }
/* * Gets an edge from the graph */ EdgeData *Graph::get_edge(Index a, Index b) { return this->get_edge(Edge(a, b)); }
//------------------------Delaunay triangulation---------------------------- void triangulate(const std::vector<Vector2>& vertices, std::vector<Triangle>& retTriangles, Graph& neighborhoodGraph) { //Possible check for less than 3 points, not required now std::vector<Triangle> triangles; Triangle superTriangle = createSuperTriangle(vertices); triangles.push_back(superTriangle); // Include each point one at a time into the existing triangulation for (std::vector<Vector2>::const_iterator vertIt = vertices.begin(); vertIt != vertices.end(); ++vertIt) { std::vector<Edge> edgeBuffer; // If the actual vertex lies inside the circumcircle, then the three edges of the // triangle are added to the edge buffer and the triangle is removed from list. std::vector<Triangle>::reverse_iterator rit = triangles.rbegin(); while (rit != triangles.rend()) { if (rit->isPointInCircumCircle(*vertIt)) { insertWithDuplicateCheck(edgeBuffer, Edge(rit->mP1, rit->mP2)); insertWithDuplicateCheck(edgeBuffer, Edge(rit->mP2, rit->mP3)); insertWithDuplicateCheck(edgeBuffer, Edge(rit->mP3, rit->mP1)); ++rit; rit = std::vector<Triangle>::reverse_iterator(triangles.erase(rit.base())); } else { ++rit; } } //Create triangles from the Edges for (std::vector<Edge>::iterator it = edgeBuffer.begin(); it != edgeBuffer.end(); ++it) { triangles.push_back(Triangle(it->mP1, it->mP2, *vertIt)); } } //Remove all triangles sharing a vertex with the supertriangle std::vector<Triangle>::reverse_iterator rit = triangles.rbegin(); while (rit != triangles.rend()) { Triangle t = *rit; if (t.hasCommonVertexWith(superTriangle)) { ++rit; rit = std::vector<Triangle>::reverse_iterator(triangles.erase(rit.base())); } else { ++rit; } } retTriangles = triangles; //Add neighborhood data to graph for (std::vector<Triangle>::const_iterator it = triangles.begin(); it != triangles.end(); ++it) { neighborhoodGraph.addNeighbor(it->mMidP1, it->mMidP2); neighborhoodGraph.addNeighbor(it->mMidP1, it->mMidP3); neighborhoodGraph.addNeighbor(it->mMidP2, it->mMidP1); neighborhoodGraph.addNeighbor(it->mMidP2, it->mMidP3); neighborhoodGraph.addNeighbor(it->mMidP3, it->mMidP1); neighborhoodGraph.addNeighbor(it->mMidP3, it->mMidP2); } }
// отрисовка из прошлой лабы, только берём цвета из текстуры void Triangle::draw(Canvas& canvas, Texture* texture = 0) { std::vector<TexturedPoint> points; // преобразование и упорядочивание по x transform(points); std::sort(points.begin(), points.end()); std::vector<Edge> edges; // установка границ int minY = (points.front().y() < 0) ? 0: points.front().y(); int maxY = (points.back().y() < this->maxY) ? points.back().y() : this->maxY - 1; int curY = minY; int i = 0; while (curY < maxY) { int nextY = maxY; while ( i != (int)points.size() && trunc( points[i].y()) <= curY ){ TexturedPoint a = points[i]; TexturedPoint b = points[(points.size() - i - 1 ) % points.size()]; TexturedPoint c = points[(i + 1) % points.size()]; if (b.y() > curY ) { edges.push_back(Edge(a,b)); if ( b.y() < nextY ) { nextY = b.y() ; } } if (c.y() > curY) { edges.push_back(Edge(a,c)); if ( c.y() < nextY) { nextY = c.y(); } } ++i; } while(curY <= nextY && curY <= maxY) { std::vector<TexturedPoint> borderX; for (int i = 0; i < (int)edges.size(); ++i) { int n = curY - edges[i].getA().y(); double curX = (edges[i].getA().x()) + n * edges[i].getK(); TexturedPoint texCoord(curX, curY); texCoord.calcTextureCoordinates(edges[i].getA(), edges[i].getB()); borderX.push_back(texCoord); } std::sort(borderX.begin(), borderX.end(), TexturedPoint::compX); int begin = borderX.front().x() > 0 ? borderX.front().x() : 0; for (int x = begin; x < borderX.back().x() && x < maxX; ++x) { TexturedPoint curPoint(x, curY); curPoint.calcTextureCoordinates(borderX.front(),borderX.back()); if (0 == texture) { // если текстуры нет( то как градиент ) canvas.drawPixel(x, curY, TexturedPoint::transformToColor(curPoint.getTexX(), curPoint.getTexY())); } else { canvas.drawPixel(x, curY, texture->get_color(curPoint)); } } ++curY; } std::vector<Edge>::iterator iter = edges.begin(); while (iter != edges.end()) { if ( (*iter).getB().y() < curY) { edges.erase(iter); } else { ++iter; } } } }
ConvexHull2<Real>::ConvexHull2 (int iVertexQuantity, Vector2<Real>* akVertex, Real fEpsilon, bool bOwner, Query::Type eQueryType) : ConvexHull<Real>(iVertexQuantity,fEpsilon,bOwner,eQueryType), m_kLineOrigin(Vector2<Real>::ZERO), m_kLineDirection(Vector2<Real>::ZERO) { assert(akVertex); m_akVertex = akVertex; m_akSVertex = 0; m_pkQuery = 0; Mapper2<Real> kMapper(m_iVertexQuantity,m_akVertex,m_fEpsilon); if (kMapper.GetDimension() == 0) { // The values of m_iDimension, m_aiIndex, and m_aiAdjacent were // already initialized by the ConvexHull base class. return; } if (kMapper.GetDimension() == 1) { // The set is (nearly) collinear. The caller is responsible for // creating a ConvexHull1 object. m_iDimension = 1; m_kLineOrigin = kMapper.GetOrigin(); m_kLineDirection = kMapper.GetDirection(0); return; } m_iDimension = 2; int i0 = kMapper.GetExtremeIndex(0); int i1 = kMapper.GetExtremeIndex(1); int i2 = kMapper.GetExtremeIndex(2); m_akSVertex = WM4_NEW Vector2<Real>[m_iVertexQuantity]; int i; if (eQueryType != Query::QT_RATIONAL && eQueryType != Query::QT_FILTERED) { // Transform the vertices to the square [0,1]^2. Vector2<Real> kMin = kMapper.GetMin(); Real fScale = ((Real)1.0)/kMapper.GetMaxRange(); for (i = 0; i < m_iVertexQuantity; i++) { m_akSVertex[i] = (m_akVertex[i] - kMin)*fScale; } Real fExpand; if (eQueryType == Query::QT_INT64) { // Scale the vertices to the square [0,2^{20}]^2 to allow use of // 64-bit integers. fExpand = (Real)(1 << 20); m_pkQuery = WM4_NEW Query2Int64<Real>(m_iVertexQuantity, m_akSVertex); } else if (eQueryType == Query::QT_INTEGER) { // Scale the vertices to the square [0,2^{24}]^2 to allow use of // TInteger. fExpand = (Real)(1 << 24); m_pkQuery = WM4_NEW Query2TInteger<Real>(m_iVertexQuantity, m_akSVertex); } else // eQueryType == Query::QT_REAL { // No scaling for floating point. fExpand = (Real)1.0; m_pkQuery = WM4_NEW Query2<Real>(m_iVertexQuantity,m_akSVertex); } for (i = 0; i < m_iVertexQuantity; i++) { m_akSVertex[i] *= fExpand; } } else { // No transformation needed for exact rational arithmetic or filtered // predicates. size_t uiSize = m_iVertexQuantity*sizeof(Vector2<Real>); System::Memcpy(m_akSVertex,uiSize,m_akVertex,uiSize); if (eQueryType == Query::QT_RATIONAL) { m_pkQuery = WM4_NEW Query2TRational<Real>(m_iVertexQuantity, m_akSVertex); } else // eQueryType == Query::QT_FILTERED { m_pkQuery = WM4_NEW Query2Filtered<Real>(m_iVertexQuantity, m_akSVertex,m_fEpsilon); } } Edge* pkE0; Edge* pkE1; Edge* pkE2; if (kMapper.GetExtremeCCW()) { pkE0 = WM4_NEW Edge(i0,i1); pkE1 = WM4_NEW Edge(i1,i2); pkE2 = WM4_NEW Edge(i2,i0); } else { pkE0 = WM4_NEW Edge(i0,i2); pkE1 = WM4_NEW Edge(i2,i1); pkE2 = WM4_NEW Edge(i1,i0); } pkE0->Insert(pkE2,pkE1); pkE1->Insert(pkE0,pkE2); pkE2->Insert(pkE1,pkE0); Edge* pkHull = pkE0; for (i = 0; i < m_iVertexQuantity; i++) { if (!Update(pkHull,i)) { pkHull->DeleteAll(); return; } } pkHull->GetIndices(m_iSimplexQuantity,m_aiIndex); pkHull->DeleteAll(); }
///\todo Enable this codepath. This if rom Geometric Tools for Computer Graphics, /// but the algorithm in the book is broken and does not take into account the /// direction of the gradient to determine the proper region of intersection. /// Instead using a slower code path above. float3 Triangle::ClosestPoint(const Line &line, float3 *otherPt) const { float3 e0 = b - a; float3 e1 = c - a; float3 v_p = a - line.pos; float3 d = line.dir; float v_p_dot_e0 = Dot(v_p, e0); float v_p_dot_e1 = Dot(v_p, e1); float v_p_dot_d = Dot(v_p, d); float3x3 m; m[0][0] = Dot(e0, e0); m[0][1] = Dot(e0, e1); m[0][2] = -Dot(e0, d); m[1][0] = m[0][1]; m[1][1] = Dot(e1, e1); m[1][2] = -Dot(e1, d); m[2][0] = m[0][2]; m[2][1] = m[1][2]; m[2][2] = Dot(d, d); float3 B(-v_p_dot_e0, -v_p_dot_e1, v_p_dot_d); float3 uvt; bool success = m.SolveAxb(B, uvt); if (!success) { float t1, t2, t3; float s1, s2, s3; LineSegment e1 = Edge(0); LineSegment e2 = Edge(1); LineSegment e3 = Edge(2); float d1 = e1.Distance(line, &t1, &s1); float d2 = e2.Distance(line, &t2, &s2); float d3 = e3.Distance(line, &t3, &s3); if (d1 < d2 && d1 < d3) { if (otherPt) *otherPt = line.GetPoint(s1); return e1.GetPoint(t1); } else if (d2 < d3) { if (otherPt) *otherPt = line.GetPoint(s2); return e2.GetPoint(t2); } else { if (otherPt) *otherPt = line.GetPoint(s3); return e3.GetPoint(t3); } } if (uvt.x < 0.f) { // Clamp to u == 0 and solve again. float m_00 = m[2][2]; float m_01 = -m[1][2]; float m_10 = -m[2][1]; float m_11 = m[1][1]; float det = m_00 * m_11 - m_01 * m_10; float v = m_00 * B[1] + m_01 * B[2]; float t = m_10 * B[1] + m_11 * B[2]; v /= det; t /= det; if (v < 0.f) { // Clamp to v == 0 and solve for t. t = B[2] / m[2][2]; // The solution is (u,v,t)=(0,0,t). if (otherPt) *otherPt = line.GetPoint(t); return a; } else if (v > 1.f) { // Clamp to v == 1 and solve for t. t = (B[2] - m[2][1]) / m[2][2]; // The solution is (u,v,t)=(0,1,t). if (otherPt) *otherPt = line.GetPoint(t); return c; // == a + v*e1 } else { // The solution is (u,v,t)=(0,v,t). if (otherPt) *otherPt = line.GetPoint(t); return a + v * e1; } } else if (uvt.y < 0.f) { // Clamp to v == 0 and solve again. float m_00 = m[2][2]; float m_01 = -m[0][2]; float m_10 = -m[2][0]; float m_11 = m[0][0]; float det = m_00 * m_11 - m_01 * m_10; float u = m_00 * B[0] + m_01 * B[2]; float t = m_10 * B[0] + m_11 * B[2]; u /= det; t /= det; if (u < 0.f) { // Clamp to u == 0 and solve for t. t = B[2] / m[2][2]; // The solution is (u,v,t)=(0,0,t). if (otherPt) *otherPt = line.GetPoint(t); return a; } else if (u > 1.f) { // Clamp to u == 1 and solve for t. t = (B[2] - m[2][0]) / m[2][2]; // The solution is (u,v,t)=(1,0,t). if (otherPt) *otherPt = line.GetPoint(t); return b; } else { // The solution is (u, 0, t). if (otherPt) *otherPt = line.GetPoint(t); return a + u * e0; } } else if (uvt.x + uvt.y > 1.f) { // Clamp to v = 1-u and solve again. float m_00 = m[2][2]; float m_01 = m[1][2] - m[0][2]; float m_10 = m_01; float m_11 = m[0][0] + m[1][1] - 2.f * m[0][1]; float det = m_00 * m_11 - m_01 * m_10; float b0 = m[1][1] - m[0][1] + v_p_dot_e1 - v_p_dot_e0; float b1 = -m[1][2] + v_p_dot_d; float u = m_00 * b0 + m_01 * b1; float t = m_10 * b0 + m_11 * b1; u /= det; t /= det; if (otherPt) *otherPt = line.GetPoint(t); if (u < 0.f) { // The solution is (u,v,t)=(0,1,t) return c; } if (u > 1.f) { // The solution is (u,v,t)=(1,0,t) return b; } return a + u*e0 + (1.f-u)*e1; } else // All parameters are within range, so the triangle and the line segment intersect, and the intersection point is the closest point. { if (otherPt) *otherPt = line.GetPoint(uvt.z); return a + uvt.x * e0 + uvt.y * e1; } }
void Graph :: addEdge(const Edge&edge) { edges.push_back(edge); matrix[edge.start].push_back(edge); matrix[edge.finish].push_back(Edge(edge.finish, edge.start, edge.weight)); }
///\todo Enable this codepath. This if rom Geometric Tools for Computer Graphics, /// but the algorithm in the book is broken and does not take into account the /// direction of the gradient to determine the proper region of intersection. /// Instead using a slower code path above. /// [groupSyntax] float3 Triangle::ClosestPoint(const LineSegment &lineSegment, float3 *otherPt) const { float3 e0 = b - a; float3 e1 = c - a; float3 v_p = a - lineSegment.a; float3 d = lineSegment.b - lineSegment.a; // Q(u,v) = a + u*e0 + v*e1 // L(t) = ls.a + t*d // Minimize the distance |Q(u,v) - L(t)|^2 under u >= 0, v >= 0, u+v <= 1, t >= 0, t <= 1. float v_p_dot_e0 = Dot(v_p, e0); float v_p_dot_e1 = Dot(v_p, e1); float v_p_dot_d = Dot(v_p, d); float3x3 m; m[0][0] = Dot(e0, e0); m[0][1] = Dot(e0, e1); m[0][2] = -Dot(e0, d); m[1][0] = m[0][1]; m[1][1] = Dot(e1, e1); m[1][2] = -Dot(e1, d); m[2][0] = m[0][2]; m[2][1] = m[1][2]; m[2][2] = Dot(d, d); float3 B(-v_p_dot_e0, -v_p_dot_e1, v_p_dot_d); float3 uvt; bool success = m.SolveAxb(B, uvt); if (!success) { float t1, t2, t3; float s1, s2, s3; LineSegment e1 = Edge(0); LineSegment e2 = Edge(1); LineSegment e3 = Edge(2); float d1 = e1.Distance(lineSegment, &t1, &s1); float d2 = e2.Distance(lineSegment, &t2, &s2); float d3 = e3.Distance(lineSegment, &t3, &s3); if (d1 < d2 && d1 < d3) { if (otherPt) *otherPt = lineSegment.GetPoint(s1); return e1.GetPoint(t1); } else if (d2 < d3) { if (otherPt) *otherPt = lineSegment.GetPoint(s2); return e2.GetPoint(t2); } else { if (otherPt) *otherPt = lineSegment.GetPoint(s3); return e3.GetPoint(t3); } } if (uvt.x < 0.f) { // Clamp to u == 0 and solve again. float m_00 = m[2][2]; float m_01 = -m[1][2]; float m_10 = -m[2][1]; float m_11 = m[1][1]; float det = m_00 * m_11 - m_01 * m_10; float v = m_00 * B[1] + m_01 * B[2]; float t = m_10 * B[1] + m_11 * B[2]; v /= det; t /= det; if (v < 0.f) { // Clamp to v == 0 and solve for t. t = B[2] / m[2][2]; t = Clamp01(t); // The solution for t must also be in the range [0,1]. // The solution is (u,v,t)=(0,0,t). if (otherPt) *otherPt = lineSegment.GetPoint(t); return a; } else if (v > 1.f) { // Clamp to v == 1 and solve for t. t = (B[2] - m[2][1]) / m[2][2]; t = Clamp01(t); // The solution is (u,v,t)=(0,1,t). if (otherPt) *otherPt = lineSegment.GetPoint(t); return c; // == a + v*e1 } else if (t < 0.f) { // Clamp to t == 0 and solve for v. v = B[1] / m[1][1]; // mathassert(EqualAbs(v, Clamp01(v))); v = Clamp01(v); // The solution for v must also be in the range [0,1]. TODO: Is this guaranteed by the above? // The solution is (u,v,t)=(0,v,0). if (otherPt) *otherPt = lineSegment.a; return a + v * e1; } else if (t > 1.f) { // Clamp to t == 1 and solve for v. v = (B[1] - m[1][2]) / m[1][1]; // mathassert(EqualAbs(v, Clamp01(v))); v = Clamp01(v); // The solution for v must also be in the range [0,1]. TODO: Is this guaranteed by the above? // The solution is (u,v,t)=(0,v,1). if (otherPt) *otherPt = lineSegment.b; return a + v * e1; } else { // The solution is (u,v,t)=(0,v,t). if (otherPt) *otherPt = lineSegment.GetPoint(t); return a + v * e1; } } else if (uvt.y < 0.f) { // Clamp to v == 0 and solve again. float m_00 = m[2][2]; float m_01 = -m[0][2]; float m_10 = -m[2][0]; float m_11 = m[0][0]; float det = m_00 * m_11 - m_01 * m_10; float u = m_00 * B[0] + m_01 * B[2]; float t = m_10 * B[0] + m_11 * B[2]; u /= det; t /= det; if (u < 0.f) { // Clamp to u == 0 and solve for t. t = B[2] / m[2][2]; t = Clamp01(t); // The solution for t must also be in the range [0,1]. // The solution is (u,v,t)=(0,0,t). if (otherPt) *otherPt = lineSegment.GetPoint(t); return a; } else if (u > 1.f) { // Clamp to u == 1 and solve for t. t = (B[2] - m[2][0]) / m[2][2]; t = Clamp01(t); // The solution for t must also be in the range [0,1]. // The solution is (u,v,t)=(1,0,t). if (otherPt) *otherPt = lineSegment.GetPoint(t); return b; } else if (t < 0.f) { // Clamp to t == 0 and solve for u. u = B[0] / m[0][0]; // mathassert(EqualAbs(u, Clamp01(u))); u = Clamp01(u); // The solution for u must also be in the range [0,1]. if (otherPt) *otherPt = lineSegment.a; return a + u * e0; } else if (t > 1.f) { // Clamp to t == 1 and solve for u. u = (B[0] - m[0][2]) / m[0][0]; // mathassert(EqualAbs(u, Clamp01(u))); u = Clamp01(u); // The solution for u must also be in the range [0,1]. if (otherPt) *otherPt = lineSegment.b; return a + u * e0; } else { // The solution is (u, 0, t). if (otherPt) *otherPt = lineSegment.GetPoint(t); return a + u * e0; } } else if (uvt.z < 0.f) { if (otherPt) *otherPt = lineSegment.a; // Clamp to t == 0 and solve again. float m_00 = m[1][1]; float m_01 = -m[0][1]; float m_10 = -m[1][0]; float m_11 = m[0][0]; float det = m_00 * m_11 - m_01 * m_10; float u = m_00 * B[0] + m_01 * B[1]; float v = m_10 * B[0] + m_11 * B[1]; u /= det; v /= det; if (u < 0.f) { // Clamp to u == 0 and solve for v. v = B[1] / m[1][1]; v = Clamp01(v); return a + v*e1; } else if (v < 0.f) { // Clamp to v == 0 and solve for u. u = B[0] / m[0][0]; u = Clamp01(u); return a + u*e0; } else if (u+v > 1.f) { // Set v = 1-u and solve again. // u = (B[0] - m[0][0]) / (m[0][0] - m[0][1]); // mathassert(EqualAbs(u, Clamp01(u))); // u = Clamp01(u); // The solution for u must also be in the range [0,1]. // return a + u*e0; // Clamp to v = 1-u and solve again. float m_00 = m[2][2]; float m_01 = m[1][2] - m[0][2]; float m_10 = m_01; float m_11 = m[0][0] + m[1][1] - 2.f * m[0][1]; float det = m_00 * m_11 - m_01 * m_10; float b0 = m[1][1] - m[0][1] + v_p_dot_e1 - v_p_dot_e0; float b1 = -m[1][2] + v_p_dot_d; float u = m_00 * b0 + m_01 * b1; u /= det; u = Clamp01(u); float t = m_10 * b0 + m_11 * b1; t /= det; t = Clamp01(t); if (otherPt) *otherPt = lineSegment.GetPoint(t); return a + u*e0 + (1.f-u)*e1; } else { // The solution is (u, v, 0) return a + u * e0 + v * e1; } } else if (uvt.z > 1.f) { if (otherPt) *otherPt = lineSegment.b; // Clamp to t == 1 and solve again. float m_00 = m[1][1]; float m_01 = -m[0][1]; float m_10 = -m[1][0]; float m_11 = m[0][0]; float det = m_00 * m_11 - m_01 * m_10; float u = m_00 * (B[0]-m[0][2]) + m_01 * (B[1]-m[1][2]); float v = m_10 * (B[0]-m[0][2]) + m_11 * (B[1]-m[1][2]); u /= det; v /= det; if (u < 0.f) { // Clamp to u == 0 and solve again. v = (B[1] - m[1][2]) / m[1][1]; v = Clamp01(v); return a + v*e1; } else if (u > 1.f) { // Clamp to u == 1 and solve again. v = (B[1] - m[1][0] - m[1][2]) / m[1][1]; v = Clamp01(v); // The solution for v must also be in the range [0,1]. TODO: Is this guaranteed by the above? // The solution is (u,v,t)=(1,v,1). return a + e0 + v*e1; } else if (u+v > 1.f) { // Set v = 1-u and solve again. // Q(u,1-u) = a + u*e0 + e1 - u*e1 = a+e1 + u*(e0-e1) // L(1) = ls.a + t*d = ls.b // Minimize the distance |Q(u,1-u) - L(1)| = |a+e1+ls.b + u*(e0-e1)| // |K + u*(e0-e1)|^2 = (K,K) + 2*u(K,e0-e1) + u^2 * (e0-e1,e0-e1) // grad = 2*(K,e0-e1) + 2*u*(e0-e1,e0-e1) == 0 // u == (K,e1-e0) / (e0-e1,e0-e1) u = (B[0] - m[0][1] - m[0][2]) / (m[0][0] - m[0][1]); // u = Dot(a + e1 + lineSegment.b, e1 - e0) / Dot(e0-e1, e0-e1); // mathassert(EqualAbs(u, Clamp01(u))); u = Clamp01(u); return a + u*e0 + (1-u)*e1; } else { // The solution is (u, v, 1) return a + u*e0 + v*e1; } } else if (uvt.x + uvt.y > 1.f) { // Clamp to v = 1-u and solve again. float m_00 = m[2][2]; float m_01 = m[1][2] - m[0][2]; float m_10 = m_01; float m_11 = m[0][0] + m[1][1] - 2.f * m[0][1]; float det = m_00 * m_11 - m_01 * m_10; float b0 = m[1][1] - m[0][1] + v_p_dot_e1 - v_p_dot_e0; float b1 = -m[1][2] + v_p_dot_d; float u = m_00 * b0 + m_01 * b1; float t = m_10 * b0 + m_11 * b1; u /= det; t /= det; t = Clamp01(t); if (otherPt) *otherPt = lineSegment.GetPoint(t); if (u < 0.f) { // The solution is (u,v,t)=(0,1,t) return c; } if (u > 1.f) { // The solution is (u,v,t)=(1,0,t) return b; } mathassert(t >= 0.f); mathassert(t <= 1.f); return a + u*e0 + (1.f-u)*e1; } else // All parameters are within range, so the triangle and the line segment intersect, and the intersection point is the closest point. { if (otherPt) *otherPt = lineSegment.GetPoint(uvt.z); return a + uvt.x * e0 + uvt.y * e1; } }
void add(ELV &g, int u, int v, int w) { g[u].push_back(Edge(v, w)); }
Triangle::Triangle() { M_points[0] = M_points[1] = M_points[2] = Point(); M_edges[0] = M_edges[1] = M_edges[2] = Edge(); }