Example #1
0
void RExporter::exportSpline(const RSpline& spline, double offset) {
    RLinetypePattern p = getLinetypePattern();

    bool continuous = false;
    if (getEntity() == NULL || !p.isValid() || p.getNumDashes() == 1 || draftMode || screenBasedLinetypes) {
        continuous = true;
    }

    if (!continuous) {
        p.scale(getPatternFactor());

        if (RMath::isNaN(offset)) {
            double length = spline.getLength();
            offset = getPatternOffset(length, p);
        }
        exportExplodable(spline, offset);
    }
    else {
        // version <= 3.0.0 was (line interpolation):
        //exportExplodable(spline, offset);

        // performance improvement (using real splines):
        RPainterPath pp;
        pp.setPen(QPen(Qt::SolidLine));
        pp.addSpline(spline);
        exportPainterPaths(QList<RPainterPath>() << pp);
    }


    /*
    RLinetypePattern p = getLinetypePattern();
    p.scale(getPatternFactor());

    if (RMath::isNaN(offset)) {
        double length = spline.getLength();
        offset = getPatternOffset(length, p);
    }

    double currentOffset = offset;
    QList<QSharedPointer<RShape> > sub = spline.getExploded();
    QList<QSharedPointer<RShape> >::iterator it;
    for (it=sub.begin(); it!=sub.end(); ++it) {
        QSharedPointer<RLine> line = (*it).dynamicCast<RLine>();
        if (!line.isNull()) {
            exportLine(*line.data(), currentOffset);
            currentOffset -= line->getLength();
        }

        QSharedPointer<RArc> arc = (*it).dynamicCast<RArc>();
        if (!arc.isNull()) {
            exportArc(*arc.data(), currentOffset);
            currentOffset -= arc->getLength();
        }
    }
    */
}
Example #2
0
void RExporter::exportExplodable(const RExplodable& explodable, double offset) {
    QList<QSharedPointer<RShape> > sub = explodable.getExploded();

    RLinetypePattern p = getLinetypePattern();
    if (!p.isValid() || p.getNumDashes() <= 1 || draftMode || screenBasedLinetypes || twoColorSelectedMode) {
        for (int i=0; i<sub.length(); i++) {
            QSharedPointer<RLine> lineP = sub[i].dynamicCast<RLine>();
            if (!lineP.isNull()) {
                exportLine(*lineP.data());
                continue;
            }

            QSharedPointer<RArc> arc = sub[i].dynamicCast<RArc>();
            if (!arc.isNull()) {
                exportArc(*arc.data());
                continue;
            }
        }
        return;
    }

    if (getEntity()!=NULL && (getEntity()->getType()!=RS::EntitySpline || RSpline::hasProxy())) {
        // all explodable entities including splines if we have a spline proxy:
        RShapesExporter(*this, sub, offset);
        return;
    }

    // use alternative algorithm for splines if we don't have a spline proxy:
    double dist;

    for (int i=0; i<sub.length(); i++) {
        QSharedPointer<RLine> lineP = sub[i].dynamicCast<RLine>();
        if (!lineP.isNull()) {
            RLine line = *lineP.data();
            dist = exportLine(line, offset);
            offset -= lineP->getLength();
            continue;
        }

        QSharedPointer<RArc> arc = sub[i].dynamicCast<RArc>();
        if (!arc.isNull()) {
            exportArc(*arc.data(), offset);
            offset -= arc->getLength();
            continue;
        }
    }
}
Example #3
0
void RExporter::exportPolyline(const RPolyline& polyline, double offset) {
    RLinetypePattern p = getLinetypePattern();

    bool continuous = false;
    if (getEntity() == NULL || !p.isValid() || p.getNumDashes() == 1 || draftMode || screenBasedLinetypes) {
        continuous = true;
    }

    if (!continuous) {
        p.scale(getPatternFactor());

        if (RMath::isNaN(offset)) {
            double length = polyline.getLength();
            offset = getPatternOffset(length, p);
        }
    }

    exportExplodable(polyline, offset);
}
Example #4
0
/**
 * \param polylineGen True: use pattern along whole polyline, False: pattern per segment.
 */
