I don't very content with current method.So a better solution is expected still.I hope it meet two conditions in following.
- That space is approximately equivalence.
- We can control how many points to produce.
v11.1 provides a new function SpherePoints
. As the Details
SpherePoints[n]
gives exactly equally spaced points in certain cases for smalln
. In other cases, it places points so they are approximately equally spaced.
Can we achieve the same goal i.e. approximately equally spaced points in an arbitrary 2D Region?
The following is my attempt based on Union
:
SeedRandom[1]
region = ConvexHullMesh[RandomReal[1, {100, 2}]];
UniformPts =
Union[RandomPoint[region, 50000],
SameTest -> (EuclideanDistance[#1, #2] < .1 &)];
Show[region, Graphics[Point[UniformPts]]]
Nevertheless, this approach has two weakness:
It is slow with a large number of pre-generated points i.e. the 2nd argument of
RandomPoint
, while the space won't be uniform enough if I don't pre-generate enough points, here's an example:The number of resulting points isn't controllable.
Answer
Annealing
Found this to be an interesting question and immediately I thought it to be a good application for simulated annealing.
Here's a little unoptimized annealing function I wrote. The idea is that your points move around like atoms in random directions but they "cool down" over time and move less and settle into a minimum energy configuration state.
My rules are:
- plan a move in a random direction and random distance of maximum length
step
- move only if the distance to the nearest point increases
- move only if the new location is inside the region
Assumes rm is a globally defined RegionMember function.
anneal[pts_, step_] :=
Module[{np, nn, test1, test2, pl, potentialMoves},
pl = Length@pts;
np = Nearest@pts;
nn = np[#, 2][[2]] & /@ pts;
potentialMoves = RandomReal[step, pl]*RandomPoint[Circle[], pl];
test1 =
Boole@Thread[
MapThread[EuclideanDistance[#1, #2] &, {pts, nn}] <
MapThread[
EuclideanDistance[#1, #2] &, {pts + potentialMoves, nn}]];
test2 = Boole[rm /@ (pts + potentialMoves)];
pts + potentialMoves*test1*test2]
Here is an example with 200 pts, 1000 steps and an anneal rate of .995. Initial step should be on the order of the region size:
Clear[x,y];reg=ImplicitRegion[x^2-y^2<=1,{{x,-3,3},{y,-3,3}}];
rm=RegionMember[reg];
pts=RandomPoint[reg,200];
step=1;
Do[pts=anneal[pts,step=.995*step],1000];
Show[RegionPlot[reg],Graphics[{Black,Point/@pts}]]
Here is an animation of the process:
Comments
Post a Comment