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