Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/contributed/sumopy/agilepy/lib_base/geometry.py
169689 views
1
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
2
# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.
3
# SUMOPy module
4
# Copyright (C) 2012-2021 University of Bologna - DICAM
5
# This program and the accompanying materials are made available under the
6
# terms of the Eclipse Public License 2.0 which is available at
7
# https://www.eclipse.org/legal/epl-2.0/
8
# This Source Code may also be made available under the following Secondary
9
# Licenses when the conditions for such availability set forth in the Eclipse
10
# Public License 2.0 are satisfied: GNU General Public License, version 2
11
# or later which is available at
12
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
13
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
14
15
# @file geometry.py
16
# @author Joerg Schweizer
17
# @date 2012
18
19
import numpy as np
20
try:
21
from shapely.geometry import MultiPoint, Polygon, Point, LineString
22
IS_SHAPELY = True
23
except:
24
IS_SHAPELY = False
25
26
27
# >>> from geometry import *
28
# >>> cv = [(0,0),(0,1),(0,2),(0,3),(3,3),(3,0)]
29
# >>> cc = [(0,0),(0,1),(1,1),(1,2),(0,2),(0,3),(3,3),(3,0)]
30
# >>>
31
# >>> p=Point(0.5,2)
32
# >>> policc=Polygon(cc)
33
# >>> policv=Polygon(cv)
34
# >>> is_point_in_polygon(p,cv, is_use_shapely = True)
35
# >>> pc = [0.5,2]
36
# >>> is_point_in_polygon(pc,cv, is_use_shapely = True)
37
# True
38
# >>> is_point_in_polygon(pc,cc, is_use_shapely = True)
39
# False
40
# >>> is_point_in_polygon(pc,cc, is_use_shapely = False)
41
# False
42
# >>> is_point_in_polygon(pc,cv, is_use_shapely = False)
43
# True
44
45
def get_norm_2d(vertex3d):
46
# print 'get_norm_2d',vertex3d.shape
47
return np.sqrt(np.sum(vertex3d[:, :2]**2, 1))
48
# print ' r',r.shape
49
# return r
50
51
52
def get_length_polylines(polylines):
53
# print 'get_length_polylines'
54
# v = np.array([[[0.0,0.0,0.0],[1,0.0,0.0]],[[1,0.0,0.0],[1,2,0.0]],[[1,2.0,0.0],[1,2,3.0]] ])
55
lengths = np.zeros(len(polylines), np.float)
56
i = 0
57
for v in polylines:
58
# print ' v=\n',v,v.shape
59
# print ' v[:,0,:]\n',v[:,0,:]
60
# print ' v[:,1,:]\n',v[:,1,:]
61
lengths[i] = np.sum(np.sqrt(np.sum((v[:, 1, :]-v[:, 0, :])**2, 1)))
62
i += 1
63
return lengths
64
65
66
def get_length_polypoints(polylines):
67
# print 'get_length_polypoints'
68
# v = np.array([[[0.0,0.0,0.0],[1,0.0,0.0]],[[1,0.0,0.0],[1,2,0.0]],[[1,2.0,0.0],[1,2,3.0]] ])
69
lengths = np.zeros(len(polylines), np.float)
70
i = 0
71
for v in polylines:
72
# print ' v=\n',v
73
a = np.array(v, np.float32)
74
# print ' a=\n',a,a.shape
75
lengths[i] = np.sum(np.sqrt(np.sum((a[1:, :]-a[:-1, :])**2, 1)))
76
i += 1
77
return lengths
78
79
80
def polypoints_to_polylines(polypoints):
81
linevertices = np.array([None]*len(polypoints), np.object) # np.zeros((0,2,3),np.float32)
82
#polyinds = []
83
#lineinds = []
84
85
ind = 0
86
ind_line = 0
87
for polyline in polypoints:
88
# Important type conversion!!
89
v = np.zeros((2*len(polyline)-2, 3), np.float32)
90
v[0] = polyline[0]
91
v[-1] = polyline[-1]
92
if len(v) > 2:
93
v[1:-1] = np.repeat(polyline[1:-1], 2, 0)
94
95
#n_lines = len(v)/2
96
#polyinds += n_lines*[ind]
97
# lineinds.append(np.arange(ind_line,ind_line+n_lines))
98
#ind_line += n_lines
99
100
linevertices[ind] = v.reshape((-1, 2, 3))
101
#linevertices = np.concatenate((linevertices, v.reshape((-1,2,3))))
102
103
ind += 1
104
105
return linevertices # , lineinds, polyinds
106
107
108
def get_vec_on_polyline_from_pos(polyline, pos, length, angle=0.0):
109
"""
110
Returns a vector ((x1,y1,z1),(x2,y2,z2))
111
where first coordinate is the point on the polyline at position pos
112
and the second coordinate is length meters ahead with an angle
113
with respect to the direction of the polyline.
114
115
TODO: Attention angle not yet implemented
116
"""
117
pos_edge = 0.0
118
pos_edge_pre = 0.0
119
x1, y1, z1 = polyline[0]
120
121
for j in xrange(1, len(polyline)):
122
x2, y2, z2 = polyline[j]
123
seglength = np.linalg.norm([x2-x1, y2-y1])
124
pos_edge += seglength
125
126
if (pos >= pos_edge_pre) & (pos <= pos_edge):
127
128
dxn = (x2-x1)/seglength
129
dyn = (y2-y1)/seglength
130
u1 = (pos-pos_edge_pre)
131
132
u2 = (pos+length-pos_edge_pre)
133
return np.array([[x1 + u1 * dxn, y1 + u1 * dyn, z2], [x1 + u2 * dxn, y1 + u2 * dyn, z2]], np.float32)
134
135
x1, y1 = x2, y2
136
pos_edge_pre = pos_edge
137
138
x1, y1, z1 = polyline[-1]
139
dxn = (x2-x1)/seglength
140
dyn = (y2-y1)/seglength
141
u1 = (pos-pos_edge_pre)
142
u2 = (pos+length-pos_edge_pre)
143
return np.array([[x2, y2, z2], [x2 + u2 * dxn, y1 + u2 * dyn, z2]], np.float32)
144
145
146
def get_coord_on_polyline_from_pos(polyline, pos):
147
pos_edge = 0.0
148
pos_edge_pre = 0.0
149
x1, y1, z1 = polyline[0]
150
151
for j in xrange(1, len(polyline)):
152
x2, y2, z2 = polyline[j]
153
length = np.linalg.norm([x2-x1, y2-y1])
154
pos_edge += length
155
156
if (pos >= pos_edge_pre) & (pos <= pos_edge):
157
u = (pos-pos_edge_pre)/length
158
x = x1 + u * (x2-x1)
159
y = y1 + u * (y2-y1)
160
return np.array([x, y, z2], np.float32)
161
162
x1, y1 = x2, y2
163
pos_edge_pre = pos_edge
164
165
return np.array([x2, y2, z2], np.float32)
166
167
168
def get_coord_angle_on_polyline_from_pos(polyline, pos):
169
"""
170
Return coordinate and respective angle
171
at position pos on the polygon.
172
"""
173
pos_edge = 0.0
174
pos_edge_pre = 0.0
175
x1, y1, z1 = polyline[0]
176
177
for j in xrange(1, len(polyline)):
178
x2, y2, z2 = polyline[j]
179
length = np.linalg.norm([x2-x1, y2-y1])
180
pos_edge += length
181
182
if (pos >= pos_edge_pre) & (pos <= pos_edge):
183
u = (pos-pos_edge_pre)/length
184
dx = (x2-x1)
185
dy = (y2-y1)
186
x = x1 + u * dx
187
y = y1 + u * dy
188
return np.array([x, y, z2], np.float32), np.arctan2(dy, dx)
189
190
dx = (x2-x1)
191
dy = (y2-y1)
192
x1, y1 = x2, y2
193
pos_edge_pre = pos_edge
194
195
return np.array([x2, y2, z2], np.float32), np.arctan2(dy, dx)
196
197
198
def get_pos_on_polyline_from_coord(polyline, coord):
199
xc, yc, zc = coord
200
n_segs = len(polyline)
201
202
d_min = 10.0**8
203
x_min = 0.0
204
y_min = 0.0
205
j_min = 0
206
p_min = 0.0
207
pos = 0.0
208
x1, y1, z1 = polyline[0]
209
for j in xrange(1, n_segs):
210
x2, y2, z2 = polyline[j]
211
d, xp, yp = shortest_dist(x1, y1, x2, y2, xc, yc)
212
# print ' x1,y1=(%d,%d)'%(x1,y1),',x2,y2=(%d,%d)'%(x2,y2),',xc,yc=(%d,%d)'%(xc,yc)
213
# print ' d,x,y=(%d,%d,%d)'%shortest_dist(x1,y1, x2,y2, xc,yc)
214
if d < d_min:
215
d_min = d
216
# print ' **d_min=',d_min,[xp,yp]
217
x_min = xp
218
y_min = yp
219
j_min = j
220
p_min = pos
221
# print ' pos',pos,[x2-x1,y2-y1],'p_min',p_min
222
pos += np.linalg.norm([x2-x1, y2-y1])
223
x1, y1 = x2, y2
224
225
x1, y1, z1 = polyline[j_min-1]
226
return p_min+np.linalg.norm([x_min-x1, y_min-y1])
227
228
229
def shortest_dist(x1, y1, x2, y2, x3, y3): # x3,y3 is the point
230
"""
231
Shortest distance between point (x3,y3) and line (x1,y1-> x2,y2).
232
Returns distance and projected point on line.
233
"""
234
235
px = x2-x1
236
py = y2-y1
237
238
something = px*px + py*py
239
if something > 0:
240
u = ((x3 - x1) * px + (y3 - y1) * py) / float(something)
241
else:
242
u = 0
243
244
# clip and return infinite distance if not on the line
245
if u > 1:
246
u = 1
247
# return 10.0**8,x1 + px,y1 + py
248
249
elif u < 0:
250
u = 0
251
# return 10.0**8,x1 ,y1
252
253
x = x1 + u * px
254
y = y1 + u * py
255
256
dx = x - x3
257
dy = y - y3
258
259
# Note: If the actual distance does not matter,
260
# if you only want to compare what this function
261
# returns to other results of this function, you
262
# can just return the squared distance instead
263
# (i.e. remove the sqrt) to gain a little performance
264
265
dist = np.sqrt(dx*dx + dy*dy)
266
267
return dist, x, y
268
269
270
def get_dist_point_to_segs(p, y1, x1, y2, x2, is_ending=True,
271
is_detect_initial=False,
272
is_detect_final=False,
273
#is_return_pos = False
274
):
275
"""
276
Minimum square distance between a Point p = (x,y) and a Line segments ,
277
where vectors x1, y1 are the first points and x2,y2 are the second points
278
of the line segments.
279
280
If is_detect_initial is True then a point whose projection is beyond
281
the start of the segment will result in a NaN distance.
282
283
If is_detect_final is True then a point whose projection is beyond
284
the end of the segment will result in a NaN distance.
285
286
If is_return_pos then the position on the section is returned.
287
288
Written by Paul Bourke, October 1988
289
http://astronomy.swin.edu.au/~pbourke/geometry/pointline/
290
291
Rewritten in vectorial form by Joerg Schweizer
292
"""
293
294
y3, x3 = p
295
296
d = np.zeros(len(y1), dtype=np.float32)
297
298
dx21 = (x2-x1)
299
dy21 = (y2-y1)
300
301
lensq21 = dx21*dx21 + dy21*dy21
302
303
# indexvector for all zero length lines
304
iz = (lensq21 == 0)
305
306
dy = y3-y1[iz]
307
dx = x3-x1[iz]
308
309
d[iz] = dx*dx + dy*dy
310
311
lensq21[iz] = 1.0 # replace zeros with 1.0 to avoid div by zero error
312
313
u = (x3-x1)*dx21 + (y3-y1)*dy21
314
u = u / lensq21 # normalize position
315
316
x = x1 + u * dx21
317
y = y1 + u * dy21
318
319
if is_ending:
320
if not is_detect_initial:
321
ie = u < 0
322
x[ie] = x1[ie]
323
y[ie] = y1[ie]
324
325
if not is_detect_final:
326
ie = u > 1
327
x[ie] = x2[ie]
328
y[ie] = y2[ie]
329
330
dx30 = x3-x
331
dy30 = y3-y
332
d[~iz] = (dx30*dx30 + dy30*dy30)[~iz]
333
334
if is_detect_final:
335
d[iz | (u > 1)] = np.nan
336
337
if is_detect_initial:
338
d[iz | (u < 0)] = np.nan
339
340
return d
341
342
343
def is_inside_triangles(p, x1, y1, x2, y2, x3, y3):
344
"""
345
Returns a binary vector with True if point p is
346
inside a triangle.
347
x1,y1,x2,y2,x3,y3 are vectors with the 3 coordiantes of the triangles.
348
"""
349
alpha = ((y2 - y3)*(p[0] - x3) + (x3 - x2)*(p[1] - y3)) \
350
/ ((y2 - y3)*(x1 - x3) + (x3 - x2)*(y1 - y3))
351
352
beta = ((y3 - y1)*(p[0] - x3) + (x1 - x3)*(p[1] - y3)) \
353
/ ((y2 - y3)*(x1 - x3) + (x3 - x2)*(y1 - y3))
354
355
gamma = 1.0 - alpha - beta
356
return (alpha > 0) & (beta > 0) & (gamma > 0)
357
358
# from http://www.arachnoid.com/area_irregular_polygon/index.html
359
360
361
def find_area_perim(array):
362
"""
363
Scalar!
364
"""
365
a = 0
366
p = 0
367
ox, oy = array[0]
368
for x, y in array[1:]:
369
a += (x*oy-y*ox)
370
p += abs((x-ox)+(y-oy)*1j)
371
ox, oy = x, y
372
return a/2, p
373
374
375
def find_area(array, is_use_shapely=True):
376
"""
377
Single polygon with 2D coordinates.
378
"""
379
# TODO: check, there are negative A!!!!
380
# print 'find_area',array
381
if len(array) >= 3:
382
if IS_SHAPELY & is_use_shapely:
383
return Polygon(np.array(array)[:, :2]).area
384
385
else:
386
a = 0
387
ox, oy = array[0]
388
for x, y in array[1:]:
389
a += (x*oy-y*ox)
390
ox, oy = x, y
391
392
# print ' =',np.abs(a/2)
393
return np.abs(a/2)
394
else:
395
return 0.0
396
397
398
def get_polygonarea_fast(x, y):
399
"""
400
Returns area in polygon represented by x,y vectors.
401
Attention: last point is not first point.
402
"""
403
# https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates
404
return 0.5*np.abs(np.dot(x, np.roll(y, 1))-np.dot(y, np.roll(x, 1)))
405
406
407
def is_point_in_polygon(point, poly, is_use_shapely=True):
408
"""
409
Scalar!
410
"""
411
if len(poly) >= 3:
412
if IS_SHAPELY & is_use_shapely:
413
pol = Polygon(np.array(poly)[:, :2])
414
return Point(point[:2]).within(pol)
415
else:
416
is_3d = len(point) == 3
417
418
if is_3d:
419
x, y, z = point
420
p1x, p1y, p1z = poly[0]
421
else:
422
x, y = point
423
p1x, p1y = poly[0]
424
n = len(poly)
425
inside = False
426
427
for i in range(n+1):
428
if is_3d:
429
p2x, p2y, p2z = poly[i % n]
430
else:
431
p2x, p2y = poly[i % n]
432
if y > min(p1y, p2y):
433
if y <= max(p1y, p2y):
434
if x <= max(p1x, p2x):
435
if p1y != p2y:
436
xints = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x
437
if p1x == p2x or x <= xints:
438
inside = not inside
439
p1x, p1y = p2x, p2y
440
441
return inside
442
443
else:
444
return False
445
446
447
def is_polyline_intersect_polygon(polyline, polygon, is_use_shapely=True, is_lineinterpolate=True):
448
if IS_SHAPELY & is_use_shapely:
449
poly = Polygon(np.array(polygon)[:, :2])
450
if is_lineinterpolate:
451
# requires that any line interpolation between 2 points
452
# intersects the polygon
453
return LineString(np.array(polyline)[:, :2]).intersects(poly)
454
else:
455
# requires that at least one point is inside the polygon
456
return MultiPoint(np.array(polyline)[:, :2]).intersects(poly)
457
458
else:
459
# WARNING: this dows not work if no point of the polyline
460
# resides within the polygon
461
for p in polyline:
462
if is_point_in_polygon(p, polygon):
463
return True
464
return False
465
466
467
def is_polyline_in_polygon(polyline, polygon, is_use_shapely=True):
468
if IS_SHAPELY & is_use_shapely:
469
poly = Polygon(np.array(polygon)[:, :2])
470
return MultiPoint(np.array(polyline)[:, :2]).within(poly)
471
472
else:
473
for p in polyline:
474
if not is_point_in_polygon(p, polygon):
475
return False
476
return True
477
478
479
def get_angles_perpendicular(shape):
480
"""
481
Returns the angle vector angles_perb which is perpendicular to the given shape.
482
The normalized
483
dxn = np.cos(angles_perb)
484
dyn = np.sin(angles_perb)
485
"""
486
487
n_vert = len(shape)
488
# print 'get_laneshapes',_id,n_lanes,n_vert
489
490
#width = self.widths_lanes_default[_id]
491
# print ' shape', shape ,len( shape)
492
v_ext_begin = (shape[0]-(shape[1]-shape[0])).reshape(1, 3)
493
v_ext_end = (shape[-1]+(shape[-1]-shape[-2])).reshape(1, 3)
494
495
exshape = np.concatenate((v_ext_begin, shape, v_ext_end))[:, 0:2]
496
# print ' exshape', exshape,len( exshape)
497
vertex_delta_x = exshape[1:, 0]-exshape[0:-1, 0]
498
vertex_delta_y = exshape[1:, 1]-exshape[0:-1, 1]
499
500
angles = np.arctan2(vertex_delta_y, vertex_delta_x)
501
#angles = np.mod(np.arctan2(vertex_delta_y,vertex_delta_x)+2*np.pi,2*np.pi)
502
#angles_perb = 0.5 *(angles[1:]+angles[0:-1])-np.pi/2
503
504
angles1 = angles[1:]
505
angles2 = angles[0:-1]
506
ind_discont = (angles1 < -0.5*np.pi) & ((angles2 > 0.5*np.pi)) | (angles2 < -0.5*np.pi) & ((angles1 > 0.5*np.pi))
507
angle_sum = angles1+angles2
508
angle_sum[ind_discont] += 2*np.pi
509
510
#angles = np.mod(np.arctan2(vertex_delta_y,vertex_delta_x)+2*np.pi,2*np.pi)
511
#angle_sum = angles[1:]+angles[0:-1]
512
#ind_discont = angle_sum>2*np.pi
513
#angle_sum[ind_discont] = angle_sum[ind_discont]-2*np.pi
514
return 0.5*angle_sum-np.pi/2
515
516
517
def rotate_vertices(vec_x, vec_y, alphas=None,
518
sin_alphas=None, cos_alphas=None,
519
is_array=False):
520
"""
521
Rotates all vertices around
522
"""
523
# print 'rotate_vertices',vec_x, vec_y
524
525
if alphas is not None:
526
sin_alphas = np.sin(alphas)
527
cos_alphas = np.cos(alphas)
528
# print ' sin_alphas',sin_alphas
529
# print ' cos_alphas',cos_alphas
530
#deltas = vertices - offsets
531
#vertices_rot = np.zeros(vertices.shape, np.float32)
532
#n= size(vec_x)
533
vec_x_rot = vec_x*cos_alphas - vec_y*sin_alphas
534
vec_y_rot = vec_x*sin_alphas + vec_y*cos_alphas
535
# print ' vec_x_rot',vec_x_rot
536
# print ' vec_y_rot',vec_y_rot
537
if is_array:
538
# print ' concatenate', np.concatenate((vec_x_rot.reshape(-1,1), vec_y_rot.reshape(-1,1)),1)
539
return np.concatenate((vec_x_rot.reshape(-1, 1), vec_y_rot.reshape(-1, 1)), 1)
540
else:
541
return vec_x_rot, vec_y_rot
542
543
544
T = np.array([[0, -1], [1, 0]])
545
546
547
def line_intersect(a1, a2, b1, b2):
548
"""
549
Works for multiple points in each of the input arguments, i.e., a1, a2, b1, b2 can be Nx2 row arrays of 2D points.
550
https://stackoverflow.com/questions/3252194/numpy-and-line-intersections
551
"""
552
da = np.atleast_2d(a2 - a1)
553
db = np.atleast_2d(b2 - b1)
554
dp = np.atleast_2d(a1 - b1)
555
dap = np.dot(da, T)
556
denom = np.sum(dap * db, axis=1)
557
num = np.sum(dap * dp, axis=1)
558
return np.atleast_2d(num / denom).T * db + b1
559
560
561
def line_intersect2(a1, a2, b1, b2):
562
"""
563
Works for multiple points in each of the input arguments, i.e., a1, a2, b1, b2 can be Nx2 row arrays of 2D points.
564
https://stackoverflow.com/questions/3252194/numpy-and-line-intersections
565
Returns also a scale factor which indicates wheter the intersection
566
is in positive or negative direction of the b vector.
567
"""
568
da = np.atleast_2d(a2 - a1)
569
db = np.atleast_2d(b2 - b1)
570
dp = np.atleast_2d(a1 - b1)
571
dap = np.dot(da, T)
572
denom = np.sum(dap * db, axis=1)
573
num = np.sum(dap * dp, axis=1)
574
la = np.atleast_2d(num / denom).T
575
return la * db + b1, la
576
577
578
def get_diff_angle_clockwise(p1, p2):
579
"""
580
Returns the clockwise angle between vector
581
0 -> p1 and 0 -> p2
582
583
p1=np.array([[x11,x11,x13,...],[y11,y12,y13,...]])
584
p2 =np.array([[x21,x21,x23,...],[y21,y22,y23,...]])
585
586
"""
587
ang1 = np.arctan2(*p1[::-1])
588
ang2 = np.arctan2(*p2[::-1])
589
# return np.rad2deg((ang1 - ang2) % (2 * np.pi))
590
if hasattr(ang1, '__iter__'):
591
return anglediffs(ang1, ang2)
592
else:
593
return anglediff(ang1, ang2)
594
################################################################
595
# old
596
597
598
def anglediff(a1, a2):
599
"""Compute the smallest difference between two angle arrays.
600
Parameters
601
----------
602
a1, a2 : np.ndarray
603
The angle arrays to subtract
604
Returns
605
-------
606
out : np.ndarray
607
The difference between a1 and a2
608
"""
609
610
dtheta = a1 - a2
611
while dtheta > np.pi:
612
dtheta -= 2.0*np.pi
613
while dtheta < -np.pi:
614
dtheta += 2.0*np.pi
615
616
return dtheta
617
618
619
def anglediffs(a1, a2, deg=False):
620
"""Compute the smallest difference between two angle arrays.
621
Parameters
622
----------
623
a1, a2 : np.ndarray
624
The angle arrays to subtract
625
deg : bool (default=False)
626
Whether to compute the difference in degrees or radians
627
Returns
628
-------
629
out : np.ndarray
630
The difference between a1 and a2
631
"""
632
print 'anglediffs', a1, a2
633
return wrapanglediffs(a1 - a2, deg=deg)
634
635
636
def wrapanglediffs(diff, deg=False):
637
"""Given an array of angle differences, make sure that they lie
638
between -pi and pi.
639
Parameters
640
----------
641
diff : np.ndarray
642
The angle difference array
643
deg : bool (default=False)
644
Whether the angles are in degrees or radians
645
Returns
646
-------
647
out : np.ndarray
648
The updated angle differences
649
"""
650
651
if deg:
652
base = 360
653
else:
654
base = np.pi * 2
655
656
i = np.abs(diff) > (base / 2.0)
657
out = diff.copy()
658
out[i] -= np.sign(diff[i]) * base
659
return out
660
661
# find indees where 2 arrays are identical
662
#idx = np.argwhere(np.diff(np.sign(f - g)) != 0).reshape(-1) + 0
663
664
665
def azimut_from_origin(p, origin=[0, 0]):
666
# determine the azimut angle relative to a 2D point
667
p = np.array(p) - np.array(origin)
668
if p[0] > 0 and p[1] > 0:
669
return np.arctan(p[0]/p[1])
670
if p[0] > 0 and p[1] < 0:
671
return np.arctan(p[0]/p[1])+np.pi
672
if p[0] < 0 and p[1] < 0:
673
return np.arctan(p[0]/p[1])+np.pi
674
if p[0] < 0 and p[1] > 0:
675
return np.arctan(p[0]/p[1])+2*np.pi
676
677
678
def angle2D(p1, p2):
679
theta1 = math.atan2(p1[1], p1[0])
680
theta2 = math.atan2(p2[1], p2[0])
681
#dtheta = theta2 - theta1;
682
# while dtheta > np.pi:
683
# dtheta -= 2.0*np.pi
684
# while dtheta < -np.pi:
685
# dtheta += 2.0*np.pi
686
return wrapanglediffs(theta2 - theta1)
687
688
689
def is_point_within_polygon(pos, shape):
690
angle = 0.
691
pos = np.array(pos, float)
692
shape = np.array(shape, float)
693
for i in range(0, len(shape)-1):
694
p1 = ((shape[i][0] - pos[0]), (shape[i][1] - pos[1]))
695
p2 = ((shape[i+1][0] - pos[0]), (shape[i+1][1] - pos[1]))
696
angle = angle + angle2D(p1, p2)
697
i = len(shape)-1
698
p1 = ((shape[i][0] - pos[0]), (shape[i][1] - pos[1]))
699
p2 = ((shape[0][0] - pos[0]), (shape[0][1] - pos[1]))
700
angle = angle + angle2D(p1, p2)
701
return math.fabs(angle) >= np.pi
702
703
704
if __name__ == '__main__':
705
a1 = 0.0
706
a2 = +0.1
707
print 'a1', a1/np.pi*180
708
print 'a2', a2/np.pi*180
709
print 'anglediff(a1, a2)', anglediff(a1, a2)/np.pi*180
710
711