void Path::DoButt(Shape *dest, double width, ButtType butt, Geom::Point pos, Geom::Point dir,
        int &leftNo, int &rightNo)
{
    Geom::Point nor;
    nor = dir.ccw();

    if (butt == butt_square)
    {
        Geom::Point x;
        x = pos + width * dir + width * nor;
        int bleftNo = dest->AddPoint (x);
        x = pos + width * dir - width * nor;
        int brightNo = dest->AddPoint (x);
        x = pos + width * nor;
        leftNo = dest->AddPoint (x);
        x = pos - width * nor;
        rightNo = dest->AddPoint (x);
        dest->AddEdge (rightNo, brightNo);
        dest->AddEdge (brightNo, bleftNo);
        dest->AddEdge (bleftNo, leftNo);
    }
    else if (butt == butt_pointy)
    {
        leftNo = dest->AddPoint (pos + width * nor);
        rightNo = dest->AddPoint (pos - width * nor);
        int mid = dest->AddPoint (pos + width * dir);
        dest->AddEdge (rightNo, mid);
        dest->AddEdge (mid, leftNo);
    }
    else if (butt == butt_round)
    {
        const Geom::Point sx = pos + width * nor;
        const Geom::Point ex = pos - width * nor;
        leftNo = dest->AddPoint (sx);
        rightNo = dest->AddPoint (ex);

        RecRound (dest, rightNo, leftNo, ex, sx, -nor, nor, pos, width);
    }
    else
    {
        leftNo = dest->AddPoint (pos + width * nor);
        rightNo = dest->AddPoint (pos - width * nor);
        dest->AddEdge (rightNo, leftNo);
    }
}
Пример #2
0
// find the position at which node "newOne" should be inserted in the subtree rooted here
// we want to order with respect to the order of intersections with the sweepline, currently 
// lying at y=px[1].
// px is the upper endpoint of newOne
int
SweepTree::Find(Geom::Point const &px, SweepTree *newOne, SweepTree *&insertL,
                SweepTree *&insertR, bool sweepSens)
{
    // get the edge associated with this node: one point+one direction
    // since we're dealing with line, the direction (bNorm) is taken downwards
    Geom::Point bOrig, bNorm;
    bOrig = src->pData[src->getEdge(bord).st].rx;
    bNorm = src->eData[bord].rdx;
    if (src->getEdge(bord).st > src->getEdge(bord).en) {
        bNorm = -bNorm;
    }
    // rotate to get the normal to the edge
    bNorm=bNorm.ccw();

    Geom::Point diff;
    diff = px - bOrig;

    // compute (px-orig)^dir to know on which side of this edge the point px lies
    double y = 0;
    //if ( startPoint == newOne->startPoint ) {
    //   y=0;
    //} else {
    y = dot(bNorm, diff);
    //}
    //y*=invDirLength;
    if (fabs(y) < 0.000001) {
        // that damn point px lies on me, so i need to consider to direction of the edge in
        // newOne to know if it goes toward my left side or my right side
        // sweepSens is needed (actually only used by the Scan() functions) because if the sweepline goes upward,
        // signs change
        // prendre en compte les directions
        Geom::Point nNorm;
        nNorm = newOne->src->eData[newOne->bord].rdx;
        if (newOne->src->getEdge(newOne->bord).st >
            newOne->src->getEdge(newOne->bord).en)
	{
            nNorm = -nNorm;
	}
        nNorm=nNorm.ccw();

        if (sweepSens) {
            y = cross(nNorm, bNorm);
        } else {
            y = cross(bNorm, nNorm);
        }
        if (y == 0) {
            y = dot(bNorm, nNorm);
            if (y == 0) {
                insertL = this;
                insertR = static_cast<SweepTree *>(elem[RIGHT]);
                return found_exact;
            }
        }
    }
    if (y < 0) {
        if (son[LEFT]) {
            return (static_cast<SweepTree *>(son[LEFT]))->Find(px, newOne,
                                                               insertL, insertR,
                                                               sweepSens);
	} else {
            insertR = this;
            insertL = static_cast<SweepTree *>(elem[LEFT]);
            if (insertL) {
                return found_between;
            } else {
                return found_on_left;
	    }
	}
    } else {
        if (son[RIGHT]) {
            return (static_cast<SweepTree *>(son[RIGHT]))->Find(px, newOne,
                                                                insertL, insertR,
                                                                sweepSens);
	} else {
            insertL = this;
            insertR = static_cast<SweepTree *>(elem[RIGHT]);
            if (insertR) {
                return found_between;
	    } else {
                return found_on_right;
	    }
	}
    }
    return not_found;
}
    void
