Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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);
		}
	}
}