|
1 from math import sqrt, hypot, radians, sin, cos, atan2 |
|
2 |
|
3 class Sijainti: |
|
4 def __init__(self, leveys, pituus): |
|
5 self.leveys, self.pituus = leveys, pituus |
|
6 def etäisyys(tämä, toinen): |
|
7 # https://stackoverflow.com/a/365853 |
|
8 a = sin(radians(tämä.leveys - toinen.leveys) / 2) ** 2 |
|
9 a += sin(radians(tämä.pituus - toinen.pituus) / 2) ** 2 * cos(radians(tämä.leveys)) * cos(radians(toinen.leveys)) |
|
10 return 6371 * 2 * atan2(sqrt(a), sqrt(1 - a)) |
|
11 def __repr__(self): |
|
12 return '%s(%r, %r)' % (type(self).__name__, self.leveys, self.pituus) |
|
13 def __str__(self): |
|
14 return '%.5f, %.5f' % (self.leveys, self.pituus) |
|
15 @property |
|
16 def x(self): |
|
17 return self.leveys |
|
18 @property |
|
19 def y(self): |
|
20 return self.pituus |
|
21 |
|
22 class Rengas: |
|
23 def __init__(tämä, säiliö): |
|
24 tämä.säiliö = säiliö |
|
25 def __getitem__(tämä, indeksi): |
|
26 while indeksi < 0: |
|
27 indeksi += len(tämä.säiliö) |
|
28 while indeksi >= len(tämä.säiliö): |
|
29 indeksi -= len(tämä.säiliö) |
|
30 return tämä.säiliö[indeksi] |
|
31 def __iter__(tämä): |
|
32 return iter(tämä.säiliö) |
|
33 def __len__(tämä): |
|
34 return len(tämä.säiliö) |
|
35 |
|
36 class Monikulmio: |
|
37 def __init__(self, *pisteet): |
|
38 self.pisteet = pisteet |
|
39 def __repr__(self): |
|
40 return '%s(%s)' % (type(self).__name__, ', '.join(map(repr, self.pisteet))) |
|
41 def pinta_ala(self): |
|
42 rengas = Rengas(self.pisteet) |
|
43 return sum( |
|
44 rengas[i].x * rengas[i + 1].y - rengas[i + 1].x * rengas[i].y |
|
45 for i in range(len(rengas)) |
|
46 ) / 2 |
|
47 def piiri(self): |
|
48 rengas = Rengas(self.pisteet) |
|
49 return sum( |
|
50 sqrt((rengas[i + 1].x - rengas[i].x)**2 + (rengas[i + 1].y - rengas[i].y)**2) |
|
51 for i in range(len(rengas)) |
|
52 ) |
|
53 def painopiste(self): |
|
54 rengas = Rengas(self.pisteet) |
|
55 x = sum( |
|
56 (rengas[i].x + rengas[i + 1].x) * (rengas[i].x * rengas[i + 1].y - rengas[i + 1].x * rengas[i].y) |
|
57 for i in range(len(rengas)) |
|
58 ) / 6 / self.pinta_ala() |
|
59 y = sum( |
|
60 (rengas[i].y + rengas[i + 1].y) * (rengas[i].x * rengas[i + 1].y - rengas[i + 1].x * rengas[i].y) |
|
61 for i in range(len(rengas)) |
|
62 ) / 6 / self.pinta_ala() |
|
63 return self.pistetyyppi()(x, y) |
|
64 def pistetyyppi(self): |
|
65 if len(self.pisteet): |
|
66 return type(self.pisteet[0]) |
|
67 else: |
|
68 return Piste |
|
69 def piiri_janat(self): |
|
70 rengas = Rengas(self.pisteet) |
|
71 for i in range(len(rengas)): |
|
72 yield Jana(rengas[i], rengas[i + 1]) |
|
73 def sisältää_pisteen(self, piste): |
|
74 ulkopiste = self.pistetyyppi()( |
|
75 min(piste.x for piste in self.pisteet) - 1, |
|
76 min(piste.y for piste in self.pisteet) - 1 |
|
77 ) |
|
78 ulkojana = Jana(piste, ulkopiste) |
|
79 leikkauksia = 0 |
|
80 for jana in self.piiri_janat(): |
|
81 if jana.leikkauspiste(ulkojana) is not None: |
|
82 leikkauksia += 1 |
|
83 return bool(leikkauksia & 1) |
|
84 |
|
85 class Jana: |
|
86 def __init__(self, alkupiste, päätepiste): |
|
87 self.alkupiste, self.päätepiste = alkupiste, päätepiste |
|
88 def __repr__(self): |
|
89 return 'Jana(%r, %r)' % (self.alkupiste, self.päätepiste) |
|
90 def pituus(self): |
|
91 return hypot(self.alkupiste.x - self.päätepiste.x, self.alkupiste.y - self.päätepiste.y) |
|
92 def leikkauspiste(tämä, toinen): |
|
93 pistetyyppi = type(tämä.alkupiste) |
|
94 x = (tämä.alkupiste.x, tämä.päätepiste.x, toinen.alkupiste.x, toinen.päätepiste.x) |
|
95 y = (tämä.alkupiste.y, tämä.päätepiste.y, toinen.alkupiste.y, toinen.päätepiste.y) |
|
96 try: |
|
97 jakaja = (x[0] - x[1]) * (y[2] - y[3]) - (y[0] - y[1]) * (x[2] - x[3]) |
|
98 Px = ((x[0] * y[1] - y[0] * x[1]) * (x[2] - x[3]) - (x[0] - x[1]) * (x[2] * y[3] - y[2] * x[3])) / jakaja |
|
99 Py = ((x[0] * y[1] - y[0] * x[1]) * (y[2] - y[3]) - (y[0] - y[1]) * (x[2] * y[3] - y[2] * x[3])) / jakaja |
|
100 etäisyys = lambda n: (Px - x[n]) ** 2 + (Py - y[n]) ** 2 |
|
101 if max(etäisyys(0), etäisyys(1)) <= tämä.pituus() ** 2 and max(etäisyys(2), etäisyys(3)) <= toinen.pituus() ** 2: |
|
102 return pistetyyppi(Px, Py) |
|
103 else: |
|
104 return None |
|
105 except ZeroDivisionError: |
|
106 return None |
|
107 |
|
108 class Piste: |
|
109 def __init__(self, x, y): |
|
110 self.x, self.y = x, y |
|
111 def __repr__(self): |
|
112 return 'Piste(%r, %r)' % (self.x, self.y) |
|
113 |
|
114 A = Monikulmio( |
|
115 Piste(2,3), |
|
116 Piste(1,1), |
|
117 Piste(4,0), |
|
118 Piste(6,2), |
|
119 Piste(4,4)) |
|
120 L1 = Jana(Piste(1, 1), Piste(-1, 5)) |
|
121 L2 = Jana(Piste(1, 5), Piste(5, 1)) |