Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaria Volvenkova <d.volvenkova@corp.mail.ru>2016-06-20 15:09:09 +0300
committerDaria Volvenkova <d.volvenkova@corp.mail.ru>2016-07-07 15:31:08 +0300
commitfdf4f75816a9ba288d3d0d5108f13054890ad555 (patch)
tree262483bcadefe5b8e3f927853625e5d109ccd425 /geometry
parenteb300949c0f0a17b14976fac3ed047a3ae3e43df (diff)
Automatic perspective angle calculation in ScreenBase.
Diffstat (limited to 'geometry')
-rw-r--r--geometry/rect2d.hpp6
-rw-r--r--geometry/screenbase.cpp164
-rw-r--r--geometry/screenbase.hpp20
3 files changed, 134 insertions, 56 deletions
diff --git a/geometry/rect2d.hpp b/geometry/rect2d.hpp
index d49fa049d0..57f7b676b3 100644
--- a/geometry/rect2d.hpp
+++ b/geometry/rect2d.hpp
@@ -288,6 +288,12 @@ namespace m2
}
template <typename T>
+ inline bool IsEqualSize(Rect<T> const & r1, Rect<T> const & r2, double epsX, double epsY)
+ {
+ return fabs(r1.SizeX() - r2.SizeX()) < epsX && fabs(r1.SizeY() - r2.SizeY()) < epsY;
+ }
+
+ template <typename T>
inline m2::Rect<T> const Add(m2::Rect<T> const & r, m2::Point<T> const & p)
{
return m2::Rect<T>(
diff --git a/geometry/screenbase.cpp b/geometry/screenbase.cpp
index 7dc94b4efd..fb462fe11c 100644
--- a/geometry/screenbase.cpp
+++ b/geometry/screenbase.cpp
@@ -16,18 +16,19 @@ double constexpr kEndPerspectiveScale1 = 0.3e-5;
double constexpr kEndPerspectiveScale2 = 0.13e-5;
ScreenBase::ScreenBase() :
- m_PixelRect(0, 0, 640, 480),
+ m_ViewportRect(0, 0, 640, 480),
+ m_PixelRect(m_ViewportRect),
m_Scale(0.1),
m_Angle(0.0),
m_Org(320, 240),
- m_3dFOV(0.0),
+ m_3dFOV(kPerspectiveAngleFOV),
m_3dNearZ(0.001),
m_3dFarZ(0.0),
m_3dAngleX(0.0),
m_3dMaxAngleX(0.0),
- m_3dScaleX(1.0),
- m_3dScaleY(1.0),
+ m_3dScale(1.0),
m_isPerspective(false),
+ m_isAutoPerspective(true),
m_GlobalRect(m_Org, ang::AngleD(0), m2::RectD(-320, -240, 320, 240)),
m_ClipRect(m2::RectD(0, 0, 640, 480))
{
@@ -43,7 +44,7 @@ ScreenBase::ScreenBase(m2::RectI const & pxRect, m2::AnyRectD const & glbRect)
ScreenBase::ScreenBase(ScreenBase const & s,
m2::PointD const & org, double scale, double angle)
- : m_PixelRect(s.m_PixelRect),
+ : m_ViewportRect(s.m_ViewportRect),
m_Scale(scale), m_Angle(angle), m_Org(org)
{
UpdateDependentParameters();
@@ -51,6 +52,8 @@ ScreenBase::ScreenBase(ScreenBase const & s,
void ScreenBase::UpdateDependentParameters()
{
+ m_PixelRect = CalculatePixelRect(m_Scale);
+
m_PtoG = math::Shift( /// 5. shifting on (E0, N0)
math::Rotate( /// 4. rotating on the screen angle
math::Scale( /// 3. scaling to translate pixel sizes to global
@@ -79,38 +82,46 @@ void ScreenBase::UpdateDependentParameters()
m_GlobalRect = m2::AnyRectD(m_Org, m_Angle, m2::RectD(-szX, -szY, szX, szY));
m_ClipRect = m_GlobalRect.GetGlobalRect();
+
+ double const kEps = 1e-5;
+ double angle = CalculatePerspectiveAngle(m_Scale);
+ m_isPerspective = angle > 0.0;
+ if (fabs(angle - m_3dAngleX) > kEps)
+ {
+ m_3dMaxAngleX = angle;
+ m_3dScale = CalculateScale3d(angle);
+ SetRotationAngle(angle);
+ }
}
-double ScreenBase::CalculatePerspectiveAngle(double scale)
+double ScreenBase::CalculatePerspectiveAngle(double scale) const
{
+ if (!m_isAutoPerspective)
+ return m_3dAngleX;
+
if (scale > kStartPerspectiveScale1)
return 0.0;
- else if (scale > kEndPerspectiveScale1)
+
+ if (scale > kEndPerspectiveScale1)
{
double const k = (kStartPerspectiveScale1 - scale) / (kStartPerspectiveScale1 - kEndPerspectiveScale1);
return kMaxPerspectiveAngle1 * k;
}
- else if (scale > kEndPerspectiveScale2)
+
+ if (scale > kEndPerspectiveScale2)
{
double const k = (kEndPerspectiveScale1 - scale) / (kEndPerspectiveScale1 - kEndPerspectiveScale2);
return kMaxPerspectiveAngle1 + (kMaxPerspectiveAngle2 - kMaxPerspectiveAngle1) * k;
}
- else
- return kMaxPerspectiveAngle2 * 0.99;
+
+ return kMaxPerspectiveAngle2 * 0.99;
}
void ScreenBase::UpdatePerspectiveParameters()
{
double const angle = CalculatePerspectiveAngle(m_Scale);
if (angle > 0.0)
- {
- if (!m_isPerspective || (angle < kMaxPerspectiveAngle1 && m_3dMaxAngleX > kMaxPerspectiveAngle1))
- ApplyPerspective(angle, kMaxPerspectiveAngle1, kPerspectiveAngleFOV);
- else if (angle > m_3dMaxAngleX)
- ApplyPerspective(angle, kMaxPerspectiveAngle2, kPerspectiveAngleFOV);
- else
- SetRotationAngle(angle);
- }
+ ApplyPerspective(angle, angle, kPerspectiveAngleFOV);
else if (m_isPerspective)
ResetPerspective();
}
@@ -132,6 +143,48 @@ void ScreenBase::SetFromRect(m2::AnyRectD const & glbRect)
SetFromRects(glbRect, m_PixelRect);
}
+void ScreenBase::SetFromRect2d(m2::AnyRectD const & glbRect)
+{
+ double hScale = glbRect.GetLocalRect().SizeX() / PixelRectIn3d().SizeX();
+ double vScale = glbRect.GetLocalRect().SizeY() / PixelRectIn3d().SizeY();
+ double scale = max(hScale, vScale);
+
+ m_Scale = scale;
+ m_Angle = glbRect.Angle();
+ m_Org = glbRect.GlobalCenter();
+
+ UpdateDependentParameters();
+ UpdatePerspectiveParameters();
+
+/* m2::PointD g_target(0.0, -glbRect.GetLocalRect().SizeY() * scale / vScale / 2.0);
+ g_target.Rotate(glbRect.Angle().val());
+ g_target = glbRect.GlobalCenter() + g_target;
+ m2::PointD p_target(m_PixelRect.SizeX() / 2.0, m_PixelRect.SizeY());
+ MatchGandP(g_target, p_target);*/
+
+ MatchGandP3d(glbRect.GlobalCenter(), PixelRectIn3d().Center());
+}
+
+void ScreenBase::SetFromParams(m2::PointD const & org, double angle, double scale)
+{
+ m_Scale = scale;
+ m_Angle = angle;
+ m_Org = org;
+ UpdateDependentParameters();
+}
+
+void ScreenBase::MatchGandP(m2::PointD const & g, m2::PointD const & p)
+{
+ m2::PointD g_current = PtoG(p);
+ SetOrg(m_Org - g_current + g);
+}
+
+void ScreenBase::MatchGandP3d(m2::PointD const & g, m2::PointD const &p3d)
+{
+ m2::PointD g_current = PtoG(P3dtoP(p3d));
+ SetOrg(m_Org - g_current + g);
+}
+
void ScreenBase::SetOrg(m2::PointD const & p)
{
m_Org = p;
@@ -164,7 +217,7 @@ void ScreenBase::Rotate(double angle)
void ScreenBase::OnSize(m2::RectI const & r)
{
- m_PixelRect = m2::RectD(r);
+ m_ViewportRect = m2::RectD(r);
UpdateDependentParameters();
}
@@ -173,11 +226,6 @@ void ScreenBase::OnSize(int x0, int y0, int w, int h)
OnSize(m2::RectI(x0, y0, x0 + w, y0 + h));
}
-double ScreenBase::GetMinPixelRectSize() const
-{
- return min(m_PixelRect.SizeX(), m_PixelRect.SizeY());
-}
-
void ScreenBase::SetScale(double scale)
{
m_Scale = scale;
@@ -294,6 +342,32 @@ void ScreenBase::ExtractGtoPParams(MatrixT const & m,
dy = m(2, 1);
}
+double ScreenBase::CalculateScale3d(double rotationAngle) const
+{
+ double const halfFOV = m_3dFOV / 2.0;
+ double const cameraZ = 1.0 / tan(halfFOV);
+
+ // Ratio of the expanded plane's size to the original size.
+ double const y3dScale = cos(rotationAngle) + sin(rotationAngle) * tan(halfFOV + rotationAngle);
+ double const x3dScale = 1.0 + 2 * sin(rotationAngle) * cos(halfFOV) / (cameraZ * cos(halfFOV + rotationAngle));
+
+ return max(x3dScale, y3dScale);
+}
+
+m2::RectD ScreenBase::CalculatePixelRect(double scale) const
+{
+ double const angle = CalculatePerspectiveAngle(scale);
+ if (angle > 0.0)
+ {
+ double const scale3d = CalculateScale3d(angle);
+
+ return m2::RectD(m2::PointD(0.0, 0.0),
+ m2::PointD(m_ViewportRect.maxX(), m_ViewportRect.maxY()) * scale3d);
+ }
+
+ return m_ViewportRect;
+}
+
// Place the camera at the distance, where it gives the same view of plane as the
// orthogonal projection does. Calculate what part of the map would be visible,
// when it is rotated through maxRotationAngle around its near horizontal side.
@@ -304,31 +378,21 @@ void ScreenBase::ApplyPerspective(double currentRotationAngle, double maxRotatio
ASSERT_GREATER_OR_EQUAL(maxRotationAngle, 0.0, ());
ASSERT_LESS(maxRotationAngle, math::pi2, ());
- if (m_isPerspective)
- ResetPerspective();
+// if (m_isPerspective)
+// ResetPerspective();
m_isPerspective = true;
m_3dMaxAngleX = maxRotationAngle;
m_3dFOV = angleFOV;
- double const halfFOV = m_3dFOV / 2.0;
- double const cameraZ = 1.0 / tan(halfFOV);
-
- // Ratio of the expanded plane's size to the original size.
- m_3dScaleY = cos(m_3dMaxAngleX) + sin(m_3dMaxAngleX) * tan(halfFOV + m_3dMaxAngleX);
- m_3dScaleX = 1.0 + 2 * sin(m_3dMaxAngleX) * cos(halfFOV) / (cameraZ * cos(halfFOV + m_3dMaxAngleX));
-
- m_3dScaleX = m_3dScaleY = max(m_3dScaleX, m_3dScaleY);
-
- double const dy = m_PixelRect.SizeY() * (m_3dScaleX - 1.0);
-
- m_PixelRect.setMaxX(m_PixelRect.maxX() * m_3dScaleX);
- m_PixelRect.setMaxY(m_PixelRect.maxY() * m_3dScaleY);
-
- Move(0.0, dy / 2.0);
+ double const old_dy = m_ViewportRect.SizeY() * (m_3dScale - 1.0);
+ m_3dScale = CalculateScale3d(m_3dMaxAngleX);
+ double const new_dy = m_ViewportRect.SizeY() * (CalculateScale3d(m_3dMaxAngleX) - 1.0);
SetRotationAngle(currentRotationAngle);
+
+ Move(0.0, (new_dy - old_dy) / 2.0);
}
// Place the camera at the distance, where it gives the same view of plane as the
@@ -347,12 +411,12 @@ void ScreenBase::SetRotationAngle(double rotationAngle)
double const halfFOV = m_3dFOV / 2.0;
double const cameraZ = 1.0 / tan(halfFOV);
- double const offsetZ = cameraZ + sin(m_3dAngleX) * m_3dScaleY;
- double const offsetY = cos(m_3dAngleX) * m_3dScaleX - 1.0;
+ double const offsetZ = cameraZ + sin(m_3dAngleX) * m_3dScale;
+ double const offsetY = cos(m_3dAngleX) * m_3dScale - 1.0;
Matrix3dT scaleM = math::Identity<double, 4>();
- scaleM(0, 0) = m_3dScaleX;
- scaleM(1, 1) = m_3dScaleY;
+ scaleM(0, 0) = m_3dScale;
+ scaleM(1, 1) = m_3dScale;
Matrix3dT rotateM = math::Identity<double, 4>();
rotateM(1, 1) = cos(m_3dAngleX);
@@ -365,7 +429,7 @@ void ScreenBase::SetRotationAngle(double rotationAngle)
translateM(3, 2) = offsetZ;
Matrix3dT projectionM = math::Zero<double, 4>();
- m_3dFarZ = cameraZ + 2.0 * sin(m_3dAngleX) * m_3dScaleY;
+ m_3dFarZ = cameraZ + 2.0 * sin(m_3dAngleX) * m_3dScale;
projectionM(0, 0) = projectionM(1, 1) = cameraZ;
projectionM(2, 2) = m_3dAngleX != 0.0 ? (m_3dFarZ + m_3dNearZ) / (m_3dFarZ - m_3dNearZ)
: 0.0;
@@ -381,14 +445,14 @@ void ScreenBase::ResetPerspective()
{
m_isPerspective = false;
- double const dy = m_PixelRect.SizeY() * (1.0 - 1.0 / m_3dScaleX);
+ double const dy = m_PixelRect.SizeY() * (1.0 - 1.0 / m_3dScale);
- m_PixelRect.setMaxX(m_PixelRect.maxX() / m_3dScaleX);
- m_PixelRect.setMaxY(m_PixelRect.maxY() / m_3dScaleY);
+ m_PixelRect.setMaxX(m_PixelRect.maxX() / m_3dScale);
+ m_PixelRect.setMaxY(m_PixelRect.maxY() / m_3dScale);
Move(0, -dy / 2.0);
- m_3dScaleX = m_3dScaleY = 1.0;
+ m_3dScale = 1.0;
m_3dAngleX = 0.0;
m_3dMaxAngleX = 0.0;
m_3dFOV = 0.0;
diff --git a/geometry/screenbase.hpp b/geometry/screenbase.hpp
index 8f99f76dbd..c3cf5eefe2 100644
--- a/geometry/screenbase.hpp
+++ b/geometry/screenbase.hpp
@@ -15,6 +15,7 @@ public:
using Vector3dT = math::Matrix<double, 1, 4>;
private:
+ m2::RectD m_ViewportRect;
m2::RectD m_PixelRect;
double m_Scale;
@@ -26,9 +27,9 @@ private:
double m_3dFarZ;
double m_3dAngleX;
double m_3dMaxAngleX;
- double m_3dScaleX;
- double m_3dScaleY;
+ double m_3dScale;
bool m_isPerspective;
+ bool m_isAutoPerspective;
protected:
/// @group Dependent parameters
@@ -64,6 +65,9 @@ public:
m2::PointD const & org, double scale, double angle);
void SetFromRect(m2::AnyRectD const & rect);
+ void SetFromRect2d(m2::AnyRectD const & glbRect);
+
+ void SetFromParams(m2::PointD const & org, double angle, double scale);
void SetFromRects(m2::AnyRectD const & glbRect, m2::RectD const & pxRect);
void SetOrg(m2::PointD const & p);
@@ -115,6 +119,9 @@ public:
void GtoP(m2::RectD const & gr, m2::RectD & sr) const;
void PtoG(m2::RectD const & pr, m2::RectD & gr) const;
+ void MatchGandP(m2::PointD const & g, m2::PointD const & p);
+ void MatchGandP3d(m2::PointD const & g, m2::PointD const & p3d);
+
void GetTouchRect(m2::PointD const & pixPoint, double pixRadius, m2::AnyRectD & glbRect) const;
void GetTouchRect(m2::PointD const & pixPoint, double const pxWidth,
double const pxHeight, m2::AnyRectD & glbRect) const;
@@ -134,7 +141,7 @@ public:
double GetRotationAngle() const { return m_3dAngleX; }
double GetMaxRotationAngle() const { return m_3dMaxAngleX; }
double GetAngleFOV() const { return m_3dFOV; }
- double GetScale3d() const { return m_3dScaleX; }
+ double GetScale3d() const { return m_3dScale; }
m2::PointD P3dtoP(m2::PointD const & pt) const;
@@ -148,17 +155,18 @@ public:
m2::RectD PixelRectIn3d() const
{
- return m2::RectD(0.0, 0.0, m_PixelRect.maxX() / m_3dScaleX, m_PixelRect.maxY() / m_3dScaleY);
+ return m_ViewportRect;
}
- double GetMinPixelRectSize() const;
+ double CalculateScale3d(double rotationAngle) const;
+ m2::RectD CalculatePixelRect(double scale) const;
+ double CalculatePerspectiveAngle(double scale) const;
/// Compute arbitrary pixel transformation, that translates the (oldPt1, oldPt2) -> (newPt1, newPt2)
static MatrixT const CalcTransform(m2::PointD const & oldPt1, m2::PointD const & oldPt2,
m2::PointD const & newPt1, m2::PointD const & newPt2,
bool allowRotate);
- static double CalculatePerspectiveAngle(double scale);
/// Setting GtoP matrix extracts the Angle and m_Org parameters, leaving PixelRect intact
void SetGtoPMatrix(MatrixT const & m);