# 四邊形修正邏輯 ## 公式 ![](https://i.imgur.com/VRkqYhc.png =500x) $$ \begin{split} &w為寬,l為長\\ &A,B,C,D為原始輸入座標\\ &A',B',C',D'為修正後座標\\ &I為\triangle ABD重心\\ &J為\triangle BCD重心\\ &L為\square ABCD重心\\\\\\ &\color{#0000ff}{先計算\square ABCD重心}\\ &x_{I}={x_{A}+x_{B}+x_{D} \over 3} \\ &y_{I}={y_{A}+y_{B}+y_{D} \over 3} \\ &x_{J}={x_{B}+x_{C}+x_{D} \over 3} \\ &y_{J}={y_{B}+y_{C}+y_{D} \over 3} \\ &\triangle ABD=\frac{1}{2}[(x_{A}y_{D}+x_{D}y_{B}+x_{B}y_{A})-(x_{D}y_{A}+x_{B}y_{D}+x_{A}y_{B})]\\ &\triangle BCD=\frac{1}{2}[(x_{B}y_{D}+x_{D}y_{C}+x_{C}y_{B})-(x_{D}y_{B}+x_{C}y_{D}+x_{B}y_{C})]\\ &\begin{bmatrix} x_{L}\\y_{L} \end{bmatrix}={\triangle ABD \over \triangle ABD + \triangle BCD}\begin{bmatrix} x_{I}\\y_{I} \end{bmatrix}+{\triangle BCD \over \triangle ABD + \triangle BCD}\begin{bmatrix} x_{J}\\y_{J} \end{bmatrix}\\\\\\ &\color{#0000ff}{接著計算長寬之單位向量\vec{n},\vec{m}}\\ &\vec{AD}=\begin{bmatrix} x_{D}-x_{A}\\y_{D}-y_{A} \end{bmatrix}\\ &\vec{n}=\frac{\vec{AD}}{\overline{AD}}\\ &\vec{m}=\begin{bmatrix} \cos{\theta} & -\sin{\theta} \\ \sin{\theta} & \cos{\theta} \end{bmatrix}\vec{n},\theta=90^\circ可根據傾斜角度做調整\\\\\\ &\color{#0000ff}{最後求得A',B',C',D'}\\ &\begin{bmatrix} x'_{A}\\y'_{A} \end{bmatrix}=\begin{bmatrix} x_{L}\\y_{L} \end{bmatrix}-\frac{w}{2}\vec{n}-\frac{l}{2}\vec{m}\\ &\begin{bmatrix} x'_{B}\\y'_{B} \end{bmatrix}=\begin{bmatrix} x'_{A}\\y'_{A} \end{bmatrix}+l\vec{m}\\ &\begin{bmatrix} x'_{C}\\y'_{C} \end{bmatrix}=\begin{bmatrix} x'_{A}\\y'_{A} \end{bmatrix}+w\vec{n}+l\vec{m}\\ &\begin{bmatrix} x'_{D}\\y'_{D} \end{bmatrix}=\begin{bmatrix} x'_{A}\\y'_{A} \end{bmatrix}+w\vec{n} \end{split} $$ ## SQL程式碼 未用質心算法(會導致車格沒對齊) ```SQL= CREATE OR REPLACE FUNCTION ST_TurnArray(point_A geometry, point_B geometry, point_C geometry,point_D geometry,length double precision,width double precision) RETURNS geometry AS $BODY$ SELECT ST_Polygon(CONCAT('LINESTRING(',ST_X(g.pL)-$5/2*ST_X(g.vM)-$6/2*ST_X(g.vN),' ',ST_Y(g.pL)-$5/2*ST_Y(g.vM)-$6/2*ST_Y(g.vN),',' ,ST_X(g.pL)+$5/2*ST_X(g.vM)-$6/2*ST_X(g.vN),' ',ST_Y(g.pL)+$5/2*ST_Y(g.vM)-$6/2*ST_Y(g.vN),',' ,ST_X(g.pL)+$5/2*ST_X(g.vM)+$6/2*ST_X(g.vN),' ',ST_Y(g.pL)+$5/2*ST_Y(g.vM)+$6/2*ST_Y(g.vN),',' ,ST_X(g.pL)-$5/2*ST_X(g.vM)+$6/2*ST_X(g.vN),' ',ST_Y(g.pL)-$5/2*ST_Y(g.vM)+$6/2*ST_Y(g.vN),',' ,ST_X(g.pL)-$5/2*ST_X(g.vM)-$6/2*ST_X(g.vN),' ',ST_Y(g.pL)-$5/2*ST_Y(g.vM)-$6/2*ST_Y(g.vN),')')::geometry,3826) --以L為中心定義出修正後四邊形位置 FROM(SELECT ST_Centroid(ST_Polygon(CONCAT('LINESTRING(',f.pAx,' ',f.pAy,',',f.pBx,' ',f.pBy,',',f.pCx,' ',f.pCy,',',f.pDx,' ',f.pDy,',',f.pAx,' ',f.pAy,')')::geometry,3826)) AS pL, case when f.dAD>f.dAB then ST_MakePoint((f.pDx-f.pAx)/f.dAD,(f.pDy-f.pAy)/f.dAD) when f.dAD<=f.dAB then ST_MakePoint((f.pBx-f.pAx)/f.dAB,(f.pBy-f.pAy)/f.dAB) END AS vM, case when f.dAB>f.dAD then ST_Rotate(ST_MakePoint((f.pBx-f.pAx)/f.dAB,(f.pBy-f.pAy)/f.dAB),f.r) when f.dAB<=f.dAD then ST_Rotate(ST_MakePoint((f.pDx-f.pAx)/f.dAD,(f.pDy-f.pAy)/f.dAD),f.r) END AS vN FROM(SELECT ST_X($1) AS pAx, ST_Y($1) AS pAy, ST_X($2) AS pBx, ST_Y($2) AS pBy, ST_X($3) AS pCx, ST_Y($3) AS pCy, ST_X($4) AS pDx, ST_Y($4) AS pDy, ST_Distance($1,$4) AS dAD, ST_Distance($1,$2) AS dAB, case when $5 < 0 AND $6 > 0 then pi()/3 when $6 < 0 AND $5 > 0 then pi()*2/3 else pi()/2 END AS r FROM public.pk_mark) AS f) AS g $BODY$ LANGUAGE sql IMMUTABLE; ``` ```SQL= CREATE OR REPLACE FUNCTION pk_mark_fixed() RETURNS trigger AS $$ BEGIN --UPDATE IF (TG_OP = 'UPDATE' AND OLD.* IS DISTINCT FROM NEW.*) THEN NEW.geom = st_turnarray(ST_AsText(ST_PointN(ST_Boundary(NEW.geom),1)), ST_AsText(ST_PointN(ST_Boundary(NEW.geom),2)), ST_AsText(ST_PointN(ST_Boundary(NEW.geom),3)), ST_AsText(ST_PointN(ST_Boundary(NEW.geom),4)), NEW.length, NEW.width); --INSERT ELSEIF(TG_OP = 'INSERT' AND OLD.* is NULL)THEN NEW.geom = st_turnarray(ST_AsText(ST_PointN(ST_Boundary(NEW.geom),1)), ST_AsText(ST_PointN(ST_Boundary(NEW.geom),2)), ST_AsText(ST_PointN(ST_Boundary(NEW.geom),3)), ST_AsText(ST_PointN(ST_Boundary(NEW.geom),4)), NEW.length, NEW.width); END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS pk_mark_fixed_update ON public.pk_mark; CREATE TRIGGER pk_mark_fixed_update BEFORE UPDATE ON public.pk_mark FOR EACH ROW WHEN (OLD.* IS DISTINCT FROM NEW.* AND NEW.length is not NULL AND NEW.width is not NULL AND NEW.length <> 0 AND NEW.width <> 0) EXECUTE PROCEDURE public.pk_mark_fixed(); DROP TRIGGER IF EXISTS pk_mark_fixed_insert ON public.pk_mark; CREATE TRIGGER pk_mark_fixed_insert BEFORE INSERT ON public.pk_mark FOR EACH ROW WHEN (NEW.length is not NULL AND NEW.width is not NULL AND NEW.length <> 0 AND NEW.width <> 0) EXECUTE PROCEDURE public.pk_mark_fixed(); ``` ###### tags: `實習` `SQL`