Esempio n. 1
0
// Möller–Trumbore intersection algorithm
bool PnPProblem::intersect_MollerTrumbore(Ray &Ray, Triangle &Triangle, double *out)
{
  const double EPSILON = 0.000001;

  cv::Point3f e1, e2;
  cv::Point3f P, Q, T;
  double det, inv_det, u, v;
  double t;

  cv::Point3f V1 = Triangle.getV0();  // Triangle vertices
  cv::Point3f V2 = Triangle.getV1();
  cv::Point3f V3 = Triangle.getV2();

  cv::Point3f O = Ray.getP0(); // Ray origin
  cv::Point3f D = Ray.getP1(); // Ray direction

  //Find vectors for two edges sharing V1
  e1 = SUB(V2, V1);
  e2 = SUB(V3, V1);

  // Begin calculation determinant - also used to calculate U parameter
  P = CROSS(D, e2);

  // If determinant is near zero, ray lie in plane of triangle
  det = DOT(e1, P);

  //NOT CULLING
  if(det > -EPSILON && det < EPSILON) return false;
  inv_det = 1.f / det;

  //calculate distance from V1 to ray origin
  T = SUB(O, V1);

  //Calculate u parameter and test bound
  u = DOT(T, P) * inv_det;

  //The intersection lies outside of the triangle
  if(u < 0.f || u > 1.f) return false;

  //Prepare to test v parameter
  Q = CROSS(T, e1);

  //Calculate V parameter and test bound
  v = DOT(D, Q) * inv_det;

  //The intersection lies outside of the triangle
  if(v < 0.f || u + v  > 1.f) return false;

  t = DOT(e2, Q) * inv_det;

  if(t > EPSILON) { //ray intersection
    *out = t;
    return true;
  }

  // No hit, no win
  return false;
}
Esempio n. 2
0
static void
findstats(Pos p, Ori o)
{
	/* Recalculate cross assert and score total at 'p'
	 */
	Pos	left, right;
	Word lword, rword;
	Node n;
	Edge e;
	int	s;

	lword.n = rword.n = 0;
	if(EDGE(p))
		return;

	/* find word to the left */
	s = 0;
	for(left=PREV(p,o); HASLETTER(left); left = PREV(left,o))
		;
	left = NEXT(left,o);
	while (HASLETTER(left)) {
		lword.c[lword.n++] = LETTER(left);
		s += SCORE(left);
		left = NEXT(left,o);
	}
	/* find word to the right */
	for(right=NEXT(p,o); HASLETTER(right); right = NEXT(right,o)) {
		rword.c[rword.n++] = LETTER(right);
		s += SCORE(right);
	}
	if(DBG) {
		wordprint(&lword);
		print("X");
		wordprint(&rword);
		print(" [%d] ", s);
	}

	SIDE(p,o) = s;
	ISANCHOR(p) = true;

	/* calculate cross asserts */
	CROSS(p,o) = 0;
	n = traverse(root, &lword, 0);
	assert(n>=0);
	if(n>0)
		do {
			e = dict[n++];
			if ( (rword.n && isword(NODE(e), &rword)) || 
				 (!rword.n && TERM(e)) ) {
				CROSS(p,o) |= 1 << LET(e);
				DPRINT("%c, ", LET(e)+'a');
			}
		} while (!(LAST(e)));
	DPRINT("\n");
}
Esempio n. 3
0
/* and one CROSS has been moved out from the if-else if-else */
int intersect_triangle3(double orig[3], double dir[3],
			double vert0[3], double vert1[3], double vert2[3],
			double *t, double *u, double *v)
{
   double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
   double det,inv_det;

   /* find vectors for two edges sharing vert0 */
   SUB(edge1, vert1, vert0);
   SUB(edge2, vert2, vert0);

   /* begin calculating determinant - also used to calculate U parameter */
   CROSS(pvec, dir, edge2);

   /* if determinant is near zero, ray lies in plane of triangle */
   det = DOT(edge1, pvec);

   /* calculate distance from vert0 to ray origin */
   SUB(tvec, orig, vert0);
   inv_det = 1.0 / det;
   
   CROSS(qvec, tvec, edge1);
      
   if (det > EPSILON)
   {
      *u = DOT(tvec, pvec);
      if (*u < 0.0 || *u > det)
	 return 0;
            
      /* calculate V parameter and test bounds */
      *v = DOT(dir, qvec);
      if (*v < 0.0 || *u + *v > det)
	 return 0;
      
   }
   else if(det < -EPSILON)
   {
      /* calculate U parameter and test bounds */
      *u = DOT(tvec, pvec);
      if (*u > 0.0 || *u < det)
	 return 0;
      
      /* calculate V parameter and test bounds */
      *v = DOT(dir, qvec) ;
      if (*v > 0.0 || *u + *v < det)
	 return 0;
   }
   else return 0;  /* ray is parallell to the plane of the triangle */

   *t = DOT(edge2, qvec) * inv_det;
   (*u) *= inv_det;
   (*v) *= inv_det;

   return 1;
}
Esempio n. 4
0
/* and one CROSS has been moved out from the if-else if-else */
int intersect_triangle3(const RAYTRI *rt)
{
	double u, v;
	double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
	double det,inv_det;

	/* find vectors for two edges sharing rt->v0 */
	SUB(edge1, rt->v1, rt->v0);
	SUB(edge2, rt->v2, rt->v0);

	/* begin calculating determinant - also used to calculate U parameter */
	CROSS(pvec, rt->dir, edge2);

	/* if determinant is near zero, ray lies in plane of triangle */
	det = DOT(edge1, pvec);

	/* calculate distance from rt->v0 to ray origin */
	SUB(tvec, rt->org, rt->v0);
	inv_det = 1.0 / det;

	CROSS(qvec, tvec, edge1);

	if (det > EPSILON)
	{
		u = DOT(tvec, pvec);
		if (u < 0.0 || u > det)
			return 0;

		/* calculate V parameter and test bounds */
		v = DOT(rt->dir, qvec);
		if (v < 0.0 || u + v > det)
			return 0;

	}
	else if(det < -EPSILON)
	{
		/* calculate U parameter and test bounds */
		u = DOT(tvec, pvec);
		if (u > 0.0 || u < det)
			return 0;

		/* calculate V parameter and test bounds */
		v = DOT(rt->dir, qvec) ;
		if (v > 0.0 || u + v < det)
			return 0;
	}
	else return 0;  /* ray is parallell to the plane of the triangle */

	double t = DOT(edge2, qvec) * inv_det;
	if(t<0.0 || t>1.0)	return 0;

	return 1;
}
Esempio n. 5
0
long point_triangle_intersection(Point3 p, Triangle3 t)
{
long sign12,sign23,sign31;
Point3 vect12,vect23,vect31,vect1h,vect2h,vect3h;
Point3 cross12_1p,cross23_2p,cross31_3p;

/* First, a quick bounding-box test:                               */
/* If P is outside triangle bbox, there cannot be an intersection. */

   if (p.x > MAX3(t.v1.x, t.v2.x, t.v3.x)) return(OUTSIDE);  
   if (p.y > MAX3(t.v1.y, t.v2.y, t.v3.y)) return(OUTSIDE);
   if (p.z > MAX3(t.v1.z, t.v2.z, t.v3.z)) return(OUTSIDE);
   if (p.x < MIN3(t.v1.x, t.v2.x, t.v3.x)) return(OUTSIDE);
   if (p.y < MIN3(t.v1.y, t.v2.y, t.v3.y)) return(OUTSIDE);
   if (p.z < MIN3(t.v1.z, t.v2.z, t.v3.z)) return(OUTSIDE);

/* For each triangle side, make a vector out of it by subtracting vertexes; */
/* make another vector from one vertex to point P.                          */
/* The crossproduct of these two vectors is orthogonal to both and the      */
/* signs of its X,Y,Z components indicate whether P was to the inside or    */
/* to the outside of this triangle side.                                    */

   SUB(t.v1, t.v2, vect12)
   SUB(t.v1,    p, vect1h);
   CROSS(vect12, vect1h, cross12_1p)
   sign12 = SIGN3(cross12_1p);      /* Extract X,Y,Z signs as 0..7 or 0...63 integer */

   SUB(t.v2, t.v3, vect23)
   SUB(t.v2,    p, vect2h);
   CROSS(vect23, vect2h, cross23_2p)
   sign23 = SIGN3(cross23_2p);

   SUB(t.v3, t.v1, vect31)
   SUB(t.v3,    p, vect3h);
   CROSS(vect31, vect3h, cross31_3p)
   sign31 = SIGN3(cross31_3p);

/* If all three crossproduct vectors agree in their component signs,  */
/* then the point must be inside all three.                           */
/* P cannot be OUTSIDE all three sides simultaneously.                */

   /* this is the old test; with the revised SIGN3() macro, the test
    * needs to be revised. */
#ifdef OLD_TEST
   if ((sign12 == sign23) && (sign23 == sign31))
      return(INSIDE);
   else
      return(OUTSIDE);
#else
   return ((sign12 & sign23 & sign31) == 0) ? OUTSIDE : INSIDE;
#endif
}
void Camera::setFaceToOrigin() {
    //    logger.prs(theta);
    //    logger.prl(gamma);

    double rad = position.mag();

    position.x = rad * cos(D2R(theta)) * cos(D2R(gamma));
    position.y = rad * sin(D2R(theta)) * cos(D2R(gamma));
    position.z = rad * sin(D2R(gamma));

    forward = -position;
    up = CROSS(CROSS(forward, Vector(0, 0, 1)), forward);
}
Esempio n. 7
0
hacd::HaI32 tri_tri_overlap_test_3d(hacd::HaF32 p1[3], hacd::HaF32 q1[3], hacd::HaF32 r1[3], 

			    hacd::HaF32 p2[3], hacd::HaF32 q2[3], hacd::HaF32 r2[3])
{
  hacd::HaF32 dp1, dq1, dr1, dp2, dq2, dr2;
  hacd::HaF32 v1[3], v2[3];
  hacd::HaF32 N1[3], N2[3]; 
  
  /* Compute distance signs  of p1, q1 and r1 to the plane of
     triangle(p2,q2,r2) */


  SUB(v1,p2,r2)
  SUB(v2,q2,r2)
  CROSS(N2,v1,v2)

  SUB(v1,p1,r2)
  dp1 = DOT(v1,N2);
  SUB(v1,q1,r2)
  dq1 = DOT(v1,N2);
  SUB(v1,r1,r2)
  dr1 = DOT(v1,N2);
  
  if (((dp1 * dq1) > 0.0f) && ((dp1 * dr1) > 0.0f))  return 0; 

  /* Compute distance signs  of p2, q2 and r2 to the plane of
     triangle(p1,q1,r1) */

  
  SUB(v1,q1,p1)
  SUB(v2,r1,p1)
  CROSS(N1,v1,v2)

  SUB(v1,p2,r1)
  dp2 = DOT(v1,N1);
  SUB(v1,q2,r1)
  dq2 = DOT(v1,N1);
  SUB(v1,r2,r1)
  dr2 = DOT(v1,N1);
  
  if (((dp2 * dq2) > 0.0f) && ((dp2 * dr2) > 0.0f)) return 0;

  /* Permutation in a canonical form of T1's vertices */


  if (dp1 > 0.0f) {
    if (dq1 > 0.0f) TRI_TRI_3D(r1,p1,q1,p2,r2,q2,dp2,dr2,dq2)
    else if (dr1 > 0.0f) TRI_TRI_3D(q1,r1,p1,p2,r2,q2,dp2,dr2,dq2)	
    else TRI_TRI_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2)
  } else if (dp1 < 0.0f) {
void PenaltyMarkPercept::draw() const
{
  DECLARE_DEBUG_DRAWING("representation:PenaltyMarkPercept:image", "drawingOnImage");
  DECLARE_DEBUG_DRAWING("representation:PenaltyMarkPercept:field", "drawingOnField");

  if(Blackboard::getInstance().exists("FrameInfo"))
  {
    const FrameInfo& frameInfo = static_cast<const FrameInfo&>(Blackboard::getInstance()["FrameInfo"]);
    if(timeLastSeen == frameInfo.time)
    {
      CROSS("representation:PenaltyMarkPercept:image", position.x(), position.y(), 5, 5, Drawings::solidPen, ColorRGBA::blue);
      CROSS("representation:PenaltyMarkPercept:field", positionOnField.x(), positionOnField.y(), 40, 40, Drawings::solidPen, ColorRGBA::blue);
    }
  }
}
Esempio n. 9
0
int
main(int argc,char *argv[])
{
	/* rotates input vector by specified angle around given rotation axis */

	VECTOR r,n,nxr,rp;
	double phi,cphi,sphi,ndotr;

	if (argc != 8) {
		(void) fprintf(stderr,"Usage: %s x y z phi rx ry rz\n",argv[0]);
		return 1;
		}

	SET_VEC(r,atof(argv[1]),atof(argv[2]),atof(argv[3]));
	assert(MAG(r) > 0.0);
	phi = atof(argv[4]);
	SET_VEC(n,atof(argv[5]),atof(argv[6]),atof(argv[7]));
	assert(MAG(n) > 0.0);

	ndotr = DOT(n,r);
	CROSS(n,r,nxr);
	cphi = cos(phi);
	sphi = sin(phi);

	SCALE_VEC(r,cphi);
	SCALE_VEC(n,ndotr*(1.0-cphi));
	SCALE_VEC(nxr,sphi);

	ADD_VEC(r,n,rp);
	ADD_VEC(rp,nxr,rp);

	(void) printf("%g %g %g\n",rp[X],rp[Y],rp[Z]);

	return 0;
	}
Esempio n. 10
0
/**
 * @name angle_change
 *
 * Return the change in angle (degrees) of the line segments between
 * points one and two, and two and three.
 */
int Wordrec::angle_change(EDGEPT *point1, EDGEPT *point2, EDGEPT *point3) {
  VECTOR vector1;
  VECTOR vector2;

  int angle;

  /* Compute angle */
  vector1.x = point2->pos.x - point1->pos.x;
  vector1.y = point2->pos.y - point1->pos.y;
  vector2.x = point3->pos.x - point2->pos.x;
  vector2.y = point3->pos.y - point2->pos.y;
  /* Use cross product */
  float length = std::sqrt(static_cast<float>(LENGTH(vector1)) * LENGTH(vector2));
  if (static_cast<int>(length) == 0)
    return (0);
  angle = static_cast<int>(floor(asin(CROSS (vector1, vector2) /
                                      length) / M_PI * 180.0 + 0.5));

  /* Use dot product */
  if (SCALAR (vector1, vector2) < 0)
    angle = 180 - angle;
  /* Adjust angle */
  if (angle > 180)
    angle -= 360;
  if (angle <= -180)
    angle += 360;
  return (angle);
}
Esempio n. 11
0
void MotionRequest::draw() const
{
  DECLARE_DEBUG_DRAWING("representation:MotionRequest", "drawingOnField"); // drawing of a request walk vector
  if(motion == walk)
  {
    switch(walkRequest.mode)
    {
    case WalkRequest::targetMode:
    {
      LINE("representation:MotionRequest", 0, 0, walkRequest.target.translation.x, walkRequest.target.translation.y, 0, Drawings::ps_solid, ColorRGBA(0xcd, 0, 0));
      CROSS("representation:MotionRequest", walkRequest.target.translation.x, walkRequest.target.translation.y, 50, 0, Drawings::ps_solid, ColorRGBA(0xcd, 0, 0));
      Vector2<> rotation(500.f, 0.f);
      rotation.rotate(walkRequest.target.rotation);
      ARROW("representation:MotionRequest", walkRequest.target.translation.x, walkRequest.target.translation.y, walkRequest.target.translation.x + rotation.x, walkRequest.target.translation.y + rotation.y, 0, Drawings::ps_solid, ColorRGBA(0xcd, 0, 0, 127));
    }
    break;
    case WalkRequest::speedMode:
    case WalkRequest::percentageSpeedMode:
    {
      Vector2<> translation = walkRequest.mode == WalkRequest::speedMode ? walkRequest.speed.translation * 10.f : walkRequest.speed.translation * 1000.f;
      ARROW("representation:MotionRequest", 0, 0, translation.x, translation.y, 0, Drawings::ps_solid, ColorRGBA(0xcd, 0, 0));
      if(walkRequest.target.rotation != 0.0f)
      {
        translation.x = translation.abs();
        translation.y = 0;
        translation.rotate(walkRequest.speed.rotation);
        ARROW("representation:MotionRequest", 0, 0,  translation.x, translation.y, 0, Drawings::ps_solid, ColorRGBA(0xcd, 0, 0, 127));
      }
    }
    break;
    default:
      break;
    }
  }
}
Esempio n. 12
0
void AseFile::ComputeNormals(zASE_Object &obj)
{
	if(obj.pFaceNormals==NULL && obj.numOfFaces>0)obj.pFaceNormals = new vec[obj.numOfFaces];
	if(obj.pFaceNormals==NULL)return;
	if(obj.pNormals==NULL && obj.numOfVerts>0)obj.pNormals = new vec[obj.numOfVerts];
	if(obj.pNormals==NULL)return;
	
	for(int j=0; j<obj.numOfFaces; j++)
	{
		vec a,b;
		a = obj.pVerts[obj.pFaces[j].index[1]] - obj.pVerts[obj.pFaces[j].index[0]];
		b = obj.pVerts[obj.pFaces[j].index[2]] - obj.pVerts[obj.pFaces[j].index[0]];
		obj.pFaceNormals[j] = CROSS( a, b);
		obj.pFaceNormals[j].Normalize();
	}

	int count;

	for( j=0; j<obj.numOfVerts; j++)
	{
		count=0;
		obj.pNormals[j].clear();
		for(int k=0; k<obj.numOfFaces; k++)
		{
			if( obj.pFaces[k].index[0]==j || obj.pFaces[k].index[1]==j ||	obj.pFaces[k].index[2]==j )
			{
				obj.pNormals[j] += obj.pFaceNormals[k];
				count++;
			}
		}
		obj.pNormals[j] *= 1.f/(float)count;
		obj.pNormals[j].Normalize();
	}
}
Esempio n. 13
0
///
//	PointTriangleIntersection()
//
//		Test if 3D point is inside 3D triangle 
static
int PointTriangleIntersection(const vector3& p, const TRI& t)
{
	int		sign12,sign23,sign31;
	vector3 vect12,vect23,vect31,vect1h,vect2h,vect3h;
	vector3 cross12_1p,cross23_2p,cross31_3p;

	///
	//	First, a quick bounding-box test:                               
	//  If P is outside triangle bbox, there cannot be an intersection. 
	//
	if (p.x() > MAX3(t.m_P[0].x(), t.m_P[1].x(), t.m_P[2].x())) return(OUTSIDE);  
	if (p.y() > MAX3(t.m_P[0].y(), t.m_P[1].y(), t.m_P[2].y())) return(OUTSIDE);
	if (p.z() > MAX3(t.m_P[0].z(), t.m_P[1].z(), t.m_P[2].z())) return(OUTSIDE);
	if (p.x() < MIN3(t.m_P[0].x(), t.m_P[1].x(), t.m_P[2].x())) return(OUTSIDE);
	if (p.y() < MIN3(t.m_P[0].y(), t.m_P[1].y(), t.m_P[2].y())) return(OUTSIDE);
	if (p.z() < MIN3(t.m_P[0].z(), t.m_P[1].z(), t.m_P[2].z())) return(OUTSIDE);

	///
	//	For each triangle side, make a vector out of it by subtracting vertexes; 
	//	make another vector from one vertex to point P.                          
	//  The crossproduct of these two vectors is orthogonal to both and the      
	//  signs of its X,Y,Z components indicate whether P was to the inside or    
	//  to the outside of this triangle side.                                    
	//
	SUB(t.m_P[0], t.m_P[1], vect12);
	SUB(t.m_P[0], p,		  vect1h);	
	CROSS(vect12, vect1h, cross12_1p)
	sign12 = SIGN3(cross12_1p);      /* Extract X,Y,Z signs as 0..7 or 0...63 integer */

	SUB(t.m_P[1], t.m_P[2], vect23)
	SUB(t.m_P[1],    p, vect2h);
	CROSS(vect23, vect2h, cross23_2p)
	sign23 = SIGN3(cross23_2p);

	SUB(t.m_P[2], t.m_P[0], vect31)
	SUB(t.m_P[2],    p, vect3h);
	CROSS(vect31, vect3h, cross31_3p)
	sign31 = SIGN3(cross31_3p);

	///
	//	If all three crossproduct vectors agree in their component signs, /
	//  then the point must be inside all three.                           
	//  P cannot be OUTSIDE all three sides simultaneously.                
	//
	return (((sign12 & sign23 & sign31) == 0) ? OUTSIDE : INSIDE);
}
Esempio n. 14
0
int
intersect_triangle(const float orig[3], const float dir[3],
                   const float vert0[3], const float vert1[3], const float vert2[3],
                   float *t, float *u, float *v)
{
   float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
   float det,inv_det;

   /* find vectors for two edges sharing vert0 */
   SUB(edge1, vert1, vert0);
   SUB(edge2, vert2, vert0);

   /* begin calculating determinant - also used to calculate U parameter */
   CROSS(pvec, dir, edge2);

   /* if determinant is near zero, ray lies in plane of triangle */
   det = DOT(edge1, pvec);

   if (det > -EPSILON && det < EPSILON)
     return 0;
   inv_det = 1.0f / det;

   /* calculate distance from vert0 to ray origin */
   SUB(tvec, orig, vert0);

   /* calculate U parameter and test bounds */
   *u = DOT(tvec, pvec) * inv_det;
   if (*u < 0.0 || *u > 1.0)
     return 0;

   /* prepare to test V parameter */
   CROSS(qvec, tvec, edge1);

   /* calculate V parameter and test bounds */
   *v = DOT(dir, qvec) * inv_det;
   if (*v < 0.0 || *u + *v > 1.0)
     return 0;

   /* calculate t, ray intersects triangle */
   *t = DOT(edge2, qvec) * inv_det;

   return 1;
}
Esempio n. 15
0
void
bp_camera_set_look_at (camera_t *camera, vector_t look_at)
{
	float dir_length, up_length, right_length;
	vector_t dir;     /* direction vector not normalized */

	dir_length   = MAG (camera->direction);
	up_length    = MAG (camera->up);
	right_length = MAG (camera->right);

	SUB   (dir, look_at, camera->location);

	CROSS   (camera->right, dir, camera->sky);
	VRESIZE (camera->right, right_length);

	CROSS   (camera->up, camera->right, dir);
	VRESIZE (camera->up, up_length);

	VSET_SIZE (camera->direction, dir, dir_length);
}
Esempio n. 16
0
static void tri_normal(tri * trn, vector  * pnt, ray * incident, vector * N) {

  CROSS((*N), trn->edge1, trn->edge2);

  VNorm(N);

  if (VDot(N, &(incident->d)) > 0.0)  {
    N->x=-N->x;
    N->y=-N->y;
    N->z=-N->z;
  }
}
Esempio n. 17
0
// Computes the min and max cross product of the outline points with the
// given vec and returns the results in min_xp and max_xp. Geometrically
// this is the left and right edge of the outline perpendicular to the
// given direction, but to get the distance units correct, you would
// have to divide by the modulus of vec.
void TESSLINE::MinMaxCrossProduct(const TPOINT vec,
                                  int* min_xp, int* max_xp) const {
  *min_xp = MAX_INT32;
  *max_xp = MIN_INT32;
  EDGEPT* this_edge = loop;
  do {
    if (!this_edge->IsHidden() || !this_edge->prev->IsHidden()) {
      int product = CROSS(this_edge->pos, vec);
      UpdateRange(product, min_xp, max_xp);
    }
    this_edge = this_edge->next;
  } while (this_edge != loop);
}
void shNgin3dMove(float frontSpeed, float rightSpeed, float upSpeed, unsigned long dt)
{
	// cashed version of conversion of latitude and longitude to points already exist in _Ngin3d_cameraTarget and _Ngin3d_cameraUp
	float targetDir[3] = {_Ngin3d_cameraTarget[0]-_Ngin3d_cameraPosition[0], _Ngin3d_cameraTarget[1]-_Ngin3d_cameraPosition[1], _Ngin3d_cameraTarget[2]-_Ngin3d_cameraPosition[2]};
	float rightDir[3] = {CROSS(targetDir, _Ngin3d_cameraUp)};		// targetDir and _Ngin3d_cameraUp should already be normalized
	float upDir[3] = {0, 1, 0};
	if (g_Ngin3d_uprightMode)
	{
		if (_Ngin3d_cameraUp[1] < 0)
			upDir[1] = -1;
	}
	else
	{
		upDir[0] = _Ngin3d_cameraUp[0];
		upDir[1] = _Ngin3d_cameraUp[1];
		upDir[2] = _Ngin3d_cameraUp[2];
	}
	float speed[3] = {frontSpeed*targetDir[0]+upSpeed*upDir[0]+rightSpeed*rightDir[0],
			frontSpeed*targetDir[1]+upSpeed*upDir[1]+rightSpeed*rightDir[1],
			frontSpeed*targetDir[2]+upSpeed*upDir[2]+rightSpeed*rightDir[2]};
	float gravity[3] = {g_Ngin3d_settings[NGIN3D_GRAVITY_X], g_Ngin3d_settings[NGIN3D_GRAVITY_Y], g_Ngin3d_settings[NGIN3D_GRAVITY_Z]};
	float normGravity = NORM(gravity);
	if (g_Ngin3d_uprightMode && !STATE_IN_AIR && normGravity > EPSILON)
	{
		float speedInDirectionOfGravity = DOT(speed, gravity)/normGravity/normGravity;
		speed[0] -= gravity[0]*speedInDirectionOfGravity;
		speed[1] -= gravity[1]*speedInDirectionOfGravity;
		speed[2] -= gravity[2]*speedInDirectionOfGravity;
	}
	shNgin3dCollisionResult cr = g_Ngin3d_player.shNgin3dPOUpdate(dt, speed);
	if (cr == NGIN3D_COLLISION_WITH_GROUND)
	{
		STATE_IN_AIR = false;
	}
	float cameraDisplacement[3] = {0, 0, 0};
	if (g_Ngin3d_uprightMode)
	{
		if (STATE_CROUCHED)
			cameraDisplacement[1] = g_Ngin3d_settings[NGIN3D_CROUCHED_HEIGHT];
		else
			cameraDisplacement[1] = g_Ngin3d_settings[NGIN3D_HEIGHT];
	}
	_Ngin3d_cameraPosition[0] = g_Ngin3d_player.position[0]+cameraDisplacement[0];
	_Ngin3d_cameraPosition[1] = g_Ngin3d_player.position[1]+cameraDisplacement[1];
	_Ngin3d_cameraPosition[2] = g_Ngin3d_player.position[2]+cameraDisplacement[2];
	_Ngin3d_cameraTarget[0] = _Ngin3d_cameraPosition[0]+targetDir[0];
	_Ngin3d_cameraTarget[1] = _Ngin3d_cameraPosition[1]+targetDir[1];
	_Ngin3d_cameraTarget[2] = _Ngin3d_cameraPosition[2]+targetDir[2];
	(*_Ngin3d_cameraPositionFunction)(_Ngin3d_cameraPosition);
	(*_Ngin3d_cameraTargetFunction)(_Ngin3d_cameraTarget);
}
Esempio n. 19
0
/**********************************************************************
 * divide_blobs
 *
 * Create two blobs by grouping the outlines in the appropriate blob.
 * The outlines that are beyond the location point are moved to the
 * other blob.  The ones whose x location is less than that point are
 * retained in the original blob.
 **********************************************************************/
void divide_blobs(TBLOB *blob, TBLOB *other_blob, bool italic_blob,
                  const TPOINT& location) {
  TPOINT vertical = italic_blob ? kDivisibleVerticalItalic
                                : kDivisibleVerticalUpright;
  TESSLINE *outline1 = NULL;
  TESSLINE *outline2 = NULL;

  TESSLINE *outline = blob->outlines;
  blob->outlines = NULL;
  int location_prod = CROSS(location, vertical);

  while (outline != NULL) {
    TPOINT mid_pt = {(outline->topleft.x + outline->botright.x) / 2,
                     (outline->topleft.y + outline->botright.y) / 2};
    int mid_prod = CROSS(mid_pt, vertical);
    if (mid_prod < location_prod) {
      // Outline is in left blob.
      if (outline1)
        outline1->next = outline;
      else
        blob->outlines = outline;
      outline1 = outline;
    } else {
      // Outline is in right blob.
      if (outline2)
        outline2->next = outline;
      else
        other_blob->outlines = outline;
      outline2 = outline;
    }
    outline = outline->next;
  }

  if (outline1)
    outline1->next = NULL;
  if (outline2)
    outline2->next = NULL;
}
Esempio n. 20
0
/**********************************************************************
 * divisible_blob
 *
 * Returns true if the blob contains multiple outlines than can be
 * separated using divide_blobs. Sets the location to be used in the
 * call to divide_blobs.
 **********************************************************************/
bool divisible_blob(TBLOB *blob, bool italic_blob, TPOINT* location) {
  if (blob->outlines == NULL || blob->outlines->next == NULL)
    return false;  // Need at least 2 outlines for it to be possible.
  int max_gap = 0;
  TPOINT vertical = italic_blob ? kDivisibleVerticalItalic
                                : kDivisibleVerticalUpright;
  for (TESSLINE* outline1 = blob->outlines; outline1 != NULL;
       outline1 = outline1->next) {
    if (outline1->is_hole)
      continue;  // Holes do not count as separable.
    TPOINT mid_pt1 = {(outline1->topleft.x + outline1->botright.x) / 2,
                      (outline1->topleft.y + outline1->botright.y) / 2};
    int mid_prod1 = CROSS(mid_pt1, vertical);
    int min_prod1, max_prod1;
    outline1->MinMaxCrossProduct(vertical, &min_prod1, &max_prod1);
    for (TESSLINE* outline2 = outline1->next; outline2 != NULL;
         outline2 = outline2->next) {
      if (outline2->is_hole)
        continue;  // Holes do not count as separable.
      TPOINT mid_pt2 = {  (outline2->topleft.x + outline2->botright.x) / 2,
                        (outline2->topleft.y + outline2->botright.y) / 2};
      int mid_prod2 = CROSS(mid_pt2, vertical);
      int min_prod2, max_prod2;
      outline2->MinMaxCrossProduct(vertical, &min_prod2, &max_prod2);
      int mid_gap = abs(mid_prod2 - mid_prod1);
      int overlap = MIN(max_prod1, max_prod2) - MAX(min_prod1, min_prod2);
      if (mid_gap - overlap / 2 > max_gap) {
        max_gap = mid_gap - overlap / 2;
        *location = mid_pt1;
        *location += mid_pt2;
        *location /= 2;
      }
    }
  }
  // Use the y component of the vertical vector as an approximation to its
  // length.
  return max_gap > vertical.y;
}
Esempio n. 21
0
static void stri_normal(stri * trn, vector  * pnt, ray * incident, vector * N) {
  flt U, V, W, lensqr;
  vector P, tmp, norm;
  
  CROSS(norm, trn->edge1, trn->edge2);
  lensqr = DOT(norm, norm); 

  VSUB((*pnt), trn->v0, P);

  CROSS(tmp, P, trn->edge2);
  U = DOT(tmp, norm) / lensqr;   

  CROSS(tmp, trn->edge1, P);
  V = DOT(tmp, norm) / lensqr;   

  W = 1.0 - (U + V);

  N->x = W*trn->n0.x + U*trn->n1.x + V*trn->n2.x;
  N->y = W*trn->n0.y + U*trn->n1.y + V*trn->n2.y;
  N->z = W*trn->n0.z + U*trn->n1.z + V*trn->n2.z;

  VNorm(N);
}
Esempio n. 22
0
/*---------------------------------------------------------------------------*/
int testDegenerateTriangle(trian t){

	double v1[3],v2[3],v3[3],s1[3],s2[3],pv[3];
	
	STORE(v1,t.v0);
	STORE(v2,t.v1);
	STORE(v3,t.v2);
	SUB(s1,v2,v1);
	SUB(s2,v3,v1);
	CROSS(pv,s1,s2);
	if((SIGNO(pv[0] == LIM)) &&(SIGNO(pv[1] == LIM)) &&(SIGNO(pv[2] == LIM)))
	    return 0;
   return 1;
	
}
Esempio n. 23
0
File: ssx.c Progetto: srs51/SRS-3000
static void
adj_ang_mom(SSDATA *d,int n,PROPERTIES *p,VECTOR v)
{
	VECTOR u,w;
	int i;

	invert(p->inertia);
	SUB_VEC(v,p->ang_mom,v);
	Transform(p->inertia,v,u);
	SCALE_VEC(u,p->total_mass);
	for (i=0;i<n;i++) {
		CROSS(u,d[i].pos,w);
		ADD_VEC(d[i].vel,w,d[i].vel);
		}
	}
Esempio n. 24
0
static void tri_intersect(tri * trn, ray * ry) {
  vector tvec, pvec, qvec;
  flt det, inv_det, t, u, v;

  /* begin calculating determinant - also used to calculate U parameter */
  CROSS(pvec, ry->d, trn->edge2);

  /* if determinant is near zero, ray lies in plane of triangle */
  det = DOT(trn->edge1, pvec);

   if (det > -EPSILON && det < EPSILON)
     return;

   inv_det = 1.0 / det;

   /* calculate distance from vert0 to ray origin */
   SUB(tvec, ry->o, trn->v0);

   /* calculate U parameter and test bounds */
   u = DOT(tvec, pvec) * inv_det;
   if (u < 0.0 || u > 1.0)
     return;

   /* prepare to test V parameter */
   CROSS(qvec, tvec, trn->edge1);

   /* calculate V parameter and test bounds */
   v = DOT(ry->d, qvec) * inv_det;
   if (v < 0.0 || u + v > 1.0)
     return;

   /* calculate t, ray intersects triangle */
   t = DOT(trn->edge2, qvec) * inv_det;

  add_intersection(t,(object *) trn, ry);
}
Esempio n. 25
0
void incr_facet(
  REAL n1, REAL n2, REAL n3,
  REAL i1, REAL i2, REAL i3,
  REAL j1, REAL j2, REAL j3,
  REAL k1, REAL k2, REAL k3){


  REAL x[3] = {i1-j1,i2-j2,i3-j3};
  REAL y[3] = {i1-k1,i2-k2,i3-k3};
  REAL zz[3]; CROSS(x,y,zz);
  REAL A = sqrt(NORM2(zz))/2;
  REAL incr = 1./3. * (i1*n1+i2*n2+i3*n3)*A;

//  REAL incr = (-1*k1*j2*i3 + j1*k2*i3 + k1*i2*j3 - i1*k2*j3 - j1*i2*k3 + i1*j2*k3)/6.;

  vol+=incr;
}
Esempio n. 26
0
void AseFile::ComputeTangentBinormal()
{
	for(int i=0; i<this->objects.size(); i++)
	{
		if(!objects[i].numOfTexVerts || !objects[i].numOfFaces)continue;

		vec* faceTangent;
		zASE_Object *obj;
		obj = &objects[i];

		faceTangent = new vec[obj->numOfFaces];		if(faceTangent==NULL)return;
		obj->pTangent = new vec[obj->numOfVerts];	if(obj->pTangent==NULL)return;
		obj->pBinormal = new vec[obj->numOfVerts];	if(obj->pBinormal==NULL)return;

		for(int j=0; j<obj->numOfFaces; j++)
		{
			tangent( obj->pVerts[obj->pFaces[j].index[0]],
					 obj->pVerts[obj->pFaces[j].index[1]],
					 obj->pVerts[obj->pFaces[j].index[2]],
					 obj->pTexVerts[obj->pFaceCoord[j].index[0]],
					 obj->pTexVerts[obj->pFaceCoord[j].index[1]],
					 obj->pTexVerts[obj->pFaceCoord[j].index[2]],
					 faceTangent[j] );
		}

		for(j=0; j<obj->numOfVerts; j++)			// Go through all of the vertices
		{
			obj->pTangent[j].clear();
			for(int k=0; k<obj->numOfFaces; k++)	// Go through all of the triangles
			{										// Check if the vertex is shared by another face
				if( obj->pFaces[k].index[0]==j || 
					obj->pFaces[k].index[1]==j ||
					obj->pFaces[k].index[2]==j )
				{
					obj->pTangent[j] += faceTangent[k];
				}
			}
			obj->pTangent[j].Normalize();
			obj->pBinormal[j] = Normalize( CROSS( obj->pNormals[j], obj->pTangent[j] ));
		}
		if(faceTangent!=NULL)delete [] faceTangent;
	}
}
Esempio n. 27
0
int
gemIntegrate_bar(gemQuilt *quilt,     /* (in)   the quilt to integrate upon */
                 int      geomFlag,   /* (in)   0 - data ref, 1 - geom based */
                 int      eIndex,     /* (in)   element index (bias 1) */
                 int      rank,       /* (in)   data depth */
                 double   res_bar[],  /* (in)   d(objective)/d(result)
                                                (rank in length) */
                 double   dat_bar[])  /* (both) d(objective)/d(data)
                                                (rank*npts in len) */
{
  int    i, in[3];
  double x1[3], x2[3], x3[3], area;
  
  /* element indices */
  
  in[0] = quilt->elems[eIndex-1].gIndices[0] - 1;
  in[1] = quilt->elems[eIndex-1].gIndices[1] - 1;
  in[2] = quilt->elems[eIndex-1].gIndices[2] - 1;
  
  x1[0] = quilt->points[in[1]].xyz[0] - quilt->points[in[0]].xyz[0];
  x2[0] = quilt->points[in[2]].xyz[0] - quilt->points[in[0]].xyz[0];
  x1[1] = quilt->points[in[1]].xyz[1] - quilt->points[in[0]].xyz[1];
  x2[1] = quilt->points[in[2]].xyz[1] - quilt->points[in[0]].xyz[1];
  x1[2] = quilt->points[in[1]].xyz[2] - quilt->points[in[0]].xyz[2];
  x2[2] = quilt->points[in[2]].xyz[2] - quilt->points[in[0]].xyz[2];
  CROSS(x3, x1, x2);
  area  = sqrt(DOT(x3, x3))/2.0;      /* 1/2 for area */
  
  if (geomFlag == 0) {
    in[0] = quilt->elems[eIndex-1].dIndices[0] - 1;
    in[1] = quilt->elems[eIndex-1].dIndices[1] - 1;
    in[2] = quilt->elems[eIndex-1].dIndices[2] - 1;
  }
  for (i = 0; i < rank; i++) {
/*  result[i] = area*(data[rank*in[0]+i] + data[rank*in[1]+i] +
                      data[rank*in[2]+i])/3.0;  */
    dat_bar[rank*in[0]+i] += area*res_bar[i]/3.0;
    dat_bar[rank*in[1]+i] += area*res_bar[i]/3.0;
    dat_bar[rank*in[2]+i] += area*res_bar[i]/3.0;
  }

  return GEM_SUCCESS;
}
Esempio n. 28
0
int
gemIntegration(gemQuilt *quilt,       /* (in)  the quilt to integrate upon */
               int      geomFlag,     /* (in)  0 - data ref, 1 - geom based */
               int      eIndex,       /* (in)  element index (bias 1) */
               int      rank,         /* (in)  data depth */
               double   data[],       /* (in)  values (rank*npts in length) */
               double   result[])     /* (out) integrated result - (rank) */
{
  int    i, in[3];
  double x1[3], x2[3], x3[3], area;

  /* element indices */

  in[0] = quilt->elems[eIndex-1].gIndices[0] - 1;
  in[1] = quilt->elems[eIndex-1].gIndices[1] - 1;
  in[2] = quilt->elems[eIndex-1].gIndices[2] - 1;
  
  x1[0] = quilt->points[in[1]].xyz[0] - quilt->points[in[0]].xyz[0];
  x2[0] = quilt->points[in[2]].xyz[0] - quilt->points[in[0]].xyz[0];
  x1[1] = quilt->points[in[1]].xyz[1] - quilt->points[in[0]].xyz[1];
  x2[1] = quilt->points[in[2]].xyz[1] - quilt->points[in[0]].xyz[1];
  x1[2] = quilt->points[in[1]].xyz[2] - quilt->points[in[0]].xyz[2];
  x2[2] = quilt->points[in[2]].xyz[2] - quilt->points[in[0]].xyz[2];
  CROSS(x3, x1, x2);
  area  = sqrt(DOT(x3, x3))/2.0;      /* 1/2 for area */

  if (geomFlag == 0) {
    in[0] = quilt->elems[eIndex-1].dIndices[0] - 1;
    in[1] = quilt->elems[eIndex-1].dIndices[1] - 1;
    in[2] = quilt->elems[eIndex-1].dIndices[2] - 1;
  }
  for (i = 0; i < rank; i++)
    result[i] = area*(data[rank*in[0]+i] + data[rank*in[1]+i] +
                      data[rank*in[2]+i])/3.0;

  return GEM_SUCCESS;
}
Esempio n. 29
0
bool intersect_triangle(Point3F orig, Point3F dir,
                   Point3F vert0, Point3F vert1, Point3F vert2,
                   F32& t, F32& u, F32& v)
{
   Point3F edge1, edge2, tvec, pvec, qvec;
   F32 det,inv_det;

   /* find vectors for two edges sharing vert0 */
   edge1.x = vert1.x - vert0.x;
   edge1.y = vert1.y - vert0.y;
   edge1.z = vert1.z - vert0.z;
   edge2.x = vert2.x - vert0.x;
   edge2.y = vert2.y - vert0.y;
   edge2.z = vert2.z - vert0.z;

   /* begin calculating determinant - also used to calculate U parameter */
   //CROSS(pvec, dir, edge2);
   mCross(dir, edge2, &pvec);

   /* if determinant is near zero, ray lies in plane of triangle */
   //det = DOT(edge1, pvec);
   det = mDot(edge1, pvec);

#ifdef TEST_CULL           /* define TEST_CULL if culling is desired */
   if (det < EPSILON)
      return 0;

   /* calculate distance from vert0 to ray origin */
   SUB(tvec, orig, vert0);

   /* calculate U parameter and test bounds */
   *u = DOT(tvec, pvec);
   if (*u < 0.0 || *u > det)
      return 0;

   /* prepare to test V parameter */
   CROSS(qvec, tvec, edge1);

    /* calculate V parameter and test bounds */
   *v = DOT(dir, qvec);
   if (*v < 0.0 || *u + *v > det)
      return 0;

   /* calculate t, scale parameters, ray intersects triangle */
   *t = DOT(edge2, qvec);
   inv_det = 1.0 / det;
   *t *= inv_det;
   *u *= inv_det;
   *v *= inv_det;
#else                    /* the non-culling branch */
   if (det > -EPSILON && det < EPSILON)
     return false;
   inv_det = 1.0 / det;

   /* calculate distance from vert0 to ray origin */
   //SUB(tvec, orig, vert0);
   tvec.x = orig.x - vert0.x;
   tvec.y = orig.y - vert0.y;
   tvec.z = orig.z - vert0.z;

   /* calculate U parameter and test bounds */
//   *u = DOT(tvec, pvec) * inv_det;
   u = mDot(tvec, pvec) * inv_det;
   if (u < 0.0 || u > 1.0)
     return false;

   /* prepare to test V parameter */
   //CROSS(qvec, tvec, edge1);
   mCross(tvec, edge1, &qvec);

   /* calculate V parameter and test bounds */
//   *v = DOT(dir, qvec) * inv_det;
   v = mDot(dir, qvec) * inv_det;
   if (v < 0.0 || u + v > 1.0)
     return false;

   /* calculate t, ray intersects triangle */
//   *t = DOT(edge2, qvec) * inv_det;
   t = mDot(edge2, qvec) * inv_det;
#endif
   return true;
}
void ArmContactModelProvider::update(ArmContactModel& model)
{
  MODIFY("module:ArmContactModelProvider:parameters", p);
  DECLARE_PLOT("module:ArmContactModelProvider:errorLeftX");
  DECLARE_PLOT("module:ArmContactModelProvider:errorRightX");
  DECLARE_PLOT("module:ArmContactModelProvider:errorLeftY");
  DECLARE_PLOT("module:ArmContactModelProvider:errorRightY");
  DECLARE_PLOT("module:ArmContactModelProvider:errorDurationLeft");
  DECLARE_PLOT("module:ArmContactModelProvider:errorDurationRight");
  DECLARE_PLOT("module:ArmContactModelProvider:errorYThreshold");
  DECLARE_PLOT("module:ArmContactModelProvider:errorXThreshold");
  DECLARE_PLOT("module:ArmContactModelProvider:contactLeft");
  DECLARE_PLOT("module:ArmContactModelProvider:contactRight");

  DECLARE_DEBUG_DRAWING("module:ArmContactModelProvider:armContact", "drawingOnField");

  CIRCLE("module:ArmContactModelProvider:armContact", 0, 0, 200, 30, Drawings::ps_solid, ColorClasses::blue, Drawings::ps_null, ColorClasses::blue);
  CIRCLE("module:ArmContactModelProvider:armContact", 0, 0, 400, 30, Drawings::ps_solid, ColorClasses::blue, Drawings::ps_null, ColorClasses::blue);
  CIRCLE("module:ArmContactModelProvider:armContact", 0, 0, 600, 30, Drawings::ps_solid, ColorClasses::blue, Drawings::ps_null, ColorClasses::blue);
  CIRCLE("module:ArmContactModelProvider:armContact", 0, 0, 800, 30, Drawings::ps_solid, ColorClasses::blue, Drawings::ps_null, ColorClasses::blue);
  CIRCLE("module:ArmContactModelProvider:armContact", 0, 0, 1000, 30, Drawings::ps_solid, ColorClasses::blue, Drawings::ps_null, ColorClasses::blue);
  CIRCLE("module:ArmContactModelProvider:armContact", 0, 0, 1200, 30, Drawings::ps_solid, ColorClasses::blue, Drawings::ps_null, ColorClasses::blue);


  /* Buffer arm angles */
  struct ArmAngles angles;
  angles.leftX = theJointRequest.angles[JointData::LShoulderPitch];
  angles.leftY = theJointRequest.angles[JointData::LShoulderRoll];
  angles.rightX = theJointRequest.angles[JointData::RShoulderPitch];
  angles.rightY = theJointRequest.angles[JointData::RShoulderRoll];
  angleBuffer.add(angles);
  
  /* Reset in case of a fall or penalty */
  if(theFallDownState.state == FallDownState::onGround || theRobotInfo.penalty != PENALTY_NONE)
  {
    leftErrorBuffer.init();
    rightErrorBuffer.init();
  }

  Pose2D odometryOffset = theOdometryData - lastOdometry;
  lastOdometry = theOdometryData;
  
  const Vector3<>& leftHandPos3D = theRobotModel.limbs[MassCalibration::foreArmLeft].translation;
  Vector2<> leftHandPos(leftHandPos3D.x, leftHandPos3D.y);
  Vector2<> leftHandSpeed = (odometryOffset + Pose2D(leftHandPos) - Pose2D(lastLeftHandPos)).translation / theFrameInfo.cycleTime;
  float leftFactor = std::max(0.f, 1.f - leftHandSpeed.abs() / p.speedBasedErrorReduction);
  lastLeftHandPos = leftHandPos;

  const Vector3<>& rightHandPos3D = theRobotModel.limbs[MassCalibration::foreArmRight].translation;
  Vector2<> rightHandPos(rightHandPos3D.x, rightHandPos3D.y);
  Vector2<> rightHandSpeed = (odometryOffset + Pose2D(rightHandPos) - Pose2D(lastRightHandPos)).translation / theFrameInfo.cycleTime;
  float rightFactor = std::max(0.f, 1.f - rightHandSpeed.abs() / p.speedBasedErrorReduction);
  lastRightHandPos = rightHandPos;
  
  /* Check for arm contact */
  // motion types to take into account: stand, walk (if the robot is upright)
  if((theMotionInfo.motion == MotionInfo::stand || theMotionInfo.motion == MotionInfo::walk) &&
     (theFallDownState.state == FallDownState::upright || theFallDownState.state == FallDownState::staggering) &&
     (theGameInfo.state == STATE_PLAYING || theGameInfo.state == STATE_READY) &&
     (theRobotInfo.penalty == PENALTY_NONE)) // TICKET 897: ArmContact only if robot is not penalized
  {
    checkArm(LEFT, leftFactor);
    checkArm(RIGHT, rightFactor);

    //left and right are projections of the 3 dimensional shoulder-joint vector
    //onto the x-y plane.
    Vector2f left = leftErrorBuffer.getAverageFloat();
    Vector2f right = rightErrorBuffer.getAverageFloat();

    
    //Determine if we are being pushed or not
    bool leftX  = fabs(left.x) > fromDegrees(p.errorXThreshold);
    bool leftY  = fabs(left.y) > fromDegrees(p.errorYThreshold);
    bool rightX = fabs(right.x)> fromDegrees(p.errorXThreshold);
    bool rightY = fabs(right.y)> fromDegrees(p.errorYThreshold);

    // update the model
    model.contactLeft  = leftX || leftY;
    model.contactRight = rightX || rightY;

    // The duration of the contact is counted upwards as long as the error
    //remains. Otherwise it is reseted to 0.
    model.durationLeft  = model.contactLeft  ? model.durationLeft + 1 : 0;
    model.durationRight = model.contactRight ? model.durationRight + 1 : 0;

    model.contactLeft &= model.durationLeft < p.malfunctionThreshold;
    model.contactRight &= model.durationRight < p.malfunctionThreshold;


    if(model.contactLeft)
    {
      model.timeOfLastContactLeft = theFrameInfo.time;
    }
    if(model.contactRight)
    {
      model.timeOfLastContactRight = theFrameInfo.time;
    }
    
    model.pushDirectionLeft = getDirection(LEFT, leftX, leftY, left);
    model.pushDirectionRight = getDirection(RIGHT, rightX, rightY, right);

    model.lastPushDirectionLeft = model.pushDirectionLeft != ArmContactModel::NONE ? model.pushDirectionLeft : model.lastPushDirectionLeft;
    model.lastPushDirectionRight = model.pushDirectionRight != ArmContactModel::NONE ? model.pushDirectionRight : model.lastPushDirectionRight;

    PLOT("module:ArmContactModelProvider:errorLeftX",         toDegrees(left.x));
    PLOT("module:ArmContactModelProvider:errorRightX",        toDegrees(right.x));
    PLOT("module:ArmContactModelProvider:errorLeftY",         toDegrees(left.y));
    PLOT("module:ArmContactModelProvider:errorRightY",        toDegrees(right.y));
    PLOT("module:ArmContactModelProvider:errorDurationLeft",  model.durationLeft);
    PLOT("module:ArmContactModelProvider:errorDurationRight", model.durationRight);
    PLOT("module:ArmContactModelProvider:errorYThreshold",    toDegrees(p.errorYThreshold));
    PLOT("module:ArmContactModelProvider:errorXThreshold",    toDegrees(p.errorXThreshold));
    PLOT("module:ArmContactModelProvider:contactLeft",        model.contactLeft ? 10.0 : 0.0);
    PLOT("module:ArmContactModelProvider:contactRight",       model.contactRight ? 10.0 : 0.0);

    ARROW("module:ArmContactModelProvider:armContact", 0, 0, -(toDegrees(left.y) * SCALE), toDegrees(left.x) * SCALE, 20, Drawings::ps_solid, ColorClasses::green);
    ARROW("module:ArmContactModelProvider:armContact", 0, 0, toDegrees(right.y) * SCALE, toDegrees(right.x) * SCALE, 20, Drawings::ps_solid, ColorClasses::red);

    COMPLEX_DRAWING("module:ArmContactModelProvider:armContact",
    {
      DRAWTEXT("module:ArmContactModelProvider:armContact", -2300, 1300, 20, ColorClasses::black, "LEFT");
      DRAWTEXT("module:ArmContactModelProvider:armContact", -2300, 1100, 20, ColorClasses::black, "ErrorX: " << toDegrees(left.x));
      DRAWTEXT("module:ArmContactModelProvider:armContact", -2300, 900, 20, ColorClasses::black,  "ErrorY: " << toDegrees(left.y));
      DRAWTEXT("module:ArmContactModelProvider:armContact", -2300, 500, 20, ColorClasses::black,  ArmContactModel::getName(model.pushDirectionLeft));
      DRAWTEXT("module:ArmContactModelProvider:armContact", -2300, 300, 20, ColorClasses::black,  "Time: " << model.timeOfLastContactLeft);

      DRAWTEXT("module:ArmContactModelProvider:armContact", 1300, 1300, 20, ColorClasses::black, "RIGHT");
      DRAWTEXT("module:ArmContactModelProvider:armContact", 1300, 1100, 20, ColorClasses::black, "ErrorX: " << toDegrees(right.x));
      DRAWTEXT("module:ArmContactModelProvider:armContact", 1300, 900, 20, ColorClasses::black,  "ErrorY: " << toDegrees(right.y));
      DRAWTEXT("module:ArmContactModelProvider:armContact", 1300, 500, 20, ColorClasses::black,  ArmContactModel::getName(model.pushDirectionRight));
      DRAWTEXT("module:ArmContactModelProvider:armContact", 1300, 300, 20, ColorClasses::black,  "Time: " << model.timeOfLastContactRight);

      if (model.contactLeft)
      {
        CROSS("module:ArmContactModelProvider:armContact", -2000, 0, 100, 20, Drawings::ps_solid, ColorClasses::red);
      }
      if (model.contactRight)
      {
        CROSS("module:ArmContactModelProvider:armContact", 2000, 0, 100, 20, Drawings::ps_solid, ColorClasses::red);
      }
  });