예제 #1
0
double DistanceTransform::rayTriangleIntersection(int nt, const Point3f& begin, const Point3f& end)
{
	const double TOLERANCE = 1.0e-6;
	Vector3f norm;
	Point3f v0, v1, v2;
	p_Surf->getTriNormal(nt, norm);
	p_Surf->getTriVerts(nt, v0, v1, v2);

	double dbeg = signedDist2Plane(begin, v0, norm);
	double dend = signedDist2Plane(end, v0, norm);
	if(fabs(dbeg) < TOLERANCE) {
		if(pointInTriangle(begin, v0, v1, v2, norm)) return 0;
	}
	if(fabs(dend) < TOLERANCE) {
		if(pointInTriangle(end, v0, v1, v2, norm)) return 1;
	}
	if(dbeg * dend > 0) return MAX_FLOAT;
	if(fabs(dbeg) < TOLERANCE && fabs(dend) < TOLERANCE) return 0.5;  // a hack that needs to fixed later
	double denom = DotProduct(norm, end - begin);
	double t = - dbeg / denom;
	assert (t >= 0); 
	if(t > 1) t = 1;
	Point3f intersect;
	intersect[0] = begin[0] + t*(end[0] - begin[0]);
	intersect[1] = begin[1] + t*(end[1] - begin[1]);
	intersect[2] = begin[2] + t*(end[2] - begin[2]);
	if(pointInTriangle(intersect, v0, v1, v2, norm)) return t;
	return MAX_FLOAT;
}
예제 #2
0
bool carve::triangulate::detail::vertex_info::isClipable() const {
  for (const vertex_info *v_test = next->next; v_test != prev; v_test = v_test->next) {
    if (v_test->convex) {
      continue;
    }

    if (v_test->p == prev->p ||
        v_test->p == next->p) {
      continue;
    }

    if (v_test->p == p) {
      if (v_test->next->p == prev->p &&
          v_test->prev->p == next->p) {
        return false;
      }
      if (v_test->next->p == prev->p ||
          v_test->prev->p == next->p) {
        continue;
      }
    }

    if (pointInTriangle(prev, this, next, v_test)) {
      return false;
    }
  }
  return true;
}
예제 #3
0
// checks if any point in _shape is inside the triangle formed by point and it's adjacent points
bool SteerLib::GJK_EPA::checkTriangle(std::vector<Util::Vector> _shape, Util::Vector predecessor, Util::Vector point, Util::Vector successor)
{
	for (int i = 0; i < _shape.size(); i++) {
		// checks if shapePoint at i is inside the triangle formed by point and it's adjacent points
		if (pointInTriangle(_shape.at(i), predecessor, point, successor)) {
			return true;
		}
	}
	return false;
}
예제 #4
0
double phiFunction(QPointF *points, quint32 size, quint32 layers,
QPointF point, quint32 vertexNumber, QPointF *centerPtr) {
	Vertex vertex = getVertex(size, vertexNumber);
	TriangleList triangles = getSurroundingTriangles(points, size,
		layers, vertex, centerPtr);
	for (int i = 0; i < triangles.size(); ++i) {
		if (pointInTriangle(point, triangles.at(i)))
			return phiFunction(point, triangles.at(i),
			getPoint(points, size, layers, vertex, centerPtr));
	}
	return 0;
}
예제 #5
0
			float heightInTriangleAt(glm::vec3 p, Triangle t) const {
				if(!pointInTriangle(p, t))
					return 0.0;

				const float d0 = glm::distance(glm::vec2(p), glm::vec2(t.p0));
				const float d1 = glm::distance(glm::vec2(p), glm::vec2(t.p1));
				const float d2 = glm::distance(glm::vec2(p), glm::vec2(t.p2));

				const float total = d0 + d1 + d2;
				const glm::vec3 hello = glm::normalize(glm::vec3(d0, d1, d2) / total);

				return hello.x * t.p0.z + hello.y * t.p1.z + hello.z + t.p1.z;
			}
