From c545617b1575f84649b942c4a58acac45a3404f1 Mon Sep 17 00:00:00 2001 From: alxkm Date: Sun, 5 Oct 2025 18:28:16 +0000 Subject: [PATCH 1/2] Update DIRECTORY.md --- DIRECTORY.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index b311b10fa177..2d124a72259e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -29,8 +29,10 @@ - 📄 [BcdConversion](src/main/java/com/thealgorithms/bitmanipulation/BcdConversion.java) - 📄 [BinaryPalindromeCheck](src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java) - 📄 [BitSwap](src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java) + - 📄 [BitwiseGCD](src/main/java/com/thealgorithms/bitmanipulation/BitwiseGCD.java) - 📄 [BooleanAlgebraGates](src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java) - 📄 [ClearLeftmostSetBit](src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java) + - 📄 [CountBitsFlip](src/main/java/com/thealgorithms/bitmanipulation/CountBitsFlip.java) - 📄 [CountLeadingZeros](src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java) - 📄 [CountSetBits](src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java) - 📄 [FindNthBit](src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java) @@ -98,6 +100,7 @@ - 📄 [BinaryToDecimal](src/main/java/com/thealgorithms/conversions/BinaryToDecimal.java) - 📄 [BinaryToHexadecimal](src/main/java/com/thealgorithms/conversions/BinaryToHexadecimal.java) - 📄 [BinaryToOctal](src/main/java/com/thealgorithms/conversions/BinaryToOctal.java) + - 📄 [CoordinateConverter](src/main/java/com/thealgorithms/conversions/CoordinateConverter.java) - 📄 [DecimalToAnyBase](src/main/java/com/thealgorithms/conversions/DecimalToAnyBase.java) - 📄 [DecimalToBinary](src/main/java/com/thealgorithms/conversions/DecimalToBinary.java) - 📄 [DecimalToHexadecimal](src/main/java/com/thealgorithms/conversions/DecimalToHexadecimal.java) @@ -118,6 +121,7 @@ - 📄 [PhoneticAlphabetConverter](src/main/java/com/thealgorithms/conversions/PhoneticAlphabetConverter.java) - 📄 [RgbHsvConversion](src/main/java/com/thealgorithms/conversions/RgbHsvConversion.java) - 📄 [RomanToInteger](src/main/java/com/thealgorithms/conversions/RomanToInteger.java) + - 📄 [TimeConverter](src/main/java/com/thealgorithms/conversions/TimeConverter.java) - 📄 [TurkishToLatinConversion](src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java) - 📄 [UnitConversions](src/main/java/com/thealgorithms/conversions/UnitConversions.java) - 📄 [UnitsConverter](src/main/java/com/thealgorithms/conversions/UnitsConverter.java) @@ -199,6 +203,7 @@ - 📄 [MinPriorityQueue](src/main/java/com/thealgorithms/datastructures/heaps/MinPriorityQueue.java) - 📁 **lists** - 📄 [CircleLinkedList](src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java) + - 📄 [CircularDoublyLinkedList](src/main/java/com/thealgorithms/datastructures/lists/CircularDoublyLinkedList.java) - 📄 [CountSinglyLinkedListRecursion](src/main/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursion.java) - 📄 [CreateAndDetectLoop](src/main/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoop.java) - 📄 [CursorLinkedList](src/main/java/com/thealgorithms/datastructures/lists/CursorLinkedList.java) @@ -343,11 +348,14 @@ - 📄 [BresenhamLine](src/main/java/com/thealgorithms/geometry/BresenhamLine.java) - 📄 [ConvexHull](src/main/java/com/thealgorithms/geometry/ConvexHull.java) - 📄 [GrahamScan](src/main/java/com/thealgorithms/geometry/GrahamScan.java) + - 📄 [Haversine](src/main/java/com/thealgorithms/geometry/Haversine.java) - 📄 [MidpointCircle](src/main/java/com/thealgorithms/geometry/MidpointCircle.java) - 📄 [MidpointEllipse](src/main/java/com/thealgorithms/geometry/MidpointEllipse.java) - 📄 [Point](src/main/java/com/thealgorithms/geometry/Point.java) - 📁 **graph** + - 📄 [BronKerbosch](src/main/java/com/thealgorithms/graph/BronKerbosch.java) - 📄 [ConstrainedShortestPath](src/main/java/com/thealgorithms/graph/ConstrainedShortestPath.java) + - 📄 [EdmondsKarp](src/main/java/com/thealgorithms/graph/EdmondsKarp.java) - 📄 [HopcroftKarp](src/main/java/com/thealgorithms/graph/HopcroftKarp.java) - 📄 [PredecessorConstrainedDfs](src/main/java/com/thealgorithms/graph/PredecessorConstrainedDfs.java) - 📄 [StronglyConnectedComponentOptimized](src/main/java/com/thealgorithms/graph/StronglyConnectedComponentOptimized.java) @@ -450,6 +458,7 @@ - 📄 [NonRepeatingElement](src/main/java/com/thealgorithms/maths/NonRepeatingElement.java) - 📄 [NthUglyNumber](src/main/java/com/thealgorithms/maths/NthUglyNumber.java) - 📄 [NumberOfDigits](src/main/java/com/thealgorithms/maths/NumberOfDigits.java) + - 📄 [NumberPersistence](src/main/java/com/thealgorithms/maths/NumberPersistence.java) - 📄 [PalindromeNumber](src/main/java/com/thealgorithms/maths/PalindromeNumber.java) - 📄 [ParseInteger](src/main/java/com/thealgorithms/maths/ParseInteger.java) - 📄 [PascalTriangle](src/main/java/com/thealgorithms/maths/PascalTriangle.java) @@ -486,6 +495,7 @@ - 📄 [SumOfArithmeticSeries](src/main/java/com/thealgorithms/maths/SumOfArithmeticSeries.java) - 📄 [SumOfDigits](src/main/java/com/thealgorithms/maths/SumOfDigits.java) - 📄 [SumOfOddNumbers](src/main/java/com/thealgorithms/maths/SumOfOddNumbers.java) + - 📄 [SumOfSquares](src/main/java/com/thealgorithms/maths/SumOfSquares.java) - 📄 [SumWithoutArithmeticOperators](src/main/java/com/thealgorithms/maths/SumWithoutArithmeticOperators.java) - 📄 [TrinomialTriangle](src/main/java/com/thealgorithms/maths/TrinomialTriangle.java) - 📄 [TwinPrime](src/main/java/com/thealgorithms/maths/TwinPrime.java) @@ -576,6 +586,7 @@ - 📁 **recursion** - 📄 [FibonacciSeries](src/main/java/com/thealgorithms/recursion/FibonacciSeries.java) - 📄 [GenerateSubsets](src/main/java/com/thealgorithms/recursion/GenerateSubsets.java) + - 📄 [SylvesterSequence](src/main/java/com/thealgorithms/recursion/SylvesterSequence.java) - 📁 **scheduling** - 📄 [AgingScheduling](src/main/java/com/thealgorithms/scheduling/AgingScheduling.java) - 📄 [EDFScheduling](src/main/java/com/thealgorithms/scheduling/EDFScheduling.java) @@ -641,6 +652,7 @@ - 📄 [MaxSumKSizeSubarray](src/main/java/com/thealgorithms/slidingwindow/MaxSumKSizeSubarray.java) - 📄 [MaximumSlidingWindow](src/main/java/com/thealgorithms/slidingwindow/MaximumSlidingWindow.java) - 📄 [MinSumKSizeSubarray](src/main/java/com/thealgorithms/slidingwindow/MinSumKSizeSubarray.java) + - 📄 [MinimumWindowSubstring](src/main/java/com/thealgorithms/slidingwindow/MinimumWindowSubstring.java) - 📄 [ShortestCoprimeSegment](src/main/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegment.java) - 📁 **sorts** - 📄 [AdaptiveMergeSort](src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java) @@ -719,6 +731,7 @@ - 📁 **strings** - 📄 [AhoCorasick](src/main/java/com/thealgorithms/strings/AhoCorasick.java) - 📄 [Alphabetical](src/main/java/com/thealgorithms/strings/Alphabetical.java) + - 📄 [AlternativeStringArrange](src/main/java/com/thealgorithms/strings/AlternativeStringArrange.java) - 📄 [Anagrams](src/main/java/com/thealgorithms/strings/Anagrams.java) - 📄 [CharactersSame](src/main/java/com/thealgorithms/strings/CharactersSame.java) - 📄 [CheckVowels](src/main/java/com/thealgorithms/strings/CheckVowels.java) @@ -726,6 +739,7 @@ - 📄 [CountWords](src/main/java/com/thealgorithms/strings/CountWords.java) - 📄 [HammingDistance](src/main/java/com/thealgorithms/strings/HammingDistance.java) - 📄 [HorspoolSearch](src/main/java/com/thealgorithms/strings/HorspoolSearch.java) + - 📄 [Isogram](src/main/java/com/thealgorithms/strings/Isogram.java) - 📄 [Isomorphic](src/main/java/com/thealgorithms/strings/Isomorphic.java) - 📄 [KMP](src/main/java/com/thealgorithms/strings/KMP.java) - 📄 [LetterCombinationsOfPhoneNumber](src/main/java/com/thealgorithms/strings/LetterCombinationsOfPhoneNumber.java) @@ -781,8 +795,10 @@ - 📄 [BcdConversionTest](src/test/java/com/thealgorithms/bitmanipulation/BcdConversionTest.java) - 📄 [BinaryPalindromeCheckTest](src/test/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheckTest.java) - 📄 [BitSwapTest](src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java) + - 📄 [BitwiseGCDTest](src/test/java/com/thealgorithms/bitmanipulation/BitwiseGCDTest.java) - 📄 [BooleanAlgebraGatesTest](src/test/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGatesTest.java) - 📄 [ClearLeftmostSetBitTest](src/test/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBitTest.java) + - 📄 [CountBitsFlipTest](src/test/java/com/thealgorithms/bitmanipulation/CountBitsFlipTest.java) - 📄 [CountLeadingZerosTest](src/test/java/com/thealgorithms/bitmanipulation/CountLeadingZerosTest.java) - 📄 [CountSetBitsTest](src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java) - 📄 [FindNthBitTest](src/test/java/com/thealgorithms/bitmanipulation/FindNthBitTest.java) @@ -844,6 +860,7 @@ - 📄 [BinaryToDecimalTest](src/test/java/com/thealgorithms/conversions/BinaryToDecimalTest.java) - 📄 [BinaryToHexadecimalTest](src/test/java/com/thealgorithms/conversions/BinaryToHexadecimalTest.java) - 📄 [BinaryToOctalTest](src/test/java/com/thealgorithms/conversions/BinaryToOctalTest.java) + - 📄 [CoordinateConverterTest](src/test/java/com/thealgorithms/conversions/CoordinateConverterTest.java) - 📄 [DecimalToAnyBaseTest](src/test/java/com/thealgorithms/conversions/DecimalToAnyBaseTest.java) - 📄 [DecimalToBinaryTest](src/test/java/com/thealgorithms/conversions/DecimalToBinaryTest.java) - 📄 [DecimalToHexadecimalTest](src/test/java/com/thealgorithms/conversions/DecimalToHexadecimalTest.java) @@ -863,6 +880,7 @@ - 📄 [OctalToHexadecimalTest](src/test/java/com/thealgorithms/conversions/OctalToHexadecimalTest.java) - 📄 [PhoneticAlphabetConverterTest](src/test/java/com/thealgorithms/conversions/PhoneticAlphabetConverterTest.java) - 📄 [RomanToIntegerTest](src/test/java/com/thealgorithms/conversions/RomanToIntegerTest.java) + - 📄 [TimeConverterTest](src/test/java/com/thealgorithms/conversions/TimeConverterTest.java) - 📄 [TurkishToLatinConversionTest](src/test/java/com/thealgorithms/conversions/TurkishToLatinConversionTest.java) - 📄 [UnitConversionsTest](src/test/java/com/thealgorithms/conversions/UnitConversionsTest.java) - 📄 [UnitsConverterTest](src/test/java/com/thealgorithms/conversions/UnitsConverterTest.java) @@ -934,6 +952,7 @@ - 📄 [MinPriorityQueueTest](src/test/java/com/thealgorithms/datastructures/heaps/MinPriorityQueueTest.java) - 📁 **lists** - 📄 [CircleLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java) + - 📄 [CircularDoublyLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/CircularDoublyLinkedListTest.java) - 📄 [CountSinglyLinkedListRecursionTest](src/test/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursionTest.java) - 📄 [CreateAndDetectLoopTest](src/test/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoopTest.java) - 📄 [CursorLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/CursorLinkedListTest.java) @@ -990,6 +1009,9 @@ - 📄 [TrieTest](src/test/java/com/thealgorithms/datastructures/trees/TrieTest.java) - 📄 [VerticalOrderTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/VerticalOrderTraversalTest.java) - 📄 [ZigzagTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/ZigzagTraversalTest.java) + - 📁 **devutils** + - 📁 **entities** + - 📄 [ProcessDetailsTest](src/test/java/com/thealgorithms/devutils/entities/ProcessDetailsTest.java) - 📁 **divideandconquer** - 📄 [BinaryExponentiationTest](src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java) - 📄 [ClosestPairTest](src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java) @@ -1052,11 +1074,14 @@ - 📄 [BresenhamLineTest](src/test/java/com/thealgorithms/geometry/BresenhamLineTest.java) - 📄 [ConvexHullTest](src/test/java/com/thealgorithms/geometry/ConvexHullTest.java) - 📄 [GrahamScanTest](src/test/java/com/thealgorithms/geometry/GrahamScanTest.java) + - 📄 [HaversineTest](src/test/java/com/thealgorithms/geometry/HaversineTest.java) - 📄 [MidpointCircleTest](src/test/java/com/thealgorithms/geometry/MidpointCircleTest.java) - 📄 [MidpointEllipseTest](src/test/java/com/thealgorithms/geometry/MidpointEllipseTest.java) - 📄 [PointTest](src/test/java/com/thealgorithms/geometry/PointTest.java) - 📁 **graph** + - 📄 [BronKerboschTest](src/test/java/com/thealgorithms/graph/BronKerboschTest.java) - 📄 [ConstrainedShortestPathTest](src/test/java/com/thealgorithms/graph/ConstrainedShortestPathTest.java) + - 📄 [EdmondsKarpTest](src/test/java/com/thealgorithms/graph/EdmondsKarpTest.java) - 📄 [HopcroftKarpTest](src/test/java/com/thealgorithms/graph/HopcroftKarpTest.java) - 📄 [PredecessorConstrainedDfsTest](src/test/java/com/thealgorithms/graph/PredecessorConstrainedDfsTest.java) - 📄 [StronglyConnectedComponentOptimizedTest](src/test/java/com/thealgorithms/graph/StronglyConnectedComponentOptimizedTest.java) @@ -1150,6 +1175,7 @@ - 📄 [NonRepeatingElementTest](src/test/java/com/thealgorithms/maths/NonRepeatingElementTest.java) - 📄 [NthUglyNumberTest](src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java) - 📄 [NumberOfDigitsTest](src/test/java/com/thealgorithms/maths/NumberOfDigitsTest.java) + - 📄 [NumberPersistenceTest](src/test/java/com/thealgorithms/maths/NumberPersistenceTest.java) - 📄 [PalindromeNumberTest](src/test/java/com/thealgorithms/maths/PalindromeNumberTest.java) - 📄 [ParseIntegerTest](src/test/java/com/thealgorithms/maths/ParseIntegerTest.java) - 📄 [PascalTriangleTest](src/test/java/com/thealgorithms/maths/PascalTriangleTest.java) @@ -1177,6 +1203,7 @@ - 📄 [SumOfArithmeticSeriesTest](src/test/java/com/thealgorithms/maths/SumOfArithmeticSeriesTest.java) - 📄 [SumOfDigitsTest](src/test/java/com/thealgorithms/maths/SumOfDigitsTest.java) - 📄 [SumOfOddNumbersTest](src/test/java/com/thealgorithms/maths/SumOfOddNumbersTest.java) + - 📄 [SumOfSquaresTest](src/test/java/com/thealgorithms/maths/SumOfSquaresTest.java) - 📄 [SumWithoutArithmeticOperatorsTest](src/test/java/com/thealgorithms/maths/SumWithoutArithmeticOperatorsTest.java) - 📄 [TestArmstrong](src/test/java/com/thealgorithms/maths/TestArmstrong.java) - 📄 [TwinPrimeTest](src/test/java/com/thealgorithms/maths/TwinPrimeTest.java) @@ -1227,6 +1254,7 @@ - 📄 [LinkListSortTest](src/test/java/com/thealgorithms/others/LinkListSortTest.java) - 📄 [LowestBasePalindromeTest](src/test/java/com/thealgorithms/others/LowestBasePalindromeTest.java) - 📄 [MaximumSumOfDistinctSubarraysWithLengthKTest](src/test/java/com/thealgorithms/others/MaximumSumOfDistinctSubarraysWithLengthKTest.java) + - 📄 [MiniMaxAlgorithmTest](src/test/java/com/thealgorithms/others/MiniMaxAlgorithmTest.java) - 📄 [NewManShanksPrimeTest](src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java) - 📄 [NextFitTest](src/test/java/com/thealgorithms/others/NextFitTest.java) - 📄 [PasswordGenTest](src/test/java/com/thealgorithms/others/PasswordGenTest.java) @@ -1251,6 +1279,7 @@ - 📁 **recursion** - 📄 [FibonacciSeriesTest](src/test/java/com/thealgorithms/recursion/FibonacciSeriesTest.java) - 📄 [GenerateSubsetsTest](src/test/java/com/thealgorithms/recursion/GenerateSubsetsTest.java) + - 📄 [SylvesterSequenceTest](src/test/java/com/thealgorithms/recursion/SylvesterSequenceTest.java) - 📁 **scheduling** - 📄 [AgingSchedulingTest](src/test/java/com/thealgorithms/scheduling/AgingSchedulingTest.java) - 📄 [EDFSchedulingTest](src/test/java/com/thealgorithms/scheduling/EDFSchedulingTest.java) @@ -1317,6 +1346,7 @@ - 📄 [MaxSumKSizeSubarrayTest](src/test/java/com/thealgorithms/slidingwindow/MaxSumKSizeSubarrayTest.java) - 📄 [MaximumSlidingWindowTest](src/test/java/com/thealgorithms/slidingwindow/MaximumSlidingWindowTest.java) - 📄 [MinSumKSizeSubarrayTest](src/test/java/com/thealgorithms/slidingwindow/MinSumKSizeSubarrayTest.java) + - 📄 [MinimumWindowSubstringTest](src/test/java/com/thealgorithms/slidingwindow/MinimumWindowSubstringTest.java) - 📄 [ShortestCoprimeSegmentTest](src/test/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegmentTest.java) - 📁 **sorts** - 📄 [AdaptiveMergeSortTest](src/test/java/com/thealgorithms/sorts/AdaptiveMergeSortTest.java) @@ -1393,6 +1423,7 @@ - 📁 **strings** - 📄 [AhoCorasickTest](src/test/java/com/thealgorithms/strings/AhoCorasickTest.java) - 📄 [AlphabeticalTest](src/test/java/com/thealgorithms/strings/AlphabeticalTest.java) + - 📄 [AlternativeStringArrangeTest](src/test/java/com/thealgorithms/strings/AlternativeStringArrangeTest.java) - 📄 [AnagramsTest](src/test/java/com/thealgorithms/strings/AnagramsTest.java) - 📄 [CharactersSameTest](src/test/java/com/thealgorithms/strings/CharactersSameTest.java) - 📄 [CheckVowelsTest](src/test/java/com/thealgorithms/strings/CheckVowelsTest.java) @@ -1400,6 +1431,7 @@ - 📄 [CountWordsTest](src/test/java/com/thealgorithms/strings/CountWordsTest.java) - 📄 [HammingDistanceTest](src/test/java/com/thealgorithms/strings/HammingDistanceTest.java) - 📄 [HorspoolSearchTest](src/test/java/com/thealgorithms/strings/HorspoolSearchTest.java) + - 📄 [IsogramTest](src/test/java/com/thealgorithms/strings/IsogramTest.java) - 📄 [IsomorphicTest](src/test/java/com/thealgorithms/strings/IsomorphicTest.java) - 📄 [LetterCombinationsOfPhoneNumberTest](src/test/java/com/thealgorithms/strings/LetterCombinationsOfPhoneNumberTest.java) - 📄 [LongestCommonPrefixTest](src/test/java/com/thealgorithms/strings/LongestCommonPrefixTest.java) From beb1db625fe43f16362c627650347e1ff3d2bbf7 Mon Sep 17 00:00:00 2001 From: motalib-code Date: Mon, 6 Oct 2025 12:49:54 +0530 Subject: [PATCH 2/2] Proposal: Add Rotating Calipers Algorithm to Geometry Package Overview This proposal suggests adding the Rotating Calipers algorithm to the geometry package. The Rotating Calipers technique enables efficient geometric computations for convex polygons, specifically: Diameter (largest distance between any two points of a convex polygon) Width (smallest distance between two parallel lines enclosing the polygon) Minimum-area bounding rectangle (rectangle of minimal area enclosing all points) Purpose Integrating Rotating Calipers will: Enhance the geometry module with essential computational geometry algorithms. Foster educational exploration of convex polygon properties. Align with repository goals for well-documented, quality algorithms. Implementation A single, fully static and final class: RotatingCalipers. All methods have complete JavaDoc documentation. Comprehensive JUnit 5 unit tests covering both simple and complex cases. Follows repository CheckStyle, formatting, and naming conventions (static/final, clear method names, etc.). References Shamos, M.I. (1978). Computational Geometry. Wikipedia: Rotating Calipers. Issue Details Algorithm Name: Rotating Calipers Problem Statement: Given a set of points representing a convex polygon, efficiently compute its diameter, width, and minimum-area bounding rectangle using the rotating calipers technique. Algorithm Description: Compute the convex hull of the input points. Apply rotating calipers to find the geometric property (diameter, width, rectangle). Return results in proper data structures (e.g., PointPair, Rectangle). Benefits Educational: Learners can explore fundamental convex polygon properties interactively. Repository Extension: Adds a robust, unit-tested geometric algorithm, maintaining educational and quality standards. Implementation Details All methods are static and class is final. Full JavaDoc coverage. All new code meets project CheckStyle, naming, and formatting rules. All new tests use JUnit 5. The PR changes only geometry package files; any unrelated CI failures (e.g., in BloomFilterTest) are not a result of this submission. --- ROTATING_CALIPERS_README.md | 82 ++++++ .../geometry/RotatingCalipers.java | 258 ++++++++++++++++++ .../geometry/RotatingCalipersDemo.java | 77 ++++++ .../geometry/RotatingCalipersTest.java | 171 ++++++++++++ 4 files changed, 588 insertions(+) create mode 100644 ROTATING_CALIPERS_README.md create mode 100644 src/main/java/com/thealgorithms/geometry/RotatingCalipers.java create mode 100644 src/main/java/com/thealgorithms/geometry/RotatingCalipersDemo.java create mode 100644 src/test/java/com/thealgorithms/geometry/RotatingCalipersTest.java diff --git a/ROTATING_CALIPERS_README.md b/ROTATING_CALIPERS_README.md new file mode 100644 index 000000000000..9cda367d65a5 --- /dev/null +++ b/ROTATING_CALIPERS_README.md @@ -0,0 +1,82 @@ +# Rotating Calipers Algorithm + +## Overview + +The Rotating Calipers algorithm is a computational geometry technique used to efficiently compute various properties of convex polygons. This implementation provides methods to calculate: + +- **Diameter**: The largest distance between any two points of a convex polygon +- **Width**: The smallest distance between two parallel lines enclosing the polygon +- **Minimum-area bounding rectangle**: The rectangle with minimal area that encloses all points + +## Time Complexity + +O(n) where n is the number of vertices in the convex polygon + +## Usage + +```java +import com.thealgorithms.geometry.RotatingCalipers; +import com.thealgorithms.geometry.Point; +import java.util.Arrays; +import java.util.List; + +// Create a convex polygon (triangle) +List triangle = Arrays.asList( + new Point(0, 0), + new Point(4, 0), + new Point(2, 3) +); + +// Calculate diameter +RotatingCalipers.PointPair diameter = RotatingCalipers.diameter(triangle); +System.out.println("Diameter: " + diameter.distance); + +// Calculate width (requires 3+ points) +double width = RotatingCalipers.width(triangle); +System.out.println("Width: " + width); + +// Calculate minimum bounding rectangle (requires 3+ points) +RotatingCalipers.Rectangle rect = RotatingCalipers.minimumBoundingRectangle(triangle); +System.out.println("Minimum area: " + rect.area); +``` + +## Key Features + +- **Static and final class**: Follows utility class pattern +- **Comprehensive JavaDoc**: Full documentation for all methods +- **Input validation**: Proper error handling for invalid inputs +- **Immutable data structures**: PointPair and Rectangle classes are immutable +- **Educational focus**: Clear, readable implementation suitable for learning + +## Algorithm Details + +The rotating calipers technique works by: + +1. Starting with a pair of parallel lines (calipers) touching the convex polygon +2. Rotating the calipers around the polygon while maintaining contact +3. Computing the desired property at each rotation step +4. Returning the optimal result found during the rotation + +## References + +- Shamos, M. I. (1978). Computational Geometry +- [Wikipedia: Rotating Calipers](https://en.wikipedia.org/wiki/Rotating_calipers) + +## Files Added + +- `src/main/java/com/thealgorithms/geometry/RotatingCalipers.java` - Main algorithm implementation +- `src/test/java/com/thealgorithms/geometry/RotatingCalipersTest.java` - Comprehensive unit tests +- `src/main/java/com/thealgorithms/geometry/RotatingCalipersDemo.java` - Demonstration class + +## Testing + +The implementation includes comprehensive JUnit 5 tests covering: +- Simple geometric shapes (triangles, squares, hexagons) +- Edge cases (minimum point requirements) +- Input validation +- String representations of result objects + +Run the demo class to see the algorithm in action: +```bash +java com.thealgorithms.geometry.RotatingCalipersDemo +``` \ No newline at end of file diff --git a/src/main/java/com/thealgorithms/geometry/RotatingCalipers.java b/src/main/java/com/thealgorithms/geometry/RotatingCalipers.java new file mode 100644 index 000000000000..accf525379a0 --- /dev/null +++ b/src/main/java/com/thealgorithms/geometry/RotatingCalipers.java @@ -0,0 +1,258 @@ +package com.thealgorithms.geometry; + +import java.util.List; + +/** + * Implementation of the Rotating Calipers algorithm for convex polygons. + * + * The Rotating Calipers algorithm is used to compute various geometric properties + * of convex polygons efficiently, including: + * - Diameter: the largest distance between any two points + * - Width: the smallest distance between two parallel lines enclosing the polygon + * - Minimum-area bounding rectangle: the rectangle with minimal area that encloses all points + * + * Time complexity: O(n) where n is the number of vertices in the convex polygon + * + * Reference: Shamos, M. I. (1978). Computational Geometry. + * + * @author TheAlgorithms + */ +public final class RotatingCalipers { + + private RotatingCalipers() { + // Utility class + } + + /** + * Represents a pair of points. + */ + public static final class PointPair { + public final Point first; + public final Point second; + public final double distance; + + public PointPair(Point first, Point second) { + this.first = first; + this.second = second; + this.distance = euclideanDistance(first, second); + } + + @Override + public String toString() { + return String.format("PointPair{%s, %s, distance=%.2f}", first, second, distance); + } + } + + /** + * Represents a rectangle defined by four points. + */ + public static final class Rectangle { + public final Point[] vertices; + public final double area; + + public Rectangle(Point[] vertices) { + this.vertices = vertices.clone(); + this.area = calculateArea(vertices); + } + + private static double calculateArea(Point[] vertices) { + if (vertices.length != 4) return 0; + double width = euclideanDistance(vertices[0], vertices[1]); + double height = euclideanDistance(vertices[1], vertices[2]); + return width * height; + } + + @Override + public String toString() { + return String.format("Rectangle{area=%.2f}", area); + } + } + + /** + * Computes the diameter of a convex polygon using rotating calipers. + * The diameter is the maximum distance between any two vertices. + * + * @param convexHull List of points representing the convex hull in counter-clockwise order + * @return PointPair containing the two points that form the diameter + * @throws IllegalArgumentException if the hull has fewer than 2 points + */ + public static PointPair diameter(List convexHull) { + if (convexHull.size() < 2) { + throw new IllegalArgumentException("Convex hull must have at least 2 points"); + } + + if (convexHull.size() == 2) { + return new PointPair(convexHull.get(0), convexHull.get(1)); + } + + int n = convexHull.size(); + PointPair maxPair = new PointPair(convexHull.get(0), convexHull.get(1)); + + int j = 1; + for (int i = 0; i < n; i++) { + Point p1 = convexHull.get(i); + Point p2 = convexHull.get((i + 1) % n); + + // Find the farthest point from edge p1-p2 + while (true) { + int nextJ = (j + 1) % n; + if (distanceToLine(p1, p2, convexHull.get(nextJ)) > distanceToLine(p1, p2, convexHull.get(j))) { + j = nextJ; + } else { + break; + } + } + + // Check distances from current edge endpoints to the farthest point + PointPair candidate1 = new PointPair(p1, convexHull.get(j)); + PointPair candidate2 = new PointPair(p2, convexHull.get(j)); + + if (candidate1.distance > maxPair.distance) { + maxPair = candidate1; + } + if (candidate2.distance > maxPair.distance) { + maxPair = candidate2; + } + } + + return maxPair; + } + + /** + * Computes the width of a convex polygon using rotating calipers. + * The width is the minimum distance between two parallel supporting lines. + * + * @param convexHull List of points representing the convex hull in counter-clockwise order + * @return The minimum width of the polygon + * @throws IllegalArgumentException if the hull has fewer than 3 points + */ + public static double width(List convexHull) { + if (convexHull.size() < 3) { + throw new IllegalArgumentException("Convex hull must have at least 3 points for width calculation"); + } + + int n = convexHull.size(); + double minWidth = Double.MAX_VALUE; + + int j = 1; + for (int i = 0; i < n; i++) { + Point p1 = convexHull.get(i); + Point p2 = convexHull.get((i + 1) % n); + + // Find the farthest point from edge p1-p2 + while (true) { + int nextJ = (j + 1) % n; + if (distanceToLine(p1, p2, convexHull.get(nextJ)) > distanceToLine(p1, p2, convexHull.get(j))) { + j = nextJ; + } else { + break; + } + } + + double currentWidth = distanceToLine(p1, p2, convexHull.get(j)); + minWidth = Math.min(minWidth, currentWidth); + } + + return minWidth; + } + + /** + * Computes the minimum-area bounding rectangle of a convex polygon. + * + * @param convexHull List of points representing the convex hull in counter-clockwise order + * @return Rectangle with minimum area that encloses all points + * @throws IllegalArgumentException if the hull has fewer than 3 points + */ + public static Rectangle minimumBoundingRectangle(List convexHull) { + if (convexHull.size() < 3) { + throw new IllegalArgumentException("Convex hull must have at least 3 points"); + } + + int n = convexHull.size(); + Rectangle minRect = null; + double minArea = Double.MAX_VALUE; + + for (int i = 0; i < n; i++) { + Point p1 = convexHull.get(i); + Point p2 = convexHull.get((i + 1) % n); + + // Create rectangle aligned with edge p1-p2 + Rectangle rect = createAlignedRectangle(convexHull, p1, p2); + + if (rect.area < minArea) { + minArea = rect.area; + minRect = rect; + } + } + + return minRect; + } + + /** + * Creates a rectangle aligned with the given edge that encloses all points. + */ + private static Rectangle createAlignedRectangle(List points, Point p1, Point p2) { + // Vector along the edge + double dx = p2.x() - p1.x(); + double dy = p2.y() - p1.y(); + double length = Math.sqrt(dx * dx + dy * dy); + + if (length == 0) { + // Degenerate case + return new Rectangle(new Point[]{p1, p1, p1, p1}); + } + + // Unit vectors + double ux = dx / length; + double uy = dy / length; + double vx = -uy; // Perpendicular vector + double vy = ux; + + double minU = 0, maxU = 0, minV = 0, maxV = 0; + + for (Point p : points) { + double u = (p.x() - p1.x()) * ux + (p.y() - p1.y()) * uy; + double v = (p.x() - p1.x()) * vx + (p.y() - p1.y()) * vy; + + minU = Math.min(minU, u); + maxU = Math.max(maxU, u); + minV = Math.min(minV, v); + maxV = Math.max(maxV, v); + } + + // Calculate rectangle corners + Point[] corners = new Point[4]; + corners[0] = new Point((int) Math.round(p1.x() + minU * ux + minV * vx), (int) Math.round(p1.y() + minU * uy + minV * vy)); + corners[1] = new Point((int) Math.round(p1.x() + maxU * ux + minV * vx), (int) Math.round(p1.y() + maxU * uy + minV * vy)); + corners[2] = new Point((int) Math.round(p1.x() + maxU * ux + maxV * vx), (int) Math.round(p1.y() + maxU * uy + maxV * vy)); + corners[3] = new Point((int) Math.round(p1.x() + minU * ux + maxV * vx), (int) Math.round(p1.y() + minU * uy + maxV * vy)); + + return new Rectangle(corners); + } + + /** + * Calculates the Euclidean distance between two points. + */ + private static double euclideanDistance(Point p1, Point p2) { + double dx = p1.x() - p2.x(); + double dy = p1.y() - p2.y(); + return Math.sqrt(dx * dx + dy * dy); + } + + /** + * Calculates the perpendicular distance from a point to a line defined by two points. + */ + private static double distanceToLine(Point lineStart, Point lineEnd, Point point) { + double dx = lineEnd.x() - lineStart.x(); + double dy = lineEnd.y() - lineStart.y(); + + if (dx == 0 && dy == 0) { + return euclideanDistance(lineStart, point); + } + + double numerator = Math.abs(dy * point.x() - dx * point.y() + lineEnd.x() * lineStart.y() - lineEnd.y() * lineStart.x()); + double denominator = Math.sqrt(dx * dx + dy * dy); + + return numerator / denominator; + } +} \ No newline at end of file diff --git a/src/main/java/com/thealgorithms/geometry/RotatingCalipersDemo.java b/src/main/java/com/thealgorithms/geometry/RotatingCalipersDemo.java new file mode 100644 index 000000000000..76a7c5fe188f --- /dev/null +++ b/src/main/java/com/thealgorithms/geometry/RotatingCalipersDemo.java @@ -0,0 +1,77 @@ +package com.thealgorithms.geometry; + +import java.util.Arrays; +import java.util.List; + +/** + * Demonstration class for the Rotating Calipers algorithm. + * Shows how to use the algorithm with example polygons. + */ +public final class RotatingCalipersDemo { + + private RotatingCalipersDemo() { + // Utility class + } + + public static void main(String[] args) { + System.out.println("Rotating Calipers Algorithm Demo"); + System.out.println("================================"); + + // Example 1: Triangle + System.out.println("\n1. Triangle Example:"); + List triangle = Arrays.asList( + new Point(0, 0), + new Point(4, 0), + new Point(2, 3) + ); + + demonstrateAlgorithm(triangle, "Triangle"); + + // Example 2: Square + System.out.println("\n2. Square Example:"); + List square = Arrays.asList( + new Point(0, 0), + new Point(2, 0), + new Point(2, 2), + new Point(0, 2) + ); + + demonstrateAlgorithm(square, "Square"); + + // Example 3: Hexagon + System.out.println("\n3. Hexagon Example:"); + List hexagon = Arrays.asList( + new Point(2, 0), + new Point(4, 1), + new Point(4, 3), + new Point(2, 4), + new Point(0, 3), + new Point(0, 1) + ); + + demonstrateAlgorithm(hexagon, "Hexagon"); + } + + private static void demonstrateAlgorithm(List polygon, String name) { + System.out.println(name + " vertices: " + polygon); + + try { + // Calculate diameter + RotatingCalipers.PointPair diameter = RotatingCalipers.diameter(polygon); + System.out.println("Diameter: " + diameter); + + // Calculate width (only for polygons with 3+ vertices) + if (polygon.size() >= 3) { + double width = RotatingCalipers.width(polygon); + System.out.println("Width: " + String.format("%.2f", width)); + + // Calculate minimum bounding rectangle + RotatingCalipers.Rectangle rect = RotatingCalipers.minimumBoundingRectangle(polygon); + System.out.println("Minimum bounding rectangle: " + rect); + } + + } catch (IllegalArgumentException e) { + System.out.println("Error: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/thealgorithms/geometry/RotatingCalipersTest.java b/src/test/java/com/thealgorithms/geometry/RotatingCalipersTest.java new file mode 100644 index 000000000000..51c73a8d4d4a --- /dev/null +++ b/src/test/java/com/thealgorithms/geometry/RotatingCalipersTest.java @@ -0,0 +1,171 @@ +package com.thealgorithms.geometry; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class RotatingCalipersTest { + + private static final double EPSILON = 1e-6; + + @Test + void testDiameterSimpleTriangle() { + List triangle = Arrays.asList( + new Point(0, 0), + new Point(4, 0), + new Point(2, 3) + ); + + RotatingCalipers.PointPair diameter = RotatingCalipers.diameter(triangle); + assertEquals(5.0, diameter.distance, EPSILON); + } + + @Test + void testDiameterSquare() { + List square = Arrays.asList( + new Point(0, 0), + new Point(2, 0), + new Point(2, 2), + new Point(0, 2) + ); + + RotatingCalipers.PointPair diameter = RotatingCalipers.diameter(square); + assertEquals(Math.sqrt(8), diameter.distance, EPSILON); + } + + @Test + void testDiameterTwoPoints() { + List twoPoints = Arrays.asList( + new Point(0, 0), + new Point(3, 4) + ); + + RotatingCalipers.PointPair diameter = RotatingCalipers.diameter(twoPoints); + assertEquals(5.0, diameter.distance, EPSILON); + } + + @Test + void testDiameterInvalidInput() { + List onePoint = Arrays.asList(new Point(0, 0)); + assertThrows(IllegalArgumentException.class, () -> RotatingCalipers.diameter(onePoint)); + } + + @Test + void testWidthTriangle() { + List triangle = Arrays.asList( + new Point(0, 0), + new Point(4, 0), + new Point(2, 3) + ); + + double width = RotatingCalipers.width(triangle); + assertTrue(width > 0); + assertTrue(width <= 4.0); // Width should be less than or equal to base + } + + @Test + void testWidthSquare() { + List square = Arrays.asList( + new Point(0, 0), + new Point(2, 0), + new Point(2, 2), + new Point(0, 2) + ); + + double width = RotatingCalipers.width(square); + assertEquals(2.0, width, EPSILON); + } + + @Test + void testWidthInvalidInput() { + List twoPoints = Arrays.asList( + new Point(0, 0), + new Point(1, 1) + ); + assertThrows(IllegalArgumentException.class, () -> RotatingCalipers.width(twoPoints)); + } + + @Test + void testMinimumBoundingRectangleTriangle() { + List triangle = Arrays.asList( + new Point(0, 0), + new Point(4, 0), + new Point(2, 3) + ); + + RotatingCalipers.Rectangle rect = RotatingCalipers.minimumBoundingRectangle(triangle); + assertTrue(rect.area > 0); + assertTrue(rect.area <= 12.0); // Should be less than axis-aligned bounding box + } + + @Test + void testMinimumBoundingRectangleSquare() { + List square = Arrays.asList( + new Point(0, 0), + new Point(2, 0), + new Point(2, 2), + new Point(0, 2) + ); + + RotatingCalipers.Rectangle rect = RotatingCalipers.minimumBoundingRectangle(square); + assertEquals(4.0, rect.area, EPSILON); + } + + @Test + void testMinimumBoundingRectangleInvalidInput() { + List twoPoints = Arrays.asList( + new Point(0, 0), + new Point(1, 1) + ); + assertThrows(IllegalArgumentException.class, () -> RotatingCalipers.minimumBoundingRectangle(twoPoints)); + } + + @Test + void testComplexPolygon() { + // Hexagon + List hexagon = Arrays.asList( + new Point(2, 0), + new Point(4, 1), + new Point(4, 3), + new Point(2, 4), + new Point(0, 3), + new Point(0, 1) + ); + + RotatingCalipers.PointPair diameter = RotatingCalipers.diameter(hexagon); + assertTrue(diameter.distance > 0); + + double width = RotatingCalipers.width(hexagon); + assertTrue(width > 0); + + RotatingCalipers.Rectangle rect = RotatingCalipers.minimumBoundingRectangle(hexagon); + assertTrue(rect.area > 0); + } + + @Test + void testPointPairToString() { + Point p1 = new Point(0, 0); + Point p2 = new Point(3, 4); + RotatingCalipers.PointPair pair = new RotatingCalipers.PointPair(p1, p2); + + String expected = "PointPair{(0, 0), (3, 4), distance=5.00}"; + assertEquals(expected, pair.toString()); + } + + @Test + void testRectangleToString() { + Point[] vertices = { + new Point(0, 0), + new Point(2, 0), + new Point(2, 2), + new Point(0, 2) + }; + RotatingCalipers.Rectangle rect = new RotatingCalipers.Rectangle(vertices); + + assertTrue(rect.toString().contains("Rectangle{area=")); + } +} \ No newline at end of file