/** Make a path from a d2 sbasis.
 \param p the d2 Symmetric basis polynomial
 \returns a Path

  If only_cubicbeziers is true, the resulting path may only contain CubicBezier curves.
 TODO: some of this logic should be lifted into svg-path
*/
std::vector<Geom::Path>
path_from_piecewise(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &B, double tol, bool only_cubicbeziers) {
    Geom::PathBuilder pb;
    if(B.size() == 0) return pb.peek();
    Geom::Point start = B[0].at0();
    pb.moveTo(start);
    for(unsigned i = 0; ; i++) {
        if ( (i+1 == B.size()) 
             || !are_near(B[i+1].at0(), B[i].at1(), tol) )
        {
            //start of a new path
            if (are_near(start, B[i].at1()) && sbasis_size(B[i]) <= 1) {
                pb.closePath();
                //last line seg already there (because of .closePath())
                goto no_add;
            }
            build_from_sbasis(pb, B[i], tol, only_cubicbeziers);
            if (are_near(start, B[i].at1())) {
                //it's closed, the last closing segment was not a straight line so it needed to be added, but still make it closed here with degenerate straight line.
                pb.closePath();
            }
          no_add:
            if (i+1 >= B.size()) {
                break;
            }
            start = B[i+1].at0();
            pb.moveTo(start);
        } else {
            build_from_sbasis(pb, B[i], tol, only_cubicbeziers);
        }
    }
    pb.flush();
    return pb.peek();
}
Example #2
0
/** Make a path from a d2 sbasis.
 \param p the d2 Symmetric basis polynomial
 \returns a Path

  If only_cubicbeziers is true, the resulting path may only contain CubicBezier curves.
*/
void build_from_sbasis(Geom::PathBuilder &pb, D2<SBasis> const &B, double tol, bool only_cubicbeziers) {
    if (!B.isFinite()) {
        THROW_EXCEPTION("assertion failed: B.isFinite()");
    }
    if(tail_error(B, 2) < tol || sbasis_size(B) == 2) { // nearly cubic enough
        if( !only_cubicbeziers && (sbasis_size(B) <= 1) ) {
            pb.lineTo(B.at1());
        } else {
            std::vector<Geom::Point> bez;
            sbasis_to_bezier(bez, B, 4);
            pb.curveTo(bez[1], bez[2], bez[3]);
        }
    } else {
        build_from_sbasis(pb, compose(B, Linear(0, 0.5)), tol, only_cubicbeziers);
        build_from_sbasis(pb, compose(B, Linear(0.5, 1)), tol, only_cubicbeziers);
    }
}
Example #3
0
// Create path for rendering shape on screen
void SPGenericEllipse::set_shape()
{
    // std::cout << "SPGenericEllipse::set_shape: Entrance" << std::endl;
    if (hasBrokenPathEffect()) {
        g_warning("The ellipse shape has unknown LPE on it! Convert to path to make it editable preserving the appearance; editing it as ellipse will remove the bad LPE");

        if (this->getRepr()->attribute("d")) {
            // unconditionally read the curve from d, if any, to preserve appearance
            Geom::PathVector pv = sp_svg_read_pathv(this->getRepr()->attribute("d"));
            SPCurve *cold = new SPCurve(pv);
            this->setCurveInsync(cold, TRUE);
            cold->unref();
        }

        return;
    }
    if (Geom::are_near(this->rx.computed, 0) || Geom::are_near(this->ry.computed, 0)) {
        return;
    }

    this->normalize();

    SPCurve *curve = NULL;

    // For simplicity, we use a circle with center (0, 0) and radius 1 for our calculations.
    Geom::Circle circle(0, 0, 1);

    if (!this->_isSlice()) {
        start = 0.0;
        end = 2.0*M_PI;
    }
    double incr = end - start; // arc angle
    if (incr < 0.0) incr += 2.0*M_PI;    

    int numsegs = 1 + int(incr*2.0/M_PI); // number of arc segments
    if (numsegs > 4) numsegs = 4;

    incr = incr/numsegs; // limit arc angle to less than 90 degrees
    Geom::Path path(Geom::Point::polar(start));
    Geom::EllipticalArc* arc;
    for (int seg = 0; seg < numsegs; seg++) {
        arc = circle.arc(Geom::Point::polar(start + seg*incr), Geom::Point::polar(start + (seg + 0.5)*incr), Geom::Point::polar(start + (seg + 1.0)*incr));
        path.append(*arc);
        delete arc;
    }
    Geom::PathBuilder pb;
    pb.append(path);
    if (this->_isSlice() && this->_closed) {
        pb.lineTo(Geom::Point(0, 0));
    }
    if (this->_closed) {
        pb.closePath();
    } else {
        pb.flush();
    }
    curve = new SPCurve(pb.peek());

    // gchar *str = sp_svg_write_path(curve->get_pathvector());
    // std::cout << "  path: " << str << std::endl;
    // g_free(str);

    // Stretching / moving the calculated shape to fit the actual dimensions.
    Geom::Affine aff = Geom::Scale(rx.computed, ry.computed) * Geom::Translate(cx.computed, cy.computed);
    curve->transform(aff);

    /* Reset the shape's curve to the "original_curve"
     * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/
    this->setCurveInsync(curve, TRUE);
    this->setCurveBeforeLPE(curve);

    if (hasPathEffect() && pathEffectsEnabled()) {
        SPCurve *c_lpe = curve->copy();
        bool success = this->performPathEffect(c_lpe);

        if (success) {
            this->setCurveInsync(c_lpe, TRUE);
        }

        c_lpe->unref();
    }

    curve->unref();
    // std::cout << "SPGenericEllipse::set_shape: Exit" << std::endl;
}