void RExporter::exportPolyline(const RPolyline& polyline, bool polylineGen, double offset) {
    RLinetypePattern p = getLinetypePattern();

    bool continuous = false;
    if (getEntity() == NULL || !p.isValid() || p.getNumDashes() <= 1 || draftMode || screenBasedLinetypes || twoColorSelectedMode) {
        continuous = true;
    }

    if (!continuous) {
        p.scale(getLineTypePatternScale(p));

        if (RMath::isNaN(offset)) {
            double length = polyline.getLength();
            offset = p.getPatternOffset(length);
        }
    }

    if (polylineGen) {
        // pattern along whole polyline:
        exportExplodable(polyline, offset);
    }
    else {
        // pattern for each individual segment:
        for (int i=0; i<polyline.countSegments(); i++) {
            QSharedPointer<RShape> shape = polyline.getSegmentAt(i);
            QSharedPointer<RLine> line = shape.dynamicCast<RLine>();
            if (!line.isNull()) {
                RExporter::exportLine(*line);
            }
            QSharedPointer<RArc> arc = shape.dynamicCast<RArc>();
            if (!arc.isNull()) {
                RExporter::exportArc(*arc);
            }
        }
    }
}
Example #5
0
void RExporter::exportArc(const RArc& arc, double offset) {
    if (!arc.isValid()) {
        return;
    }

    RLinetypePattern p = getLinetypePattern();

    if (getEntity() == NULL || !p.isValid() || p.getNumDashes() == 1 || draftMode || screenBasedLinetypes) {
        exportArcSegment(arc);
        return;
    }

    RArc normalArc = arc;
    if (arc.isReversed()) {
        normalArc.reverse();
    }

    if (normalArc.radius < 1.0e-12) {
        return;
    }

    p.scale(getPatternFactor());

    double length = normalArc.getLength();
    double patternLength = p.getPatternLength();

    // avoid huge number of small segments due to very fine 
    // pattern or long lines:
    if (patternLength<RS::PointTolerance || length / patternLength > 5000) {
        exportArcSegment(arc);
        return;
    }

    double* vp = NULL;
    vp = new double[p.getNumDashes()];
    for (int i = 0; i < p.getNumDashes(); ++i) {
        vp[i] = fabs(p.getDashLengthAt(i)) / normalArc.radius;
    }

    if (RMath::isNaN(offset)) {
        offset = getPatternOffset(length, p);
    }

    QList<RArc> arcSegments;
    bool done = false;
    int i = 0;
    double cursor = normalArc.getStartAngle() + offset / normalArc.radius;
    double total = offset;
    bool dashFound = false;
    bool gapFound = false;
    double a1 = normalArc.getStartAngle();
    double a2;
    do {
        if (dashFound && !gapFound) {
            if (total + fabs(p.getDashLengthAt(i)) >= length - 1.0e-6) {
                arcSegments.append(RArc(normalArc.getCenter(), normalArc.getRadius(), a1, normalArc.getEndAngle()));
                break;
            }
            arcSegments.append(RArc(normalArc.getCenter(), normalArc.getRadius(), a1, a2));
        }
        if (p.getDashLengthAt(i) > 0) {
            // dash, no gap
            if (total + p.getDashLengthAt(i) > 0) {
                a1 = cursor;
                if (total < 0 || !dashFound) {
                    a1 = normalArc.startAngle;
                }
                a2 = cursor + vp[i];
                if (fabs(a2 - normalArc.getStartAngle()) > 1.0e-6) {
                    dashFound = true;
                }
            }
            gapFound = false;
        } else {
            gapFound = true;
        }
        cursor += vp[i];
        total += fabs(p.getDashLengthAt(i));
        done = total > length;
        ++i;
        if (i >= p.getNumDashes()) {
            i = 0;
        }
    } while (!done);

    if (!gapFound || !dashFound) {
        if (total + fabs(p.getDashLengthAt(i)) >= length - 1.0e-6) {
            arcSegments.append(RArc(normalArc.getCenter(), normalArc.getRadius(), a1, normalArc.getEndAngle()));
        } else {
            arcSegments.append(RArc(normalArc.getCenter(), normalArc.getRadius(), a1, a2));
        }
    }

    if (arc.isReversed()) {
        for (int i=arcSegments.length()-1; i>=0; i--) {
            arcSegments[i].reverse();
            exportArcSegment(arcSegments[i]);
        }
    }
    else {
        for (int i=0; i<arcSegments.length(); i++) {
            exportArcSegment(arcSegments[i]);
        }
    }

    delete[] vp;
}
Example #6
0
void RExporter::exportLine(const RLine& line, double offset) {
    if (!line.isValid()) {
        return;
    }

    double length = line.getLength();

    if (length>1e100 || length<RS::PointTolerance) {
        return;
    }

    RLinetypePattern p = getLinetypePattern();

    // continuous line or
    // we are in draft mode or
    // QCAD is configured to show screen based line patterns
    if (!p.isValid() || p.getNumDashes() == 1 || draftMode || screenBasedLinetypes) {
        exportLineSegment(line);
        return;
    }

    p.scale(getPatternFactor());
    double patternLength = p.getPatternLength();
    

    // avoid huge number of small segments due to very fine 
    // pattern or long lines:
    if (patternLength<RS::PointTolerance || length / patternLength > 5000) {
        exportLineSegment(line);
        return;
    }

    double angle = line.getAngle();
    RVector* vp = NULL;
    vp = new RVector[p.getNumDashes()];
    for (int i = 0; i < p.getNumDashes(); ++i) {
        vp[i] = RVector(cos(angle) * fabs(p.getDashLengthAt(i)),
                        sin(angle) * fabs(p.getDashLengthAt(i)));
    }

    bool optimizeEnds = false;
    if (RMath::isNaN(offset)) {
        offset = getPatternOffset(length, p);
        optimizeEnds = true;
    }
    else {
        double num = ceil(offset / patternLength);
        offset -= num * patternLength;
    }

    bool done = false;
    int i = 0;
    RVector cursor(line.getStartPoint() + RVector::createPolar(offset, angle));
    double total = offset;
    bool dashFound = false;
    bool gapFound = false;
    RVector p1 = line.getStartPoint();
    RVector p2 = p1;

    do {
        if (dashFound && !gapFound) {
            // don't shoot over end of line:
            if (total + fabs(p.getDashLengthAt(i)) >= length - 1.0e-6) {
                if (optimizeEnds) {
                    exportLineSegment(RLine(p1, line.endPoint));
                }
                else {
                    exportLineSegment(RLine(p1, p2));
                }
                break;
            }
            exportLineSegment(RLine(p1, p2));
        }

        // dash, no gap. note that a dash can have a length of 0.0 (point):
        if (p.getDashLengthAt(i) > -RS::PointTolerance) {
            // check if we're on the line already:
            if (total + p.getDashLengthAt(i) > 0) {
                p1 = cursor;

                // no gap at the beginning of the line:
                if (total < 0 || (!dashFound && optimizeEnds)) {
                    p1 = line.startPoint;
                }

                p2 = cursor + vp[i];
                if (!p2.equalsFuzzy(line.startPoint, 1.0e-6)) {
                    dashFound = true;
                }
            }
            gapFound = false;
        }

        // gap:
        else {
            gapFound = true;
        }

        cursor += vp[i];
        total += fabs(p.getDashLengthAt(i));

        done = total > length;

        ++i;
        if (i >= p.getNumDashes()) {
            i = 0;
        }
    } while (!done);

    if (!gapFound || !dashFound) {
        if (total + fabs(p.getDashLengthAt(i)) >= length - 1.0e-6) {
            if (optimizeEnds || (total>length && !gapFound)) {
                exportLineSegment(RLine(p1, line.endPoint));
            }
            else {
                exportLineSegment(RLine(p1, p2));
            }
        } else {
            exportLineSegment(RLine(p1, p2));
        }
    }

    delete[] vp;
}
Example #7
0
void RExporter::exportArc(const RArc& arc, double offset) {
    if (!arc.isValid()) {
        return;
    }

    if (getEntity() == NULL || draftMode || screenBasedLinetypes || twoColorSelectedMode) {
        exportArcSegment(arc);
        return;
    }

    RLinetypePattern p = getLinetypePattern();
    if (!p.isValid() || p.getNumDashes() <= 1) {
        exportArcSegment(arc);
        return;
    }

    p.scale(getLineTypePatternScale(p));
    double patternLength = p.getPatternLength();
    if (patternLength<RS::PointTolerance || arc.getLength() / patternLength > RSettings::getDashThreshold()) {
        exportArcSegment(arc);
        return;
    }

    RArc normalArc = arc;
    if (arc.isReversed()) {
        normalArc.reverse();
    }

    if (normalArc.radius < 1.0e-12) {
        return;
    }

    RArcExporter(*this, arc, offset);

    /*
    p.scale(getLineTypePatternScale(p));

    double length = normalArc.getLength();
    double patternLength = p.getPatternLength();

    // avoid huge number of small segments due to very fine 
    // pattern or long lines:
    if (patternLength<RS::PointTolerance || length / patternLength > 5000) {
        exportArcSegment(arc);
        return;
    }

    double* vp = NULL;
    vp = new double[p.getNumDashes()];
    for (int i = 0; i < p.getNumDashes(); ++i) {
        vp[i] = fabs(p.getDashLengthAt(i)) / normalArc.radius;
    }

    //bool optimizeEnds = false;
    if (RMath::isNaN(offset)) {
        offset = p.getPatternOffset(length);
        //optimizeEnds = true;
    }

    QList<RArc> arcSegments;
    bool done = false;
    int i = 0;
    double cursor = normalArc.getStartAngle() + offset / normalArc.radius;
    double total = offset;
    bool dashFound = false;
    bool gapFound = false;
    double a1 = normalArc.getStartAngle();
    double a2 = 0.0;
    do {
        if (dashFound && !gapFound) {
            if (total + fabs(p.getDashLengthAt(i)) >= length - 1.0e-6) {
                arcSegments.append(RArc(normalArc.getCenter(), normalArc.getRadius(), a1, normalArc.getEndAngle()));
                break;
            }
            arcSegments.append(RArc(normalArc.getCenter(), normalArc.getRadius(), a1, a2));
        }
        if (p.getDashLengthAt(i) >= 0.0) {
            // dash, no gap
            if (total + p.getDashLengthAt(i) >= 0.0) {
                a1 = cursor;
                if (total < 0.0 || !dashFound) {
                    a1 = normalArc.startAngle;
                }
                a2 = cursor + vp[i];
                if (fabs(a2 - normalArc.getStartAngle()) > 1.0e-6) {
                    dashFound = true;
                }
            }
            gapFound = false;
        } else {
            gapFound = true;
        }
        cursor += vp[i];
        total += fabs(p.getDashLengthAt(i));
        done = total > length;

        if (!done && total>0.0) {
            // handle shape at end of dash / gap:
            if (p.hasShapeAt(i)) {
                QList<RPainterPath> pps = p.getShapeAt(i);
//                RVector min = RPainterPath::getMinList(pps);
//                RVector max = RPainterPath::getMaxList(pps);
                RPainterPath::rotateList(pps, cursor+M_PI/2);
                RPainterPath::translateList(pps, normalArc.getPointAtAngle(cursor));
                exportPainterPaths(pps);
            }
        }

        ++i;
        if (i >= p.getNumDashes()) {
            i = 0;
        }
    } while (!done);

    if (!gapFound || !dashFound) {
        if (total + fabs(p.getDashLengthAt(i)) >= length - 1.0e-6) {
            arcSegments.append(RArc(normalArc.getCenter(), normalArc.getRadius(), a1, normalArc.getEndAngle()));
        } else {
            arcSegments.append(RArc(normalArc.getCenter(), normalArc.getRadius(), a1, a2));
        }
    }

    if (arc.isReversed()) {
        for (int i=arcSegments.length()-1; i>=0; i--) {
            arcSegments[i].reverse();
            exportArcSegment(arcSegments[i], true);
        }
    }
    else {
        for (int i=0; i<arcSegments.length(); i++) {
            exportArcSegment(arcSegments[i], true);
        }
    }

    delete[] vp;
    */
}
Example #8
0
double RExporter::exportLine(const RLine& line, double offset) {
    double ret = RNANDOUBLE;

    if (!line.isValid()) {
        return ret;
    }

    double length = line.getLength();

    if (length>1e100 || length<RS::PointTolerance) {
        return ret;
    }

    double angle = line.getAngle();

    // continuous line or
    // we are in draft mode or
    // QCAD is configured to show screen based line patterns
    if (draftMode || screenBasedLinetypes || twoColorSelectedMode) {
        exportLineSegment(line, angle);
        return ret;
    }

    RLinetypePattern p = getLinetypePattern();
    if (!p.isValid() || p.getNumDashes() <= 1) {
        exportLineSegment(line, angle);
        return ret;
    }

    p.scale(getLineTypePatternScale(p));
    double patternLength = p.getPatternLength();

    // avoid huge number of small segments due to very fine 
    // pattern or long lines:
    if (patternLength<RS::PointTolerance || length / patternLength > RSettings::getDashThreshold()) {
        exportLineSegment(line, angle);
        return ret;
    }

    RVector* vp = NULL;
    vp = new RVector[p.getNumDashes()];
    for (int i = 0; i < p.getNumDashes(); ++i) {
        vp[i] = RVector(cos(angle) * fabs(p.getDashLengthAt(i)),
                        sin(angle) * fabs(p.getDashLengthAt(i)));
    }

    if (RMath::isNaN(offset)) {
        offset = p.getPatternOffset(length);
    }
    else {
        double num = ceil(offset / patternLength);
        offset -= num * patternLength;
    }

    bool done = false;
    int i = 0;
    RVector cursor(line.getStartPoint() + RVector::createPolar(offset, angle));
    double total = offset;
    double nextTotal;
    bool isGap = false;
    RLine dash;

    do {
        double dashLength = p.getDashLengthAt(i);
        nextTotal = total + fabs(dashLength);
        //qDebug() << "total: " << total;
        //qDebug() << "nextTotal: " << nextTotal;

        // dash, no gap. note that a dash can have a length of 0.0 (point):
        if (dashLength > -RS::PointTolerance) {
            isGap = false;
        }

        // gap:
        else {
            isGap = true;
        }

        // check if we're on the line already
        // (since we might start before the line due to pattern offset):
        if (nextTotal > 0.0) {
            dash = RLine(cursor, cursor + vp[i]);

            if (!isGap) {
                // fist part is gap, then dash
                ret = -nextTotal;
            }
            else {
                // fist part is dash, then gap
                ret = nextTotal;
            }

            // shorten at start of line:
            if (total < 0.0 /*&& nextTotal > 0.0*/) {
                dash.startPoint = line.startPoint;
                ret = RNANDOUBLE;
            }

            // shorten at end of line:
            if (/*total < length &&*/ nextTotal >= length - 1.0e-6) {
                dash.endPoint = line.endPoint;
                ret = RINFDOUBLE;
            }

            if (!isGap) {
                exportLineSegment(dash, angle);
                ret = nextTotal;
            }
        }

        cursor += vp[i];
        total = nextTotal;

        done = total > length;

        // export shape (zigzag, text, etc.) at end of dash / gap:
        if (p.hasShapeAt(i)) {
            QList<RPainterPath> pps = p.getShapeAt(i);
            exportLinetypeShape(pps, line, total, length, angle, cursor);
        }

        ++i;
        if (i >= p.getNumDashes()) {
            i = 0;
        }
    } while (!done);

    delete[] vp;

    return ret;
}
Example #9
0
void RExporter::exportSpline(const RSpline& spline, double offset) {
    RLinetypePattern p = getLinetypePattern();

    bool continuous = false;
    if (getEntity() == NULL || !p.isValid() || p.getNumDashes() <= 1 || draftMode || screenBasedLinetypes || twoColorSelectedMode) {
        continuous = true;
    }

    p.scale(getLineTypePatternScale(p));
    double patternLength = p.getPatternLength();
    if (patternLength<RS::PointTolerance || spline.getLength() / patternLength > RSettings::getDashThreshold()) {
        continuous = true;
    }

    if (!continuous) {
        if (getEntity()!=NULL && (getEntity()->getType()!=RS::EntitySpline || RSpline::hasProxy())) {
            // we have a spline proxy:
            RShapesExporter(*this, QList<QSharedPointer<RShape> >() << QSharedPointer<RShape>(spline.clone()), offset);
        }
        else {
            // fallback if we don't have a spline proxy:
            p.scale(getLineTypePatternScale(p));

            if (RMath::isNaN(offset)) {
                double length = spline.getLength();
                offset = p.getPatternOffset(length);
            }
            exportExplodable(spline, offset);
        }
    }
    else {
        // version <= 3.0.0 was (line interpolation):
        //exportExplodable(spline, offset);

        // performance improvement (using real splines):
        RPainterPath pp;
        pp.setPen(currentPen);
        pp.setInheritPen(true);
        pp.addSpline(spline);
        exportPainterPaths(QList<RPainterPath>() << pp);
    }

    /*
    RLinetypePattern p = getLinetypePattern();
    p.scale(getLineTypePatternScale(p));

    if (RMath::isNaN(offset)) {
        double length = spline.getLength();
        offset = p.getPatternOffset(length);
    }

    double currentOffset = offset;
    QList<QSharedPointer<RShape> > sub = spline.getExploded();
    QList<QSharedPointer<RShape> >::iterator it;
    for (it=sub.begin(); it!=sub.end(); ++it) {
        QSharedPointer<RLine> line = (*it).dynamicCast<RLine>();
        if (!line.isNull()) {
            exportLine(*line.data(), currentOffset);
            currentOffset -= line->getLength();
        }

        QSharedPointer<RArc> arc = (*it).dynamicCast<RArc>();
        if (!arc.isNull()) {
            exportArc(*arc.data(), currentOffset);
            currentOffset -= arc->getLength();
        }
    }
    */
}