Mathematica Asked by joka on February 22, 2021
I don’t understand why I get the following output:
when in fact I was expecting to get $Failed
, 1
or 2
instead of res$xxxx
.
I am especially baffled because I think that.
Graphics[{Red, Circle[{Dynamic[x0], Dynamic[y0]}, Dynamic[r0]]}]
is syntactically equivalent to
allIntersections[
{Dynamic[x0], Dynamic[y0]}, Dynamic[r0],
{Dynamic[x1], Dynamic[y1]}, Dynamic[r1], {Dynamic[x2], Dynamic[y2]}, Dynamic[r2]]
and although the former displays and updates as expected, the later doesn’t.
(* do two circles intersect in one or two points? *)
nIntersections[o0_, r0_, o1_, r1_] :=
Module[{res, hyp},
If[
(* concentric circles *)
o0 == o1,
res = $Failed,
(* non-concentric circles *)
hyp = Total[(o1 - o0)^2];
res =
Which[
(* do not intersect *)
r0 + r1 < hyp, $Failed,
(* single intersection point *)
r0 + r1 == hyp, 1,
(* two intersection points *)
r0 + r1 > hyp, 2,
(* something went wrong *)
True, $Failed]];
res]
allIntersections[o0_, r0_, o1_, r1_, o2_, r2_] :=
Module[{ni01, ni02, ni12, nis},
(* count the number of possible intersections *)
ni01 = nIntersections[Dynamic[o0], Dynamic[r0], Dynamic[o1], Dynamic[r1]];
ni02 = nIntersections[Dynamic[o0], Dynamic[r0], Dynamic[o2], Dynamic[r2]];
ni12 = nIntersections[Dynamic[o1], Dynamic[r1], Dynamic[o2], Dynamic[r2]];
nis = {ni01, ni02, ni12};
nis]
(* styled row *)
row = (Riffle[#, " "] &) /* Row;
sldr[x_, tag_, x0_, xe_, dx_] :=
{tag, Slider[Dynamic[x], {x0, xe, dx}], Dynamic[x]}
(* slider controls *)
sldrs[{xs__}, {tags__}, {x0s__}, {xes__}, {dxs__}] :=
Module[{args = {{xs}, {tags}, {x0s},{xes}, {dxs}}},
MapThread[row[sldr[##]]&, args]]
(* entry point *)
DynamicModule[
{x0, y0, r0, x1, y1, r1, x2, y2, r2, vars, tags, x0s, xes, dxs, args, rng},
vars = {x0, y0, r0, x1, y1, r1, x2, y2, r2};
tags = {"x0", "y0", "r0", "x1", "y1", "r1", "x2", "y2", "r2"};
x0s = {0, 0, 0, 0, 0, 0, 0, 0, 0};
xes = {9, 9, 9, 9, 9, 9, 9, 9, 9};
dxs = {0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001};
rng = Transpose @ Map[Through[{Min, Max}[#]]&, {x0s, xes}];
args = {vars, tags, x0s, xes, dxs};
{
(* display *)
{Graphics[{Red, Circle[{Dynamic[x0], Dynamic[y0]}, Dynamic[r0]]}],
Graphics[{Darker @ Green, Circle[{Dynamic[x1], Dynamic[y1]}, Dynamic[r1]]}],
Graphics[{Darker@Blue, Circle[{Dynamic[x2], Dynamic[y2]}, Dynamic[r2]]}]}
//
Show[#, PlotRange -> rng] &,
(* controls *)
Column[sldrs @@ args, Alignment -> Left],
(* numerical output *)
allIntersections[
{Dynamic[x0], Dynamic[y0]},
Dynamic[r0],
{Dynamic[x1], Dynamic[y1]}, Dynamic[r1], {Dynamic[x2],
Dynamic[y2]}, Dynamic[r2]]},
Initialization :> (
x0 = 2.6;
y0 = 4;
r0 = 1.9;
x1 = 4.;
y1 = 4.;
r1 = 1.65;
x2 = 5.5;
y2 = 4.;
r2 = 1.4;)]
The answer to why you get the res$nnn
in the output:
The condition o0 == o1
of If
in nIntersections
evaluates to neither True
nor False
, because the arguments are wrapped in Dynamic
. I will insert two hooks, murf
and foo
, to trace what happens.
nIntersections[o0_, r0_, o1_, r1_] := Module[{res, hyp},
If[(*concentric circles*)o0 == o1,
murf = True; (* first case: o0 == o1 is True *)
res = $Failed,(*non-concentric circles*)
murf = False; (* second case: o0 == o1 is False *)
hyp = Total[(o1 - o0)^2];
res = Which[(*do not intersect*)
r0 + r1 < hyp,
foo = Less;
$Failed,(*single intersection point*)
r0 + r1 == hyp,
foo = Equal;
1,(*two intersection points*)
r0 + r1 > hyp,
foo = Greater;
2,(*something went wrong*)
True,
foo = True;
$Failed],
murf = Equal (* third case: o0 == o1 does not evaluate to True or False *)
];
res]
Check after executing the DynamicModule
:
foo
murf
(* foo <-- shows Which was never evaluated Equal <-- show If evaluated third case (4th argument) *)
So indeed, the condition in If
was neither True
nor False
.
It can probably be fixed by removing Dynamic
from the arguments. Dynamic
need only wrap the output that is displayed, I think.
Appendix: Elaboration of remark about removing Dynamic
First I removed all the Dynamic[]
wrappers in the OP's code with the following, and then I edited Dynamic
back in where it is needed in the output:
Hold[< pasted OP's code >] /. Dynamic[x_] :> x // InputForm
The additions of Dynamic[]
are preceded by comments. I gave two alternative codes for nIntersections
but resisted other refactoring.
nIntersections[o0_, r0_, o1_, r1_] :=
RegionMeasure@RegionIntersection[Circle[o0, r0], Circle[o1, r1]] /.
0 -> $Failed;
nIntersections[o0_, r0_, o1_, r1_] :=
With[{r2 = EuclideanDistance[o0, o1]},
1 + Min[Sign[r0 + r1 - r2], Sign[r1 + r2 - r0],
Sign[r2 + r0 - r1]] /. 0 -> $Failed
];
allIntersections[o0_, r0_, o1_, r1_, o2_, r2_] :=
Module[{ni01, ni02, ni12, nis},
ni01 = nIntersections[o0, r0, o1, r1];
ni02 = nIntersections[o0, r0, o2, r2];
ni12 = nIntersections[o1, r1, o2, r2];
nis = {ni01, ni02, ni12}; nis];
row = (Riffle[#1, " "] & ) /* Row;
sldr[x_, tag_, x0_, xe_, dx_] := {tag, Slider[x, {x0, xe, dx}], x};
sldrs[{xs__}, {tags__}, {x0s__}, {xes__}, {dxs__}] :=
Module[{args = {{xs}, {tags}, {x0s}, {xes}, {dxs}}},
MapThread[row[sldr[##1]] & ,
args]];
DynamicModule[
{x0, y0, r0, x1, y1, r1, x2, y2, r2, vars, tags, x0s, xes,
dxs, args, rng},
vars = {x0, y0, r0, x1, y1, r1, x2, y2, r2};
tags = {"x0", "y0", "r0", "x1", "y1", "r1", "x2", "y2", "r2"};
x0s = {0, 0, 0, 0, 0, 0, 0, 0, 0};
xes = {9, 9, 9, 9, 9, 9, 9, 9, 9};
dxs = {0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001,
0.001};
rng = Transpose[(Through[{Min, Max}[#1]] & ) /@ {x0s, xes}];
(*** wrap vars in Dynamic[] ***)
args = {Dynamic /@ vars, tags, x0s, xes, dxs};
{(Show[#1, PlotRange -> rng] & )[
{(*** wrap Circle[]s in Dynamic[] ***)
Graphics[{Red, Dynamic@Circle[{x0, y0}, r0]}],
Graphics[{Darker[Green], Dynamic@Circle[{x1, y1}, r1]}],
Graphics[{Darker[Blue], Dynamic@Circle[{x2, y2}, r2]}]}],
Column[sldrs @@ args, Alignment -> Left],
(*** wrap allIntersections[] in Dynamic[] ***)
Dynamic@allIntersections[{x0, y0}, r0, {x1, y1},
r1, {x2, y2}, r2]},
Initialization :> (x0 = 2.6; y0 = 4; r0 = 1.9; x1 = 4.;
y1 = 4.; r1 = 1.65; x2 = 5.5; y2 = 4.; r2 = 1.4; )]
Other alternatives
Row[sldr[##1], " "] (* instead of row[sldr[##1]] *)
(* set up vars and the rest can be constructed from it *)
tags = Subscript @@ (* works if vars named by char + number *)
Characters@First@StringSplit[SymbolName[#], "$"] & /@ vars;
x0s = 0 vars;
xes = 9 + x0s;
dxs = 0.001 + x0s;
Graphics[<all three circles>] (* instead of Show[...] *)
Answered by Michael E2 on February 22, 2021
There are many errors in your code. The most serious is that your definition of nIntersections
doesn't compute the intersection correctly. When I rewrite your code as:
(*do two circles intersect in one or two points?*)
With[{ϵ = .01},
nIntersections[o0_, r0_, o1_, r1_] :=
If[(*concentric circles*)o0 == o1, 0,
(*non-concentric circles*)
With[{d = EuclideanDistance[o0, o1]},
Which[
(*single intersection point*)Abs[r0 + r1 - d] < ϵ, 1,
(*do not intersect*)r0 + r1 < d, 0,
(*two intersection points*)r0 + r1 > d, 2,
(*something went wrong*)True, $Failed]]]]
(*styled row*)
row = (Riffle[#, " "] &) /* Row;
sldr[x_, tag_, x0_, xe_, dx_] := {tag, Slider[Dynamic[x], {x0, xe, dx}], Dynamic[x]}
(*slider controls*)
sldrs[{xs__}, {tags__}, {x0s__}, {xes__}, {dxs__}] :=
Module[{args = {{xs}, {tags}, {x0s}, {xes}, {dxs}}},
MapThread[row[sldr[##]] &, args]]
DynamicModule[
{x0, y0, r0, x1, y1, r1, x2, y2, r2, vars, tags, x0s, xes, dxs, args, rng},
vars = {x0, y0, r0, x1, y1, r1, x2, y2, r2};
tags = {"x0", "y0", "r0", "x1", "y1", "r1", "x2", "y2", "r2"};
x0s = {0, 0, 0, 0, 0, 0, 0, 0, 0};
xes = {9, 9, 9, 9, 9, 9, 9, 9, 9};
dxs = {0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001};
rng = Transpose @ Map[Through[{Min, Max}[#]]&, {x0s, xes}];
args = {vars, tags, x0s, xes, dxs};
(*display*)
Column[
{Show[
Graphics[{Red, Circle[{x0, y0}, r0]}],
Graphics[{Darker@Green, Circle[{x1, y1}, r1]}],
Graphics[{Darker@Blue, Circle[{x2, y2}, r2]}],
PlotRange -> rng],
(*sliders*)
Column[sldrs @@ args, Alignment -> Left],
(*intersection count*)
Dynamic @
{nIntersections[{x0, y0}, r0, {x1, y1}, r1],
nIntersections[{x0, y0}, r0, {x2, y2}, r2],
nIntersections[{x1, y1}, r1, {x2, y2}, r2]}}],
Initialization :> (
x0 = 2.6; y0 = 4; r0 = 1.9;
x1 = 4.; y1 = 4.; r1 = 1.65;
x2 = 5.5; y2 = 4.; r2 = 1.4;)]
I get something that works and even seems to get the intersections correctly.
Answered by m_goldberg on February 22, 2021
Michael E2. and m_goldberg's detailed answers address directly the questions in OP. This post suggests an alternative approach using LocatorPane
with locators to modify centers ("●") and radii ("◆"):
DynamicModule[{pts = {{-5., 0.}, {0., 0.}, {5., 0.}, {-5., 2.}, {0., 1.}, {5., 3.}},
rd = {2., 1., 3}, ri, circles},
LocatorPane[Dynamic[pts,
With[{i = CurrentValue["CurrentLocatorPaneThumb"]},
If[1 <= i <= 3, pts[[i]] = #[[i]];
pts[[i + 3]] = pts[[i]] + rd[[i]] Normalize[pts[[i + 3]] - #[[i]]],
pts[[i]] = #[[i]]; rd[[i - 3]] = Norm[#[[i]] - pts[[i - 3]]]]] &],
Deploy @ Dynamic @ Legended[Framed @
Graphics[{Black, PointSize[Large], ri = RegionIntersection @@@
Subsets[circles = Circle @@@ Transpose[{pts[[;; 3]], rd}], {2}] /.
_EmptyRegion -> {},
Transpose[{{ Green, Red, Blue}, circles}]},
PlotRange -> 20, ImageSize -> 1 -> 12, Frame -> False], None],
Appearance -> (Style[##, 12] & @@@ Tuples[{{"●", "◆"}, {Green, Red, Blue}}])]]
To add a legend use
legend = Grid[{Prepend[Style["○", 32, #] & /@ {Green, Red, Blue}, ""],
{"radius", ## & @@ Round[#2, 10.^-3]},
{"center", ## & @@ Round[#[[;; 3]], 10.^-3]},
{Item[Row[{"intersections :",
Total[Flatten[#3] /. Point -> Length]}], Alignment -> Left,
Background -> LightBlue], SpanFromLeft, SpanFromLeft},
## & @@ Thread[{Row[#, Spacer[1]] & /@
Subsets[Style["○", 32, #] & /@ {Green, Red, Blue}, {2}], #3 /.
Point -> (Row[#, ", "] &), SpanFromLeft, SpanFromLeft}]},
Dividers -> All, ItemSize -> {{9, 9, 9, 9}, Automatic}] &;
and replace Legended[..., None]
above with Legended[..., Placed[legend[pts, rd, ri], Right]]
to get:
Answered by kglr on February 22, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP