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 "ChannelTransform.h" 10 11 #include <math.h> 12 #include <stdio.h> 13 14 15 // constructor 16 ChannelTransform::ChannelTransform() 17 : 18 Transformable(), 19 fPivot(0.0, 0.0), 20 fTranslation(0.0, 0.0), 21 fRotation(0.0), 22 fXScale(1.0), 23 fYScale(1.0) 24 { 25 } 26 27 // copy constructor 28 ChannelTransform::ChannelTransform(const ChannelTransform& other) 29 : 30 Transformable(other), 31 fPivot(other.fPivot), 32 fTranslation(other.fTranslation), 33 fRotation(other.fRotation), 34 fXScale(other.fXScale), 35 fYScale(other.fYScale) 36 { 37 } 38 39 40 // destructor 41 ChannelTransform::~ChannelTransform() 42 { 43 } 44 45 46 // SetTransformation 47 void 48 ChannelTransform::SetTransformation(const Transformable& other) 49 { 50 // calc affine parameters 51 52 // translation 53 double tx; 54 double ty; 55 other.translation(&tx, &ty); 56 57 // rotation 58 double rotation = agg::rad2deg(other.rotation()); 59 60 // scale 61 double scaleX; 62 double scaleY; 63 other.scaling(&scaleX, &scaleY); 64 65 if (isnanf(tx) || isnanf(ty) || isnanf(scaleX) || isnanf(scaleY)) 66 return; 67 68 SetTransformation(B_ORIGIN, BPoint(tx, ty), rotation, scaleX, scaleY); 69 } 70 71 72 // SetTransformation 73 void 74 ChannelTransform::SetTransformation(BPoint pivot, BPoint translation, 75 double rotation, double xScale, double yScale) 76 { 77 //printf("SetTransformation(BPoint(%.1f, %.1f), BPoint(%.1f, %.1f), " 78 //"%.2f, %.2f, %.2f)\n", pivot.x, pivot.y, translation.x, translation.y, 79 //rotation, xScale, yScale); 80 81 if (fTranslation != translation || 82 fPivot != pivot || 83 fRotation != rotation || 84 fXScale != xScale || 85 fYScale != yScale) { 86 87 fPivot = pivot; 88 fTranslation = translation; 89 fRotation = rotation; 90 fXScale = xScale; 91 fYScale = yScale; 92 93 _UpdateMatrix(); 94 } 95 } 96 97 98 // SetPivot 99 void 100 ChannelTransform::SetPivot(BPoint pivot) 101 { 102 if (pivot == fPivot) 103 return; 104 105 fPivot = pivot; 106 107 _UpdateMatrix(); 108 } 109 110 111 // TranslateBy 112 void 113 ChannelTransform::TranslateBy(BPoint offset) 114 { 115 if (offset.x == 0.0 && offset.y == 0.0) 116 return; 117 118 fTranslation += offset; 119 120 _UpdateMatrix(); 121 } 122 123 124 // RotateBy 125 /*! Converts a rotation in world coordinates into 126 a combined local rotation and a translation. 127 */ 128 void 129 ChannelTransform::RotateBy(BPoint origin, double degrees) 130 { 131 if (degrees == 0.0) 132 return; 133 134 origin -= fPivot; 135 136 fRotation += degrees; 137 138 // rotate fTranslation 139 double xOffset = fTranslation.x - origin.x; 140 double yOffset = fTranslation.y - origin.y; 141 142 agg::trans_affine_rotation m(degrees * M_PI / 180.0); 143 m.transform(&xOffset, &yOffset); 144 145 fTranslation.x = origin.x + xOffset; 146 fTranslation.y = origin.y + yOffset; 147 148 _UpdateMatrix(); 149 } 150 151 152 // RotateBy 153 void 154 ChannelTransform::RotateBy(double degrees) 155 { 156 if (degrees == 0.0) 157 return; 158 159 fRotation += degrees; 160 161 _UpdateMatrix(); 162 } 163 164 165 // ScaleBy 166 // 167 // converts a scalation in world coordinates into 168 // a combined local scalation and a translation 169 void 170 ChannelTransform::ScaleBy(BPoint origin, double xScale, double yScale) 171 { 172 // TODO: Untested? 173 if (xScale == 1.0 && yScale == 1.0) 174 return; 175 176 fXScale *= xScale; 177 fYScale *= yScale; 178 179 // scale fTranslation 180 double xOffset = fTranslation.x - origin.x; 181 double yOffset = fTranslation.y - origin.y; 182 183 fTranslation.x = origin.x + (xOffset * xScale); 184 fTranslation.y = origin.y + (yOffset * yScale); 185 186 _UpdateMatrix(); 187 } 188 189 // ScaleBy 190 void 191 ChannelTransform::ScaleBy(double xScale, double yScale) 192 { 193 if (xScale == 1.0 && yScale == 1.0) 194 return; 195 196 fXScale *= xScale; 197 fYScale *= yScale; 198 199 _UpdateMatrix(); 200 } 201 202 203 // SetTranslationAndScale 204 void 205 ChannelTransform::SetTranslationAndScale(BPoint offset, double xScale, 206 double yScale) 207 { 208 if (fTranslation == offset && fXScale == xScale && fYScale == yScale) 209 return; 210 211 fTranslation = offset; 212 213 fXScale = xScale; 214 fYScale = yScale; 215 216 _UpdateMatrix(); 217 } 218 219 220 // Reset 221 void 222 ChannelTransform::Reset() 223 { 224 SetTransformation(B_ORIGIN, B_ORIGIN, 0.0, 1.0, 1.0); 225 } 226 227 228 // = 229 ChannelTransform& 230 ChannelTransform::operator=(const ChannelTransform& other) 231 { 232 fTranslation = other.fTranslation; 233 fRotation = other.fRotation; 234 fXScale = other.fXScale; 235 fYScale = other.fYScale; 236 237 Transformable::operator=(other); 238 239 return *this; 240 } 241 242 243 // _UpdateMatrix 244 void 245 ChannelTransform::_UpdateMatrix() 246 { 247 // fix up scales in case any is zero 248 double xScale = fXScale; 249 if (xScale == 0.0) 250 xScale = 0.000001; 251 double yScale = fYScale; 252 if (yScale == 0.0) 253 yScale = 0.000001; 254 255 // start clean 256 reset(); 257 // the "pivot" is like the offset from world to local 258 // coordinate system and is the center for rotation and scale 259 multiply(agg::trans_affine_translation(-fPivot.x, -fPivot.y)); 260 multiply(agg::trans_affine_scaling(xScale, yScale)); 261 multiply(agg::trans_affine_rotation(fRotation * M_PI / 180.0)); 262 263 multiply(agg::trans_affine_translation(fPivot.x + fTranslation.x, 264 fPivot.y + fTranslation.y)); 265 266 // call hook function 267 Update(); 268 } 269 270