Skip to content

Commit

Permalink
mark a lot more stuff inlineable, since ghc 9.4 is more agressive wit…
Browse files Browse the repository at this point in the history
…h inlines.
  • Loading branch information
julialongtin committed Dec 15, 2023
1 parent cb3a33b commit 78aea14
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Graphics/Slicer/Math/Arcs.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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!"
Expand Down
2 changes: 2 additions & 0 deletions Graphics/Slicer/Math/Intersections.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
12 changes: 12 additions & 0 deletions Graphics/Slicer/Math/PGA.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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."
Expand All @@ -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 ||
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -323,13 +332,15 @@ 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
intersectsWithErr (Left l1) (Right pl1) = pLineIntersectsLineSeg pl1 l1
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
Expand Down Expand Up @@ -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)
Expand Down
20 changes: 20 additions & 0 deletions Graphics/Slicer/Math/PGAPrimitives.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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

-----------------------------------------
Expand All @@ -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.
Expand Down Expand Up @@ -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 &&
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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],
Expand All @@ -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)
Expand All @@ -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.
Expand Down Expand Up @@ -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)
Expand All @@ -845,6 +862,7 @@ projectivePointToEuclidianPoint point
(GVec vals) = vecOfP pointRes
(pointRes, resErr) = canonicalizeP point
-- | Wrapper.
{-# INLINABLE pToEP #-}
pToEP = projectivePointToEuclidianPoint

------------------------------------------
Expand All @@ -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
Expand All @@ -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
2 changes: 2 additions & 0 deletions Graphics/Slicer/Math/Skeleton/Concave.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit 78aea14

Please sign in to comment.