예제 #6
0
double DistanceTransform::distance2Triangle(const Point3f& pnt, int nt, Point3f& nearPnt)
{
	double  dist, temp[3];
	Point3f v0, v1, v2;
	p_Surf->getTriVerts(nt, v0, v1, v2);
	Vector3f norm;
	p_Surf->getTriNormal(nt, norm);
	vector3 vnorm(norm[0], norm[1], norm[2]), vdiff;
	
	Point3f edgePnt;

	//1) First compute the shortest distance from the pnt to the plane of the Triangle.
	vdiff[0] = pnt[0] - v0[0];
	vdiff[1] = pnt[1] - v0[1];
	vdiff[2] = pnt[2] - v0[2];
	dist = DotProduct(vdiff, vnorm);
	nearPnt[0] = pnt[0] - dist * norm[0];
	nearPnt[1] = pnt[1] - dist * norm[1];
	nearPnt[2] = pnt[2] - dist * norm[2];

	//2) Then check if the projected point is within the triangle or not. 
	//	  if yes, then the above is the correct shortest distance.
	if(pointInTriangle(nearPnt, v0, v1, v2, norm)) {
		return fabs(dist);
	}

    //3) now, the closest point must on the edge.
	// find the nearest point on each edge.
	dist = distance2Edge(pnt, v0, v1, nearPnt);
	double edgeDist = distance2Edge(pnt, v1, v2, edgePnt);
	if(edgeDist < dist) {
		dist = edgeDist;
		nearPnt = edgePnt;
	}
	edgeDist = distance2Edge(pnt, v2, v0, edgePnt);
	if(edgeDist < dist) {
		dist = edgeDist;
		nearPnt = edgePnt;
	}
	
	assert(dist >= 0);
	return dist;
}
예제 #7
0
파일: utils.cpp 프로젝트: poseidon4o/NN-aim
Vector2 closestPointOnTriangle(Vector2 p, Vector2 v[3]) {

	if (pointInTriangle(p, v))
		return p;

	float maxDist = 10000.f;
	Vector2 closest;

	for (int i = 0; i < 3; ++i)
	{
		Vector2 temp = closestPointOnSegment(p, v[i], v[(i + 1) % 3]);
		float dist = (temp - p).lengthSq();

		if (dist < maxDist)
		{
			maxDist = dist;
			closest = temp;
		}

	}
	return closest;
}
예제 #8
0
    float rayTriangleCollision(
        const Vec3f &rayOrign, const Vec3f &rayDir,
        const Vec3f &p0, const Vec3f &p1,
        const Vec3f &p2)
    {
        Planef trigPlane(p0, p1, p2);
        float div = vecDot(rayDir, trigPlane.normal);

        if ( div == 0.0f )
            return NoIntersection;

        const float t = -(vecDot(rayOrign, trigPlane.normal) + trigPlane.d) / div;

        if ( t < 0.0f )
            return NoIntersection;

        Vec3f interscPoint = rayOrign  + rayDir * t;

        if ( pointInTriangle(interscPoint, rayOrign, p0, p1, p2) == true )
            return t;
        else
            return NoIntersection;
    }
