| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include "lc_division.h" |
| |
|
| | #include <QVector> |
| | #include <cfloat> |
| |
|
| | #include "rs_entitycontainer.h" |
| | #include "lc_containertraverser.h" |
| | #include "lc_linemath.h" |
| | #include "rs_arc.h" |
| | #include "rs_circle.h" |
| | #include "rs_information.h" |
| | #include "rs_line.h" |
| | #include "rs_math.h" |
| | #include "rs_vector.h" |
| |
|
| | class RS_EntityContainer; |
| |
|
| | LC_Division::LC_Division(RS_EntityContainer *entityContainer): |
| | m_container{entityContainer} { |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | LC_Division::ArcSegmentData *LC_Division::findArcSegmentBetweenIntersections(RS_Arc *arc, RS_Vector &snap, bool allowEntireArcAsSegment){ |
| | ArcSegmentData *result = nullptr; |
| | |
| | QVector<RS_Vector> allIntersections = collectAllIntersectionsWithEntity(arc); |
| | if (allIntersections.empty()) { |
| | if (allowEntireArcAsSegment){ |
| | result = new ArcSegmentData(); |
| | result->segmentDisposition = SEGMENT_INSIDE; |
| | result->snapSegmentStartAngle = arc->getAngle1(); |
| | result->snapSegmentEndAngle = arc->getAngle2(); |
| | } |
| | } |
| | else{ |
| | |
| | result = findArcSegmentEdges(arc, snap, allIntersections, allowEntireArcAsSegment); |
| | } |
| | return result; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | LC_Division::CircleSegmentData *LC_Division::findCircleSegmentBetweenIntersections(RS_Circle *circle, RS_Vector &snap, bool allowEntireCircleAsSegment){ |
| | CircleSegmentData *result = nullptr; |
| | |
| | QVector<RS_Vector> allIntersections = collectAllIntersectionsWithEntity(circle); |
| | if (allIntersections.empty()) { |
| | if (allowEntireCircleAsSegment) { |
| | result = new CircleSegmentData(); |
| | result->snapSegmentStartAngle = 0; |
| | result->snapSegmentEndAngle = M_PI * 2; |
| | } |
| | } |
| | else{ |
| | |
| | result = findCircleSegmentEdges(circle, snap, allIntersections); |
| | } |
| | return result; |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | LC_Division::LineSegmentData *LC_Division::findLineSegmentBetweenIntersections(RS_Line *line, RS_Vector &snap, bool allowEntireLine){ |
| | LineSegmentData *result = nullptr; |
| | |
| | QVector<RS_Vector> allIntersections = collectAllIntersectionsWithEntity(line); |
| | if (allIntersections.empty()) { |
| | if (allowEntireLine){ |
| | result = new LineSegmentData(); |
| | result->segmentDisposition = SEGMENT_INSIDE; |
| | result->snapSegmentStart = line->getStartpoint(); |
| | result->snapSegmentEnd = line->getEndpoint(); |
| | result->snap = snap; |
| | } |
| | } |
| | else{ |
| | |
| | result = findLineSegmentEdges(line, snap, allIntersections, allowEntireLine); |
| | } |
| | return result; |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | LC_Division::LineSegmentData *LC_Division::findLineSegmentEdges(RS_Line *line, RS_Vector &snap, QVector<RS_Vector> intersections, |
| | bool allowEntireLineAsSegment){ |
| | double angle = line->getAngle1(); |
| | RS_Vector lineStartPoint = line->getStartpoint(); |
| | RS_Vector lineEndPoint = line->getEndpoint(); |
| |
|
| | |
| |
|
| | int intersectionsCount = intersections.size(); |
| | for (int i = 0; i < intersectionsCount; i++) { |
| | RS_Vector v = intersections.at(i); |
| | if (LC_LineMath::isNotMeaningfulDistance(v, lineStartPoint) || |
| | LC_LineMath::isNotMeaningfulDistance(v,lineEndPoint)) { |
| | |
| | |
| | intersections.replace(i, RS_Vector(false)); |
| | } |
| | else { |
| | |
| | v.rotate(lineStartPoint, -angle); |
| | intersections.replace(i, v); |
| | } |
| | } |
| |
|
| | |
| | double maxXLeft = -DBL_MAX; |
| | double minXRight = DBL_MAX; |
| |
|
| | |
| | RS_Vector nearestLeft(false); |
| | RS_Vector nearestRight(false); |
| |
|
| | |
| | RS_Vector rotatedSnap = snap; |
| | rotatedSnap.rotate(lineStartPoint, -angle); |
| |
|
| | RS_Vector rotatedEndPoint = lineEndPoint; |
| | rotatedEndPoint.rotate(lineStartPoint, -angle); |
| |
|
| | double snapX = rotatedSnap.x; |
| |
|
| | |
| | bool hasNonEdgesIntersection = false; |
| |
|
| | |
| | for (int i = 0; i < intersectionsCount; i++) { |
| | RS_Vector v = intersections.at(i); |
| | if (v.valid){ |
| | |
| | hasNonEdgesIntersection = true; |
| | } |
| | else{ |
| | |
| | continue; |
| | } |
| | |
| | double vX = v.x; |
| | if (vX <= snapX){ |
| | if (vX >= maxXLeft){ |
| | |
| | maxXLeft = vX; |
| | nearestLeft = v; |
| | } |
| | } else { |
| | if (vX < minXRight){ |
| | |
| | minXRight = vX; |
| | nearestRight = v; |
| | } |
| | } |
| | } |
| |
|
| | LineSegmentData* result = nullptr; |
| | if (hasNonEdgesIntersection){ |
| | |
| | bool startOnLeft = rotatedEndPoint.x > lineStartPoint.x; |
| |
|
| | result = new LineSegmentData(); |
| | result->segmentDisposition = SEGMENT_INSIDE; |
| |
|
| | if (nearestLeft.valid){ |
| | |
| | |
| | nearestLeft.rotate(lineStartPoint, angle); |
| | |
| | if (startOnLeft){ |
| | result->snapSegmentStart = nearestLeft; |
| | } else { |
| | result->snapSegmentEnd = nearestLeft; |
| | } |
| | } else { |
| | |
| | if (startOnLeft){ |
| | |
| | result->segmentDisposition = SEGMENT_TO_START; |
| | result->snapSegmentStart = lineStartPoint; |
| | } else { |
| | |
| | result->segmentDisposition = SEGMENT_TO_END; |
| | result->snapSegmentEnd = lineEndPoint; |
| | } |
| | } |
| |
|
| | if (nearestRight.valid){ |
| | |
| | |
| | nearestRight.rotate(lineStartPoint, angle); |
| | |
| | if (startOnLeft){ |
| | result->snapSegmentEnd = nearestRight; |
| | } else { |
| | result->snapSegmentStart = nearestRight; |
| | } |
| | } else { |
| | |
| | if (startOnLeft){ |
| | |
| | result->segmentDisposition = SEGMENT_TO_END; |
| | result->snapSegmentEnd = lineEndPoint; |
| | } else { |
| | |
| | result->segmentDisposition = SEGMENT_TO_START; |
| | result->snapSegmentStart = lineStartPoint; |
| | } |
| | } |
| | } |
| | else{ |
| | if (allowEntireLineAsSegment){ |
| | result = new LineSegmentData(); |
| | result->segmentDisposition = SEGMENT_INSIDE; |
| | result->snapSegmentStart = line->getStartpoint(); |
| | result->snapSegmentEnd = line->getEndpoint(); |
| | } |
| | } |
| | return result; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | LC_Division::ArcSegmentData *LC_Division::findArcSegmentEdges(RS_Arc *arc, RS_Vector &snap, const QVector<RS_Vector>& intersections, bool allowEntireArcAsSegment){ |
| |
|
| | double arcStartAngle = arc->getAngle1(); |
| | double arcEndAngle = arc->getAngle2(); |
| | double radius = arc->getRadius(); |
| | bool reversed = arc->isReversed(); |
| |
|
| | if (reversed){ |
| | |
| | arcStartAngle = arcEndAngle; |
| | arcEndAngle = arc->getAngle1(); |
| | } |
| | const RS_Vector ¢er = arc->getCenter(); |
| | double snapAngle = center.angleTo(snap); |
| |
|
| | |
| | double nearestLeft = -M_PI; |
| | double nearestRight = 3 * M_PI; |
| |
|
| | int intersectionsCount = intersections.size(); |
| |
|
| | |
| | double correctedSnapAngle = RS_Math::correctAngle(snapAngle - arcStartAngle); |
| | double correctedEndAngle = RS_Math::correctAngle(arcEndAngle - arcStartAngle); |
| |
|
| | double minLeft = 0; |
| | double maxRight = 2 * M_PI; |
| |
|
| | |
| | RS_Vector arcStartPoint = LC_LineMath::findPointOnCircle(radius, arcStartAngle, center); |
| | RS_Vector arcEndPoint = LC_LineMath::findPointOnCircle(radius, arcEndAngle, center); |
| |
|
| | bool hasNonEdgeIntersections = false; |
| |
|
| | for (int i = 0; i < intersectionsCount; i++) { |
| | RS_Vector v = intersections.at(i); |
| | if (LC_LineMath::isNotMeaningfulDistance(v, arcStartPoint) || |
| | LC_LineMath::isNotMeaningfulDistance(v,arcEndPoint)) { |
| | |
| | continue; |
| | } |
| | else{ |
| | hasNonEdgeIntersections = true; |
| | } |
| |
|
| | double angleToIntersection = center.angleTo(v); |
| |
|
| | |
| | double vA = RS_Math::correctAngle(angleToIntersection - arcStartAngle); |
| |
|
| | if (vA <= correctedSnapAngle){ |
| | if (vA >= minLeft){ |
| | nearestLeft = angleToIntersection; |
| | minLeft = vA; |
| | } |
| | } else if (vA < correctedEndAngle){ |
| | if (vA < maxRight){ |
| | nearestRight = angleToIntersection; |
| | maxRight = vA; |
| | } |
| | } |
| | } |
| |
|
| | ArcSegmentData *result = nullptr; |
| | if (hasNonEdgeIntersections){ |
| | result = new ArcSegmentData(); |
| | result->segmentDisposition = SEGMENT_INSIDE; |
| |
|
| |
|
| | if (nearestLeft != -M_PI){ |
| | |
| | result->snapSegmentStartAngle = nearestLeft; |
| | } else { |
| | |
| | if (reversed){ |
| | result->segmentDisposition = SEGMENT_TO_END; |
| | } |
| | else { |
| | result->segmentDisposition = SEGMENT_TO_START; |
| | } |
| | result->snapSegmentStartAngle = arcStartAngle; |
| | } |
| |
|
| | if (nearestRight != 3 * M_PI){ |
| | |
| | result->snapSegmentEndAngle = nearestRight; |
| |
|
| | } else { |
| | |
| | if (reversed){ |
| | result->segmentDisposition = SEGMENT_TO_START; |
| | } else { |
| | result->segmentDisposition = SEGMENT_TO_END; |
| | } |
| | result->snapSegmentEndAngle = arcEndAngle; |
| | } |
| |
|
| | if (reversed){ |
| | std::swap(result->snapSegmentEndAngle, result->snapSegmentStartAngle); |
| | } |
| | } |
| | else { |
| | if (allowEntireArcAsSegment){ |
| | result = new ArcSegmentData(); |
| | result->segmentDisposition = SEGMENT_INSIDE; |
| | result->snapSegmentStartAngle = arcStartAngle; |
| | result->snapSegmentEndAngle = arcEndAngle; |
| | } |
| | } |
| | return result; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | LC_Division::CircleSegmentData* LC_Division::findCircleSegmentEdges(RS_Circle *circle, RS_Vector &snap, |
| | const QVector<RS_Vector> &intersections){ |
| |
|
| | CircleSegmentData *result = nullptr; |
| | int intersectionsCount = intersections.size(); |
| |
|
| | |
| | |
| | |
| | |
| | if (intersectionsCount >= 2){ |
| | const RS_Vector ¢er = circle->getCenter(); |
| | double snapAngle = center.angleTo(snap); |
| | double leftAngle = 0; |
| | double rightAngle = 0; |
| | double maxRight = M_PI*3; |
| | double minLeft = -M_PI*3; |
| |
|
| | |
| | |
| | |
| | for (int i = 0; i < intersectionsCount; i++) { |
| | RS_Vector v = intersections.at(i); |
| |
|
| | |
| |
|
| | double angleToIntersection = center.angleTo(v); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | double vA = RS_Math::correctAnglePlusMinusPi(angleToIntersection - snapAngle); |
| |
|
| | bool left = vA < 0; |
| |
|
| | if (left){ |
| | if (vA > minLeft){ |
| | minLeft = vA; |
| | leftAngle = angleToIntersection; |
| | } |
| | } else { |
| | if (vA < maxRight){ |
| | maxRight = vA; |
| | rightAngle = angleToIntersection; |
| | } |
| | } |
| | } |
| |
|
| |
|
| | if (maxRight == M_PI*3){ |
| | |
| | |
| | |
| | maxRight = -M_PI*3; |
| | for (int i = 0; i < intersectionsCount; i++) { |
| | RS_Vector v = intersections.at(i); |
| | double angleToIntersection = center.angleTo(v); |
| | if (angleToIntersection == leftAngle){ |
| | continue; |
| | } |
| | double vA = RS_Math::correctAnglePlusMinusPi(angleToIntersection - snapAngle); |
| |
|
| | if (vA > maxRight){ |
| | maxRight = vA; |
| | rightAngle = angleToIntersection; |
| | } |
| |
|
| | } |
| | } |
| |
|
| | if (minLeft == -M_PI*3){ |
| | |
| | |
| | |
| | minLeft = M_PI*3; |
| | for (int i = 0; i < intersectionsCount; i++) { |
| | RS_Vector v = intersections.at(i); |
| | double angleToIntersection = center.angleTo(v); |
| | if (angleToIntersection == rightAngle){ |
| | continue; |
| | } |
| | double vA = RS_Math::correctAnglePlusMinusPi(angleToIntersection - snapAngle); |
| |
|
| | if (vA < minLeft){ |
| | minLeft = vA; |
| | leftAngle = angleToIntersection; |
| | } |
| | } |
| | } |
| |
|
| | result = new CircleSegmentData(); |
| |
|
| | result->snapSegmentStartAngle = leftAngle; |
| | result->snapSegmentEndAngle = rightAngle; |
| | } |
| | return result; |
| | } |
| |
|
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | QVector<RS_Vector> LC_Division::collectAllIntersectionsWithEntity(RS_Entity *entity){ |
| | QVector<RS_Vector> result; |
| | RS_VectorSolutions sol; |
| | |
| | for (auto* e: *m_container) { |
| | |
| | if (e != nullptr && e->isVisible()){ |
| | |
| | if (e->isContainer()){ |
| | |
| | auto *ec = static_cast<RS_EntityContainer*>(e); |
| |
|
| | for(RS_Entity* e2: lc::LC_ContainerTraverser{*ec, RS2::ResolveAll}.entities()) { |
| | sol = RS_Information::getIntersection(entity, e2, true); |
| | addPointsFromSolutionToList(sol, result); |
| | } |
| | } else { |
| | |
| | sol = RS_Information::getIntersection(entity, e, true); |
| | |
| | addPointsFromSolutionToList(sol, result); |
| | } |
| | } |
| | } |
| | return result; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | void LC_Division::addPointsFromSolutionToList(RS_VectorSolutions &sol, QVector<RS_Vector> &result) const{ |
| | if (sol.hasValid()){ |
| | size_t size = sol.size(); |
| | for (size_t i = 0; i < size; i++) { |
| | const RS_Vector point = sol.at(i); |
| | if (point.valid){ |
| | result.append(point); |
| | } |
| | } |
| | } |
| | } |
| |
|