4
\$\begingroup\$

I looking around and not finding anything, I developed a simple function for estimating the area of a possibly cropped circle inside a frame. It uses a very basic MC implementation.

It is pretty fast but I think it could be made simpler. Any thoughts are appreciated.

import numpy as np
from scipy.spatial import distance


def circFrac(cx, cy, rad, x0, x1, y0, y1, N_tot=100000):
    """
    Use Monte Carlo to estimate the fraction of the area of a circle centered
    in (cx, cy) with a radius of 'rad', that is located within the frame given
    by the limits 'x0, x1, y0, y1'.
    """
    # Generate a square containing the circle.
    xmin, xmax = cx - rad, cx + rad
    ymin, ymax = cy - rad, cy + rad

    # Generate 'N_tot' uniform random points inside that square.
    xr = np.random.uniform(xmin, xmax, N_tot)
    yr = np.random.uniform(ymin, ymax, N_tot)

    # Obtain the distances of those points to the center of the circle.
    dist = distance.cdist([(cx, cy)], np.array([xr, yr]).T)[0]

    # Find the points within the circle.
    msk_in_circ = dist < rad

    # Find the points that are within the frame, from the points that are
    # within the circle.
    msk_xy = (xr[msk_in_circ] > x0) & (xr[msk_in_circ] < x1) &\
        (yr[msk_in_circ] > y0) & (yr[msk_in_circ] < y1)

    # The area is the points within circle and frame over the points within
    # circle.
    return msk_xy.sum() / msk_in_circ.sum()


# Define the (x, y) limits of the frame
x0, x1 = 0., 1.
y0, y1 = 0., 1.

for _ in range(10):
    # Random center coordinates within the frame
    cx = np.random.uniform(x0, x1)
    cy = np.random.uniform(y0, y1)
    # Random radius
    rad = np.random.uniform(.05, .5)
    print("({:.2f}, {:.2f}), {:.2f}".format(cx, cy, rad))

    frac = circFrac(cx, cy, rad, x0, x1, y0, y1)

    print("Fraction of circle inside frame: {:.2f}".format(frac))
\$\endgroup\$
  • 1
    \$\begingroup\$ Why use a Monty Carlo estimate when you can compute the required area directly using the formula for the area of circular sectors? \$\endgroup\$ – AJNeufeld Oct 25 at 13:35
  • \$\begingroup\$ Because I found this general approach to be simpler that a geometrical approach. I'm open to it if you think it would be better and/or simpler. \$\endgroup\$ – Gabriel Oct 25 at 13:45
  • 2
    \$\begingroup\$ There's a more efficient way of uniformly sampling over a circle (rather than the sample from a bounding square and discard approach that you describe) described here: stackoverflow.com/a/50746409/1845650 . \$\endgroup\$ – Russ Hyde Oct 25 at 14:37
  • 4
    \$\begingroup\$ @Gabriel Code Review is not a code writing service. Yes, I can write a direct formula-based calculation, and I believe it would be faster, simpler, and more accurate, but it goes beyond the scope of a simple "code review". (If you write one yourself, and post it here, we can review it and perhaps clean it up to make it better.) \$\endgroup\$ – AJNeufeld Oct 25 at 16:09
  • 3
    \$\begingroup\$ @CloseVoters, even if OP wrote in a comment they'd like to see another implementation of the code, the post itself is 100% in the scope of CodeReview. Please try to get some context before using your VTC... \$\endgroup\$ – IEatBagels Dec 2 at 15:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.