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