Exemple #1
0
float32 b2PolygonShape::ComputeSubmergedArea(	const b2Vec2& normal,
												float32 offset,
												const b2XForm& xf, 
												b2Vec2* c) const
{
	//Transform plane into shape co-ordinates
	b2Vec2 normalL = b2MulT(xf.R,normal);
	float32 offsetL = offset - b2Dot(normal,xf.position);
	
	float32 depths[b2_maxPolygonVertices];
	int32 diveCount = 0;
	int32 intoIndex = -1;
	int32 outoIndex = -1;
	
	bool lastSubmerged = false;
	int32 i;
	for(i=0;i<m_vertexCount;i++){
		depths[i] = b2Dot(normalL,m_vertices[i]) - offsetL;
		bool isSubmerged = depths[i]<-B2_FLT_EPSILON;
		if(i>0){
			if(isSubmerged){
				if(!lastSubmerged){
					intoIndex = i-1;
					diveCount++;
				}
			}else{
				if(lastSubmerged){
					outoIndex = i-1;
					diveCount++;
				}
			}
		}
		lastSubmerged = isSubmerged;
	}
	switch(diveCount){
		case 0:
			if(lastSubmerged){
				//Completely submerged
				b2MassData md;
				ComputeMass(&md);
				*c = b2Mul(xf,md.center);
				return md.mass/m_density;
			}else{
				//Completely dry
				return 0;
			}
			break;
		case 1:
			if(intoIndex==-1){
				intoIndex = m_vertexCount-1;
			}else{
				outoIndex = m_vertexCount-1;
			}
			break;
	}
	int32 intoIndex2 = (intoIndex+1)%m_vertexCount;
	int32 outoIndex2 = (outoIndex+1)%m_vertexCount;
	
	float32 intoLambda = (0 - depths[intoIndex]) / (depths[intoIndex2] - depths[intoIndex]);
	float32 outoLambda = (0 - depths[outoIndex]) / (depths[outoIndex2] - depths[outoIndex]);
	
	b2Vec2 intoVec(	m_vertices[intoIndex].x*(1-intoLambda)+m_vertices[intoIndex2].x*intoLambda,
					m_vertices[intoIndex].y*(1-intoLambda)+m_vertices[intoIndex2].y*intoLambda);
	b2Vec2 outoVec(	m_vertices[outoIndex].x*(1-outoLambda)+m_vertices[outoIndex2].x*outoLambda,
					m_vertices[outoIndex].y*(1-outoLambda)+m_vertices[outoIndex2].y*outoLambda);
	
	//Initialize accumulator
	float32 area = 0;
	b2Vec2 center(0,0);
	b2Vec2 p2 = m_vertices[intoIndex2];
	b2Vec2 p3;
	
	float32 k_inv3 = 1.0f / 3.0f;
	
	//An awkward loop from intoIndex2+1 to outIndex2
	i = intoIndex2;
	while(i!=outoIndex2){
		i=(i+1)%m_vertexCount;
		if(i==outoIndex2)
			p3 = outoVec;
		else
			p3 = m_vertices[i];
		//Add the triangle formed by intoVec,p2,p3
		{
			b2Vec2 e1 = p2 - intoVec;
			b2Vec2 e2 = p3 - intoVec;
			
			float32 D = b2Cross(e1, e2);
			
			float32 triangleArea = 0.5f * D;

			area += triangleArea;
			
			// Area weighted centroid
			center += triangleArea * k_inv3 * (intoVec + p2 + p3);

		}
		//
		p2=p3;
	}
	
	//Normalize and transform centroid
	center *= 1.0f/area;
	
	*c = b2Mul(xf,center);
	
	return area;
}
float32 LH_b2BuoyancyController::ComputeSubmergedArea(b2Shape* shape,
                                                   const b2Vec2& normal,
                                                   float32 offset,
                                                   const b2Transform& xf,
                                                   b2Vec2* c,
                                                   float32 density) const
{
    if(shape->GetType() == b2Shape::e_edge)
    {
        //Note that v0 is independant of any details of the specific edge
        //We are relying on v0 being consistent between multiple edges of the same body
        b2Vec2 v0 = offset * normal;
        //b2Vec2 v0 = xf.position + (offset - b2Dot(normal, xf.position)) * normal;
        
        b2Vec2 v1 = b2Mul(xf, ((b2EdgeShape*)shape)->m_vertex1);
        b2Vec2 v2 = b2Mul(xf, ((b2EdgeShape*)shape)->m_vertex2);
        
        float32 d1 = b2Dot(normal, v1) - offset;
        float32 d2 = b2Dot(normal, v2) - offset;
        
        if(d1>0)
        {
            if(d2>0)
            {
                return 0;
            }
            else
            {
                v1 = -d2 / (d1 - d2) * v1 + d1 / (d1 - d2) * v2;
            }
        }
        else
        {
            if(d2>0)
            {
                v2 = -d2 / (d1 - d2) * v1 + d1 / (d1 - d2) * v2;
            }
            else
            {
                //Nothing
            }
        }
        
        // v0,v1,v2 represents a fully submerged triangle
        float32 k_inv3 = 1.0f / 3.0f;
        
        // Area weighted centroid
        *c = k_inv3 * (v0 + v1 + v2);
        
        b2Vec2 e1 = v1 - v0;
        b2Vec2 e2 = v2 - v0;
        
        return 0.5f * b2Cross(e1, e2);
    }
    else if(shape->GetType() == b2Shape::e_polygon)
    {
        //Transform plane into shape co-ordinates
        b2Vec2 normalL = b2MulT(xf.q,normal);
        float32 offsetL = offset - b2Dot(normal,xf.p);
        
        float32 depths[b2_maxPolygonVertices];
        int32 diveCount = 0;
        int32 intoIndex = -1;
        int32 outoIndex = -1;
        
        bool lastSubmerged = false;
        int32 i;
        for(i=0;i<((b2PolygonShape*)shape)->m_vertexCount;i++){
            depths[i] = b2Dot(normalL,((b2PolygonShape*)shape)->m_vertices[i]) - offsetL;
            
            
            bool isSubmerged = depths[i]<-FLT_EPSILON;
            if(i>0){
                if(isSubmerged){
                    if(!lastSubmerged){
                        intoIndex = i-1;
                        diveCount++;
                    }
                }else{
                    if(lastSubmerged){
                        outoIndex = i-1;
                        diveCount++;
                    }
                }
            }
            lastSubmerged = isSubmerged;
        }
        switch(diveCount){
            case 0:
                if(lastSubmerged){
                    //Completely submerged
                    b2MassData md;
                    ((b2PolygonShape*)shape)->ComputeMass(&md, density);
                    *c = b2Mul(xf,md.center);
                    return md.mass/density;
                }else{
                    //Completely dry
                    return 0;
                }
                break;
            case 1:
                if(intoIndex==-1){
                    intoIndex = ((b2PolygonShape*)shape)->m_vertexCount-1;
                }else{
                    outoIndex = ((b2PolygonShape*)shape)->m_vertexCount-1;
                }
                break;
        }
        int32 intoIndex2 = (intoIndex+1)%((b2PolygonShape*)shape)->m_vertexCount;
        int32 outoIndex2 = (outoIndex+1)%((b2PolygonShape*)shape)->m_vertexCount;
        
        float32 intoLambda = (0 - depths[intoIndex]) / (depths[intoIndex2] - depths[intoIndex]);
        float32 outoLambda = (0 - depths[outoIndex]) / (depths[outoIndex2] - depths[outoIndex]);
        
        b2Vec2 intoVec(	((b2PolygonShape*)shape)->m_vertices[intoIndex].x*(1-intoLambda)+((b2PolygonShape*)shape)->m_vertices[intoIndex2].x*intoLambda,
                       ((b2PolygonShape*)shape)->m_vertices[intoIndex].y*(1-intoLambda)+((b2PolygonShape*)shape)->m_vertices[intoIndex2].y*intoLambda);
        b2Vec2 outoVec(	((b2PolygonShape*)shape)->m_vertices[outoIndex].x*(1-outoLambda)+((b2PolygonShape*)shape)->m_vertices[outoIndex2].x*outoLambda,
                       ((b2PolygonShape*)shape)->m_vertices[outoIndex].y*(1-outoLambda)+((b2PolygonShape*)shape)->m_vertices[outoIndex2].y*outoLambda);
        
        //Initialize accumulator
        float32 area = 0;
        b2Vec2 center(0,0);
        b2Vec2 p2 = ((b2PolygonShape*)shape)->m_vertices[intoIndex2];
        b2Vec2 p3;
        
        float32 k_inv3 = 1.0f / 3.0f;
        
        //An awkward loop from intoIndex2+1 to outIndex2
        i = intoIndex2;
        while(i!=outoIndex2){
            i=(i+1)%((b2PolygonShape*)shape)->m_vertexCount;
            if(i==outoIndex2)
                p3 = outoVec;
            else
                p3 = ((b2PolygonShape*)shape)->m_vertices[i];
            //Add the triangle formed by intoVec,p2,p3
            {
                b2Vec2 e1 = p2 - intoVec;
                b2Vec2 e2 = p3 - intoVec;
                
                float32 D = b2Cross(e1, e2);
                
                float32 triangleArea = 0.5f * D;
                
                area += triangleArea;
                
                // Area weighted centroid
                center += triangleArea * k_inv3 * (intoVec + p2 + p3);
                
            }
            //
            p2=p3;
        }
        
        //Normalize and transform centroid
        center *= 1.0f/area;
        
        *c = b2Mul(xf,center);
        
        return area;
    }
    else if(shape->GetType() == b2Shape::e_circle)
    {
        b2Vec2 p = b2Mul(xf,((b2CircleShape*)shape)->m_p);
        float32 l = -(b2Dot(normal,p) - offset);
        if(l<-((b2CircleShape*)shape)->m_radius+FLT_EPSILON){
            //Completely dry
            return 0;
        }
        if(l > ((b2CircleShape*)shape)->m_radius){
            //Completely wet
            *c = p;
            return b2_pi*((b2CircleShape*)shape)->m_radius*((b2CircleShape*)shape)->m_radius;
        }
        
        //Magic
        float32 r2 = ((b2CircleShape*)shape)->m_radius*((b2CircleShape*)shape)->m_radius;
        float32 l2 = l*l;
        //TODO: write b2Sqrt to handle fixed point case.
        float32 area = r2 * (asin(l/((b2CircleShape*)shape)->m_radius) + b2_pi/2.0f)+ l * b2Sqrt(r2 - l2);
        float32 com = -2.0f/3.0f*pow(r2-l2,1.5f)/area;
        
        c->x = p.x + normal.x * com;
        c->y = p.y + normal.y * com;
        
        return area;
    }
    
    return 0;
}