Is there a simple strategy to determine whether a point is inside a boundary?
One way you can do this is to first discretize the graphics, then turn it into a region with an interior using DelaunayMesh
, and finally using RegionMember
:
mat1 = {{0., -5., 0}, {-5.2203, 0., 1.7945}};
mat2 = {{-0.8583, -4.9384, 0.1765}, {-5.4189, 0.7822, 2.3088}};
θ1 = 2.4798;
θ2 = 3.1275;
gr=
Show[
{ParametricPlot[
mat1.{Sin[θ], Cos[θ], 1}, {θ, 0, 2.4798}, PlotStyle -> Red],
ParametricPlot[
mat1.{Sin[θ], Cos[θ], 1}, {θ, 5.8629, 2 Pi}, PlotStyle -> Red],
ParametricPlot[
mat2.{Sin[θ], Cos[θ], 1}, {θ, 3.1275, 6.1325}],
Graphics[
{Line[{mat1.{Sin[θ1], Cos[θ1], 1}, mat2.{Sin[θ2], Cos[θ2], 1}}]}]},
PlotRange -> All];
Now we turn the graphics into a region:
dg = DelaunayMesh@MeshCoordinates@DiscretizeGraphics@gr;
And we can now determine that {0,3}
is inside this region:
RegionMember[dg, {0., 3.}]
True
Note that you can get better performance by creating a RegionMemberFunction
and applying it directly to a list of points (it's Listable
).
rf = RegionMember[dg]; (* create RegionMemberFunction *)
rf[{{0., 3.}, {0., 2.}, {5., 0.}, {0., 8.}, {1., 1.}}] (* apply the function *)
{True, True, False, False, True}
I am going to use Graphics`PolygonUtils`PointWindingNumber
from R.M's answer to How to check if a 2D point is in a polygon?. In M10 you can use RegionMember
.
The idea is to convert your region into a polygon and then test if the point is inside or not.
mat1 = {{0., -5., 0}, {-5.2203, 0., 1.7945}};
mat2 = {{-0.8583, -4.9384, 0.1765}, {-5.4189, 0.7822, 2.3088}};
q1 = 2.4798; q2 = 3.1275;
dq = 0.1; (*use smaller value for better precession*)
seg1 = Table[mat1.{Sin[q], Cos[q], 1}, {q, 0, 2.4798, dq}];
seg2 = Table[mat1.{Sin[q], Cos[q], 1}, {q, 5.8629, 2 Pi, dq}];
seg3 = Table[mat2.{Sin[q], Cos[q], 1}, {q, 3.1275, 6.1325, dq}];
seg4 = {mat1.{Sin[q1], Cos[q1], 1}, mat2.{Sin[q2], Cos[q2], 1}};
path = Join[seg1, seg2, seg3, seg4];
(*Make a continuous path from all the points*)
spath = FindCurvePath[path]//First;
boundary = path[[#]] & /@ spath;
inPolyQ[poly_, pt_] := Graphics`PolygonUtils`PointWindingNumber[poly, pt] =!= 0
Manipulate[Graphics[Line[boundary],
PlotLabel -> Text[Style[StringForm["Point`` is ``", p,
If[inPolyQ[boundary, p], "Inside ", "Outside"]], Bold, Italic]]],
{{p, {0, 0}}, Locator}]
For Mathematica9
For MMA9 you have to use Graphics`Mesh`PointWindingNumber[poly, pt]
in place of Graphics`PolygonUtils`PointWindingNumber[poly, pt]
.
Perhaps a bit of an overkill. Imagine the points on the boundary and the points you input as electric charges:
mat1 = {{0., -5., 0}, {-5.2203, 0., 1.7945}};
mat2 = {{-0.8583, -4.9384, 0.1765}, {-5.4189, 0.7822, 2.3088}};
θ1 = 2.4798;
θ2 = 3.1275;
g=Show[
{ParametricPlot[
mat1.{Sin[θ], Cos[θ], 1}, {θ, 0, 2.4798}, PlotStyle -> Red],
ParametricPlot[
mat1.{Sin[θ], Cos[θ], 1}, {θ, 5.8629, 2 Pi}, PlotStyle -> Red],
ParametricPlot[
mat2.{Sin[θ], Cos[θ], 1}, {θ, 3.1275, 6.1325}, PlotStyle -> Red],
Graphics[
{Thick, Red, Line[{mat1.{Sin[θ1], Cos[θ1], 1}, mat2.{Sin[θ2], Cos[θ2], 1}}]}]},
PlotRange -> All];
step[form_] :=
Function[# -
10^-4 Sum[
Normalize[ext[[i]] - #]/Norm[ext[[i]] - #]^2, {i,
Length@ext}]] /@ form
relax[object_, t_] := First@{
ext = RandomPoint[DiscretizeGraphics@g, 10^3];
fin = NestList[step, object, t];
Print@ListAnimate[
Function@Show[g, #, Axes -> False] /@
Function@ListPlot[#, PlotStyle -> Gray] /@ fin];
Table[{Part[First@fin, i],
If[EuclideanDistance[Part[Last@fin, i], Mean@ext] -
EuclideanDistance[Part[First@fin, i], Mean@ext] < 0,
Text["Inside"], Text["Outside"]]}, {i, Length@First@fin}
] // MatrixForm
}
Usage
Note that increasing t
yields more accurate results.
relax[{{0, 0}, {2, 0}, {5, 6}}, 100]