//----------------------------------------------------------------------------
void Boolean2D::DrawPolySolid (BspPolygon2& polygon, ColorRGB color)
{
    Vector2d  v0, v1;
    Edge2 edge;
    int i, x0, y0, x1, y1;

    // Draw the edges.
    for (i = 0; i < polygon.GetNumEdges(); ++i)
    {
        polygon.GetEdge(i, edge);
        polygon.GetVertex(edge.I0, v0);
        polygon.GetVertex(edge.I1, v1);
        
        x0 = (int)(v0.X() + 0.5f);
        y0 = GetWidth() - 1 - (int)(v0.Y() + 0.5f);
        x1 = (int)(v1.X() + 0.5f);
        y1 = GetWidth() - 1 - (int)(v1.Y() + 0.5f);

        DrawLine(x0, y0, x1, y1, color);
    }

    // Draw the vertices.
    ColorRGB black(0, 0, 0);
    for (i = 0; i < polygon.GetNumVertices(); ++i)
    {
        polygon.GetVertex(i, v0);
        x0 = (int)(v0.X() + 0.5f);
        y0 = GetWidth() - 1 - (int)(v0.Y() + 0.5f);
        SetThickPixel(x0, y0, 1, black);
    }
}
//----------------------------------------------------------------------------
BspPolygon2* Boolean2D::ConstructPentagon ()
{
    const int numVertices = 5;

    double primitiveAngle = Mathd::TWO_PI/numVertices;
    double radius = 0.35*GetWidth();
    double cx = 0.5*GetWidth(), cy = 0.5*GetWidth();

    Vector2d vertices[numVertices];
    for (int i = 0; i < numVertices; ++i)
    {
        double angle = i*primitiveAngle;
        vertices[i].X() = cx + radius*Mathd::Cos(angle);
        vertices[i].Y() = cy + radius*Mathd::Sin(angle);
    }

    BspPolygon2* poly = new0 BspPolygon2();
    for (int i0 = numVertices - 1, i1 = 0; i1 < numVertices; i0 = i1++)
    {
        poly->InsertVertex(vertices[i1]);
        poly->InsertEdge(Edge2(i0, i1));
    }
    poly->Finalize();
    return poly;
}
//----------------------------------------------------------------------------
BspPolygon2* Boolean2D::ConstructInvertedEll ()
{
    double w = (double)GetWidth();
    double d1d8 = 0.125*w;
    double d2d8 = 0.250*w;
    double d3d8 = 0.375*w;
    double d5d8 = 0.625*w;
    double d6d8 = 0.750*w;
    double d7d8 = 0.875*w;

    const int numVertices = 10;
    Vector2d vertices[numVertices] =
    {
        Vector2d(d1d8, d1d8),
        Vector2d(d3d8, d1d8),
        Vector2d(d3d8, d3d8),
        Vector2d(d2d8, d3d8),
        Vector2d(d2d8, d6d8),
        Vector2d(d5d8, d6d8),
        Vector2d(d5d8, d5d8),
        Vector2d(d7d8, d5d8),
        Vector2d(d7d8, d7d8),
        Vector2d(d1d8, d7d8)
    };

    BspPolygon2* poly = new0 BspPolygon2();
    for (int i0 = numVertices - 1, i1 = 0; i1 < numVertices; i0 = i1++)
    {
        poly->InsertVertex(vertices[i1]);
        poly->InsertEdge(Edge2(i0, i1));
    }
    poly->Finalize();
    return poly;
}
Exemple #4
0
//----------------------------------------------------------------------------
BspPolygon2 BspPolygon2::operator& (const BspPolygon2& polygon) const
{
    assertion(mTree != 0, "Tree must exist.\n");

    // intersection
    BspPolygon2 intersect;
    GetInsideEdgesFrom(polygon, intersect);
    polygon.GetInsideEdgesFrom(*this, intersect);
    intersect.Finalize();
    return intersect;
}
Exemple #5
0
//----------------------------------------------------------------------------
void BspTree2::GetNegPartition (const BspPolygon2& polygon,
    const Vector2d& v0, const Vector2d& v1, BspPolygon2& pos,
    BspPolygon2& neg, BspPolygon2& coSame, BspPolygon2& coDiff) const
{
    if (mNegChild)
    {
        mNegChild->GetPartition(polygon, v0, v1, pos, neg, coSame, coDiff);
    }
    else
    {
        int i0 = neg.InsertVertex(v0);
        int i1 = neg.InsertVertex(v1);
        neg.InsertEdge(Edge2(i0, i1));
    }
}
Exemple #6
0
//----------------------------------------------------------------------------
BspPolygon2 BspPolygon2::operator~ () const
{
    assertion(mTree != 0, "Tree must exist.\n");

    // negation
    BspPolygon2 neg;
    neg.mVMap = mVMap;
    neg.mVArray = mVArray;
    ECIterator iter = mEMap.begin();
    ECIterator end = mEMap.end();
    for (/**/; iter != end; ++iter)
    {
        neg.InsertEdge(Edge2(iter->first.I1, iter->first.I0));
    }

    neg.mTree = mTree->GetCopy();
    neg.mTree->Negate();
    return neg;
}
//----------------------------------------------------------------------------
BspPolygon2* Boolean2D::ConstructSShape ()
{
    double w = (double)GetWidth();
    double d10d32 = 10.0*w/32.0;
    double d12d32 = 12.0*w/32.0;
    double d13d32 = 13.0*w/32.0;
    double d16d32 = 16.0*w/32.0;
    double d19d32 = 19.0*w/32.0;
    double d20d32 = 20.0*w/32.0;
    double d22d32 = 22.0*w/32.0;
    double d24d32 = 24.0*w/32.0;
    double d26d32 = 26.0*w/32.0;
    double d28d32 = 28.0*w/32.0;

    const int numVertices = 12;
    Vector2d vertices[numVertices] =
    {
        Vector2d(d24d32, d10d32),
        Vector2d(d28d32, d10d32),
        Vector2d(d28d32, d16d32),
        Vector2d(d22d32, d16d32),
        Vector2d(d22d32, d19d32),
        Vector2d(d24d32, d19d32),
        Vector2d(d24d32, d22d32),
        Vector2d(d20d32, d22d32),
        Vector2d(d20d32, d13d32),
        Vector2d(d26d32, d13d32),
        Vector2d(d26d32, d12d32),
        Vector2d(d24d32, d12d32)
    };

    BspPolygon2* poly = new0 BspPolygon2();
    for (int i0 = numVertices - 1, i1 = 0; i1 < numVertices; i0 = i1++)
    {
        poly->InsertVertex(vertices[i1]);
        poly->InsertEdge(Edge2(i0, i1));
    }
    poly->Finalize();
    return poly;
}
//----------------------------------------------------------------------------
BspPolygon2* Boolean2D::ConstructSquare ()
{
    double w = (double)GetWidth();
    double d2d8 = 0.250*w;
    double d6d8 = 0.750*w;

    const int numVertices = 4;
    Vector2d vertices[numVertices] =
    {
        Vector2d(d2d8, d2d8),
        Vector2d(d6d8, d2d8),
        Vector2d(d6d8, d6d8),
        Vector2d(d2d8, d6d8)
    };

    BspPolygon2* poly = new0 BspPolygon2();
    for (int i0 = numVertices - 1, i1 = 0; i1 < numVertices; i0 = i1++)
    {
        poly->InsertVertex(vertices[i1]);
        poly->InsertEdge(Edge2(i0, i1));
    }
    poly->Finalize();
    return poly;
}
Exemple #9
0
//----------------------------------------------------------------------------
void BspPolygon2::GetInsideEdgesFrom (const BspPolygon2& polygon,
    BspPolygon2& inside) const
{
    assertion(mTree != 0, "Tree must exist.\n");

    BspPolygon2 ignore;
    const int numEdges = polygon.GetNumEdges();
    for (int i = 0; i < numEdges; ++i)
    {
        int v0 = polygon.mEArray[i].I0;
        int v1 = polygon.mEArray[i].I1;
        Vector2d vertex0 = polygon.mVArray[v0];
        Vector2d vertex1 = polygon.mVArray[v1];
        mTree->GetPartition(*this, vertex0, vertex1, ignore, inside, inside,
            ignore);
    }
}
//----------------------------------------------------------------------------
BspPolygon2* Boolean2D::ConstructPolyWithHoles ()
{
    double w = (double)GetWidth();
    double d2d16 = 2.0*w/16.0;
    double d3d16 = 3.0*w/16.0;
    double d4d16 = 4.0*w/16.0;
    double d6d16 = 6.0*w/16.0;
    double d14d16 = 14.0*w/16.0;

    const int numVertices = 6;
    Vector2d vertices[numVertices] =
    {
        // outer boundary
        Vector2d(d2d16, d2d16),
        Vector2d(d14d16, d2d16),
        Vector2d(d2d16, d14d16),

        // inner boundary
        Vector2d(d4d16, d3d16),
        Vector2d(d6d16, d6d16),
        Vector2d(d6d16, d3d16)
    };

    BspPolygon2* poly = new0 BspPolygon2();
    for (int i = 0; i < numVertices; ++i)
    {
        poly->InsertVertex(vertices[i]);
    }

    poly->InsertEdge(Edge2(0, 1));
    poly->InsertEdge(Edge2(1, 2));
    poly->InsertEdge(Edge2(2, 0));
    poly->InsertEdge(Edge2(3, 4));
    poly->InsertEdge(Edge2(4, 5));
    poly->InsertEdge(Edge2(5, 3));

    poly->Finalize();
    return poly;
}
Exemple #11
0
//----------------------------------------------------------------------------
void BspTree2::GetCoPartition (const BspPolygon2& polygon, const Vector2d& v0,
    const Vector2d& v1, BspPolygon2& pos, BspPolygon2& neg,
    BspPolygon2& coSame, BspPolygon2& coDiff) const
{
    const double epsilon = 0.00001;

    // Segment the line containing V0 and V1 by the coincident intervals that
    // intersect <V0,V1>.
    Vector2d dir = v1 - v0;
    double tmax = dir.Dot(dir);

    Vector2d end0, end1;
    double t0, t1;
    bool sameDir;

    std::list<Interval> intervalList;
    std::list<Interval>::iterator iter;

    const int numEdges = (int)mCoincident.size();
    for (int i = 0; i < numEdges; ++i)
    {
        end0 = polygon.mVArray[mCoincident[i].I0];
        end1 = polygon.mVArray[mCoincident[i].I1];

        t0 = dir.Dot(end0 - v0);
        if (Mathd::FAbs(t0) <= epsilon)
        {
            t0 = 0.0;
        }
        else if (Mathd::FAbs(t0 - tmax) <= epsilon)
        {
            t0 = tmax;
        }

        t1 = dir.Dot(end1 - v0);
        if (Mathd::FAbs(t1) <= epsilon)
        {
            t1 = 0.0;
        }
        else if (Mathd::FAbs(t1 - tmax) <= epsilon)
        {
            t1 = tmax;
        }

        sameDir = (t1 > t0);
        if (!sameDir)
        {
            double save = t0;
            t0 = t1;
            t1 = save;
        }

        if (t1 > 0.0 && t0 < tmax)
        {
            if (intervalList.empty())
            {
                intervalList.push_front(Interval(t0, t1, sameDir, true));
            }
            else
            {
                iter = intervalList.begin();
                for (/**/; iter != intervalList.end(); ++iter)
                {
                    if (Mathd::FAbs(t1 - iter->T0) <= epsilon)
                    {
                        t1 = iter->T0;
                    }

                    if (t1 <= iter->T0)
                    {
                        // [t0,t1] is on the left of [I.t0,I.t1]
                        intervalList.insert(iter,
                            Interval(t0, t1, sameDir, true));
                        break;
                    }

                    // Theoretically, the intervals are disjoint or intersect
                    // only at an end point.  The assert makes sure that
                    // [t0,t1] is to the right of [I.t0,I.t1].
                    if (Mathd::FAbs(t0 - iter->T1) <= epsilon)
                    {
                        t0 = iter->T1;
                    }

                    assertion(t0 >= iter->T1, "Invalid ordering.\n");

                    std::list<Interval>::iterator last = intervalList.end();
                    --last;
                    if (iter == last)
                    {
                        intervalList.push_back(Interval(t0, t1, sameDir,
                            true));
                        break;
                    }
                }
            }
        }
    }

    if (intervalList.empty())
    {
        GetPosPartition(polygon, v0, v1, pos, neg, coSame, coDiff);
        GetNegPartition(polygon, v0, v1, pos, neg, coSame, coDiff);
        return;
    }

    // Insert outside intervals between the touching intervals.  It is
    // possible that two touching intervals are adjacent, so this is not just
    // a simple alternation of touching and outside intervals.
    Interval& front = intervalList.front();
    if (front.T0 > 0.0)
    {
        intervalList.push_front(Interval(0.0, front.T0, front.SameDir,
            false));
    }
    else
    {
        front.T0 = 0.0;
    }

    Interval& back = intervalList.back();
    if (back.T1 < tmax)
    {
        intervalList.push_back(Interval(back.T1, tmax, back.SameDir, false));
    }
    else
    {
        back.T1 = tmax;
    }

    std::list<Interval>::iterator iter0 = intervalList.begin();
    std::list<Interval>::iterator iter1 = intervalList.begin();
    for (++iter1; iter1 != intervalList.end(); ++iter0, ++iter1)
    {
        t0 = iter0->T1;
        t1 = iter1->T0;
        if (t1 - t0 > epsilon)
        {
            iter0 = intervalList.insert(iter1, Interval(t0, t1, true, false));
        }
    }

    // Process the segmentation.
    double invTMax = 1.0/tmax;
    t0 = intervalList.front().T0*invTMax;
    end1 = v0 + (intervalList.front().T0*invTMax)*dir;
    iter = intervalList.begin();
    for (/**/; iter != intervalList.end(); ++iter)
    {
        end0 = end1;
        t1 = iter->T1*invTMax;
        end1 = v0 + (iter->T1*invTMax)*dir;

        if (iter->Touching)
        {
            Edge2 edge;
            if (iter->SameDir)
            {
                edge.I0 = coSame.InsertVertex(end0);
                edge.I1 = coSame.InsertVertex(end1);
                if (edge.I0 != edge.I1)
                {
                    coSame.InsertEdge(edge);
                }
            }
            else
            {
                edge.I0 = coDiff.InsertVertex(end1);
                edge.I1 = coDiff.InsertVertex(end0);
                if (edge.I0 != edge.I1)
                {
                    coDiff.InsertEdge(edge);
                }
            }
        }
        else
        {
            GetPosPartition(polygon, end0, end1, pos, neg, coSame, coDiff);
            GetNegPartition(polygon, end0, end1, pos, neg, coSame, coDiff);
        }
    }
}
Exemple #12
0
//----------------------------------------------------------------------------
BspTree2::BspTree2 (BspPolygon2& polygon, const EArray& edges)
{
    assertion(edges.size() > 0, "Invalid input.\n");

    // Construct splitting line from first edge.
    Vector2d end0 = polygon.mVArray[edges[0].I0];
    Vector2d end1 = polygon.mVArray[edges[0].I1];

    // Add edge to coincident list.
    mCoincident.push_back(edges[0]);

    // Split remaining edges.
    EArray posArray, negArray;
    int imax = (int)edges.size();
    for (int i = 1; i < imax; ++i)
    {
        int v0 = edges[i].I0;
        int v1 = edges[i].I1;
        Vector2d vertex0 = polygon.mVArray[v0];
        Vector2d vertex1 = polygon.mVArray[v1];

        Vector2d intr;
        int vmid;

        switch (Classify(end0, end1, vertex0, vertex1, intr))
        {
            case TRANSVERSE_POSITIVE:
                // modify edge <V0,V1> to <V0,I> and add new edge <I,V1>
                vmid = polygon.InsertVertex(intr);
                polygon.SplitEdge(v0, v1, vmid);
                posArray.push_back(Edge2(vmid, v1));
                negArray.push_back(Edge2(v0, vmid));
                break;
            case TRANSVERSE_NEGATIVE:
                // modify edge <V0,V1> to <V0,I> and add new edge <I,V1>
                vmid = polygon.InsertVertex(intr);
                polygon.SplitEdge(v0, v1, vmid);
                posArray.push_back(Edge2(v0, vmid));
                negArray.push_back(Edge2(vmid, v1));
                break;
            case ALL_POSITIVE:
                posArray.push_back(edges[i]);
                break;
            case ALL_NEGATIVE:
                negArray.push_back(edges[i]);
                break;
            default:  // COINCIDENT
                mCoincident.push_back(edges[i]);
                break;
        }
    }

    if (posArray.size() > 0)
    {
        mPosChild = new0 BspTree2(polygon, posArray);
    }
    else
    {
        mPosChild = 0;
    }

    if (negArray.size() > 0)
    {
        mNegChild = new0 BspTree2(polygon, negArray);
    }
    else
    {
        mNegChild = 0;
    }
}