Çokgen özelliğine sahibim ve içinde noktalar oluşturabilmek istiyorum. Bir sınıflandırma görevi için buna ihtiyacım var.
Biri çokgenin içine girinceye kadar rastgele puan üretmek işe yaramaz çünkü bu zamanın gelmesi gerçekten tahmin edilemez.
Çokgen özelliğine sahibim ve içinde noktalar oluşturabilmek istiyorum. Bir sınıflandırma görevi için buna ihtiyacım var.
Biri çokgenin içine girinceye kadar rastgele puan üretmek işe yaramaz çünkü bu zamanın gelmesi gerçekten tahmin edilemez.
Yanıtlar:
Çokgenin üçgenlere ayrıştırılması ile başlayın, sonra bunların içinde noktalar oluşturun . (Düzgün bir dağılım için, her üçgeni alanına göre ağırlıklandırın.)
Bu soruya bir QGIS etiketi koyduğunuzda: Random Points aracı bir sınır katmanıyla birlikte kullanılabilir.
Kod arıyorsanız, temel eklenti kaynak kodunun yardımı olmalıdır.
Çokgenin genişliğini belirleyebilir, daha sonra bu uzantılardaki X ve Y değerleri için rasgele sayı oluşturmayı sınırlayabilirsiniz.
Temel işlem: 1) Maxx, maxy, minx, çokgen köşelerinin minidini belirle, 2) Bu değerleri sınırlar olarak kullanarak rastgele noktalar oluşturun 3) Poligonunuzla kesişmek için her noktayı test edin, 4) Kesişmeyi tatmin eden yeterli noktaya sahip olduğunuzda üretmeyi durdurun Ölçek
Kesişim testi için bir algoritma (C #):
bool PointIsInGeometry(PointCollection points, MapPoint point)
{
int i;
int j = points.Count - 1;
bool output = false;
for (i = 0; i < points.Count; i++)
{
if (points[i].X < point.X && points[j].X >= point.X || points[j].X < point.X && points[i].X >= point.X)
{
if (points[i].Y + (point.X - points[i].X) / (points[j].X - points[i].X) * (points[j].Y - points[i].Y) < point.Y)
{
output = !output;
}
}
j = i;
}
return output;
}
Dışarıda sizin için ağır yüklerin çoğunu yapan iyi kütüphaneler var.
Python'da [düzgün] [1] kullanan örnek.
import random
from shapely.geometry import Polygon, Point
def get_random_point_in_polygon(poly):
minx, miny, maxx, maxy = poly.bounds
while True:
p = Point(random.uniform(minx, maxx), random.uniform(miny, maxy))
if poly.contains(p):
return p
p = Polygon([(0, 0), (0, 2), (1, 1), (2, 2), (2, 0), (1, 1), (0, 0)])
point_in_poly = get_random_point_in_polygon(mypoly)
Veya .representative_point()
nesne içinde bir noktaya ulaşmak için kullanın (dain tarafından belirtildiği gibi):
Geometrik nesnenin içinde olması garanti edilen ucuz bir hesaplanan noktayı döndürür.
poly.representative_point().wkt
'POINT (-1.5000000000000000 0.0000000000000000)'
[1]: https://shapely.readthedocs.io
representative_point
: yöntem shapely.readthedocs.io/en/latest/...
R bir seçenek ?spsample
ise, sp
pakete bakınız . Poligonlar, rgdal paketine yerleştirilmiş herhangi bir GDAL destekli formattan okunabilir ve daha sonra spsample
çeşitli örnekleme seçenekleriyle doğrudan ithal edilen nesnede çalışır.
GIS analizi açısından çok az gerektiren bir çözüm sunmak istiyorum. Özellikle, herhangi bir poligonun üçgenleştirilmesini gerektirmez.
Sözde kodda verilen aşağıdaki algoritma, temel liste işleme yeteneklerine (aralık oluşturma, uzunluk bulma, toplama, sıralama, alt listeleri çıkarma ve birleştirme) ve aralıktaki rasgele kayan noktaların üretilmesine ek olarak bazı basit işlemlere atıfta bulunur: [0, 1):
Area: Return the area of a polygon (0 for an empty polygon).
BoundingBox: Return the bounding box (extent) of a polygon.
Width: Return the width of a rectangle.
Height: Return the height of a rectangle.
Left: Split a rectangle into two halves and return the left half.
Right: ... returning the right half.
Top: ... returning the top half.
Bottom: ... returning the bottom half.
Clip: Clip a polygon to a rectangle.
RandomPoint: Return a random point in a rectangle.
Search: Search a sorted list for a target value. Return the index
of the last element less than the target.
In: Test whether a point is inside a polygon.
Bunların hepsi neredeyse tüm GIS veya grafik programlama ortamlarında mevcuttur (ve değilse kodlaması kolaydır). Clip
yozlaşmış poligonları (yani, sıfır alana sahip olanlar) döndürmemelidir.
Prosedür SimpleRandomSample
verimli bir şekilde bir çokgen içinde rastgele dağıtılan noktaların bir listesini alır. Bunun için bir sarıcı SRS
her parça etkili bir numune için yeterince kompakt kadar küçük parçalar halinde çokgen kırılır. Bunu yapmak için, her bir parçaya kaç nokta tahsis edileceğine karar vermek için önceden hesaplanmış bir rasgele sayı listesi kullanır.
SRS, parametre değiştirilerek "ayarlanabilir" t
. Bu maksimum sınırlayıcı kutudur: tolere edilebilen çokgen alan oranı. Küçültmek (ancak 1'den büyük) çoğu poligonun birçok parçaya bölünmesine neden olur; onu büyütmek, bazı poligonlar için birçok deneme noktasının reddedilmesine neden olabilir (kıvrımlı, şeritlerle veya deliklerle dolu). Bu, orijinal poligonu örneklemek için maksimum sürenin tahmin edilebilir olduğunu garanti eder.
Procedure SimpleRandomSample(P:Polygon, N:Integer) {
U = Sorted list of N independent uniform values between 0 and 1
Return SRS(P, BoundingBox(P), U)
}
Bir sonraki prosedür gerektiğinde kendisini tekrarlı olarak çağırır. Gizemli ifade t*N + 5*Sqrt(t*N)
muhafazakar bir şekilde kaç noktaya ihtiyaç duyulacağına dair bir üst sınır olduğunu tahmin eder, bu da şans değişkenliğini açıklar. Bunun başarısız olacağı olasılığı milyonlarca işlem başına sadece 0.3 puandır. İsterseniz bu olasılığını azaltmak için 5 ila 6, hatta 7'yi artırın.
Procedure SRS(P:Polygon, B:Rectangle, U:List) {
N = Length(U)
If (N == 0) {Return empty list}
aP = Area(P)
If (aP <= 0) {
Error("Cannot sample degenerate polygons.")
Return empty list
}
t = 2
If (aP*t < Area(B)) {
# Cut P into pieces
If (Width(B) > Height(B)) {
B1 = Left(B); B2 = Right(B)
} Else {
B1 = Bottom(B); B2 = Top(B)
}
P1 = Clip(P, B1); P2 = Clip(P, B2)
K = Search(U, Area(P1) / aP)
V = Concatenate( SRS(P1, B1, U[1::K]), SRS(P2, B2, U[K+1::N]) )
} Else {
# Sample P
V = empty list
maxIter = t*N + 5*Sqrt(t*N)
While(Length(V) < N and maxIter > 0) {
Decrement maxIter
Q = RandomPoint(B)
If (Q In P) {Append Q to V}
}
If (Length(V) < N) {
Error("Too many iterations.")
}
}
Return V
}
Poligonunuz dışbükey ise ve tüm köşeleri biliyorsanız, dışbükey kabuğun içinde uzanması garantili yeni bir noktayı örneklemek için köşelerin "rasgele" dışbükey ağırlığını düşünmeyi düşünebilirsiniz (bu durumda çokgen).
Örneğin, köşeli bir N dışbükey poligonunuz var
V_i, i={1,..,N}
Ardından rasgele N dışbükey ağırlıkları oluşturun
w_1,w_2,..,w_N such that ∑ w_i = 1; w_i>=0
Rastgele örneklenmiş nokta daha sonra
Y= ∑ w_i*V_i
N dışbükey ağırlıklarını ölçmenin farklı bir yolu olabilir
Poligonunuz çok fazla dışbükey olmadığında, önce onu dışbükey bir gövdeye dönüştürmeyi düşünebilirsiniz. Bu, en azından çokgeninizin dışında kalan noktaların sayısını büyük ölçüde sınırlamalıdır.
Görevi v.random kullanarak GRASS GIS'de (bir komut) çözmek çok kolaydır .
Seçilen sayfadaki 3 rastgele noktanın nasıl ekleneceğine dair bir örnek aşağıda (Raleigh, NC şehrinin posta kodu alanları) kılavuz sayfasından bulabilirsiniz. SQL "where" deyimini değiştirerek, çokgen (ler) seçilebilir.
Cevap linki
https://gis.stackexchange.com/a/307204/103524
Farklı yaklaşımlar kullanarak üç algoritma.
İşlev =========================================================================== ==================
CREATE OR REPLACE FUNCTION public.I_Grid_Point_Distance(geom public.geometry, x_side decimal, y_side decimal)
RETURNS public.geometry AS $BODY$
DECLARE
x_min decimal;
x_max decimal;
y_max decimal;
x decimal;
y decimal;
returnGeom public.geometry[];
i integer := -1;
srid integer := 4326;
input_srid integer;
BEGIN
CASE st_srid(geom) WHEN 0 THEN
geom := ST_SetSRID(geom, srid);
----RAISE NOTICE 'No SRID Found.';
ELSE
----RAISE NOTICE 'SRID Found.';
END CASE;
input_srid:=st_srid(geom);
geom := st_transform(geom, srid);
x_min := ST_XMin(geom);
x_max := ST_XMax(geom);
y_max := ST_YMax(geom);
y := ST_YMin(geom);
x := x_min;
i := i + 1;
returnGeom[i] := st_setsrid(ST_MakePoint(x, y), srid);
<<yloop>>
LOOP
IF (y > y_max) THEN
EXIT;
END IF;
CASE i WHEN 0 THEN
y := ST_Y(returnGeom[0]);
ELSE
y := ST_Y(ST_Project(st_setsrid(ST_MakePoint(x, y), srid), y_side, radians(0))::geometry);
END CASE;
x := x_min;
<<xloop>>
LOOP
IF (x > x_max) THEN
EXIT;
END IF;
i := i + 1;
returnGeom[i] := st_setsrid(ST_MakePoint(x, y), srid);
x := ST_X(ST_Project(st_setsrid(ST_MakePoint(x, y), srid), x_side, radians(90))::geometry);
END LOOP xloop;
END LOOP yloop;
RETURN
ST_CollectionExtract(st_transform(ST_Intersection(st_collect(returnGeom), geom), input_srid), 1);
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE;
Fonksiyonu basit bir sorgu ile kullanın, geometri geçerli olmalı ve çokgen, çokgenler veya zarf
SELECT I_Grid_Point_Distance(geom, 50, 61) from polygons limit 1;
Sonuç ================================================= =====================
Nicklas Avén algoritmasına dayalı ikinci fonksiyon . Herhangi bir SRID ile işlem yapmaya çalıştınız.
Algoritmada aşağıdaki değişiklikleri uyguladım.
İşlev =========================================================================== ==================
CREATE OR REPLACE FUNCTION I_Grid_Point(geom geometry, x_side decimal, y_side decimal, spheroid boolean default false)
RETURNS SETOF geometry AS $BODY$
DECLARE
x_max decimal;
y_max decimal;
x_min decimal;
y_min decimal;
srid integer := 4326;
input_srid integer;
BEGIN
CASE st_srid(geom) WHEN 0 THEN
geom := ST_SetSRID(geom, srid);
RAISE NOTICE 'SRID Not Found.';
ELSE
RAISE NOTICE 'SRID Found.';
END CASE;
CASE spheroid WHEN false THEN
RAISE NOTICE 'Spheroid False';
srid := 4326;
x_side := x_side / 100000;
y_side := y_side / 100000;
else
srid := 900913;
RAISE NOTICE 'Spheroid True';
END CASE;
input_srid:=st_srid(geom);
geom := st_transform(geom, srid);
x_max := ST_XMax(geom);
y_max := ST_YMax(geom);
x_min := ST_XMin(geom);
y_min := ST_YMin(geom);
RETURN QUERY
WITH res as (SELECT ST_SetSRID(ST_MakePoint(x, y), srid) point FROM
generate_series(x_min, x_max, x_side) as x,
generate_series(y_min, y_max, y_side) as y
WHERE st_intersects(geom, ST_SetSRID(ST_MakePoint(x, y), srid))
) select ST_TRANSFORM(ST_COLLECT(point), input_srid) from res;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE STRICT;
Basit bir sorgu ile kullanın.
SELECT I_Grid_Point(geom, 22, 15, false) from polygons;
Sonuç ================================================= ==================
Fonksiyon ================================================= =================
CREATE OR REPLACE FUNCTION I_Grid_Point_Series(geom geometry, x_side decimal, y_side decimal, spheroid boolean default false)
RETURNS SETOF geometry AS $BODY$
DECLARE
x_max decimal;
y_max decimal;
x_min decimal;
y_min decimal;
srid integer := 4326;
input_srid integer;
x_series DECIMAL;
y_series DECIMAL;
BEGIN
CASE st_srid(geom) WHEN 0 THEN
geom := ST_SetSRID(geom, srid);
RAISE NOTICE 'SRID Not Found.';
ELSE
RAISE NOTICE 'SRID Found.';
END CASE;
CASE spheroid WHEN false THEN
RAISE NOTICE 'Spheroid False';
else
srid := 900913;
RAISE NOTICE 'Spheroid True';
END CASE;
input_srid:=st_srid(geom);
geom := st_transform(geom, srid);
x_max := ST_XMax(geom);
y_max := ST_YMax(geom);
x_min := ST_XMin(geom);
y_min := ST_YMin(geom);
x_series := CEIL ( @( x_max - x_min ) / x_side);
y_series := CEIL ( @( y_max - y_min ) / y_side );
RETURN QUERY
SELECT st_collect(st_setsrid(ST_MakePoint(x * x_side + x_min, y*y_side + y_min), srid)) FROM
generate_series(0, x_series) as x,
generate_series(0, y_series) as y
WHERE st_intersects(st_setsrid(ST_MakePoint(x*x_side + x_min, y*y_side + y_min), srid), geom);
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE STRICT;
Basit bir sorgu ile kullanın.
SELECT I_Grid_Point_Series(geom, 22, 15, false) from polygons;
Sonuç ================================================= =========================