sql >> Databasteknik >  >> RDS >> PostgreSQL

Kan jag använda Postgres-funktionerna för att hitta punkter inuti en roterande rektangel med fast storlek?

Det slutade med att jag genererade rektangelhörn, roterade dessa hörn och sedan jämförde arean av rektangeln (konstant) med arean av de 4 trianglarna som skapas genom att inkludera testpunkten.

Den här tekniken är baserad på det sparade svaret :

Rektanglarna definieras av

  • A längst ner till vänster (-x/2,-y/2)

  • B uppe till vänster (-x/2,+y/2)

  • C uppe till höger (+x/2,+y/2)

  • D längst ner till höger (+x/2,-y/2)

Denna kod kontrollerar sedan om punkten (qx,qy) är inuti en rektangel med bredd x=10 och höjd y=20 , som roteras runt origo (0,0) med en vinkel med intervallet 0 till 180, med 10 grader.

Här är koden. Det tar 9 minuter att kontrollera 750 000 poäng, så det finns absolut utrymme för förbättringar. Dessutom kan den parallelliseras när jag uppgraderar till 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
;

resultaten är då

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

Där rotationerna för vinklarna 100, 110, 120, 130 och 140 grader inkluderar testpunkten (anges med * )




  1. SQL:Sammanfoga på två tabeller där kolumnen är null

  2. Hur man ställer in alternativet för autoreconnect med mysql-kontakten c++

  3. mysql fungerar inte för IS NOT NULL

  4. Initcap hoppa över ord som är mindre än 4 tecken