How to use Wolfram(Alpha) to calculate location of three overlapping Circles

Werner Geiger, 07.05.2023
Note: I think WolframAlpha is not able to do this.
In response to Don Baechtel: https://community.wolfram.com/groups/-/m/t/2915829
​​
I have three sensors, and each sensor provides the distance to a person. The distance sensed provides a Radius for the person in a circle around the sensor. But the distances sensed are not exact, only approximate. It may be off by several feet. So the Radii of the three circles may not overlap, or they may intersect at one point, or the circles may overlap without intersecting exactly at one point. This may be corrected, if necessary, by increasing the radii proportionally until the three circles overlap each other. Once the circles overlap each other, the person’s approximate location can be found by calculating the center of the overlapped area.
​
How can Wolfram Alpha give the person’s location from the distance reported by three sensors? What are the methods to do this?

My Solution

I have some sensors
S
i
and their readings
dist
i
for i=1, …, sCnt.
This defines sCnt circles around
S
i
with radius
dist
i
.
A point
C
i
on a circle is defined by its angle
α
i
which denotes the radius angle in its circle.
The person is at location p where the sum of the squared distances from p to all circle points is at a minimum.
We define some functions draw…[…] which draw the problem.
​
We define a function calcDistFunc[{p,
{
α
i
,… }}, dists, sensors] which calculates this sum to be minimized for a given point p and given circle points
C
i
(i.e. given angles
α
i
).
​
From that we can use the WL-function Minimize[fun, vars] to solve the problem.
This is done by calcMinCPs[dists, sensors]. It returns {p,
{
α
i
,… }}, i.e. the persons location p and the circle points
C
i
where the minimum is achieved.
​
Note: Just for fun we define similar functions
calcMinCPsA[p, dists, sensors] and calcMinCPsP[
{
α
i
,… }, dists, sensors] which do the same for fixed p and fixed
α
i
respectively.

Initialize

In[]:=
ClearAll["Global`*"];​​SetOptions[$FrontEnd,Language"English"]
In[]:=
testLvl=0;​​sensorsDef={{3,-2},{0,3},{-2,-1}};​​distsDef={2,2.5,4};​​sCntDef=Length[sensorsDef];​​sensorsDef4={{3,-2},{0,3},{-2,-1},{-3,3}};​​distsDef4={2,2.5,4,1.5};​​sCntDef4=Length[sensorsDef4];

Presentation

