How to make a circle within another circle?












1












$begingroup$


I'm coding a "storm" for a battle royale map, and I'm trying to make a new safe zone (a perfect circle) inside of a preexisting circle.



Right now, it looks like this:
Link to circle picture



This, as you can see, is a big bug in my code, which is:



cir = new Circle(random.nextInt(cir.Width-cir.X)+cir.X, random.nextInt(Math.abs(cir1.Height-cir.Y))+cir.Y, 270, 270, 135, Color.cyan, true);


cir1 is a preexisting Circle I created, which I am changing the values of.
cir is the Circle I created before (e.g. for Safe Zone 3, cir1 is the new Circle, and cir is Safe Zone 2.



My math to get the circles' $x$'s and $y$'s explained:

The math is: $rndInt(d-x)+x$ and $rndInt(|d-y|)+y$.
$d$ is the diameter of the circle, $x$ is the left x value, and $y$ is the top y of the circle.



This - in theory - should work, but it doesn't, as seen in the image.



In it, I basically get a random number between $0$ and the difference of the diameter and x.

From there, I add it to x. In theory, this will make a number and add it to x, making it between the preexisting circle.



Is there anything I'm doing wrong? I've spent weeks trying to figure out a formula, and this is the best I've got.










share|cite|improve this question









$endgroup$








  • 2




    $begingroup$
    Although this is a maths QA stack, if you could provide an MWE that might rule out any mathematical errors on your part... Otherwise, perhaps good old Stack Overflow might be your friend, too.
    $endgroup$
    – MacRance
    Dec 26 '18 at 4:18










  • $begingroup$
    To get a point inside the circle, the relation is x+rndInt(d),y-rndInt(d)$
    $endgroup$
    – Shubham Johri
    Dec 26 '18 at 5:11












  • $begingroup$
    I don't see why this should work even "in theory." You have two different objects (cir and cir1) contributing parameters to your constructor. One of these presumably is not the "preexisting" circle you wanted to stay inside. Moreover, all you would have done (if it worked like you said) is to put one corner of the bounding box inside the other bounding box--almost all the rest could be outside.
    $endgroup$
    – David K
    Dec 26 '18 at 5:20










  • $begingroup$
    By the way, there are multiple Java classes named Circle (or in one case Circle2D) documented online; so far yours is the only one I've seen that describes a circle by a corner of its bounding box, its width, and its height. (Can the width and height be different?) Everyone else uses the center and the radius.
    $endgroup$
    – David K
    Dec 26 '18 at 5:26


















1












$begingroup$


I'm coding a "storm" for a battle royale map, and I'm trying to make a new safe zone (a perfect circle) inside of a preexisting circle.



Right now, it looks like this:
Link to circle picture



This, as you can see, is a big bug in my code, which is:



cir = new Circle(random.nextInt(cir.Width-cir.X)+cir.X, random.nextInt(Math.abs(cir1.Height-cir.Y))+cir.Y, 270, 270, 135, Color.cyan, true);


cir1 is a preexisting Circle I created, which I am changing the values of.
cir is the Circle I created before (e.g. for Safe Zone 3, cir1 is the new Circle, and cir is Safe Zone 2.



My math to get the circles' $x$'s and $y$'s explained:

The math is: $rndInt(d-x)+x$ and $rndInt(|d-y|)+y$.
$d$ is the diameter of the circle, $x$ is the left x value, and $y$ is the top y of the circle.



This - in theory - should work, but it doesn't, as seen in the image.



In it, I basically get a random number between $0$ and the difference of the diameter and x.

From there, I add it to x. In theory, this will make a number and add it to x, making it between the preexisting circle.



Is there anything I'm doing wrong? I've spent weeks trying to figure out a formula, and this is the best I've got.










share|cite|improve this question









$endgroup$








  • 2




    $begingroup$
    Although this is a maths QA stack, if you could provide an MWE that might rule out any mathematical errors on your part... Otherwise, perhaps good old Stack Overflow might be your friend, too.
    $endgroup$
    – MacRance
    Dec 26 '18 at 4:18










  • $begingroup$
    To get a point inside the circle, the relation is x+rndInt(d),y-rndInt(d)$
    $endgroup$
    – Shubham Johri
    Dec 26 '18 at 5:11












  • $begingroup$
    I don't see why this should work even "in theory." You have two different objects (cir and cir1) contributing parameters to your constructor. One of these presumably is not the "preexisting" circle you wanted to stay inside. Moreover, all you would have done (if it worked like you said) is to put one corner of the bounding box inside the other bounding box--almost all the rest could be outside.
    $endgroup$
    – David K
    Dec 26 '18 at 5:20










  • $begingroup$
    By the way, there are multiple Java classes named Circle (or in one case Circle2D) documented online; so far yours is the only one I've seen that describes a circle by a corner of its bounding box, its width, and its height. (Can the width and height be different?) Everyone else uses the center and the radius.
    $endgroup$
    – David K
    Dec 26 '18 at 5:26
















1












1








1





$begingroup$


I'm coding a "storm" for a battle royale map, and I'm trying to make a new safe zone (a perfect circle) inside of a preexisting circle.



Right now, it looks like this:
Link to circle picture



This, as you can see, is a big bug in my code, which is:



cir = new Circle(random.nextInt(cir.Width-cir.X)+cir.X, random.nextInt(Math.abs(cir1.Height-cir.Y))+cir.Y, 270, 270, 135, Color.cyan, true);


cir1 is a preexisting Circle I created, which I am changing the values of.
cir is the Circle I created before (e.g. for Safe Zone 3, cir1 is the new Circle, and cir is Safe Zone 2.



My math to get the circles' $x$'s and $y$'s explained:

The math is: $rndInt(d-x)+x$ and $rndInt(|d-y|)+y$.
$d$ is the diameter of the circle, $x$ is the left x value, and $y$ is the top y of the circle.



This - in theory - should work, but it doesn't, as seen in the image.



In it, I basically get a random number between $0$ and the difference of the diameter and x.

From there, I add it to x. In theory, this will make a number and add it to x, making it between the preexisting circle.



Is there anything I'm doing wrong? I've spent weeks trying to figure out a formula, and this is the best I've got.










share|cite|improve this question









$endgroup$




I'm coding a "storm" for a battle royale map, and I'm trying to make a new safe zone (a perfect circle) inside of a preexisting circle.



Right now, it looks like this:
Link to circle picture



This, as you can see, is a big bug in my code, which is:



cir = new Circle(random.nextInt(cir.Width-cir.X)+cir.X, random.nextInt(Math.abs(cir1.Height-cir.Y))+cir.Y, 270, 270, 135, Color.cyan, true);


cir1 is a preexisting Circle I created, which I am changing the values of.
cir is the Circle I created before (e.g. for Safe Zone 3, cir1 is the new Circle, and cir is Safe Zone 2.



My math to get the circles' $x$'s and $y$'s explained:

The math is: $rndInt(d-x)+x$ and $rndInt(|d-y|)+y$.
$d$ is the diameter of the circle, $x$ is the left x value, and $y$ is the top y of the circle.



This - in theory - should work, but it doesn't, as seen in the image.



In it, I basically get a random number between $0$ and the difference of the diameter and x.

From there, I add it to x. In theory, this will make a number and add it to x, making it between the preexisting circle.



Is there anything I'm doing wrong? I've spent weeks trying to figure out a formula, and this is the best I've got.







geometry random






share|cite|improve this question













share|cite|improve this question











share|cite|improve this question




share|cite|improve this question










asked Dec 26 '18 at 4:07









Not Sp33dyNot Sp33dy

84




84








  • 2




    $begingroup$
    Although this is a maths QA stack, if you could provide an MWE that might rule out any mathematical errors on your part... Otherwise, perhaps good old Stack Overflow might be your friend, too.
    $endgroup$
    – MacRance
    Dec 26 '18 at 4:18










  • $begingroup$
    To get a point inside the circle, the relation is x+rndInt(d),y-rndInt(d)$
    $endgroup$
    – Shubham Johri
    Dec 26 '18 at 5:11












  • $begingroup$
    I don't see why this should work even "in theory." You have two different objects (cir and cir1) contributing parameters to your constructor. One of these presumably is not the "preexisting" circle you wanted to stay inside. Moreover, all you would have done (if it worked like you said) is to put one corner of the bounding box inside the other bounding box--almost all the rest could be outside.
    $endgroup$
    – David K
    Dec 26 '18 at 5:20










  • $begingroup$
    By the way, there are multiple Java classes named Circle (or in one case Circle2D) documented online; so far yours is the only one I've seen that describes a circle by a corner of its bounding box, its width, and its height. (Can the width and height be different?) Everyone else uses the center and the radius.
    $endgroup$
    – David K
    Dec 26 '18 at 5:26
















  • 2




    $begingroup$
    Although this is a maths QA stack, if you could provide an MWE that might rule out any mathematical errors on your part... Otherwise, perhaps good old Stack Overflow might be your friend, too.
    $endgroup$
    – MacRance
    Dec 26 '18 at 4:18










  • $begingroup$
    To get a point inside the circle, the relation is x+rndInt(d),y-rndInt(d)$
    $endgroup$
    – Shubham Johri
    Dec 26 '18 at 5:11












  • $begingroup$
    I don't see why this should work even "in theory." You have two different objects (cir and cir1) contributing parameters to your constructor. One of these presumably is not the "preexisting" circle you wanted to stay inside. Moreover, all you would have done (if it worked like you said) is to put one corner of the bounding box inside the other bounding box--almost all the rest could be outside.
    $endgroup$
    – David K
    Dec 26 '18 at 5:20










  • $begingroup$
    By the way, there are multiple Java classes named Circle (or in one case Circle2D) documented online; so far yours is the only one I've seen that describes a circle by a corner of its bounding box, its width, and its height. (Can the width and height be different?) Everyone else uses the center and the radius.
    $endgroup$
    – David K
    Dec 26 '18 at 5:26










2




2




$begingroup$
Although this is a maths QA stack, if you could provide an MWE that might rule out any mathematical errors on your part... Otherwise, perhaps good old Stack Overflow might be your friend, too.
$endgroup$
– MacRance
Dec 26 '18 at 4:18




$begingroup$
Although this is a maths QA stack, if you could provide an MWE that might rule out any mathematical errors on your part... Otherwise, perhaps good old Stack Overflow might be your friend, too.
$endgroup$
– MacRance
Dec 26 '18 at 4:18












$begingroup$
To get a point inside the circle, the relation is x+rndInt(d),y-rndInt(d)$
$endgroup$
– Shubham Johri
Dec 26 '18 at 5:11






$begingroup$
To get a point inside the circle, the relation is x+rndInt(d),y-rndInt(d)$
$endgroup$
– Shubham Johri
Dec 26 '18 at 5:11














$begingroup$
I don't see why this should work even "in theory." You have two different objects (cir and cir1) contributing parameters to your constructor. One of these presumably is not the "preexisting" circle you wanted to stay inside. Moreover, all you would have done (if it worked like you said) is to put one corner of the bounding box inside the other bounding box--almost all the rest could be outside.
$endgroup$
– David K
Dec 26 '18 at 5:20




$begingroup$
I don't see why this should work even "in theory." You have two different objects (cir and cir1) contributing parameters to your constructor. One of these presumably is not the "preexisting" circle you wanted to stay inside. Moreover, all you would have done (if it worked like you said) is to put one corner of the bounding box inside the other bounding box--almost all the rest could be outside.
$endgroup$
– David K
Dec 26 '18 at 5:20












$begingroup$
By the way, there are multiple Java classes named Circle (or in one case Circle2D) documented online; so far yours is the only one I've seen that describes a circle by a corner of its bounding box, its width, and its height. (Can the width and height be different?) Everyone else uses the center and the radius.
$endgroup$
– David K
Dec 26 '18 at 5:26






$begingroup$
By the way, there are multiple Java classes named Circle (or in one case Circle2D) documented online; so far yours is the only one I've seen that describes a circle by a corner of its bounding box, its width, and its height. (Can the width and height be different?) Everyone else uses the center and the radius.
$endgroup$
– David K
Dec 26 '18 at 5:26












1 Answer
1






active

oldest

votes


















1












$begingroup$

I am not absolutely sure if I understood your problem statement correctly, so here is the question as I understood it:




How do I ensure that a randomly generated circle is completely contained in an existing circle?




Let's assume the existing circle is centered at $(X, Y)$ and has radius $R = D/2$, where $D$ is its diameter.



First, pick a radius $r$, $0 lt r le R$ for the new circle.



Then, pick an uniform random angle $0text{°} le varphi lt 360text{°}$, or $-180text{°} le varphi lt 180text{°}$, or $0 le varphi lt 2pi$ in radians.



Finally, pick an uniform random deviation $d$ from center, $0 le d le R - r$.



The center of the new smaller circle is then
$$bbox{ leftlbrace ; begin{aligned}
x &= X + d cos varphi \
y &= Y + d sin varphi \
end{aligned} right . }$$



The reason for using trigonometric functions instead of the axis-aligned bounding box is that you can fit a small circle completely within the bounding box of a larger circle, without overlapping at all with the larger circle. Using the radius, and choosing the direction from the center of the larger circle randomly, avoids that sort of error completely.



In pseudocode (in no particular programming language), you could implement this using



Function RandomCircleInside(centerX, centerY, radius):
Let newRadius = radius * Random()
Let radians = 2.0 * 3.14159265358979323846 * Random()
Let deviation = (radius - newRadius) * Sqrt(Random())
Let newX = centerX + deviation * Cos(radians)
Let newY = centerY + deviation * Sin(radians)
Return (newX, newY, newRadius)
End Function


where Random() is a function that returns an uniform random floating-point number between 0 and 1.0, inclusive (meaning it can return 0 and 1); and Sin() and Cos() are the respective trigonometric functions, with argument in radians; and Sqrt() is the square root operation. The square root is needed to ensure an uniform distribution within the disc.



If you want, you can also supply the newRadius parameter to the function (and not calculate it from radius * Random()); the function will work as long as newRadiusradius.



If you cannot use trigonometric functions, we can rewrite the function as



Function RandomCircleInside(centerX, centerY, radius):
Let newRadius = radius * Random()
Let deviation = (radius - newRadius) * Random()
Let dd = deviation * deviation

Do:
dX = deviation - 2 * deviation * Random()
dY = deviation - 2 * deviation * Random()
While (dX*dX + dY*dY > dd)

Let newX = centerX + dX
Let newY = centerY + dY
Return (newX, newY, newRadius)
End Function


This is just as good as the trigonometric function using one, except that it calls Random() about 27% "extra times" on average. (This uses the "exclusion method" to generate a random point within a circular disc. It generates a random point within the axis-aligned square that contains the disc, but ignores any point outside the disc. Since the ratio of their areas is $4 / pi approx 1.27324$, the do-while loop iterates 1.27324 times on average. That is, most times it only does one iteration, and sometimes more than one.)



If your circles are determined by their axis-aligned bounding box, note that the left edge (minimum $x$) is at $X - R$; right edge (maximum $x$) at $X + R$; top edge (minimum $y$) is at $Y - R$; and bottom edge (maximum $y$) at $Y + R$.



If you define your circles based on their axis-aligned bounding box, then center X is (right + left) / 2 = left + width/2, center Y is (bottom + top) / 2 = top + height/2, and radius is (right - left) / 2 = (bottom - top) / 2 = (right - left + bottom - top) / 4 = width / 2 = height / 2 = (width + height) / 2.






share|cite|improve this answer











$endgroup$













  • $begingroup$
    @DavidK: Good point. That radial distribution in an unit disc is obtained by taking the square root of the uniform distribution; now fixed. Thank you!
    $endgroup$
    – Nominal Animal
    Dec 26 '18 at 10:51












  • $begingroup$
    Yes, that looks good. Either of these methods should be fine for what OP asked for.
    $endgroup$
    – David K
    Dec 26 '18 at 14:57











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["$", "$"], ["\\(","\\)"]]);
});
});
}, "mathjax-editing");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "69"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
noCode: true, onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmath.stackexchange.com%2fquestions%2f3052626%2fhow-to-make-a-circle-within-another-circle%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1












