Reference &Reference::append( const Reference &ref ) { Segment::List segments = ref.segments(); Segment::List::ConstIterator it; for( it = segments.constBegin(); it != segments.constEnd(); ++it ) { mSegments.append( *it ); } return *this; }
BoundingBox3D BSPTree2D::Node::findBoundingBox( Segment::List& inSegmentList ) { BoundingBox3D bbox; for(Segment::List::iterator segmentItr = inSegmentList.begin(); segmentItr != inSegmentList.end(); segmentItr++) { bbox.add(segmentItr->point1()); bbox.add(segmentItr->point2()); } return bbox; }
BSPTree2D* BSPTree2D::create( const PointList& inPointList, std::string& outState, double inTol /*= 1.0e-13*/, size_t inMaxNodeCount /*= 7000*/, size_t numAxialDivsn /*= 0*/ ) { Segment::List seglist; PointList::const_iterator itrP1 = inPointList.begin(); PointList::const_iterator itrP2 = inPointList.begin(); for(itrP2++;itrP2 != inPointList.end();itrP1++,itrP2++) seglist.push_back(Segment(*itrP1,*itrP2)); outState.clear(); Node* baseNode = new Node(seglist,outState,inTol,inMaxNodeCount,numAxialDivsn); if(!outState.empty()) { delete baseNode; return nullptr; } return new BSPTree2D(baseNode,inTol); }
BSPTree2D* BSPTree2D::create( const PointArray& inPointArray, std::string& outState, double inTol /*= 1.0e-13*/, size_t inMaxNodeCount /*= 7000*/, size_t numAxialDivsn /*= 0*/ ) { Segment::List seglist; for(auto itPoint = inPointArray.begin(); itPoint != --inPointArray.end();) { auto & p1 = *itPoint, & p2 = *(++itPoint); seglist.push_back(Segment(p1, p2)); } outState.clear(); Node* baseNode = new Node(seglist,outState,inTol,inMaxNodeCount,numAxialDivsn); if(!outState.empty()) { delete baseNode; return nullptr; } return new BSPTree2D(baseNode,inTol); }
void BSPTree2D::Node::genSplittingLine( Segment::List& inSegmentList, double inTol, size_t inNumMidPlaneDivsn /*= 0*/ ) { assert(inSegmentList.size()); if(inNumMidPlaneDivsn > 0) return genMidLine(findBoundingBox(inSegmentList),(MidLineType)(inNumMidPlaneDivsn%2)); Segment seg = inSegmentList.back(); inSegmentList.pop_back(); if(seg.point1().distance(seg.point2()) < inTol) { if(inSegmentList.size()) return genSplittingLine(inSegmentList,inTol); assert(0);//"Huge problem in seg magnitude" return; } mSeg = new Segment(seg); }
BSPTree2D::Node::Node( Segment::List& inSegmentList, std::string& outState, double inTol, size_t inMaxDepth, size_t inNumMidPlaneDivsn /*= 0*/ ) :mSeg(nullptr) { mChild[LEFT] = nullptr; mChild[RIGHT] = nullptr; if(!inMaxDepth) { outState = "BSP Build Fail Due To high No. Of Segment "; return; } // Select best possible partitioning plane based on the input geometry genSplittingLine(inSegmentList,inTol,inNumMidPlaneDivsn); Segment::List leftList, rightList; // Test each polygon against the dividing plane, adding them // to the front list, back list, or both, as appropriate for(Segment::List::iterator itrSeg = inSegmentList.begin(); itrSeg != inSegmentList.end(); itrSeg++) { Segment leftPart,rightPart; switch (itrSeg->split(*mSeg,leftPart,rightPart,inTol)) { case COLLINEAR: break; // Whats done in this case depends on what type of tree is being // built. For a node-storing tree, the polygon is stored inside // the node at this level (along with all other polygons coplanar // with the plane). Here, for a leaf-storing tree, coplanar polygons // are sent to either side of the plane. In this case, to the front // side, by falling through to the next case case LEFTSIDE: leftList.push_back(*itrSeg); break; case RIGHTSIDE: rightList.push_back(*itrSeg); break; case STRADDLING: // Split polygon to plane and send a part to each side of the plane leftList.push_back(leftPart); rightList.push_back(rightPart); break; default: break; } } //if (inPolygonList.size() <= _DT_BSP_MIN_POLYGON_) //{ // // If criterion for a leaf is matched, create a leaf node from remaining polygons // // //return new FacetBSPNode(polygons); //} // Recursively build child subtrees and return new tree root combining them size_t numMidPlaneDivsn = inNumMidPlaneDivsn>0?inNumMidPlaneDivsn-1:0; if(leftList.size()) mChild[LEFT] = new Node(leftList,outState,inTol,inMaxDepth-1,numMidPlaneDivsn); if (!outState.empty()) return; if(rightList.size()) mChild[RIGHT] = new Node(rightList,outState,inTol,inMaxDepth-1,numMidPlaneDivsn); if (!outState.empty()) return; }
void Object::doCollision(Background &bg) { WallSet set; const TileMap &tilemap = bg.getTileMap(); /* get tile bounds of circle */ int l = (int)floor((pos.x-radius)/8), r = (int)ceil((pos.x+radius)/8); int t = (int)floor((pos.y-radius)/8), b = (int)ceil((pos.y+radius)/8); /* add all walls declared for the tiles */ for (int j= t; j < b; j++) for (int i= l; i < r; i++) { const TileMapEntry *tme = tilemap.index(i,j); set.addFromTile(tme); } /* we want to ignore certain walls (tops of ladders when climbing through them, and one way walls). This loop removes walls from the ignore list if the object doesn't intersect with it */ { Wall::CPListIterator i; for (i = ignore.begin(); i != ignore.end();) { const Segment &s = (**i).wall.segment; if (!s.intersect(Circle(pos, radius))) ignore.erase(i++); else ++i; } } /* all the collision gets messed up when the sometimes here/sometimes not walls enter the equation */ bool irregularWalls = false; { WallSet::Iterator i; for (i = set.begin(); i != set.end(); ++i) { const Edge::EdgeType &type = (**i).wall.type; if (type == Edge::LADDER_TOP || type == Edge::ONE_WAY) { irregularWalls = true; break; } } } /* check all walls found above for collision */ WallSet::Iterator i; Segment::List collide; for (i = set.begin(); i != set.end(); ++i) { const Wall &w = (**i); const Segment &s = w.wall.segment; preProcessWall(**i); /* don't process it if it's in the ignore list... */ if (std::find(ignore.begin(), ignore.end(), &w) != ignore.end()) continue; /* we wait to do segment-circle collision if we're doing complicated collision */ if (!irregularWalls) { /* ...or if it doesn't even intersect the circle */ if (!s.intersect(Circle(pos, radius))) continue; } if (processWall(**i)) { if (irregularWalls) collide.push_back((**i).wall.segment); else collideWall((**i).wall.segment); } } /* the problem with using normal collision: if we have some walls that are here today/gone tomorrow the collision will be irregular because of the way segment-circle collision works. when the circle collides with two walls with the same normal near their intersection point, one of the segments will (probably) provide a shunt vector that is not the normal, whereas the other (probably) will. This will push the object in the direction of the vector, even though it shouldn't. how to fix it (basic idea): * combine collinear segment that intersect at a point like in Walls::addWall * sometimes walls will exist on the other side of this newly created wall. If the object is on the normal side, remove this "T-Bone" wall. */ if (irregularWalls) { /* combine collinear segments that intersect at a point, like in Walls::addWall */ Segment::ListIterator k, l; for (k = collide.begin(); k != collide.end();) { bool removed = false; const Segment &s = *k; l = k; for (++l; l != collide.end(); ++l) { const Segment &t = *l; Point p0, p1; Segment::IntersectType it = s.intersect(t,p0,p1); if (it != Segment::COLLINEAR_POINT) continue; if (s.normal != t.normal) continue; if (p0 == t.p0) collide.push_back(Segment(s.p0, t.p1)); else collide.push_back(Segment(t.p0, s.p1)); collide.erase(k++); if (k == l) collide.erase(k++); else collide.erase(l); removed = true; break; } if (!removed) ++k; } /* look for edges that T-bone another segment */ for (k = collide.begin(); k != collide.end();) { bool removed = false; const Segment &s = *k; l = k; for (++l; l != collide.end(); ++l) { const Segment &t = *l; Point p0, p1; Segment::IntersectType it = s.intersect(t,p0,p1); if (it != Segment::POINT) continue; /* we know that the combined segments are at the end of the collide list, therefore if two segments are T-boned, the top of the "T" must be t and the base of the "T" must be s. Therefore, if the intersection point is t, we know it can't be a T-bone. */ if (p0 == t.p0 || p0 == t.p1) continue; /* find which point connects the top of the "T" to the base. */ if (p0 == s.p0) { /* we'll erase the base if the top normal points away from the base and if the object is on the top normal side */ if (!t.faces(s.p1) && t.faces(pos)) { collide.erase(k++); removed = true; break; } } else if (p0 == s.p1) { /* we'll erase the base if the top normal points away from the base and if the object is on the top normal side */ if (!t.faces(s.p0) && t.faces(pos)) { collide.erase(k++); removed = true; break; } } } if (!removed) ++k; } /* shunt object around to avoid collision */ for (k = collide.begin(); k != collide.end(); ++k) { const Segment &s = *k; /* this check is necessary, if we check walls without moving the object, we get false positives */ if (s.intersect(Circle(pos, radius))) collideWall(*k); } } }