예제 #9
0
// Checks if two co-planar triangles intersect.
bool CCLayerSorter::LayerIntersector::triangleTriangleTest(const FloatPoint& a1, const FloatPoint& b1, const FloatPoint& c1, const FloatPoint& a2, const FloatPoint& b2, const FloatPoint& c2)
{
    // Check all edges of first triangle with edges of the second one.
    if (edgeTriangleTest(a1, b1, a2, b2, c2)
            || edgeTriangleTest(a1, c1, a2, b2, c2)
            || edgeTriangleTest(b1, c1, a2, b2, c2))
        return true;

    // Check all points of the first triangle for inclusion in the second triangle.
    if ((pointInTriangle(a1, a2, b2, c2) && checkZDiff(a1))
            || (pointInTriangle(b1, a2, b2, c2) && checkZDiff(b1))
            || (pointInTriangle(c1, a2, b2, c2) && checkZDiff(c1)))
        return true;

    // Check all points of the second triangle for inclusion in the first triangle.
    if ((pointInTriangle(a2, a1, b1, c1) && checkZDiff(a2))
            || (pointInTriangle(b2, a1, b1, c1) && checkZDiff(b2))
            || (pointInTriangle(c2, a1, b1, c1) && checkZDiff(c2)))
        return true;

    return false;
}
bool SphereTriangleDetector::facecontains(const btVector3 &p,const btVector3* vertices,btVector3& normal)  {
    btVector3 lp(p);
    btVector3 lnormal(normal);

    return pointInTriangle(vertices, lnormal, &lp);
}
예제 #11
0
    float sphereTriangleCollision(
        const BoundingSphere &sphere,
        const Vec3f &dir,
        const Vec3f &p0, const Vec3f &p1,
        const Vec3f &p2, Vec3f *contactPoint)
    {
        Planef trigPlane(p0, p1, p2);
        float d = vecDot(dir, trigPlane.normal);
        float minDist = NoIntersection;

        if  ( vecDot(dir, trigPlane.normal) > 0.0 )
        {
            return NoIntersection;
        }
    
        if ( d == 0.0f )
        {
            if ( trigPlane.distance(sphere.center()) < sphere.radius() )
                return NoIntersection;
        }
        else 
        {
            const Vec3f orign = sphere.center()
                - sphere.radius()*vecNormal(trigPlane.normal);
            const float t = -(trigPlane.d + vecDot(orign, trigPlane.normal)) / d;

            if ( t >= 0.0f )
            {
            
                const Vec3f planePoint = orign + dir * t;
                if ( pointInTriangle(planePoint,
                                     vecNormal(trigPlane.normal),
                                     p0, p1, p2) )
                {
                    *contactPoint = planePoint;
                    return t;
                }
            }
        }

        float dist = spherePointDistance(sphere, dir, p0);
        if ( dist < minDist )
        {
            minDist = dist;
            *contactPoint = p0;
        }

        dist = spherePointDistance(sphere, dir, p1);
        if ( dist < minDist )
        {
            minDist = dist;
            *contactPoint = p1;
        }

        dist = spherePointDistance(sphere, dir, p2);
        if ( dist < minDist )
        {
            minDist = dist;
            *contactPoint = p2;
        }

        Vec3f edgeContactPoint;
        dist = sphereEdgeDistance(sphere, dir, p1, p0, &edgeContactPoint);
        if ( dist < minDist )
        {
            minDist = dist;
            *contactPoint = edgeContactPoint;
        }

        dist = sphereEdgeDistance(sphere, dir, p2, p1, &edgeContactPoint);
        if ( dist < minDist )
        {
            minDist = dist;
            *contactPoint = edgeContactPoint;
        }

        dist = sphereEdgeDistance(sphere, dir, p0, p2, &edgeContactPoint);
        if ( dist < minDist )
        {
            minDist = dist;
            *contactPoint = edgeContactPoint;
        }

        return minDist;
    }
