1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkPoint3.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci// Returns the square of the Euclidian distance to (x,y,z). 11cb93a386Sopenharmony_cistatic inline float get_length_squared(float x, float y, float z) { 12cb93a386Sopenharmony_ci return x * x + y * y + z * z; 13cb93a386Sopenharmony_ci} 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ci// Calculates the square of the Euclidian distance to (x,y,z) and stores it in 16cb93a386Sopenharmony_ci// *lengthSquared. Returns true if the distance is judged to be "nearly zero". 17cb93a386Sopenharmony_ci// 18cb93a386Sopenharmony_ci// This logic is encapsulated in a helper method to make it explicit that we 19cb93a386Sopenharmony_ci// always perform this check in the same manner, to avoid inconsistencies 20cb93a386Sopenharmony_ci// (see http://code.google.com/p/skia/issues/detail?id=560 ). 21cb93a386Sopenharmony_cistatic inline bool is_length_nearly_zero(float x, float y, float z, float *lengthSquared) { 22cb93a386Sopenharmony_ci *lengthSquared = get_length_squared(x, y, z); 23cb93a386Sopenharmony_ci return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero); 24cb93a386Sopenharmony_ci} 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_civoid SkPoint3::dump(std::string& desc, int depth) const { 27cb93a386Sopenharmony_ci std::string split(depth, '\t'); 28cb93a386Sopenharmony_ci desc += split + "\n SkPoint3:{ \n"; 29cb93a386Sopenharmony_ci desc += split + "\t fX: " + std::to_string(fX) + "\n"; 30cb93a386Sopenharmony_ci desc += split + "\t fY: " + std::to_string(fY) + "\n"; 31cb93a386Sopenharmony_ci desc += split + "\t fZ: " + std::to_string(fZ) + "\n"; 32cb93a386Sopenharmony_ci desc += split + "}\n"; 33cb93a386Sopenharmony_ci} 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ciSkScalar SkPoint3::Length(SkScalar x, SkScalar y, SkScalar z) { 36cb93a386Sopenharmony_ci float magSq = get_length_squared(x, y, z); 37cb93a386Sopenharmony_ci if (SkScalarIsFinite(magSq)) { 38cb93a386Sopenharmony_ci return sk_float_sqrt(magSq); 39cb93a386Sopenharmony_ci } else { 40cb93a386Sopenharmony_ci double xx = x; 41cb93a386Sopenharmony_ci double yy = y; 42cb93a386Sopenharmony_ci double zz = z; 43cb93a386Sopenharmony_ci return (float)sqrt(xx * xx + yy * yy + zz * zz); 44cb93a386Sopenharmony_ci } 45cb93a386Sopenharmony_ci} 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci/* 48cb93a386Sopenharmony_ci * We have to worry about 2 tricky conditions: 49cb93a386Sopenharmony_ci * 1. underflow of magSq (compared against nearlyzero^2) 50cb93a386Sopenharmony_ci * 2. overflow of magSq (compared w/ isfinite) 51cb93a386Sopenharmony_ci * 52cb93a386Sopenharmony_ci * If we underflow, we return false. If we overflow, we compute again using 53cb93a386Sopenharmony_ci * doubles, which is much slower (3x in a desktop test) but will not overflow. 54cb93a386Sopenharmony_ci */ 55cb93a386Sopenharmony_cibool SkPoint3::normalize() { 56cb93a386Sopenharmony_ci float magSq; 57cb93a386Sopenharmony_ci if (is_length_nearly_zero(fX, fY, fZ, &magSq)) { 58cb93a386Sopenharmony_ci this->set(0, 0, 0); 59cb93a386Sopenharmony_ci return false; 60cb93a386Sopenharmony_ci } 61cb93a386Sopenharmony_ci // sqrtf does not provide enough precision; since sqrt takes a double, 62cb93a386Sopenharmony_ci // there's no additional penalty to storing invScale in a double 63cb93a386Sopenharmony_ci double invScale; 64cb93a386Sopenharmony_ci if (sk_float_isfinite(magSq)) { 65cb93a386Sopenharmony_ci invScale = magSq; 66cb93a386Sopenharmony_ci } else { 67cb93a386Sopenharmony_ci // our magSq step overflowed to infinity, so use doubles instead. 68cb93a386Sopenharmony_ci // much slower, but needed when x, y or z is very large, otherwise we 69cb93a386Sopenharmony_ci // divide by inf. and return (0,0,0) vector. 70cb93a386Sopenharmony_ci double xx = fX; 71cb93a386Sopenharmony_ci double yy = fY; 72cb93a386Sopenharmony_ci double zz = fZ; 73cb93a386Sopenharmony_ci invScale = xx * xx + yy * yy + zz * zz; 74cb93a386Sopenharmony_ci } 75cb93a386Sopenharmony_ci // using a float instead of a double for scale loses too much precision 76cb93a386Sopenharmony_ci double scale = 1 / sqrt(invScale); 77cb93a386Sopenharmony_ci fX *= scale; 78cb93a386Sopenharmony_ci fY *= scale; 79cb93a386Sopenharmony_ci fZ *= scale; 80cb93a386Sopenharmony_ci if (!sk_float_isfinite(fX) || !sk_float_isfinite(fY) || !sk_float_isfinite(fZ)) { 81cb93a386Sopenharmony_ci this->set(0, 0, 0); 82cb93a386Sopenharmony_ci return false; 83cb93a386Sopenharmony_ci } 84cb93a386Sopenharmony_ci return true; 85cb93a386Sopenharmony_ci} 86