4
$\begingroup$

I don't understand why I get the following output:

enter image description here

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.

Code

(* 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;)]
$\endgroup$
5
$\begingroup$

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[...] *)
| improve this answer | |
$\endgroup$
  • $\begingroup$ yes, it is not evaluating If how I thought it were; however, removing Dynamic from the arguments does not resolve it $\endgroup$ – joka Oct 11 at 16:00
  • $\begingroup$ @joka I show how to remove Dynamic from the arguments but keep it on the output that is displayed. $\endgroup$ – Michael E2 Oct 12 at 13:50
4
$\begingroup$

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.

demo

| improve this answer | |
$\endgroup$
  • $\begingroup$ you're right, my distance formula was missing a square root; other than that-please correct me if I'm wrong-I only see minor changes in your code; allIntersections is still not operational and you had to unwrap it in order for it to work; that's what I didn't get in the first place, why allIntersections refuses to cooperate when instead eg. sldr, which includes a Dynamic[x] (outside Slider I mean) works as expected? $\endgroup$ – joka Oct 11 at 21:09
  • $\begingroup$ @joka Another problem is that nIntersections (this answer) returns 2 when one circle lies inside the other. Shouldn't it be 0? $\endgroup$ – Michael E2 Oct 11 at 21:17
  • $\begingroup$ @MichaelE2 sure-preferably it should return $Failed-but like I said these are minor issues; my problem is with Dynamic and what I understand as 'weird' behavior $\endgroup$ – joka Oct 12 at 7:28
  • $\begingroup$ @joka. allIntersections can be made to work by removing the Dynamic wrappers. I rejected the whole function because I think it simply isn't needed. $\endgroup$ – m_goldberg Oct 12 at 14:24
3
$\begingroup$

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}}])]]

enter image description here

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:

enter image description here

| improve this answer | |
$\endgroup$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.