$begingroup$

I am not absolutely sure if I understood your problem statement correctly, so here is the question as I understood it:




How do I ensure that a randomly generated circle is completely contained in an existing circle?




Let's assume the existing circle is centered at $(X, Y)$ and has radius $R = D/2$, where $D$ is its diameter.



First, pick a radius $r$, $0 lt r le R$ for the new circle.



Then, pick an uniform random angle $0text{°} le varphi lt 360text{°}$, or $-180text{°} le varphi lt 180text{°}$, or $0 le varphi lt 2pi$ in radians.



Finally, pick an uniform random deviation $d$ from center, $0 le d le R - r$.



The center of the new smaller circle is then
$$bbox{ leftlbrace ; begin{aligned}
x &= X + d cos varphi \
y &= Y + d sin varphi \
end{aligned} right . }$$



The reason for using trigonometric functions instead of the axis-aligned bounding box is that you can fit a small circle completely within the bounding box of a larger circle, without overlapping at all with the larger circle. Using the radius, and choosing the direction from the center of the larger circle randomly, avoids that sort of error completely.



In pseudocode (in no particular programming language), you could implement this using



Function RandomCircleInside(centerX, centerY, radius):
Let newRadius = radius * Random()
Let radians = 2.0 * 3.14159265358979323846 * Random()
Let deviation = (radius - newRadius) * Sqrt(Random())
Let newX = centerX + deviation * Cos(radians)
Let newY = centerY + deviation * Sin(radians)
Return (newX, newY, newRadius)
End Function


