13d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips/* 23d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips * Copyright 2015 Google Inc. 33d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips * 43d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips * Use of this source code is governed by a BSD-style license that can be 53d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips * found in the LICENSE file. 63d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips */ 73d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips 83d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips#include "SkPoint3.h" 93d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips 103d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips// Returns the square of the Euclidian distance to (x,y,z). 113d32d768cd8b66c49c070495c08f7933b9dd2423robertphillipsstatic inline float get_length_squared(float x, float y, float z) { 123d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips return x * x + y * y + z * z; 133d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips} 143d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips 153d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips// Calculates the square of the Euclidian distance to (x,y,z) and stores it in 163d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips// *lengthSquared. Returns true if the distance is judged to be "nearly zero". 173d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips// 183d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips// This logic is encapsulated in a helper method to make it explicit that we 193d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips// always perform this check in the same manner, to avoid inconsistencies 203d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips// (see http://code.google.com/p/skia/issues/detail?id=560 ). 213d32d768cd8b66c49c070495c08f7933b9dd2423robertphillipsstatic inline bool is_length_nearly_zero(float x, float y, float z, float *lengthSquared) { 223d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips *lengthSquared = get_length_squared(x, y, z); 233d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero); 243d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips} 253d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips 263d32d768cd8b66c49c070495c08f7933b9dd2423robertphillipsSkScalar SkPoint3::Length(SkScalar x, SkScalar y, SkScalar z) { 273d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips float magSq = get_length_squared(x, y, z); 283d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips if (SkScalarIsFinite(magSq)) { 293d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips return sk_float_sqrt(magSq); 303d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips } else { 313d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips double xx = x; 323d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips double yy = y; 333d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips double zz = z; 343d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips return (float)sqrt(xx * xx + yy * yy + zz * zz); 353d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips } 363d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips} 373d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips 383d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips/* 393d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips * We have to worry about 2 tricky conditions: 403d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips * 1. underflow of magSq (compared against nearlyzero^2) 413d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips * 2. overflow of magSq (compared w/ isfinite) 423d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips * 433d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips * If we underflow, we return false. If we overflow, we compute again using 443d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips * doubles, which is much slower (3x in a desktop test) but will not overflow. 453d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips */ 463d32d768cd8b66c49c070495c08f7933b9dd2423robertphillipsbool SkPoint3::normalize() { 473d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips float magSq; 483d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips if (is_length_nearly_zero(fX, fY, fZ, &magSq)) { 493d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips this->set(0, 0, 0); 503d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips return false; 513d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips } 523d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips 533d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips float scale; 543d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips if (SkScalarIsFinite(magSq)) { 553d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips scale = 1.0f / sk_float_sqrt(magSq); 563d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips } else { 573d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips // our magSq step overflowed to infinity, so use doubles instead. 583d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips // much slower, but needed when x, y or z is very large, otherwise we 593d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips // divide by inf. and return (0,0,0) vector. 603d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips double xx = fX; 613d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips double yy = fY; 623d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips double zz = fZ; 633d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips#ifdef SK_CPU_FLUSH_TO_ZERO 643d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips // The iOS ARM processor discards small denormalized numbers to go faster. 653d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips // Casting this to a float would cause the scale to go to zero. Keeping it 663d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips // as a double for the multiply keeps the scale non-zero. 673d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips double dscale = 1.0f / sqrt(xx * xx + yy * yy + zz * zz); 683d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips fX = x * dscale; 693d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips fY = y * dscale; 703d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips fZ = z * dscale; 713d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips return true; 723d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips#else 733d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips scale = (float)(1.0f / sqrt(xx * xx + yy * yy + zz * zz)); 743d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips#endif 753d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips } 763d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips fX *= scale; 773d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips fY *= scale; 783d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips fZ *= scale; 793d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips return true; 803d32d768cd8b66c49c070495c08f7933b9dd2423robertphillips} 81