Exemple #1
0
dFloat dPolygonRayCast (const dVector& l0, const dVector& l1, int indexCount, const dFloat* const vertex, int strideInBytes, const int* const indices)
{
	int stride = strideInBytes / sizeof (dFloat);

	dBigVector line0 (l0);
	dBigVector line1(l1);
	dBigVector segment (line1 - line0);
	dBigVector normal (dPolygonNormal (indexCount, vertex, strideInBytes, indices));
	double den = normal % segment;
	if (dAbs(den) < 1.0e-6) {
		return 1.2f;
	}
	
	double sign = (den < 0.0f) ? 1.0f : -1.0f;

	int index = indices[indexCount - 1] * stride;
	dBigVector v0 (vertex[index], vertex[index + 1], vertex[index + 2], 0.0f);
	dBigVector p0v0 (v0 - line0);
	for (int i = 0; i < indexCount; i ++) {
		index = indices[i] * stride;
		dBigVector v1 (vertex[index], vertex[index + 1], vertex[index + 2], 0.0f);
		dBigVector p0v1 (v1 - line0);
		double alpha = sign * ((p0v1 * p0v0) % segment);
		if (alpha < 1.0e-3f) {
			return 1.2f;
		}
		p0v0 = p0v1;
	}

	double t = - ((line0 - v0) % normal) / den;
	if ((t < 0.0f) || (t > 1.0f)) {
		return 1.2f;
	}
	return dFloat (t);
}
dgFloat32 FastRayTest::PolygonIntersect (const dgVector& normal, const dgFloat32* const polygon, dgInt32 strideInBytes, const dgInt32* const indexArray, dgInt32 indexCount) const
{
	_ASSERTE (m_p0.m_w == m_p1.m_w);

	dgFloat32 dist = normal % m_diff;
	if (dist < m_dirError) {

		dgInt32 stride = dgInt32 (strideInBytes / sizeof (dgFloat32));

		dgVector v0 (&polygon[indexArray[indexCount - 1] * stride]);
		dgVector p0v0 (v0 - m_p0);
		dgFloat32 tOut = normal % p0v0;
		// this only work for convex polygons and for single side faces 
		// walk the polygon around the edges and calculate the volume 
		if ((tOut < dgFloat32 (0.0f)) && (tOut > dist)) {
			for (dgInt32 i = 0; i < indexCount; i ++) {
				dgInt32 i2 = indexArray[i] * stride;
				dgVector v1 (&polygon[i2]);
				dgVector p0v1 (v1 - m_p0);
				// calculate the volume formed by the line and the edge of the polygon
				dgFloat32 alpha = (m_diff * p0v1) % p0v0;
				// if a least one volume is negative it mean the line cross the polygon outside this edge and do not hit the face
				if (alpha < DG_RAY_TOL_ERROR) {
					return 1.2f;
				}
				p0v0 = p0v1;
			}

			//the line is to the left of all the polygon edges, 
			//then the intersection is the point we the line intersect the plane of the polygon
			tOut = tOut / dist;
			_ASSERTE (tOut >= dgFloat32 (0.0f));
			_ASSERTE (tOut <= dgFloat32 (1.0f));
			return tOut;
		}
	}
	return dgFloat32 (1.2f);

}
float dgFastRayTest::PolygonIntersect (const dgVector& normal, const float* const polygon, int32_t strideInBytes, const int32_t* const indexArray, int32_t indexCount) const
{
	HACD_ASSERT (m_p0.m_w == m_p1.m_w);


	#ifndef __USE_DOUBLE_PRECISION__
	float unrealible = float (1.0e10f);
	#endif

	float dist = normal % m_diff;
	if (dist < m_dirError) {

		int32_t stride = int32_t (strideInBytes / sizeof (float));

		dgVector v0 (&polygon[indexArray[indexCount - 1] * stride]);
		dgVector p0v0 (v0 - m_p0);
		float tOut = normal % p0v0;
		// this only work for convex polygons and for single side faces 
		// walk the polygon around the edges and calculate the volume 
		if ((tOut < float (0.0f)) && (tOut > dist)) {
			for (int32_t i = 0; i < indexCount; i ++) {
				int32_t i2 = indexArray[i] * stride;
				dgVector v1 (&polygon[i2]);
				dgVector p0v1 (v1 - m_p0);
				// calculate the volume formed by the line and the edge of the polygon
				float alpha = (m_diff * p0v1) % p0v0;
				// if a least one volume is negative it mean the line cross the polygon outside this edge and do not hit the face
				if (alpha < DG_RAY_TOL_ERROR) {
					#ifdef __USE_DOUBLE_PRECISION__
						return 1.2f;
					#else
						unrealible = alpha;
						break;
					#endif
				}
				p0v0 = p0v1;
			}

			#ifndef __USE_DOUBLE_PRECISION__ 
				if ((unrealible  < float (0.0f)) && (unrealible > (DG_RAY_TOL_ERROR * float (10.0f)))) {
					// the edge is too close to an edge float is not reliable, do the calculation with double
					dgBigVector v0_ (v0);
					dgBigVector m_p0_ (m_p0);
					//dgBigVector m_p1_ (m_p1);
					dgBigVector p0v0_ (v0_ - m_p0_);
					dgBigVector normal_ (normal);
					dgBigVector diff_ (m_diff);
					double tOut_ = normal_ % p0v0_;
					//double dist_ = normal_ % diff_;
					if ((tOut < double (0.0f)) && (tOut > dist)) {
						for (int32_t i = 0; i < indexCount; i ++) {
							int32_t i2 = indexArray[i] * stride;
							dgBigVector v1 (&polygon[i2]);
							dgBigVector p0v1_ (v1 - m_p0_);
							// calculate the volume formed by the line and the edge of the polygon
							double alpha = (diff_ * p0v1_) % p0v0_;
							// if a least one volume is negative it mean the line cross the polygon outside this edge and do not hit the face
							if (alpha < DG_RAY_TOL_ERROR) {
								return 1.2f;
							}
							p0v0_ = p0v1_;
						}

						tOut = float (tOut_);
					}
				}
			#endif

			//the line is to the left of all the polygon edges, 
			//then the intersection is the point we the line intersect the plane of the polygon
			tOut = tOut / dist;
			HACD_ASSERT (tOut >= float (0.0f));
			HACD_ASSERT (tOut <= float (1.0f));
			return tOut;
		}
	}
	return float (1.2f);

}
dgFloat32 FastRayTest::PolygonIntersectSimd (const dgVector& normal, const dgFloat32* const polygon, dgInt32 strideInBytes, const dgInt32* const indexArray, dgInt32 indexCount) const
{
	_ASSERTE (m_p0.m_w == m_p1.m_w);
	simd_128 normal1 ((simd_128&)normal & simd_128 (-1, -1, -1, 0));
	simd_128 dist (((simd_128&)normal1).DotProduct((simd_128&)m_diff));
	if ((dist < simd_128(m_dirError)).GetSignMask() & 1) {
		dgInt32 stride = dgInt32 (strideInBytes / sizeof (dgFloat32));

		simd_128 v0 (&polygon[indexArray[indexCount - 1] * stride]);
		simd_128 p0v0 (v0 - (simd_128&)m_p0);
		simd_128 tOut = normal1.DotProduct(p0v0);

		simd_128 zero (dgFloat32 (0.0f));
		// this only work for convex polygons and for single side faces 
		// walk the polygon around the edges and calculate the volume 
		simd_128 test ((tOut < zero) & (tOut > dist));
		if (test.GetSignMask()) {
			dgInt32 i3 = indexCount - 1; 
			dgInt32 i2 = indexCount - 2; 
			dgInt32 i1 = indexCount - 3; 
			dgInt32 i0 = (indexCount > 3) ? indexCount - 4 : 2; 
			for (dgInt32 i4 = 0; i4 < indexCount; i4 += 4) {
				simd_128 v0 (&polygon[indexArray[i0] * stride]);
				simd_128 v1 (&polygon[indexArray[i1] * stride]);
				simd_128 v2 (&polygon[indexArray[i2] * stride]);
				simd_128 v3 (&polygon[indexArray[i3] * stride]);
				simd_128 v4 (&polygon[indexArray[i4] * stride]);

				simd_128 p0v0 (v0 - (simd_128&)m_p0);
				simd_128 p0v1 (v1 - (simd_128&)m_p0);
				simd_128 p0v2 (v2 - (simd_128&)m_p0);
				simd_128 p0v3 (v3 - (simd_128&)m_p0);
				simd_128 p0v4 (v4 - (simd_128&)m_p0);

				simd_128 p0v0_x;
				simd_128 p0v0_y;
				simd_128 p0v0_z;
				simd_128 p0v1_x;
				simd_128 p0v1_y;
				simd_128 p0v1_z;

				Transpose4x4Simd_128 (p0v0_x, p0v0_y, p0v0_z, test, p0v0, p0v1, p0v2, p0v3);
				Transpose4x4Simd_128 (p0v1_x, p0v1_y, p0v1_z, test, p0v1, p0v2, p0v3, p0v4);

				simd_128 volume = (m_ray_yyyy * p0v1_z - m_ray_zzzz * p0v1_y) * p0v0_x + 
							      (m_ray_zzzz * p0v1_x - m_ray_xxxx * p0v1_z) * p0v0_y + 
								  (m_ray_xxxx * p0v1_y - m_ray_yyyy * p0v1_x) * p0v0_z;


				// if a least one volume is negative it mean the line cross the polygon outside this edge and do not hit the face
				if ((volume < (simd_128&)m_tolerance).GetSignMask()) {
					return 1.2f;
				}
				i3 = i4 + 3; 
				i2 = i4 + 2; 
				i1 = i4 + 1; 
				i0 = i4 + 0; 
			}

			//the line is to the left of all the polygon edges, 
			//then the intersection is the point we the line intersect the plane of the polygon
			tOut = tOut / dist;
			dgFloat32 ret;
			tOut.StoreScalar(&ret);
			_ASSERTE (ret >= dgFloat32 (0.0f));
			_ASSERTE (ret <= dgFloat32 (1.0f));
			return ret;
		}
	}
	return dgFloat32 (1.2f);
}