diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/llmath/llsphere.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/llmath/llsphere.cpp')
-rw-r--r-- | indra/llmath/llsphere.cpp | 740 |
1 files changed, 370 insertions, 370 deletions
diff --git a/indra/llmath/llsphere.cpp b/indra/llmath/llsphere.cpp index 3f04ca704c..b68743ea6e 100644 --- a/indra/llmath/llsphere.cpp +++ b/indra/llmath/llsphere.cpp @@ -1,370 +1,370 @@ -/** - * @file llsphere.cpp - * @author Andrew Meadows - * @brief Simple line class that can compute nearest approach between two lines - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llsphere.h" - -LLSphere::LLSphere() -: mCenter(0.f, 0.f, 0.f), - mRadius(0.f) -{ } - -LLSphere::LLSphere( const LLVector3& center, F32 radius) -{ - set(center, radius); -} - -void LLSphere::set( const LLVector3& center, F32 radius ) -{ - mCenter = center; - setRadius(radius); -} - -void LLSphere::setCenter( const LLVector3& center) -{ - mCenter = center; -} - -void LLSphere::setRadius( F32 radius) -{ - if (radius < 0.f) - { - radius = -radius; - } - mRadius = radius; -} - -const LLVector3& LLSphere::getCenter() const -{ - return mCenter; -} - -F32 LLSphere::getRadius() const -{ - return mRadius; -} - -// returns 'true' if this sphere completely contains other_sphere -bool LLSphere::contains(const LLSphere& other_sphere) const -{ - F32 separation = (mCenter - other_sphere.mCenter).length(); - return mRadius >= separation + other_sphere.mRadius; -} - -// returns 'true' if this sphere completely contains other_sphere -bool LLSphere::overlaps(const LLSphere& other_sphere) const -{ - F32 separation = (mCenter - other_sphere.mCenter).length(); - return mRadius >= separation - other_sphere.mRadius; -} - -// returns overlap -// negative overlap is closest approach -F32 LLSphere::getOverlap(const LLSphere& other_sphere) const -{ - // separation is distance from other_sphere's edge and this center - return (mCenter - other_sphere.mCenter).length() - mRadius - other_sphere.mRadius; -} - -bool LLSphere::operator==(const LLSphere& rhs) const -{ - return fabs(mRadius - rhs.mRadius) <= FLT_EPSILON && - (mCenter - rhs.mCenter).length() <= FLT_EPSILON; -} - -std::ostream& operator<<( std::ostream& output_stream, const LLSphere& sphere) -{ - output_stream << "{center=" << sphere.mCenter << "," << "radius=" << sphere.mRadius << "}"; - return output_stream; -} - -// static -// removes any spheres that are contained in others -void LLSphere::collapse(std::vector<LLSphere>& sphere_list) -{ - std::vector<LLSphere>::iterator first_itr = sphere_list.begin(); - while (first_itr != sphere_list.end()) - { - bool delete_from_front = false; - - std::vector<LLSphere>::iterator second_itr = first_itr; - ++second_itr; - while (second_itr != sphere_list.end()) - { - if (second_itr->contains(*first_itr)) - { - delete_from_front = true; - break; - } - else if (first_itr->contains(*second_itr)) - { - sphere_list.erase(second_itr++); - } - else - { - ++second_itr; - } - } - - if (delete_from_front) - { - sphere_list.erase(first_itr++); - } - else - { - ++first_itr; - } - } -} - -// static -// returns the bounding sphere that contains both spheres -LLSphere LLSphere::getBoundingSphere(const LLSphere& first_sphere, const LLSphere& second_sphere) -{ - LLVector3 direction = second_sphere.mCenter - first_sphere.mCenter; - - // HACK -- it is possible to get enough floating point error in the - // other getBoundingSphere() method that we have to add some slop - // at the end. Unfortunately, this breaks the link-order invarience - // for the linkability tests... unless we also apply the same slop - // here. - F32 half_milimeter = 0.0005f; - - F32 distance = direction.length(); - if (0.f == distance) - { - direction.setVec(1.f, 0.f, 0.f); - } - else - { - direction.normVec(); - } - // the 'edge' is measured from the first_sphere's center - F32 max_edge = 0.f; - F32 min_edge = 0.f; - - max_edge = llmax(max_edge + first_sphere.getRadius(), max_edge + distance + second_sphere.getRadius() + half_milimeter); - min_edge = llmin(min_edge - first_sphere.getRadius(), min_edge + distance - second_sphere.getRadius() - half_milimeter); - F32 radius = 0.5f * (max_edge - min_edge); - LLVector3 center = first_sphere.mCenter + (0.5f * (max_edge + min_edge)) * direction; - return LLSphere(center, radius); -} - -// static -// returns the bounding sphere that contains an arbitrary set of spheres -LLSphere LLSphere::getBoundingSphere(const std::vector<LLSphere>& sphere_list) -{ - // this algorithm can get relatively inaccurate when the sphere - // collection is 'small' (contained within a bounding sphere of about - // 2 meters or less) - // TODO -- improve the accuracy for small collections of spheres - - LLSphere bounding_sphere( LLVector3(0.f, 0.f, 0.f), 0.f ); - S32 sphere_count = sphere_list.size(); - if (1 == sphere_count) - { - // trivial case -- single sphere - std::vector<LLSphere>::const_iterator sphere_itr = sphere_list.begin(); - bounding_sphere = *sphere_itr; - } - else if (2 == sphere_count) - { - // trivial case -- two spheres - std::vector<LLSphere>::const_iterator first_sphere = sphere_list.begin(); - std::vector<LLSphere>::const_iterator second_sphere = first_sphere; - ++second_sphere; - bounding_sphere = LLSphere::getBoundingSphere(*first_sphere, *second_sphere); - } - else if (sphere_count > 0) - { - // non-trivial case -- we will approximate the solution - // - // NOTE -- there is a fancy/fast way to do this for large - // numbers of arbirary N-dimensional spheres -- you can look it - // up on the net. We're dealing with 3D spheres at collection - // sizes of 256 spheres or smaller, so we just use this - // brute force method. - - // TODO -- perhaps would be worthwile to test for the solution where - // the largest spanning radius just happens to work. That is, where - // there are really two spheres that determine the bounding sphere, - // and all others are contained therein. - - // compute the AABB - std::vector<LLSphere>::const_iterator first_itr = sphere_list.begin(); - LLVector3 max_corner = first_itr->getCenter() + first_itr->getRadius() * LLVector3(1.f, 1.f, 1.f); - LLVector3 min_corner = first_itr->getCenter() - first_itr->getRadius() * LLVector3(1.f, 1.f, 1.f); - { - std::vector<LLSphere>::const_iterator sphere_itr = sphere_list.begin(); - for (++sphere_itr; sphere_itr != sphere_list.end(); ++sphere_itr) - { - LLVector3 center = sphere_itr->getCenter(); - F32 radius = sphere_itr->getRadius(); - for (S32 i=0; i<3; ++i) - { - if (center.mV[i] + radius > max_corner.mV[i]) - { - max_corner.mV[i] = center.mV[i] + radius; - } - if (center.mV[i] - radius < min_corner.mV[i]) - { - min_corner.mV[i] = center.mV[i] - radius; - } - } - } - } - - // get the starting center and radius from the AABB - LLVector3 diagonal = max_corner - min_corner; - F32 bounding_radius = 0.5f * diagonal.length(); - LLVector3 bounding_center = 0.5f * (max_corner + min_corner); - - // compute the starting step-size - F32 minimum_radius = 0.5f * llmin(diagonal.mV[VX], llmin(diagonal.mV[VY], diagonal.mV[VZ])); - F32 step_length = bounding_radius - minimum_radius; - //S32 step_count = 0; - //S32 max_step_count = 12; - F32 half_milimeter = 0.0005f; - - // wander the center around in search of tighter solutions - S32 last_dx = 2; // 2 is out of bounds --> no match - S32 last_dy = 2; - S32 last_dz = 2; - - while (step_length > half_milimeter - /*&& step_count < max_step_count*/) - { - // the algorithm for testing the maximum radius could be expensive enough - // that it makes sense to NOT duplicate testing when possible, so we keep - // track of where we last tested, and only test the new points - - S32 best_dx = 0; - S32 best_dy = 0; - S32 best_dz = 0; - - // sample near the center of the box - bool found_better_center = false; - for (S32 dx = -1; dx < 2; ++dx) - { - for (S32 dy = -1; dy < 2; ++dy) - { - for (S32 dz = -1; dz < 2; ++dz) - { - if (dx == 0 && dy == 0 && dz == 0) - { - continue; - } - - // count the number of indecies that match the last_*'s - S32 match_count = 0; - if (last_dx == dx) ++match_count; - if (last_dy == dy) ++match_count; - if (last_dz == dz) ++match_count; - if (match_count == 2) - { - // we've already tested this point - continue; - } - - LLVector3 center = bounding_center; - center.mV[VX] += (F32) dx * step_length; - center.mV[VY] += (F32) dy * step_length; - center.mV[VZ] += (F32) dz * step_length; - - // compute the radius of the bounding sphere - F32 max_radius = 0.f; - std::vector<LLSphere>::const_iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - F32 radius = (sphere_itr->getCenter() - center).length() + sphere_itr->getRadius(); - if (radius > max_radius) - { - max_radius = radius; - } - } - if (max_radius < bounding_radius) - { - best_dx = dx; - best_dy = dy; - best_dz = dz; - bounding_center = center; - bounding_radius = max_radius; - found_better_center = true; - } - } - } - } - if (found_better_center) - { - // remember where we came from so we can avoid retesting - last_dx = -best_dx; - last_dy = -best_dy; - last_dz = -best_dz; - } - else - { - // reduce the step size - step_length *= 0.5f; - //++step_count; - // reset the last_*'s - last_dx = 2; // 2 is out of bounds --> no match - last_dy = 2; - last_dz = 2; - } - } - - // HACK -- it is possible to get enough floating point error for the - // bounding sphere to too small on the order of 10e-6, but we only need - // it to be accurate to within about half a millimeter - bounding_radius += half_milimeter; - - // this algorithm can get relatively inaccurate when the sphere - // collection is 'small' (contained within a bounding sphere of about - // 2 meters or less) - // TODO -- fix this - /* debug code - { - std::vector<LLSphere>::const_iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - F32 radius = (sphere_itr->getCenter() - bounding_center).length() + sphere_itr->getRadius(); - if (radius + 0.1f > bounding_radius) - { - std::cout << " rad = " << radius << " bounding - rad = " << (bounding_radius - radius) << std::endl; - } - } - std::cout << "\n" << std::endl; - } - */ - - bounding_sphere.set(bounding_center, bounding_radius); - } - return bounding_sphere; -} - - +/**
+ * @file llsphere.cpp
+ * @author Andrew Meadows
+ * @brief Simple line class that can compute nearest approach between two lines
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llsphere.h"
+
+LLSphere::LLSphere()
+: mCenter(0.f, 0.f, 0.f),
+ mRadius(0.f)
+{ }
+
+LLSphere::LLSphere( const LLVector3& center, F32 radius)
+{
+ set(center, radius);
+}
+
+void LLSphere::set( const LLVector3& center, F32 radius )
+{
+ mCenter = center;
+ setRadius(radius);
+}
+
+void LLSphere::setCenter( const LLVector3& center)
+{
+ mCenter = center;
+}
+
+void LLSphere::setRadius( F32 radius)
+{
+ if (radius < 0.f)
+ {
+ radius = -radius;
+ }
+ mRadius = radius;
+}
+
+const LLVector3& LLSphere::getCenter() const
+{
+ return mCenter;
+}
+
+F32 LLSphere::getRadius() const
+{
+ return mRadius;
+}
+
+// returns 'true' if this sphere completely contains other_sphere
+bool LLSphere::contains(const LLSphere& other_sphere) const
+{
+ F32 separation = (mCenter - other_sphere.mCenter).length();
+ return mRadius >= separation + other_sphere.mRadius;
+}
+
+// returns 'true' if this sphere completely contains other_sphere
+bool LLSphere::overlaps(const LLSphere& other_sphere) const
+{
+ F32 separation = (mCenter - other_sphere.mCenter).length();
+ return mRadius >= separation - other_sphere.mRadius;
+}
+
+// returns overlap
+// negative overlap is closest approach
+F32 LLSphere::getOverlap(const LLSphere& other_sphere) const
+{
+ // separation is distance from other_sphere's edge and this center
+ return (mCenter - other_sphere.mCenter).length() - mRadius - other_sphere.mRadius;
+}
+
+bool LLSphere::operator==(const LLSphere& rhs) const
+{
+ return fabs(mRadius - rhs.mRadius) <= FLT_EPSILON &&
+ (mCenter - rhs.mCenter).length() <= FLT_EPSILON;
+}
+
+std::ostream& operator<<( std::ostream& output_stream, const LLSphere& sphere)
+{
+ output_stream << "{center=" << sphere.mCenter << "," << "radius=" << sphere.mRadius << "}";
+ return output_stream;
+}
+
+// static
+// removes any spheres that are contained in others
+void LLSphere::collapse(std::vector<LLSphere>& sphere_list)
+{
+ std::vector<LLSphere>::iterator first_itr = sphere_list.begin();
+ while (first_itr != sphere_list.end())
+ {
+ bool delete_from_front = false;
+
+ std::vector<LLSphere>::iterator second_itr = first_itr;
+ ++second_itr;
+ while (second_itr != sphere_list.end())
+ {
+ if (second_itr->contains(*first_itr))
+ {
+ delete_from_front = true;
+ break;
+ }
+ else if (first_itr->contains(*second_itr))
+ {
+ sphere_list.erase(second_itr++);
+ }
+ else
+ {
+ ++second_itr;
+ }
+ }
+
+ if (delete_from_front)
+ {
+ sphere_list.erase(first_itr++);
+ }
+ else
+ {
+ ++first_itr;
+ }
+ }
+}
+
+// static
+// returns the bounding sphere that contains both spheres
+LLSphere LLSphere::getBoundingSphere(const LLSphere& first_sphere, const LLSphere& second_sphere)
+{
+ LLVector3 direction = second_sphere.mCenter - first_sphere.mCenter;
+
+ // HACK -- it is possible to get enough floating point error in the
+ // other getBoundingSphere() method that we have to add some slop
+ // at the end. Unfortunately, this breaks the link-order invarience
+ // for the linkability tests... unless we also apply the same slop
+ // here.
+ F32 half_milimeter = 0.0005f;
+
+ F32 distance = direction.length();
+ if (0.f == distance)
+ {
+ direction.setVec(1.f, 0.f, 0.f);
+ }
+ else
+ {
+ direction.normVec();
+ }
+ // the 'edge' is measured from the first_sphere's center
+ F32 max_edge = 0.f;
+ F32 min_edge = 0.f;
+
+ max_edge = llmax(max_edge + first_sphere.getRadius(), max_edge + distance + second_sphere.getRadius() + half_milimeter);
+ min_edge = llmin(min_edge - first_sphere.getRadius(), min_edge + distance - second_sphere.getRadius() - half_milimeter);
+ F32 radius = 0.5f * (max_edge - min_edge);
+ LLVector3 center = first_sphere.mCenter + (0.5f * (max_edge + min_edge)) * direction;
+ return LLSphere(center, radius);
+}
+
+// static
+// returns the bounding sphere that contains an arbitrary set of spheres
+LLSphere LLSphere::getBoundingSphere(const std::vector<LLSphere>& sphere_list)
+{
+ // this algorithm can get relatively inaccurate when the sphere
+ // collection is 'small' (contained within a bounding sphere of about
+ // 2 meters or less)
+ // TODO -- improve the accuracy for small collections of spheres
+
+ LLSphere bounding_sphere( LLVector3(0.f, 0.f, 0.f), 0.f );
+ S32 sphere_count = sphere_list.size();
+ if (1 == sphere_count)
+ {
+ // trivial case -- single sphere
+ std::vector<LLSphere>::const_iterator sphere_itr = sphere_list.begin();
+ bounding_sphere = *sphere_itr;
+ }
+ else if (2 == sphere_count)
+ {
+ // trivial case -- two spheres
+ std::vector<LLSphere>::const_iterator first_sphere = sphere_list.begin();
+ std::vector<LLSphere>::const_iterator second_sphere = first_sphere;
+ ++second_sphere;
+ bounding_sphere = LLSphere::getBoundingSphere(*first_sphere, *second_sphere);
+ }
+ else if (sphere_count > 0)
+ {
+ // non-trivial case -- we will approximate the solution
+ //
+ // NOTE -- there is a fancy/fast way to do this for large
+ // numbers of arbirary N-dimensional spheres -- you can look it
+ // up on the net. We're dealing with 3D spheres at collection
+ // sizes of 256 spheres or smaller, so we just use this
+ // brute force method.
+
+ // TODO -- perhaps would be worthwile to test for the solution where
+ // the largest spanning radius just happens to work. That is, where
+ // there are really two spheres that determine the bounding sphere,
+ // and all others are contained therein.
+
+ // compute the AABB
+ std::vector<LLSphere>::const_iterator first_itr = sphere_list.begin();
+ LLVector3 max_corner = first_itr->getCenter() + first_itr->getRadius() * LLVector3(1.f, 1.f, 1.f);
+ LLVector3 min_corner = first_itr->getCenter() - first_itr->getRadius() * LLVector3(1.f, 1.f, 1.f);
+ {
+ std::vector<LLSphere>::const_iterator sphere_itr = sphere_list.begin();
+ for (++sphere_itr; sphere_itr != sphere_list.end(); ++sphere_itr)
+ {
+ LLVector3 center = sphere_itr->getCenter();
+ F32 radius = sphere_itr->getRadius();
+ for (S32 i=0; i<3; ++i)
+ {
+ if (center.mV[i] + radius > max_corner.mV[i])
+ {
+ max_corner.mV[i] = center.mV[i] + radius;
+ }
+ if (center.mV[i] - radius < min_corner.mV[i])
+ {
+ min_corner.mV[i] = center.mV[i] - radius;
+ }
+ }
+ }
+ }
+
+ // get the starting center and radius from the AABB
+ LLVector3 diagonal = max_corner - min_corner;
+ F32 bounding_radius = 0.5f * diagonal.length();
+ LLVector3 bounding_center = 0.5f * (max_corner + min_corner);
+
+ // compute the starting step-size
+ F32 minimum_radius = 0.5f * llmin(diagonal.mV[VX], llmin(diagonal.mV[VY], diagonal.mV[VZ]));
+ F32 step_length = bounding_radius - minimum_radius;
+ //S32 step_count = 0;
+ //S32 max_step_count = 12;
+ F32 half_milimeter = 0.0005f;
+
+ // wander the center around in search of tighter solutions
+ S32 last_dx = 2; // 2 is out of bounds --> no match
+ S32 last_dy = 2;
+ S32 last_dz = 2;
+
+ while (step_length > half_milimeter
+ /*&& step_count < max_step_count*/)
+ {
+ // the algorithm for testing the maximum radius could be expensive enough
+ // that it makes sense to NOT duplicate testing when possible, so we keep
+ // track of where we last tested, and only test the new points
+
+ S32 best_dx = 0;
+ S32 best_dy = 0;
+ S32 best_dz = 0;
+
+ // sample near the center of the box
+ bool found_better_center = false;
+ for (S32 dx = -1; dx < 2; ++dx)
+ {
+ for (S32 dy = -1; dy < 2; ++dy)
+ {
+ for (S32 dz = -1; dz < 2; ++dz)
+ {
+ if (dx == 0 && dy == 0 && dz == 0)
+ {
+ continue;
+ }
+
+ // count the number of indecies that match the last_*'s
+ S32 match_count = 0;
+ if (last_dx == dx) ++match_count;
+ if (last_dy == dy) ++match_count;
+ if (last_dz == dz) ++match_count;
+ if (match_count == 2)
+ {
+ // we've already tested this point
+ continue;
+ }
+
+ LLVector3 center = bounding_center;
+ center.mV[VX] += (F32) dx * step_length;
+ center.mV[VY] += (F32) dy * step_length;
+ center.mV[VZ] += (F32) dz * step_length;
+
+ // compute the radius of the bounding sphere
+ F32 max_radius = 0.f;
+ std::vector<LLSphere>::const_iterator sphere_itr;
+ for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
+ {
+ F32 radius = (sphere_itr->getCenter() - center).length() + sphere_itr->getRadius();
+ if (radius > max_radius)
+ {
+ max_radius = radius;
+ }
+ }
+ if (max_radius < bounding_radius)
+ {
+ best_dx = dx;
+ best_dy = dy;
+ best_dz = dz;
+ bounding_center = center;
+ bounding_radius = max_radius;
+ found_better_center = true;
+ }
+ }
+ }
+ }
+ if (found_better_center)
+ {
+ // remember where we came from so we can avoid retesting
+ last_dx = -best_dx;
+ last_dy = -best_dy;
+ last_dz = -best_dz;
+ }
+ else
+ {
+ // reduce the step size
+ step_length *= 0.5f;
+ //++step_count;
+ // reset the last_*'s
+ last_dx = 2; // 2 is out of bounds --> no match
+ last_dy = 2;
+ last_dz = 2;
+ }
+ }
+
+ // HACK -- it is possible to get enough floating point error for the
+ // bounding sphere to too small on the order of 10e-6, but we only need
+ // it to be accurate to within about half a millimeter
+ bounding_radius += half_milimeter;
+
+ // this algorithm can get relatively inaccurate when the sphere
+ // collection is 'small' (contained within a bounding sphere of about
+ // 2 meters or less)
+ // TODO -- fix this
+ /* debug code
+ {
+ std::vector<LLSphere>::const_iterator sphere_itr;
+ for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
+ {
+ F32 radius = (sphere_itr->getCenter() - bounding_center).length() + sphere_itr->getRadius();
+ if (radius + 0.1f > bounding_radius)
+ {
+ std::cout << " rad = " << radius << " bounding - rad = " << (bounding_radius - radius) << std::endl;
+ }
+ }
+ std::cout << "\n" << std::endl;
+ }
+ */
+
+ bounding_sphere.set(bounding_center, bounding_radius);
+ }
+ return bounding_sphere;
+}
+
+
|