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