where Random() is a function that returns an uniform random floating-point number between 0 and 1.0, inclusive (meaning it can return 0 and 1); and Sin() and Cos() are the respective trigonometric functions, with argument in radians; and Sqrt() is the square root operation. The square root is needed to ensure an uniform distribution within the disc.



If you want, you can also supply the newRadius parameter to the function (and not calculate it from radius * Random()); the function will work as long as newRadiusradius.



If you cannot use trigonometric functions, we can rewrite the function as



Function RandomCircleInside(centerX, centerY, radius):
Let newRadius = radius * Random()
Let deviation = (radius - newRadius) * Random()
Let dd = deviation * deviation

Do:
dX = deviation - 2 * deviation * Random()
dY = deviation - 2 * deviation * Random()
While (dX*dX + dY*dY > dd)

Let newX = centerX + dX
Let newY = centerY + dY
Return (newX, newY, newRadius)
End Function


This is just as good as the trigonometric function using one, except that it calls Random() about 27% "extra times" on average. (This uses the "exclusion method" to generate a random point within a circular disc. It generates a random point within the axis-aligned square that contains the disc, but ignores any point outside the disc. Since the ratio of their areas is $4 / pi approx 1.27324$, the do-while loop iterates 1.27324 times on average. That is, most times it only does one iteration, and sometimes more than one.)



