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.