$OpenBSD: patch-src_common_Projection_h,v 1.1 2021/04/12 10:17:11 landry Exp $

Index: src/common/Projection.h
--- src/common/Projection.h.orig
+++ src/common/Projection.h
@@ -4,77 +4,53 @@
 #include "IProjection.h"
 #include "Coord.h"
 
-#include <QPointF>
-
-#ifndef _MOBILE
 #include "MerkaartorPreferences.h"
 
-/* TODO: Proj.4 version 6.0.0 introduces new API changes, but is not widely
- * available yet. Until it is available on most distros, we will keep using the legacy API.
- * A migration will eventually be necessary (more research is needed). */
-#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 1
-#include <proj_api.h>
 
-typedef projPJ ProjProjection;
+#include <QPointF>
+#include <proj.h>
+#include <functional>
+#include <memory>
 
-#endif // _MOBILE
-
 class QRect;
 class Node;
 
-class Projection : public IProjection
+class ProjectionBackend : public IProjection
 {
 public:
-    Projection(void);
-    virtual ~Projection(void);
+    ProjectionBackend(QString initProjection, std::function<QString(QString)> mapProjectionName);
 
     qreal latAnglePerM() const;
     qreal lonAnglePerM(qreal Lat) const;
     QLineF project(const QLineF & Map) const;
     QPointF project(const QPointF& Map) const;
-    Coord inverse2Coord(const QPointF& Screen) const;
-    QPointF inverse2Point(const QPointF& Map) const;
+    QPointF inverse(const QPointF& Map) const;
 
     bool setProjectionType(QString aProjectionType);
     QString getProjectionType() const;
     bool projIsLatLong() const;
 
-    QPointF project(Node* aNode) const;
     QRectF toProjectedRectF(const QRectF& Viewport, const QRect& screen) const;
     CoordBox fromProjectedRectF(const QRectF& Viewport) const;
 
     int projectionRevision() const;
     QString getProjectionProj4() const;
 
-#ifndef _MOBILE
-
-    static ProjProjection getProjection(QString projString);
-    static void projTransform(ProjProjection srcdefn,
-                              ProjProjection dstdefn,
-                              long point_count, int point_offset, qreal *x, qreal *y, qreal *z );
-    void projTransformToWGS84(long point_count, int point_offset, qreal *x, qreal *y, qreal *z ) const;
-    void projTransformFromWGS84(long point_count, int point_offset, qreal *x, qreal *y, qreal *z ) const;
-
-#endif
     bool toXML(QXmlStreamWriter& stream);
     void fromXML(QXmlStreamReader& stream);
 
 protected:
-#ifndef _MOBILE
-    ProjProjection theProj;
+    PJ* getProjection(QString projString);
     QPointF projProject(const QPointF& Map) const;
     Coord projInverse(const QPointF& Screen) const;
 
-    ProjProjection theWGS84Proj;
-#endif
-
     QString projType;
     QString projProj4;
     QRectF ProjectedViewport;
     int ProjectionRevision;
     bool IsMercator;
     bool IsLatLong;
-
+    std::function<QString(QString)> mapProjectionName;
 protected:
     QPointF mercatorProject(const QPointF& c) const;
     Coord mercatorInverse(const QPointF& point) const;
@@ -88,7 +64,30 @@ class Projection : public IProjection (protected)
     {
         return Coord(point.x()/*/EQUATORIALMETERPERDEGREE*/, point.y()/*/EQUATORIALMETERPERDEGREE*/);
     }
+private:
+    // Note: keep the order of projCtx and projTransform, as projTransform depends on projCtx.
+    std::shared_ptr<PJ_CONTEXT> projCtx;
+    std::shared_ptr<PJ> projTransform;
+    std::shared_ptr<QMutex> projMutex;
+    // TODO: projTransform is not thread-safe by itself, so we need to protect
+    // it by a mutex.  In theory, each thread could have it's own projection
+    // object, but currently the object is copied around.  Until this changes,
+    // the mutex stays here.
+};
 
+/**
+ * Proxy class to inject M_PREFS externally and allow unit testing of ProjectionBackend itself.
+ */
+class Projection : public ProjectionBackend {
+  public:
+    static QString mapProjectionName(QString projName) {
+        return M_PREFS->getProjection(projName).projection;
+    }
+
+    Projection(void) :
+      ProjectionBackend(M_PREFS->getProjectionType(), mapProjectionName)
+    {
+    }
 };
 
 
