Here's a fast algo: 1) find convex vertices, 2) from those find one with the maximum Cross
between its segments, 3) then pick a point using bisector and a small distance. This approach remotely resembles @Richard Kirk ‘s idea.
Testing code:
(* Generate a convex polygon *)
n = 1;(* 1 | 100 | 1000 | 5000 | 10000 *)
points =
Join[Transpose[{Range[2*n + 1]*5,
Drop[Flatten@ConstantArray[{0, 45}, n + 1], -1]}],
Transpose[{Reverse@Range[2*n + 1]*5 - 5,
Drop[Flatten@ConstantArray[{55, 10}, n + 1], -1]}]];
(* OP slow solution *)
{t0, pt0} = RandomPoint@Polygon[points] // RepeatedTiming;
(* Greg Hurst 1 - RandomPoint@MeshRegion *)
{t1, pt1} =
RandomPoint@MeshRegion[points, Polygon[Range[Length[points]]]] //
RepeatedTiming;
(* Greg Hurst 2 - RandomPoint@
BoundaryMeshRegion *)
{t2, pt2} =
RandomPoint@
BoundaryMeshRegion[points,
Line[Append[Range[Length[points]], 1]]] // RepeatedTiming;
(* cvgmt *)
{t3, nothing} = RepeatedTiming[
triangles = PolygonDecomposition[Polygon@points, "Triangle"];
areas = Area /@ triangles;
pt3 = RandomPoint@RandomChoice[areas -> triangles];
];
(* Anton *)
distance = 1*^-9;
generateInsidePoint[points_, distance_] :=
Module[{segVectors, svNorm, svNormRL, cross, rotations, ccws,
ccwcrosses, vertexPos, vertex},
segVectors = RotateLeft@points - points;
svNorm =
segVectors/(segVectors[[All, 1]]^2 + segVectors[[All, 2]]^2)^.5;
svNormRL = RotateLeft@svNorm;
cross =
Abs[-svNorm[[All, 2]]*svNormRL[[All, 1]] +
svNorm[[All, 1]]*svNormRL[[All, 2]]];
rotations = isitclockwise@points;
ccws = Pick[Range@Length@points, rotations, -1];
ccwcrosses = cross[[ccws]];
vertexPos = ccws[[Ordering[ccwcrosses][[-1]]]];
vertex = points[[vertexPos]];
vertex +
Normalize[
Mean@{vertex -
Normalize[vertex - RotateRight[points][[vertexPos]]],
vertex +
Normalize[RotateLeft[points][[vertexPos]] - vertex]} -
vertex]*distance]
generateInsidePoint2[points_, distance_] :=
Module[{segVectors, svNorm, svNormRL, cross, rotations, ccws,
ccwcrosses, vertexPos, vertex, rtL, rtR,
triples, t1, t2},
segVectors = RotateLeft@points - points;
svNorm =
segVectors/(segVectors[[All, 1]]^2 + segVectors[[All, 2]]^2)^.5;
svNormRL = RotateLeft@svNorm;
cross =
Abs[-svNorm[[All, 2]]*svNormRL[[All, 1]] +
svNorm[[All, 1]]*svNormRL[[All, 2]]];
rtR = RotateRight@points;
rtL = RotateLeft@points;
triples = Transpose[{rtR, points, rtL}];
t1 = triples[[All, All, 1]];
t2 = triples[[All, All, 2]];
rotations =
Sign[Total /@ ((RotateLeft /@ t1 - t1)*(RotateLeft /@ t2 + t2))];
ccws = Pick[Range@Length@points, rotations, -1];
ccwcrosses = cross[[ccws]];
vertexPos = ccws[[Ordering[ccwcrosses][[-1]]]];
vertex = points[[vertexPos]];
vertex +
Normalize[
Mean@{vertex -
Normalize[vertex - RotateRight[points][[vertexPos]]],
vertex +
Normalize[RotateLeft[points][[vertexPos]] - vertex]} -
vertex]*distance
]
(* Anton 1 - we do this one for those of us who speaks of themselves in the plural *)
{t4, nothing} = RepeatedTiming[
isitclockwise =
Compile[{{pts, _Real, 2}}, Module[{rtR, rtL, triples, t1, t2},
rtR = RotateRight@pts;
rtL = RotateLeft@pts;
triples = Transpose[{rtR, pts, rtL}];
t1 = triples[[All, All, 1]];
t2 = triples[[All, All, 2]];
Sign[
Total /@ ((RotateLeft /@ t1 - t1)*(RotateLeft /@ t2 + t2))]],
RuntimeOptions -> "Speed"];
pt4 = generateInsidePoint[points, 1*^-9];
];
(* Anton 2 - using compiled function but not being dumb af *)
{t5, pt5} = generateInsidePoint[points, 1*^-9] // RepeatedTiming;
(* Anton 3 - without compiled functions *)
{t6, pt6} = generateInsidePoint2[points, 1*^-9] // RepeatedTiming;
Timings in log scale:
Timings in regular scale: