CircularSurveyComplexItem.cc 10.9 KB
Newer Older
1 2 3
#include "CircularSurveyComplexItem.h"


Valentin Platzgummer's avatar
Valentin Platzgummer committed
4
const char* CircularSurveyComplexItem::settingsGroup =              "CircularSurvey";
5 6
const char* CircularSurveyComplexItem::deltaRName =                 "DeltaR";
const char* CircularSurveyComplexItem::deltaAlphaName =             "DeltaAlpha";
7 8

CircularSurveyComplexItem::CircularSurveyComplexItem(Vehicle *vehicle, bool flyView, const QString &kmlOrShpFile, QObject *parent)
9
    :   TransectStyleComplexItem    (vehicle, flyView, settingsGroup, parent)
Valentin Platzgummer's avatar
Valentin Platzgummer committed
10
    ,   _referencePoint             (QGeoCoordinate(0, 0,0))
11 12 13
    ,   _metaDataMap                (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CircularSurvey.SettingsGroup.json"), this))
    ,   _deltaR                     (settingsGroup, _metaDataMap[deltaRName])
    ,   _deltaAlpha                 (settingsGroup, _metaDataMap[deltaAlphaName])
14
{
15 16
    _editorQml = "qrc:/qml/CircularSurveyItemEditor.qml";

Valentin Platzgummer's avatar
Valentin Platzgummer committed
17 18 19
    connect(&_deltaR,       &Fact::valueChanged, this, &CircularSurveyComplexItem::_setDirty);
    connect(&_deltaAlpha,   &Fact::valueChanged, this, &CircularSurveyComplexItem::_setDirty);
    connect(this,           &CircularSurveyComplexItem::refPointChanged, this, &CircularSurveyComplexItem::_setDirty);
20

Valentin Platzgummer's avatar
Valentin Platzgummer committed
21 22 23 24
    _deltaR.setRawValue(_deltaR.rawDefaultValue());
    _deltaAlpha.setRawValue(_deltaAlpha.rawDefaultValue());
    qDebug() << _deltaAlpha.rawDefaultValue().toDouble();
    qDebug() << _deltaAlpha.rawValue().toDouble();
25

26 27
    connect(&_updateTimer, &QTimer::timeout, this, &CircularSurveyComplexItem::_updateItem);
    _updateTimer.start(100);
28 29 30
}

void CircularSurveyComplexItem::setRefPoint(const QGeoCoordinate &refPt)
31
{
32 33
    if (refPt != _referencePoint){
        _referencePoint = refPt;
34

35
        emit refPointChanged();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
36
        //qDebug() << _referencePoint.toString();
37 38 39 40 41 42
    }
}

QGeoCoordinate CircularSurveyComplexItem::refPoint() const
{
    return _referencePoint;
43 44
}

45 46 47 48 49 50 51 52 53 54
Fact *CircularSurveyComplexItem::deltaR()
{
    return &_deltaR;
}

Fact *CircularSurveyComplexItem::deltaAlpha()
{
    return &_deltaAlpha;
}

55 56
bool CircularSurveyComplexItem::load(const QJsonObject &complexObject, int sequenceNumber, QString &errorString)
{
57
    return false;
58 59 60 61
}

void CircularSurveyComplexItem::save(QJsonArray &planItems)
{
62

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
}

void CircularSurveyComplexItem::appendMissionItems(QList<MissionItem *> &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()
{
92 93 94 95
    using namespace GeoUtilities;
    using namespace PolygonCalculus;
    using namespace PlanimetryCalculus;

96 97 98
    if ( _surveyAreaPolygon.count() < 3)
        return;

99
    _transects.clear();
100 101 102
    QPolygonF surveyPolygon = toQPolygonF(toCartesian2D(_surveyAreaPolygon.coordinateList(), _referencePoint));

    QVector<double> distances;
103 104
    for (const QPointF &p : surveyPolygon) distances.append(norm(p));

105 106 107 108 109 110 111 112 113
    // check if input is valid
    if (   _deltaAlpha.rawValue() > _deltaAlpha.rawMax()
           && _deltaAlpha.rawValue() < _deltaAlpha.rawMin())
        return;
    if (   _deltaR.rawValue() > _deltaR.rawMax()
           && _deltaR.rawValue() < _deltaR.rawMin())
        return;


Valentin Platzgummer's avatar
Valentin Platzgummer committed
114
    double dalpha = _deltaAlpha.rawValue().toDouble()/180.0*M_PI; // radiants
115
    double dr = _deltaR.rawValue().toDouble(); // meter
Valentin Platzgummer's avatar
Valentin Platzgummer committed
116 117
//    double dalpha = 1.0/180.0*M_PI; // radiants
//    double dr = 10.0; // meter
118 119 120 121 122
    double r_min = dr; // meter
    double r_max = (*std::max_element(distances.begin(), distances.end())); // meter

    QPointF origin(0, 0);
    IntersectType type;
123
    bool originInside = true;
124 125 126 127 128
    if (!contains(surveyPolygon, origin, type)) {
        QVector<double> angles;
        for (const QPointF &p : surveyPolygon) angles.append(truncateAngle(angle(p)));

        // determine r_min by successive approximation
129 130
        double r = r_min;
        while ( r < r_max) {
131 132
            Circle circle(r, origin);

133
            if (intersects(circle, surveyPolygon)) {
134 135 136 137
                r_min = r;
                break;
            }

138
            r += dr;
139
        }
140
        originInside = false;
141 142
    }

143 144 145
//    qWarning("r_min, r_max:");
//    qWarning() << r_min;
//    qWarning() << r_max;
146 147 148 149

    QList<QPolygonF> convexPolygons;
    decomposeToConvex(surveyPolygon, convexPolygons);

150
    QList<QList<QPointF>> fullPath;
151
    for (int i = 0; i < convexPolygons.size(); i++) {
152
        const QPolygonF &polygon = convexPolygons[i];
153
        double r = r_min;
154

155 156
        QList<QList<QPointF>> currPolyPath;
        while (r < r_max) {
157
            Circle circle(r, origin);
158 159
            QList<QPointFList> intersectPoints;
            QList<IntersectType> typeList;
160 161
            QList<QPair<int, int>> neighbourList;
            if (intersects(circle, polygon, intersectPoints, neighbourList, typeList)) {
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

                // intersection Points between circle and polygon, entering polygon
                // when walking in counterclockwise direction along circle
                QPointFList entryPoints;
                // intersection Points between circle and polygon, leaving polygon
                // when walking in counterclockwise direction along circle
                QPointFList exitPoints;
                // determine entryPoints and exit Points
                for (int j = 0; j < intersectPoints.size(); j++) {
                    QList<QPointF> intersects = intersectPoints[j];

                    QPointF p1 = polygon[neighbourList[j].first];
                    QPointF p2 = polygon[neighbourList[j].second];
                    QLineF intersetLine(p1, p2);
                    double lineAngle = truncateAngle(angle(intersetLine));

                    for (QPointF ipt : intersects) {
                        double circleTangentAngle = truncateAngle(angle(ipt)+M_PI_2);
                        // compare line angle and circle tangent at intersection point
                        // to determine between exit and entry point
                        if (   !qFuzzyCompare(lineAngle, circleTangentAngle)
                            && !qFuzzyCompare(lineAngle, truncateAngle(circleTangentAngle + M_PI))) {
                            if (truncateAngle(lineAngle - circleTangentAngle)  < M_PI) {
                                entryPoints.append(ipt);
                            } else {
                                exitPoints.append(ipt);
188 189
                            }
                        }
190 191
                    }
                }
192

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
                // sort
                std::sort(entryPoints.begin(), entryPoints.end(), [](QPointF p1, QPointF p2) {
                   return angle(p1) < angle(p2);
                });
                std::sort(exitPoints.begin(), exitPoints.end(), [](QPointF p1, QPointF p2) {
                   return angle(p1) < angle(p2);
                });

                // match entry and exit points
                int offset = 0;
                double minAngle = std::numeric_limits<double>::infinity();
                for (int k = 0; k < exitPoints.size(); k++) {
                    QPointF pt = exitPoints[k];
                    double alpha = truncateAngle(angle(pt) - angle(entryPoints[0]));
                    if (minAngle > alpha) {
                        minAngle = alpha;
                        offset = k;
                    }
                }
212

213 214 215
                for (int k = 0; k < entryPoints.size(); k++) {
                    double alpha1 = angle(entryPoints[k]);
                    double alpha2 = angle(exitPoints[(k+offset) % entryPoints.size()]);
216

217
                    QList<QPointF> sectorPath = circle.approximateSektor(double(dalpha), alpha1, alpha2);
218 219
                    // use shortestPath() here if necessary, could be a problem if dr >>
                    if (sectorPath.size() > 0)
220 221
                        currPolyPath.append(sectorPath);
                }
222 223
            } else if (originInside) {
                // circle fully inside polygon
224
                QList<QPointF> sectorPath = circle.approximateSektor(double(dalpha), 0, 2*M_PI);
225 226
                // use shortestPath() here if necessary, could be a problem if dr >>
                currPolyPath.append(sectorPath);
227 228
            }
            r += dr;
229 230 231
         }
        if (currPolyPath.size() > 0) {
            fullPath.append(currPolyPath);
232
        }
233
    }
234

Valentin Platzgummer's avatar
Valentin Platzgummer committed
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
//    // optimize path to lawn pattern
//    if (fullPath.size() == 0)
//        return;
//    QList<QPointF> currentSection = fullPath.takeFirst();
//    QList<QList<QPointF>> optiPath; // optimized path
//    while( !fullPath.empty() ) {
//        optiPath.append(currentSection);
//        QPointF endVertex = currentSection.last();
//        double minDist = std::numeric_limits<double>::infinity();
//        int index = 0;
//        bool reversePath = false;

//        // iterate over all paths in fullPath and assign the one with the shortest distance to endVertex to currentSection
//        for (int i = 0; i < fullPath.size(); i++) {
//            auto iteratorPath = fullPath[i];
//            double dist = PlanimetryCalculus::distance(endVertex, iteratorPath.first());
//            if ( dist < minDist ) {
//                minDist = dist;
//                index = i;
//            }
//            dist = PlanimetryCalculus::distance(endVertex, iteratorPath.last());
//            if (dist < minDist) {
//                minDist = dist;
//                index = i;
//                reversePath = true;
//            }
//        }
//        currentSection = fullPath.takeAt(index);
//        if (reversePath) {
//            PolygonCalculus::reversePath(currentSection);
//        }
//    }
267

268 269

    // convert to CoordInfo_t
Valentin Platzgummer's avatar
Valentin Platzgummer committed
270 271
//    for ( const QList<QPointF> &transect : optiPath) {
    for ( const QList<QPointF> &transect : fullPath) {
272 273 274 275 276 277 278 279
        QList<QGeoCoordinate> geoPath = toGeo(transect, _referencePoint);
        QList<CoordInfo_t> transectList;
        for ( const QGeoCoordinate &coordinate : geoPath) {
            CoordInfo_t coordinfo = {coordinate, CoordTypeInterior};
            transectList.append(coordinfo);
        }
        _transects.append(transectList);
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
280

281 282 283 284 285 286 287 288 289 290 291 292
}

void CircularSurveyComplexItem::_recalcComplexDistance()
{

}

void CircularSurveyComplexItem::_recalcCameraShots()
{

}

293 294 295 296
void CircularSurveyComplexItem::_updateItem()
{
    if (_dirty) {
        _rebuildTransects();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
297
        qDebug() << "CircularSurveyComplexItem::_updateItem()";
298 299 300 301 302
        setDirty(false);
    }

}

303 304 305 306 307 308 309 310 311 312 313
/*!
    \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
*/