Home > Back-end >  circular segment in haskell CodeWorld
circular segment in haskell CodeWorld

Time:03-24

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

enter image description here

  • Related