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 15Transformable::Transformable() 16 : agg::trans_affine() 17{ 18} 19 20// copy constructor 21Transformable::Transformable(const Transformable& other) 22 : agg::trans_affine(other) 23{ 24} 25 26// destructor 27Transformable::~Transformable() 28{ 29} 30 31// StoreTo 32void 33Transformable::StoreTo(double matrix[matrix_size]) const 34{ 35 store_to(matrix); 36} 37 38// LoadFrom 39void 40Transformable::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 54void 55Transformable::SetTransform(const Transformable& other) 56{ 57 if (*this != other) { 58 *this = other; 59 TransformationChanged(); 60 } 61} 62 63// operator= 64Transformable& 65Transformable::operator=(const Transformable& other) 66{ 67 if (other != *this) { 68 reset(); 69 multiply(other); 70 TransformationChanged(); 71 } 72 return *this; 73} 74 75// Multiply 76Transformable& 77Transformable::Multiply(const Transformable& other) 78{ 79 if (!other.IsIdentity()) { 80 multiply(other); 81 TransformationChanged(); 82 } 83 return *this; 84} 85 86// Reset 87void 88Transformable::Reset() 89{ 90 if (!IsIdentity()) { 91 reset(); 92 TransformationChanged(); 93 } 94} 95 96// Invert 97void 98Transformable::Invert() 99{ 100 if (!IsIdentity()) { 101 invert(); 102 TransformationChanged(); 103 } 104} 105 106// IsIdentity 107bool 108Transformable::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 123bool 124Transformable::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 137bool 138Transformable::IsNotDistorted() const 139{ 140 double m[matrix_size]; 141 store_to(m); 142 return (m[0] == m[3]); 143} 144 145// IsValid 146bool 147Transformable::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== 155bool 156Transformable::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!= 166bool 167Transformable::operator!=(const Transformable& other) const 168{ 169 return !(*this == other); 170} 171 172// Transform 173void 174Transformable::Transform(double* x, double* y) const 175{ 176 transform(x, y); 177} 178 179// Transform 180void 181Transformable::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 195BPoint 196Transformable::Transform(const BPoint& point) const 197{ 198 BPoint p(point); 199 Transform(&p); 200 return p; 201} 202 203// InverseTransform 204void 205Transformable::InverseTransform(double* x, double* y) const 206{ 207 inverse_transform(x, y); 208} 209 210// InverseTransform 211void 212Transformable::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 226BPoint 227Transformable::InverseTransform(const BPoint& point) const 228{ 229 BPoint p(point); 230 InverseTransform(&p); 231 return p; 232} 233 234inline float 235min4(float a, float b, float c, float d) 236{ 237 return min_c(a, min_c(b, min_c(c, d))); 238} 239 240inline float 241max4(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 247BRect 248Transformable::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 270void 271Transformable::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 280void 281Transformable::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 292void 293Transformable::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 304void 305Transformable::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 316void 317Transformable::TransformationChanged() 318{ 319 // default implementation doesn't care 320} 321 322