1 /* 2 * Copyright 2006, 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 reset(); 91 } 92 93 // Invert 94 void 95 Transformable::Invert() 96 { 97 invert(); 98 } 99 100 // IsIdentity 101 bool 102 Transformable::IsIdentity() const 103 { 104 double m[matrix_size]; 105 store_to(m); 106 if (m[0] == 1.0 && 107 m[1] == 0.0 && 108 m[2] == 0.0 && 109 m[3] == 1.0 && 110 m[4] == 0.0 && 111 m[5] == 0.0) 112 return true; 113 return false; 114 } 115 116 // IsTranslationOnly 117 bool 118 Transformable::IsTranslationOnly() const 119 { 120 double m[matrix_size]; 121 store_to(m); 122 if (m[0] == 1.0 && 123 m[1] == 0.0 && 124 m[2] == 0.0 && 125 m[3] == 1.0) 126 return true; 127 return false; 128 } 129 130 // IsNotDistorted 131 bool 132 Transformable::IsNotDistorted() const 133 { 134 double m[matrix_size]; 135 store_to(m); 136 return (m[0] == m[3]); 137 } 138 139 // IsValid 140 bool 141 Transformable::IsValid() const 142 { 143 double m[matrix_size]; 144 store_to(m); 145 return ((m[0] * m[3] - m[1] * m[2]) != 0.0); 146 } 147 148 // operator== 149 bool 150 Transformable::operator==(const Transformable& other) const 151 { 152 double m1[matrix_size]; 153 other.store_to(m1); 154 double m2[matrix_size]; 155 store_to(m2); 156 return memcmp(m1, m2, sizeof(m1)) == 0; 157 } 158 159 // operator!= 160 bool 161 Transformable::operator!=(const Transformable& other) const 162 { 163 return !(*this == other); 164 } 165 166 // Transform 167 void 168 Transformable::Transform(double* x, double* y) const 169 { 170 transform(x, y); 171 } 172 173 // Transform 174 void 175 Transformable::Transform(BPoint* point) const 176 { 177 if (point) { 178 double x = point->x; 179 double y = point->y; 180 181 transform(&x, &y); 182 183 point->x = x; 184 point->y = y; 185 } 186 } 187 188 // Transform 189 BPoint 190 Transformable::Transform(const BPoint& point) const 191 { 192 BPoint p(point); 193 Transform(&p); 194 return p; 195 } 196 197 // InverseTransform 198 void 199 Transformable::InverseTransform(double* x, double* y) const 200 { 201 inverse_transform(x, y); 202 } 203 204 // InverseTransform 205 void 206 Transformable::InverseTransform(BPoint* point) const 207 { 208 if (point) { 209 double x = point->x; 210 double y = point->y; 211 212 inverse_transform(&x, &y); 213 214 point->x = x; 215 point->y = y; 216 } 217 } 218 219 // InverseTransform 220 BPoint 221 Transformable::InverseTransform(const BPoint& point) const 222 { 223 BPoint p(point); 224 InverseTransform(&p); 225 return p; 226 } 227 228 inline float 229 min4(float a, float b, float c, float d) 230 { 231 return min_c(a, min_c(b, min_c(c, d))); 232 } 233 234 inline float 235 max4(float a, float b, float c, float d) 236 { 237 return max_c(a, max_c(b, max_c(c, d))); 238 } 239 240 // TransformBounds 241 BRect 242 Transformable::TransformBounds(BRect bounds) const 243 { 244 if (bounds.IsValid()) { 245 BPoint lt(bounds.left, bounds.top); 246 BPoint rt(bounds.right, bounds.top); 247 BPoint lb(bounds.left, bounds.bottom); 248 BPoint rb(bounds.right, bounds.bottom); 249 250 Transform(<); 251 Transform(&rt); 252 Transform(&lb); 253 Transform(&rb); 254 255 return BRect(floorf(min4(lt.x, rt.x, lb.x, rb.x)), 256 floorf(min4(lt.y, rt.y, lb.y, rb.y)), 257 ceilf(max4(lt.x, rt.x, lb.x, rb.x)), 258 ceilf(max4(lt.y, rt.y, lb.y, rb.y))); 259 } 260 return bounds; 261 } 262 263 // TranslateBy 264 void 265 Transformable::TranslateBy(BPoint offset) 266 { 267 if (offset.x != 0.0 || offset.y != 0.0) { 268 multiply(agg::trans_affine_translation(offset.x, offset.y)); 269 TransformationChanged(); 270 } 271 } 272 273 // RotateBy 274 void 275 Transformable::RotateBy(BPoint origin, double degrees) 276 { 277 if (degrees != 0.0) { 278 multiply(agg::trans_affine_translation(-origin.x, -origin.y)); 279 multiply(agg::trans_affine_rotation(degrees * (PI / 180.0))); 280 multiply(agg::trans_affine_translation(origin.x, origin.y)); 281 TransformationChanged(); 282 } 283 } 284 285 // ScaleBy 286 void 287 Transformable::ScaleBy(BPoint origin, double xScale, double yScale) 288 { 289 if (xScale != 1.0 || yScale != 1.0) { 290 multiply(agg::trans_affine_translation(-origin.x, -origin.y)); 291 multiply(agg::trans_affine_scaling(xScale, yScale)); 292 multiply(agg::trans_affine_translation(origin.x, origin.y)); 293 TransformationChanged(); 294 } 295 } 296 297 // ShearBy 298 void 299 Transformable::ShearBy(BPoint origin, double xShear, double yShear) 300 { 301 if (xShear != 0.0 || yShear != 0.0) { 302 multiply(agg::trans_affine_translation(-origin.x, -origin.y)); 303 multiply(agg::trans_affine_skewing(xShear, yShear)); 304 multiply(agg::trans_affine_translation(origin.x, origin.y)); 305 TransformationChanged(); 306 } 307 } 308 309 // TransformationChanged 310 void 311 Transformable::TransformationChanged() 312 { 313 // default implementation doesn't care 314 } 315 316