Skip to content
WimaArea.cc 12.8 KiB
Newer Older
 * \variable WimaArea::epsilonMeter
 * \brief The accuracy used for distance calculations (unit: m).
/*!
 * \variable WimaArea::maxAltitudeName
 * \brief A string containing the name of the \c _maxAltitude member. Among other used for storing.
 */
const char* WimaArea::maxAltitudeName       = "maxAltitude";
/*!
 * \variable WimaArea::wimaAreaName
 * \brief A string containing the name of this \c WimaArea member. Among other used for storing.
 */
const char* WimaArea::wimaAreaName          = "WimaArea";
/*!
 * \variable WimaArea::areaTypeName
 * \brief A string containing \c {"AreaType"}. Among other used for stroing.
 */
const char* WimaArea::areaTypeName          = "AreaType";

WimaArea::WimaArea(QObject *parent)
    :  QGCMapPolygon (parent)
Valentin Platzgummer's avatar
Valentin Platzgummer committed
{
Valentin Platzgummer's avatar
Valentin Platzgummer committed
    _maxAltitude = 30;
}
Valentin Platzgummer's avatar
Valentin Platzgummer committed
WimaArea::WimaArea(const WimaArea &other, QObject *parent)
Valentin Platzgummer's avatar
Valentin Platzgummer committed
{
    *this = other;
}

/*!
 *\fn WimaArea &WimaArea::operator=(const WimaArea &other)
 *
 * Assigns \a other to this \c WimaArea and returns a reference to this \c WimaArea.
 *
 * Copies only path and maximum altitude.
 */
WimaArea &WimaArea::operator=(const WimaArea &other)
{
    QGCMapPolygon::operator=(other);
    this->_maxAltitude = other.maxAltitude();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
    this->setPath(other.path());
Valentin Platzgummer's avatar
Valentin Platzgummer committed
}
/*!
  \fn void WimaArea::setMaxAltitude(double altitude)

  Sets the \c _maxAltitude member to \a altitude and emits the signal \c maxAltitudeChanged()
  if \c _maxAltitude is not equal to altitude.
 */
void WimaArea::setMaxAltitude(double altitude)
    if ( altitude > 0 && qFuzzyCompare(altitude, _maxAltitude) ) {
        _maxAltitude = altitude;
        emit maxAltitudeChanged();
    }
}

/*!
 * \fn int WimaArea::getClosestVertexIndex(const QGeoCoordinate &coordinate) const
 * Returns the index of the vertex (element of the polygon path)
 * which has the least distance to \a coordinate.
 *
 * \sa QGeoCoordinate
 */
int WimaArea::getClosestVertexIndex(const QGeoCoordinate &coordinate) const
{
    if (this->count() == 0) {
        qWarning("Polygon count == 0!");
        return -1;
    }else if (this->count() == 1) {
        return 0;
    }else {
        int index = 0;
        double min_dist = coordinate.distanceTo(this->vertexCoordinate(index));
        for(int i = 1; i < this->count(); i++){
            double dist = coordinate.distanceTo(this->vertexCoordinate(i));
            if (dist < min_dist){
                min_dist = dist;
                index = i;
            }
        }

        return index;
    }
}

/*!
 * \fn  QGeoCoordinate WimaArea::getClosestVertex(const QGeoCoordinate& coordinate) const
 *  Returns the vertex of the polygon path with the least distance to \a coordinate.
 *
 * \sa QGeoCoordinate
 */
QGeoCoordinate WimaArea::getClosestVertex(const QGeoCoordinate& coordinate) const
{
    return this->vertexCoordinate(getClosestVertexIndex(coordinate));
}

/*!
 * \fn QGCMapPolygon WimaArea::toQGCPolygon(const WimaArea &area)
 * Converts the \c WimaArea \a area to \c QGCMapPolygon by copying the path only.
 */
QGCMapPolygon WimaArea::toQGCPolygon(const WimaArea &area)
Valentin Platzgummer's avatar
Valentin Platzgummer committed
    QGCMapPolygon qgcPoly;
    qgcPoly.setPath(area.path());
Valentin Platzgummer's avatar
Valentin Platzgummer committed
    return QGCMapPolygon(qgcPoly);
/*!
 * \fn QGCMapPolygon WimaArea::toQGCPolygon() const
 * Converts the calling \c WimaArea to \c QGCMapPolygon by copying the path only.
 */
QGCMapPolygon WimaArea::toQGCPolygon() const
{
    return toQGCPolygon(*this);
}

 * \fn bool WimaArea::join(WimaArea &area1, WimaArea &area2, WimaArea &joinedArea, QString &errorString)
 * Joins the areas \a area1 and \a area2 such that a \l {Simple Polygon} is created.
 * Stores the result inside \a joinedArea.
 * Returns \c true if the algorithm was able to join the areas; false else.
 * The algorithm will be able to join the areas, if either their edges intersect with each other,
 * or one area contains the other.
 */