예제 #12
0
bool point_in_hull(const Quadratic& quad, const _Point& pt) {
    return pointInTriangle((const Triangle&) quad, pt);
}
예제 #13
0
static void drawDebugMaterials() {
	
	if(!ACTIVEBKG || !ACTIVEBKG->exist) {
		return;
	}
	
	PolyType skip = POLY_NODRAW | POLY_HIDE;
	if(GInput->isKeyPressed(Keyboard::Key_LeftShift)) {
		skip |= POLY_TRANS | POLY_WATER;
	}
	
	Vec2f point(DANAEMouse);
	
	Entity * owner = GetFirstInterAtPos(Vec2s(point));
	TextureContainer * material = NULL;
	size_t count = 0;
	Vec2f pp[4];
	Vec2f puv[4];
	PolyType flags;
	
	float minz = std::numeric_limits<float>::max();
	
	for(size_t k = 1; k < entities.size(); k++) {
		
		EntityHandle h = EntityHandle(k);
		if(!entities[h] || !entities[h]->obj) {
			continue;
		}
		Entity * entity = entities[h];
		
		if((entity->ioflags & IO_CAMERA) || (entity->ioflags & IO_MARKER))
			continue;
		
		if(!(entity->gameFlags & GFLAG_ISINTREATZONE))
			continue;
		if((entity->gameFlags & GFLAG_INVISIBILITY))
			continue;
		if((entity->gameFlags & GFLAG_MEGAHIDE))
			continue;
		
		switch(entity->show) {
			case SHOW_FLAG_DESTROYED:    continue;
			case SHOW_FLAG_IN_INVENTORY: continue;
			case SHOW_FLAG_ON_PLAYER:    continue;
			case SHOW_FLAG_LINKED:       break;
			case SHOW_FLAG_NOT_DRAWN:    continue;
			case SHOW_FLAG_HIDDEN:       continue;
			case SHOW_FLAG_MEGAHIDE:     continue;
			case SHOW_FLAG_KILLED:       continue;
			case SHOW_FLAG_IN_SCENE:     break;
			case SHOW_FLAG_TELEPORTING:  break;
		}
		
		if(!entity->bbox2D.valid()) {
			continue;
		}
		
		for(size_t j = 0; j < entity->obj->facelist.size(); j++) {
			const EERIE_FACE & face = entity->obj->facelist[j];
			
			if(face.facetype & skip) {
				continue;
			}
			
			bool valid = true;
			bool bvalid = false;
			Vec3f p[3];
			Vec2f uv[3];
			for(size_t i = 0; i < 3; i++) {
				unsigned short v = face.vid[i];
				valid = valid && v < entity->obj->vertexlist3.size();
				if(valid) {
					if(entity->animlayer[0].cur_anim) {
						p[i] = entity->obj->vertexlist3[v].vert.p;
						uv[i] = entity->obj->vertexlist3[v].vert.uv;
					} else {
						p[i] = entity->obj->vertexlist[v].vert.p;
						uv[i] = entity->obj->vertexlist[v].vert.uv;
					}
					valid = valid && (p[i].z > 0.000001f);
					bvalid = bvalid || (p[i].x >= g_size.left && p[i].x < g_size.right
					                 && p[i].y >= g_size.top && p[i].y < g_size.bottom);
				}
			}
			
			if(!valid || !bvalid) {
				continue;
			}
			
			float z = pointInTriangle(point, p[0], p[1], p[2]);
			
			if(z > 0 && z <= minz) {
				count = 3;
				for(size_t i = 0; i < count; i++) {
					pp[i] = Vec2f(p[i].x, p[i].y);
					puv[i] = uv[i];
				}
				if(face.texid >= 0 && size_t(face.texid) < entity->obj->texturecontainer.size()) {
					material = entity->obj->texturecontainer[face.texid];
				} else {
					material = NULL;
				}
				owner = entity;
				minz = z;
				flags = face.facetype & ~(POLY_WATER | POLY_LAVA);
			}
			
		}
	}
	
	for(short z = 0; z < ACTIVEBKG->Zsize; z++)
	for(short x = 0; x < ACTIVEBKG->Xsize; x++) {
		const EERIE_BKG_INFO & feg = ACTIVEBKG->fastdata[x][z];
		
		if(!feg.treat) {
			continue;
		}
		
		for(long l = 0; l < feg.nbpolyin; l++) {
			EERIEPOLY * ep = feg.polyin[l];
			
			if(!ep) {
				continue;
			}
			
			if(ep->type & skip) {
				continue;
			}
			
			bool valid = true;
			bool bvalid = false;
			Vec3f p[4];
			for(size_t i = 0; i < ((ep->type & POLY_QUAD) ? 4u : 3u); i++) {
				TexturedVertex tv;
				tv.p = EE_RT(ep->v[i].p);
				valid = valid && (tv.p.z > 0.000001f);
				EE_P(tv.p, tv);
				bvalid = bvalid || (tv.p.x >= g_size.left && tv.p.x < g_size.right
				                 && tv.p.y >= g_size.top && tv.p.y < g_size.bottom);
				p[i] = tv.p;
			}
			
			if(!valid || !bvalid) {
				continue;
			}
			
			float z = pointInTriangle(point, p[0], p[1], p[2]);
			if(z <= 0 && (ep->type & POLY_QUAD)) {
				z = pointInTriangle(point, p[1], p[3], p[2]);
			}
			
			if(z > 0 && z <= minz) {
				count = ((ep->type & POLY_QUAD) ? 4 : 3);
				for(size_t i = 0; i < count; i++) {
					pp[i] = Vec2f(p[i].x, p[i].y);
					puv[i] = ep->v[i].uv;
				}
				material = ep->tex;
				owner = NULL;
				minz = z;
				flags = ep->type;
			}
			
		}
	}
	
	if(count) {
		
		GRenderer->SetRenderState(Renderer::DepthTest, false);
		
		drawLine2D(pp[0], pp[1], 0.1f, Color::magenta);
		drawLine2D(pp[2], pp[0], 0.1f, Color::magenta);
		if(count == 4) {
			drawLine2D(pp[2], pp[3], 0.1f, Color::magenta);
			drawLine2D(pp[3], pp[1], 0.1f, Color::magenta);
		} else {
			drawLine2D(pp[1], pp[2], 0.1f, Color::magenta);
		}
		
		Vec2f c = Vec2f(0.f);
		float miny = std::numeric_limits<float>::max();
		float maxy = std::numeric_limits<float>::min();
		for(size_t i = 0; i < count; i++) {
			c += pp[i];
			miny = std::min(miny, pp[i].y);
			maxy = std::max(maxy, pp[i].y);
		}
		c *= 1.f / count;
		
		Vec2f textpos(c.x, miny - 2 * hFontDebug->getLineHeight());
		
		std::ostringstream oss;
		
		if(owner) {
			textpos.y -= hFontDebug->getLineHeight();
		}
		if(material && material->m_pTexture) {
			textpos.y -= hFontDebug->getLineHeight();
		}
		if((flags & (POLY_WATER | POLY_LAVA)) && enviro && enviro->m_pTexture) {
			textpos.y -= hFontDebug->getLineHeight();
		}
		if(textpos.y < g_size.top + 5) {
			textpos.y = maxy + 2 * hFontDebug->getLineHeight();
		}
		
		
		if(owner) {
			drawTextCentered(hFontDebug, textpos, owner->idString(), Color::cyan);
			textpos.y += hFontDebug->getLineHeight();
		}
		if(material && material->m_pTexture) {
			drawDebugMaterialTexture(textpos, "Diffuse: ", *material->m_pTexture, Color::green);
		}
		if((flags & (POLY_WATER | POLY_LAVA)) && enviro && enviro->m_pTexture) {
			oss.str(std::string());
			oss << "Animation: ";
			oss << ((flags & (POLY_LAVA)) ? "lava" : "water");
			if(flags & POLY_FALL) {
				oss << " (flowing)";
			}
			drawDebugMaterialTexture(textpos, oss.str(), *enviro->m_pTexture, Color::yellow);
		}
		
		(void)textpos;
		
		for(size_t i = 0; i < count; i++) {
			
			oss.str(std::string());
			oss.setf(std::ios_base::fixed, std::ios_base::floatfield);
			oss.precision(2);
			oss << '(' << puv[i].x << ',' << puv[i].y << ')';
			std::string text = oss.str();
			
			Vec2f textpos = pp[i];
			if(pp[i].y < c.y) {
				textpos.y -= hFontDebug->getLineHeight();
			}
			
			if(pp[i].x < c.x) {
				Vec2i size = hFontDebug->getTextSize(text);
				textpos.x -= size.x;
			}
			
			hFontDebug->draw(textpos.x, textpos.y, text, Color::gray(0.7f));
		}
		
		GRenderer->SetRenderState(Renderer::DepthTest, true);
		
	}
	
}
예제 #14
0
			bool hasPoint(glm::vec3 point) const {
				return pointInTriangle(point, firstTriangle()) || pointInTriangle(point, secondTriangle());
			};
