Could anyone tell me the best way to draw a circular segment using the haskell codeworld API?
I have a method that works only when the circular segment is cut off below the radius by combining three sectors. However, this does not work in the case where the circle is cut off above the radius.
Edit: My current attempt modified to be context independent
-- x = coords of the centre of the circle
-- y = A point on the circumference
-- z = the y-axis to cut off the circle at.
Segment :: Point -> Point -> Double -> Picture
Segment x y z = case capCutOffPoints x (pointDistance x y) z of
Nothing
| z <= snd x - pointDistance x y -> translated (fst x) (snd x) (solidCircle (pointDistance x y))
| otherwise -> blank
Just points
| snd (fst points) < snd x -> solidPolygon [(fst x, snd x 0.5*(pointDistance x y)), fst points, snd points] & translated (fst x) (snd x) (sector (fst (capArcAngles x points) 2*pi) (snd (capArcAngles x points)) (pointDistance x y))
| otherwise -> translated (fst x) (snd x) (sector (fst (capArcAngles x points)) (snd (capArcAngles x points)) (pointDistance x y))
-- | Returns the points at which the circle of the cap is cut off at.
capCutOffPoints :: Point -> Double -> Double -> Maybe (Point, Point)
capCutOffPoints centre radius y = points
where
sqrtX = sqrt (radius^2 - (y - (snd centre))^2)
points
| isNaN sqrtX = Nothing
| otherwise = Just ((sqrtX fst centre, y), (-sqrtX fst centre, y))
-- | Returns the angle from the centre of the cap circle to the cut off points
-- Modified to always return an angle between 0 and 2pi
capArcAngles :: Point -> (Point, Point) -> (Double, Double)
capArcAngles centre points = (a2, a1)
where
a1 = atan2 (snd (fst points) - snd centre) (fst (fst points) - fst centre)
a2 = atan2 (snd (snd points) - snd centre) (fst (snd points) - fst centre)
pointDistance :: Point -> Point -> Double
pointDistance p1 p2 = sqrt ((abs ((fst p1) - (fst p2)))^2 (abs ((snd p1) - (snd p2)))^2)
CodePudding user response:
I think the easiest way is clipping the circle out at the angle you want. So the proccess goes.
- Plot a solid circle coord
(0,0)
- Move it to de desired coordinate to produce the segment
- clip it using rectangle
- Move it back to the original position.
The code below produces solid circle segments on the given angle and cetered at (0,0)
import CodeWorld
-- |- Angle |- Radious
circularSegment :: Double -> Double -> Picture
circularSegment ang r = translated 0 (- translation_dir * translation_amount) -- Translate back
$ clipped (2*r) (2*r) -- clip it using rectangle
$ translated 0 (translation_dir * translation_amount) -- translate it
$ solidCircle r -- plot a solid circle
where s = r * sin ang
translation_amount = r abs s -- you want to translate your circle a the radious the sin of the angle
translation_dir = - signum s -- you want to translate the circle in the oposite direction as the sinus
As an example. The code below produces the given picture
topCirc = circularSegment (pi / 4) 3
bottomCirc = coloured red $ circularSegment ( - pi / 4) 3
main = drawingOf $ topCirc
<> bottomCirc