| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <vector> |
| |
|
| | #include "lc_quadratic.h" |
| |
|
| | #include "rs_circle.h" |
| | #include "rs_debug.h" |
| | #include "rs_information.h" |
| | #include "rs_line.h" |
| | #include "rs_math.h" |
| | #include "rs_painter.h" |
| |
|
| |
|
| | namespace { |
| | |
| | |
| | constexpr double Tangent_Tolerance_Factor = 1e-6; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | bool identicalXOrY(const std::vector<std::vector<double>>& mat) { |
| | |
| | assert(mat.size() >= 2 && mat.front().size() >= 3); |
| | const auto isDegenerateCol = [&mat] (size_t column) { |
| | return RS_Math::equal(std::max(std::abs(mat[0][column]), std::abs(mat[1][column])), 0., RS_TOLERANCE); |
| | }; |
| | |
| | return isDegenerateCol(0) || isDegenerateCol(1); |
| | } |
| | } |
| |
|
| | RS_CircleData::RS_CircleData(RS_Vector const& center, double radius): |
| | center(center) |
| | , radius(radius){ |
| | } |
| |
|
| | bool RS_CircleData::isValid() const { |
| | return (center.valid && radius>RS_TOLERANCE); |
| | } |
| |
|
| | bool RS_CircleData::operator == (RS_CircleData const& rhs) const{ |
| | if (!(center.valid && rhs.center.valid)) { |
| | return false; |
| | } |
| | if (center.squaredTo(rhs.center) > RS_TOLERANCE2) { |
| | return false; |
| | } |
| | return std::abs(radius - rhs.radius) < RS_TOLERANCE; |
| | } |
| |
|
| | std::ostream& operator << (std::ostream& os, const RS_CircleData& ad){ |
| | os << "(" << ad.center << |
| | "/" << ad.radius << |
| | ")"; |
| | return os; |
| | } |
| |
|
| | |
| | |
| | |
| | RS_Circle::RS_Circle(RS_EntityContainer* parent, |
| | const RS_CircleData& d) |
| | :LC_CachedLengthEntity(parent), data(d) { |
| | calculateBorders(); |
| | } |
| |
|
| | RS_Circle::RS_Circle(const RS_CircleData& d) |
| | :LC_CachedLengthEntity(nullptr), data(d) { |
| | calculateBorders(); |
| | } |
| |
|
| | RS_Entity* RS_Circle::clone() const { |
| | auto c = new RS_Circle(*this); |
| | return c; |
| | } |
| |
|
| | void RS_Circle::calculateBorders() { |
| | RS_Vector r{data.radius, data.radius}; |
| | minV = data.center - r; |
| | maxV = data.center + r; |
| | updateLength(); |
| | } |
| |
|
| | |
| | RS_Vector RS_Circle::getCenter() const { |
| | return data.center; |
| | } |
| | |
| | void RS_Circle::setCenter(const RS_Vector& c) { |
| | data.center = c; |
| | } |
| | |
| | double RS_Circle::getRadius() const { |
| | return data.radius; |
| | } |
| |
|
| | |
| | void RS_Circle::setRadius(double r) { |
| | data.radius = r; |
| | } |
| |
|
| | |
| | |
| | |
| | double RS_Circle::getAngleLength() const { |
| | return 2*M_PI; |
| | } |
| |
|
| | |
| | |
| | |
| | void RS_Circle::updateLength() { |
| | cachedLength = 2.0 * M_PI * data.radius; |
| | } |
| |
|
| | bool RS_Circle::isTangent(const RS_CircleData& circleData) const{ |
| | const double d=circleData.center.distanceTo(data.center); |
| | double r0=std::abs(circleData.radius); |
| | double r1=std::abs(data.radius); |
| | if (r0 < r1) { |
| | std::swap(r0, r1); |
| | } |
| | const double tol = Tangent_Tolerance_Factor * r0; |
| | if (r1 < tol || d < tol) { |
| | return false; |
| | } |
| |
|
| | const double tangentTol = std::max(200.*RS_TOLERANCE, tol); |
| | |
| | bool ret = std::abs(d-r0+r1)<tangentTol ||std::abs(d-r0-r1)<tangentTol; |
| | return ret; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | bool RS_Circle::createFromCR(const RS_Vector& c, double r) { |
| | if (std::abs(r)>RS_TOLERANCE && c.valid ) { |
| | data.radius = std::abs(r); |
| | data.center = c; |
| | return true; |
| | } else { |
| | RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFromCR(): " |
| | "Cannot create a circle with radius 0.0."); |
| | return false; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | bool RS_Circle::createFrom2P(const RS_Vector& p1, const RS_Vector& p2) { |
| | double r=0.5*p1.distanceTo(p2); |
| | if (r>RS_TOLERANCE) { |
| | data.radius = r; |
| | data.center = (p1+p2)*0.5; |
| | return true; |
| | } else { |
| | |
| | |
| | return false; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | bool RS_Circle::createFrom3P(const RS_Vector& p1, const RS_Vector& p2, |
| | const RS_Vector& p3) { |
| | RS_Vector vra = p2 - p1; |
| | RS_Vector vrb = p3 - p1; |
| | double ra2 = vra.squared() * 0.5; |
| | double rb2 = vrb.squared() * 0.5; |
| | double crossp = vra.x * vrb.y - vra.y * vrb.x; |
| | if (std::abs(crossp) < RS_TOLERANCE2) { |
| | RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom3P(): " |
| | "Cannot create a circle with radius 0.0."); |
| | return false; |
| | } |
| | crossp = 1. / crossp; |
| | data.center.set((ra2 * vrb.y - rb2 * vra.y) * crossp, (rb2 * vra.x - ra2 * vrb.x) * crossp); |
| | data.radius = data.center.magnitude(); |
| | data.center += p1; |
| | return true; |
| | } |
| | |
| | |
| | bool RS_Circle::createFrom3P(const RS_VectorSolutions& sol) { |
| | if(sol.getNumber() < 2) { |
| | return false; |
| | } |
| | if(sol.getNumber() == 2) { |
| | return createFrom2P(sol.get(0),sol.get(1)); |
| | } |
| | if((sol.get(1)-sol.get(2)).squared() < RS_TOLERANCE2) { |
| | return createFrom2P(sol.get(0),sol.get(1)); |
| | } |
| | RS_Vector vra(sol.get(1) - sol.get(0)); |
| | RS_Vector vrb(sol.get(2) - sol.get(0)); |
| | double ra2=vra.squared()*0.5; |
| | double rb2=vrb.squared()*0.5; |
| | double crossp=vra.x * vrb.y - vra.y * vrb.x; |
| | if (std::abs(crossp)< RS_TOLERANCE2) { |
| | RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Circle::createFrom3P(): " |
| | "Cannot create a circle with radius 0.0."); |
| | return false; |
| | } |
| | crossp=1./crossp; |
| | data.center.set((ra2*vrb.y - rb2*vra.y)*crossp,(rb2*vra.x - ra2*vrb.x)*crossp); |
| | data.radius=data.center.magnitude(); |
| | data.center += sol.get(0); |
| | return true; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | bool RS_Circle::createInscribe(const RS_Vector& coord, const std::vector<RS_Line*>& lines){ |
| | if (lines.size() < 3) { |
| | return false; |
| | } |
| | std::vector<RS_Line*> tri(lines); |
| | RS_VectorSolutions sol = RS_Information::getIntersectionLineLine(tri[0], tri[1]); |
| | if (sol.isEmpty()) { |
| | std::swap(tri[1], tri[2]); |
| | sol = RS_Information::getIntersectionLineLine(tri[0], tri[1]); |
| | } |
| | if (sol.isEmpty()) { |
| | return false; |
| | } |
| | RS_Vector vp0(sol.get(0)); |
| | sol = RS_Information::getIntersectionLineLine(tri[2], tri[1]); |
| | if (sol.isEmpty()) { |
| | return false; |
| | } |
| | RS_Vector vp1(sol.get(0)); |
| | RS_Vector dvp(vp1 - vp0); |
| | double a(dvp.squared()); |
| | if (a < RS_TOLERANCE2) { |
| | return false; |
| | } |
| | RS_Vector vp(coord - vp0); |
| | vp -= dvp * (RS_Vector::dotP(dvp, vp) / a); |
| | RS_Vector vl0(tri[0]->getEndpoint() - tri[0]->getStartpoint()); |
| | a = dvp.angle(); |
| | double angle0(0.5 * (vl0.angle() + a)); |
| | if (RS_Vector::dotP(vp, vl0) < 0.) { |
| | angle0 += 0.5 * M_PI; |
| | } |
| |
|
| | RS_Line line0(vp0, vp0 + RS_Vector(angle0)); |
| | vl0 = (tri[2]->getEndpoint() - tri[2]->getStartpoint()); |
| | angle0 = 0.5 * (vl0.angle() + a + M_PI); |
| | if (RS_Vector::dotP(vp, vl0) < 0.) { |
| | angle0 += 0.5 * M_PI; |
| | } |
| | RS_Line line1(vp1, vp1 + RS_Vector(angle0)); |
| | sol = RS_Information::getIntersectionLineLine(&line0, &line1); |
| | if (sol.isEmpty()) { |
| | return false; |
| | } |
| | bool ret = createFromCR(sol.get(0), tri[1]->getDistanceToPoint(sol.get(0))); |
| | if (!ret) { |
| | return false; |
| | } |
| | for (auto p : lines) { |
| | if (!p->isTangent(data)) { |
| | return false; |
| | } |
| | } |
| | return true; |
| | } |
| |
|
| | std::vector<RS_Entity* > RS_Circle::offsetTwoSides(const double& distance) const{ |
| | std::vector<RS_Entity*> ret(0,nullptr); |
| | ret.push_back(new RS_Circle(nullptr, {getCenter(),getRadius()+distance})); |
| | if(std::abs(getRadius()-distance)>RS_TOLERANCE) |
| | ret.push_back(new RS_Circle(nullptr, {getCenter(),std::abs(getRadius()-distance)})); |
| | return ret; |
| | } |
| |
|
| | RS_VectorSolutions RS_Circle::createTan1_2P(const RS_AtomicEntity* circle, const std::vector<RS_Vector>& points) { |
| | RS_VectorSolutions ret; |
| | if (!circle || points.size() < 2) { |
| | return ret; |
| | } |
| | return LC_Quadratic::getIntersection(LC_Quadratic(circle, points[0]),LC_Quadratic(circle, points[1])); |
| | } |
| |
|
| | |
| | |
| | |
| | RS_VectorSolutions RS_Circle::createTan2(const std::vector<RS_AtomicEntity*>& circles, const double& r){ |
| | if (circles.size() < 2) { |
| | return false; |
| | } |
| | auto e0 = circles[0]->offsetTwoSides(r); |
| | auto e1 = circles[1]->offsetTwoSides(r); |
| | RS_VectorSolutions centers; |
| | if (e0.size() && e1.size()) { |
| | for (auto it0 = e0.begin(); it0 != e0.end(); it0++) { |
| | for (auto it1 = e1.begin(); it1 != e1.end(); it1++) { |
| | centers.push_back(RS_Information::getIntersection(*it0, *it1)); |
| | } |
| | } |
| | } |
| | for (auto it0 = e0.begin(); it0 != e0.end(); it0++) { |
| | delete *it0; |
| | } |
| | for (auto it0 = e1.begin(); it0 != e1.end(); it0++) { |
| | delete *it0; |
| | } |
| | return centers; |
| | } |
| |
|
| | std::vector<RS_Circle> RS_Circle::createTan3(const std::vector<RS_AtomicEntity*>& circles) { |
| | std::vector<RS_Circle> ret; |
| | if (circles.size() != 3) { |
| | return ret; |
| | } |
| | std::vector<RS_Circle> cs; |
| | for (RS_AtomicEntity* c : circles) { |
| | cs.emplace_back(RS_Circle(nullptr, {c->getCenter(), c->getRadius()})); |
| | } |
| | unsigned short flags = 0; |
| | do { |
| | for (unsigned short j = 0u; j < 3u; ++j) { |
| | if (flags & (1u << j)) { |
| | cs[j].setRadius(-std::abs(cs[j].getRadius())); |
| | } |
| | else { |
| | cs[j].setRadius(std::abs(cs[j].getRadius())); |
| | } |
| | } |
| | |
| | std::vector<RS_Circle> list = solveAolloniusSingle(cs); |
| | if (list.empty()) { |
| | list = solveApolloniusHyperbola(cs); |
| | } |
| | if (list.size() >= 1) { |
| | for (RS_Circle& c0 : list) { |
| | bool addNew = true; |
| | for (RS_Circle& c : ret) { |
| | if ((c0.getCenter() - c.getCenter()).squared() < RS_TOLERANCE15 && std::abs( |
| | c0.getRadius() - c.getRadius()) < RS_TOLERANCE) { |
| | addNew = false; |
| | break; |
| | } |
| | } |
| | if (addNew) |
| | ret.push_back(c0); |
| | } |
| | } |
| | } |
| | while (++flags < 8u); |
| | |
| | |
| | auto it = std::remove_if(ret.begin(), ret.end(), [&circles](const RS_Circle& circle) { |
| | return !circle.testTan3(circles); |
| | }); |
| | ret.erase(it, ret.end()); |
| | |
| | |
| | return ret; |
| | } |
| |
|
| | bool RS_Circle::testTan3(const std::vector<RS_AtomicEntity*>& circles) const{ |
| | if(circles.size()!=3) { |
| | return false; |
| | } |
| | for(auto const& c: circles){ |
| | if (!c->isTangent(data)) { |
| | return false; |
| | } |
| | } |
| | return true; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | std::vector<RS_Circle> RS_Circle::solveAolloniusSingle(const std::vector<RS_Circle>& circles){ |
| | |
| | |
| | |
| | |
| |
|
| | std::vector<RS_Vector> centers; |
| | std::vector<double> radii; |
| |
|
| | for (const RS_Circle& c : circles) { |
| | if (!c.getCenter().valid) { |
| | return {}; |
| | } |
| | centers.push_back(c.getCenter()); |
| | radii.push_back(c.getRadius()); |
| | } |
| | |
| | |
| | |
| | |
| | std::vector<std::vector<double>> mat(2, std::vector<double>(3, 0.)); |
| | mat[0][0] = centers[2].x - centers[0].x; |
| | mat[0][1] = centers[2].y - centers[0].y; |
| | mat[1][0] = centers[2].x - centers[1].x; |
| | mat[1][1] = centers[2].y - centers[1].y; |
| |
|
| | |
| | |
| | LC_LOG << __func__ << "(): identicalXOrY=" << identicalXOrY(mat); |
| | if (identicalXOrY(mat) || std::abs(mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]) < RS_TOLERANCE15) { |
| | return {}; |
| | } |
| | |
| | mat[0][2] = 0.5 * (centers[2].squared() - centers[0].squared() + radii[0] * radii[0] - radii[2] * radii[2]); |
| | mat[1][2] = 0.5 * (centers[2].squared() - centers[1].squared() + radii[1] * radii[1] - radii[2] * radii[2]); |
| | |
| | |
| | |
| | |
| | |
| | std::vector<double> sm(2, 0.); |
| | if (RS_Math::linearSolver(mat, sm) == false) { |
| | return {}; |
| | } |
| |
|
| | RS_Vector vp(sm[0], sm[1]); |
| | |
| | |
| |
|
| | |
| | mat[0][2] = radii[0] - radii[2]; |
| | mat[1][2] = radii[1] - radii[2]; |
| | |
| | |
| | |
| | if (RS_Math::linearSolver(mat, sm) == false) { |
| | return {}; |
| | } |
| | RS_Vector vq(sm[0], sm[1]); |
| | |
| | |
| | RS_Vector dcp = vp - centers[0]; |
| | double a = vq.squared() - 1.; |
| | if (std::abs(a) < RS_TOLERANCE * 1e-4) { |
| | return {}; |
| | } |
| | std::vector<double> ce(0, 0.); |
| | ce.push_back(2. * (dcp.dotP(vq) - radii[0]) / a); |
| | ce.push_back((dcp.squared() - radii[0] * radii[0]) / a); |
| | std::vector<double> vr = RS_Math::quadraticSolver(ce); |
| | std::vector<RS_Circle> ret; |
| | for (double dist : vr) { |
| | if (dist >= RS_TOLERANCE) { |
| | ret.emplace_back(RS_Circle(nullptr, {vp + vq * dist, std::abs(dist)})); |
| | } |
| | } |
| | |
| | |
| |
|
| | return ret; |
| | } |
| |
|
| | std::vector<RS_Circle> RS_Circle::solveApolloniusHyperbola(const std::vector<RS_Circle>& circles){ |
| | assert(circles.size() == 3); |
| | std::vector<RS_Vector> centers; |
| | std::vector<double> radii; |
| |
|
| | for (const RS_Circle& c : circles) { |
| | if (!c.getCenter().valid) { |
| | return {}; |
| | } |
| | centers.push_back(c.getCenter()); |
| | radii.push_back(c.getRadius()); |
| | } |
| | size_t i0 = (centers[0] == centers[1] || centers[0] == centers[2]) ? 1 : 0; |
| |
|
| | std::vector<RS_Circle> ret; |
| | LC_Quadratic lc0(&(circles[i0]), &(circles[(i0 + 1) % 3])); |
| | LC_Quadratic lc1(&(circles[i0]), &(circles[(i0 + 2) % 3])); |
| | RS_VectorSolutions c0 = LC_Quadratic::getIntersection(lc0, lc1); |
| | for (size_t i = 0; i < c0.size(); i++) { |
| | const double dc = c0[i].distanceTo(centers[i0]); |
| | ret.push_back(RS_Circle(nullptr, {c0[i], std::abs(dc - radii[i0])})); |
| | if (dc > radii[i0]) { |
| | ret.push_back(RS_Circle(nullptr, {c0[i], dc + radii[i0]})); |
| | } |
| | } |
| | return ret; |
| | } |
| |
|
| | RS_VectorSolutions RS_Circle::getRefPoints() const{ |
| | RS_Vector v1(data.radius, 0.0); |
| | RS_Vector v2(0.0, data.radius); |
| | return RS_VectorSolutions ({data.center,data.center+v1, data.center+v2,data.center-v1, data.center-v2}); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | RS_Vector RS_Circle::getNearestEndpoint(const RS_Vector& coord, double* dist ) const{ |
| | return getNearestMiddle( coord, dist, 0); |
| | } |
| |
|
| | RS_Vector RS_Circle::getNearestPointOnEntity(const RS_Vector& coord, |
| | bool , double* dist, RS_Entity** entity)const { |
| |
|
| | if (entity) { |
| | *entity = const_cast<RS_Circle*>(this); |
| | } |
| | RS_Vector vp(coord - data.center); |
| | double d(vp.magnitude()); |
| | if (d < RS_TOLERANCE) { |
| | return RS_Vector(false); |
| | } |
| | vp =data.center+vp*(data.radius/d); |
| | |
| |
|
| | if(dist){ |
| | *dist=coord.distanceTo(vp); |
| | |
| | } |
| | return vp; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | RS_VectorSolutions RS_Circle::getTangentPoint(const RS_Vector& point) const { |
| | RS_VectorSolutions ret; |
| | double radius = getRadius(); |
| | double r2(radius * radius); |
| | if (r2 < RS_TOLERANCE2){ |
| | return ret; |
| | } |
| | RS_Vector vp(point - getCenter()); |
| | double c2(vp.squared()); |
| | if (c2 < r2 - radius * 2. * RS_TOLERANCE) { |
| | |
| | return ret; |
| | } |
| | if (c2 > r2 + radius * 2. * RS_TOLERANCE) { |
| | |
| | RS_Vector vp1(-vp.y, vp.x); |
| | vp1 *= radius * sqrt(c2 - r2) / c2; |
| | vp *= r2 / c2; |
| | vp += getCenter(); |
| | if (vp1.squared() > RS_TOLERANCE2) { |
| | ret.push_back(vp + vp1); |
| | ret.push_back(vp - vp1); |
| | return ret; |
| | } |
| | } |
| | ret.push_back(point); |
| | return ret; |
| | } |
| | RS_Vector RS_Circle::getTangentDirection(const RS_Vector& point) const { |
| | RS_Vector vp(point-getCenter()); |
| | |
| | |
| | |
| | |
| | |
| | return RS_Vector(-vp.y,vp.x); |
| | } |
| |
|
| | RS_Vector RS_Circle::getNearestCenter(const RS_Vector& coord,double* dist) const{ |
| | if (dist) { |
| | *dist = coord.distanceTo(data.center); |
| | } |
| | return data.center; |
| | } |
| |
|
| | RS_Vector RS_Circle::getMiddlePoint(void)const{ |
| | return RS_Vector(false); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | RS_Vector RS_Circle::getNearestMiddle(const RS_Vector& coord, |
| | double* dist , |
| | const int middlePoints ) const{ |
| | if( data.radius <= RS_TOLERANCE) { |
| | |
| | if ( nullptr != dist) { |
| | *dist = RS_MAXDOUBLE; |
| | } |
| | return RS_Vector(false); |
| | } |
| |
|
| | RS_Vector vPoint( getNearestPointOnEntity( coord, true, dist)); |
| | int iCounts = middlePoints + 1; |
| | double dAngleSteps = M_PI_2 / iCounts; |
| | double dAngleToPoint = data.center.angleTo(vPoint); |
| | int iStepCount = static_cast<int>((dAngleToPoint + 0.5 * dAngleSteps) / dAngleSteps); |
| | if( 0 < middlePoints) { |
| | |
| | int iQuadrant = static_cast<int>(dAngleToPoint / 0.5 / M_PI); |
| | int iQuadrantStep = iStepCount - iQuadrant * iCounts; |
| | if( 0 == iQuadrantStep) { |
| | ++iStepCount; |
| | } |
| | else if( iCounts == iQuadrantStep) { |
| | --iStepCount; |
| | } |
| | } |
| |
|
| | vPoint.setPolar( data.radius, dAngleSteps * iStepCount); |
| | vPoint.move( data.center); |
| |
|
| | if(dist) { |
| | *dist = vPoint.distanceTo( coord); |
| | } |
| | return vPoint; |
| | } |
| |
|
| | RS_Vector RS_Circle::getNearestDist(double ,const RS_Vector& ,double* dist) const{ |
| | if (dist) { |
| | *dist = RS_MAXDOUBLE; |
| | } |
| | return RS_Vector(false); |
| | } |
| |
|
| | RS_Vector RS_Circle::getNearestDist(double ,bool ) const{ |
| | return RS_Vector(false); |
| | } |
| |
|
| | RS_Vector RS_Circle::getNearestOrthTan(const RS_Vector& coord,const RS_Line& normal,bool ) const{ |
| | if (!coord.valid) { |
| | return RS_Vector(false); |
| | } |
| | RS_Vector vp0(coord - getCenter()); |
| | RS_Vector vp1(normal.getAngle1()); |
| | double d = RS_Vector::dotP(vp0, vp1); |
| | if (d >= 0.) { |
| | return getCenter() + vp1 * getRadius(); |
| | } |
| | else { |
| | return getCenter() - vp1 * getRadius(); |
| | } |
| | } |
| |
|
| | RS_Vector RS_Circle::dualLineTangentPoint(const RS_Vector& line) const{ |
| | RS_Vector dr = line.normalized() * data.radius; |
| | RS_Vector vp0 = data.center + dr; |
| | RS_Vector vp1 = data.center - dr; |
| | auto lineEqu = [&line](const RS_Vector& vp) { |
| | return std::abs(line.dotP(vp) + 1.); |
| | }; |
| |
|
| | return lineEqu(vp0) < lineEqu(vp1) ? vp0 : vp1; |
| | } |
| |
|
| | void RS_Circle::move(const RS_Vector& offset) { |
| | data.center.move(offset); |
| | moveBorders(offset); |
| | |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | bool RS_Circle::offset(const RS_Vector& coord, const double& distance) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | double dist(coord.distanceTo(getCenter())); |
| | double newRadius; |
| | if (dist > getRadius()) { |
| | |
| | newRadius = getRadius() + fabs(distance); |
| | } |
| | else { |
| | newRadius = getRadius() - fabs(distance); |
| | if (newRadius < RS_TOLERANCE) { |
| | return false; |
| | } |
| | } |
| | setRadius(newRadius); |
| | calculateBorders(); |
| | setRadius(newRadius); |
| | calculateBorders(); |
| | return true; |
| | } |
| |
|
| | void RS_Circle::rotate(const RS_Vector& center, double angle) { |
| | data.center.rotate(center, angle); |
| | calculateBorders(); |
| | } |
| |
|
| | void RS_Circle::rotate(const RS_Vector& center, const RS_Vector& angleVector) { |
| | data.center.rotate(center, angleVector); |
| | calculateBorders(); |
| | } |
| |
|
| | void RS_Circle::scale(const RS_Vector& center, const RS_Vector& factor) { |
| | data.center.scale(center, factor); |
| | |
| | data.radius *= std::abs(factor.x); |
| | scaleBorders(center,factor); |
| | } |
| |
|
| | double RS_Circle::getDirection1() const{ |
| | return M_PI_2; |
| | } |
| |
|
| | double RS_Circle::getDirection2() const { |
| | return M_PI_2 * 3.0; |
| | } |
| |
|
| | void RS_Circle::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) { |
| | data.center.mirror(axisPoint1, axisPoint2); |
| | calculateBorders(); |
| | } |
| | RS_Entity& RS_Circle::shear(double k){ |
| | if (!std::isnormal(k)) { |
| | assert(!"shear() should not not be called for circle"); |
| | } |
| | return *this; |
| | } |
| |
|
| | void RS_Circle::draw(RS_Painter* painter) { |
| | painter->drawEntityCircle(this); |
| | } |
| |
|
| | void RS_Circle::moveRef(const RS_Vector& ref, const RS_Vector& offset) { |
| | if (ref.distanceTo(data.center) < 1.0e-4) { |
| | data.center += offset; |
| | calculateBorders(); |
| | return; |
| | } |
| | RS_Vector v1(data.radius, 0.0); |
| | RS_VectorSolutions sol; |
| | sol.push_back(data.center + v1); |
| | sol.push_back(data.center - v1); |
| | v1.set(0., data.radius); |
| | sol.push_back(data.center + v1); |
| | sol.push_back(data.center - v1); |
| | double dist; |
| | v1 = sol.getClosest(ref, &dist); |
| | if (dist > 1.0e-4) { |
| | calculateBorders(); |
| | return; |
| | } |
| | else { |
| | data.radius = data.center.distanceTo(v1 + offset); |
| | calculateBorders(); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | LC_Quadratic RS_Circle::getQuadratic() const{ |
| | std::vector<double> ce(6, 0.); |
| | ce[0] = 1.; |
| | ce[2] = 1.; |
| | ce[5] = -data.radius * data.radius; |
| | LC_Quadratic ret(ce); |
| | ret.move(data.center); |
| | return ret; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | double RS_Circle::areaLineIntegral() const{ |
| | const double r = getRadius(); |
| | return M_PI*r*r; |
| | } |
| |
|
| | |
| | |
| | |
| | std::ostream& operator << (std::ostream& os, const RS_Circle& a) { |
| | os << " Circle: " << a.data << "\n"; |
| | return os; |
| | } |
| |
|