+++ /dev/null
-// Copyright (c) 2025 OPEN CASCADE SAS
-//
-// This file is part of Open CASCADE Technology software library.
-//
-// This library is free software; you can redistribute it and/or modify it under
-// the terms of the GNU Lesser General Public License version 2.1 as published
-// by the Free Software Foundation, with special exception defined in the file
-// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
-// distribution for complete text of the license and disclaimer of any warranty.
-//
-// Alternatively, this file may be used under the terms of Open CASCADE
-// commercial license or contractual agreement.
-
-#include <TopLoc_Location.hxx>
-#include <TopoDS_Shape.hxx>
-#include <TopoDS_Vertex.hxx>
-#include <TopoDS.hxx>
-#include <BRepBuilderAPI_MakeVertex.hxx>
-#include <BRep_Tool.hxx>
-#include <gp.hxx>
-#include <gp_Ax1.hxx>
-#include <gp_Trsf.hxx>
-#include <gp_Vec.hxx>
-#include <gp_Pnt.hxx>
-#include <OSD_Parallel.hxx>
-
-#include <gtest/gtest.h>
-
-#include <atomic>
-#include <vector>
-
-namespace
-{
-//! Functor for testing concurrent access to TopLoc_Location::Transformation()
-struct TopLocTransformFunctor
-{
- TopLocTransformFunctor(const std::vector<TopoDS_Shape>& theShapeVec)
- : myShapeVec(&theShapeVec),
- myIsRaceDetected(0)
- {
- }
-
- void operator()(size_t i) const
- {
- if (!myIsRaceDetected)
- {
- const TopoDS_Vertex& aVertex = TopoDS::Vertex(myShapeVec->at(i));
- gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
- if (aPoint.X() != static_cast<double>(i))
- {
- ++myIsRaceDetected;
- }
- }
- }
-
- const std::vector<TopoDS_Shape>* myShapeVec;
- mutable std::atomic<int> myIsRaceDetected;
-};
-} // namespace
-
-TEST(TopLoc_Location_Test, OCC25545_ConcurrentTransformationAccess)
-{
- // Bug OCC25545: TopLoc_Location::Transformation() provokes data races
- // This test verifies that concurrent access to TopLoc_Location::Transformation()
- // does not cause data races or incorrect geometry results
-
- // Place vertices in a vector, giving the i-th vertex the
- // transformation that translates it on the vector (i,0,0) from the origin
- Standard_Integer n = 1000;
- std::vector<TopoDS_Shape> aShapeVec(n);
- std::vector<TopLoc_Location> aLocVec(n);
- TopoDS_Shape aShape = BRepBuilderAPI_MakeVertex(gp::Origin());
- aShapeVec[0] = aShape;
-
- for (Standard_Integer i = 1; i < n; ++i)
- {
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1, 0, 0));
- aLocVec[i] = aLocVec[i - 1] * aTrsf;
- aShapeVec[i] = aShape.Moved(aLocVec[i]);
- }
-
- // Evaluator function will access vertices geometry concurrently
- TopLocTransformFunctor aFunc(aShapeVec);
-
- // Process concurrently
- OSD_Parallel::For(0, n, aFunc);
-
- // Verify no data race was detected
- EXPECT_EQ(aFunc.myIsRaceDetected, 0)
- << "Data race detected in concurrent TopLoc_Location::Transformation() access";
-}
-
-//=================================================================================================
-// Tests for Phase 1 & 2 Optimizations
-//=================================================================================================
-
-TEST(TopLoc_Location_Test, DefaultConstructor_CreatesIdentity)
-{
- // Test that default constructor creates identity location
- TopLoc_Location aLoc;
-
- EXPECT_TRUE(aLoc.IsIdentity()) << "Default constructed location should be identity";
-
- const gp_Trsf& aTrsf = aLoc.Transformation();
- EXPECT_EQ(aTrsf.Form(), gp_Identity) << "Default location should return identity transformation";
-}
-
-TEST(TopLoc_Location_Test, IdentityTransformation_ReturnsSameInstance)
-{
- // Test that identity locations return the same transformation instance
- TopLoc_Location aLoc1;
- TopLoc_Location aLoc2;
-
- const gp_Trsf& aTrsf1 = aLoc1.Transformation();
- const gp_Trsf& aTrsf2 = aLoc2.Transformation();
-
- // Both should return reference to the same identity transformation
- EXPECT_EQ(&aTrsf1, &aTrsf2) << "Identity locations should share the same transformation instance";
-}
-
-TEST(TopLoc_Location_Test, Squared_EqualsMultipliedBySelf)
-{
- // Test that Squared() equals Multiplied(self)
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1.0, 2.0, 3.0));
- TopLoc_Location aLoc(aTrsf);
-
- TopLoc_Location aSquared = aLoc.Squared();
- TopLoc_Location aMultiplied = aLoc.Multiplied(aLoc);
-
- EXPECT_EQ(aSquared, aMultiplied) << "Squared() should equal Multiplied(self)";
-
- // Verify the transformation is actually squared
- gp_Pnt anOrigin(0, 0, 0);
- gp_Pnt aTransformed = anOrigin.Transformed(aSquared.Transformation());
- gp_Pnt anExpected(2.0, 4.0, 6.0); // Double translation
-
- EXPECT_NEAR(aTransformed.X(), anExpected.X(), 1e-10);
- EXPECT_NEAR(aTransformed.Y(), anExpected.Y(), 1e-10);
- EXPECT_NEAR(aTransformed.Z(), anExpected.Z(), 1e-10);
-}
-
-TEST(TopLoc_Location_Test, Powered2_UsesSquaredFastPath)
-{
- // Test that Powered(2) equals Squared() (verifies fast path)
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(5.0, -3.0, 1.5));
- TopLoc_Location aLoc(aTrsf);
-
- TopLoc_Location aPowered = aLoc.Powered(2);
- TopLoc_Location aSquared = aLoc.Squared();
-
- EXPECT_EQ(aPowered, aSquared) << "Powered(2) should equal Squared()";
-}
-
-TEST(TopLoc_Location_Test, Powered_VariousPowers)
-{
- // Test Powered() with various power values
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1.0, 0.0, 0.0));
- TopLoc_Location aLoc(aTrsf);
-
- // Power 0 should return identity
- TopLoc_Location aPow0 = aLoc.Powered(0);
- EXPECT_TRUE(aPow0.IsIdentity()) << "Powered(0) should return identity";
-
- // Power 1 should return self
- TopLoc_Location aPow1 = aLoc.Powered(1);
- EXPECT_EQ(aPow1, aLoc) << "Powered(1) should return self";
-
- // Power 2 should be double translation
- TopLoc_Location aPow2 = aLoc.Powered(2);
- gp_Pnt anOrigin(0, 0, 0);
- gp_Pnt aResult = anOrigin.Transformed(aPow2.Transformation());
- EXPECT_NEAR(aResult.X(), 2.0, 1e-10) << "Powered(2) should double the translation";
-
- // Power 3
- TopLoc_Location aPow3 = aLoc.Powered(3);
- aResult = anOrigin.Transformed(aPow3.Transformation());
- EXPECT_NEAR(aResult.X(), 3.0, 1e-10) << "Powered(3) should triple the translation";
-
- // Negative power (inverse)
- TopLoc_Location aPowNeg1 = aLoc.Powered(-1);
- TopLoc_Location anInverted = aLoc.Inverted();
- EXPECT_EQ(aPowNeg1, anInverted) << "Powered(-1) should equal Inverted()";
-}
-
-TEST(TopLoc_Location_Test, SharesNode_DetectsSharedStructure)
-{
- // Test that SharesNode correctly detects shared list nodes
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1.0, 2.0, 3.0));
- TopLoc_Location aLoc1(aTrsf);
-
- // Copy constructor should share the same nodes
- TopLoc_Location aLoc2 = aLoc1;
-
- EXPECT_EQ(aLoc1, aLoc2) << "Copied location should equal original";
-
- // Assignment should also share nodes
- TopLoc_Location aLoc3;
- aLoc3 = aLoc1;
-
- EXPECT_EQ(aLoc3, aLoc1) << "Assigned location should equal original";
-}
-
-TEST(TopLoc_Location_Test, Equality_DifferentTransformations)
-{
- // Test that different transformations are not equal
- gp_Trsf aTrsf1;
- aTrsf1.SetTranslation(gp_Vec(1.0, 0.0, 0.0));
- TopLoc_Location aLoc1(aTrsf1);
-
- gp_Trsf aTrsf2;
- aTrsf2.SetTranslation(gp_Vec(0.0, 1.0, 0.0));
- TopLoc_Location aLoc2(aTrsf2);
-
- EXPECT_NE(aLoc1, aLoc2) << "Different transformations should not be equal";
- EXPECT_TRUE(aLoc1.IsDifferent(aLoc2))
- << "IsDifferent should return true for different transformations";
-}
-
-TEST(TopLoc_Location_Test, Multiplication_Composition)
-{
- // Test location multiplication (composition)
- gp_Trsf aTrsf1;
- aTrsf1.SetTranslation(gp_Vec(1.0, 0.0, 0.0));
- TopLoc_Location aLoc1(aTrsf1);
-
- gp_Trsf aTrsf2;
- aTrsf2.SetTranslation(gp_Vec(0.0, 2.0, 0.0));
- TopLoc_Location aLoc2(aTrsf2);
-
- TopLoc_Location aComposed = aLoc1 * aLoc2;
-
- // Apply composed transformation
- gp_Pnt anOrigin(0, 0, 0);
- gp_Pnt aResult = anOrigin.Transformed(aComposed.Transformation());
-
- EXPECT_NEAR(aResult.X(), 1.0, 1e-10);
- EXPECT_NEAR(aResult.Y(), 2.0, 1e-10);
- EXPECT_NEAR(aResult.Z(), 0.0, 1e-10);
-}
-
-TEST(TopLoc_Location_Test, Inverted_ProducesInverse)
-{
- // Test that Location * Inverted() = Identity
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(5.0, -3.0, 2.0));
- TopLoc_Location aLoc(aTrsf);
-
- TopLoc_Location anInv = aLoc.Inverted();
- TopLoc_Location anIdentity = aLoc * anInv;
-
- EXPECT_TRUE(anIdentity.IsIdentity()) << "Location * Inverted() should produce identity";
-
- // Also test in reverse order
- TopLoc_Location anIdentity2 = anInv * aLoc;
- EXPECT_TRUE(anIdentity2.IsIdentity()) << "Inverted() * Location should also produce identity";
-}
-
-TEST(TopLoc_Location_Test, Divided_EqualsMultipliedByInverse)
-{
- // Test that Divided equals Multiplied by inverse
- gp_Trsf aTrsf1;
- aTrsf1.SetTranslation(gp_Vec(3.0, 4.0, 5.0));
- TopLoc_Location aLoc1(aTrsf1);
-
- gp_Trsf aTrsf2;
- aTrsf2.SetTranslation(gp_Vec(1.0, 1.0, 1.0));
- TopLoc_Location aLoc2(aTrsf2);
-
- TopLoc_Location aDivided = aLoc1 / aLoc2;
- TopLoc_Location aMultiplied = aLoc1 * aLoc2.Inverted();
-
- EXPECT_EQ(aDivided, aMultiplied) << "Divided should equal Multiplied by Inverted";
-}
-
-TEST(TopLoc_Location_Test, Predivided_EqualsInverseMultiplied)
-{
- // Test Predivided = Other.Inverted() * this
- gp_Trsf aTrsf1;
- aTrsf1.SetTranslation(gp_Vec(2.0, 3.0, 4.0));
- TopLoc_Location aLoc1(aTrsf1);
-
- gp_Trsf aTrsf2;
- aTrsf2.SetTranslation(gp_Vec(1.0, 1.0, 1.0));
- TopLoc_Location aLoc2(aTrsf2);
-
- TopLoc_Location aPredivided = aLoc1.Predivided(aLoc2);
- TopLoc_Location anExpected = aLoc2.Inverted() * aLoc1;
-
- EXPECT_EQ(aPredivided, anExpected) << "Predivided should equal Other.Inverted() * this";
-}
-
-TEST(TopLoc_Location_Test, HashCode_ConsistentForEqualLocations)
-{
- // Test that locations sharing the same structure have the same hash code
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1.0, 2.0, 3.0));
- TopLoc_Location aLoc1(aTrsf);
-
- // Copy constructor shares the same underlying structure
- TopLoc_Location aLoc2 = aLoc1;
-
- EXPECT_EQ(aLoc1.HashCode(), aLoc2.HashCode())
- << "Copied locations (sharing structure) should have the same hash code";
-
- // Identity locations should have the same hash code
- TopLoc_Location anId1;
- TopLoc_Location anId2;
- EXPECT_EQ(anId1.HashCode(), anId2.HashCode())
- << "Identity locations should have the same hash code";
- EXPECT_EQ(anId1.HashCode(), static_cast<size_t>(0)) << "Identity location hash should be 0";
-}
-
-TEST(TopLoc_Location_Test, HashCode_DifferentForDifferentLocations)
-{
- // Test that different locations (likely) have different hash codes
- gp_Trsf aTrsf1;
- aTrsf1.SetTranslation(gp_Vec(1.0, 0.0, 0.0));
- TopLoc_Location aLoc1(aTrsf1);
-
- gp_Trsf aTrsf2;
- aTrsf2.SetTranslation(gp_Vec(0.0, 1.0, 0.0));
- TopLoc_Location aLoc2(aTrsf2);
-
- // Hash codes should (very likely) be different
- // Note: Hash collision is theoretically possible but highly unlikely
- EXPECT_NE(aLoc1.HashCode(), aLoc2.HashCode())
- << "Different locations should (likely) have different hash codes";
-}
-
-TEST(TopLoc_Location_Test, ConstCorrectness_TransformationAccess)
-{
- // Test const correctness of Transformation() access
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1.0, 2.0, 3.0));
- const TopLoc_Location aLoc(aTrsf);
-
- // This should compile - Transformation() is const
- const gp_Trsf& aTrsfRef = aLoc.Transformation();
-
- EXPECT_EQ(aTrsfRef.Form(), gp_Translation);
-
- // Test identity case
- const TopLoc_Location anIdLoc;
- const gp_Trsf& anIdTrsf = anIdLoc.Transformation();
-
- EXPECT_EQ(anIdTrsf.Form(), gp_Identity);
-}
-
-TEST(TopLoc_Location_Test, Rotation_Composition)
-{
- // Test rotation transformations
- gp_Trsf aRot;
- gp_Ax1 anAxis(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1));
- aRot.SetRotation(anAxis, M_PI / 2.0); // 90 degrees around Z
-
- TopLoc_Location aLoc(aRot);
- TopLoc_Location aSquared = aLoc.Squared();
-
- // Point at (1,0,0) rotated 90 degrees twice should be at (-1,0,0)
- gp_Pnt aPnt(1, 0, 0);
- gp_Pnt aResult = aPnt.Transformed(aSquared.Transformation());
-
- EXPECT_NEAR(aResult.X(), -1.0, 1e-10);
- EXPECT_NEAR(aResult.Y(), 0.0, 1e-10);
- EXPECT_NEAR(aResult.Z(), 0.0, 1e-10);
-}
-
-TEST(TopLoc_Location_Test, Clear_ResetsToIdentity)
-{
- // Test that Clear() resets location to identity
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1.0, 2.0, 3.0));
- TopLoc_Location aLoc(aTrsf);
-
- EXPECT_FALSE(aLoc.IsIdentity()) << "Location should not be identity before Clear()";
-
- aLoc.Clear();
-
- EXPECT_TRUE(aLoc.IsIdentity()) << "Location should be identity after Clear()";
-}
-
-TEST(TopLoc_Location_Test, Identity_Method)
-{
- // Test Identity() method
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1.0, 2.0, 3.0));
- TopLoc_Location aLoc(aTrsf);
-
- EXPECT_FALSE(aLoc.IsIdentity());
-
- aLoc.Identity();
-
- EXPECT_TRUE(aLoc.IsIdentity()) << "Identity() should reset location to identity";
-}
-
-//=================================================================================================
-// Additional Edge Case Tests
-//=================================================================================================
-
-TEST(TopLoc_Location_Test, ChainedMultiplication_MultipleLocations)
-{
- // Test multiple location multiplications
- gp_Trsf aTrsf1, aTrsf2, aTrsf3;
- aTrsf1.SetTranslation(gp_Vec(1.0, 0.0, 0.0));
- aTrsf2.SetTranslation(gp_Vec(0.0, 1.0, 0.0));
- aTrsf3.SetTranslation(gp_Vec(0.0, 0.0, 1.0));
-
- TopLoc_Location aLoc1(aTrsf1);
- TopLoc_Location aLoc2(aTrsf2);
- TopLoc_Location aLoc3(aTrsf3);
-
- // Chain multiplication
- TopLoc_Location aResult = aLoc1 * aLoc2 * aLoc3;
-
- // Apply to point
- gp_Pnt anOrigin(0, 0, 0);
- gp_Pnt aTransformed = anOrigin.Transformed(aResult.Transformation());
-
- EXPECT_NEAR(aTransformed.X(), 1.0, 1e-10);
- EXPECT_NEAR(aTransformed.Y(), 1.0, 1e-10);
- EXPECT_NEAR(aTransformed.Z(), 1.0, 1e-10);
-}
-
-TEST(TopLoc_Location_Test, IdentityMultiplication_NeutralElement)
-{
- // Test that identity is neutral element for multiplication
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(5.0, 3.0, 1.0));
- TopLoc_Location aLoc(aTrsf);
- TopLoc_Location anIdentity;
-
- // Identity * Location = Location
- TopLoc_Location aResult1 = anIdentity * aLoc;
- EXPECT_EQ(aResult1, aLoc) << "Identity * Location should equal Location";
-
- // Location * Identity = Location
- TopLoc_Location aResult2 = aLoc * anIdentity;
- EXPECT_EQ(aResult2, aLoc) << "Location * Identity should equal Location";
-}
-
-TEST(TopLoc_Location_Test, CopySemantics)
-{
- // Test copy construction and assignment
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(2.0, 3.0, 4.0));
- TopLoc_Location anOriginal(aTrsf);
-
- // Copy construction
- TopLoc_Location aCopied(anOriginal);
- EXPECT_EQ(aCopied, anOriginal);
- EXPECT_EQ(aCopied.HashCode(), anOriginal.HashCode());
-
- // Copy assignment
- TopLoc_Location anAssigned;
- anAssigned = anOriginal;
- EXPECT_EQ(anAssigned, anOriginal);
-
- // All three should be equal (share structure)
- EXPECT_EQ(aCopied, anAssigned);
-}
-
-TEST(TopLoc_Location_Test, ScaleTransformation_Composition)
-{
- // Test scale transformations
- gp_Trsf aScale;
- aScale.SetScale(gp_Pnt(0, 0, 0), 2.0);
-
- TopLoc_Location aLoc(aScale);
- TopLoc_Location aSquared = aLoc.Squared();
-
- // Point scaled by 2, then by 2 again = scaled by 4
- gp_Pnt aPnt(1, 1, 1);
- gp_Pnt aResult = aPnt.Transformed(aSquared.Transformation());
-
- EXPECT_NEAR(aResult.X(), 4.0, 1e-10);
- EXPECT_NEAR(aResult.Y(), 4.0, 1e-10);
- EXPECT_NEAR(aResult.Z(), 4.0, 1e-10);
-}
-
-TEST(TopLoc_Location_Test, ComplexTransformation_TranslationAndRotation)
-{
- // Test combination of translation and rotation
- gp_Trsf aTrans;
- aTrans.SetTranslation(gp_Vec(10.0, 0.0, 0.0));
-
- gp_Trsf aRot;
- gp_Ax1 anAxis(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1));
- aRot.SetRotation(anAxis, M_PI); // 180 degrees
-
- TopLoc_Location aLocTrans(aTrans);
- TopLoc_Location aLocRot(aRot);
-
- // Translate then rotate
- TopLoc_Location aComposed = aLocRot * aLocTrans;
-
- // Point at origin, translate to (10,0,0), then rotate 180 degrees -> (-10,0,0)
- gp_Pnt anOrigin(0, 0, 0);
- gp_Pnt aResult = anOrigin.Transformed(aComposed.Transformation());
-
- EXPECT_NEAR(aResult.X(), -10.0, 1e-9);
- EXPECT_NEAR(aResult.Y(), 0.0, 1e-9);
- EXPECT_NEAR(aResult.Z(), 0.0, 1e-9);
-}
-
-TEST(TopLoc_Location_Test, PoweredWithLargePower)
-{
- // Test Powered() with larger power value
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1.0, 0.0, 0.0));
- TopLoc_Location aLoc(aTrsf);
-
- // Power of 10
- TopLoc_Location aPow10 = aLoc.Powered(10);
-
- gp_Pnt anOrigin(0, 0, 0);
- gp_Pnt aResult = anOrigin.Transformed(aPow10.Transformation());
-
- EXPECT_NEAR(aResult.X(), 10.0, 1e-9) << "Powered(10) should translate 10 units";
-}
-
-TEST(TopLoc_Location_Test, SelfMultiplication_MultipleIterations)
-{
- // Test repeated self-multiplication
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1.0, 0.0, 0.0));
- TopLoc_Location aLoc(aTrsf);
-
- TopLoc_Location aResult = aLoc;
- for (int i = 0; i < 5; ++i)
- {
- aResult = aResult * aLoc;
- }
-
- // Should be 6 times the original (1 + 5 multiplications)
- gp_Pnt anOrigin(0, 0, 0);
- gp_Pnt aTransformed = anOrigin.Transformed(aResult.Transformation());
-
- EXPECT_NEAR(aTransformed.X(), 6.0, 1e-10);
-}
-
-TEST(TopLoc_Location_Test, AssociativityOfMultiplication)
-{
- // Test that (A * B) * C = A * (B * C)
- gp_Trsf aTrsf1, aTrsf2, aTrsf3;
- aTrsf1.SetTranslation(gp_Vec(1.0, 0.0, 0.0));
- aTrsf2.SetTranslation(gp_Vec(0.0, 2.0, 0.0));
- aTrsf3.SetTranslation(gp_Vec(0.0, 0.0, 3.0));
-
- TopLoc_Location aLocA(aTrsf1);
- TopLoc_Location aLocB(aTrsf2);
- TopLoc_Location aLocC(aTrsf3);
-
- TopLoc_Location aLeft = (aLocA * aLocB) * aLocC;
- TopLoc_Location aRight = aLocA * (aLocB * aLocC);
-
- gp_Pnt anOrigin(0, 0, 0);
- gp_Pnt aResultLeft = anOrigin.Transformed(aLeft.Transformation());
- gp_Pnt aResultRight = anOrigin.Transformed(aRight.Transformation());
-
- EXPECT_NEAR(aResultLeft.X(), aResultRight.X(), 1e-10);
- EXPECT_NEAR(aResultLeft.Y(), aResultRight.Y(), 1e-10);
- EXPECT_NEAR(aResultLeft.Z(), aResultRight.Z(), 1e-10);
-}
-
-TEST(TopLoc_Location_Test, InversionIdempotence)
-{
- // Test that (L.Inverted()).Inverted() = L
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(3.0, 4.0, 5.0));
- TopLoc_Location aLoc(aTrsf);
-
- TopLoc_Location aDoubleInverted = aLoc.Inverted().Inverted();
-
- gp_Pnt aPnt(1, 1, 1);
- gp_Pnt aResult1 = aPnt.Transformed(aLoc.Transformation());
- gp_Pnt aResult2 = aPnt.Transformed(aDoubleInverted.Transformation());
-
- EXPECT_NEAR(aResult1.X(), aResult2.X(), 1e-10);
- EXPECT_NEAR(aResult1.Y(), aResult2.Y(), 1e-10);
- EXPECT_NEAR(aResult1.Z(), aResult2.Z(), 1e-10);
-}
-
-//=================================================================================================
-// Tests for Phase 3: Binary Exponentiation Optimization
-//=================================================================================================
-
-TEST(TopLoc_Location_Test, BinaryExponentiation_PowerOf2)
-{
- // Test binary exponentiation for powers of 2 (4, 8, 16)
- // These should be most efficient: L^8 requires only 3 squarings instead of 7 multiplications
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1.0, 0.0, 0.0));
- TopLoc_Location aLoc(aTrsf);
-
- // Test power of 4 (2^2)
- TopLoc_Location aPow4 = aLoc.Powered(4);
- gp_Pnt anOrigin(0, 0, 0);
- gp_Pnt aResult = anOrigin.Transformed(aPow4.Transformation());
- EXPECT_NEAR(aResult.X(), 4.0, 1e-9) << "Powered(4) should translate 4 units";
-
- // Test power of 8 (2^3)
- TopLoc_Location aPow8 = aLoc.Powered(8);
- aResult = anOrigin.Transformed(aPow8.Transformation());
- EXPECT_NEAR(aResult.X(), 8.0, 1e-9) << "Powered(8) should translate 8 units";
-
- // Test power of 16 (2^4)
- TopLoc_Location aPow16 = aLoc.Powered(16);
- aResult = anOrigin.Transformed(aPow16.Transformation());
- EXPECT_NEAR(aResult.X(), 16.0, 1e-9) << "Powered(16) should translate 16 units";
-}
-
-TEST(TopLoc_Location_Test, BinaryExponentiation_OddPowers)
-{
- // Test binary exponentiation for odd powers (5, 7, 9)
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1.0, 0.0, 0.0));
- TopLoc_Location aLoc(aTrsf);
-
- gp_Pnt anOrigin(0, 0, 0);
-
- // Test power of 5
- TopLoc_Location aPow5 = aLoc.Powered(5);
- gp_Pnt aResult = anOrigin.Transformed(aPow5.Transformation());
- EXPECT_NEAR(aResult.X(), 5.0, 1e-9) << "Powered(5) should translate 5 units";
-
- // Test power of 7
- TopLoc_Location aPow7 = aLoc.Powered(7);
- aResult = anOrigin.Transformed(aPow7.Transformation());
- EXPECT_NEAR(aResult.X(), 7.0, 1e-9) << "Powered(7) should translate 7 units";
-
- // Test power of 9
- TopLoc_Location aPow9 = aLoc.Powered(9);
- aResult = anOrigin.Transformed(aPow9.Transformation());
- EXPECT_NEAR(aResult.X(), 9.0, 1e-9) << "Powered(9) should translate 9 units";
-}
-
-TEST(TopLoc_Location_Test, BinaryExponentiation_VeryLargePower)
-{
- // Test with very large power to verify efficiency improvement
- // L^64 with binary exponentiation: only 6 squarings
- // L^64 with naive: 63 multiplications
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(0.5, 0.0, 0.0));
- TopLoc_Location aLoc(aTrsf);
-
- TopLoc_Location aPow64 = aLoc.Powered(64);
-
- gp_Pnt anOrigin(0, 0, 0);
- gp_Pnt aResult = anOrigin.Transformed(aPow64.Transformation());
-
- EXPECT_NEAR(aResult.X(), 32.0, 1e-8) << "Powered(64) should translate 32 units (64 * 0.5)";
-}
-
-TEST(TopLoc_Location_Test, BinaryExponentiation_NegativePowers)
-{
- // Test binary exponentiation for negative powers
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(1.0, 0.0, 0.0));
- TopLoc_Location aLoc(aTrsf);
-
- // Test power of -4 (should be inverse of power 4)
- TopLoc_Location aPowNeg4 = aLoc.Powered(-4);
- TopLoc_Location aPow4 = aLoc.Powered(4);
-
- TopLoc_Location aIdentity = aPowNeg4 * aPow4;
- EXPECT_TRUE(aIdentity.IsIdentity()) << "L^(-4) * L^4 should produce identity";
-
- // Verify the transformation
- gp_Pnt anOrigin(0, 0, 0);
- gp_Pnt aResult = anOrigin.Transformed(aPowNeg4.Transformation());
- EXPECT_NEAR(aResult.X(), -4.0, 1e-9) << "Powered(-4) should translate -4 units";
-}
-
-TEST(TopLoc_Location_Test, BinaryExponentiation_RotationPowers)
-{
- // Test binary exponentiation with rotation transformations
- // 45 degrees rotation, power of 8 should equal 360 degrees (identity)
- gp_Trsf aRot;
- gp_Ax1 anAxis(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1));
- aRot.SetRotation(anAxis, M_PI / 4.0); // 45 degrees
-
- TopLoc_Location aLoc(aRot);
- TopLoc_Location aPow8 = aLoc.Powered(8); // 8 * 45 degrees = 360 degrees
-
- // Should be close to identity (full rotation)
- gp_Pnt aPnt(1, 0, 0);
- gp_Pnt aResult = aPnt.Transformed(aPow8.Transformation());
-
- EXPECT_NEAR(aResult.X(), 1.0, 1e-8);
- EXPECT_NEAR(aResult.Y(), 0.0, 1e-8);
- EXPECT_NEAR(aResult.Z(), 0.0, 1e-8);
-}
-
-TEST(TopLoc_Location_Test, BinaryExponentiation_MixedEvenOdd)
-{
- // Test a mix of even and odd powers to verify the algorithm handles both cases
- gp_Trsf aTrsf;
- aTrsf.SetTranslation(gp_Vec(2.0, 0.0, 0.0));
- TopLoc_Location aLoc(aTrsf);
-
- gp_Pnt anOrigin(0, 0, 0);
-
- // Test 6 (even)
- TopLoc_Location aPow6 = aLoc.Powered(6);
- gp_Pnt aResult = anOrigin.Transformed(aPow6.Transformation());
- EXPECT_NEAR(aResult.X(), 12.0, 1e-9);
-
- // Test 11 (odd)
- TopLoc_Location aPow11 = aLoc.Powered(11);
- aResult = anOrigin.Transformed(aPow11.Transformation());
- EXPECT_NEAR(aResult.X(), 22.0, 1e-9);
-
- // Test 15 (odd)
- TopLoc_Location aPow15 = aLoc.Powered(15);
- aResult = anOrigin.Transformed(aPow15.Transformation());
- EXPECT_NEAR(aResult.X(), 30.0, 1e-9);
-}