1 /* 2 * Copyright 2006-2009, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9 #include "Transformable.h" 10 11 #include <stdio.h> 12 #include <string.h> 13 14 // constructor 15 Transformable::Transformable() 16 : agg::trans_affine() 17 { 18 } 19 20 // copy constructor 21 Transformable::Transformable(const Transformable& other) 22 : agg::trans_affine(other) 23 { 24 } 25 26 // destructor 27 Transformable::~Transformable() 28 { 29 } 30 31 // StoreTo 32 void 33 Transformable::StoreTo(double matrix[matrix_size]) const 34 { 35 store_to(matrix); 36 } 37 38 // LoadFrom 39 void 40 Transformable::LoadFrom(const double matrix[matrix_size]) 41 { 42 // before calling the potentially heavy TransformationChanged() 43 // hook function, make sure that the transformation 44 // really changed 45 Transformable t; 46 t.load_from(matrix); 47 if (*this != t) { 48 load_from(matrix); 49 TransformationChanged(); 50 } 51 } 52 53 // SetTransform 54 void 55 Transformable::SetTransform(const Transformable& other) 56 { 57 if (*this != other) { 58 *this = other; 59 TransformationChanged(); 60 } 61 } 62 63 // operator= 64 Transformable& 65 Transformable::operator=(const Transformable& other) 66 { 67 if (other != *this) { 68 reset(); 69 multiply(other); 70 TransformationChanged(); 71 } 72 return *this; 73 } 74 75 // Multiply 76 Transformable& 77 Transformable::Multiply(const Transformable& other) 78 { 79 if (!other.IsIdentity()) { 80 multiply(other); 81 TransformationChanged(); 82 } 83 return *this; 84 } 85 86 // Reset 87 void 88 Transformable::Reset() 89 { 90 if (!IsIdentity()) { 91 reset(); 92 TransformationChanged(); 93 } 94 } 95 96 // Invert 97 void 98 Transformable::Invert() 99 { 100 if (!IsIdentity()) { 101 invert(); 102 TransformationChanged(); 103 } 104 } 105 106 // IsIdentity 107 bool 108 Transformable::IsIdentity() const 109 { 110 double m[matrix_size]; 111 store_to(m); 112 if (m[0] == 1.0 && 113 m[1] == 0.0 && 114 m[2] == 0.0 && 115 m[3] == 1.0 && 116 m[4] == 0.0 && 117 m[5] == 0.0) 118 return true; 119 return false; 120 } 121 122 // IsTranslationOnly 123 bool 124 Transformable::IsTranslationOnly() const 125 { 126 double m[matrix_size]; 127 store_to(m); 128 if (m[0] == 1.0 && 129 m[1] == 0.0 && 130 m[2] == 0.0 && 131 m[3] == 1.0) 132 return true; 133 return false; 134 } 135 136 // IsNotDistorted 137 bool 138 Transformable::IsNotDistorted() const 139 { 140 double m[matrix_size]; 141 store_to(m); 142 return (m[0] == m[3]); 143 } 144 145 // IsValid 146 bool 147 Transformable::IsValid() const 148 { 149 double m[matrix_size]; 150 store_to(m); 151 return ((m[0] * m[3] - m[1] * m[2]) != 0.0); 152 } 153 154 // operator== 155 bool 156 Transformable::operator==(const Transformable& other) const 157 { 158 double m1[matrix_size]; 159 other.store_to(m1); 160 double m2[matrix_size]; 161 store_to(m2); 162 return memcmp(m1, m2, sizeof(m1)) == 0; 163 } 164 165 // operator!= 166 bool 167 Transformable::operator!=(const Transformable& other) const 168 { 169 return !(*this == other); 170 } 171 172 // Transform 173 void 174 Transformable::Transform(double* x, double* y) const 175 { 176 transform(x, y); 177 } 178 179 // Transform 180 void 181 Transformable::Transform(BPoint* point) const 182 { 183 if (point) { 184 double x = point->x; 185 double y = point->y; 186 187 transform(&x, &y); 188 189 point->x = x; 190 point->y = y; 191 } 192 } 193 194 // Transform 195 BPoint 196 Transformable::Transform(const BPoint& point) const 197 { 198 BPoint p(point); 199 Transform(&p); 200 return p; 201 } 202 203 // InverseTransform 204 void 205 Transformable::InverseTransform(double* x, double* y) const 206 { 207 inverse_transform(x, y); 208 } 209 210 // InverseTransform 211 void 212 Transformable::InverseTransform(BPoint* point) const 213 { 214 if (point) { 215 double x = point->x; 216 double y = point->y; 217 218 inverse_transform(&x, &y); 219 220 point->x = x; 221 point->y = y; 222 } 223 } 224 225 // InverseTransform 226 BPoint 227 Transformable::InverseTransform(const BPoint& point) const 228 { 229 BPoint p(point); 230 InverseTransform(&p); 231 return p; 232 } 233 234 inline float 235 min4(float a, float b, float c, float d) 236 { 237 return min_c(a, min_c(b, min_c(c, d))); 238 } 239 240 inline float 241 max4(float a, float b, float c, float d) 242 { 243 return max_c(a, max_c(b, max_c(c, d))); 244 } 245 246 // TransformBounds 247 BRect 248 Transformable::TransformBounds(BRect bounds) const 249 { 250 if (bounds.IsValid()) { 251 BPoint lt(bounds.left, bounds.top); 252 BPoint rt(bounds.right, bounds.top); 253 BPoint lb(bounds.left, bounds.bottom); 254 BPoint rb(bounds.right, bounds.bottom); 255 256 Transform(<); 257 Transform(&rt); 258 Transform(&lb); 259 Transform(&rb); 260 261 return BRect(floorf(min4(lt.x, rt.x, lb.x, rb.x)), 262 floorf(min4(lt.y, rt.y, lb.y, rb.y)), 263 ceilf(max4(lt.x, rt.x, lb.x, rb.x)), 264 ceilf(max4(lt.y, rt.y, lb.y, rb.y))); 265 } 266 return bounds; 267 } 268 269 // TranslateBy 270 void 271 Transformable::TranslateBy(BPoint offset) 272 { 273 if (offset.x != 0.0 || offset.y != 0.0) { 274 multiply(agg::trans_affine_translation(offset.x, offset.y)); 275 TransformationChanged(); 276 } 277 } 278 279 // RotateBy 280 void 281 Transformable::RotateBy(BPoint origin, double degrees) 282 { 283 if (degrees != 0.0) { 284 multiply(agg::trans_affine_translation(-origin.x, -origin.y)); 285 multiply(agg::trans_affine_rotation(degrees * (M_PI / 180.0))); 286 multiply(agg::trans_affine_translation(origin.x, origin.y)); 287 TransformationChanged(); 288 } 289 } 290 291 // ScaleBy 292 void 293 Transformable::ScaleBy(BPoint origin, double xScale, double yScale) 294 { 295 if (xScale != 1.0 || yScale != 1.0) { 296 multiply(agg::trans_affine_translation(-origin.x, -origin.y)); 297 multiply(agg::trans_affine_scaling(xScale, yScale)); 298 multiply(agg::trans_affine_translation(origin.x, origin.y)); 299 TransformationChanged(); 300 } 301 } 302 303 // ShearBy 304 void 305 Transformable::ShearBy(BPoint origin, double xShear, double yShear) 306 { 307 if (xShear != 0.0 || yShear != 0.0) { 308 multiply(agg::trans_affine_translation(-origin.x, -origin.y)); 309 multiply(agg::trans_affine_skewing(xShear, yShear)); 310 multiply(agg::trans_affine_translation(origin.x, origin.y)); 311 TransformationChanged(); 312 } 313 } 314 315 // TransformationChanged 316 void 317 Transformable::TransformationChanged() 318 { 319 // default implementation doesn't care 320 } 321 322