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