Beispiel #1
0
QList<RVector> RShape::getIntersectionPointsLT(const RLine& line1,
        const RTriangle& triangle2, bool limited) {

    QList<RVector> res;

    RVector normal = triangle2.getNormal();

    if (normal.getMagnitude() < 1.0e-12) {
        return res;
    }

    if (line1.getLength() < 1.0e-12) {
        return res;
    }

    double t = RVector::getDotProduct(normal, triangle2.getCorner(2) - line1.getStartPoint())
            / RVector::getDotProduct(normal, (line1.getEndPoint() - line1.getStartPoint()));

    // check if intersection point is on the line:
    if (limited && (t < 0.0 || t > 1.0)) {
        return res;
    }

    // intersection point:
    RVector ip = line1.getStartPoint() + (line1.getEndPoint() - line1.getStartPoint()) * t;

    // check if intersection point is inside the triangle:
    if (!limited || triangle2.isPointInTriangle(ip)) {
        res.push_back(ip);
    }

    return res;
}
void RPainterPathExporter::exportLineSegment(const RLine& line, double angle) {
    if (line.getLength()<RS::PointTolerance) {
        if (exportZeroLinesAsPoints) {
            path.addPoint(line.getStartPoint());
        }
        else {
            // Qt won't export a zero length line as point:
            // e.g. dot in a dash/dot line:
            RVector startPoint = line.startPoint - RVector::createPolar(0.01, angle);
            RVector endPoint = line.endPoint + RVector::createPolar(0.01, angle);
            path.moveTo(startPoint);
            path.lineTo(endPoint);
//            path.moveTo(line.getStartPoint()-RVector(0.01,0));
//            path.lineTo(line.getEndPoint()+RVector(0.01, 0));
//            path.moveTo(line.getStartPoint()-RVector(0,0.01));
//            path.lineTo(line.getEndPoint()+RVector(0, 0.01));
        }
    }
    else {
        if (!path.isAtPosition(line.getStartPoint())) {
            path.moveTo(line.getStartPoint());
        }
        path.lineTo(line.getEndPoint());
    }
}
Beispiel #3
0
void RGraphicsSceneQt::exportRay(const RRay& ray) {
    bool created = beginPath();

    Q_ASSERT(currentPainterPath.isValid());

    // find largest view box over all attached views:
    RBox box;
    QList<RGraphicsView*>::iterator it;
    for (it=views.begin(); it!=views.end(); it++) {
        RBox b = (*it)->getBox();
        box.growToIncludeBox(b);
    }

    // trim line to view box:
    RLine clippedLine = ray.getClippedLine(box);

    double offs = clippedLine.getStartPoint().getDistanceTo(ray.getBasePoint());
    if (RMath::isSameDirection(ray.getBasePoint().getAngleTo(clippedLine.getStartPoint()), ray.getDirection1())) {
        offs *= -1;
    }

    exportLine(clippedLine, offs);

    currentPainterPath.setAlwaysRegen(true);

    if (created) {
        endPath();
    }
}
void RPainterPathExporter::exportLineSegment(const RLine& line) {
    if (line.getLength()<RS::PointTolerance) {
        path.addPoint(line.getStartPoint());
    }
    else {
        path.moveTo(line.getStartPoint());
        path.lineTo(line.getEndPoint());
    }
}
Beispiel #5
0
RVector RVector::rotate3D(const RLine& axis, double rotation) {
    RVector off = -axis.getStartPoint();
    RVector ret = *this;
    ret.move(off);
    RVector ax = axis.getStartPoint() - axis.getEndPoint();
    QQuaternion quat = QQuaternion::fromAxisAndAngle(ax.x, ax.y, ax.z, RMath::rad2deg(rotation));
    QVector3D qv = quat.rotatedVector(QVector3D(ret.x, ret.y, ret.z));
    ret = RVector(qv.x(), qv.y(), qv.z());
    ret.move(-off);
    *this = ret;
    return *this;
}
Beispiel #6
0
bool RDimRotatedData::mirror(const RLine& axis) {
    RDimLinearData::mirror(axis);
    //extensionPoint1.mirror(axis);
    //extensionPoint2.mirror(axis);

    RLine neutralAxis = axis;
    neutralAxis.move(-neutralAxis.getStartPoint());
    RVector vec = RVector::createPolar(1.0, rotation);
    vec.mirror(neutralAxis);
    rotation = vec.getAngle();

    update();
    return true;
}
Beispiel #7
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;
}
Beispiel #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;
}
Beispiel #9
0
QList<RVector> RShape::getIntersectionPointsLE(const RLine& line1,
        const REllipse& ellipse2, bool limited) {

    QList<RVector> res;

    // find out if line1 is (almost) a tangent:
    QList<RLine> tangents = ellipse2.getTangents(line1.getMiddlePoint());
    for (int i=0; i<tangents.length(); i++) {
        double a = tangents[i].getAngle();
        double ad1 = fabs(RMath::getAngleDifference180(a, line1.getDirection1()));
        double ad2 = fabs(RMath::getAngleDifference180(a, line1.getDirection2()));

        if (ad1 < 1.0e-2 || ad2 < 1.0e-2) {
            res.append(tangents[i].getEndPoint());

            // no need to continue: max. one tangent possible:
            return res;
        }
    }

    // rotate into normal position:
    double ang = ellipse2.getAngle();

    double rx = ellipse2.getMajorRadius();
    double ry = ellipse2.getMinorRadius();
    RVector center = ellipse2.getCenter();
    RVector a1 = line1.getStartPoint();
    a1.rotate(-ang, center);
    RVector a2 = line1.getEndPoint();
    a2.rotate(-ang, center);
    RVector origin = a1;
    RVector dir = a2-a1;
    RVector diff = origin - center;
    RVector mDir = RVector(dir.x/(rx*rx), dir.y/(ry*ry));
    RVector mDiff = RVector(diff.x/(rx*rx), diff.y/(ry*ry));

    double a = RVector::getDotProduct(dir, mDir);
    double b = RVector::getDotProduct(dir, mDiff);
    double c = RVector::getDotProduct(diff, mDiff) - 1.0;
    double d = b*b - a*c;

    RVector res1 = RVector::invalid;
    RVector res2 = RVector::invalid;

    if (d < 0) {
        // no solution
    } else if ( d > 0 ) {
        double root = sqrt(d);
        double t_a = (-b - root) / a;
        double t_b = (-b + root) / a;

        res1 = a1.getLerp(a2, t_a).rotate(ang, center);
        res2 = a1.getLerp(a2, t_b).rotate(ang, center);
    } else {
        double t = -b/a;
        if ( 0 <= t && t <= 1 ) {
            // one solution:
            res1 = a1.getLerp(a2, t).rotate(ang, center);
        } else {
            // no solution
        }
    }

    if (res1.isValid()) {
        if (!limited || (line1.isOnShape(res1) && ellipse2.isOnShape(res1))) {
            res.append(res1);
        }
    }
    if (res2.isValid()) {
        if (!limited || (line1.isOnShape(res2) && ellipse2.isOnShape(res2))) {
            res.append(res2);
        }
    }

    return res;
}
Beispiel #10
0
QList<RVector> RShape::getIntersectionPointsLC(const RLine& line1,
        const RCircle& circle2, bool limited) {
    QList<RVector> res;

    RVector vLineCenter = line1.getVectorTo(circle2.getCenter(), false);
    double dist = vLineCenter.getMagnitude();

    // special case: arc touches line (tangent):
    if (fabs(dist - circle2.getRadius()) < 1.0e-4) {
        res.append(circle2.getCenter() - vLineCenter);
        // ret.setTangent(true);
        return res;
    }

    RVector p = line1.getStartPoint();
    RVector d = line1.getEndPoint() - line1.getStartPoint();
    if (d.getMagnitude() < 1.0e-6) {
        return res;
    }

    RVector delta = p - circle2.getCenter();

    // root term:
    double term = RMath::pow(RVector::getDotProduct(d, delta), 2.0)
                  - RMath::pow(d.getMagnitude(), 2.0)
                  * (RMath::pow(delta.getMagnitude(), 2.0) - RMath::pow(circle2.getRadius(), 2.0));

    // no intersection:
    if (term<0.0) {
        return res;
    }

    // one or two intersections:
    double t1 = (- RVector::getDotProduct(d, delta) + sqrt(term))
                / RMath::pow(d.getMagnitude(), 2.0);
    double t2;
    bool tangent = false;

    // only one intersection:
    if (fabs(term) < RS::PointTolerance) {
        t2 = t1;
        tangent = true;
    }

    // two intersections
    else {
        t2 = (-RVector::getDotProduct(d, delta) - sqrt(term))
             / RMath::pow(d.getMagnitude(), 2.0);
    }

    RVector sol1;
    RVector sol2 = RVector::invalid;

    sol1 = p + d * t1;

    if (!tangent) {
        sol2 = p + d * t2;
    }

    if (!limited || line1.isOnShape(sol1)) {
        res.append(sol1);
    }
    if (sol2.isValid()) {
        if (!limited || line1.isOnShape(sol2)) {
            res.append(sol2);
        }
    }
    // ret.setTangent(tangent);

    return res;
}
Beispiel #11
0
RXLine::RXLine(const RLine& line) :
    basePoint(line.getStartPoint()), directionVector(line.getEndPoint()-line.getStartPoint()) {
}