If your circles are determined by their axis-aligned bounding box, note that the left edge (minimum $x$) is at $X - R$; right edge (maximum $x$) at $X + R$; top edge (minimum $y$) is at $Y - R$; and bottom edge (maximum $y$) at $Y + R$.



If you define your circles based on their axis-aligned bounding box, then center X is (right + left) / 2 = left + width/2, center Y is (bottom + top) / 2 = top + height/2, and radius is (right - left) / 2 = (bottom - top) / 2 = (right - left + bottom - top) / 4 = width / 2 = height / 2 = (width + height) / 2.






share|cite|improve this answer











$endgroup$













  • $begingroup$
    @DavidK: Good point. That radial distribution in an unit disc is obtained by taking the square root of the uniform distribution; now fixed. Thank you!
    $endgroup$
    – Nominal Animal
    Dec 26 '18 at 10:51












  • $begingroup$
    Yes, that looks good. Either of these methods should be fine for what OP asked for.
    $endgroup$
    – David K
    Dec 26 '18 at 14:57
















1












$begingroup$

I am not absolutely sure if I understood your problem statement correctly, so here is the question as I understood it:




How do I ensure that a randomly generated circle is completely contained in an existing circle?




Let's assume the existing circle is centered at $(X, Y)$ and has radius $R = D/2$, where $D$ is its diameter.



