delphi 判断点在多边形内

  1 unit MainFM;
  2 
  3 interface
  4 
  5 uses
  6   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  7   Vcl.Controls, Vcl.Forms, Vcl.Dialogs,utils_dvalue, utils_DValue_JSON, math;
  8 
  9 type
 10   PPos = ^TPos;
 11   TPos = record
 12     x: double;
 13     y: double;
 14   end;
 15   TForm1 = class(TForm)
 16     procedure FormCreate(Sender: TObject);
 17     procedure FormDestroy(Sender: TObject);
 18   private
 19     { Private declarations }
 20     FInfo: TDValue;
 21     min_x, min_y, max_x, max_y: Double;
 22     function in_line(p, a, b: TPos):boolean;
 23     function in_scope(x, y: double):boolean;
 24     function js_scope(x, y: double):boolean;
 25     function get_angle(a, p, b: TPos): Double;
 26     function angle_scope(x, y: double):Boolean;
 27   public
 28     { Public declarations }
 29   end;
 30 
 31 var
 32   Form1: TForm1;
 33 
 34 implementation
 35 
 36 {$R *.dfm}
 37 
 38 const
 39    AREA_JS = '[{"x":25.050192,"y":102.685862},{"x":25.048684,"y":102.679662},{"x":25.046881,"y":102.6795},{"x":25.046794,"y":102.679432},{"x":25.045442,"y":102.679317},{"x":25.045053,"y":102.679703},' +
 40           '{"x":25.044956,"y":102.680877},{"x":25.044077,"y":102.680803},{"x":25.04405,"y":102.68082},{"x":25.043932,"y":102.680812},{"x":25.042992,"y":102.681473},{"x":25.042543,"y":102.680512},' +
 41           '{"x":25.040577,"y":102.680628},{"x":25.040201,"y":102.680619},{"x":25.040199,"y":102.680616},{"x":25.038735,"y":102.680584},{"x":25.038131,"y":102.679581},{"x":25.036289,"y":102.68087},' +
 42           '{"x":25.035543,"y":102.680316},{"x":25.032567,"y":102.682154},{"x":25.030944,"y":102.679494},{"x":25.030683,"y":102.679922},{"x":25.02918,"y":102.678526},{"x":25.020929,"y":102.691384},' +
 43           '{"x":25.018434,"y":102.695194},{"x":25.018199,"y":102.695462},{"x":25.018154,"y":102.695623},{"x":25.014317,"y":102.701847},{"x":25.014257,"y":102.701777},{"x":25.014214,"y":102.701799},' +
 44           '{"x":25.014193,"y":102.701833},{"x":25.013665,"y":102.703895},{"x":25.0135,"y":102.708667},{"x":25.013731,"y":102.711444},{"x":25.013688,"y":102.711598},{"x":25.014635,"y":102.728022},' +
 45           '{"x":25.017457,"y":102.727245},{"x":25.017227,"y":102.727632},{"x":25.017398,"y":102.730491},{"x":25.017994,"y":102.731972},{"x":25.019514,"y":102.734679},{"x":25.019822,"y":102.736062},' +
 46           '{"x":25.021592,"y":102.734747},{"x":25.022972,"y":102.736725},{"x":25.024394,"y":102.739288},{"x":25.025337,"y":102.739351},{"x":25.02553,"y":102.741181},{"x":25.027447,"y":102.741482},' +
 47           '{"x":25.027511,"y":102.740923},{"x":25.027796,"y":102.741078},{"x":25.029644,"y":102.737365},{"x":25.032853,"y":102.737421},{"x":25.032824,"y":102.743083},{"x":25.034417,"y":102.743137},' +
 48           '{"x":25.035607,"y":102.743816},{"x":25.036682,"y":102.741746},{"x":25.038471,"y":102.743515},{"x":25.040554,"y":102.744645},{"x":25.041723,"y":102.744501},{"x":25.042272,"y":102.743377},' +
 49           '{"x":25.041406,"y":102.741458},{"x":25.041972,"y":102.740368},{"x":25.043552,"y":102.739007},{"x":25.044843,"y":102.737357},{"x":25.045317,"y":102.737367},{"x":25.045394,"y":102.737643},' +
 50           '{"x":25.046456,"y":102.737673},{"x":25.046487,"y":102.736363},{"x":25.047268,"y":102.736121},{"x":25.048442,"y":102.736882},{"x":25.049793,"y":102.735303},{"x":25.049454,"y":102.734985},' +
 51           '{"x":25.049949,"y":102.734738},{"x":25.050208,"y":102.73392},{"x":25.049452,"y":102.732817},{"x":25.050428,"y":102.731672},{"x":25.051611,"y":102.730455},{"x":25.052832,"y":102.731477},' +
 52           '{"x":25.053183,"y":102.730854},{"x":25.055187,"y":102.728466},{"x":25.055845,"y":102.729135},{"x":25.057024,"y":102.727607},{"x":25.057807,"y":102.726003},{"x":25.059392,"y":102.720135},' +
 53           '{"x":25.059951,"y":102.72017},{"x":25.062027,"y":102.721034},{"x":25.062385,"y":102.72006},{"x":25.063003,"y":102.720215},{"x":25.063863,"y":102.717103},{"x":25.062979,"y":102.716844},' +
 54           '{"x":25.063065,"y":102.715942},{"x":25.062657,"y":102.715496},{"x":25.062696,"y":102.715054},{"x":25.062367,"y":102.714957},{"x":25.062725,"y":102.713192},{"x":25.061683,"y":102.713097},' +
 55           '{"x":25.061665,"y":102.712598},{"x":25.060553,"y":102.712448},{"x":25.060689,"y":102.710459},{"x":25.061079,"y":102.708519},{"x":25.061649,"y":102.707398},{"x":25.06164,"y":102.706604},' +
 56           '{"x":25.060134,"y":102.706413},{"x":25.060187,"y":102.704655},{"x":25.06047,"y":102.704099},{"x":25.060271,"y":102.702606},{"x":25.061233,"y":102.702174},{"x":25.062926,"y":102.702057},' +
 57           '{"x":25.063063,"y":102.700747},{"x":25.062848,"y":102.698117},{"x":25.062557,"y":102.698149},{"x":25.062526,"y":102.697755},{"x":25.062375,"y":102.697764},{"x":25.062467,"y":102.697104},' +
 58           '{"x":25.062128,"y":102.696998},{"x":25.062086,"y":102.696072},{"x":25.060061,"y":102.696191},{"x":25.05891,"y":102.695299},{"x":25.058661,"y":102.694585},{"x":25.058814,"y":102.693901},' +
 59           '{"x":25.059055,"y":102.69348},{"x":25.059847,"y":102.692906},{"x":25.05932,"y":102.691352},{"x":25.059009,"y":102.69107},{"x":25.058361,"y":102.691324},{"x":25.058288,"y":102.692227},' +
 60           '{"x":25.058544,"y":102.69323},{"x":25.057257,"y":102.693822},{"x":25.055803,"y":102.694269},{"x":25.053974,"y":102.6905},{"x":25.053752,"y":102.690326},{"x":25.053012,"y":102.690614},' +
 61           '{"x":25.052192,"y":102.690245},{"x":25.052909,"y":102.687701},{"x":25.052385,"y":102.685977},{"x":25.051531,"y":102.686171},{"x":25.051377,"y":102.686717},{"x":25.050672,"y":102.686137},' +
 62           '{"x":25.050192,"y":102.685862}]';
 63 
 64 procedure TForm1.FormCreate(Sender: TObject);
 65 var
 66   i: Integer;
 67   x, y: double;
 68 begin
 69   FInfo := TDValue.Create(vntArray);
 70   JSONParser(AREA_JS, FInfo);
 71   //计算最大最小值
 72   min_x := FInfo.Items[0].ForceByName('x').AsFloat;
 73   min_y := FInfo.Items[0].ForceByName('y').AsFloat;
 74   max_x := min_x; max_y := min_y;
 75   for i := 1 to FInfo.Count - 1 do
 76   begin
 77     x := FInfo.Items[i].ForceByName('x').AsFloat;
 78     y := FInfo.Items[i].ForceByName('y').AsFloat;
 79     if min_x > x then min_x := x;
 80     if min_y > y then min_y := y;
 81     if max_x < x then max_x := x;
 82     if max_y < y then max_y := y;
 83   end;
 84   x := 25.035571963033; y := 102.71040295303;
 85   x := 25.06574; y := 102.69685;
 86   x := 25.032819; y:= 102.744553;
 87   if in_scope(x,y) then showmessage('在区域内')
 88   else showmessage('不在区域内');
 89 end;
 90 
 91 procedure TForm1.FormDestroy(Sender: TObject);
 92 begin
 93   FInfo.Free;
 94 end;
 95 
 96 function TForm1.in_line(p, a, b: TPos):Boolean;
 97 var
 98   minx,miny,maxx, maxy, a1, a2, tmp: double;
 99 begin
