void RArcEntity::setShape(const RArc& a) { data.setCenter(a.getCenter()); data.setRadius(a.getRadius()); data.setStartAngle(a.getStartAngle()); data.setEndAngle(a.getEndAngle()); data.setReversed(a.isReversed()); }
/** * \return List of splines which approximate the given arc. */ QList<RSpline> RSpline::createSplinesFromArc(const RArc& arc) { RArc a = arc; if (a.isReversed()) { a.reverse(); } double startAngle = RMath::getNormalizedAngle(a.getStartAngle()); double endAngle = RMath::getNormalizedAngle(a.getEndAngle()); if (a.isFullCircle()) { startAngle = 0.0; endAngle = 2*M_PI; } // normalize startAngle, endAngle to [-2PI, 2PI] double twoPI = M_PI * 2; //double startAngle = RMath::getNormalizedAngle(a.getStartAngle()); //double endAngle = RMath::getNormalizedAngle(a.getEndAngle()); if (startAngle>endAngle) { startAngle-=2*M_PI; } double radius = a.getRadius(); double EPSILON = 0.00001; // Compute the sequence of arc curves, up to PI/2 at a time. Total arc angle // is less than 2PI. QList<RSpline> curves; double piOverTwo = M_PI_2; double segmentationAngle = piOverTwo/4; //double segmentationAngle = M_PI/8; double sgn = (startAngle < endAngle) ? +1 : -1; double a1 = startAngle; for (double totalAngle = qMin(twoPI, qAbs(endAngle - startAngle)); totalAngle > EPSILON; ) { double a2 = a1 + sgn * qMin(totalAngle, segmentationAngle); RSpline sp = RSpline::createBezierFromSmallArc(radius, a1, a2); sp.move(a.getCenter()); curves.append(sp); totalAngle -= qAbs(a2 - a1); a1 = a2; } return curves; }
void RExporter::exportArcSegment(const RArc& arc) { double segmentLength; if (pixelSizeHint>0.0) { // approximate arc with segments with the length of 2 pixels: segmentLength = pixelSizeHint * 2; } else { segmentLength = arc.getRadius() / 40.0; } // avoid a segment length of 0: if (segmentLength<1.0e-4) { segmentLength = 1.0e-4; } double a1 = arc.getStartAngle(); double a2 = arc.getEndAngle(); RVector center = arc.getCenter(); double radius = arc.getRadius(); // avoid huge radius and slow down to almost stand-still: if (radius>1.0e6) { return; } double aStep; if (radius<1.0e-3) { aStep = 0.1; } else { aStep = segmentLength / radius; if (aStep>1.0) { aStep = 1.0; } double minAStep = 2*M_PI/360.0; if (!draftMode) { minAStep /= 4; } if (aStep<minAStep) { aStep = minAStep; } } RVector prev = arc.getStartPoint(); RVector ci; double a; if(!arc.isReversed()) { // Arc Counterclockwise: if(a1>a2-RS::AngleTolerance) { a2+=2*M_PI; } for(a=a1+aStep; a<=a2; a+=aStep) { ci.x = center.x + cos(a) * radius; ci.y = center.y + sin(a) * radius; //path.lineTo(RVector(ci.x, ci.y)); this->exportLineSegment(RLine(prev, ci)); prev = ci; } } else { // Arc Clockwise: if(a1<a2+RS::AngleTolerance) { a2-=2*M_PI; } for(a=a1-aStep; a>=a2; a-=aStep) { ci.x = center.x + cos(a) * radius; ci.y = center.y + sin(a) * radius; this->exportLineSegment(RLine(prev, ci)); //path.lineTo(RVector(cix, ciy)); prev = ci; } } this->exportLineSegment(RLine(prev, arc.getEndPoint())); //path.lineTo(arc.getEndPoint()); }
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; }
void RExporter::exportArcSegment(const RArc& arc, bool allowForZeroLength) { if (allowForZeroLength && arc.isFullCircle()) { exportLineSegment(RLine(arc.getStartPoint(), arc.getEndPoint()), arc.getDirection1()); return; } double segmentLength; if (pixelSizeHint>0.0) { // approximate arc with segments with the length of 2 pixels: segmentLength = pixelSizeHint * 2; } else { segmentLength = arc.getRadius() / 40.0; } // avoid a segment length of 0: if (segmentLength<1.0e-4) { segmentLength = 1.0e-4; } double a1 = arc.getStartAngle(); double a2 = arc.getEndAngle(); RVector center = arc.getCenter(); double radius = arc.getRadius(); double aStep; if (radius<1.0e-3) { aStep = 0.1; } else { aStep = segmentLength / radius; if (aStep>1.0) { aStep = 1.0; } double minAStep = RSettings::getMinArcAngleStep(); if (draftMode) { minAStep *= 4; } if (aStep<minAStep) { aStep = minAStep; } } RVector prev = arc.getStartPoint(); RVector ci; double a; if (!arc.isReversed()) { // Arc Counterclockwise: if(a1>a2-RS::AngleTolerance) { a2+=2*M_PI; } for (a=a1+aStep; a<=a2; a+=aStep) { ci.x = center.x + cos(a) * radius; ci.y = center.y + sin(a) * radius; exportLineSegment(RLine(prev, ci), a+M_PI_2); prev = ci; } } else { // Arc Clockwise: if (a1<a2+RS::AngleTolerance) { a2-=2*M_PI; } for (a=a1-aStep; a>=a2; a-=aStep) { ci.x = center.x + cos(a) * radius; ci.y = center.y + sin(a) * radius; exportLineSegment(RLine(prev, ci), a+M_PI_2); prev = ci; } } this->exportLineSegment(RLine(prev, arc.getEndPoint()), arc.getEndAngle()+M_PI_2); }