xref: /haiku/headers/libs/agg/agg_trans_viewport.h (revision 3e216965baa8d58a67bf7372e2bfa13d999f5a9d)
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 
28 namespace 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