1//----------------------------------------------------------------------------
2// Anti-Grain Geometry - Version 2.4
3// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4//
5// Permission to copy, use, modify, sell and distribute this software
6// is granted provided this copyright notice appears in all copies.
7// This software is provided "as is" without express or implied
8// warranty, and with no claim as to its suitability for any purpose.
9//
10//----------------------------------------------------------------------------
11// Contact: mcseem@antigrain.com
12//          mcseemagg@yahoo.com
13//          http://www.antigrain.com
14//----------------------------------------------------------------------------
15//
16// Viewport transformer - simple orthogonal conversions from world coordinates
17//                        to screen (device) ones.
18//
19//----------------------------------------------------------------------------
20
21#ifndef AGG_TRANS_VIEWPORT_INCLUDED
22#define AGG_TRANS_VIEWPORT_INCLUDED
23
24#include <string.h>
25#include "agg_trans_affine.h"
26
27
28namespace agg
29{
30
31    enum aspect_ratio_e
32    {
33        aspect_ratio_stretch,
34        aspect_ratio_meet,
35        aspect_ratio_slice
36    };
37
38
39    //----------------------------------------------------------trans_viewport
40    class trans_viewport
41    {
42    public:
43        //-------------------------------------------------------------------
44        trans_viewport() :
45            m_world_x1(0.0),
46            m_world_y1(0.0),
47            m_world_x2(1.0),
48            m_world_y2(1.0),
49            m_device_x1(0.0),
50            m_device_y1(0.0),
51            m_device_x2(1.0),
52            m_device_y2(1.0),
53            m_aspect(aspect_ratio_stretch),
54            m_is_valid(true),
55            m_align_x(0.5),
56            m_align_y(0.5),
57            m_wx1(0.0),
58            m_wy1(0.0),
59            m_wx2(1.0),
60            m_wy2(1.0),
61            m_dx1(0.0),
62            m_dy1(0.0),
63            m_kx(1.0),
64            m_ky(1.0)
65        {}
66
67        //-------------------------------------------------------------------
68        void preserve_aspect_ratio(double alignx,
69                                   double aligny,
70                                   aspect_ratio_e aspect)
71        {
72            m_align_x = alignx;
73            m_align_y = aligny;
74            m_aspect  = aspect;
75            update();
76        }
77
78        //-------------------------------------------------------------------
79        void device_viewport(double x1, double y1, double x2, double y2)
80        {
81            m_device_x1 = x1;
82            m_device_y1 = y1;
83            m_device_x2 = x2;
84            m_device_y2 = y2;
85            update();
86        }
87
88        //-------------------------------------------------------------------
89        void world_viewport(double x1, double y1, double x2, double y2)
90        {
91            m_world_x1 = x1;
92            m_world_y1 = y1;
93            m_world_x2 = x2;
94            m_world_y2 = y2;
95            update();
96        }
97
98        //-------------------------------------------------------------------
99        void device_viewport(double* x1, double* y1, double* x2, double* y2) const
100        {
101            *x1 = m_device_x1;
102            *y1 = m_device_y1;
103            *x2 = m_device_x2;
104            *y2 = m_device_y2;
105        }
106
107        //-------------------------------------------------------------------
108        void world_viewport(double* x1, double* y1, double* x2, double* y2) const
109        {
110            *x1 = m_world_x1;
111            *y1 = m_world_y1;
112            *x2 = m_world_x2;
113            *y2 = m_world_y2;
114        }
115
116        //-------------------------------------------------------------------
117        void world_viewport_actual(double* x1, double* y1,
118                                   double* x2, double* y2) const
119        {
120            *x1 = m_wx1;
121            *y1 = m_wy1;
122            *x2 = m_wx2;
123            *y2 = m_wy2;
124        }
125
126        //-------------------------------------------------------------------
127        bool   is_valid()             const { return m_is_valid; }
128        double align_x()              const { return m_align_x; }
129        double align_y()              const { return m_align_y; }
130        aspect_ratio_e aspect_ratio() const { return m_aspect; }
131
132        //-------------------------------------------------------------------
133        void transform(double* x, double* y) const
134        {
135            *x = (*x - m_wx1) * m_kx + m_dx1;
136            *y = (*y - m_wy1) * m_ky + m_dy1;
137        }
138
139        //-------------------------------------------------------------------
140        void transform_scale_only(double* x, double* y) const
141        {
142            *x *= m_kx;
143            *y *= m_ky;
144        }
145
146        //-------------------------------------------------------------------
147        void inverse_transform(double* x, double* y) const
148        {
149            *x = (*x - m_dx1) / m_kx + m_wx1;
150            *y = (*y - m_dy1) / m_ky + m_wy1;
151        }
152
153        //-------------------------------------------------------------------
154        void inverse_transform_scale_only(double* x, double* y) const
155        {
156            *x /= m_kx;
157            *y /= m_ky;
158        }
159
160        //-------------------------------------------------------------------
161        double device_dx() const { return m_dx1 - m_wx1 * m_kx; }
162        double device_dy() const { return m_dy1 - m_wy1 * m_ky; }
163
164        //-------------------------------------------------------------------
165        double scale_x() const
166        {
167            return m_kx;
168        }
169
170        //-------------------------------------------------------------------
171        double scale_y() const
172        {
173            return m_ky;
174        }
175
176        //-------------------------------------------------------------------
177        double scale() const
178        {
179            return (m_kx + m_ky) * 0.5;
180        }
181
182        //-------------------------------------------------------------------
183        trans_affine to_affine() const
184        {
185            trans_affine mtx = trans_affine_translation(-m_wx1, -m_wy1);
186            mtx *= trans_affine_scaling(m_kx, m_ky);
187            mtx *= trans_affine_translation(m_dx1, m_dy1);
188            return mtx;
189        }
190
191        //-------------------------------------------------------------------
192        trans_affine to_affine_scale_only() const
193        {
194            return trans_affine_scaling(m_kx, m_ky);
195        }
196
197        //-------------------------------------------------------------------
198        unsigned byte_size() const
199        {
200            return sizeof(*this);
201        }
202
203        void serialize(int8u* ptr) const
204        {
205            memcpy(ptr, this, sizeof(*this));
206        }
207
208        void deserialize(const int8u* ptr)
209        {
210            memcpy(this,  ptr, sizeof(*this));
211        }
212
213    private:
214        void update();
215
216        double         m_world_x1;
217        double         m_world_y1;
218        double         m_world_x2;
219        double         m_world_y2;
220        double         m_device_x1;
221        double         m_device_y1;
222        double         m_device_x2;
223        double         m_device_y2;
224        aspect_ratio_e m_aspect;
225        bool           m_is_valid;
226        double         m_align_x;
227        double         m_align_y;
228        double         m_wx1;
229        double         m_wy1;
230        double         m_wx2;
231        double         m_wy2;
232        double         m_dx1;
233        double         m_dy1;
234        double         m_kx;
235        double         m_ky;
236    };
237
238
239
240    //-----------------------------------------------------------------------
241    inline void trans_viewport::update()
242    {
243        const double epsilon = 1e-30;
244        if(fabs(m_world_x1  - m_world_x2)  < epsilon ||
245           fabs(m_world_y1  - m_world_y2)  < epsilon ||
246           fabs(m_device_x1 - m_device_x2) < epsilon ||
247           fabs(m_device_y1 - m_device_y2) < epsilon)
248        {
249            m_wx1 = m_world_x1;
250            m_wy1 = m_world_y1;
251            m_wx2 = m_world_x1 + 1.0;
252            m_wy2 = m_world_y2 + 1.0;
253            m_dx1 = m_device_x1;
254            m_dy1 = m_device_y1;
255            m_kx  = 1.0;
256            m_ky  = 1.0;
257            m_is_valid = false;
258            return;
259        }
260
261        double world_x1  = m_world_x1;
262        double world_y1  = m_world_y1;
263        double world_x2  = m_world_x2;
264        double world_y2  = m_world_y2;
265        double device_x1 = m_device_x1;
266        double device_y1 = m_device_y1;
267        double device_x2 = m_device_x2;
268        double device_y2 = m_device_y2;
269        if(m_aspect != aspect_ratio_stretch)
270        {
271            double d;
272            m_kx = (device_x2 - device_x1) / (world_x2 - world_x1);
273            m_ky = (device_y2 - device_y1) / (world_y2 - world_y1);
274
275            if((m_aspect == aspect_ratio_meet) == (m_kx < m_ky))
276            {
277                d         = (world_y2 - world_y1) * m_ky / m_kx;
278                world_y1 += (world_y2 - world_y1 - d) * m_align_y;
279                world_y2  =  world_y1 + d;
280            }
281            else
282            {
283                d         = (world_x2 - world_x1) * m_kx / m_ky;
284                world_x1 += (world_x2 - world_x1 - d) * m_align_x;
285                world_x2  =  world_x1 + d;
286            }
287        }
288        m_wx1 = world_x1;
289        m_wy1 = world_y1;
290        m_wx2 = world_x2;
291        m_wy2 = world_y2;
292        m_dx1 = device_x1;
293        m_dy1 = device_y1;
294        m_kx  = (device_x2 - device_x1) / (world_x2 - world_x1);
295        m_ky  = (device_y2 - device_y1) / (world_y2 - world_y1);
296        m_is_valid = true;
297    }
298
299
300}
301
302
303#endif
304