diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 7013df0f30e6df4fd94847e4a008d00190d981ec..201c14ba08b9869b1fb616d27ba1a908e6e8bd9d 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -424,8 +424,10 @@ HEADERS += \ src/Wima/WimaPlanData.h \ src/Wima/WimaJoinedArea.h \ src/Wima/WimaJoinedAreaData.h \ - src/Wima/SphericalGeometryCalculus.h \ - src/Wima/SphereCalculus.h + src/Wima/SphereCalculus.h \ + src/Wima/CircularSurveyComplexItem.h \ + src/Wima/PlanimetryCalculus.h \ + src/Wima/Circle.h SOURCES += \ src/api/QGCCorePlugin.cc \ src/api/QGCOptions.cc \ @@ -448,8 +450,10 @@ SOURCES += \ src/Wima/WimaMeasurementAreaData.cc \ src/Wima/WimaJoinedArea.cc \ src/Wima/WimaJoinedAreaData.cc \ - src/Wima/SphericalGeometryCalculus.cc \ - src/Wima/SphereCalculus.cc + src/Wima/SphereCalculus.cc \ + src/Wima/CircularSurveyComplexItem.cc \ + src/Wima/PlanimetryCalculus.cc \ + src/Wima/Circle.cc # # Unit Test specific configuration goes here (requires full debug build with all plugins) diff --git a/src/Wima/Circle.c b/src/Wima/Circle.c new file mode 100644 index 0000000000000000000000000000000000000000..7e72f32c8c124129810d6f7d5ae1049cbf45ab31 --- /dev/null +++ b/src/Wima/Circle.c @@ -0,0 +1,6 @@ +#include "Circle.h" + +Circle::Circle() +{ + +} diff --git a/src/Wima/Circle.cc b/src/Wima/Circle.cc new file mode 100644 index 0000000000000000000000000000000000000000..552c4bd55761224c6af1992a3fdb6dcd1676670e --- /dev/null +++ b/src/Wima/Circle.cc @@ -0,0 +1,122 @@ +#include "Circle.h" + + + +Circle::Circle(QObject *parent) + : QObject (parent) + , _circleRadius(0) + , _circleOrigin(QPointF(0,0)) +{ + +} + +Circle::Circle(double radius, QObject *parent) + : QObject (parent) + , _circleRadius(radius) + , _circleOrigin(QPointF(0,0)) +{ + +} + +Circle::Circle(double radius, QPointF origin, QObject *parent) + : QObject (parent) + , _circleRadius(radius) + , _circleOrigin(origin) +{ + +} + +Circle::Circle(const Circle &other, QObject *parent) + : QObject (parent) +{ + *this = other; +} + +Circle &Circle::operator=(const Circle &other) +{ + this->setRadius(other.radius()); + this->setOrigin(other.origin()); + + return *this; +} + +/*! + * \fn void Circle::setRadius(double radius) + * Sets the radius of the circle to \a radius + */ +void Circle::setRadius(double radius) +{ + if ( radius >= 0 && !qFuzzyCompare(_circleRadius, radius) ) { + _circleRadius = radius; + + emit radiusChanged(_circleRadius); + } +} + +/*! + * \fn void Circle::setOrigin(const QPointF &origin) + * Sets the origin of the circle to \a origin + * + * \sa QPointF + */ +void Circle::setOrigin(const QPointF &origin) +{ + if (origin != _circleOrigin) { + _circleOrigin = origin; + + emit originChanged(_circleOrigin); + } +} + +/*! + * \fn double Circle::radius() const + * Returns the radius of the circle. + */ +double Circle::radius() const +{ + return _circleRadius; +} + +/*! + * \fn QPointF Circle::origin() const + * Returns the origin of the circle. + * + * \sa QPointF + */ +QPointF Circle::origin() const +{ + return _circleOrigin; +} + + +/*! + * \fn QPolygonF Circle::approximate(int numberOfCorners) + * Returns a polygon with \a numberOfCorners corners which approximates the circle. + * + * \sa QPointF + */ +QPolygonF Circle::approximate(int numberOfCorners) +{ + if ( numberOfCorners < 3) + return QPolygonF(); + + double rotationAngle = 2*M_PI/numberOfCorners; + + QPolygonF polygon; + QPointF vertex(-_circleRadius,0); // initial vertex + polygon.append(vertex + _circleOrigin); + // rotate the vertex numberOfCorners-1 times add the origin and append to the polygon. + for(int i = 0; i < numberOfCorners; i++) { + rotatePoint(vertex, rotationAngle); + polygon.append(vertex + _circleOrigin); + } + + return polygon; +} + +/*! + * \class Circle + * \brief Provies a circle with radius and origin. + * + * \sa QPointF + */ diff --git a/src/Wima/Circle.h b/src/Wima/Circle.h new file mode 100644 index 0000000000000000000000000000000000000000..3b5e10bb8bcc22e257581fe0683205c5c4fc3f5e --- /dev/null +++ b/src/Wima/Circle.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include + +#include "PlanimetryCalculus.h" + +class Circle : public QObject, protected PlanimetryCalculus +{ + Q_OBJECT +public: + Circle(QObject *parent = nullptr); + Circle(double radius = 0, QObject *parent = nullptr); + Circle(double radius = 0, QPointF origin = QPointF(0,0), QObject *parent = nullptr); + Circle(const Circle &other, QObject *parent = nullptr); + Circle &operator=(const Circle &other); + + // Property setters + void setRadius(double radius); + void setOrigin(const QPointF &origin); + + // Property getters + double radius() const; + QPointF origin() const; + + // Member methodes + QPolygonF approximate(int numberOfCorners); + +signals: + void radiusChanged(double radius); + void originChanged(QPointF origin); + +private: + double _circleRadius; + QPointF _circleOrigin; +}; + diff --git a/src/Wima/CircularSurveyComplexItem.cc b/src/Wima/CircularSurveyComplexItem.cc new file mode 100644 index 0000000000000000000000000000000000000000..be1cc6f0cd5d09793d345a23a3526a5d6450d29e --- /dev/null +++ b/src/Wima/CircularSurveyComplexItem.cc @@ -0,0 +1,72 @@ +#include "CircularSurveyComplexItem.h" + + +const char* CircularSurveyComplexItem::settingsGroup = "Survey"; + +CircularSurveyComplexItem::CircularSurveyComplexItem(Vehicle *vehicle, bool flyView, const QString &kmlOrShpFile, QObject *parent) + : TransectStyleComplexItem (vehicle, flyView, settingsGroup, parent) +{ + +} + +bool CircularSurveyComplexItem::load(const QJsonObject &complexObject, int sequenceNumber, QString &errorString) +{ + return TransectStyleComplexItem::load(complexObject, sequenceNumber, errorString); +} + +void CircularSurveyComplexItem::save(QJsonArray &planItems) +{ + TransectStyleComplexItem::save(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() +{ + _transects.clear(); +} + +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 +*/ diff --git a/src/Wima/CircularSurveyComplexItem.h b/src/Wima/CircularSurveyComplexItem.h new file mode 100644 index 0000000000000000000000000000000000000000..887a4d85877b7e92ece71339b44c548e60b08c9e --- /dev/null +++ b/src/Wima/CircularSurveyComplexItem.h @@ -0,0 +1,42 @@ +# pragma once + +#include "TransectStyleComplexItem.h" + +class CircularSurveyComplexItem :public TransectStyleComplexItem +{ + Q_OBJECT +public: + /// @param vehicle Vehicle which this is being contructed for + /// @param flyView true: Created for use in the Fly View, false: Created for use in the Plan View + /// @param kmlOrShpFile Polygon comes from this file, empty for default polygon + CircularSurveyComplexItem(Vehicle* vehicle, bool flyView, const QString& kmlOrShpFile, QObject* parent); + + // Overrides from ComplexMissionItem + bool load (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) final; + QString mapVisualQML (void) const final { return QStringLiteral("SpericalSurveyMapVisual.qml"); } + + // Overrides from TransectStyleComplexItem + void save (QJsonArray& planItems) final; + bool specifiesCoordinate (void) const final { return true; } + void appendMissionItems (QList& items, QObject* missionItemParent) final; + void applyNewAltitude (double newAltitude) final; + double timeBetweenShots (void) final; + + // Overrides from VisualMissionionItem + QString commandDescription (void) const final { return tr("Spherical Survey"); } + QString commandName (void) const final { return tr("SphericalSurvey"); } + QString abbreviation (void) const final { return tr("Sph.S"); } + bool readyForSave (void) const final; + double additionalTimeDelay (void) const final; + + static const char* settingsGroup; + +private slots: + // Overrides from TransectStyleComplexItem + void _rebuildTransectsPhase1 (void) final; + void _recalcComplexDistance (void) final; + void _recalcCameraShots (void) final; +}; + + + diff --git a/src/Wima/PlanimetryCalculus.cc b/src/Wima/PlanimetryCalculus.cc new file mode 100644 index 0000000000000000000000000000000000000000..ca3a9eab7c4cc63eb8d867b3d2f75e881c29e7bc --- /dev/null +++ b/src/Wima/PlanimetryCalculus.cc @@ -0,0 +1,64 @@ +#include "PlanimetryCalculus.h" + + +PlanimetryCalculus::PlanimetryCalculus() +{ + +} + +/*! + \fn void PlanimetryCalculus::rotatePoint(QPointF &point, double alpha) + Rotates the \a point counter clockwisely by the angle \a alpha (in radiants). +*/ +void PlanimetryCalculus::rotatePoint(QPointF &point, double alpha) +{ + double x = point.x(); + double y = point.y(); + + point.setX(x*qCos(alpha) - y*qSin(alpha)); + point.setY(x*qSin(alpha) + y*qCos(alpha)); +} + +/*! + \fn void PlanimetryCalculus::rotatePointDegree(QPointF &point, double alpha) + Rotates the \a point counter clockwisely by the angle \a alpha (in degrees). +*/ +void PlanimetryCalculus::rotatePointDegree(QPointF &point, double alpha) +{ + rotatePoint(point, alpha/180*M_PI); +} + +/*! + \fn PlanimetryCalculus::IntersectType PlanimetryCalculus::intersects(const Circle &circle1, const Circle &circle2) + Returns the intersection type of the two cirles \a circle1 and \a circle2. + + \sa Circle +*/ +PlanimetryCalculus::IntersectType PlanimetryCalculus::intersects(const Circle &circle1, const Circle &circle2) +{ + double r1 = circle1.radius(); + double r2 = circle2.radius(); + double d = distance(circle1.origin(), circle2.origin()); + + //go on here +} + +/*! + \fn double PlanimetryCalculus::distance(const QPointF &p1, const QPointF p2) + Calculates the distance (2-norm) between \a p1 and \a p2. + \sa QPointF +*/ +double PlanimetryCalculus::distance(const QPointF &p1, const QPointF p2) +{ + double dx = p1.x()-p2.x(); + double dy = p1.y()-p2.y(); + + return qSqrt(dx*dx+dy*dy); +} + +/*! + \class PlanimetryCalculus + \inmodule Wima + + \brief The \c PlanimetryCalculus class provides routines handy for planimetrical (2D) calculations. +*/ diff --git a/src/Wima/PlanimetryCalculus.h b/src/Wima/PlanimetryCalculus.h new file mode 100644 index 0000000000000000000000000000000000000000..110b2ddd942707859f17c5135a3fea9de6a36780 --- /dev/null +++ b/src/Wima/PlanimetryCalculus.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include + +#include "Circle.h" +class PlanimetryCalculus +{ +public: + PlanimetryCalculus(); + + enum IntersectType{CircleInsideNoIntersection, CircleInsideTouching, CircleInsideIntersection, + CircleOutsideIntersection, CircleOutsideTouching, CircleOutsideNoIntersection, //Circle Circle intersection + + NoIntersection, Tangent, Secant // Circle Line Intersetion + }; + + void rotatePoint(QPointF &point, double alpha); + void rotatePointDegree(QPointF &point, double alpha); + IntersectType intersects(const Circle &circle1, const Circle &circle2); + IntersectType intersects(const Circle &circle, const QLineF &line); + double distance(const QPointF &p1, const QPointF p2); +}; + diff --git a/src/Wima/SphericalSurveyComplexItem.cc b/src/Wima/SphericalSurveyComplexItem.cc new file mode 100644 index 0000000000000000000000000000000000000000..1454a53f0cc313ff33234b55a0377ff842156644 --- /dev/null +++ b/src/Wima/SphericalSurveyComplexItem.cc @@ -0,0 +1,72 @@ +#include "CircularSurveyComplexItem.h" + + +const char* CircularSurveyComplexItem::settingsGroup = "Survey"; + +CircularSurveyComplexItem::CircularSurveyComplexItem(Vehicle *vehicle, bool flyView, const QString &kmlOrShpFile, QObject *parent) + : TransectStyleComplexItem (vehicle, flyView, settingsGroup, parent) +{ + +} + +bool CircularSurveyComplexItem::load(const QJsonObject &complexObject, int sequenceNumber, QString &errorString) +{ + return TransectStyleComplexItem::load(complexObject, sequenceNumber, errorString); +} + +void CircularSurveyComplexItem::save(QJsonArray &planItems) +{ + TransectStyleComplexItem::save(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() +{ + +} + +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 +*/ diff --git a/src/Wima/SphericalSurveyComplexItem.h b/src/Wima/SphericalSurveyComplexItem.h new file mode 100644 index 0000000000000000000000000000000000000000..15f07f2f4d37fd55b9a959560d1c6eda2f2199dd --- /dev/null +++ b/src/Wima/SphericalSurveyComplexItem.h @@ -0,0 +1,43 @@ +# pragma once + +#include "TransectStyleComplexItem.h" + + +class CircularSurveyComplexItem :public TransectStyleComplexItem +{ + Q_OBJECT +public: + /// @param vehicle Vehicle which this is being contructed for + /// @param flyView true: Created for use in the Fly View, false: Created for use in the Plan View + /// @param kmlOrShpFile Polygon comes from this file, empty for default polygon + CircularSurveyComplexItem(Vehicle* vehicle, bool flyView, const QString& kmlOrShpFile, QObject* parent); + + // Overrides from ComplexMissionItem + bool load (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) final; + QString mapVisualQML (void) const final { return QStringLiteral("SpericalSurveyMapVisual.qml"); } + + // Overrides from TransectStyleComplexItem + void save (QJsonArray& planItems) final; + bool specifiesCoordinate (void) const final { return true; } + void appendMissionItems (QList& items, QObject* missionItemParent) final; + void applyNewAltitude (double newAltitude) final; + double timeBetweenShots (void) final; + + // Overrides from VisualMissionionItem + QString commandDescription (void) const final { return tr("Spherical Survey"); } + QString commandName (void) const final { return tr("SphericalSurvey"); } + QString abbreviation (void) const final { return tr("Sph.S"); } + bool readyForSave (void) const final; + double additionalTimeDelay (void) const final; + + static const char* settingsGroup; + +private slots: + // Overrides from TransectStyleComplexItem + void _rebuildTransectsPhase1 (void) final; + void _recalcComplexDistance (void) final; + void _recalcCameraShots (void) final; +}; + + + diff --git a/src/Wima/WimaArea.cc b/src/Wima/WimaArea.cc index 2d936087cdea940b1225dc598743577baf12f1bc..e770572671b0198f6e422b26e0eab55e22228901 100644 --- a/src/Wima/WimaArea.cc +++ b/src/Wima/WimaArea.cc @@ -221,7 +221,7 @@ bool WimaArea::join(WimaArea &area1, WimaArea &area2, WimaArea &joinedArea, QStr QGeoCoordinate protoCurrentVertex = intersectionList.value(minDistIndex); // take numerical erros into account if (protoCurrentVertex.distanceTo(currentVertex) > epsilonMeter) { - currentVertex = protoCurrentVertexertexCoordinate; + currentVertex = protoNextVertex; QPair neighbours = neighbourList.value(minDistIndex); protoNextVertex = crossPoly->vertexCoordinate(neighbours.second); nextVertexIndex = neighbours.second; @@ -668,7 +668,23 @@ void WimaArea::saveToJson(QJsonObject &json) 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()) { + if ( json.contains(maxAltitudeName) && json[maxAltitudeName].i// Overrides from ComplexMissionItem + bool load (const QJsonObject& complexObject, int sequenceNumber, QString& errorString) final; + QString mapVisualQML (void) const final { return QStringLiteral("SurveyMapVisual.qml"); } + + // Overrides from TransectStyleComplexItem + void save (QJsonArray& planItems) final; + bool specifiesCoordinate (void) const final { return true; } + void appendMissionItems (QList& items, QObject* missionItemParent) final; + void applyNewAltitude (double newAltitude) final; + double timeBetweenShots (void) final; + + // Overrides from VisualMissionionItem + QString commandDescription (void) const final { return tr("Survey"); } + QString commandName (void) const final { return tr("Survey"); } + QString abbreviation (void) const final { return tr("S"); } + bool readyForSave (void) const final; + double additionalTimeDelay (void) const final;sDouble()) { _maxAltitude = json[maxAltitudeName].toDouble(); return true; } else {