Subversion Repositories public iLand

Rev

Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1211 werner 1
/********************************************************************************************
2
**    iLand - an individual based forest landscape and disturbance model
3
**    http://iland.boku.ac.at
4
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
5
**
6
**    This program is free software: you can redistribute it and/or modify
7
**    it under the terms of the GNU General Public License as published by
8
**    the Free Software Foundation, either version 3 of the License, or
9
**    (at your option) any later version.
10
**
11
**    This program is distributed in the hope that it will be useful,
12
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
**    GNU General Public License for more details.
15
**
16
**    You should have received a copy of the GNU General Public License
17
**    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
********************************************************************************************/
808 werner 19
#include "global.h"
20
#include "viewport.h"
21
 
22
 
23
/** @class Viewport
24
  Handles coordinaive transforation between grids (based on real-world metric coordinates).
25
  The visible part of the grid is defined by the "viewport" (defaults to 100% of the grid).
26
  The result coordinates are mapped into a "ScreenRect", which is a pixel-based viewing window.
27
*/
28
 
29
/// toWorld() converts the pixel-information (e.g. by an mouse event) to the corresponding real world coordinates (defined by viewport).
30
const QPointF Viewport::toWorld(const QPoint pixel)
31
{
32
    QPointF p;
33
    p.setX( pixel.x()/m_scale_worldtoscreen +  m_delta_worldtoscreen.x());
34
    p.setY( (m_screen.height() - pixel.y()  )/m_scale_worldtoscreen + m_delta_worldtoscreen.y() );
35
    return p;
36
 
37
}
38
 
39
/// toScreen() converts world coordinates in screen coordinates using the defined viewport.
40
const QPoint Viewport::toScreen(const QPointF p)
41
{
42
    QPoint pixel;
43
    pixel.setX( qRound( (p.x()-m_delta_worldtoscreen.x())* m_scale_worldtoscreen ) );
44
    pixel.setY( m_screen.height() - 1 -  qRound( (p.y()-m_delta_worldtoscreen.y() ) * m_scale_worldtoscreen ));
45
    return pixel;
46
}
47
 
48
/// sets the screen rect; this also modifies the viewport.
49
void Viewport::setScreenRect(const QRect &viewrect)
50
{
51
    if (m_screen!=viewrect) {
52
        m_screen = viewrect;
53
        m_viewport = viewrect;
54
        zoomToAll();
55
    }
56
}
57
 
58
/// show the full extent of the world.
59
void Viewport::zoomToAll()
60
{
61
    // calculate move/scale so that world-rect maps entirely onto screen
62
    double scale_x = m_screen.width() /  m_world.width(); // pixel per meter in x
63
    double scale_y = m_screen.height() / m_world.height(); // pixel per meter in y
64
    double scale = qMin(scale_x, scale_y);
65
    QPointF d;
66
    if (scale_x < scale_y) {
67
        // x-axis fills the screen; center in y-axis
68
        d.setX(m_world.left());
69
        int py_mid = m_screen.height()/2;
70
        double world_mid = m_world.center().y();
71
        d.setY( world_mid - py_mid/scale );
72
    } else {
73
        d.setY(m_world.top());
74
        int px_mid = m_screen.width()/2;
75
        double world_mid = m_world.center().x();
76
        d.setX( world_mid - px_mid/scale );
77
    }
78
    m_delta_worldtoscreen = d;
79
    m_scale_worldtoscreen = scale;
80
    m_viewport.setBottomLeft(toWorld(m_screen.topLeft()));
81
    m_viewport.setTopRight(toWorld(m_screen.bottomRight()));
82
}
83
 
84
/// zoom using a factor of @p factor. Values > 1 means zoom out, < 1 zoom in. (factor=1 would have no effect).
85
/// after zooming, the world-point under the mouse @p screen_point is still under the mouse.
86
void Viewport::zoomTo(const QPoint &screen_point, const double factor)
87
{
88
    QPointF focus_point = toWorld(screen_point); // point under the mouse
89
 
90
    m_viewport.setWidth(m_viewport.width() * factor);
91
    m_viewport.setHeight(m_viewport.height() * factor);
92
 
93
    m_scale_worldtoscreen /= factor;
94
 
95
    // get scale/delta
96
    QPointF new_focus = toWorld(screen_point);
97
    m_delta_worldtoscreen -= (new_focus - focus_point);
98
 
99
    m_viewport.setBottomLeft(toWorld(m_screen.topLeft()));
100
    m_viewport.setTopRight(toWorld(m_screen.bottomRight()));
101
 
102
    //qDebug() <<"oldf"<< new_focus << "newf" << focus_point << "m_delta" << m_delta_worldtoscreen << "m_scale:" << m_scale_worldtoscreen << "viewport:"<<m_viewport;
103
}
104
 
105
/// move the viewport. @p screen_from and @p screen_to give mouse positions (in pixel) from dragging the mouse.
106
void Viewport::moveTo(const QPoint &screen_from, const QPoint &screen_to)
107
{
108
    QPointF p1 = toWorld(screen_from);
109
    QPointF p2 = toWorld(screen_to);
110
    m_delta_worldtoscreen -= (p2-p1);
111
    // correct the viewport
112
    m_viewport.setBottomLeft(toWorld(m_screen.topLeft()));
113
    m_viewport.setTopRight(toWorld(m_screen.bottomRight()));
114
}
115
 
116
/// set 'world_center' as the new center point of the viewport
117
void Viewport::setViewPoint(const QPointF &world_center, const double px_per_meter)
118
{
119
    QPoint p = toScreen(world_center); // point where world_center would be
120
    QPoint target = m_screen.center();
121
    moveTo(p,target);
1016 werner 122
    double px_p_m = qMax(px_per_meter, 0.001);
123
    double factor =  m_scale_worldtoscreen / px_p_m;
808 werner 124
    zoomTo(target, factor);
125
}
126
 
127
bool Viewport::isVisible(const QPointF &world_coord) const
128
{
129
    return m_viewport.contains(world_coord);
130
}
131
bool Viewport::isVisible(const QRectF &world_rect) const
132
{
133
    return m_viewport.contains(world_rect)
134
            || m_viewport.intersects(world_rect);
135
}
136