bool RPolylineData::moveReferencePoint(const RVector& referencePoint, const RVector& targetPoint) { bool ret = false; QList<RVector>::iterator it; for (it=vertices.begin(); it!=vertices.end(); ++it) { if (referencePoint.equalsFuzzy(*it)) { (*it) = targetPoint; ret = true; } } for (int i=0; i<countSegments(); i++) { if (isArcSegmentAt(i)) { QSharedPointer<RArc> arc = getSegmentAt(i).dynamicCast<RArc>(); if (!arc.isNull()) { if (referencePoint.equalsFuzzy(arc->getMiddlePoint())) { RArc a = RArc::createFrom3Points(arc->getStartPoint(), targetPoint, arc->getEndPoint()); setBulgeAt(i, a.getBulge()); ret = true; } } } } return ret; }
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; }
RArc RArc::createTangential(const RVector& startPoint, const RVector& pos, double direction, double radius) { RArc arc; arc.radius = radius; // orthogonal to base entity: RVector ortho; ortho.setPolar(radius, direction + M_PI/2.0); // two possible center points for arc: RVector center1 = startPoint + ortho; RVector center2 = startPoint - ortho; if (center1.getDistanceTo(pos) < center2.getDistanceTo(pos)) { arc.center = center1; } else { arc.center = center2; } // angles: arc.startAngle = arc.center.getAngleTo(startPoint); arc.endAngle = arc.center.getAngleTo(pos); // handle arc direction: arc.reversed = false; double diff = RMath::getNormalizedAngle(arc.getDirection1() - direction); if (fabs(diff-M_PI) < 1.0e-1) { arc.reversed = true; } return arc; }
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); }
QList<RVector> RShape::getIntersectionPointsAC(const RArc& arc1, const RCircle& circle2, bool limited) { QList<RVector> candidates = RShape::getIntersectionPoints( RCircle(arc1.getCenter(), arc1.getRadius()), circle2 ); if (!limited) { return candidates; } QList<RVector> res; for (int i=0; i<candidates.count(); i++) { if (arc1.isOnShape(candidates[i])) { res.append(candidates[i]); } } // ret.setTangent(tangent); return res; }
QList<RVector> RShape::getIntersectionPointsLA(const RLine& line1, const RArc& arc2, bool limited1, bool limited2) { QList<RVector> candidates = RShape::getIntersectionPointsLC( line1, RCircle(arc2.getCenter(), arc2.getRadius()), limited1 ); if (!limited2) { return candidates; } QList<RVector> res; for (int i=0; i<candidates.count(); i++) { if (arc2.isOnShape(candidates[i])) { res.append(candidates[i]); } } // ret.setTangent(tangent); return res; }
/** * \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::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; */ }
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); }
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); } }
void REcmaHelper::fromScriptValue(QScriptEngine* engine, QScriptValue scriptValue, QList<QSharedPointer<RShape> >& cppValue) { QVariantList variantList = engine->fromScriptValue<QVariantList>(scriptValue); for (int i = 0; i < variantList.size(); ++i) { QVariant v = variantList.at(i); QSharedPointer<RShape> pShape = v.value<QSharedPointer<RShape> >(); if (!pShape.isNull()) { cppValue.append(pShape); } else { RShape* shape = v.value<RShape*>(); if (shape!=NULL) { QSharedPointer<RShape> pShape(shape->clone()); cppValue.append(pShape); } else if (v.canConvert<RArc>()) { RArc obj = v.value<RArc>(); QSharedPointer<RArc> p(obj.clone()); cppValue.append(p); } else if (v.canConvert<RCircle>()) { RCircle obj = v.value<RCircle>(); QSharedPointer<RCircle> p(obj.clone()); cppValue.append(p); } else if (v.canConvert<RLine>()) { RLine obj = v.value<RLine>(); QSharedPointer<RLine> p(obj.clone()); cppValue.append(p); } else if (v.canConvert<RPoint>()) { RPoint obj = v.value<RPoint>(); QSharedPointer<RPoint> p(obj.clone()); cppValue.append(p); } else if (v.canConvert<RPolyline>()) { RPolyline obj = v.value<RPolyline>(); QSharedPointer<RPolyline> p(obj.clone()); cppValue.append(p); } else if (v.canConvert<RSpline>()) { RSpline obj = v.value<RSpline>(); QSharedPointer<RSpline> p(obj.clone()); cppValue.append(p); } else if (v.canConvert<RTextLabel>()) { RTextLabel obj = v.value<RTextLabel>(); QSharedPointer<RTextLabel> p(obj.clone()); cppValue.append(p); } else if (v.canConvert<RTriangle>()) { RTriangle obj = v.value<RTriangle>(); QSharedPointer<RTriangle> p(obj.clone()); cppValue.append(p); } } } }