QList<RVector> RShape::getIntersectionPointsCC(const RCircle& circle1, const RCircle& circle2) { QList<RVector> res; bool tangent = false; RVector c1 = circle1.getCenter(); RVector c2 = circle2.getCenter(); double r1 = circle1.getRadius(); double r2 = circle2.getRadius(); RVector u = c2 - c1; // the two circles (almost) touch in one point (tangent): if (RMath::fuzzyCompare(u.getMagnitude(), r1+r2, 1.0e-6)) { u.setMagnitude2d(r1); res.append(c1 + u); tangent = true; return res; } // concentric if (u.getMagnitude() < RS::PointTolerance) { return res; } RVector v = RVector(u.y, -u.x); double s, t1, t2, term; s = 1.0/2.0 * ((r1*r1 - r2*r2)/(RMath::pow(u.getMagnitude(), 2.0)) + 1.0); term = (r1*r1)/(RMath::pow(u.getMagnitude(), 2.0)) - s*s; // no intersection: if (term < 0.0) { return res; } // one or two intersections: t1 = sqrt(term); t2 = -sqrt(term); RVector sol1 = c1 + u*s + v*t1; RVector sol2 = c1 + u*s + v*t2; if (sol1.equalsFuzzy(sol2, 1.0e-4)) { res.append(sol1); tangent = true; } else { res.append(sol1); res.append(sol2); } return res; }
RVector RCircle::getVectorTo(const RVector& point, bool /*limited*/) const { RVector v = point - center; // point is at the center of the circle, infinite solutions: if (v.getMagnitude()<RS::PointTolerance) { return RVector::invalid; } return RVector::createPolar(v.getMagnitude() - radius, v.getAngle()); }
/** * \return The distance vector from this entity to the given point. * * \param point the point to which the distance was measured * * \param limited: If true, an invalid vector is returned if the * closest point on the entity is outside of the entity (e.g. in * the extension line of a line or outside the start / end angle * of an arc). */ RVector REntityData::getVectorTo(const RVector& point, bool limited) const { RVector ret = RVector::invalid; QList<QSharedPointer<RShape> > shapes = getShapes(); for (int i=0; i<shapes.size(); i++) { shapes.at(i)->to2D(); RVector r = shapes.at(i)->getVectorTo(point, limited); if (!ret.isValid() || r.getMagnitude()<ret.getMagnitude()) { ret = r; } } return ret; }
RVector RPolyline::getVectorTo(const RVector& point, bool limited, double strictRange) const { RVector ret = RVector::invalid; QList<QSharedPointer<RShape> > sub = getExploded(); QList<QSharedPointer<RShape> >::iterator it; for (it=sub.begin(); it!=sub.end(); ++it) { RVector v = (*it)->getVectorTo(point, limited, strictRange); if (v.isValid() && (!ret.isValid() || v.getMagnitude()<ret.getMagnitude())) { ret = v; } } return ret; }
bool RCircle::move(const RVector& offset) { if (!offset.isValid() || offset.getMagnitude() < RS::PointTolerance) { return false; } center += offset; return true; }
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; }
/** * \return Shortest distance from this shape to the given point. * Based on \ref getVectorTo. */ double RShape::getDistanceTo(const RVector& point, bool limited) const { RVector v = getVectorTo(point, limited); if (v.isValid()) { return v.getMagnitude(); } return RNANDOUBLE; }
/** * \return The shortest distance from this entity to the given point. */ double REntityData::getDistanceTo(const RVector& point, bool limited, double range, bool draft) const { Q_UNUSED(range); Q_UNUSED(draft); RVector v = getVectorTo(point, limited); if (v.isValid()) { return v.getMagnitude(); } return RNANDOUBLE; }
RVector RArc::getVectorTo(const RVector& point, bool limited) const { double angle = center.getAngleTo(point); if (limited && !RMath::isAngleBetween(angle, startAngle, endAngle, reversed)) { return RVector::invalid; } RVector v = point - center; return RVector::createPolar(v.getMagnitude() - radius, v.getAngle()); }
RVector RSpline::getVectorTo(const RVector& point, bool limited, double strictRange) const { RVector ret = RVector::invalid; // TODO: not implemented in Teigha: // if (splineProxy!=NULL) { // RVector p = splineProxy->getClosestPointOnShape(*this, point, limited); // if (p.isValid()) { // ret = p - point; // } // } // else { QList<QSharedPointer<RShape> > sub = getExploded(); QList<QSharedPointer<RShape> >::iterator it; for (it=sub.begin(); it!=sub.end(); ++it) { RVector v = (*it)->getVectorTo(point, limited, strictRange); if (v.isValid() && (!ret.isValid() || v.getMagnitude()<ret.getMagnitude())) { ret = v; } } // } return ret; }
double RTriangle::getDistanceTo(const RVector& point, bool limited) const { RVector normal = getNormal(); double d = getD(); double distance = (normal.x * point.x + normal.y * point.y + normal.z * point.z + d) / (normal.getMagnitude()); if (!limited || isPointInTriangle(point - normal.getUnitVector() * distance)) { return distance; } return RMAXDOUBLE; }
void ROrthoGrid::paintRuler(RRuler& ruler, qreal devicePixelRatio) { RDocument* doc = view.getDocument(); if (doc == NULL) { return; } RS::Unit unit = doc->getUnit(); RS::LinearFormat linearFormat = doc->getLinearFormat(); // use grid spacing if available or auto grid spacing: RVector localSpacing = spacing; if (!localSpacing.isValid() || (autoSpacing.isValid() && autoSpacing.getMagnitude2d() < localSpacing.getMagnitude2d())) { localSpacing = autoSpacing; } // use meta grid spacing if available or auto meta grid spacing: RVector localMetaSpacing = metaSpacing; if (!localMetaSpacing.isValid() || (autoMetaSpacing.isValid() && autoMetaSpacing.getMagnitude2d() < localMetaSpacing.getMagnitude2d())) { //localMetaSpacing = autoMetaSpacing; } //if (!localMetaSpacing.isValid()) { // qDebug() << "no local meta spacing"; // return; //} if (localSpacing.getMagnitude()<1.0e-6 || localMetaSpacing.getMagnitude()<1.0e-6) { //qDebug() << "local (meta) spacing too small"; return; } RVector min = gridBox.getCorner1(); RVector max = gridBox.getCorner2(); bool isHorizontal = ruler.getOrientation() == Qt::Horizontal; double tickSpacing; //if (!RUnit::isMetric(doc->getUnit())) { if (isFractionalFormat(linearFormat) && !RUnit::isMetric(unit)) { if (isHorizontal) { tickSpacing = localSpacing.x; } else { tickSpacing = localSpacing.y; } } else { if (isHorizontal) { tickSpacing = localMetaSpacing.x; } else { tickSpacing = localMetaSpacing.y; } if (view.mapDistanceToView(tickSpacing) >= 80) { tickSpacing /= 10; } else if (view.mapDistanceToView(tickSpacing) >= 30) { tickSpacing /= 5; } else if (view.mapDistanceToView(tickSpacing) >= 20) { tickSpacing /= 2; } } // ideal tick spacing in pixels: int pSpacing = (int) ceil(view.mapDistanceToView(tickSpacing)); QString l1 = RUnit::getLabel(isHorizontal ? min.x : min.y, *doc, false, true); QString l2 = RUnit::getLabel(isHorizontal ? max.x : max.y, *doc, false, true); int labelWidth = std::max( QFontMetrics(ruler.getFont()).boundingRect(l1).width(), QFontMetrics(ruler.getFont()).boundingRect(l2).width()) + 15; // smallest displayable distance between labels in steps (ticks): int minLabelStep = 1; if (pSpacing>0) { minLabelStep = labelWidth / pSpacing + 1; } int labelStep = minLabelStep; //if (!RUnit::isMetric(doc->getUnit())) { if (isFractionalFormat(linearFormat) && !RUnit::isMetric(unit)) { // non metric double f = 1.0/128; do { if (localMetaSpacing.isValid()) { if (isHorizontal) { labelStep = RMath::mround(localMetaSpacing.x / localSpacing.x) * f; } else { labelStep = RMath::mround(localMetaSpacing.y / localSpacing.y) * f; } } else { labelStep = (int)f; } f = f * 2; if (f>65536) { labelStep = -1; } } while (labelStep < minLabelStep && labelStep>=0); } else { // metric if (labelStep >= 3 && labelStep <= 4) { labelStep = 5; } else if (labelStep >= 6 && labelStep <= 9) { labelStep = 10; } else if (labelStep >= 11 && labelStep <= 19) { labelStep = 20; } else if (labelStep >= 21 && labelStep <= 99) { labelStep = 100; } } if (labelStep<0) { return; } if (labelStep<1) { labelStep = 1; } double minPos; double maxPos; if (isHorizontal) { minPos = (floor(view.mapFromView(RVector(0, 0)).x / (labelStep * tickSpacing))-1) * (labelStep * tickSpacing); maxPos = (ceil(view.mapFromView(RVector(view.getWidth(), 0)).x / (labelStep * tickSpacing))+1) * (labelStep * tickSpacing); } else { minPos = (floor(view.mapFromView(RVector(0, view.getHeight())).y / (labelStep * tickSpacing))-1) * (labelStep * tickSpacing); maxPos = (ceil(view.mapFromView(RVector(0, 0)).y / (labelStep * tickSpacing))+1) * (labelStep * tickSpacing); } if ((maxPos - minPos) / tickSpacing > 1e3) { return; } int c; double p; for (c = 0, p = minPos; p < maxPos; p += tickSpacing, ++c) { bool hasLabel = c % labelStep == 0; double v; if (isHorizontal) { v = view.mapToView(RVector(p, 0)).x; } else { v = view.mapToView(RVector(0, p)).y; } ruler.paintTick(v*devicePixelRatio, hasLabel, hasLabel ? RUnit::getLabel(p, *doc, false, true, true) : QString()); } }
/** * Sets the minor point relative to the center point. */ void REllipse::setMinorPoint(const RVector& p) { double angle = RMath::getNormalizedAngle(p.getAngle() - M_PI/2.0); majorPoint.setPolar(getMajorRadius(), angle); setRatio(p.getMagnitude() / getMajorRadius()); }
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; }