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()); }
QList<RVector> RShape::getIntersectionPointsAE(const RArc& arc1, const REllipse& ellipse2, bool limited) { QList<RVector> candidates = RShape::getIntersectionPointsCE( RCircle(arc1.getCenter(), arc1.getRadius()), ellipse2); if (!limited) { return candidates; } QList<RVector> res; for (int i=0; i<candidates.count(); i++) { RVector c = candidates[i]; if (arc1.isOnShape(c)) { if (!ellipse2.isFullEllipse()) { double a1 = ellipse2.getCenter().getAngleTo(ellipse2.getStartPoint()); double a2 = ellipse2.getCenter().getAngleTo(ellipse2.getEndPoint()); double a = ellipse2.getCenter().getAngleTo(c); if (!RMath::isAngleBetween(a, a1, a2, ellipse2.isReversed())) { continue; } } res.append(c); } } return res; }
void RGraphicsSceneQt::exportArcSegment(const RArc& arc, bool allowForZeroLength) { Q_ASSERT(currentPainterPath.isValid()); if (arc.getRadius()<RS::PointTolerance) { currentPainterPath.addPoint(arc.getCenter()); return; } // arc threshold is configurable (FS#1012): if (arc.getAngleLength(allowForZeroLength)<=RSettings::getArcAngleLengthThreshold()) { // Qt won't export a zero length line as point: RVector startPoint = arc.getStartPoint() - RVector::createPolar(0.01, arc.getStartAngle()+M_PI_2); RVector endPoint = arc.getEndPoint() + RVector::createPolar(0.01, arc.getStartAngle()+M_PI_2); currentPainterPath.moveTo(startPoint); currentPainterPath.lineTo(endPoint); return; } // arc approximation with splines: faster but not precise enough: // RPainterPath p; // p.addArc(arc); // currentPainterPath.addPath(p); if (twoColorSelectedMode) { // QPainterPath with pattern shown as solid when clipped bug workaround: currentPainterPath.moveTo(arc.getStartPoint()); currentPainterPath.arcTo( arc.getCenter().x-arc.getRadius(), arc.getCenter().y-arc.getRadius(), arc.getRadius()*2, arc.getRadius()*2, RMath::rad2deg(-arc.getStartAngle()), RMath::rad2deg(-arc.getSweep()) ); } else { currentPainterPath.setAutoRegen(true); RGraphicsScene::exportArcSegment(arc, allowForZeroLength); } }
QList<RVector> RShape::getIntersectionPointsAA(const RArc& arc1, const RArc& arc2, bool limited) { QList<RVector> candidates = RShape::getIntersectionPoints( RCircle(arc1.getCenter(), arc1.getRadius()), RCircle(arc2.getCenter(), arc2.getRadius()) ); if (!limited) { return candidates; } QList<RVector> res; for (int i=0; i<candidates.count(); i++) { if (arc1.isOnShape(candidates[i]) && arc2.isOnShape(candidates[i])) { res.append(candidates[i]); } } // ret.setTangent(tangent); return res; }
QList<RVector> RShape::getIntersectionPointsAT(const RArc& arc1, const RTriangle& triangle2, bool limited) { Q_UNUSED(limited) RTriangle plane(arc1.getCenter(), arc1.getStartPoint(), arc1.getEndPoint()); QList<RVector> r = plane.getIntersectionPoints(RLine(triangle2.getCorner(0), triangle2.getCorner(1))); r.append(plane.getIntersectionPoints(RLine(triangle2.getCorner(1), triangle2.getCorner(2)))); r.append(plane.getIntersectionPoints(RLine(triangle2.getCorner(2), triangle2.getCorner(0)))); if (r.size()<2) { return QList<RVector>(); } RLine l(r[0], r[1]); return l.getIntersectionPoints(arc1); }
/** * \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); }