First, pick a radius $r$, $0 lt r le R$ for the new circle.



Then, pick an uniform random angle $0text{°} le varphi lt 360text{°}$, or $-180text{°} le varphi lt 180text{°}$, or $0 le varphi lt 2pi$ in radians.



Finally, pick an uniform random deviation $d$ from center, $0 le d le R - r$.



The center of the new smaller circle is then
$$bbox{ leftlbrace ; begin{aligned}
x &= X + d cos varphi \
y &= Y + d sin varphi \
end{aligned} right . }$$



The reason for using trigonometric functions instead of the axis-aligned bounding box is that you can fit a small circle completely within the bounding box of a larger circle, without overlapping at all with the larger circle. Using the radius, and choosing the direction from the center of the larger circle randomly, avoids that sort of error completely.



In pseudocode (in no particular programming language), you could implement this using



Function RandomCircleInside(centerX, centerY, radius):
Let newRadius = radius * Random()
Let radians = 2.0 * 3.14159265358979323846 * Random()
Let deviation = (radius - newRadius) * Sqrt(Random())
Let newX = centerX + deviation * Cos(radians)
Let newY = centerY + deviation * Sin(radians)
Return (newX, newY, newRadius)
End Function


where Random() is a function that returns an uniform random floating-point number between 0 and 1.0, inclusive (meaning it can return 0 and 1); and Sin() and Cos() are the respective trigonometric functions, with argument in radians; and Sqrt() is the square root operation. The square root is needed to ensure an uniform distribution within the disc.



