Antonio Serrano
Antonio Serrano

Reputation: 505

How to draw a circular sector in the Julia language?

I am new to the Julia language and need to draw a circular sector on an image (2-dimensional UInt8 array for gray version or 3-dimensional UInt8 array for an RGB version). Afterwards this image is to be used as a mask to select data in other arrays, so I need the result, not as an image object, but as an array of booleans or integers.

There is the way to draw a circle by means of the ImageDraw package:

draw!(img, Ellipse(CirclePointRadius(350,200,100), fill = tue))

but found no way to provide a start and end angle.

Upvotes: 4

Views: 343

Answers (2)

Antonio Serrano
Antonio Serrano

Reputation: 505

I think Julia is a great language, because (among other things) all libraries are implemented in the same language and you have ease acces to their sources.

And in this way, I have been able to modify the ellipse2d.jl script of the ImageDraw library.

The modification consits of adding another definition of the draw! funciton for ellipse objects (multiple dispatch of Julia is also great) that accepts a start and end angle.

I think the best way could be to define new objects, ellipse_sector and circle_sector, which would be the same as the ellipse and circle objects but with two more members: start_angle and end_angle. Then the correspondent drawing functions should be implemented. I would like to write to the ImageDraw package developers in order to make this suggestion or even offer me to make these changes, but I do not know the manage of github.

My solution, instead, does not modify any existing object, just adds a method to the draw! function that accpets two more arguments: startAngle and endAngle.

Here is the code, to be copied to the end of the ellipse2d.jl script:

function draw!(img::AbstractArray{T, 2}, ellipse::Ellipse, startAng::Real, endAng::Real, color::T) where T<:Colorant
    # Solution to find out if an angle lies between two given ones, borrowed from:
    # https://stackoverflow.com/questions/11406189/determine-if-angle-lies-between-2-other-angles/11412077#11412077

    # Make all angles to lie in [0, 2π)
    # rem2pi(ϕ, RoundNearest) returns the remainder of the division by 2π in the range [−π,π]
    # mod2pi returns the remainder of the division by 2π in the range [0,2π)
    Angle1 = mod2pi(startAng)
    Angle2 = mod2pi(endAng)

    # make the angle from angle1 to angle2 to be <= 180 degrees
    rAngle = mod2pi( mod2pi(Angle2 - Angle1) + 2π)
    if rAngle >= π
        Angle1, Angle2 = Angle2, Angle1 # Swaps the values
    end # if

    ys = Int[]
    xs = Int[]
    break_point = 0
    if ellipse.fill == false
        break_point = ((ellipse.ρy - ellipse.thickness) / ellipse.ρy) ^ 2 + ((ellipse.ρx - ellipse.thickness) / ellipse.ρx) ^ 2 
    end
    for i in ellipse.center.y - ellipse.ρy : ellipse.center.y + ellipse.ρy
        for j in ellipse.center.x - ellipse.ρx: ellipse.center.x + ellipse.ρx
            y = i - ellipse.center.y
            x = j - ellipse.center.x
            val = (x / ellipse.ρy) ^ 2 + (y / ellipse.ρx) ^ 2
            # atan(y, x) returns the angle in the correct quadrant [−π,π], not like atan(y/x)
            # But make it to be in the range [0, 2π)by means of mod2pi()
            ang = mod2pi( atan(y, x) )

            # Test if the angle lies betwen the startAngle and the endAngle
            if (Angle1 <= Angle2)
                AngleIsBetween = ang >= Angle1 && ang <= Angle2
            else
                AngleIsBetween = ang >= Angle1 || ang <= Angle2
            end # if
            if val < 1 && val >= break_point && AngleIsBetween
                push!(ys, i)
                push!(xs, j)
            end
        end
    end
    for (yi, xi) in zip(ys, xs)
        drawifinbounds!(img, yi, xi, color)
    end
    img
end

Upvotes: 1

Sundar R
Sundar R

Reputation: 14705

You can use Luxor.jl's pie or sector function:


julia> begin 
       img = readpng("/path/Images/deepam.png")
       Drawing(img.width, img.height, "sector-on-img.png")
       placeimage(img)
       origin()

       sethue("orange")
       pie(0, 0, 100, π/2, π, :fill)

       sethue("olive")
       sector(25, 125, 3π/2, 0, 15, :fill)

       finish()
       end
true

Result:

PNG image with a pie segment and a sector colored on top

(Original png image scaled down, for comparison: )

Upvotes: 3

Related Questions