100     minx := a.x; if minx > b.x then minx := b.x;
101     miny := a.y; if miny > b.y then miny := b.y;
102     maxx := a.x; if maxx < b.x then maxx := b.x;
103     maxy := a.y; if maxy < b.y then maxy := b.y;
104     if (p.x >= minx) and (p.y >= miny) and (p.x <= maxx) and (p.y <= maxy) then
105     begin
106        a1 := (a.x - p.x)*(b.y - p.y);
107        a2 := (b.x - p.x)*(a.y - p.y);
108        tmp := a1 - a2;
109        if tmp < 0 then tmp := a2 - a1;
110        Result := tmp < 0.0001;
111     end else begin
112       Result := false;
113     end;
114 end;
115 
116 function TForm1.get_angle(a, p, b: TPos): Double;
117 var
118   pa, pb, ab, apb: Double;
119 begin
120   pa := (a.x - p.x)*(a.x - p.x) + (a.y - p.y)* (a.y - p.y);
121   pb := (b.x - p.x)*(b.x - p.x) + (b.y - p.y)* (b.y - p.y);
122   ab := (b.x - a.x)*(b.x - a.x) + (b.y - a.y)* (b.y - a.y);
123 
124   apb := pa + pb - ab;
125 
126   pa := sqrt(pa);
127   pb := sqrt(pb);
128   apb := apb / (2 * pa * pb);
129   REsult := ArcCos(apb);
130 end;
131 
132 function TForm1.angle_scope(x, y: double):Boolean;
133 var
134   i,k: Integer;
135   d1, d2: TDValue;
136   p, p1, p2: TPos;
137   angle: double;
138 begin
139   k := 1000;
140   p.x := x * k;
141   p.y := y * k;
142   for i := 0 to FInfo.Count - 1 do
143   begin
144     d1 := FInfo.Items[i];
145     d2 := FInfo.Items[(i + 1) mod FInfo.Count];
146     p1.x := d1.ForceByName('x').AsFloat * k;
147     p1.y := d1.ForceByName('y').AsFloat * k;
148     p2.x := d2.ForceByName('x').AsFloat * k;
149     p2.y := d2.ForceByName('y').AsFloat * k;
150     if in_line(p, p1, p2) then
151     begin
152       Result := True;
153       exit;
154     end;
155     angle := angle + get_angle(p1, p, p2);
156   end;
157   angle := angle - PI * 2;
158   if angle < 0 then angle := -1 * angle;
159   Result := angle < 0.0001;
160 end;
161 
162 function TForm1.in_scope(x, y: double):boolean;
163 var
164   i,cross: Integer;
165   d1, d2: TDValue;
166   p, p1, p2: TPos;
167   y1, y2, tmp, tmpx: double;
168 begin
169   cross := 0;
170   p.x := x;
171   p.y := y;
172   for i := 0 to FInfo.Count - 1 do
173   begin
174     d1 := FInfo.Items[i];
175     d2 := FInfo.Items[(i + 1) mod FInfo.Count];
176     p1.x := d1.ForceByName('x').AsFloat;  p1.y := d1.ForceByName('y').AsFloat;
177     p2.x := d2.ForceByName('x').AsFloat;  p2.y := d2.ForceByName('y').AsFloat;
178 
179     if in_line(p, p1, p2) then
180     begin
181       cross := 1;
182       break;
183     end;
184     if p1.y = p2.y then continue;
185     y1 := p1.y;
186     y2 := p2.y;
187     if y1 > y2 then
188     begin
189       y1 := p2.y;
190       y2 := p1.y;
191     end;
192     if p.y < y1 then continue;
193     if p.y > y2 then continue;
194 
195     tmpx := (p.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;
196     (*
197     tmp := p.x - tmpx;
198     if tmp < 0 then tmp := tmpx - p.x;
199     if tmp < 0.0001 then
200     begin
201       cross := 1;
202       break;
203     end;
204     tmp := p1.y - p.y;
205     if tmp < 0 then tmp := p.y - p1.y;
206     if tmp < 0.0001 then
207     begin
208         if( (min_y = p1.y) or (max_y = p1.y) ) and (p.x< p1.x ) then
209         begin
210           cross := 0;
211           break;
212         end;
213         continue;
214     end;
215     *)
216     if(tmpx > p.x) then cross := cross + 1;
217   end; // end of for
218   Result := (cross mod 2) = 1
219 end;
220 
221 function TForm1.js_scope(x, y: double):boolean;
222 var
223   i,j: Integer;
224   d1,d2: TDValue;
225   xi,yi,xj,yj: Single;
226 begin
227   Result := False;
228   j := FInfo.Count - 1;
229   for i := 0 to FInfo.Count - 1 do
230   begin
231     d1 := FInfo.Items[i];
232     d2 := FInfo.Items[j];
233     j := i;
234     xi := d1.ForceByName('x').AsFloat;
235     yi := d1.ForceByName('y').AsFloat;
236     xj := d2.ForceByName('x').AsFloat;
237     yj := d2.ForceByName('y').AsFloat;
238     if( (yi > y) <> (yj > y) ) and ( x < ((xj - xi) * (y - yi) / (yj - yi) + xi) ) then
239       Result := not Result;
240   end;
241 end;
242 
243 end.

 

posted @ 2020-05-30 14:56  伯通心智  阅读(360)  评论(1编辑  收藏  举报