bool WimaArea::join(const WimaArea &area1, const WimaArea &area2, WimaArea &joinedArea, QString &errorString)
    using namespace GeoUtilities;
    using namespace PolygonCalculus;
    QList<QGeoCoordinate> GeoPolygon1 = area1.coordinateList();
    QList<QGeoCoordinate> GeoPolygon2 = area2.coordinateList();
//    qWarning("befor joining");
//    qWarning() << GeoPolygon1;
//    qWarning() << GeoPolygon2;
    QGeoCoordinate origin = GeoPolygon1[0];
//    QGeoCoordinate tset = GeoPolygon1[2];
//    qWarning() << tset;qWarning() << toGeo(toCartesian2D(tset, origin), origin);
    QPolygonF polygon1 = toQPolygonF(toCartesian2D(GeoPolygon1, origin));
    QPolygonF polygon2 = toQPolygonF(toCartesian2D(GeoPolygon2, origin));
//    qWarning("after 1 transform");
//    qWarning() << polygon1;
//    qWarning() << polygon2;

    QPolygonF joinedPolygon;
    JoinPolygonError retValue = PolygonCalculus::join(polygon1, polygon2, joinedPolygon);


//    qWarning("after joining");
//    qWarning() << joinedPolygon;

    if (retValue == JoinPolygonError::Disjoint) {
        qWarning("Polygons are disjoint.");
    } else if (retValue == JoinPolygonError::NotSimplePolygon) {
        qWarning("Not a simple polygon.");
    } else if (retValue == JoinPolygonError::PathSizeLow) {
        qWarning("Polygon vertex count is low.");
    } else {
        QList<QGeoCoordinate> path = toGeo(toQPointFList(joinedPolygon), origin);
//        qWarning("after transform");
//        qWarning() << path;
        joinedArea.setPath(path);
        return true;
    }

    return false;

/*!
 * \fn bool WimaArea::join(WimaArea &area1, WimaArea &area2, WimaArea &joinedArea)
 * Joins the areas \a area1 and \a area2 such that a \l {Simple Polygon} is created.
 * Stores the result inside \a joinedArea.
 * Returns \c true if the algorithm was able to join the areas; false else.
 * The algorithm will be able to join the areas, if either their edges intersect with each other,
 * or one area contains the other.
 */
Valentin Platzgummer's avatar
Valentin Platzgummer committed
bool WimaArea::join(const WimaArea &area1, const WimaArea &area2, WimaArea &joinedArea)
/*!
 * \fn bool WimaArea::join(WimaArea &area)
 * Joins the calling \c WimaArea and the \a area such that a \l {Simple Polygon} is created.
 * Overwrites the calling \c WimaArea with the result, if the algorithm was successful.
 * Returns \c true if the algorithm was able to join the areas; false else.
 * The algorithm will be able to join the areas, if either their edges intersect with each other,
 * or one area contains the other.
 */
bool WimaArea::join(WimaArea &area)
Valentin Platzgummer's avatar
Valentin Platzgummer committed
    WimaArea joinedArea;
    if ( join(*this, area, joinedArea) ) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
        //qWarning("WimaArea::join(WimaArea &area)");
        //qWarning() << joinedArea.coordinateList();
        this->setPath(joinedArea.path());
        return true;
    } else {
        return false;
    }
 * \fn bool WimaArea::join(WimaArea &area, QString &errorString)
 * Joins the calling \c WimaArea and the \a area such that a \l {Simple Polygon} is created.
 * Overwrites the calling \c WimaArea with the result, if the algorithm was successful.
 *
 * Returns \c true if the algorithm was able to join the areas; false else.
 * Stores error messages in \a errorString.
 *
 * The algorithm will be able to join the areas, if either their edges intersect with each other,
 * or one area contains the other.
bool WimaArea::join(WimaArea &area, QString &errorString)
    WimaArea joinedArea;
    if ( join(*this, area, joinedArea, errorString) ) {
        this->setPath(joinedArea.path());
        return true;
    } else {
        return false;
    }
/*!
 * \fn int WimaArea::nextVertexIndex(int index) const
 * Returns the index of the next vertex (of the areas path), which is \a index + 1 if \a index is smaller than \c {area.count() - 1},
 * or 0 if \a index equals \c {area.count() - 1}, or -1 if the \a index is out of bounds.
 * \note The function \c {area.count()} (derived from \c QGCMapPolygon) returns the number of vertices defining the area.
 */
int WimaArea::nextVertexIndex(int index) const
{
    if (index >= 0 && index < count()-1) {
        return index + 1;
    } else if (index == count()-1) {
        return 0;
    } else {
        qWarning("WimaArea::nextVertexIndex(): Index out of bounds! index:count = %i:%i", index, count());
        return -1;
    }
}