drawSRs[dists:distsDef, {withRad:True, withLeg:True}, sensors:sensorDefs, size:300] draws the sensors at locations sensors and their reading circles of radius dists.
​withRad draws the circle radius.
​withLeg draws a legend.
​size is the size of the drawing.
The whole parameter {withRad, withLeg} can be omitted.
Returns a Graphics
In[]:=
ClearAll[drawSRs];​​drawSRs[dists:{(_?NumericQ)..}:distsDef,sensors:{{_?NumericQ,_?NumericQ}..}:sensorsDef]:=drawSRs[dists,{},sensors];​​drawSRs[dists:{(_?NumericQ)..}:distsDef,{withRad:(_?BooleanQ):True,withLeg:(_?BooleanQ):True,size_:300},sensors:{{_?NumericQ,_?NumericQ}..}:sensorsDef]:=Module[{myName="drawSRs",lvl0=15,cols={Red,Green,Blue},fs=12,sCnt,snames,pCenter,pLR},​​If[testLvl>=lvl0,Echo[Column[{dists,{withRad,withLeg,size},sensors}],myName<>".{dists,{withRad,withLeg,size},sensors}: "]];​​sCnt=Length[sensors];assertTxt[Length[dists]==sCnt,myName."Wrong dists call!"];​​(*Sensornames*)​​snames=Table[Style[Subscript["S",i],Bold,fs,ScriptMinSize->fs-1],{i,sCnt}];​​(*Sensorscenter*)​​pCenter=Mean[sensors];​​(*Lowerrightpointforlegend*)​​pLR=sensorsDef+((#*{1,-1})&/@distsDef);​​pLR={Max[pLR[[All,1]]],Min[pLR[[All,2]]]}+{1,0};​​(*Draw*)​​Graphics[{​​(*sensorsPolygonandcenter*)​​{FaceForm[GrayLevel[0.9]],ConvexHullMesh[sensors]},​​Black,AbsolutePointSize[3],Point[pCenter],​​(*Sensorsandreadings*)​​PointSize[Large],​​Table[{cols[[Mod[i,3,1]]],If[withRad,{Dashed,Thickness[Medium],Line[{sensors[[i]],sensors[[i]]-dists[[i]]*Normalize[pCenter-sensors[[i]]]}]},Nothing],​​Point[sensors[[i]]],Thickness[Small],Circle[sensors[[i]],dists[[i]]],Inset[snames[[i]],sensors[[i]],{2,-1}]}​​,{i,sCnt}],​​(*Legend*)​​If[withLeg,​​Inset[Framed[PointLegend[Table[cols[[Mod[i,3,1]]],{i,sCnt}],snames],Background->GrayLevel[0.9],FrameStyle->None],pLR,{-1,-1}]​​,Nothing]​​},Axes->True,AxesOrigin->{0,0},ImageSize->size​​]​​];
In[]:=
Block[{testLvl=0*15},​​Print[Row[{drawSRs[],drawSRs[distsDef,{False,False}]},"\t"]];​​Print[Row[{drawSRs[distsDef4,{},sensorsDef4],drawSRs[distsDef4,{False,False},sensorsDef4]},"\t"]];​​];
drawCPs[{p, αs}, dists:distsDef, sensors:sensorDefs, size:300] draws the locations and distances of a point p from the sensor reading circle points at angles αs.
​For the other parameters see function drawSRs.
​Returns a Graphics
In[]:=
ClearAll[drawCPs];​​drawCPs[{p:{_?NumericQ,_?NumericQ},αs:{(_?NumericQ)..}},dists:{(_?NumericQ)..}:distsDef,sensors:{{_?NumericQ,_?NumericQ}..}:sensorsDef,size_:300]:=Module[{myName="drawCPs",lvl0=15,cols={Red,Green,Blue},colP=Darker[Orange],fs=12,sCnt,cnames,cPs},​​If[testLvl>=lvl0,Echo[Column[{p,αs,dists,sensors,size}],myName<>".{p,αs,dists,sensors,size}: "]];​​sCnt=Length[sensors];assertTxt[Length[αs]==sCnt,myName."Wrong αs call!"];​​assertTxt[Length[dists]==sCnt,myName."Wrong dists call!"];​​(*Circlepoints*)​​cnames=Table[Style[Subscript["C",i],fs,ScriptMinSize->fs-1],{i,sCnt}];​​cPs=Table[sensors[[i]]+dists[[i]]*{Cos[αs[[i]]],Sin[αs[[i]]]},{i,sCnt}];​​(*Draw*)​​Graphics[{​​(*circlepointsanddistancestop*)​​PointSize[Medium],Thickness[Medium],​​Table[{cols[[Mod[i,3,1]]],Line[{cPs[[i]],p}],Point[cPs[[i]]],Inset[cnames[[i]],cPs[[i]],{2,1}]},{i,sCnt}],​​(*Pointp*)​​colP,Point[p],Inset[Style["P",Bold,fs],p,{-2,1}]​​},Axes->True,AxesOrigin->{0,0},ImageSize->{Automatic,size}​​]​​];
In[]:=
Block[{testLvl=0*15},​​Row[{drawCPs[{{4,5},{0°,0°,0°}}],drawCPs[{{4,5},{0°,0°,0°,0°}},distsDef4,sensorsDef4]},"\t"]​​]
Out[]=
makePαL[p, αs] returns a well readable text of point p and angles αs.
makeDL[dists] returns a well readable text of distances dists.
draw[{p, αs}, dists:distsDef, {pl:””, withRad:True, withLeg:True, size:400}, sensors:sensorDefs] draws the sensors at locations sensors and their reading circles of radius dists together with the distances of a point p from the sensor reading circle points at angles αs.
pl is a PlotLabel. If None, no label. If “”, a default label.
For the parameters see functions drawSRs and drawCPs.
Returns a Graphics

Calculations

calcMinCPs - The solution to the problem

Auto-Save

General Init

Initialization Functions

Enhanced Assert functions

Those functions provide some better readable Assert messages and some enhanced Assert-functions:
​assertState[] gets current Assert-state.
​onAssert[] switch on Assert with a nicer $AssertFunction. Returns the previous state.
​offAssert[] switch off Assert. Returns the previous state.
​onoffAssert[], toggles the Assert-state. Returns the previous state.
​assertGo[test, tag, goLbl, txt] has an additional Goto-label and text. If the assertion fails, the text is outputted and the program jumps to goLbl.
​assertTxt[tes, tag, txt] has an additional text. If the assertion fails, the text is outputted.
​assertBody[tes, tag, body] has an additional body of statements. If the assertion fails, the body is executed. body can be a sequence of statements in parentheses, a Block or a Module.
​