If you want, you can also supply the newRadius parameter to the function (and not calculate it from radius * Random()); the function will work as long as newRadiusradius.



If you cannot use trigonometric functions, we can rewrite the function as



Function RandomCircleInside(centerX, centerY, radius):
Let newRadius = radius * Random()
Let deviation = (radius - newRadius) * Random()
Let dd = deviation * deviation

Do:
dX = deviation - 2 * deviation * Random()
dY = deviation - 2 * deviation * Random()
While (dX*dX + dY*dY > dd)

Let newX = centerX + dX
Let newY = centerY + dY
Return (newX, newY, newRadius)
End Function


This is just as good as the trigonometric function using one, except that it calls Random() about 27% "extra times" on average. (This uses the "exclusion method" to generate a random point within a circular disc. It generates a random point within the axis-aligned square that contains the disc, but ignores any point outside the disc. Since the ratio of their areas is $4 / pi approx 1.27324$, the do-while loop iterates 1.27324 times on average. That is, most times it only does one iteration, and sometimes more than one.)



If your circles are determined by their axis-aligned bounding box, note that the left edge (minimum $x$) is at $X - R$; right edge (maximum $x$) at $X + R$; top edge (minimum $y$) is at $Y - R$; and bottom edge (maximum $y$) at $Y + R$.



If you define your circles based on their axis-aligned bounding box, then center X is (right + left) / 2 = left + width/2, center Y is (bottom + top) / 2 = top + height/2, and radius is (right - left) / 2 = (bottom - top) / 2 = (right - left + bottom - top) / 4 = width / 2 = height / 2 = (width + height) / 2.






share|cite|improve this answer











$endgroup$













  • $begingroup$
    @DavidK: Good point. That radial distribution in an unit disc is obtained by taking the square root of the uniform distribution; now fixed. Thank you!
    $endgroup$
    – Nominal Animal
    Dec 26 '18 at 10:51












  • $begingroup$
    Yes, that looks good. Either of these methods should be fine for what OP asked for.
    $endgroup$
    – David K
    Dec 26 '18 at 14:57














1












1








1





$begingroup$

I am not absolutely sure if I understood your problem statement correctly, so here is the question as I understood it:




How do I ensure that a randomly generated circle is completely contained in an existing circle?




Let's assume the existing circle is centered at $(X, Y)$ and has radius $R = D/2$, where $D$ is its diameter.



First, pick a radius $r$, $0 lt r le R$ for the new circle.



Then, pick an uniform random angle $0text{°} le varphi lt 360text{°}$, or $-180text{°} le varphi lt 180text{°}$, or $0 le varphi lt 2pi$ in radians.



Finally, pick an uniform random deviation $d$ from center, $0 le d le R - r$.



