Exemplo n.º 1
0
bool TestReset() {
    BEGIN_TEST;
    PathFixture fixture;
    ASSERT_TRUE(fixture.Create());

    Path path;
    ASSERT_EQ(ZX_OK, path.Push(fixture.path()));

    path.Reset();
    EXPECT_STR_EQ(path.c_str(), "/");

    END_TEST;
}
void SPOffset::set_shape() {
    if ( this->originalPath == NULL ) {
        // oops : no path?! (the offset object should do harakiri)
        return;
    }
#ifdef OFFSET_VERBOSE
    g_print ("rad=%g\n", offset->rad);
#endif
    // au boulot

    if ( fabs(this->rad) < 0.01 ) {
        // grosso modo: 0
        // just put the source this as the offseted one, no one will notice
        // it's also useless to compute the offset with a 0 radius

        //XML Tree being used directly here while it shouldn't be.
        const char *res_d = this->getRepr()->attribute("inkscape:original");

        if ( res_d ) {
            Geom::PathVector pv = sp_svg_read_pathv(res_d);
            SPCurve *c = new SPCurve(pv);
            g_assert(c != NULL);

            this->setCurveInsync (c, TRUE);
            this->setCurveBeforeLPE(c);

            c->unref();
        }

        return;
    }

    // extra paraniac careful check. the preceding if () should take care of this case
    if (fabs (this->rad) < 0.01) {
        this->rad = (this->rad < 0) ? -0.01 : 0.01;
    }

    Path *orig = new Path;
    orig->Copy ((Path *)this->originalPath);

    if ( use_slow_but_correct_offset_method == false ) {
        // version par outline
        Shape *theShape = new Shape;
        Shape *theRes = new Shape;
        Path *originaux[1];
        Path *res = new Path;
        res->SetBackData (false);

        // and now: offset
        float o_width;
        if (this->rad >= 0)
        {
            o_width = this->rad;
            orig->OutsideOutline (res, o_width, join_round, butt_straight, 20.0);
        }
        else
        {
            o_width = -this->rad;
            orig->OutsideOutline (res, -o_width, join_round, butt_straight, 20.0);
        }

        if (o_width >= 1.0)
        {
            //      res->ConvertForOffset (1.0, orig, offset->rad);
            res->ConvertWithBackData (1.0);
        }
        else
        {
            //      res->ConvertForOffset (o_width, orig, offset->rad);
            res->ConvertWithBackData (o_width);
        }
        res->Fill (theShape, 0);
        theRes->ConvertToShape (theShape, fill_positive);
        originaux[0] = res;

        theRes->ConvertToForme (orig, 1, originaux);

        Geom::OptRect bbox = this->desktopVisualBounds();

        if ( bbox ) {
            gdouble size = L2(bbox->dimensions());
            gdouble const exp = this->transform.descrim();

            if (exp != 0) {
                size /= exp;
            }

            orig->Coalesce (size * 0.001);
            //g_print ("coa %g    exp %g    item %p\n", size * 0.001, exp, item);
        }


        //  if (o_width >= 1.0)
        //  {
        //    orig->Coalesce (0.1);  // small treshhold, since we only want to get rid of small segments
        // the curve should already be computed by the Outline() function
        //   orig->ConvertEvenLines (1.0);
        //   orig->Simplify (0.5);
        //  }
        //  else
        //  {
        //          orig->Coalesce (0.1*o_width);
        //   orig->ConvertEvenLines (o_width);
        //   orig->Simplify (0.5 * o_width);
        //  }

        delete theShape;
        delete theRes;
        delete res;
    } else {
        // version par makeoffset
        Shape *theShape = new Shape;
        Shape *theRes = new Shape;


        // and now: offset
        float o_width;
        if (this->rad >= 0)
        {
            o_width = this->rad;
        }
        else
        {
            o_width = -this->rad;
        }

        // one has to have a measure of the details
        if (o_width >= 1.0)
        {
            orig->ConvertWithBackData (0.5);
        }
        else
        {
            orig->ConvertWithBackData (0.5*o_width);
        }

        orig->Fill (theShape, 0);
        theRes->ConvertToShape (theShape, fill_positive);

        Path *originaux[1];
        originaux[0]=orig;

        Path *res = new Path;
        theRes->ConvertToForme (res, 1, originaux);

        int    nbPart=0;
        Path** parts=res->SubPaths(nbPart,true);
        char   *holes=(char*)malloc(nbPart*sizeof(char));

        // we offset contours separately, because we can.
        // this way, we avoid doing a unique big ConvertToShape when dealing with big shapes with lots of holes
        {
            Shape* onePart=new Shape;
            Shape* oneCleanPart=new Shape;

            theShape->Reset();

            for (int i=0; i<nbPart; i++) {
                double partSurf=parts[i]->Surface();
                parts[i]->Convert(1.0);

                {
                    // raffiner si besoin
                    double  bL,bT,bR,bB;
                    parts[i]->PolylineBoundingBox(bL,bT,bR,bB);
                    double  mesure=((bR-bL)+(bB-bT))*0.5;
                    if ( mesure < 10.0 ) {
                        parts[i]->Convert(0.02*mesure);
                    }
                }

                if ( partSurf < 0 ) { // inverse par rapport a la realite
                    // plein
                    holes[i]=0;
                    parts[i]->Fill(oneCleanPart,0);
                    onePart->ConvertToShape(oneCleanPart,fill_positive); // there aren't intersections in that one, but maybe duplicate points and null edges
                    oneCleanPart->MakeOffset(onePart,this->rad,join_round,20.0);
                    onePart->ConvertToShape(oneCleanPart,fill_positive);

                    onePart->CalcBBox();
                    double  typicalSize=0.5*((onePart->rightX-onePart->leftX)+(onePart->bottomY-onePart->topY));

                    if ( typicalSize < 0.05 ) {
                        typicalSize=0.05;
                    }

                    typicalSize*=0.01;

                    if ( typicalSize > 1.0 ) {
                        typicalSize=1.0;
                    }

                    onePart->ConvertToForme (parts[i]);
                    parts[i]->ConvertEvenLines (typicalSize);
                    parts[i]->Simplify (typicalSize);

                    double nPartSurf=parts[i]->Surface();

                    if ( nPartSurf >= 0 ) {
                        // inversion de la surface -> disparait
                        delete parts[i];
                        parts[i]=NULL;
                    } else {
                    }

                    /*          int  firstP=theShape->nbPt;
                                for (int j=0;j<onePart->nbPt;j++) theShape->AddPoint(onePart->pts[j].x);
                                for (int j=0;j<onePart->nbAr;j++) theShape->AddEdge(firstP+onePart->aretes[j].st,firstP+onePart->aretes[j].en);*/
                } else {
                    // trou
                    holes[i]=1;
                    parts[i]->Fill(oneCleanPart,0,false,true,true);
                    onePart->ConvertToShape(oneCleanPart,fill_positive);
                    oneCleanPart->MakeOffset(onePart,-this->rad,join_round,20.0);
                    onePart->ConvertToShape(oneCleanPart,fill_positive);
//          for (int j=0;j<onePart->nbAr;j++) onePart->Inverse(j); // pas oublier de reinverser

                    onePart->CalcBBox();
                    double  typicalSize=0.5*((onePart->rightX-onePart->leftX)+(onePart->bottomY-onePart->topY));

                    if ( typicalSize < 0.05 ) {
                        typicalSize=0.05;
                    }

                    typicalSize*=0.01;

                    if ( typicalSize > 1.0 ) {
                        typicalSize=1.0;
                    }

                    onePart->ConvertToForme (parts[i]);
                    parts[i]->ConvertEvenLines (typicalSize);
                    parts[i]->Simplify (typicalSize);
                    double nPartSurf=parts[i]->Surface();

                    if ( nPartSurf >= 0 ) {
                        // inversion de la surface -> disparait
                        delete parts[i];
                        parts[i]=NULL;
                    } else {
                    }

                    /*         int  firstP=theShape->nbPt;
                               for (int j=0;j<onePart->nbPt;j++) theShape->AddPoint(onePart->pts[j].x);
                               for (int j=0;j<onePart->nbAr;j++) theShape->AddEdge(firstP+onePart->aretes[j].en,firstP+onePart->aretes[j].st);*/
                }
//        delete parts[i];
            }
//      theShape->MakeOffset(theRes,offset->rad,join_round,20.0);
            delete onePart;
            delete oneCleanPart;
        }

        if ( nbPart > 1 ) {
            theShape->Reset();

            for (int i=0; i<nbPart; i++) {
                if ( parts[i] ) {
                    parts[i]->ConvertWithBackData(1.0);

                    if ( holes[i] ) {
                        parts[i]->Fill(theShape,i,true,true,true);
                    } else {
                        parts[i]->Fill(theShape,i,true,true,false);
                    }
                }
            }

            theRes->ConvertToShape (theShape, fill_positive);
            theRes->ConvertToForme (orig,nbPart,parts);

            for (int i=0; i<nbPart; i++) {
                if ( parts[i] ) {
                    delete parts[i];
                }
            }
        } else if ( nbPart == 1 ) {
            orig->Copy(parts[0]);

            for (int i=0; i<nbPart; i++) {
                if ( parts[i] ) {
                    delete parts[i];
                }
            }
        } else {
            orig->Reset();
        }
//    theRes->ConvertToShape (theShape, fill_positive);
//    theRes->ConvertToForme (orig);

        /*    if (o_width >= 1.0) {
              orig->ConvertEvenLines (1.0);
              orig->Simplify (1.0);
              } else {
              orig->ConvertEvenLines (1.0*o_width);
              orig->Simplify (1.0 * o_width);
              }*/

        if ( parts ) {
            free(parts);
        }

        if ( holes ) {
            free(holes);
        }

        delete res;
        delete theShape;
        delete theRes;
    }
    {
        char *res_d = NULL;

        if (orig->descr_cmd.size() <= 1)
        {
            // Aie.... nothing left.
            res_d = strdup ("M 0 0 L 0 0 z");
            //printf("%s\n",res_d);
        }
        else
        {

            res_d = orig->svg_dump_path ();
        }

        delete orig;

        Geom::PathVector pv = sp_svg_read_pathv(res_d);
        SPCurve *c = new SPCurve(pv);
        g_assert(c != NULL);

        this->setCurveInsync (c, TRUE);
        this->setCurveBeforeLPE(c);
        c->unref();

        free (res_d);
    }
}