1
$\begingroup$

This question already has an answer here:

I have a list of triangles.

{{{2, 3}, {23, 31}, {32, 19}}, {{2, 5}, {23, 33}, {32, 21}}, {{2, 
   6}, {23, 34}, {32, 22}}, {{2, 8}, {23, 36}, {32, 24}}, {{2, 
   9}, {23, 37}, {32, 25}}, {{2, 10}, {23, 38}, {32, 26}}, {{2, 
   11}, {23, 39}, {32, 27}}, {{3, 4}, {24, 32}, {33, 20}}, {{3, 
   6}, {24, 34}, {33, 22}}, {{3, 7}, {24, 35}, {33, 23}}, {{3, 
   9}, {24, 37}, {33, 25}}, {{3, 10}, {24, 38}, {33, 26}}, {{3, 
   11}, {24, 39}, {33, 27}}, {{4, 3}, {25, 31}, {34, 19}}, {{4, 
   5}, {25, 33}, {34, 21}}, {{4, 7}, {25, 35}, {34, 23}}, {{4, 
   8}, {25, 36}, {34, 24}}, {{4, 10}, {25, 38}, {34, 26}}, {{4, 
   11}, {25, 39}, {34, 27}}, {{5, 3}, {26, 31}, {35, 19}}, {{5, 
   4}, {26, 32}, {35, 20}}, {{5, 6}, {26, 34}, {35, 22}}, {{5, 
   8}, {26, 36}, {35, 24}}, {{5, 9}, {26, 37}, {35, 25}}, {{5, 
   11}, {26, 39}, {35, 27}}, {{6, 3}, {27, 31}, {36, 19}}, {{6, 
   4}, {27, 32}, {36, 20}}, {{6, 5}, {27, 33}, {36, 21}}, {{6, 
   7}, {27, 35}, {36, 23}}, {{6, 9}, {27, 37}, {36, 25}}, {{6, 
   10}, {27, 38}, {36, 26}}, {{7, 3}, {28, 31}, {37, 19}}, {{7, 
   4}, {28, 32}, {37, 20}}, {{7, 5}, {28, 33}, {37, 21}}, {{7, 
   6}, {28, 34}, {37, 22}}, {{7, 8}, {28, 36}, {37, 24}}, {{7, 
   10}, {28, 38}, {37, 26}}, {{7, 11}, {28, 39}, {37, 27}}, {{8, 
   3}, {29, 31}, {38, 19}}, {{8, 4}, {29, 32}, {38, 20}}, {{8, 
   5}, {29, 33}, {38, 21}}, {{8, 6}, {29, 34}, {38, 22}}, {{8, 
   7}, {29, 35}, {38, 23}}, {{8, 9}, {29, 37}, {38, 25}}, {{8, 
   11}, {29, 39}, {38, 27}}, {{9, 3}, {30, 31}, {39, 19}}, {{9, 
   4}, {30, 32}, {39, 20}}, {{9, 5}, {30, 33}, {39, 21}}, {{9, 
   6}, {30, 34}, {39, 22}}, {{9, 7}, {30, 35}, {39, 23}}, {{9, 
   8}, {30, 36}, {39, 24}}, {{9, 10}, {30, 38}, {39, 26}}, {{10, 
   4}, {31, 32}, {40, 20}}, {{10, 5}, {31, 33}, {40, 21}}, {{10, 
   6}, {31, 34}, {40, 22}}, {{10, 7}, {31, 35}, {40, 23}}, {{10, 
   8}, {31, 36}, {40, 24}}, {{10, 9}, {31, 37}, {40, 25}}, {{10, 
   11}, {31, 39}, {40, 27}}}

Now I want to find incenter of all triangles of that list. For each triangle, I used

