Logo Search packages:      
Sourcecode: inkscape version File versions

static void sp_offset_set_shape ( SPShape *  shape  )  [static]

Compute and set shape's offset.

Definition at line 515 of file sp-offset.cpp.

References Geom::L2(), SPOffset::originalPath, SPOffset::rad, sp_curve_new_from_bpath(), sp_curve_unref(), and SPItem::transform.

Referenced by sp_offset_class_init(), sp_offset_top_point(), and sp_offset_write().

{
    SPOffset *offset = SP_OFFSET (shape);

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

        const char *res_d = SP_OBJECT(shape)->repr->attribute("inkscape:original");
        if ( res_d ) {
            NArtBpath *bpath = sp_svg_read_path (res_d);
            SPCurve *c = sp_curve_new_from_bpath (bpath);
            g_assert(c != NULL);
            sp_shape_set_curve_insync ((SPShape *) offset, c, TRUE);
            sp_curve_unref (c);
        }
        return;
    }

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

    Path *orig = new Path;
    orig->Copy ((Path *) offset->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 (offset->rad >= 0)
        {
            o_width = offset->rad;
            orig->OutsideOutline (res, o_width, join_round, butt_straight, 20.0);
        }
        else
        {
            o_width = -offset->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);

        SPItem *item = shape;
        NR::Maybe<NR::Rect> bbox = sp_item_bbox_desktop (item);
        if ( bbox && !bbox->isEmpty() ) {
            gdouble size = L2(bbox->dimensions());
            gdouble const exp = NR::expansion(item->transform);
            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 (offset->rad >= 0)
        {
            o_width = offset->rad;
        }
        else
        {
            o_width = -offset->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,offset->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,-offset->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;

        NArtBpath *bpath = sp_svg_read_path (res_d);
        SPCurve *c = sp_curve_new_from_bpath (bpath);
        g_assert(c != NULL);
        sp_shape_set_curve_insync ((SPShape *) offset, c, TRUE);
        sp_curve_unref (c);

        free (res_d);
    }
}


Generated by  Doxygen 1.6.0   Back to index