short int delaunay(){
	Point * point, * p;
	Triangle * T, * A, * B, * C;
	int i, e, m;
	float a, b;
	short int len;

	for(e=0, p=pHead; p; ++e, p=p->next){
		if(ABS(p->x) > ABS(p->y)){
			i = ABS(p->x) > i ? ABS(p->x) : i;
		}
		else{
			i = ABS(p->y) > i ? ABS(p->y) : i;
		}
	}
	len = e;
	if(e==2) return -100;

	T = tHead = NEWT;
	T->next = NULL;

	P0 = NEWP;
	P0->id = -1;
	P0->x = i * 3 + 1;
	P0->y = 0;
	P0->next = pHead;
	pHead = P0;

	P1 = NEWP;
	P1->id = -2;
	P1->x = 0;
	P1->y = i * 3 + 1;
	P1->next = pHead;
	pHead = P1;

	P2 = NEWP;
	P2->id = -3;
	P2->x = P2->y = -(3 * i) - 1;
	P2->next = pHead;
	pHead = P2;

	for(point = pHead->next->next->next; point; point = point->next){
		for(T=tHead; T; T = T->next){
			e = pointInTriangle(point, T);
			switch(e){
				case -2: continue;
				case -1: goto pit;
				default: goto poe;
			}
		}
		return -200;
		poe:
		ADJACENT(T, T->points[e], T->points[NEXT(e)], A)
		if(!A) return -300;

		for(m=0; m<3 && A->points[m] != T->points[e]; ++m);
		if(m==3) return -400;

		B = NEWT;
		B->next = tHead;
		tHead = B;
		C = NEWT;
		C->next = tHead;
		tHead = C;

		B->points[0] = C->points[0] = T->points[e];
		B->points[1] = T->points[PREV(e)];
		C->points[1] = A->points[NEXT(m)] == T->points[NEXT(e)] ? A->points[PREV(m)] : A->points[NEXT(m)];
		T->points[e] = A->points[m] = B->points[2] = C->points[2] = point;

		if((i=legalizeEdge(point, T))<0) return i-510;
		if((i=legalizeEdge(point, A))<0) return i-520;
		if((i=legalizeEdge(point, B))<0) return i-530;
		if((i=legalizeEdge(point, C))<0) return i-540;

		continue;

		pit:

		A = NEWT;
		B = NEWT;
		A->next=tHead;
		tHead = A;
		B->next = tHead;
		tHead=B;

		A0 = P1;
		A1 = B->points[0] = P2;
		B->points[1] = P0;
		P2 = A2 = B->points[2] = point;

		if((i=legalizeEdge(point, T))<0) return i-610;
		if((i=legalizeEdge(point, A))<0) return i-620;
		if((i=legalizeEdge(point, B))<0) return i-630;


	}

	/*Calculate peak memory allocation*/
	mem=0;
	for(T=tHead, i=0; T; T=T->next, ++i);
	for(point=pHead, e=0; point; point=point->next, ++e);
	mem = i*sizeof(Triangle) + e*sizeof(Point);

	/*Patch*/
	for(T=tHead; T; T = T->next){
		/*Find # of external points*/
		for(i=0, e=0; i<3; e+=(T->points[i]->id < 0 ? 1 : 0), ++i);

		/*If # of external points is not equal to 1 continue*/
		if(e != 1) continue;

		check:

		/*Find external point*/
		for(e=0; e<3 && T->points[e]->id > -1; e++);

		/*Next mutual case*/
		/*Find the adjacent triangle*/
		ADJACENT(T, T->points[e], T->points[NEXT(e)], A)
		if(!A) return -710;

		/*Find the # of external points in the adjacent triangle*/
		for(i=0, m=0; i<3; m+=(A->points[i]->id < 0 ? 1 : 0), ++i);

		if(m==1){
			/*Find adjacent triangles external point*/
			for(m=0; m<3 && A->points[m]->id > -1; m++);
			/*Check whether the convex hull criteria apply*/
			a = CCW(T->points[PREV(e)], T->points[e],	A->points[T->points[NEXT(e)] == A->points[NEXT(m)] ? PREV(m) : NEXT(m)]);
			b = CCW(T->points[PREV(e)], T->points[NEXT(e)], A->points[T->points[NEXT(e)] == A->points[NEXT(m)] ? PREV(m) : NEXT(m)]);
			a*=b;
			if(a<0){
				if((i=swap(T, A))<0) return -711;
				T = P0->id<0 || P1->id<0 || P2->id<0 ? T : A;
				goto check;
			}
		}

		/*Find external point*/
		for(e=0; e<3 && T->points[e]->id > -1; e++);

		/*Prev mutual case*/
		/*Find the adjacent triangle*/
		ADJACENT(T, T->points[e], T->points[PREV(e)], A)
		if(!A) return -720;

		/*Find the external point in the adjacent triangle*/
		for(i=0, m=0; i<3; m+=(A->points[i]->id < 0 ? 1 : 0), ++i);

		if(m==1){
			/*Find adjacent triangles external point*/
			for(m=0; m<3 && A->points[m]->id > -1; m++);
			/*Check whether the convex hull criteria apply*/
			a = CCW(T->points[NEXT(e)], T->points[e],       A->points[T->points[NEXT(e)] == A->points[NEXT(m)] ? NEXT(m) : PREV(m)]);
			b = CCW(T->points[NEXT(e)], T->points[PREV(e)], A->points[T->points[NEXT(e)] == A->points[NEXT(m)] ? NEXT(m) : PREV(m)]);
			a*=b;
			if(a<0){
				if((i=swap(T, A))<0)return -721;;
				T = P0->id<0 || P1->id<0 || P2->id<0 ? T : A;
				goto check;
			}
		}

	}

	for(T=tHead, A=NULL; T; A=T, T=(A==NULL?T:T->next)){
		for(i=0, e=0; i<3; e+=(T->points[i]->id<0?1:0), ++i);
		if(e==0) continue;
		if(!A){
			A=T;
			T=T->next;
			free(A);
			A=NULL;
			tHead=T;
		} else {
			A->next = T->next;
			free(T);
			T=A;
		}
	}

	for(i=0; i<3; ++i){
		point=pHead;
		pHead=pHead->next;
		free(point);
	}

	//return 1;
	return len;
}