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