The center of the new smaller circle is then
$$bbox{ leftlbrace ; begin{aligned}
x &= X + d cos varphi \
y &= Y + d sin varphi \
end{aligned} right . }$$



The reason for using trigonometric functions instead of the axis-aligned bounding box is that you can fit a small circle completely within the bounding box of a larger circle, without overlapping at all with the larger circle. Using the radius, and choosing the direction from the center of the larger circle randomly, avoids that sort of error completely.



In pseudocode (in no particular programming language), you could implement this using



Function RandomCircleInside(centerX, centerY, radius):
Let newRadius = radius * Random()
Let radians = 2.0 * 3.14159265358979323846 * Random()
Let deviation = (radius - newRadius) * Sqrt(Random())
Let newX = centerX + deviation * Cos(radians)
Let newY = centerY + deviation * Sin(radians)
Return (newX, newY, newRadius)
End Function


where Random() is a function that returns an uniform random floating-point number between 0 and 1.0, inclusive (meaning it can return 0 and 1); and Sin() and Cos() are the respective trigonometric functions, with argument in radians; and Sqrt() is the square root operation. The square root is needed to ensure an uniform distribution within the disc.



If you want, you can also supply the newRadius parameter to the function (and not calculate it from radius * Random()); the function will work as long as newRadiusradius.



If you cannot use trigonometric functions, we can rewrite the function as



Function RandomCircleInside(centerX, centerY, radius):
Let newRadius = radius * Random()
Let deviation = (radius - newRadius) * Random()
Let dd = deviation * deviation

Do:
dX = deviation - 2 * deviation * Random()
dY = deviation - 2 * deviation * Random()
While (dX*dX + dY*dY > dd)

Let newX = centerX + dX
Let newY = centerY + dY
Return (newX, newY, newRadius)
End Function


This is just as good as the trigonometric function using one, except that it calls Random() about 27% "extra times" on average. (This uses the "exclusion method" to generate a random point within a circular disc. It generates a random point within the axis-aligned square that contains the disc, but ignores any point outside the disc. Since the ratio of their areas is $4 / pi approx 1.27324$, the do-while loop iterates 1.27324 times on average. That is, most times it only does one iteration, and sometimes more than one.)



If your circles are determined by their axis-aligned bounding box, note that the left edge (minimum $x$) is at $X - R$; right edge (maximum $x$) at $X + R$; top edge (minimum $y$) is at $Y - R$; and bottom edge (maximum $y$) at $Y + R$.



If you define your circles based on their axis-aligned bounding box, then center X is (right + left) / 2 = left + width/2, center Y is (bottom + top) / 2 = top + height/2, and radius is (right - left) / 2 = (bottom - top) / 2 = (right - left + bottom - top) / 4 = width / 2 = height / 2 = (width + height) / 2.






share|cite|improve this answer











$endgroup$



I am not absolutely sure if I understood your problem statement correctly, so here is the question as I understood it:




How do I ensure that a randomly generated circle is completely contained in an existing circle?




Let's assume the existing circle is centered at $(X, Y)$ and has radius $R = D/2$, where $D$ is its diameter.



First, pick a radius $r$, $0 lt r le R$ for the new circle.



Then, pick an uniform random angle $0text{°} le varphi lt 360text{°}$, or $-180text{°} le varphi lt 180text{°}$, or $0 le varphi lt 2pi$ in radians.



Finally, pick an uniform random deviation $d$ from center, $0 le d le R - r$.



The center of the new smaller circle is then
$$bbox{ leftlbrace ; begin{aligned}
x &= X + d cos varphi \
y &= Y + d sin varphi \
end{aligned} right . }$$



The reason for using trigonometric functions instead of the axis-aligned bounding box is that you can fit a small circle completely within the bounding box of a larger circle, without overlapping at all with the larger circle. Using the radius, and choosing the direction from the center of the larger circle randomly, avoids that sort of error completely.



In pseudocode (in no particular programming language), you could implement this using



Function RandomCircleInside(centerX, centerY, radius):
Let newRadius = radius * Random()
Let radians = 2.0 * 3.14159265358979323846 * Random()
Let deviation = (radius - newRadius) * Sqrt(Random())
Let newX = centerX + deviation * Cos(radians)
Let newY = centerY + deviation * Sin(radians)
Return (newX, newY, newRadius)
End Function