/*!
 * \fn int WimaArea::previousVertexIndex(int index) const
 * Returns the index of the previous vertex (of the areas path), which is \a index - 1 if \a index is larger 0,
 * or \c {area.count() - 1} if \a index equals 0, or -1 if the \a index is out of bounds.
 * \note The function \c {area.count()} (derived from \c QGCMapPolygon) returns the number of vertices defining the area.
 */
int WimaArea::previousVertexIndex(int index) const
{
    if (index > 0 && index < count()) {
        return index - 1;
    } else if (index == 0) {
        return count()-1;
    } else {
        qWarning("WimaArea::previousVertexIndex(): Index out of bounds! index:count = %i:%i", index, count());
        return -1;
    }
}

/*!
 * \fn bool WimaArea::isSelfIntersecting()
 * Returns \c true if the calling area is self intersecting, \c false else.
 * \note If the calling area is self intersecting, it's not a \l {Simple Polygon}.
 */
bool WimaArea::isSimplePolygon()
    using namespace PolygonCalculus;
    using namespace GeoUtilities;

    if (this->count() > 2) {
        QPolygonF polygon = toQPolygonF(toCartesian2D(this->coordinateList(), this->vertexCoordinate(0)));
        return PolygonCalculus::isSimplePolygon(polygon);
    } else
        return false;

/*!
 * \fn void WimaArea::saveToJson(QJsonObject &json)
 * Saves the calling area to \c QJsonObject object and stores it inside \a json.
 *
 * \sa QJsonObject
 */
void WimaArea::saveToJson(QJsonObject &json)
{
    this->QGCMapPolygon::saveToJson(json);
    json[maxAltitudeName]   = _maxAltitude;
    json[areaTypeName]      = wimaAreaName;
    // add WimaVehicle if necessary..
}
/*!
 * \fn bool WimaArea::loadFromJson(const QJsonObject &json, QString& errorString)
 * Loads data from \a json and stores it inside the calling area.
 * Returns \c true if loading was successful, \c false else.
 * Stores error messages inside \a errorString.
 *
 * \sa QJsonObject
 */
bool WimaArea::loadFromJson(const QJsonObject &json, QString& errorString)
{
    if ( this->QGCMapPolygon::loadFromJson(json, false /*no poly required*/, errorString) ) {
        if ( json.contains(maxAltitudeName) && json[maxAltitudeName].isDouble()) {
            _maxAltitude = json[maxAltitudeName].toDouble();
            return true;
        } else {
            errorString.append(tr("Could not load Maximum Altitude value!\n"));
            return false;
        }
    } else {
        qWarning() << errorString;
        return false;
/*!
 * \fn void WimaArea::init()
 * Funtion to be called during construction.
 */
void WimaArea::init()
{
    this->setObjectName(wimaAreaName);
}

/*!
 * \fn void print(const WimaArea &area)
 * Prints the data contained in \a area to the console.
 */
void print(const WimaArea &area)
{
    QString message;
    print(area, message);
    qWarning() << message;
}

/*!
 * \fn void print(const WimaArea &area)
 * Prints the data contained in \a area to the \a outputString.
 */
void print(const WimaArea &area, QString &outputString)
{
    outputString.append(QString("Type: %1\n").arg(area.objectName()));
    print(static_cast<const QGCMapPolygon&>(area), outputString);
    outputString.append(QString("Maximum Altitude: %1\n").arg(area._maxAltitude));

// QDoc Documentation

/*!
    \group WimaAreaGroup
    \title Group of WimaAreas

    Every \c WimaArea of the equally named group uses a \l {Simple Polygon} derived from \c {QGCMapPolygon}
    to define areas inside which certain taskts are performed.
*/

/*!
    \class WimaArea
    \inmodule Wima
    \ingroup WimaArea

    \brief The \c WimaArea class provides the a base class for
    all areas used within the Wima extension.

    \c WimaArea uses a \l {Simple Polygon} derived from \c {QGCMapPolygon}
    to define areas inside which certain taskts are performed. The polygon (often refered to as the path) can
    be displayed visually on a map.
*/

/*!
  \variable WimaArea::_maxAltitude
  \brief The maximum altitude vehicles are allowed to fly inside this area.
*/

/*!
  \property WimaArea::maxAltitude
  \brief The maximum altitude at which vehicles are allowed to fly.
*/

/*!
  \property WimaArea::mapVisualQML
  \brief A string containing the name of the QML file used to displays this area on a map.
*/

/*!
  \property WimaArea::editorQML
  \brief A string containing the name of the QML file allowing to edit the area's properties.
*/

/*!
    \externalpage https://en.wikipedia.org/wiki/Simple_polygon
    \title Simple Polygon
*/

/*!
    \externalpage https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
    \title Dijkstra Algorithm
*/