pA = {2, 3}; pB = {23, 31}; pC = {32, 19};
lr = MeshRegion[{pA, pB, pC}, Triangle[Range@3]];
r1 = RegionDistance[InfiniteLine[{pA, pB}], {x, y}];
r2 = RegionDistance[InfiniteLine[{pB, pC}], {x, y}];
r3 = RegionDistance[InfiniteLine[{pC, pA}], {x, y}];
centerC = {x, y} /. Solve[{r1 == r2, r2 == r3}, {x, y}, Reals];
centerC = Select[centerC, RegionMember[lr, #] &][[1]]
raioC = RegionDistance[Line[{pA, pB}], centerC]
Graphics[{EdgeForm[{Thick, Blue}], White, Triangle[{pA, pB, pC}], 
  PointSize[Large], Red, Point@centerC, Red, Circle[centerC, raioC]}]

How can I use that code with the above list?

$\endgroup$

marked as duplicate by Sektor, MarcoB, rcollyer, b3m2a1, Öskå Jan 19 '18 at 13:48

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

4
$\begingroup$

Why not use Insphere? For example:

triangles = {{{2,3},{23,31},{32,19}},{{2,5},{23,33},{32,21}},{{2,6},{23,34},{32,22}}};

(Insphere /@ triangles)[[All, 1]]

{{23, 21}, {23, 23}, {23, 24}}

$\endgroup$
  • $\begingroup$ While J.M. alluded to Insphere[] in his answer to this question, it seems to me it ought to be a separate answer, since I think it's more efficient than the posted answers. $\endgroup$ – Michael E2 Jan 7 '18 at 16:48
7
$\begingroup$

The question according to the OP might be further clarified thus:

I have a procedure that works on a single input. How do I apply it to a list of inputs?

The question isn't really about incenters, but being couched in a lot incentral detail, it is unlikely to help others who face exactly the same good, basic programming question, whether it is about finding triangles, or derivatives, or whatever. (But if the question is really about finding incenters, then I think it's a duplicate.)

Methods for applying functions to lists are outlined in the guide Applying Functions to Lists.

The first step in repeatedly applying a block of code is usually to convert it to a function. One question is whether the function is to compute the graphic or just the center and radius. The latter seems preferable to me, but to each their own. There are other choices. Usually you want to localize all the variables in a Module. Even the symbolic variables x and y should be localized, in case you execute something like x = 1 during your session.

incenterRaio[tri_] :=     
 Module[{pA, pB, pC, lr, r1, r2, r3, centerC, x, y, raioC},
  {pA, pB, pC} = tri;
  lr = MeshRegion[{pA, pB, pC}, Triangle[Range@3]];
  r1 = RegionDistance[InfiniteLine[{pA, pB}], {x, y}];
  r2 = RegionDistance[InfiniteLine[{pB, pC}], {x, y}];
  r3 = RegionDistance[InfiniteLine[{pC, pA}], {x, y}];
  centerC = {x, y} /. Solve[{r1 == r2, r2 == r3}, {x, y}, Reals];
  centerC = Select[centerC, RegionMember[lr, #] &][[1]];
  raioC = RegionDistance[Line[{pA, pB}], centerC];
  {centerC, raioC}
  ]

One could also set up the function with the points as arguments:

incenterRaio[{pA_, pB_, pC_}] :=     
 Module[{lr, r1, r2, r3, centerC, x, y, raioC},  (* omit pA etc and first line *)
  lr = MeshRegion[{pA, pB, pC}, Triangle[Range@3]];
  ...
  {centerC, raioC}
  ]

But one doesn't need to overthink this before you see it's working.

Applying a function to a single list

Map

Map (/@) is @CarlWoll's solution. It is the "functional programming" approach and often valued above others in this community. For the function incenterRaio, it's the same: incenterRaio /@ triangles.

Table

Table is a personal favorite for getting the job at hand done, when I don't have to worry about code reuse or building a package. I think it's easy for those coming from procedural programming paradigms if you think of Table as a for-loop that makes a list of the results. You don't even have to convert the code block to a function. Just make the input a variable and use the variable in the Table iterator.

incircles = Table[
  {pA, pB, pC} = tri;  (* the only change to the OP's code block *)
  lr = MeshRegion[{pA, pB, pC}, Triangle[Range@3]];
  r1 = RegionDistance[InfiniteLine[{pA, pB}], {x, y}];
  r2 = RegionDistance[InfiniteLine[{pB, pC}], {x, y}];
  r3 = RegionDistance[InfiniteLine[{pC, pA}], {x, y}];
  centerC = {x, y} /. Solve[{r1 == r2, r2 == r3}, {x, y}, Reals];
  centerC = Select[centerC, RegionMember[lr, #] &][[1]];
  raioC = RegionDistance[Line[{pA, pB}], centerC];
  {centerC, raioC},
  {tri, triangles}]   (* Table[] will loop over the list  triangles  *)
(*
{{{23, 21}, 6}, {{23, 23}, 6}, {{23, 24}, 6}, {{23, 26}, 6}, {{23, 27}, 6}, {{23, 28}, 6},
 {{23, 29}, 6}, {{24, 22}, 6}, {{24, 24}, 6}, {{24, 25}, 6}, {{24, 27}, 6}, {{24, 28}, 6},
 {{24, 29}, 6}, {{25, 21}, 6}, {{25, 23}, 6}, {{25, 25}, 6}, {{25, 26}, 6}, {{25, 28}, 6},
 {{25, 29}, 6}, {{26, 21}, 6}, {{26, 22}, 6}, {{26, 24}, 6}, {{26, 26}, 6}, {{26, 27}, 6},
 {{26, 29}, 6}, {{27, 21}, 6}, {{27, 22}, 6}, {{27, 23}, 6}, {{27, 25}, 6}, {{27, 27}, 6},
 {{27, 28}, 6}, {{28, 21}, 6}, {{28, 22}, 6}, {{28, 23}, 6}, {{28, 24}, 6}, {{28, 26}, 6},
 {{28, 28}, 6}, {{28, 29}, 6}, {{29, 21}, 6}, {{29, 22}, 6}, {{29, 23}, 6}, {{29, 24}, 6},
 {{29, 25}, 6}, {{29, 27}, 6}, {{29, 29}, 6}, {{30, 21}, 6}, {{30, 22}, 6}, {{30, 23}, 6},
 {{30, 24}, 6}, {{30, 25}, 6}, {{30, 26}, 6}, {{30, 28}, 6}, {{31, 22}, 6}, {{31, 23}, 6},
 {{31, 24}, 6}, {{31, 25}, 6}, {{31, 26}, 6}, {{31, 27}, 6}, {{31, 29}, 6}}
*)

Applying a function to two (or more) lists

Suppose you want to apply the Graphic[..] code to the list of incircles. You also need the corresponding triangle from the list of triangles. The setup is this. Input:

triangles = {tri1, tri2, ...}
incircles = {cr1,  cr2, ...}

Desired output:

Out[]= {f[tri1, cr1], f[tri2, cr2], ...}

MapThread

The solution is MapThread:

MapThread[f, {triangles, incircles}]

How to make the elements of a list the arguments of a function

Now, how to construct f? There is one problem to address first: We want to construct Circle[centerC, raioC] given a list cr = {centerC, raioC}.

Apply

The solution is Apply (@@):

Circle @@ {centerC, raioC}
(*  Circle[centerC, raioC]  *)

Function for the graphics

One can make a function as we did above, but let's show another common way, Function.

MapThread[
  Function[
   {tri, cr},  (* arguments: tri = triangle, cr = {center, radius} *)
   Graphics[{EdgeForm[{Thick, Blue}], White, Triangle[tri], 
     PointSize[Large], Red, Point@First@cr, Red, Circle @@ cr}, (* First@cr = center *)
    PlotRange -> {{2.`, 40.`}, {3.`, 39.`}}, 
    PlotRangePadding -> Scaled[.05]]
   ],
  {triangles, incircles}] //
 ListAnimate  (* optional visualization *)

enter image description here

$\endgroup$
  • $\begingroup$ Thank you very much for you answer. $\endgroup$ – minhthien_2016 Jan 9 '18 at 3:49
  • 1
    $\begingroup$ @toandhsp You're welcome. :) $\endgroup$ – Michael E2 Jan 9 '18 at 3:49
  • $\begingroup$ Now I understand clearly my problem. I have just tried MapThread[Insphere, {triangles}]. A big problem is how can I make list triangles like that. $\endgroup$ – minhthien_2016 Jan 9 '18 at 3:51
  • $\begingroup$ In your code, * First@cr = center *, How can I get the second? I used Second@cr, I didn't get the result. $\endgroup$ – minhthien_2016 Mar 30 '18 at 8:34
  • $\begingroup$ First[cr] is equivalent to cr[[1]] (see the "Details" of the doc page for First); use cr[[2]] for the second part. e[[...]] is the same as Part[e,...]. First and Last are for convenience, I guess; they're easier to read when there's an excessive amount of e2[[e1[[n]]]]. $\endgroup$ – Michael E2 Mar 30 '18 at 11:45

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