#include "CircularSurveyComplexItem.h" const char* CircularSurveyComplexItem::settingsGroup = "Survey"; CircularSurveyComplexItem::CircularSurveyComplexItem(Vehicle *vehicle, bool flyView, const QString &kmlOrShpFile, QObject *parent) : TransectStyleComplexItem (vehicle, flyView, settingsGroup, parent) , _referencePoint(QGeoCoordinate(47.770859, 16.531076,0)) { } void CircularSurveyComplexItem::setRefPoint(const QGeoCoordinate &refPt) { if (refPt != _referencePoint){ _referencePoint = refPt; emit refPointChanged(); } } QGeoCoordinate CircularSurveyComplexItem::refPoint() const { return _referencePoint; } bool CircularSurveyComplexItem::load(const QJsonObject &complexObject, int sequenceNumber, QString &errorString) { return false; } void CircularSurveyComplexItem::save(QJsonArray &planItems) { } void CircularSurveyComplexItem::appendMissionItems(QList &items, QObject *missionItemParent) { } void CircularSurveyComplexItem::applyNewAltitude(double newAltitude) { } double CircularSurveyComplexItem::timeBetweenShots() { return 1; } bool CircularSurveyComplexItem::readyForSave() const { return false; } double CircularSurveyComplexItem::additionalTimeDelay() const { return 0; } void CircularSurveyComplexItem::_rebuildTransectsPhase1() { using namespace GeoUtilities; using namespace PolygonCalculus; using namespace PlanimetryCalculus; if ( _surveyAreaPolygon.count() < 3) return; _transects.clear(); QPolygonF surveyPolygon = toQPolygonF(toCartesian2D(_surveyAreaPolygon.coordinateList(), _referencePoint)); QVector distances; for (const QPointF &p : surveyPolygon) distances.append(norm(p)); double dalpha = 0.5/180*M_PI; // radiants double dr = 30; // meter double r_min = dr; // meter double r_max = (*std::max_element(distances.begin(), distances.end())); // meter QPointF origin(0, 0); IntersectType type; if (!contains(surveyPolygon, origin, type)) { QVector angles; for (const QPointF &p : surveyPolygon) angles.append(truncateAngle(angle(p))); // determine r_min by successive approximation double r = r_max; while ( r > r_min) { Circle circle(r, origin); if (!intersects(circle, surveyPolygon)) { r_min = r; break; } r -= dr; } } // qWarning("r_min, r_max:"); // qWarning() << r_min; // qWarning() << r_max; QList convexPolygons; decomposeToConvex(surveyPolygon, convexPolygons); QList> fullPath; for (int i = 0; i < convexPolygons.size(); i++){ const QPolygonF &polygon = convexPolygons[i]; double r = r_min; QList> currPolyPath; bool currentPolyPathUpdated = false; while (r < r_max) { Circle circle(r, origin); QList intersectPoints; QList typeList; QList> neighbourList; if (intersects(circle, polygon, intersectPoints, neighbourList, typeList)) { if (intersectPoints.size() >= 1) { for (int i = 0; i < intersectPoints.size(); i++) { QList intersects = intersectPoints[i]; QPointF p1 = polygon[neighbourList[i].first]; QPointF p2 = polygon[neighbourList[i].second]; QLineF intersetLine(p1, p2); double lineAngle = truncateAngle(angle(intersetLine)); double alpha1 = 0; bool skip = true; QPointF vertex; for (QPointF ipt : intersects) { double circleTangentAngle = truncateAngle(angle(ipt)+M_PI_2); if (lineAngle > circleTangentAngle && lineAngle < circleTangentAngle + M_PI) { alpha1 = truncateAngle(circleTangentAngle-M_PI_2); vertex = ipt; skip = false; } } QList sectorPath; // walk clockwisely along the circle, and break when leaving the polygon if (!skip) { double alpha = alpha1; do { sectorPath.append(vertex); alpha += dalpha; circle.toCoordinate(vertex, alpha); } while (polygon.containsPoint(vertex, Qt::FillRule::OddEvenFill)); } // use shortestPath() here if necessary, could be a problem if dr >> currPolyPath.append(sectorPath); currentPolyPathUpdated = true; } } } r += dr; } if (currentPolyPathUpdated) { if (fullPath.size() > 1) { QPointF start = fullPath.last().last(); QPointF end = currPolyPath.last().first(); QList path; if(!shortestPath(surveyPolygon, start, end, path)) return; path.removeFirst(); path.removeLast(); currPolyPath.last().append(path); } fullPath.append(currPolyPath); } } for ( const QList &transect : fullPath) { QList geoPath = toGeo(transect, _referencePoint); QList transectList; for ( const QGeoCoordinate &coordinate : geoPath) { CoordInfo_t coordinfo = {coordinate, CoordTypeInterior}; transectList.append(coordinfo); } _transects.append(transectList); } } void CircularSurveyComplexItem::_recalcComplexDistance() { } void CircularSurveyComplexItem::_recalcCameraShots() { } /*! \class CircularSurveyComplexItem \inmodule Wima \brief The \c CircularSurveyComplexItem class provides a survey mission item with circular transects around a point of interest. CircularSurveyComplexItem class provides a survey mission item with circular transects around a point of interest. Within the \c Wima module it's used to scan a defined area with constant angle (circular transects) to the base station (point of interest). \sa WimaArea */