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 // if (xScale == 1.0 && yScale == 1.0) 173 // return; 174 // 175 // fXScale *= xScale; 176 // fYScale *= yScale; 177 // 178 // // scale fTranslation 179 // double xOffset = fTranslation.x - origin.x; 180 // double yOffset = fTranslation.y - origin.y; 181 // 182 // fTranslation.x = origin.x + (xOffset * xScale); 183 // fTranslation.y = origin.y + (yOffset * yScale); 184 // 185 // _UpdateMatrix(); 186 //} 187 188 // ScaleBy 189 void 190 ChannelTransform::ScaleBy(double xScale, double yScale) 191 { 192 if (xScale == 1.0 && yScale == 1.0) 193 return; 194 195 fXScale *= xScale; 196 fYScale *= yScale; 197 198 _UpdateMatrix(); 199 } 200 201 202 // SetTranslationAndScale 203 void 204 ChannelTransform::SetTranslationAndScale(BPoint offset, double xScale, 205 double yScale) 206 { 207 if (fTranslation == offset && fXScale == xScale && fYScale == yScale) 208 return; 209 210 fTranslation = offset; 211 212 fXScale = xScale; 213 fYScale = yScale; 214 215 _UpdateMatrix(); 216 } 217 218 219 // Reset 220 void 221 ChannelTransform::Reset() 222 { 223 SetTransformation(B_ORIGIN, B_ORIGIN, 0.0, 1.0, 1.0); 224 } 225 226 227 // = 228 ChannelTransform& 229 ChannelTransform::operator=(const ChannelTransform& other) 230 { 231 fTranslation = other.fTranslation; 232 fRotation = other.fRotation; 233 fXScale = other.fXScale; 234 fYScale = other.fYScale; 235 236 Transformable::operator=(other); 237 238 return *this; 239 } 240 241 242 // _UpdateMatrix 243 void 244 ChannelTransform::_UpdateMatrix() 245 { 246 // fix up scales in case any is zero 247 double xScale = fXScale; 248 if (xScale == 0.0) 249 xScale = 0.000001; 250 double yScale = fYScale; 251 if (yScale == 0.0) 252 yScale = 0.000001; 253 254 // start clean 255 reset(); 256 // the "pivot" is like the offset from world to local 257 // coordinate system and is the center for rotation and scale 258 multiply(agg::trans_affine_translation(-fPivot.x, -fPivot.y)); 259 multiply(agg::trans_affine_scaling(xScale, yScale)); 260 multiply(agg::trans_affine_rotation(fRotation * M_PI / 180.0)); 261 262 multiply(agg::trans_affine_translation(fPivot.x + fTranslation.x, 263 fPivot.y + fTranslation.y)); 264 265 // call hook function 266 Update(); 267 } 268 269