From 1c997f6baaba23acdcc38ded3d44ed6d5746005b Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Wed, 15 Nov 2023 01:35:49 +0000 Subject: [PATCH 01/18] try some updates. --- .github/workflows/ci.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7e4eb8ae..43736135 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,10 +1,10 @@ jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - uses: "actions/checkout@v1" + - uses: "actions/checkout@v3" - id: setup-haskell-cabal - uses: "haskell/actions/setup@v1.2" + uses: "haskell-actions/setup@v2" with: cabal-version: "${{ matrix.cabal }}" enable-stack: false @@ -33,10 +33,10 @@ jobs: strategy: matrix: cabal: - - '3.4' + - '3.10' ghc: - '9.0.2' - - '8.10.4' + - '8.10.7' - '8.8.4' name: Haskell CI on: From 8faea77518d4322fef55491d35297d5a410d5c36 Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Wed, 15 Nov 2023 02:01:16 +0000 Subject: [PATCH 02/18] add ghc 9.2.9 --- .github/workflows/ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 43736135..e22c3923 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -35,6 +35,7 @@ jobs: cabal: - '3.10' ghc: + - '9.2.8' - '9.0.2' - '8.10.7' - '8.8.4' From c07687734e4abf4de2d89868e70398aade433c16 Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Sun, 3 Dec 2023 00:02:29 +0000 Subject: [PATCH 03/18] add missing carriage return. --- Graphics/Slicer/Math/Definitions.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/Graphics/Slicer/Math/Definitions.hs b/Graphics/Slicer/Math/Definitions.hs index 2067c2e9..8436855e 100644 --- a/Graphics/Slicer/Math/Definitions.hs +++ b/Graphics/Slicer/Math/Definitions.hs @@ -281,3 +281,4 @@ pointsOfContour (PointContour _ _ p1 p2 p3 pts@(Slist vals _)) pointsOfContour (LineSegContour _ _ l1 l2 moreLines@(Slist lns _)) | size moreLines == Infinity = error "cannot handle infinite contours." | otherwise = startPoint l1:startPoint l2:(startPoint <$> lns) + From 4392d98a7a520104b5671edca5053e18bfc43e31 Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Sun, 3 Dec 2023 00:04:03 +0000 Subject: [PATCH 04/18] use hackage haskell-floating-point, and master of floating-bits. --- cabal.project | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cabal.project b/cabal.project index 53150794..a78a0051 100644 --- a/cabal.project +++ b/cabal.project @@ -5,10 +5,10 @@ documentation: True source-repository-package type: git location: https://github.com/julialongtin/floating-bits.git - tag: 302c996 +-- tag: 302c996 -source-repository-package - type: git - location: https://github.com/julialongtin/haskell-floating-point.git - tag: 76df773 - subdir: rounded-hw +-- source-repository-package +-- type: git +-- location: https://github.com/julialongtin/haskell-floating-point.git +-- tag: 76df773 +-- subdir: rounded-hw From 8b67269819877e609cb29856ba410175047ab2eb Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Sun, 3 Dec 2023 16:30:17 +0000 Subject: [PATCH 05/18] use vecOfP accessor, instead of manually unwrapping type. --- Graphics/Slicer/Math/PGAPrimitives.hs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Graphics/Slicer/Math/PGAPrimitives.hs b/Graphics/Slicer/Math/PGAPrimitives.hs index 2489361c..db9b415c 100644 --- a/Graphics/Slicer/Math/PGAPrimitives.hs +++ b/Graphics/Slicer/Math/PGAPrimitives.hs @@ -599,7 +599,8 @@ angleCosBetweenProjectiveLines line1 line2 iErrSum = sumPPointErrs iPointErrVals <> sumIErrs rawAngleErrs angle = valOf 0 $ getVal [GEZero 1, GEPlus 1, GEPlus 2] rawAngle (GVec rawAngle, rawAngleErrs) = lvec2 ∧+ (motor • iPointVec • antiMotor) - (CPPoint2 iPointVec, (npl1Err, npl2Err, PPoint2Err _ iPointErrVals _ _ _ _ _)) = fromJust canonicalizedIntersection + iPointVec = vecOfP iPoint + (iPoint, (npl1Err, npl2Err, PPoint2Err _ iPointErrVals _ _ _ _ _)) = fromJust canonicalizedIntersection motor = addVecPairWithoutErr (lvec1 • gaI) (GVec [GVal 1 (singleton G0)]) antiMotor = addVecPairWithoutErr (lvec1 • gaI) (GVec [GVal (-1) (singleton G0)]) canonicalizedIntersection = canonicalizedIntersectionOf2PL line1 line2 @@ -841,7 +842,8 @@ projectivePointToEuclidianPoint point res = Point2 (xVal, yVal) xVal = negate $ valOf 0 $ getVal [GEZero 1, GEPlus 2] vals yVal = valOf 0 $ getVal [GEZero 1, GEPlus 1] vals - (CPPoint2 (GVec vals), resErr) = canonicalizeP point + (GVec vals) = vecOfP pointRes + (pointRes, resErr) = canonicalizeP point -- | Wrapper. pToEP = projectivePointToEuclidianPoint From a11c35d3025083b886e30671bcce1a2f0450d93a Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Sun, 3 Dec 2023 16:43:15 +0000 Subject: [PATCH 06/18] use vecOfL accessor, instead of manually unwrapping type. --- Graphics/Slicer/Math/PGA.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Graphics/Slicer/Math/PGA.hs b/Graphics/Slicer/Math/PGA.hs index 44dedf57..46df97e9 100644 --- a/Graphics/Slicer/Math/PGA.hs +++ b/Graphics/Slicer/Math/PGA.hs @@ -229,13 +229,14 @@ pPointOnPerpWithErr line point d = (PPoint2 res, resErr) -- translate the input point along the perpendicular bisector. res = motor•pVec•reverseGVec motor resErr = (nLineErr, cPointErr, perpLineErrs, gaIScaledErr) - motor = addVecPairWithoutErr (perpLine • gaIScaled) (GVec [GVal 1 (singleton G0)]) + motor = addVecPairWithoutErr (perpLineVec • gaIScaled) (GVec [GVal 1 (singleton G0)]) -- I, in this geometric algebra system. we multiply it times d/2, to reduce the number of multiples we have to do when creating the motor. gaIScaled = GVec [GVal (d/2) (fromList [GEZero 1, GEPlus 1, GEPlus 2])] gaIScaledErr = UlpSum $ realToFrac $ doubleUlp $ realToFrac (realToFrac (abs d) / 2 :: Rounded 'TowardInf ℝ) -- | Get a perpendicular line, crossing the input line at the given point. -- FIXME: where should we put this in the error quotent of PLine2Err? - (PLine2 perpLine, (nLineErr, _, perpLineErrs)) = perpLineAt line cPoint + perpLineVec = vecOfL perpLine + (perpLine, (nLineErr, _, perpLineErrs)) = perpLineAt line cPoint pVec = vecOfP $ forceBasisOfP cPoint (cPoint, cPointErr) = canonicalizeP point From 24b375cc67214089baba00ea008969f558884f1f Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Sun, 3 Dec 2023 16:48:36 +0000 Subject: [PATCH 07/18] remove unneeded cast. --- Graphics/Slicer/Math/PGA.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Graphics/Slicer/Math/PGA.hs b/Graphics/Slicer/Math/PGA.hs index 46df97e9..b64a42dc 100644 --- a/Graphics/Slicer/Math/PGA.hs +++ b/Graphics/Slicer/Math/PGA.hs @@ -341,7 +341,7 @@ pLineIntersectsLineSeg (pl1, pl1ErrOrigin) l1 | hasIntersection && endDistance <= ulpEndSum = Left $ HitEndPoint l1 | hasIntersection = Right $ IntersectsIn rawIntersection (pl1Err, pl2Err, rawIntersectionErr) | hasRawIntersection = Left $ NoIntersection rawIntersection (pl1Err, pl2Err, rawIntersectionErr) - | otherwise = Left $ NoIntersection ((\(PPoint2 v) -> CPPoint2 v) rawIntersect) (pl1Err, pl2Err, rawIntersectErr) + | otherwise = Left $ NoIntersection rawIntersect (pl1Err, pl2Err, rawIntersectErr) where res = plinesIntersectIn (pl1, pl1Err) (pl2, pl2Err) ulpStartSum = ulpVal startDistanceErr @@ -392,7 +392,7 @@ lineSegIntersectsLineSeg l1 l2 | hasIntersection && end2Distance <= ulpEnd2Sum = Left $ HitEndPoint l2 | hasIntersection = Right $ IntersectsIn rawIntersection (pl1Err, pl2Err, rawIntersectionErr) | hasRawIntersection = Left $ NoIntersection rawIntersection (pl1Err, pl2Err, rawIntersectionErr) - | otherwise = Left $ NoIntersection ((\(PPoint2 v) -> CPPoint2 v) rawIntersect) (pl1Err, pl2Err, rawIntersectErr) + | otherwise = Left $ NoIntersection rawIntersect (pl1Err, pl2Err, rawIntersectErr) where res = plinesIntersectIn (pl1, pl1Err) (pl2, pl2Err) start1FudgeFactor = start1DistanceErr <> pLineErrAtPPoint (pl1,pl1Err) start1 From eeefd5f111a6469229e488bf7af6fbdaa3ee1e15 Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Thu, 14 Dec 2023 13:35:02 +0000 Subject: [PATCH 08/18] use vecOfL accessor, instead of manually unwrapping type. --- Graphics/Slicer/Math/Skeleton/Definitions.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Graphics/Slicer/Math/Skeleton/Definitions.hs b/Graphics/Slicer/Math/Skeleton/Definitions.hs index 0cb4c553..7457840d 100644 --- a/Graphics/Slicer/Math/Skeleton/Definitions.hs +++ b/Graphics/Slicer/Math/Skeleton/Definitions.hs @@ -95,7 +95,7 @@ import Graphics.Slicer.Math.Intersections (intersectionsAtSamePoint, noIntersect import Graphics.Slicer.Math.Lossy (eToPLine2) -import Graphics.Slicer.Math.PGA (Arcable(errOfOut, hasArc, outOf), PIntersection(IntersectsIn), PLine2Err, Pointable(canPoint, cPPointOf, errOfCPPoint, ePointOf), PPoint2Err, ProjectiveLine(PLine2), ProjectiveLine2, ProjectivePoint, distance2PP, eToPP, flipL, outAndErrOf, pToEP, plinesIntersectIn, pLineIsLeft) +import Graphics.Slicer.Math.PGA (Arcable(errOfOut, hasArc, outOf), PIntersection(IntersectsIn), PLine2Err, Pointable(canPoint, cPPointOf, errOfCPPoint, ePointOf), PPoint2Err, ProjectiveLine(PLine2), ProjectiveLine2, ProjectivePoint, distance2PP, eToPP, flipL, outAndErrOf, pToEP, plinesIntersectIn, pLineIsLeft, vecOfL) -- | A point where two lines segments that are part of a contour intersect, emmiting an arc toward the interior of a contour. -- FIXME: a source should have a different UlpSum for it's point and it's output. @@ -429,8 +429,8 @@ concavePLines seg1 seg2 | eToPLine2 seg1 `pLineIsLeft` eToPLine2 seg2 == Just True = Just $ PLine2 $ addVecPair pv1 pv2 | otherwise = Nothing where - (PLine2 pv1) = eToPLine2 seg1 - (PLine2 pv2) = flipL $ eToPLine2 seg2 + pv1 = vecOfL $ eToPLine2 seg1 + pv2 = vecOfL $ flipL $ eToPLine2 seg2 -- | Sort a set of PLines. yes, this is 'backwards', to match the counterclockwise order of contours. {-# INLINABLE sortedPLines #-} From 756a98b5f97392c5dd00861ca959f43d74e2a2b9 Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Thu, 14 Dec 2023 13:38:29 +0000 Subject: [PATCH 09/18] use vecOfL accessor, instead of manually unwrapping type. --- tests/Math/PGA.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Math/PGA.hs b/tests/Math/PGA.hs index f13c1231..d986c12a 100644 --- a/tests/Math/PGA.hs +++ b/tests/Math/PGA.hs @@ -1049,7 +1049,7 @@ prop_translateRotateMovesY x y rawD prop_NormPLineIsPLine :: ℝ -> ℝ -> NonZero ℝ -> NonZero ℝ -> Bool prop_NormPLineIsPLine x y dx dy = fst (normalizeL $ randomPLine x y dx dy) `sameDirection` - fst (normalizeL ((\(NPLine2 a) -> PLine2 a) $ fst $ normalizeL $ randomPLine x y dx dy)) + fst (normalizeL (PLine2 $ vecOfL $ fst $ normalizeL $ randomPLine x y dx dy)) prop_PLinesIntersectAtOrigin :: NonZero ℝ -> ℝ -> NonZero ℝ -> ℝ -> Bool prop_PLinesIntersectAtOrigin rawX y rawX2 rawY2 From 1a26d85562f650e3018f1f447a5180617d8e5a35 Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Thu, 14 Dec 2023 14:08:50 +0000 Subject: [PATCH 10/18] create pattern matching function functions that return tuples, rather than relying on a fixed size list. --- Graphics/Slicer/Math/RandomGeometry.hs | 34 +++++++++++++++++------ tests/Math/Geometry/ConcaveChevronQuad.hs | 14 ++++++++-- tests/Math/Geometry/Rectangle.hs | 10 +++++-- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/Graphics/Slicer/Math/RandomGeometry.hs b/Graphics/Slicer/Math/RandomGeometry.hs index 2c06d9e2..b4d3eacc 100644 --- a/Graphics/Slicer/Math/RandomGeometry.hs +++ b/Graphics/Slicer/Math/RandomGeometry.hs @@ -162,7 +162,7 @@ instance Fractional (Radian a) where (/) (Radian r1) (Radian r2) = Radian $ r1 / r2 fromRational a = Radian $ fromRational a -instance (Ord a, Num a, Fractional a) => Fractional (Positive a) where +instance (Ord a, Fractional a) => Fractional (Positive a) where (/) (Positive r1) (Positive r2) = Positive $ r1 / r2 fromRational a = Positive $ fromRational a @@ -223,6 +223,24 @@ randomRectangle centerX centerY rawFirstTilt secondTilt distanceToCorner = rando | otherwise = rawFirstTilt radians = sort [firstTilt, secondTilt, flipRadian firstTilt, flipRadian secondTilt] +-- | Ensure only two distances are returned. +twoDistances :: [Positive ℝ] -> (Positive ℝ, Positive ℝ) +twoDistances distances = case distances of + [a,b] -> (a,b) + _ -> error "wrong distance count." + +-- | Ensure only two tilt angles are returned. +twoTilts :: [Radian ℝ] -> (Radian ℝ, Radian ℝ) +twoTilts tilts = case tilts of + [a,b] -> (a,b) + _ -> error "wrong tilt count." + +threeTilts :: [Radian ℝ] -> (Radian ℝ, Radian ℝ, Radian ℝ) +threeTilts tilts = case tilts of + [a,b,c] -> (a,b,c) + _ -> error "wrong tilt count." + + -- | Generate a random convex four sided polygon, with two right angles. -- FIXME: only supports non-sequential right angles. -- FIXME: also only supports bisectable angles, where the line between the non-right angled sides intersects the origin. @@ -231,7 +249,7 @@ randomDualRightQuad centerX centerY firstTilt rawFirstDistanceToCorner rawSecond where distances = [firstDistanceToCorner, secondDistanceToCorner, firstDistanceToCorner, fourthDistanceToCorner] fourthDistanceToCorner = (firstDistanceToCorner * firstDistanceToCorner) / secondDistanceToCorner - [firstDistanceToCorner, secondDistanceToCorner] = sort $ ensureUniqueDistance [rawFirstDistanceToCorner, rawSecondDistanceToCorner] + (firstDistanceToCorner, secondDistanceToCorner) = twoDistances $ sort $ ensureUniqueDistance [rawFirstDistanceToCorner, rawSecondDistanceToCorner] radians = [firstTilt, secondTilt, flipRadian firstTilt, flipRadian secondTilt] secondTilt = firstTilt + (Radian pi/2) @@ -240,9 +258,9 @@ randomConvexSingleRightQuad :: ℝ -> ℝ -> Radian ℝ -> Radian ℝ -> Radian randomConvexSingleRightQuad centerX centerY rawFirstTilt rawSecondTilt rawThirdTilt rawFirstDistanceToCorner rawSecondDistanceToCorner = randomStarPoly centerX centerY $ makePairs distances radians where distances = replicate 3 secondDistanceToCorner <> [firstDistanceToCorner] - [firstDistanceToCorner, secondDistanceToCorner] = sort $ ensureUniqueDistance [rawFirstDistanceToCorner, rawSecondDistanceToCorner] + (firstDistanceToCorner, secondDistanceToCorner) = twoDistances $ sort $ ensureUniqueDistance [rawFirstDistanceToCorner, rawSecondDistanceToCorner] radians = sort [firstTilt, secondTilt, flipRadian firstTilt, flipRadian thirdTilt] - [firstTilt, secondTilt, thirdTilt] = sort $ ensureUniqueClippedRadian rawRadians + (firstTilt, secondTilt, thirdTilt) = threeTilts $ sort $ ensureUniqueClippedRadian rawRadians rawRadians = [rawFirstTilt, rawSecondTilt, rawThirdTilt] -- | Generate a random convex four sided polygon, with the property that it can be folded down an axis. @@ -250,11 +268,11 @@ randomConvexBisectableQuad :: ℝ -> ℝ -> Radian ℝ -> Radian ℝ -> Positive randomConvexBisectableQuad centerX centerY rawFirstTilt rawSecondTilt rawFirstDistanceToCorner rawSecondDistanceToCorner = randomStarPoly centerX centerY $ makePairs distances radians where distances = [firstDistanceToCorner, secondDistanceToCorner, firstDistanceToCorner, secondDistanceToCorner] - [firstDistanceToCorner, secondDistanceToCorner] = sort $ ensureUniqueDistance [rawFirstDistanceToCorner, rawSecondDistanceToCorner] + (firstDistanceToCorner, secondDistanceToCorner) = twoDistances $ sort $ ensureUniqueDistance [rawFirstDistanceToCorner, rawSecondDistanceToCorner] radians = [firstTilt, secondTilt, thirdTilt, fourthTilt] thirdTilt = secondTilt + (secondTilt - firstTilt) fourthTilt = flipRadian secondTilt - [firstTilt, secondTilt] = sort $ ensureUniqueClippedRadian rawRadians + (firstTilt, secondTilt) = twoTilts $ sort $ ensureUniqueClippedRadian rawRadians rawRadians = [rawFirstTilt, rawSecondTilt] -- | Generate a random convex four sided polygon. @@ -264,7 +282,7 @@ randomConvexQuad centerX centerY rawFirstTilt rawSecondTilt rawThirdTilt firstDi distances = replicate 4 firstDistanceToCorner radians = sort [firstTilt, secondTilt, thirdTilt, fourthTilt] fourthTilt = flipRadian secondTilt - [firstTilt, secondTilt, thirdTilt] = ensureUniqueClippedRadian rawRadians + (firstTilt, secondTilt, thirdTilt) = threeTilts $ ensureUniqueClippedRadian rawRadians rawRadians = [rawFirstTilt, rawSecondTilt, rawThirdTilt] -- | Generate a concave four sided polygon, with the convex motorcycle impacting the opposing bend (a 'dart' per wikipedia. a chevron, or a ^.) @@ -273,7 +291,7 @@ randomConcaveChevronQuad :: ℝ -> ℝ -> Radian ℝ -> Positive ℝ -> Positive randomConcaveChevronQuad centerX centerY rawFirstTilt rawFirstDistanceToCorner rawSecondDistanceToCorner = randomStarPoly centerX centerY $ makePairs distances radians where distances = [firstDistanceToCorner, secondDistanceToCorner, firstDistanceToCorner, thirdDistanceToCorner] - [firstDistanceToCorner, secondDistanceToCorner] = sort $ ensureUniqueDistance [rawFirstDistanceToCorner, rawSecondDistanceToCorner] + (firstDistanceToCorner, secondDistanceToCorner) = twoDistances $ sort $ ensureUniqueDistance [rawFirstDistanceToCorner, rawSecondDistanceToCorner] thirdDistanceToCorner = secondDistanceToCorner / 2 radians = [firstTilt, secondTilt, flipRadian firstTilt, secondTilt] secondTilt = clipRadian $ firstTilt + (Radian pi/2) diff --git a/tests/Math/Geometry/ConcaveChevronQuad.hs b/tests/Math/Geometry/ConcaveChevronQuad.hs index e8c61462..64bae300 100644 --- a/tests/Math/Geometry/ConcaveChevronQuad.hs +++ b/tests/Math/Geometry/ConcaveChevronQuad.hs @@ -94,7 +94,10 @@ unit_ConcaveChevronQuadHasAStraightSkeleton <> show (plinesIntersectIn (outAndErrOf motorcycle) (outAndErrOf eNode)) <> "\n" <> show divides <> "\n" where - eNode = (\(WithENode a) -> a) $ landingPointOf contour motorcycle + eNode = onlyENode $ landingPointOf contour motorcycle + onlyENode landingPoint = case landingPoint of + (WithENode enode) -> enode + _ -> error "got something other than an ENode in our landing point." divides = findDivisions contour (fromMaybe (error "no") $ crashMotorcycles contour []) motorcycle = head $ convexMotorcycles contour contour = randomConcaveChevronQuad x y tilt1 distance1 distance2 @@ -202,7 +205,10 @@ unit_ConcaveChevronQuadCanPlaceFaces where faces = facesOf skeleton skeleton = fromJust $ findStraightSkeleton contour [] - eNode = (\(WithENode a) -> a) $ landingPointOf contour motorcycle + eNode = onlyENode $ landingPointOf contour motorcycle + onlyENode landingPoint = case landingPoint of + (WithENode enode) -> enode + _ -> error "got something other than an ENode in our landing point." divides = findDivisions contour (fromMaybe (error "no") $ crashMotorcycles contour []) motorcycle = head $ convexMotorcycles contour contour = randomConcaveChevronQuad x y tilt1 distance1 distance2 @@ -230,7 +236,9 @@ unit_ConcaveChevronQuadCanPlaceFaces_2 faces = facesOf skeleton skeleton = fromJust $ findStraightSkeleton contour [] divides = findDivisions contour (fromMaybe (error "no") $ crashMotorcycles contour []) - [_, targetENode, _] = eNodes + targetENode = case eNodes of + [_, t, _] -> t + _ -> error "wrong amount of eNodes." eNodes = eNodesOfOutsideContour contour motorcycle = head $ convexMotorcycles contour contour = randomConcaveChevronQuad x y tilt1 distance1 distance2 diff --git a/tests/Math/Geometry/Rectangle.hs b/tests/Math/Geometry/Rectangle.hs index aaff4ec1..6a0bc898 100644 --- a/tests/Math/Geometry/Rectangle.hs +++ b/tests/Math/Geometry/Rectangle.hs @@ -125,7 +125,10 @@ prop_RectangleFacesInsetWithRemainder :: Contour -> Positive ℝ -> Bool prop_RectangleFacesInsetWithRemainder contour maxInsetDistance = length faces == 4 where faces = facesOf $ fromMaybe (error $ show insetContour) $ findStraightSkeleton insetContour [] - ([insetContour],_) = insetBy (coerce $ maxInsetDistance/2) $ facesOf $ fromMaybe (error $ show contour) $ findStraightSkeleton contour [] + insetContour = case insetContours of + [a] -> a + _ -> error "found multiple inset contours." + (insetContours,_) = insetBy (coerce $ maxInsetDistance/2) $ facesOf $ fromMaybe (error $ show contour) $ findStraightSkeleton contour [] prop_RectangleFacesInsetSmallerThanRectangle :: Contour -> Positive ℝ -> Bool prop_RectangleFacesInsetSmallerThanRectangle contour maxInsetDistance = prop_InsetIsSmaller (coerce $ maxInsetDistance/2) contour @@ -257,13 +260,16 @@ maxInsetDistanceOfRectangle rawFirstTilt rawSecondTilt distanceToCorner = Positi (tilt1, tilt2) | r2 - r1 < r3 - r2 = (r1, r2) | otherwise = (r2, r3) - [r1, r2, r3, _] = sort + (r1, r2, r3, _) = fourTilts $ sort [ firstTilt , rawSecondTilt , flipRadian firstTilt , flipRadian rawSecondTilt ] + fourTilts tilts = case tilts of + [t1, t2, t3, t4] -> (t1, t2, t3, t4) + _ -> error "too many tilts?" firstTilt | rawFirstTilt == rawSecondTilt = rawFirstTilt + rawSecondTilt | otherwise = rawFirstTilt From a96fdcd16e98da6f6426d1562d69d134a6a2b560 Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Thu, 14 Dec 2023 14:11:25 +0000 Subject: [PATCH 11/18] remove unnecessary type casts. --- tests/Math/PGA.hs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Math/PGA.hs b/tests/Math/PGA.hs index d986c12a..326804a3 100644 --- a/tests/Math/PGA.hs +++ b/tests/Math/PGA.hs @@ -503,12 +503,12 @@ prop_QuadBisectorCrosses rawX1 rawY1 rawX2 rawY2 <> show eNode <> "\n" <> "(" <> show x3 <> "," <> show y3 <> ")\n" where - intersect1 = intersectsWithErr (Right (PLine2 bisector1, bisector1Err)) (Left lineSeg1 :: Either LineSeg (ProjectiveLine, PLine2Err)) - intersect2 = intersectsWithErr (Right (PLine2 bisector1, bisector1Err)) (Left lineSeg2 :: Either LineSeg (ProjectiveLine, PLine2Err)) + intersect1 = intersectsWithErr (Right (bisector1, bisector1Err)) (Left lineSeg1 :: Either LineSeg (ProjectiveLine, PLine2Err)) + intersect2 = intersectsWithErr (Right (bisector1, bisector1Err)) (Left lineSeg2 :: Either LineSeg (ProjectiveLine, PLine2Err)) intersect3 = outputIntersectsLineSeg eNode lineSeg1 intersect4 = outputIntersectsLineSeg eNode lineSeg2 -- note that our bisector always intersects the origin. - (NPLine2 bisector1, bisector1Err) = normalizeL bisector + (bisector1, bisector1Err) = normalizeL bisector (bisector, _) = eToPL $ makeLineSeg (Point2 (0,0)) (Point2 (x3,y3)) eNode = makeENode (Point2 (x1,y1)) (Point2 (0,0)) (Point2 (x2,y2)) -- X1, Y1 and X2 forced uniqueness. additionally, forced "not 180 degree opposition). @@ -550,17 +550,17 @@ prop_QuadBisectorCrossesMultiple rawX1 rawY1 rawX2 rawY2 rawTimes <> show lineSeg2 <> "\n" <> show bisector1 <> "\n" <> show eNode <> "\n" - <> show (angleBetween2PL (outOf eNode) (PLine2 bisector1)) <> "\n" + <> show (angleBetween2PL (outOf eNode) bisector1) <> "\n" <> show (errOfOut eNode) <> "\n" <> "(" <> show x3 <> "," <> show y3 <> ")\n" <> "(" <> show x4 <> "," <> show y4 <> ")\n" where - intersect1 = intersectsWithErr (Right (PLine2 bisector1, bisector1Err)) (Left lineSeg1 :: Either LineSeg (ProjectiveLine, PLine2Err)) - intersect2 = intersectsWithErr (Right (PLine2 bisector1, bisector1Err)) (Left lineSeg2 :: Either LineSeg (ProjectiveLine, PLine2Err)) + intersect1 = intersectsWithErr (Right (bisector1, bisector1Err)) (Left lineSeg1 :: Either LineSeg (ProjectiveLine, PLine2Err)) + intersect2 = intersectsWithErr (Right (bisector1, bisector1Err)) (Left lineSeg2 :: Either LineSeg (ProjectiveLine, PLine2Err)) intersect3 = outputIntersectsLineSeg eNode lineSeg1 intersect4 = outputIntersectsLineSeg eNode lineSeg2 -- note that our bisector always intersects the origin. - (NPLine2 bisector1, bisector1Err) = normalizeL bisector + (bisector1, bisector1Err) = normalizeL bisector (bisector, _) = eToPL $ makeLineSeg (Point2 (0,0)) (Point2 (x3,y3)) eNode = makeENode (Point2 (x1,y1)) (Point2 (0,0)) (Point2 (x2,y2)) -- X1, Y1 and X2 forced uniqueness. additionally, forced "not 180 degree opposition). From 6dd10d266af92a026cf1927e621dc7f5f8d67fcf Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Fri, 15 Dec 2023 15:39:51 +0000 Subject: [PATCH 12/18] fix spacing. --- Graphics/Slicer/Math/RandomGeometry.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/Graphics/Slicer/Math/RandomGeometry.hs b/Graphics/Slicer/Math/RandomGeometry.hs index b4d3eacc..9117dea7 100644 --- a/Graphics/Slicer/Math/RandomGeometry.hs +++ b/Graphics/Slicer/Math/RandomGeometry.hs @@ -240,7 +240,6 @@ threeTilts tilts = case tilts of [a,b,c] -> (a,b,c) _ -> error "wrong tilt count." - -- | Generate a random convex four sided polygon, with two right angles. -- FIXME: only supports non-sequential right angles. -- FIXME: also only supports bisectable angles, where the line between the non-right angled sides intersects the origin. From b85499c285885856d9cbce744c3807587e1b3117 Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Fri, 15 Dec 2023 15:45:10 +0000 Subject: [PATCH 13/18] use specific tag of floating-bits. --- cabal.project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cabal.project b/cabal.project index a78a0051..bf93e926 100644 --- a/cabal.project +++ b/cabal.project @@ -5,7 +5,7 @@ documentation: True source-repository-package type: git location: https://github.com/julialongtin/floating-bits.git --- tag: 302c996 + tag: 0a142179941eb28366085beae5baca6f8e4d36bf -- source-repository-package -- type: git From fef814a8ec0fdb1df31a6022b2414d9763c7150b Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Fri, 15 Dec 2023 15:53:39 +0000 Subject: [PATCH 14/18] make CI run the same cabal as my host system. --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e22c3923..f6914be7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,7 +33,7 @@ jobs: strategy: matrix: cabal: - - '3.10' + - '3.8' ghc: - '9.2.8' - '9.0.2' From 8e0201bc03a8e6e3a1a087f53cd8005c14176c23 Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Fri, 15 Dec 2023 18:13:14 +0000 Subject: [PATCH 15/18] add cabal 3.10 to tested versions. --- .github/workflows/ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f6914be7..32ed5aeb 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,6 +33,7 @@ jobs: strategy: matrix: cabal: + - '3.10' - '3.8' ghc: - '9.2.8' From b3aa2b6db3e283a8cbcebd4628bf1f89e3f350fe Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Fri, 15 Dec 2023 18:13:46 +0000 Subject: [PATCH 16/18] use floating-bits master. --- cabal.project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cabal.project b/cabal.project index bf93e926..015c5188 100644 --- a/cabal.project +++ b/cabal.project @@ -5,7 +5,7 @@ documentation: True source-repository-package type: git location: https://github.com/julialongtin/floating-bits.git - tag: 0a142179941eb28366085beae5baca6f8e4d36bf +-- tag: 0a142179941eb28366085beae5baca6f8e4d36bf -- source-repository-package -- type: git From cb3a33bf1619d484810f6ffff0c77a20025eb014 Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Fri, 15 Dec 2023 19:05:45 +0000 Subject: [PATCH 17/18] just test against cabal 3.10, and add ghc 9.4.6 to our tests. --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 32ed5aeb..885f9527 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -34,8 +34,8 @@ jobs: matrix: cabal: - '3.10' - - '3.8' ghc: + - '9.4.6' - '9.2.8' - '9.0.2' - '8.10.7' From 78aea148244073dbbbc1b6fb78826f3c915d9b78 Mon Sep 17 00:00:00 2001 From: Julia Longtin Date: Fri, 15 Dec 2023 22:47:26 +0000 Subject: [PATCH 18/18] mark a lot more stuff inlineable, since ghc 9.4 is more agressive with inlines. --- Graphics/Slicer/Math/Arcs.hs | 2 ++ Graphics/Slicer/Math/Intersections.hs | 2 ++ Graphics/Slicer/Math/PGA.hs | 12 ++++++++++++ Graphics/Slicer/Math/PGAPrimitives.hs | 20 ++++++++++++++++++++ Graphics/Slicer/Math/Skeleton/Concave.hs | 2 ++ 5 files changed, 38 insertions(+) diff --git a/Graphics/Slicer/Math/Arcs.hs b/Graphics/Slicer/Math/Arcs.hs index f7b19e08..df5e62f1 100644 --- a/Graphics/Slicer/Math/Arcs.hs +++ b/Graphics/Slicer/Math/Arcs.hs @@ -82,12 +82,14 @@ getAcuteAngleBisectorFromLines line1@(pl1, _) line2@(pl2, _) (npline2, npline2Err) = normalizeL pl2 -- | Get a projective line along the angle bisector of the intersection of the two given lines, pointing in the 'obtuse' direction. +{-# INLINABLE getOutsideArc #-} getOutsideArc :: (ProjectivePoint2 a, ProjectiveLine2 b, ProjectivePoint2 c, ProjectiveLine2 d) => (a, PPoint2Err) -> (b, PLine2Err) -> (c, PPoint2Err) -> (d, PLine2Err) -> (ProjectiveLine, PLine2Err) getOutsideArc a b c d = (res, resErr) where (res, (_,_, resErr)) = getObtuseAngleBisectorFromPointedLines a b c d -- | Get a projective line along the angle bisector of the intersection of the two given lines, pointing in the 'obtuse' direction. +{-# INLINABLE getObtuseAngleBisectorFromPointedLines #-} getObtuseAngleBisectorFromPointedLines :: (ProjectivePoint2 a, ProjectiveLine2 b, ProjectivePoint2 c, ProjectiveLine2 d) => (a, PPoint2Err) -> (b, PLine2Err) -> (c, PPoint2Err) -> (d, PLine2Err) -> (ProjectiveLine, (PLine2Err, PLine2Err, PLine2Err)) getObtuseAngleBisectorFromPointedLines ppoint1 line1 ppoint2 line2 | isCollinear line1 line2 = error "Asked to find the obtuse bisector of two colinear lines!" diff --git a/Graphics/Slicer/Math/Intersections.hs b/Graphics/Slicer/Math/Intersections.hs index 85a0cbd1..a5318a93 100644 --- a/Graphics/Slicer/Math/Intersections.hs +++ b/Graphics/Slicer/Math/Intersections.hs @@ -138,6 +138,7 @@ outputIntersectsPLineAt n line where res = plinesIntersectIn (outAndErrOf n) line +-- | Check if two line segments intersect. lineSegsIntersect :: LineSeg -> LineSeg -> Bool lineSegsIntersect l1 l2 = isIntersection $ intersectsWithErr (Left l1 :: Either LineSeg (ProjectiveLine, PLine2Err)) (Left l2 :: Either LineSeg (ProjectiveLine, PLine2Err)) where @@ -146,6 +147,7 @@ lineSegsIntersect l1 l2 = isIntersection $ intersectsWithErr (Left l1 :: Either _ -> False -- | Find out if all of the possible intersections between all of the given nodes are close enough to be considered intersecting at the same point. +{-# INLINABLE intersectionsAtSamePoint #-} intersectionsAtSamePoint :: (ProjectiveLine2 a) => [(a, PLine2Err)] -> Bool intersectionsAtSamePoint nodeOutsAndErrs = case nodeOutsAndErrs of diff --git a/Graphics/Slicer/Math/PGA.hs b/Graphics/Slicer/Math/PGA.hs index b64a42dc..80a6731d 100644 --- a/Graphics/Slicer/Math/PGA.hs +++ b/Graphics/Slicer/Math/PGA.hs @@ -126,6 +126,7 @@ data PIntersection = deriving (Show, Eq) -- | Determine the intersection point of two projective lines, if applicable. Otherwise, classify the relationship between the two line segments. +{-# INLINABLE plinesIntersectIn #-} plinesIntersectIn :: (ProjectiveLine2 a, ProjectiveLine2 b) => (a, PLine2Err) -> (b, PLine2Err) -> PIntersection plinesIntersectIn (pl1, pl1Err) (pl2, pl2Err) | isNothing canonicalizedIntersection @@ -162,6 +163,7 @@ pLineIsLeft line1 line2 -- | Find the distance between a projective point and a projective line, along with the difference's error quotent. -- Note: Fails in the case of ideal points. +{-# INLINABLE distanceProjectivePointToProjectiveLine #-} distanceProjectivePointToProjectiveLine, distancePPToPL :: (ProjectivePoint2 a, ProjectiveLine2 b) => (a, PPoint2Err) -> (b, PLine2Err) -> (ℝ, (PPoint2Err, PLine2Err, ([ErrVal],[ErrVal]), PLine2Err, PPoint2Err, UlpSum)) distanceProjectivePointToProjectiveLine (inPoint, inPointErr) (inLine, inLineErr) | isIdealP inPoint = error "attempted to get the distance of an ideal point." @@ -182,10 +184,12 @@ distanceProjectivePointToProjectiveLine (inPoint, inPointErr) (inLine, inLineErr (nLine, nLineErr) = normalizeL inLine (cPoint, cPointErr) = canonicalizeP inPoint -- FIXME: return result is a bit soupy. +{-# INLINABLE distancePPToPL #-} distancePPToPL = distanceProjectivePointToProjectiveLine -- | Determine if two points are on the same side of a given line. -- Returns Nothing if one of the points is on the line. +{-# INLINABLE pPointsOnSameSideOfPLine #-} pPointsOnSameSideOfPLine :: (ProjectivePoint2 a, ProjectivePoint2 b, ProjectiveLine2 c) => a -> b -> c -> Maybe Bool pPointsOnSameSideOfPLine point1 point2 line | abs foundP1 < foundErr1 || @@ -203,6 +207,7 @@ pPointsOnSameSideOfPLine point1 point2 line lv1 = vecOfL $ forceBasisOfL line -- | A checker, to ensure two Projective Lines are going the same direction, and are parallel, or colinear. +{-# INLINABLE sameDirection #-} sameDirection :: (ProjectiveLine2 a, ProjectiveLine2 b) => a -> b -> Bool sameDirection a b = res >= maxAngle where @@ -212,6 +217,7 @@ sameDirection a b = res >= maxAngle (res, (_,_, resErr)) = angleBetween2PL a b -- | A checker, to ensure two Projective Lines are going the opposite direction, and are parallel. +{-# INLINABLE oppositeDirection #-} oppositeDirection :: (ProjectiveLine2 a, ProjectiveLine2 b) => a -> b -> Bool oppositeDirection a b = res <= minAngle where @@ -224,6 +230,7 @@ oppositeDirection a b = res <= minAngle -- FIXME: many operators here have error preserving forms, use those! -- FIXME: we were skipping canonicalization, are canonicalization and normalization necessary? pPointOnPerpWithErr :: (ProjectiveLine2 a, ProjectivePoint2 b) => a -> b -> ℝ -> (ProjectivePoint, (PLine2Err, PPoint2Err, ([ErrVal],[ErrVal]), UlpSum)) +{-# INLINABLE pPointOnPerpWithErr #-} pPointOnPerpWithErr line point d = (PPoint2 res, resErr) where -- translate the input point along the perpendicular bisector. @@ -242,6 +249,7 @@ pPointOnPerpWithErr line point d = (PPoint2 res, resErr) -- Find a projective line crossing the given projective line at the given projective point at a 90 degree angle. perpLineAt :: (ProjectiveLine2 a, ProjectivePoint2 b) => a -> b -> (ProjectiveLine, (PLine2Err, PPoint2Err, ([ErrVal],[ErrVal]))) +{-# INLINABLE perpLineAt #-} perpLineAt line point = (PLine2 res, resErr) where (res, perpLineErrs) = lvec ⨅+ pvec @@ -253,6 +261,7 @@ perpLineAt line point = (PLine2 res, resErr) -- | Translate a point a given distance away from where it is, rotating it a given amount clockwise (in radians) around it's original location, with 0 degrees being aligned to the X axis. -- FIXME: throw this error into PPoint2Err. +{-# INLINABLE translateRotatePPoint2WithErr #-} translateRotatePPoint2WithErr :: (ProjectivePoint2 a) => a -> ℝ -> ℝ -> (ProjectivePoint, (UlpSum, UlpSum, [ErrVal], PLine2Err, PLine2Err, PPoint2Err, ([ErrVal],[ErrVal]))) translateRotatePPoint2WithErr point d rotation = (res, resErr) where @@ -323,6 +332,7 @@ data Intersection = deriving Show -- | Entry point usable for common intersection needs, complete with passed in error values. +{-# INLINABLE intersectsWithErr #-} intersectsWithErr :: (ProjectiveLine2 a, ProjectiveLine2 b) => Either LineSeg (a, PLine2Err) -> Either LineSeg (b, PLine2Err) -> Either Intersection PIntersection intersectsWithErr (Left l1) (Left l2) = lineSegIntersectsLineSeg l1 l2 intersectsWithErr (Right pl1) (Right pl2) = Right $ plinesIntersectIn pl1 pl2 @@ -330,6 +340,7 @@ intersectsWithErr (Left l1) (Right pl1) = pLineIntersectsLineSeg pl1 l intersectsWithErr (Right pl1) (Left l1) = pLineIntersectsLineSeg pl1 l1 -- | Check if/where a line segment and a PLine intersect. +{-# INLINABLE pLineIntersectsLineSeg #-} pLineIntersectsLineSeg :: (ProjectiveLine2 a) => (a, PLine2Err) -> LineSeg -> Either Intersection PIntersection pLineIntersectsLineSeg (pl1, pl1ErrOrigin) l1 | res == PParallel = Right PParallel @@ -436,6 +447,7 @@ lineSegIntersectsLineSeg l1 l2 -- | Given the result of intersectionPoint, find out whether this intersection point is on the given segment, or not. onSegment :: (ProjectivePoint2 a) => LineSeg -> (a, PPoint2Err) -> Bool +{-# INLINABLE onSegment #-} onSegment lineSeg iPoint@(iP, _) = (startDistance <= startFudgeFactor) || (lineDistance <= lineFudgeFactor && midDistance <= (lengthOfSegment/2) + midFudgeFactor) diff --git a/Graphics/Slicer/Math/PGAPrimitives.hs b/Graphics/Slicer/Math/PGAPrimitives.hs index db9b415c..fce503d4 100644 --- a/Graphics/Slicer/Math/PGAPrimitives.hs +++ b/Graphics/Slicer/Math/PGAPrimitives.hs @@ -306,6 +306,7 @@ forceBasisOfL = forceProjectiveLineBasis -- For complete results, combine this with scaling xIntercept and yIntercept. fuzzinessOfProjectiveLine, fuzzinessOfL :: (ProjectiveLine2 a) => (a, PLine2Err) -> UlpSum -- | Actual implementation. +{-# INLINABLE fuzzinessOfProjectiveLine #-} fuzzinessOfProjectiveLine (line, lineErr) = tUlp <> joinAddTErr <> joinMulTErr <> normalizeTErr <> additionTErr where (PLine2Err additionErr normalizeErr _ _ tUlp (joinMulErr, joinAddErr)) = lineErr <> normalizeErrRaw @@ -315,6 +316,7 @@ fuzzinessOfProjectiveLine (line, lineErr) = tUlp <> joinAddTErr <> joinMulTErr < joinAddTErr = eValOf mempty (getVal [GEZero 1] joinAddErr) (_,normalizeErrRaw) = normalizeL line -- | Wrapper. +{-# INLINABLE fuzzinessOfL #-} fuzzinessOfL = fuzzinessOfProjectiveLine -- | Find out where two lines intersect, returning a projective point, and the error quotents. @@ -396,6 +398,7 @@ normalizeProjectiveLine line = (res, resErr) -- FIXME: should we be placing this error in the PLine2Err? it doesn't effect resolving the line... normOfProjectiveLine, normOfL :: (ProjectiveLine2 a) => a -> (ℝ, PLine2Err) -- | Actual implementation. +{-# INLINABLE normOfProjectiveLine #-} normOfProjectiveLine line = (res, resErr) where (res, resErr) = case sqNormOfPLine2 of @@ -405,11 +408,13 @@ normOfProjectiveLine line = (res, resErr) rawResUlp = UlpSum (abs $ realToFrac $ doubleUlp rawRes) (sqNormOfPLine2, sqNormUlp) = sqNormOfL line -- | Wrapper. +{-# INLINABLE normOfL #-} normOfL = normOfProjectiveLine -- | Find the squared norm of a given Projective Line. squaredNormOfProjectiveLine, sqNormOfL :: (ProjectiveLine2 a) => a -> (ℝ, UlpSum) -- | Actual implementation. +{-# INLINABLE squaredNormOfProjectiveLine #-} squaredNormOfProjectiveLine line = (res, ulpTotal) where res = a*a+b*b @@ -421,10 +426,12 @@ squaredNormOfProjectiveLine line = (res, ulpTotal) + abs (realToFrac $ doubleUlp res) (GVec vals) = vecOfL line -- | Wrapper. +{-# INLINABLE sqNormOfL#-} sqNormOfL = squaredNormOfProjectiveLine -- | Translate a line a given distance along it's perpendicular bisector. -- Uses the property that translation of a line is expressed on the GEZero component. +{-# INLINABLE translateProjectiveLine #-} translateProjectiveLine, translateL :: (ProjectiveLine2 a) => a -> ℝ -> (ProjectiveLine, PLine2Err) -- | Actual implementation. translateProjectiveLine line d = (PLine2 res, normErr <> PLine2Err resErrs mempty mempty mempty tUlp mempty) @@ -436,6 +443,7 @@ translateProjectiveLine line d = (PLine2 res, normErr <> PLine2Err resErrs mempt tUlp = UlpSum $ abs $ realToFrac $ doubleUlp tAdd (norm, normErr) = normOfL line -- | Wrapper. +{-# INLINABLE translateL #-} translateL = translateProjectiveLine ----------------------------------------- @@ -444,6 +452,7 @@ translateL = translateProjectiveLine -- | When given a projective line, return the maximum distance between a projective point known to be on the line and the equivalent point on the 'real' line, which is to say, the projective line without floating point error. -- Note: We do not add fuzzinessOfL (nPLine, nPLineErr) here, so you have to add it to this result to get a full value. +{-# INLINABLE pLineErrAtPPoint #-} pLineErrAtPPoint :: (ProjectiveLine2 a, ProjectivePoint2 b) => (a, PLine2Err) -> b -> UlpSum pLineErrAtPPoint (line, lineErr) errPoint -- Both intercepts are real. This line is not parallel or collinear to X or Y axises, and does not pass through the origin. @@ -481,6 +490,7 @@ pLineErrAtPPoint (line, lineErr) errPoint (nPLine, nPLineErrRaw) = normalizeL line -- | is it possible that after taking error into account, both of the two given PLines may overlap? +{-# INLINABLE pLinesWithinErr #-} pLinesWithinErr :: (ProjectiveLine2 a, ProjectiveLine2 b) => (a, PLine2Err) -> (b, PLine2Err) -> Bool pLinesWithinErr (pl1, pl1Err) (pl2, pl2Err) | x1InterceptExists && x2InterceptExists && signum x1InterceptDistance == signum x2InterceptDistance && @@ -712,6 +722,7 @@ canonicalizeProjectivePoint point (GVec rawVals) = vecOfP point -- | Find the distance between two projective points, and the error component of the result. +{-# INLINABLE distanceBetweenProjectivePoints #-} distanceBetweenProjectivePoints :: (ProjectivePoint2 a, ProjectivePoint2 b) => (a, PPoint2Err) -> (b, PPoint2Err) -> (ℝ, (PPoint2Err, PPoint2Err, PLine2Err, UlpSum)) distanceBetweenProjectivePoints (point1, point1Err) (point2, point2Err) -- Short circuit (returning 0) if the two inputs are identical, and of the same type. @@ -733,6 +744,7 @@ distanceBetweenProjectivePoints (point1, point1Err) (point2, point2Err) (cPoint2, cPoint2Err) = canonicalizeP point2 -- | A wrapper for the above function, that removes error quotents that are not directly related to the input or result. +{-# INLINABLE distance2PP #-} distance2PP :: (ProjectivePoint2 a, ProjectivePoint2 b) => (a, PPoint2Err) -> (b, PPoint2Err) -> (ℝ, (PPoint2Err, PPoint2Err, UlpSum)) distance2PP p1 p2 = crushErr $ distanceBetweenProjectivePoints p1 p2 where @@ -741,6 +753,7 @@ distance2PP p1 p2 = crushErr $ distanceBetweenProjectivePoints p1 p2 -- | Ensure all of the '0' components exist on a Projective Point. This is to ensure like, unlike, and reductive work properly. forceProjectivePointBasis, forceBasisOfP :: (ProjectivePoint2 a) => a -> a -- | Actual implementation. +{-# INLINABLE forceProjectivePointBasis #-} forceProjectivePointBasis point | gnums == Just [fromList [GEZero 1, GEPlus 1], fromList [GEZero 1, GEPlus 2], @@ -753,11 +766,13 @@ forceProjectivePointBasis point _ -> Nothing vec@(GVec vals) = vecOfP point -- | Wrapper. +{-# INLINABLE forceBasisOfP #-} forceBasisOfP = forceProjectivePointBasis -- | Find the idealized norm of a projective point (ideal or not). idealNormOfProjectivePoint, idealNormOfP :: (ProjectivePoint2 a) => a -> (ℝ, UlpSum) -- | Actual implementation. +{-# INLINABLE idealNormOfProjectivePoint #-} idealNormOfProjectivePoint point | preRes == 0 = (0, mempty) | otherwise = (res, ulpTotal) @@ -776,6 +791,7 @@ idealNormOfProjectivePoint point e12Val = valOf 0 (getVal [GEPlus 1, GEPlus 2] rawVals) (GVec rawVals) = vecOfP point -- | Wrapper. +{-# INLINABLE idealNormOfP #-} idealNormOfP = idealNormOfProjectivePoint -- | Join two points, returning the line that connects them. @@ -835,6 +851,7 @@ projectivePointIsIdeal point = isNothing $ getVal [GEPlus 1, GEPlus 2] $ (\(GVec -- | Maybe create a euclidian point from a projective point. Will fail if the projective point is ideal. projectivePointToEuclidianPoint, pToEP :: (ProjectivePoint2 a) => a -> (Point2, PPoint2Err) -- | Actual implementation. +{-# INLINABLE projectivePointToEuclidianPoint #-} projectivePointToEuclidianPoint point | projectivePointIsIdeal point = error "Attempted to create an infinite point when trying to convert from a Projective Point to a Euclidian Point." | otherwise = (res, resErr) @@ -845,6 +862,7 @@ projectivePointToEuclidianPoint point (GVec vals) = vecOfP pointRes (pointRes, resErr) = canonicalizeP point -- | Wrapper. +{-# INLINABLE pToEP #-} pToEP = projectivePointToEuclidianPoint ------------------------------------------ @@ -866,6 +884,7 @@ sumIErrs (unlikeMulErrs, unlikeAddErrs, _, _, _) = eValOf mempty (getVal [GEZero -- FIXME: This 1000 here is completely made up BS. fuzzinessOfProjectivePoint, fuzzinessOfP :: (ProjectivePoint2 a) => (a, PPoint2Err) -> UlpSum -- | Actual implementation. +{-# INLINABLE fuzzinessOfProjectivePoint #-} fuzzinessOfProjectivePoint (point, pointErr) = UlpSum $ sumTotal * realToFrac (1+(1000*(abs angleIn + realToFrac (ulpRaw $ sumPPointErrs angleUnlikeAddErr <> sumPPointErrs angleUnlikeMulErr)))) where sumTotal = ulpRaw $ sumPPointErrs pJoinAddErr @@ -877,4 +896,5 @@ fuzzinessOfProjectivePoint (point, pointErr) = UlpSum $ sumTotal * realToFrac (1 (PPoint2Err (pJoinAddErr, pJoinMulErr) pCanonicalizeErr pAddErr pIn1MulErr pIn2MulErr angleIn (angleUnlikeAddErr,angleUnlikeMulErr)) = cPointErr <> pointErr (_, cPointErr) = canonicalizeP point -- | Wrapper. +{-# INLINABLE fuzzinessOfP #-} fuzzinessOfP = fuzzinessOfProjectivePoint diff --git a/Graphics/Slicer/Math/Skeleton/Concave.hs b/Graphics/Slicer/Math/Skeleton/Concave.hs index 53f4b6ae..18d53f66 100644 --- a/Graphics/Slicer/Math/Skeleton/Concave.hs +++ b/Graphics/Slicer/Math/Skeleton/Concave.hs @@ -170,10 +170,12 @@ errorIfLeft (Right val) = val -- | For a given pair of nodes, construct a new internal node, where it's parents are the given nodes, and the line leaving it is along the the obtuse bisector. -- Note: this should be hidden in skeletonOfConcaveRegion, but it's exposed here, for testing. averageNodes :: (Arcable a, Pointable a, Arcable b, Pointable b) => a -> b -> INode +{-# INLINABLE averageNodes #-} averageNodes n1 n2 = makeINode (sortedPair n1 n2) $ Just $ getOutsideArc (cPPointAndErrOf n1) (outAndErrOf n1) (cPPointAndErrOf n2) (outAndErrOf n2) -- | Take a pair of arcables, and return their outOfs, in a sorted order. sortedPair :: (Arcable a, Arcable b) => a -> b -> [(ProjectiveLine, PLine2Err)] +{-# INLINABLE sortedPair #-} sortedPair n1 n2 | hasArc n1 && hasArc n2 = sortedPLines [outAndErrOf n1, outAndErrOf n2] | otherwise = error $ "Cannot get the average of nodes if one of the nodes does not have an out!\n"