where Random() is a function that returns an uniform random floating-point number between 0 and 1.0, inclusive (meaning it can return 0 and 1); and Sin() and Cos() are the respective trigonometric functions, with argument in radians; and Sqrt() is the square root operation. The square root is needed to ensure an uniform distribution within the disc.



If you want, you can also supply the newRadius parameter to the function (and not calculate it from radius * Random()); the function will work as long as newRadiusradius.



If you cannot use trigonometric functions, we can rewrite the function as



Function RandomCircleInside(centerX, centerY, radius):
Let newRadius = radius * Random()
Let deviation = (radius - newRadius) * Random()
Let dd = deviation * deviation

Do:
dX = deviation - 2 * deviation * Random()
dY = deviation - 2 * deviation * Random()
While (dX*dX + dY*dY > dd)

Let newX = centerX + dX
Let newY = centerY + dY
Return (newX, newY, newRadius)
End Function


This is just as good as the trigonometric function using one, except that it calls Random() about 27% "extra times" on average. (This uses the "exclusion method" to generate a random point within a circular disc. It generates a random point within the axis-aligned square that contains the disc, but ignores any point outside the disc. Since the ratio of their areas is $4 / pi approx 1.27324$, the do-while loop iterates 1.27324 times on average. That is, most times it only does one iteration, and sometimes more than one.)



If your circles are determined by their axis-aligned bounding box, note that the left edge (minimum $x$) is at $X - R$; right edge (maximum $x$) at $X + R$; top edge (minimum $y$) is at $Y - R$; and bottom edge (maximum $y$) at $Y + R$.



If you define your circles based on their axis-aligned bounding box, then center X is (right + left) / 2 = left + width/2, center Y is (bottom + top) / 2 = top + height/2, and radius is (right - left) / 2 = (bottom - top) / 2 = (right - left + bottom - top) / 4 = width / 2 = height / 2 = (width + height) / 2.







share|cite|improve this answer














share|cite|improve this answer



share|cite|improve this answer








edited Dec 26 '18 at 10:55

























answered Dec 26 '18 at 4:47









Nominal AnimalNominal Animal

7,0332517




7,0332517












  • $begingroup$
    @DavidK: Good point. That radial distribution in an unit disc is obtained by taking the square root of the uniform distribution; now fixed. Thank you!
    $endgroup$
    – Nominal Animal
    Dec 26 '18 at 10:51












  • $begingroup$
    Yes, that looks good. Either of these methods should be fine for what OP asked for.
    $endgroup$
    – David K
    Dec 26 '18 at 14:57


















  • $begingroup$
    @DavidK: Good point. That radial distribution in an unit disc is obtained by taking the square root of the uniform distribution; now fixed. Thank you!
    $endgroup$
    – Nominal Animal
    Dec 26 '18 at 10:51












  • $begingroup$
    Yes, that looks good. Either of these methods should be fine for what OP asked for.
    $endgroup$
    – David K
    Dec 26 '18 at 14:57
















$begingroup$
@DavidK: Good point. That radial distribution in an unit disc is obtained by taking the square root of the uniform distribution; now fixed. Thank you!
$endgroup$
– Nominal Animal
Dec 26 '18 at 10:51






$begingroup$
@DavidK: Good point. That radial distribution in an unit disc is obtained by taking the square root of the uniform distribution; now fixed. Thank you!
$endgroup$
– Nominal Animal
Dec 26 '18 at 10:51














$begingroup$
Yes, that looks good. Either of these methods should be fine for what OP asked for.
$endgroup$
– David K
Dec 26 '18 at 14:57




$begingroup$
Yes, that looks good. Either of these methods should be fine for what OP asked for.
$endgroup$
– David K
Dec 26 '18 at 14:57


















draft saved

draft discarded




















































Thanks for contributing an answer to Mathematics Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmath.stackexchange.com%2fquestions%2f3052626%2fhow-to-make-a-circle-within-another-circle%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Bressuire

Cabo Verde

Gyllenstierna