bool ConvexPolyhedron3<Real>::ComputeSilhouette (V3Array& rkTerminator,
    const Vector3<Real>& rkEye, const Plane3<Real>& rkPlane,
    const Vector3<Real>& rkU, const Vector3<Real>& rkV,
    V2Array& rkSilhouette)
{
    Real fEDist = rkPlane.DistanceTo(rkEye);  // assert:  fEDist > 0

    // closest planar point to E is K = E-dist*N
    Vector3<Real> kClosest = rkEye - fEDist*rkPlane.GetNormal();

    // project polyhedron points onto plane
    for (int i = 0; i < (int)rkTerminator.size(); i++)
    {
        Vector3<Real>& rkPoint = rkTerminator[i];

        Real fVDist = rkPlane.DistanceTo(rkPoint);
        if ( fVDist >= fEDist )
        {
            // cannot project vertex onto plane
            return false;
        }

        // compute projected point Q
        Real fRatio = fEDist/(fEDist-fVDist);
        Vector3<Real> kProjected = rkEye + fRatio*(rkPoint - rkEye);

        // compute (x,y) so that Q = K+x*U+y*V+z*N
        Vector3<Real> kDiff = kProjected - kClosest;
        rkSilhouette.push_back(Vector2<Real>(rkU.Dot(kDiff),rkV.Dot(kDiff)));
    }

    return true;
}
Exemplo n.º 2
0
bool Wml::Culled (const Plane3<Real>& rkPlane, const Box3<Real>& rkBox)
{
    Real fTmp[3] =
    {
        rkBox.Extent(0)*(rkPlane.GetNormal().Dot(rkBox.Axis(0))),
        rkBox.Extent(1)*(rkPlane.GetNormal().Dot(rkBox.Axis(1))),
        rkBox.Extent(2)*(rkPlane.GetNormal().Dot(rkBox.Axis(2)))
    };

    Real fRadius = Math<Real>::FAbs(fTmp[0]) + Math<Real>::FAbs(fTmp[1]) +
        Math<Real>::FAbs(fTmp[2]);

    Real fPseudoDistance = rkPlane.DistanceTo(rkBox.Center());
    return fPseudoDistance <= -fRadius;
}
Exemplo n.º 3
0
int BVaabb::WhichSide(const Plane3& plane) const
{
	if (mAlwaysPass)
		return 1;
	Real fDistance = plane.DistanceTo(mCenter);
	if (fDistance <= -mRadius)
	{
		return -1;
	}

	if (fDistance >= mRadius)
	{
		return +1;
	}

	return 0;
}
Exemplo n.º 4
0
void PerspectiveProjectEllipsoid (const Ellipsoid3<Real>& ellipsoid,
    const Vector3<Real>& eye, const Plane3<Real>& plane,
    const Vector3<Real>& U, const Vector3<Real>& V, Vector3<Real>& P,
    Ellipse2<Real>& ellipse)
{
    // Get coefficients for ellipsoid as X^T*A*X + B^T*X + C = 0.
    Matrix3<Real> A;
    Vector3<Real> B;
    Real C;
    ellipsoid.ToCoefficients(A, B, C);

    // Compute matrix M (see PerspectiveProjectionEllipsoid.pdf).
    Vector3<Real> AE = A*eye;
    Real EAE = eye.Dot(AE);
    Real BE = B.Dot(eye);
    Real QuadE = ((Real)4)*(EAE + BE + C);
    Vector3<Real> Bp2AE = B + ((Real)2)*AE;
    Matrix3<Real> mat = Matrix3<Real>(Bp2AE, Bp2AE) - QuadE*A;

    // Compute coefficients for projected ellipse.
    Vector3<Real> MU = mat*U;
    Vector3<Real> MV = mat*V;
    Vector3<Real> MN = mat*plane.Normal;
    Real DmNdE = -plane.DistanceTo(eye);
    P = eye + DmNdE*plane.Normal;

    Matrix2<Real> AOut;
    Vector2<Real> BOut;
    Real COut;
    AOut[0][0] = U.Dot(MU);
    AOut[0][1] = U.Dot(MV);
    AOut[1][1] = V.Dot(MV);
    AOut[1][0] = AOut[0][1];
    BOut[0] = ((Real)2)*DmNdE*(U.Dot(MN));
    BOut[1] = ((Real)2)*DmNdE*(V.Dot(MN));
    COut = DmNdE*DmNdE*(plane.Normal.Dot(MN));
    ellipse.FromCoefficients(AOut, BOut, COut);
}
Exemplo n.º 5
0
int ConvexClipper<Real>::Clip (const Plane3<Real>& plane)
{
    // Sompute signed distances from vertices to plane.
    int numPositive = 0, numNegative = 0;
    const int numVertices = (int)mVertices.size();
    for (int v = 0; v < numVertices; ++v)
    {
        Vertex& vertex = mVertices[v];
        if (vertex.Visible)
        {
            vertex.Distance = plane.DistanceTo(vertex.Point);
            if (vertex.Distance >= mEpsilon)
            {
                ++numPositive;
            }
            else if (vertex.Distance <= -mEpsilon)
            {
                ++numNegative;
                vertex.Visible = false;
            }
            else
            {
                // The point is on the plane (within floating point
                // tolerance).
                vertex.Distance = (Real)0;
            }
        }
    }

    if (numPositive == 0)
    {
        // Mesh is in negative half-space, fully clipped.
        return -1;
    }

    if (numNegative == 0)
    {
        // Mesh is in positive half-space, fully visible.
        return +1;
    }

    // Clip the visible edges.
    const int numEdges = (int)mEdges.size();
    for (int e = 0; e < numEdges; ++e)
    {
        Edge& edge = mEdges[e];
        if (edge.Visible)
        {
            int v0 = edge.Vertex[0];
            int v1 = edge.Vertex[1];
            int f0 = edge.Face[0];
            int f1 = edge.Face[1];
            Face& face0 = mFaces[f0];
            Face& face1 = mFaces[f1];
            Real d0 = mVertices[v0].Distance;
            Real d1 = mVertices[v1].Distance;

            if (d0 <= (Real)0 && d1 <= (Real)0)
            {
                // The edge is culled.  If the edge is exactly on the clip
                // plane, it is possible that a visible triangle shares it.
                // The edge will be re-added during the face loop.
                face0.Edges.erase(e);
                if (face0.Edges.empty())
                {
                    face0.Visible = false;
                }

                face1.Edges.erase(e);
                if (face1.Edges.empty())
                {
                    face1.Visible = false;
                }

                edge.Visible = false;
                continue;
            }

            if (d0 >= (Real)0 && d1 >= (Real)0)
            {
                // Face retains the edge.
                continue;
            }

            // The edge is split by the plane.  Compute the point of
            // intersection.  If the old edge is <V0,V1> and I is the
            // intersection point, the new edge is <V0,I> when d0 > 0 or
            // <I,V1> when d1 > 0.
            int vNew = (int)mVertices.size();
            mVertices.push_back(Vertex());
            Vertex& vertexNew = mVertices[vNew];

            Vector3<Real>& point0 = mVertices[v0].Point;
            Vector3<Real>& point1 = mVertices[v1].Point;
            vertexNew.Point = point0 + (d0/(d0 - d1))*(point1 - point0);

            if (d0 > (Real)0)
            {
                edge.Vertex[1] = vNew;
            }
            else
            {
                edge.Vertex[0] = vNew;
            }
        }
    }

    // The mesh straddles the plane.  A new convex polygonal face will be
    // generated.  Add it now and insert edges when they are visited.
    int fNew = (int)mFaces.size();
    mFaces.push_back(Face());
    Face& faceNew = mFaces[fNew];
    faceNew.Plane = plane;

    // Process the faces.
    for (int f = 0; f < fNew; ++f)
    {
        Face& face = mFaces[f];
        if (face.Visible)
        {
            // Determine if the face is on the negative side, the positive
            // side, or split by the clipping plane.  The Occurs members
            // are set to zero to help find the end points of the polyline
            // that results from clipping a face.
            assertion(face.Edges.size() >= 2, "Unexpected condition.\n");
            std::set<int>::iterator iter = face.Edges.begin();
            std::set<int>::iterator end = face.Edges.end();
            while (iter != end)
            {
                int e = *iter++;
                Edge& edge = mEdges[e];
                assertion(edge.Visible, "Unexpected condition.\n");
                mVertices[edge.Vertex[0]].Occurs = 0;
                mVertices[edge.Vertex[1]].Occurs = 0;
            }

            int vStart, vFinal;
            if (GetOpenPolyline(face, vStart, vFinal))
            {
                // Polyline is open, close it up.
                int eNew = (int)mEdges.size();
                mEdges.push_back(Edge());
                Edge& edgeNew = mEdges[eNew];

                edgeNew.Vertex[0] = vStart;
                edgeNew.Vertex[1] = vFinal;
                edgeNew.Face[0] = f;
                edgeNew.Face[1] = fNew;

                // Add new edge to polygons.
                face.Edges.insert(eNew);
                faceNew.Edges.insert(eNew);
            }
        }
    }

    // Process 'faceNew' to make sure it is a simple polygon (theoretically
    // convex, but numerically may be slightly not convex).  Floating-point
    // round-off errors can cause the new face from the last loop to be
    // needle-like with a collapse of two edges into a single edge.  This
    // block guarantees the invariant "face always a simple polygon".
    Postprocess(fNew, faceNew);
    if (faceNew.Edges.size() < 3)
    {
        // Face is completely degenerate, remove it from mesh.
        mFaces.pop_back();
    }

    return 0;
}
void IntrTetrahedron3Tetrahedron3<Real>::SplitAndDecompose (
    Tetrahedron3<Real> tetra, const Plane3<Real>& plane,
    std::vector<Tetrahedron3<Real> >& inside)
{
    // Determine on which side of the plane the points of the tetrahedron lie.
    Real C[4];
    int i, pos[4], neg[4], zer[4];
    int positive = 0, negative = 0, zero = 0;

    for (i = 0; i < 4; ++i)
    {
        C[i] = plane.DistanceTo(tetra.V[i]);
        if (C[i] > (Real)0)
        {
            pos[positive++] = i;
        }
        else if (C[i] < (Real)0)
        {
            neg[negative++] = i;
        }
        else
        {
            zer[zero++] = i;
        }
    }

    // For a split to occur, one of the c_i must be positive and one must
    // be negative.

    if (negative == 0)
    {
        // Tetrahedron is completely on the positive side of plane, full clip.
        return;
    }

    if (positive == 0)
    {
        // Tetrahedron is completely on the negative side of plane.
        inside.push_back(tetra);
        return;
    }

    // Tetrahedron is split by plane.  Determine how it is split and how to
    // decompose the negative-side portion into tetrahedra (6 cases).
    Real w0, w1, invCDiff;
    Vector3<Real> intp[4];

    if (positive == 3)
    {
        // +++-
        for (i = 0; i < positive; ++i)
        {
            invCDiff = ((Real)1)/(C[pos[i]] - C[neg[0]]);
            w0 = -C[neg[0]]*invCDiff;
            w1 = +C[pos[i]]*invCDiff;
            tetra.V[pos[i]] = w0*tetra.V[pos[i]] +
                w1*tetra.V[neg[0]];
        }
        inside.push_back(tetra);
    }
    else if (positive == 2)
    {
        if (negative == 2)
        {
            // ++--
            for (i = 0; i < positive; ++i)
            {
                invCDiff = ((Real)1)/(C[pos[i]] - C[neg[0]]);
                w0 = -C[neg[0]]*invCDiff;
                w1 = +C[pos[i]]*invCDiff;
                intp[i] = w0*tetra.V[pos[i]] + w1*tetra.V[neg[0]];
            }
            for (i = 0; i < negative; ++i)
            {
                invCDiff = ((Real)1)/(C[pos[i]] - C[neg[1]]);
                w0 = -C[neg[1]]*invCDiff;
                w1 = +C[pos[i]]*invCDiff;
                intp[i+2] = w0*tetra.V[pos[i]] +
                    w1*tetra.V[neg[1]];
            }

            tetra.V[pos[0]] = intp[2];
            tetra.V[pos[1]] = intp[1];
            inside.push_back(tetra);

            inside.push_back(Tetrahedron3<Real>(tetra.V[neg[1]],
                intp[3], intp[2], intp[1]));

            inside.push_back(Tetrahedron3<Real>(tetra.V[neg[0]],
                intp[0], intp[1], intp[2]));
        }
        else
        {
            // ++-0
            for (i = 0; i < positive; ++i)
            {
                invCDiff = ((Real)1)/(C[pos[i]] - C[neg[0]]);
                w0 = -C[neg[0]]*invCDiff;
                w1 = +C[pos[i]]*invCDiff;
                tetra.V[pos[i]] = w0*tetra.V[pos[i]] +
                    w1*tetra.V[neg[0]];
            }
            inside.push_back(tetra);
        }
    }
    else if (positive == 1)
    {
        if (negative == 3)
        {
            // +---
            for (i = 0; i < negative; ++i)
            {
                invCDiff = ((Real)1)/(C[pos[0]] - C[neg[i]]);
                w0 = -C[neg[i]]*invCDiff;
                w1 = +C[pos[0]]*invCDiff;
                intp[i] = w0*tetra.V[pos[0]] + w1*tetra.V[neg[i]];
            }

            tetra.V[pos[0]] = intp[0];
            inside.push_back(tetra);

            inside.push_back(Tetrahedron3<Real>(intp[0],
                tetra.V[neg[1]], tetra.V[neg[2]], intp[1]));

            inside.push_back(Tetrahedron3<Real>(tetra.V[neg[2]],
                intp[1], intp[2], intp[0]));
        }
        else if (negative == 2)
        {
            // +--0
            for (i = 0; i < negative; ++i)
            {
                invCDiff = ((Real)1)/(C[pos[0]] - C[neg[i]]);
                w0 = -C[neg[i]]*invCDiff;
                w1 = +C[pos[0]]*invCDiff;
                intp[i] = w0*tetra.V[pos[0]] + w1*tetra.V[neg[i]];
            }

            tetra.V[pos[0]] = intp[0];
            inside.push_back(tetra);

            inside.push_back(Tetrahedron3<Real>(intp[1],
                tetra.V[zer[0]], tetra.V[neg[1]], intp[0]));
        }
        else
        {
            // +-00
            invCDiff = ((Real)1)/(C[pos[0]] - C[neg[0]]);
            w0 = -C[neg[0]]*invCDiff;
            w1 = +C[pos[0]]*invCDiff;
            tetra.V[pos[0]] = w0*tetra.V[pos[0]] +
                w1*tetra.V[neg[0]];
            inside.push_back(tetra);
        }
    }
}