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