Transform.cpp revision 29a367bb7c14c916e991a6a0028727bd06c1e16e
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <math.h> 18 19#include <cutils/compiler.h> 20#include <utils/String8.h> 21#include <ui/Region.h> 22 23#include "Transform.h" 24 25// --------------------------------------------------------------------------- 26 27namespace android { 28 29// --------------------------------------------------------------------------- 30 31template <typename T> 32static inline T min(T a, T b) { 33 return a<b ? a : b; 34} 35template <typename T> 36static inline T min(T a, T b, T c) { 37 return min(a, min(b, c)); 38} 39template <typename T> 40static inline T min(T a, T b, T c, T d) { 41 return min(a, b, min(c, d)); 42} 43 44template <typename T> 45static inline T max(T a, T b) { 46 return a>b ? a : b; 47} 48template <typename T> 49static inline T max(T a, T b, T c) { 50 return max(a, max(b, c)); 51} 52template <typename T> 53static inline T max(T a, T b, T c, T d) { 54 return max(a, b, max(c, d)); 55} 56 57template <typename T> 58static inline 59void swap(T& a, T& b) { 60 T t(a); 61 a = b; 62 b = t; 63} 64 65// --------------------------------------------------------------------------- 66 67Transform::Transform() { 68 reset(); 69} 70 71Transform::Transform(const Transform& other) 72 : mMatrix(other.mMatrix), mType(other.mType) { 73} 74 75Transform::Transform(uint32_t orientation) { 76 set(orientation, 0, 0); 77} 78 79Transform::~Transform() { 80} 81 82static const float EPSILON = 0.0f; 83 84bool Transform::isZero(float f) { 85 return fabs(f) <= EPSILON; 86} 87 88bool Transform::absIsOne(float f) { 89 return isZero(fabs(f) - 1.0f); 90} 91 92Transform Transform::operator * (const Transform& rhs) const 93{ 94 if (CC_LIKELY(mType == IDENTITY)) 95 return rhs; 96 97 Transform r(*this); 98 if (rhs.mType == IDENTITY) 99 return r; 100 101 // TODO: we could use mType to optimize the matrix multiply 102 const mat33& A(mMatrix); 103 const mat33& B(rhs.mMatrix); 104 mat33& D(r.mMatrix); 105 for (int i=0 ; i<3 ; i++) { 106 const float v0 = A[0][i]; 107 const float v1 = A[1][i]; 108 const float v2 = A[2][i]; 109 D[0][i] = v0*B[0][0] + v1*B[0][1] + v2*B[0][2]; 110 D[1][i] = v0*B[1][0] + v1*B[1][1] + v2*B[1][2]; 111 D[2][i] = v0*B[2][0] + v1*B[2][1] + v2*B[2][2]; 112 } 113 r.mType |= rhs.mType; 114 115 // TODO: we could recompute this value from r and rhs 116 r.mType &= 0xFF; 117 r.mType |= UNKNOWN_TYPE; 118 return r; 119} 120 121float const* Transform::operator [] (int i) const { 122 return mMatrix[i].v; 123} 124 125bool Transform::transformed() const { 126 return type() > TRANSLATE; 127} 128 129int Transform::tx() const { 130 return floorf(mMatrix[2][0] + 0.5f); 131} 132 133int Transform::ty() const { 134 return floorf(mMatrix[2][1] + 0.5f); 135} 136 137void Transform::reset() { 138 mType = IDENTITY; 139 for(int i=0 ; i<3 ; i++) { 140 vec3& v(mMatrix[i]); 141 for (int j=0 ; j<3 ; j++) 142 v[j] = ((i==j) ? 1.0f : 0.0f); 143 } 144} 145 146void Transform::set(float tx, float ty) 147{ 148 mMatrix[2][0] = tx; 149 mMatrix[2][1] = ty; 150 mMatrix[2][2] = 1.0f; 151 152 if (isZero(tx) && isZero(ty)) { 153 mType &= ~TRANSLATE; 154 } else { 155 mType |= TRANSLATE; 156 } 157} 158 159void Transform::set(float a, float b, float c, float d) 160{ 161 mat33& M(mMatrix); 162 M[0][0] = a; M[1][0] = b; 163 M[0][1] = c; M[1][1] = d; 164 M[0][2] = 0; M[1][2] = 0; 165 mType = UNKNOWN_TYPE; 166} 167 168status_t Transform::set(uint32_t flags, float w, float h) 169{ 170 if (flags & ROT_INVALID) { 171 // that's not allowed! 172 reset(); 173 return BAD_VALUE; 174 } 175 176 Transform H, V, R; 177 if (flags & ROT_90) { 178 // w & h are inverted when rotating by 90 degrees 179 swap(w, h); 180 } 181 182 if (flags & FLIP_H) { 183 H.mType = (FLIP_H << 8) | SCALE; 184 H.mType |= isZero(w) ? IDENTITY : TRANSLATE; 185 mat33& M(H.mMatrix); 186 M[0][0] = -1; 187 M[2][0] = w; 188 } 189 190 if (flags & FLIP_V) { 191 V.mType = (FLIP_V << 8) | SCALE; 192 V.mType |= isZero(h) ? IDENTITY : TRANSLATE; 193 mat33& M(V.mMatrix); 194 M[1][1] = -1; 195 M[2][1] = h; 196 } 197 198 if (flags & ROT_90) { 199 const float original_w = h; 200 R.mType = (ROT_90 << 8) | ROTATE; 201 R.mType |= isZero(original_w) ? IDENTITY : TRANSLATE; 202 mat33& M(R.mMatrix); 203 M[0][0] = 0; M[1][0] =-1; M[2][0] = original_w; 204 M[0][1] = 1; M[1][1] = 0; 205 } 206 207 *this = (R*(H*V)); 208 return NO_ERROR; 209} 210 211Transform::vec2 Transform::transform(const vec2& v) const { 212 vec2 r; 213 const mat33& M(mMatrix); 214 r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]; 215 r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]; 216 return r; 217} 218 219Transform::vec3 Transform::transform(const vec3& v) const { 220 vec3 r; 221 const mat33& M(mMatrix); 222 r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]*v[2]; 223 r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]*v[2]; 224 r[2] = M[0][2]*v[0] + M[1][2]*v[1] + M[2][2]*v[2]; 225 return r; 226} 227 228void Transform::transform(float* point, int x, int y) const 229{ 230 const mat33& M(mMatrix); 231 vec2 v(x, y); 232 v = transform(v); 233 point[0] = v[0]; 234 point[1] = v[1]; 235} 236 237Rect Transform::makeBounds(int w, int h) const 238{ 239 return transform( Rect(w, h) ); 240} 241 242Rect Transform::transform(const Rect& bounds) const 243{ 244 Rect r; 245 vec2 lt( bounds.left, bounds.top ); 246 vec2 rt( bounds.right, bounds.top ); 247 vec2 lb( bounds.left, bounds.bottom ); 248 vec2 rb( bounds.right, bounds.bottom ); 249 250 lt = transform(lt); 251 rt = transform(rt); 252 lb = transform(lb); 253 rb = transform(rb); 254 255 r.left = floorf(min(lt[0], rt[0], lb[0], rb[0]) + 0.5f); 256 r.top = floorf(min(lt[1], rt[1], lb[1], rb[1]) + 0.5f); 257 r.right = floorf(max(lt[0], rt[0], lb[0], rb[0]) + 0.5f); 258 r.bottom = floorf(max(lt[1], rt[1], lb[1], rb[1]) + 0.5f); 259 260 return r; 261} 262 263Region Transform::transform(const Region& reg) const 264{ 265 Region out; 266 if (CC_UNLIKELY(transformed())) { 267 if (CC_LIKELY(preserveRects())) { 268 Region::const_iterator it = reg.begin(); 269 Region::const_iterator const end = reg.end(); 270 while (it != end) { 271 out.orSelf(transform(*it++)); 272 } 273 } else { 274 out.set(transform(reg.bounds())); 275 } 276 } else { 277 out = reg.translate(tx(), ty()); 278 } 279 return out; 280} 281 282uint32_t Transform::type() const 283{ 284 if (mType & UNKNOWN_TYPE) { 285 // recompute what this transform is 286 287 const mat33& M(mMatrix); 288 const float a = M[0][0]; 289 const float b = M[1][0]; 290 const float c = M[0][1]; 291 const float d = M[1][1]; 292 const float x = M[2][0]; 293 const float y = M[2][1]; 294 295 bool scale = false; 296 uint32_t flags = ROT_0; 297 if (isZero(b) && isZero(c)) { 298 if (a<0) flags |= FLIP_H; 299 if (d<0) flags |= FLIP_V; 300 if (!absIsOne(a) || !absIsOne(d)) { 301 scale = true; 302 } 303 } else if (isZero(a) && isZero(d)) { 304 flags |= ROT_90; 305 if (b>0) flags |= FLIP_V; 306 if (c<0) flags |= FLIP_H; 307 if (!absIsOne(b) || !absIsOne(c)) { 308 scale = true; 309 } 310 } else { 311 // there is a skew component and/or a non 90 degrees rotation 312 flags = ROT_INVALID; 313 } 314 315 mType = flags << 8; 316 if (flags & ROT_INVALID) { 317 mType |= UNKNOWN; 318 } else { 319 if ((flags & ROT_90) || ((flags & ROT_180) == ROT_180)) 320 mType |= ROTATE; 321 if (flags & FLIP_H) 322 mType ^= SCALE; 323 if (flags & FLIP_V) 324 mType ^= SCALE; 325 if (scale) 326 mType |= SCALE; 327 } 328 329 if (!isZero(x) || !isZero(y)) 330 mType |= TRANSLATE; 331 } 332 return mType; 333} 334 335uint32_t Transform::getType() const { 336 return type() & 0xFF; 337} 338 339uint32_t Transform::getOrientation() const 340{ 341 return (type() >> 8) & 0xFF; 342} 343 344bool Transform::preserveRects() const 345{ 346 return (type() & ROT_INVALID) ? false : true; 347} 348 349void Transform::dump(const char* name) const 350{ 351 type(); // updates the type 352 353 String8 flags, type; 354 const mat33& m(mMatrix); 355 uint32_t orient = mType >> 8; 356 357 if (orient&ROT_INVALID) { 358 flags.append("ROT_INVALID "); 359 } else { 360 if (orient&ROT_90) { 361 flags.append("ROT_90 "); 362 } else { 363 flags.append("ROT_0 "); 364 } 365 if (orient&FLIP_V) 366 flags.append("FLIP_V "); 367 if (orient&FLIP_H) 368 flags.append("FLIP_H "); 369 } 370 371 if (!(mType&(SCALE|ROTATE|TRANSLATE))) 372 type.append("IDENTITY "); 373 if (mType&SCALE) 374 type.append("SCALE "); 375 if (mType&ROTATE) 376 type.append("ROTATE "); 377 if (mType&TRANSLATE) 378 type.append("TRANSLATE "); 379 380 LOGD("%s 0x%08x (%s, %s)", name, mType, flags.string(), type.string()); 381 LOGD("%.4f %.4f %.4f", m[0][0], m[1][0], m[2][0]); 382 LOGD("%.4f %.4f %.4f", m[0][1], m[1][1], m[2][1]); 383 LOGD("%.4f %.4f %.4f", m[0][2], m[1][2], m[2][2]); 384} 385 386// --------------------------------------------------------------------------- 387 388}; // namespace android 389