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 16ChannelTransform::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 28ChannelTransform::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 41ChannelTransform::~ChannelTransform() 42{ 43} 44 45 46// SetTransformation 47void 48ChannelTransform::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 73void 74ChannelTransform::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 99void 100ChannelTransform::SetPivot(BPoint pivot) 101{ 102 if (pivot == fPivot) 103 return; 104 105 fPivot = pivot; 106 107 _UpdateMatrix(); 108} 109 110 111// TranslateBy 112void 113ChannelTransform::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*/ 128void 129ChannelTransform::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 153void 154ChannelTransform::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 169void 170ChannelTransform::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 190void 191ChannelTransform::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 204void 205ChannelTransform::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 221void 222ChannelTransform::Reset() 223{ 224 SetTransformation(B_ORIGIN, B_ORIGIN, 0.0, 1.0, 1.0); 225} 226 227 228// = 229ChannelTransform& 230ChannelTransform::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 244void 245ChannelTransform::_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