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); } }