sql >> Database teknologi >  >> RDS >> PostgreSQL

Kan jeg bruge Postgres-funktionerne til at finde punkter inde i et roterende rektangel af fast størrelse?

Jeg endte med at generere rektangulære toppunkter, rotere disse toppunkter og derefter sammenligne arealet af rektanglet (konstanten) med arealet af de 4 trekanter, der er lavet ved at inkludere testpunktet.

Denne teknik er baseret på det sparsomme svar :

Rektanglerne er defineret af

  • A nederst til venstre (-x/2,-y/2)

  • B øverst til venstre (-x/2,+y/2)

  • C øverst til højre (+x/2,+y/2)

  • D nederst til højre (+x/2,-y/2)

Denne kode kontrollerer derefter, om punktet (qx,qy) er inde i et rektangel med bredden x=10 og højde y=20 , som er roteret rundt om origo (0,0) med en vinkel med intervallet 0 til 180, med 10 grader.

Her er koden. Det tager 9 minutter at tjekke 750.000 point, så der er absolut plads til forbedringer. Derudover kan det paralleliseres, når jeg opgraderer til 9.6

with t as (select 10*0.5 as x, 20*0.5 as y, 17.0 as qx, -3.0 as qy)

select 
    z.angle
    -- ABC area
    --,abs(0.5*(z.ax*(z.by-z.cy)+z.bx*(z.cy-z.ay)+z.cx*(z.ay-z.by)))

    -- CDA area
    --,abs(0.5*(z.cx*(z.dy-z.ay)+z.dx*(z.ay-z.cy)+z.ax*(z.cy-z.dy)))

    -- ABCD area
    ,abs(0.5*(z.ax*(z.by-z.cy)+z.bx*(z.cy-z.ay)+z.cx*(z.ay-z.by))) + abs(0.5*(z.cx*(z.dy-z.ay)+z.dx*(z.ay-z.cy)+z.ax*(z.cy-z.dy))) as abcd_area

    -- ABQ area
    --,abs(0.5*(z.ax*(z.by-z.qx)+z.bx*(z.qy-z.ay)+z.qx*(z.ay-z.by)))

    -- BCQ area
    --,abs(0.5*(z.bx*(z.cy-z.qx)+z.cx*(z.qy-z.by)+z.qx*(z.by-z.cy)))

    -- CDQ area
    --,abs(0.5*(z.cx*(z.dy-z.qx)+z.dx*(z.qy-z.cy)+z.qx*(z.cy-z.dy)))

    -- DAQ area
    --,abs(0.5*(z.dx*(z.ay-z.qx)+z.ax*(z.qy-z.dy)+z.qx*(z.dy-z.ay)))

    -- total area of triangles with question point (ABQ + BCQ + CDQ + DAQ)
    ,abs(0.5*(z.ax*(z.by-z.qx)+z.bx*(z.qy-z.ay)+z.qx*(z.ay-z.by)))
        + abs(0.5*(z.bx*(z.cy-z.qx)+z.cx*(z.qy-z.by)+z.qx*(z.by-z.cy)))
        + abs(0.5*(z.cx*(z.dy-z.qx)+z.dx*(z.qy-z.cy)+z.qx*(z.cy-z.dy)))
        + abs(0.5*(z.dx*(z.ay-z.qx)+z.ax*(z.qy-z.dy)+z.qx*(z.dy-z.ay))) as point_area

from
(
SELECT 
    a.id as angle
    -- bottom left (A)
    ,(-t.x) * cos(radians(a.id)) - (-t.y) * sin(radians(a.id)) as ax
    ,(-t.x) * sin(radians(a.id)) + (-t.y) * cos(radians(a.id)) as ay
    --top left (B)
    ,(-t.x) * cos(radians(a.id)) - (t.y) * sin(radians(a.id)) as bx
    ,(-t.x) * sin(radians(a.id)) + (t.y) * cos(radians(a.id)) as by
    --top right (C)
    ,(t.x) * cos(radians(a.id)) - (t.y) * sin(radians(a.id)) as cx
    ,(t.x) * sin(radians(a.id)) + (t.y) * cos(radians(a.id)) as cy
    --bottom right (D)
    ,(t.x) * cos(radians(a.id)) - (-t.y) * sin(radians(a.id)) as dx
    ,(t.x) * sin(radians(a.id)) + (-t.y) * cos(radians(a.id)) as dy

    -- point to check (Q)
    ,t.qx as qx
    ,t.qy as qy
FROM generate_series(0,180,10) AS a(id), t
) z
;

resultaterne er så

angle;abcd_area;point_area
0;200;340
10;200;360.6646055963
20;200;373.409049054212
30;200;377.846096908265
40;200;373.84093170467
50;200;361.515248361426
60;200;341.243556529821
70;200;313.641801308188
80;200;279.548648061772
90;200;240
*100;200;200*
*110;200;200*
*120;200;200*
*130;200;200*
*140;200;200*
150;200;237.846096908265
160;200;277.643408923024
170;200;312.04311584956
180;200;340

Hvor rotationerne af vinklerne 100, 110, 120, 130 og 140 grader så inkluderer testpunktet (angivet med * )




  1. PostgreSQL Trigger efter opdatering af en specifik kolonne

  2. Hvordan indsætter jeg i en tabel fra en anden tabel ved at matche på værdier?

  3. Sletning af rækker med MySQL LEFT JOIN

  4. Laravel Sail genopbygge standarddatabasen