snake.cpp 10.3 KB
Newer Older
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1 2
#include <iostream>

3 4
#include "snake.h"

Valentin Platzgummer's avatar
Valentin Platzgummer committed
5 6
#include "clipper.hpp"

Valentin Platzgummer's avatar
Valentin Platzgummer committed
7 8 9 10 11
using namespace snake_geometry;
using namespace std;

namespace bg = boost::geometry;
namespace trans = bg::strategy::transform;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
12

13 14
namespace snake {

Valentin Platzgummer's avatar
Valentin Platzgummer committed
15
Scenario::Scenario() :
Valentin Platzgummer's avatar
Valentin Platzgummer committed
16
    _mAreaBoundingBox(min_bbox_rt{0, 0, 0, BoostPolygon{}})
Valentin Platzgummer's avatar
Valentin Platzgummer committed
17 18 19 20
{

}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
21
bool Scenario::addArea(Area &area)
22 23
    {
        if (area.geoPolygon.size() < 3){
Valentin Platzgummer's avatar
Valentin Platzgummer committed
24
            errorString = "Area has less than three vertices.";
25 26 27 28 29 30 31 32 33
            return false;
        }
        if (area.type == MeasurementArea)
            return Scenario::_setMeasurementArea(area);
        else if (area.type == ServiceArea)
            return Scenario::_setServiceArea(area);
        else if (area.type == Corridor)
            return Scenario::_setCorridor(area);
        return false;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
34
}
35

Valentin Platzgummer's avatar
Valentin Platzgummer committed
36 37 38 39 40 41 42 43 44 45
bool Scenario::defined(double tileWidth, double tileHeight, double minTileArea)
{
    if (!_areas2enu())
        return false;
    if (!_calculateBoundingBox())
        return false;
    if (!_calculateTiles(tileWidth, tileHeight, minTileArea))
        return false;
    if (!_calculateJoinedArea())
        return false;
46

Valentin Platzgummer's avatar
Valentin Platzgummer committed
47 48
    return true;
}
49

Valentin Platzgummer's avatar
Valentin Platzgummer committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
bool Scenario::_areas2enu()
{
    if (_measurementArea.geoPolygon.size() > 0){
        _measurementAreaENU.clear();
        for(auto vertex : _measurementArea.geoPolygon) {
                Point3D ENUVertex;
                toENU(_geoOrigin, Point3D{vertex[0], vertex[1], _measurementArea.altitude}, ENUVertex);
                _measurementAreaENU.outer().push_back(BoostPoint{ENUVertex[0], ENUVertex[1]});
        }
        bg::correct(_measurementAreaENU);

        _serviceAreaENU.clear();
        if (_serviceArea.geoPolygon.size() > 0){
            for(auto vertex : _serviceArea.geoPolygon) {
                    Point3D ENUVertex;
                    toENU(_geoOrigin, Point3D{vertex[0], vertex[1], _serviceArea.altitude}, ENUVertex);
                    _serviceAreaENU.outer().push_back(BoostPoint{ENUVertex[0], ENUVertex[1]});
67
            }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
68 69 70 71 72 73
        } else{
            errorString = "Service area has no vertices.";
            return false;
        }
        bg::correct(_serviceAreaENU);
        polygonCenter(_serviceAreaENU, _homePositionENU);
74

Valentin Platzgummer's avatar
Valentin Platzgummer committed
75 76 77 78 79 80 81
        _corridorENU.clear();
        if (_corridor.geoPolygon.size() > 0){
            for(auto vertex : _corridor.geoPolygon) {
                    Point3D ENUVertex;
                    toENU(_geoOrigin, Point3D{vertex[0], vertex[1], _corridor.altitude}, ENUVertex);
                    _corridorENU.outer().push_back(BoostPoint{ENUVertex[0], ENUVertex[1]});
            }
82
        }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
83
        bg::correct(_corridorENU);
84

Valentin Platzgummer's avatar
Valentin Platzgummer committed
85
        return true;
86 87
    }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
88 89 90
    errorString = "Measurement area has no vertices.";
    return false;
}
91

Valentin Platzgummer's avatar
Valentin Platzgummer committed
92 93 94 95 96 97 98 99 100 101 102
bool Scenario::_setMeasurementArea(Area &area)
{
    if (area.geoPolygon.size() <= 0)
        return false;
    GeoPoint2D origin2D = area.geoPolygon[0];
    _geoOrigin = GeoPoint3D{origin2D[0], origin2D[1], 0};
    _measurementArea = area;
    _measurementAreaENU.clear();
    _serviceAreaENU.clear();
    _corridorENU.clear();
    return true;
103

Valentin Platzgummer's avatar
Valentin Platzgummer committed
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
}

bool Scenario::_setServiceArea(Area &area)
{
    if (area.geoPolygon.size() <= 0)
        return false;
    _serviceArea = area;
    _serviceAreaENU.clear();
    return true;
}

bool Scenario::_setCorridor(Area &area)
{
    if (area.geoPolygon.size() <= 0)
        return false;
    _corridor = area;
    _corridorENU.clear();
    return true;
}

bool Scenario::_calculateBoundingBox()
{
    minimalBoundingBox(_measurementAreaENU, _mAreaBoundingBox);
    return true;
}
/**
 * Devides the (measurement area) bounding  box into tiles and clips it to the measurement area.
 *
 * Devides the (measurement area) bounding  box into tiles of width \p tileWidth and height \p tileHeight.
 * Clips the resulting tiles to the measurement area. Tiles are rejected, if their area is smaller than \p minTileArea.
 * The function assumes that \a _measurementAreaENU and \a _mAreaBoundingBox have correct values. \see \ref Scenario::_areas2enu() and \ref
 * Scenario::_calculateBoundingBox().
 *
 * @param tileWidth The width (>0) of a tile.
 * @param tileHeight The heigth (>0) of a tile.
 * @param minTileArea The minimal area (>0) of a tile.
 *
 * @return Returns true if successful.
 */
bool Scenario::_calculateTiles(double tileWidth, double tileHeight, double minTileArea)
{
    _tilesENU.clear();
    _tileCenterPointsENU.clear();

    if (tileWidth <= 0 || tileHeight <= 0 || minTileArea <= 0) {
        errorString = "Parameters tileWidth, tileHeight, minTileArea must be positive.";
        return false;
151 152
    }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
    double bbox_width = _mAreaBoundingBox.width;
    double bbox_height = _mAreaBoundingBox.height;

    BoostPoint origin = _mAreaBoundingBox.corners.outer()[0];

    //cout << "Origin: " << origin[0] << " " << origin[1] << endl;
    // Transform _measurementAreaENU polygon to bounding box coordinate system.
    trans::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate(_mAreaBoundingBox.angle*180/M_PI);
    trans::translate_transformer<double, 2, 2> translate(-origin.get<0>(), -origin.get<1>());
    BoostPolygon translated_polygon;
    BoostPolygon rotated_polygon;
    boost::geometry::transform(_measurementAreaENU, translated_polygon, translate);
    boost::geometry::transform(translated_polygon, rotated_polygon, rotate);
    bg::correct(rotated_polygon);

    //cout << bg::wkt<BoostPolygon2D>(rotated_polygon) << endl;

    size_t i_max = ceil(bbox_width/tileWidth);
    size_t j_max = ceil(bbox_height/tileHeight);

    if (i_max < 1 || j_max < 1) {
        errorString = "tileWidth or tileHeight to small.";
        return false;
176 177
    }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216

    trans::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate_back(-_mAreaBoundingBox.angle*180/M_PI);
    trans::translate_transformer<double, 2, 2> translate_back(origin.get<0>(), origin.get<1>());
    for (size_t i = 0; i < i_max; ++i){
        double x_min = tileWidth*i;
        double x_max = x_min + tileWidth;
        for (size_t j = 0; j < j_max; ++j){
            double y_min = tileHeight*j;
            double y_max = y_min + tileHeight;

            BoostPolygon tile_unclipped;
            tile_unclipped.outer().push_back(BoostPoint{x_min, y_min});
            tile_unclipped.outer().push_back(BoostPoint{x_min, y_max});
            tile_unclipped.outer().push_back(BoostPoint{x_max, y_max});
            tile_unclipped.outer().push_back(BoostPoint{x_max, y_min});
            tile_unclipped.outer().push_back(BoostPoint{x_min, y_min});


            std::deque<BoostPolygon> boost_tiles;
            if (!boost::geometry::intersection(tile_unclipped, rotated_polygon, boost_tiles))
                continue;

           for (BoostPolygon t : boost_tiles)
           {
                if (bg::area(t) > minTileArea){
                    // Transform boost_tile to world coordinate system.
                    BoostPolygon rotated_tile;
                    BoostPolygon translated_tile;
                    boost::geometry::transform(t, rotated_tile, rotate_back);
                    boost::geometry::transform(rotated_tile, translated_tile, translate_back);

                    // Store tile and calculate center point.
                    _tilesENU.push_back(translated_tile);
                    BoostPoint tile_center;
                    polygonCenter(translated_tile, tile_center);
                    _tileCenterPointsENU.push_back(tile_center);
                }
           }
        }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
217 218
    }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
219 220 221
    if (_tilesENU.size() < 1){
        errorString = "No tiles calculated. Is the minTileArea parameter large enough?";
        return false;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
222 223
    }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
224 225
    return true;
}
Valentin Platzgummer's avatar
Valentin Platzgummer committed
226

Valentin Platzgummer's avatar
Valentin Platzgummer committed
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
bool Scenario::_calculateJoinedArea()
{
    _joinedAreaENU.clear();
    // Measurement area and service area overlapping?
    bool overlapingSerMeas = bg::intersects(_measurementAreaENU, _serviceAreaENU) ? true : false;
    bool corridorValid = _corridorENU.outer().size() > 0 ? true : false;


    // Check if corridor is connecting measurement area and service area.
    bool corridor_is_connection = false;
    if (corridorValid) {
        // Corridor overlaping with measurement area?
        if ( bg::intersects(_corridorENU, _measurementAreaENU) ) {
            // Corridor overlaping with service area?
            if ( bg::intersects(_corridorENU, _serviceAreaENU) )
                corridor_is_connection = true;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
243
        }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
244
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
245

Valentin Platzgummer's avatar
Valentin Platzgummer committed
246 247 248 249 250 251
    // Are areas joinable?
    std::deque<BoostPolygon> sol;
    BoostPolygon partialArea = _measurementAreaENU;
    if (overlapingSerMeas){
        if(corridor_is_connection){
            bg::union_(partialArea, _corridorENU, sol);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
252
        }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
253 254 255 256 257 258
    } else if (corridor_is_connection){
        bg::union_(partialArea, _corridorENU, sol);
    } else {
        errorString = "Areas are not overlapping";
        return false;
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
259

Valentin Platzgummer's avatar
Valentin Platzgummer committed
260 261 262 263
    if (sol.size() > 0) {
        partialArea = sol[0];
        sol.clear();
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
264

Valentin Platzgummer's avatar
Valentin Platzgummer committed
265 266
    // Join areas.
    bg::union_(partialArea, _serviceAreaENU, sol);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
267

Valentin Platzgummer's avatar
Valentin Platzgummer committed
268 269 270 271 272
    if (sol.size() > 0) {
        _joinedAreaENU = sol[0];
    } else {
        return false;
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
273

Valentin Platzgummer's avatar
Valentin Platzgummer committed
274 275
    return true;
}
Valentin Platzgummer's avatar
Valentin Platzgummer committed
276

Valentin Platzgummer's avatar
Valentin Platzgummer committed
277 278 279 280 281 282
bool FlightPlan::_generateTransects(double lineDistance, double minTransectLength)
{
    if (_scenario.getTilesENU().size() != _progress.size()){
        errorString = "Number of tiles is not equal progress array length";
        return false;
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
283

Valentin Platzgummer's avatar
Valentin Platzgummer committed
284 285 286 287 288 289 290
    size_t num_tiles = _progress.size();
    vector<BoostPolygon> processedTiles;
    const auto &tiles = _scenario.getTilesENU();
    for (size_t i=0; i<num_tiles; ++i) {
        if (_progress[i] == 100)
            processedTiles.push_back(tiles[i]);
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
291 292


Valentin Platzgummer's avatar
Valentin Platzgummer committed
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
    _transects.clear();
    const min_bbox_rt &bbox     = _scenario.getMeasurementAreaBBoxENU();
    double alpha                = bbox.angle;
    double x0                   = bbox.corners.outer()[0].get<0>();
    double y0                   = bbox.corners.outer()[0].get<1>();
    double bboxWidth            = bbox.width;
    double bboxHeight           = bbox.height;
    double delta                = detail::polygonOffset;

    size_t num_t = int(ceil((bboxHeight + 2*delta)/lineDistance)); // number of transects
    vector<double> yCoords;
    yCoords.reserve(num_t);
    double y = -delta;
    for (size_t i=0; i < num_t; ++i) {
        yCoords.push_back(y);
        y += lineDistance;
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
310

Valentin Platzgummer's avatar
Valentin Platzgummer committed
311 312 313 314
    for (size_t i=0; i < num_t; ++i) {
        BoostPoint v1{-delta, yCoords[i]};
        BoostPoint v2{bboxWidth+delta, yCoords[i]};
        _transects.push_back(tuple<BoostPoint, BoostPoint>{v1, v2});
Valentin Platzgummer's avatar
Valentin Platzgummer committed
315 316
    }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
317 318 319

}

320
}