コード例 #1
0
void SRS::SolveAim(float psi_angle, Matrix  R1)
{
    float h1[3], N[3], angle;
    Matrix S0, S1;

    // Get the final hand position 
    evalcircle(c, u, v, radius, psi_angle, h1);

    // Rotate ee_r1 to h1
    crossproduct(N, ee_r1, h1);
    unitize(N);
    angle = angle_between_vectors(ee_r1, h1, N);
    rotation_axis_to_matrix(N, angle, S0);

    // Now rotate a0 to a
    float a[3], a0[3];

    vecsub(a, (float*)ee, h1);
    unitize(a);
    
    hmatmult(S1,Ry,S0);
    vecmult0(a0, (float*)axis, S1);

    cpvector(N, h1);
    unitize(N);
    angle = angle_between_vectors(a0, a, N);
    rotation_axis_to_matrix(N, angle, S1);

    hmatmult(R1, S0, S1);
}
コード例 #2
0
ファイル: MxQMetric.cpp プロジェクト: 2asoft/xray
MxQuadric::MxQuadric(const MxVector& p1,const MxVector& p2,const MxVector& p3,
		     double area)
    : A(p1.dim()), b(p1.dim())
{
    VERIFY( p1.dim()==p2.dim() && p1.dim()==p3.dim() );

    MxVector e1=p2; e1-=p1; unitize(e1); // e1 = p2-p1; unitize
    MxVector e2=p3; e2-=p1;              // e2 = p3-p1
    MxVector t = e1;
    t*=e1*e2; e2-=t; unitize(e2);        // e2 = p3-p1-e1*(e1*(p3-p1)); unitize

    double p1e1 = p1*e1;
    double p1e2 = p1*e2;

    mxm_identity(A, A.dim());
    symmetric_subfrom(A, e1,e1);
    symmetric_subfrom(A, e2,e2);

    // b = e1*p1e1 + e2*p1e2 - p1
    b=e1; b*=p1e1; t=e2; t*=p1e2; b += t; b -= p1;

    c = p1*p1 - p1e1*p1e1 - p1e2*p1e2;

    r = area;
}
コード例 #3
0
float get_circle_equation(const float ee[3], 
			  const float axis[3],
			  const float pos_axis[3],
			  float upper_len,
			  float lower_len,
			  float c[3],
			  float u[3],
			  float v[3],
			  float n[3])
{
    float wn = norm((float *)ee);
    float radius;

    cpvector(n, ee);
    unitize(n);

    
    // Use law of cosines to get angle between first spherical joint
    // and revolute joint

    float alpha; 

    if (!law_of_cosines(wn, upper_len, lower_len, alpha))
	return 0;

    // center of circle (origin is location of first S joint)
    vecscalarmult(c, n, _cos(alpha) * upper_len);

    
    radius = _sin(alpha) * upper_len;

    float temp[3];

    //
    // A little kludgy. If the goal is behind the joint instead
    // of in front of it, we reverse the angle measurement by
    // inverting the normal vector
    //

    if (DOT(n,pos_axis) < 0.0)
	vecscalarmult(n,n,-1.0);

    vecscalarmult(temp, n, DOT(axis,n));
    vecsub(u, (float *)axis, temp);
    unitize(u);

    crossproduct(v, n, u);
#if 0
    printf("Circle equation\n");
    printf("c = [%lf,%lf,%lf]\n", c[0], c[1], c[2]);
    printf("u = [%lf,%lf,%lf]\n", u[0], u[1], u[2]);
    printf("v = [%lf,%lf,%lf]\n", v[0], v[1], v[2]);
    printf("n = [%lf,%lf,%lf]\n", n[0], n[1], n[2]);
    printf("r = %lf\n", radius);
#endif
    return radius;
}
コード例 #4
0
ファイル: mat2.cpp プロジェクト: Frankie-666/xray-16
bool eigenvectors(const Mat2& M, const Vec2& evals, Vec2 evecs[2])
{
    evecs[0] = Vec2(-M(0,1), M(0,0)-evals[0]);
    evecs[1] = Vec2(-M(0,1), M(0,0)-evals[1]);

    unitize(evecs[0]);
    unitize(evecs[1]);

    return true;
}
コード例 #5
0
ファイル: MxPropSlim.cpp プロジェクト: AntonioModer/xray-16
void MxPropSlim::discontinuity_constraint(MxVertexID i, MxVertexID j, MxFaceID f)
{
	Vec3 org(m->vertex(i)), dest(m->vertex(j));
	Vec3 e = dest - org;

	Vec3 v1(m->vertex(m->face(f)(0)));
	Vec3 v2(m->vertex(m->face(f)(1)));
	Vec3 v3(m->vertex(m->face(f)(2)));
	Vec3 n = triangle_normal(v1,v2,v3);

	Vec3 n2 = e ^ n;
	unitize(n2);

	MxQuadric3 Q3(n2, -(n2*org));
	Q3 *= boundary_weight;

	if( weighting_policy == MX_WEIGHT_AREA ||
		weighting_policy == MX_WEIGHT_AREA_AVG )
	{
		Q3.set_area(norm2(e));
		Q3 *= Q3.area();
	}

	MxQuadric Q(Q3, dim());

	quadric(i) += Q;
	quadric(j) += Q;
}
コード例 #6
0
ファイル: math3d.cpp プロジェクト: vasilenkomike/xray
//
// p = Projection of u onto v
//
void project(float p[3], const float u[3], const float v[3])
{
    float vnorm[3];

    cpvector(vnorm, v);
    unitize(vnorm);
    vecscalarmult(p, vnorm, DOT(u,vnorm));
}
コード例 #7
0
ファイル: ring.c プロジェクト: zero-clouds-/RayTracer
int hitRing(entity_t * ent, point_t base, vector_t dir, hitinfo_t * hit) {
  if(hitPlane(ent, base, dir, hit) != 1) return 0;

  assert(ent->magic == ENTITY_T);
  sobj_t *sobj = ent->entDerived;
  assert(sobj->magic == SCENEOBJ_T);
  plane_t *plane = sobj->sobjDerived;
  assert(plane->magic == PLANE_T);
  ring_t * ring = plane->planeDerived;
  assert(ring->magic == RING_T);

  tuple_t r_centerTOhit = ray(plane->point, hit->hitpoint);
  double  d_hitpoint    = length(r_centerTOhit);
  double  d_inner       = length(scale(unitize(r_centerTOhit), ring->radius1));
  double  d_outer       = length(scale(unitize(r_centerTOhit), ring->radius2));

  return ((d_hitpoint > d_inner) && (d_hitpoint < d_outer));
}
コード例 #8
0
ファイル: math3d.cpp プロジェクト: vasilenkomike/xray
//
// Return the angle between two vectors u,v about the axis n
//
float angle_between_vectors(float u[3], float v[3], float n[3])
{
#if 0
    float temp[3];
    float up[3];
    float vp[3];

    cpvector(up, u);
    cpvector(vp, v);
    unitize(up);
    unitize(vp);

    crossproduct(temp, up, vp);
    float mag = DOT(temp,n);

    // Vectors are parallel at 0 or 180
    if (mag*mag < 1e-8)
    {
        if (DOT(up,vp) < 0)
            return M_PI;
        else
            return 0;
    }

    int sign = (mag > 0) ? 1 : -1;
    float t = DOT(up,vp);
    if (t > 1.0)
        t = 1.0;
    else if (t < -1.0)
        t = -1.0;
    return sign*acos(t);
#else

    float up[3];
    float vp[3];
    float uv[3];

    project_plane(up, u, n);
    project_plane(vp, v, n);
    crossproduct(uv, up, vp);
    return atan2(DOT(n, uv), DOT(up, vp));

#endif
}
コード例 #9
0
Mat4 quadrix_discontinuity_constraint(Edge *edge, const Vec3& n)
{
    Vec3& org = *edge->org();
    Vec3& dest = *edge->dest();
    Vec3 e = dest - org;

    Vec3 n2 = e ^ n;
    unitize(n2);

    real d = -n2 * org;
    return quadrix_plane_constraint(n2, d);
}
コード例 #10
0
ファイル: plane.c プロジェクト: joshua-hull/School-Work
/** completePlane **/
void completePlane(scene_t *scene, entity_t *ent) {
     sobj_t *sobj;
     plane_t *plane;
     assert(scene->magic == SCENE_T);
     assert(ent->magic == ENTITY_T);
     sobj = ent->entDerived;
     assert(sobj->magic == SCENEOBJ_T);
     plane = sobj->sobjDerived;
     assert(plane->magic == PLANE_T);
     plane->normal = unitize(cross(plane->orient1, plane->orient2));
     completeSceneObj(scene, ent);
}
コード例 #11
0
ファイル: raytrace.c プロジェクト: zero-clouds-/RayTracer
/** rayTrace **/
intensity_t rayTrace(scene_t *scene, point_t base, vector_t unitDir,
                 double total_dist, entity_t *self) {
  intensity_t intensity = ((intensity_t){0, 0, 0});
  entity_t * closestEnt;
  hitinfo_t * hit = malloc(sizeof(hitinfo_t));

  closestEnt = closest(scene, base, unitDir, self, hit);
  if (closestEnt == NULL) {
    free(hit);
    return (intensity);
  }

  total_dist += hit->distance;

  window_t * window = ((window_t *)(scene->window->entDerived));
  sobj_t   * sobj   = ((sobj_t   *)(closestEnt->entDerived));

  intensity = ((tuple_t){window->ambient.x * sobj->color.r,
                         window->ambient.y * sobj->color.g,
                         window->ambient.z * sobj->color.b});

  intensity_t light = lighting(scene, closestEnt, hit);
  intensity.x += light.x;
  intensity.y += light.y;
  intensity.z += light.z;

  intensity.x /= 255;
  intensity.y /= 255;
  intensity.z /= 255;
  
  intensity.x /= total_dist;
  intensity.y /= total_dist;
  intensity.z /= total_dist;

  sobj_t * closestSobj = closestEnt->entDerived;
  if (length(((tuple_t)(closestSobj->reflective))) != 0) {
    vector_t U = scale(unitDir, -1);
    vector_t N = hit->normal;
    vector_t V = unitize(add(scale(N, (2 * dot(U, N))), unitDir));

    intensity_t reflection;
    reflection = rayTrace(scene, hit->hitpoint, V, total_dist, closestEnt);

    multiply(reflection, closestSobj->reflective);
    intensity = add(intensity, reflection);
  }


  free(hit);
  return (intensity);

} /* End rayTrace */
コード例 #12
0
void ParticleSystem::simulate(float DeltaT)
{

	//need to initialize force every iteration
	
	for (unsigned i=0;i<f.size() ;i++)
	{
		f[i]={0.0,-9.0,0.0};
	}
//	f[0]={-.5,-0.1,-0.1};
//	f[6]={ .5, 0.1,0.1};
	
	//for all spring related particle calculate the force
	
	double const K=10.0; //spring constant
	double const zeta=0.05; //damping ratio
	
	for (map< pair<int,int>, float >::iterator it=springConnection.begin();it!=springConnection.end();it++)
	{
		float rest = it->second;
		Vector3D particleDistance= vertices[ it->first.first]->co - vertices[it->first.second]->co;
		double l = norm(particleDistance);
		
		unitize(particleDistance);
		
		Vector3D force = K*( rest- l)*particleDistance ;
		
		f[it->first.first]=f[it->first.first]+force-v[it->first.first]*zeta;
		f[it->first.second]=f[it->first.second]-force-v[it->first.second]*zeta;
	
	
	}


//	#pragma omp parallel for
	for (unsigned i=0; i<v.size();i++)
	{
		v[i] = ((f[i]/m[i])*DeltaT)+v[i];
		if (vertices[i]->co[1]<=0)
		{
			v[i]=-v[i];
		}
	}
//	#pragma omp parallel for
	for (unsigned i=0; i<v.size(); i++)
	{
		Vector3D offset=DeltaT*v[i];
		vertices[i]->co=vertices[i]->co+offset;
	}

}	
コード例 #13
0
Quaternion::Quaternion( const Vec3& axis, double radians )
{
    radians *= 0.5;
    Vec3 naxis = axis;
    unitize( naxis );
    double sine = sin( radians );

    w = cos( radians );
    x = sine * naxis[0];
    y = sine * naxis[1];
    z = sine * naxis[2];

    make_unit( *this );
}
コード例 #14
0
ファイル: pointlight.c プロジェクト: joshua-hull/School-Work
intensity_t processPointLight(scene_t *scene, entity_t *ent, entity_t *light, hitinfo_t *hit) {
    
    assert(ent->magic == ENTITY_T);

    tuple_t surfaceNormal = unitize(hit->normal);
    tuple_t testRay = ray(hit->hitpoint,((pointlight_t *)(light->entDerived))->center);
    testRay = unitize(testRay);
    intensity_t returnIntensity = {0,0,0};
    hitinfo_t *occlude = malloc(sizeof(hitinfo_t));

    pointlight_t *pointlight = light->entDerived;
    assert(pointlight->magic == POINTLIGHT_T);

    sobj_t *obj = ent->entDerived;
    assert(obj->magic == SCENEOBJ_T);

    intensity_t diffuse = obj->diffuse;
    intensity_t intensity = {pointlight->color.r * pointlight->brightness,pointlight->color.g*pointlight->brightness,pointlight->color.b*pointlight->brightness};
    double lightDistance = length(ray(pointlight->center,hit->hitpoint));

    if( dot(testRay,surfaceNormal) > 0 ) {
        entity_t *occludingObject = closest(scene,pointlight->center,scale(testRay, -1.0),NULL, occlude);
        free(occlude);
        if(occludingObject == ent){ 
            returnIntensity.x = diffuse.x * intensity.x * dot(testRay,surfaceNormal); 
            returnIntensity.y = diffuse.y*intensity.y * dot(testRay,surfaceNormal);
            returnIntensity.z = diffuse.z*intensity.z * dot(testRay,surfaceNormal);
            returnIntensity = scale(returnIntensity,1.0/lightDistance);
            return(returnIntensity);
        } else {
            return(returnIntensity);
        }
    } else {
        free(occlude);
        return(returnIntensity);    
    }
}
コード例 #15
0
//
// Form local coordinate system {x,y} from points p,q relative to the
// implicit origin 0. pscale is the reciprocal length of the p vector
// which as it turns out is already known. If the invert flag is true
// construct the transpose of the rotation matrix instead
//
inline void make_frame(const float p[3], 
		       float p_scale,
		       const float q[3], 
		       Matrix R, 
		       int invert = 0)
{
    float x[3], y[3], t[3];

    // x vector is unit vector from origin to p
    vecscalarmult(x, (float *)p, p_scale);

    // y vector is unit perpendicular projection of q onto x 
    vecscalarmult(t, x, DOT(q,x));
    vecsub(y, (float *) q, t);
    unitize(y);

    // z vector is x cross y

    if (invert)
    {
	R[0][0] = x[0];	R[1][0] = x[1];	R[2][0] = x[2];
	R[0][1] = y[0];	R[1][1] = y[1];	R[2][1] = y[2];

	R[0][2] = x[1]*y[2] - x[2]*y[1];
	R[1][2] = x[2]*y[0] - x[0]*y[2];
	R[2][2] = x[0]*y[1] - x[1]*y[0];
    }
    else
    {
	R[0][0] = x[0];	R[0][1] = x[1];	R[0][2] = x[2];
	R[1][0] = y[0];	R[1][1] = y[1];	R[1][2] = y[2];

	R[2][0] = x[1]*y[2] - x[2]*y[1];
	R[2][1] = x[2]*y[0] - x[0]*y[2];
	R[2][2] = x[0]*y[1] - x[1]*y[0];
    }

    R[3][0] = R[3][1] = R[3][2] = 
    R[0][3] = R[1][3] = R[2][3] = 0;

    R[3][3] = 1.0;
}
コード例 #16
0
//
// To extract axis and angle from R use the formulas (murray, pg 414)
//
//	2 * cos(theta) - 1 = trace(R) 
// and 
//	axis = vector associated with skew symmetric matrix (R-R')/(2*sin(theta)) 
//
//
// By our convention always return 0 <= angle < M_PI
// 
void rotation_matrix_to_axis(const Matrix R, float axis[], float &angle)
{
    const float eps = 1e-7f;

    angle = acos((R[0][0] + R[1][1] + R[2][2] - 1) / 2.0f);
    

    // Close to identity. Arbitrarily set solution to z axis rotation of 0 
    if (_abs(angle) < eps || _abs(angle - M_PI) < eps)
    {
	angle = 0.0;
	axis[0] = axis[1] = 0.0; axis[2] = 1.0; 
    }
    else
    {
	axis[0] = R[1][2] - R[2][1]; 
	axis[1] = R[2][0] - R[0][2];
	axis[2] = R[0][1] - R[1][0]; 
	unitize(axis);
    }
}
コード例 #17
0
ファイル: plane.c プロジェクト: joshua-hull/School-Work
int hitPlane(entity_t *ent, point_t base, vector_t dir, hitinfo_t *hit) {
    assert(ent->magic == ENTITY_T);
    sobj_t *sobj =  ent->entDerived;     
    assert(sobj->magic == SCENEOBJ_T);
    plane_t *planePtr = sobj->sobjDerived;
    assert(planePtr->magic == PLANE_T);

    point_t  Q = planePtr->point;      /* Point data      */
    vector_t N = planePtr->normal;     /* Normal data     */
    vector_t D = dir;                  /* Direction vector*/
    point_t  V = base;                 /* Base coordinates*/
    point_t  H;                        /* Hit point                 */
    double   t;                        /* Distance                  */

    if (dot(N, D) == 0)
        return 0; // parallel
    
    t = (dot(N, Q) - dot(N, V))/
           dot(N, D);
    if (t < 0)
        return 0; // behind me
    
    H = scale(D, t); 
    H = add(H, V);
    if (H.z > 0)
        return 0; // between the "screen" and me
    
    hit->hitpoint = H;
    hit->normal = unitize(N);
    hit->distance = t;
    /* Adjust the normal depending on whether ray hit from front
       or back of plane */
    if (dot(D, hit->normal) > 0) {
       hit->normal = scale(hit->normal, -1);
    }

    return 1;
}
コード例 #18
0
ファイル: raytrace.c プロジェクト: zero-clouds-/RayTracer
/** genRay **/
vector_t genRay(scene_t *scene, int column, int row) {
   vector_t direction;                       // Directior vector
   entity_t    *ent;
   window_t *window;

   assert(scene->magic == SCENE_T);
   ent = scene->window;
   window = ent->entDerived;
   assert(window->magic == WINDOW_T);

   /* Computer the pixel's real scene coordinates */
   direction.x = ((double)(column)/
      (double)(scene->picture->columns-1))*window->windowWidth;
   direction.x -= window->windowWidth/2.0;
   direction.y = ((double)(row)/
      (double)(scene->picture->rows-1))*window->windowHeight;
   direction.y -= window->windowHeight/2.0;
   direction.z = 0;

   /* And now construct a unit vector from the view point to the pixel */
   direction = ray(window->viewPoint, direction);
   direction = unitize(direction);
   return(direction);
} /* End genRay */
コード例 #19
0
ファイル: math3d.cpp プロジェクト: vasilenkomike/xray
void find_normal_vector(float v[3], float n[3])
{
    int   num_zero;
    float min, temp;
    int   min_i;

    min_i    = 0;
    min      = _abs(v[0]);
    num_zero = (min < 1e-8f);

    temp = _abs(v[1]);
    if (temp < 1e-8f)
        num_zero++;
    if (temp < min)
    {
        min = temp;
        min_i = 1;
    }

    temp = _abs(v[2]);
    if (temp < 1e-8)
        num_zero++;
    if (temp < min)
    {
        min = temp;
        min_i = 2;
    }

    n[0] = n[1] = n[2] = 0.0;

    switch (num_zero)
    {
    case 3:
        // Vector is zero so there is no soln
        break;
    case 2:
        // Vector has only one nonzero component. Set any of the
        // other to 1.0 and 0 to the others
        n[min_i] = 1.0;
        break;

    // Vector has at least two nonzero components
    case 1:
    default:
        if (min_i == 0)
        {
            n[1] = -v[2];
            n[2] = v[1];
        }
        else if (min_i == 1)
        {
            n[0] = -v[2];
            n[2] = v[0];
        }
        else
        {
            n[0] = -v[1];
            n[1] = v[0];
        }
        unitize(n);
        break;
    }

}
コード例 #20
0
ファイル: 3DPlotView.cpp プロジェクト: jontheepi/geoda
void C3DPlotCanvas::OnMouse( wxMouseEvent& event )
{
	wxPoint pt(event.GetPosition());
	wxClientDC dc(this);
	PrepareDC(dc);

	wxPoint point(event.GetLogicalPosition(dc));

	if (event.RightDown()) {
		m_bRButton = true;
		int where[2];
		where[0] = point.x;
		where[1] = point.y;
		last[0] = point.x;
		last[1] = point.y;
		ball->mouse_down(where,3);
	}
	
	if (event.RightUp()) {
		m_bRButton = false;
		int where[2];
		where[0] = point.x;
		where[1] = point.y;
		ball->mouse_up(where,3);
	}
	
	if (event.LeftDown()) {
		if ((event.CmdDown()) && this->m_d && this->b_select) {
			m_brush = true;
			last[0] = point.x;
			last[1] = point.y;
		} else {
			m_bLButton = true;
			int where[2];
			where[0] = point.x;
			where[1] = point.y;
			last[0] = point.x;
			last[1] = point.y;
			ball->mouse_down(where,1);
		}
	}
	
	if (event.LeftUp()) {
		if (bSelect && this->m_d ) {
			bSelect = false;
			SelectByRect();
		} else if (m_brush) {
			m_brush = false;
		} else {
			m_bLButton = false;
			int where[2];
			where[0] = point.x;
			where[1] = point.y;
			ball->mouse_up(where,1);
		}
	}
	
	if (event.Dragging()) {
		int where[2];
		where[0] = point.x;
		where[1] = point.y;
		if (m_brush) {
			float vp[4];
			glGetFloatv(GL_VIEWPORT, vp);
			float W=vp[2], H=vp[3];
			float diam = 2*(ball->radius);
			
			ball->apply_transform();
			
			int pix1[2], pix2[2], pix3[2];
			pix1[0] = (int)(W/2);
			pix1[1] = (int)(H/2);
			pix2[0] = (int)(W/2-1);
			pix2[1] = (int)(H/2);
			pix3[0] = (int)(W/2);
			pix3[1] = (int)(H/2-1);
			double world1[3], world2[3],world3[3];
			unproject_pixel(pix1, world1, 0.0);
			unproject_pixel(pix2, world2, 0.0);
			unproject_pixel(pix3, world3, 0.0);

			ball->unapply_transform();

			Vec3f w1(world1);
			Vec3f w2(world2);
			Vec3f w3(world3);

			Vec3f screen_x = w1-w2;
			unitize(screen_x);
			Vec3f screen_y = w3-w1;
			unitize(screen_y);

			Vec3f XX(1,0,0);
			Vec3f YY(0,1,0);
			Vec3f ZZ(0,0,1);

			xp += diam * (where[0] - last[0]) / W *(XX*screen_x);
			yp += diam * (where[0] - last[0]) / W *(YY*screen_x);
			zp += diam * (where[0] - last[0]) / W *(ZZ*screen_x); 

			xp += diam * (last[1] - where[1]) / H *(XX*screen_y);
			yp += diam * (last[1] - where[1]) / H *(YY*screen_y);
			zp += diam * (last[1] - where[1]) / H *(ZZ*screen_y);

			if (xp < -1.0) xp = -1.0;
			if (xp > 1.0) xp = 1.0;
			if (yp < -1.0) yp = -1.0;
			if (yp > 1.0) yp = 1.0;
			if (zp < -1.0) zp = -1.0;
			if (zp > 1.0) zp = 1.0;

			last[0] = where[0];
			last[1] = where[1];

			c3d_plot_frame->control->m_xp->SetValue((int)((xp+1)*10000));
			c3d_plot_frame->control->m_yp->SetValue((int)((yp+1)*10000));
			c3d_plot_frame->control->m_zp->SetValue((int)((zp+1)*10000));

			this->UpdateSelect();
		} else {
			bSelect = false;
			if (m_bLButton & m_bRButton) {
				ball->mouse_drag(where,last,2);
				last[0] = where[0];
				last[1] = where[1];
			} else if (m_bLButton) {
				ball->mouse_drag(where,last,1);
				last[0] = where[0];
				last[1] = where[1];
			} else if (m_bRButton) {
				ball->mouse_drag(where,last,3);
				last[0] = where[0];
				last[1] = where[1];
			}
		}
	}
	
	Refresh();
}
コード例 #21
0
static void get_aim_circle_equation(const float g[3], 
			 const float a[3],
			 const float ta[3],
			 const float tb[3],
			 const float proj_axis[3],
			 float theta4,
			 float center[3],
			 float u[3],
			 float v[3],
			 float &radius)
{
    float L1 = DOT(ta,ta);
    float L2 = DOT(tb,tb);
    Matrix Ry, Ryt;

    rotation_principal_axis_to_matrix('y', theta4, Ry);
    invertrmatrix(Ryt, Ry);

    // Compute distance of hand to shoulder 

    float t1[3], t2[3];

    vecmult(t1, (float *) tb, Ry);
    vecmult(t2, (float *) ta, Ryt);
    float L3 = _sqrt(L1 + L2 + DOT(ta,t1) + DOT(tb,t2));

    // Lengths of upper and lower arms
    L1 = _sqrt(L1);
    L2 = _sqrt(L2);

    // Compute angle between a and shoulder-to-hand vector
    // This is done assuming R1 = I since the angle does
    // not depend on the shoulder joints
    //
    // h = Ry*tb + ta
    // a = Ry*a 

    vecadd(t2, t1, (float *) ta);
    unitize(t2);

    vecmult(t1, (float *) a, Ry);
    float alpha = acos(DOT(t1,t2));


    //
    // Compute the angles of the triangle s,h,g
    //
    float L4 = _sqrt(DOT(g,g));
    float beta = M_PI - alpha;

    float delta = asin(_sin(beta)*L3/L4);
    if (delta < 0)
	delta = - delta;
    float gamma = M_PI - delta - beta;

    float c_gamma = _cos(gamma);
    float n[3]; 
    cpvector(n, g);
    unitize(n);
    vecscalarmult(center, n, c_gamma*L3);

    radius = _sqrt(1-c_gamma*c_gamma)*L3;

    project_plane(u, (float *) proj_axis, n);
    unitize(u);
    crossproduct(v, n, u);
}