Path::DoRightJoin (Shape * dest, double width, JoinType join, Geom::Point pos,
        Geom::Point prev, Geom::Point next, double miter, double /*prevL*/,
        double /*nextL*/, int &rightStNo, int &rightEnNo,int pathID,int pieceID,double tID)
{
    const Geom::Point pnor=prev.ccw();
    const Geom::Point nnor=next.ccw();
    double angSi = cross (next,prev);
    if (angSi > -0.0001 && angSi < 0.0001)
    {
        double angCo = dot (prev, next);
        if (angCo > 0.9999)
        {
            // tout droit
            rightEnNo = rightStNo = dest->AddPoint (pos - width*pnor);
        }
        else
        {
            // demi-tour
            rightEnNo = dest->AddPoint (pos + width*pnor);
            rightStNo = dest->AddPoint (pos - width*pnor);
            int nEdge=dest->AddEdge (rightStNo, rightEnNo);
            if ( dest->hasBackData() ) {
                dest->ebData[nEdge].pathID=pathID;
                dest->ebData[nEdge].pieceID=pieceID;
                dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
            }
        }
        return;
    }
    if (angSi < 0)
    {
        if (join == join_pointy)
        {
            rightStNo = dest->AddPoint (pos - width*pnor);
            rightEnNo = dest->AddPoint (pos - width*nnor);

            const Geom::Point biss = StrokeNormalize (pnor + nnor);
            double c2 = dot (biss, nnor);
            double l = width / c2;
            double emiter = width * c2;
            if (emiter < miter)
                emiter = miter;
            if (l <= emiter)
            {
                int nrightStNo = dest->AddPoint (pos - l * biss);
                int nEdge=dest->AddEdge (rightStNo, nrightStNo);
                if ( dest->hasBackData() ) {
                    dest->ebData[nEdge].pathID=pathID;
                    dest->ebData[nEdge].pieceID=pieceID;
                    dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
                }
                nEdge=dest->AddEdge (nrightStNo, rightEnNo);
                if ( dest->hasBackData() ) {
                    dest->ebData[nEdge].pathID=pathID;
                    dest->ebData[nEdge].pieceID=pieceID;
                    dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
                }
            }
            else
            {
                double s2 = cross (biss, nnor);
                double dec = (l - emiter) * c2 / s2;
                const Geom::Point tbiss=biss.ccw();

                int nrightStNo = dest->AddPoint (pos - emiter*biss - dec*tbiss);
                int nrightEnNo = dest->AddPoint (pos - emiter*biss + dec*tbiss);
                int nEdge=dest->AddEdge (rightStNo, nrightStNo);
                if ( dest->hasBackData() ) {
                    dest->ebData[nEdge].pathID=pathID;
                    dest->ebData[nEdge].pieceID=pieceID;
                    dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
                }
                nEdge=dest->AddEdge (nrightStNo, nrightEnNo);
                if ( dest->hasBackData() ) {
                    dest->ebData[nEdge].pathID=pathID;
                    dest->ebData[nEdge].pieceID=pieceID;
                    dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
                }
                nEdge=dest->AddEdge (nrightEnNo, rightEnNo);
                if ( dest->hasBackData() ) {
                    dest->ebData[nEdge].pathID=pathID;
                    dest->ebData[nEdge].pieceID=pieceID;
                    dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
                }
            }
        }
        else if (join == join_round)
        {
            const Geom::Point sx = pos - width * pnor;
            rightStNo = dest->AddPoint (sx);
            const Geom::Point ex = pos - width * nnor;
            rightEnNo = dest->AddPoint (ex);

            RecRound(dest, rightStNo, rightEnNo, 
                    sx, ex, -pnor, -nnor ,pos, width);
        }
        else
        {
            rightStNo = dest->AddPoint (pos - width * pnor);
            rightEnNo = dest->AddPoint (pos - width * nnor);
            int nEdge=dest->AddEdge (rightStNo, rightEnNo);
            if ( dest->hasBackData() ) {
                dest->ebData[nEdge].pathID=pathID;
                dest->ebData[nEdge].pieceID=pieceID;
                dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
            }
        }
    }
    else
    {
        /*		Geom::Point     biss;
                        biss=next.x-prev.x;
                        biss.y=next.y-prev.y;
                        double   c2=cross(next,biss);
                        double   l=width/c2;
                        double		projn=l*(dot(biss,next));
                        double		projp=-l*(dot(biss,prev));
                        if ( projp <= 0.5*prevL && projn <= 0.5*nextL ) {
                        double   x,y;
                        x=pos.x+l*biss.x;
                        y=pos.y+l*biss.y;
                        rightEnNo=rightStNo=dest->AddPoint(x,y);
                        } else {*/
        rightStNo = dest->AddPoint (pos - width*pnor);
        rightEnNo = dest->AddPoint (pos - width*nnor);
        int midNo = dest->AddPoint (pos);
        int nEdge=dest->AddEdge (rightStNo, midNo);
        if ( dest->hasBackData() ) {
            dest->ebData[nEdge].pathID=pathID;                                  
            dest->ebData[nEdge].pieceID=pieceID;
            dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
        }
        nEdge=dest->AddEdge (midNo, rightEnNo);
        if ( dest->hasBackData() ) {
            dest->ebData[nEdge].pathID=pathID;
            dest->ebData[nEdge].pieceID=pieceID;
            dest->ebData[nEdge].tSt=dest->ebData[nEdge].tEn=tID;
        }
        //              }
    }
}
void Path::DoJoin (Shape *dest, double width, JoinType join, Geom::Point pos, Geom::Point prev,
        Geom::Point next, double miter, double /*prevL*/, double /*nextL*/,
        int *stNo, int *enNo)
{
    Geom::Point pnor = prev.ccw();
    Geom::Point nnor = next.ccw();
    double angSi = cross(next, prev);

    /* FIXED: this special case caused bug 1028953 */
    if (angSi > -0.0001 && angSi < 0.0001) {
        double angCo = dot (prev, next);
        if (angCo > 0.9999) {
            // tout droit
            stNo[LEFT] = enNo[LEFT] = dest->AddPoint(pos + width * pnor);
            stNo[RIGHT] = enNo[RIGHT] = dest->AddPoint(pos - width * pnor);
        } else {
            // demi-tour
            const Geom::Point sx = pos + width * pnor;
            const Geom::Point ex = pos - width * pnor;
            stNo[LEFT] = enNo[RIGHT] = dest->AddPoint (sx);
            stNo[RIGHT] = enNo[LEFT] = dest->AddPoint (ex);
            if (join == join_round) {
                RecRound (dest, enNo[LEFT], stNo[LEFT], ex, sx, -pnor, pnor, pos, width);
                dest->AddEdge(stNo[RIGHT], enNo[RIGHT]);
            } else {
                dest->AddEdge(enNo[LEFT], stNo[LEFT]);
                dest->AddEdge(stNo[RIGHT], enNo[RIGHT]);	// two times because both are crossing each other
            }
        }
        return;
    }

    if (angSi < 0) {
        int midNo = dest->AddPoint(pos);
        stNo[LEFT] = dest->AddPoint(pos + width * pnor);
        enNo[LEFT] = dest->AddPoint(pos + width * nnor);
        dest->AddEdge(enNo[LEFT], midNo);
        dest->AddEdge(midNo, stNo[LEFT]);

        if (join == join_pointy) {

            stNo[RIGHT] = dest->AddPoint(pos - width * pnor);
            enNo[RIGHT] = dest->AddPoint(pos - width * nnor);

            const Geom::Point biss = StrokeNormalize(prev - next);
            double c2 = dot(biss, nnor);
            double l = width / c2;
            double emiter = width * c2;
            if (emiter < miter) {
                emiter = miter;
            }

            if (fabs(l) < miter) {
                int const n = dest->AddPoint(pos - l * biss);
                dest->AddEdge(stNo[RIGHT], n);
                dest->AddEdge(n, enNo[RIGHT]);
            } else {
                dest->AddEdge(stNo[RIGHT], enNo[RIGHT]);
            }

        } else if (join == join_round) {
            Geom::Point sx = pos - width * pnor;
            stNo[RIGHT] = dest->AddPoint(sx);
            Geom::Point ex = pos - width * nnor;
            enNo[RIGHT] = dest->AddPoint(ex);

            RecRound(dest, stNo[RIGHT], enNo[RIGHT], 
                    sx, ex, -pnor, -nnor, pos, width);

        } else {
            stNo[RIGHT] = dest->AddPoint(pos - width * pnor);
            enNo[RIGHT] = dest->AddPoint(pos - width * nnor);
            dest->AddEdge(stNo[RIGHT], enNo[RIGHT]);
        }

    } else {

        int midNo = dest->AddPoint(pos);
        stNo[RIGHT] = dest->AddPoint(pos - width * pnor);
        enNo[RIGHT] = dest->AddPoint(pos - width * nnor);
        dest->AddEdge(stNo[RIGHT], midNo);
        dest->AddEdge(midNo, enNo[RIGHT]);

        if (join == join_pointy) {

            stNo[LEFT] = dest->AddPoint(pos + width * pnor);
            enNo[LEFT] = dest->AddPoint(pos + width * nnor);

            const Geom::Point biss = StrokeNormalize(next - prev);
            double c2 = dot(biss, nnor);
            double l = width / c2;
            double emiter = width * c2;
            if (emiter < miter) {
                emiter = miter;
            }
            if ( fabs(l) < miter) {
                int const n = dest->AddPoint (pos + l * biss);
                dest->AddEdge (enNo[LEFT], n);
                dest->AddEdge (n, stNo[LEFT]);
            }
            else
            {
                dest->AddEdge (enNo[LEFT], stNo[LEFT]);
            }

        } else if (join == join_round) {

            Geom::Point sx = pos + width * pnor;
            stNo[LEFT] = dest->AddPoint(sx);
            Geom::Point ex = pos + width * nnor;
            enNo[LEFT] = dest->AddPoint(ex);

            RecRound(dest, enNo[LEFT], stNo[LEFT], 
                    ex, sx, nnor, pnor, pos, width);

        } else {
            stNo[LEFT] = dest->AddPoint(pos + width * pnor);
            enNo[LEFT] = dest->AddPoint(pos + width * nnor);
            dest->AddEdge(enNo[LEFT], stNo[LEFT]);
        }
    }
}