geometria.py

changeset 5
a65b680f1774
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/geometria.py	Thu May 25 16:41:21 2017 +0300
@@ -0,0 +1,121 @@
+from math import sqrt, hypot, radians, sin, cos, atan2
+
+class Sijainti:
+	def __init__(self, leveys, pituus):
+		self.leveys, self.pituus = leveys, pituus
+	def etäisyys(tämä, toinen):
+		# https://stackoverflow.com/a/365853
+		a = sin(radians(tämä.leveys - toinen.leveys) / 2) ** 2
+		a += sin(radians(tämä.pituus - toinen.pituus) / 2) ** 2 * cos(radians(tämä.leveys)) * cos(radians(toinen.leveys))
+		return 6371 * 2 * atan2(sqrt(a), sqrt(1 - a))
+	def __repr__(self):
+		return '%s(%r, %r)' % (type(self).__name__, self.leveys, self.pituus)
+	def __str__(self):
+		return '%.5f, %.5f' % (self.leveys, self.pituus)
+	@property
+	def x(self):
+		return self.leveys
+	@property
+	def y(self):
+		return self.pituus
+
+class Rengas:
+	def __init__(tämä, säiliö):
+		tämä.säiliö = säiliö
+	def __getitem__(tämä, indeksi):
+		while indeksi < 0:
+			indeksi += len(tämä.säiliö)
+		while indeksi >= len(tämä.säiliö):
+			indeksi -= len(tämä.säiliö)
+		return tämä.säiliö[indeksi]
+	def __iter__(tämä):
+		return iter(tämä.säiliö)
+	def __len__(tämä):
+		return len(tämä.säiliö)
+
+class Monikulmio:
+	def __init__(self, *pisteet):
+		self.pisteet = pisteet
+	def __repr__(self):
+		return '%s(%s)' % (type(self).__name__, ', '.join(map(repr, self.pisteet)))
+	def pinta_ala(self):
+		rengas = Rengas(self.pisteet)
+		return sum(
+			rengas[i].x * rengas[i + 1].y - rengas[i + 1].x * rengas[i].y
+			for i in range(len(rengas))
+		) / 2
+	def piiri(self):
+		rengas = Rengas(self.pisteet)
+		return sum(
+			sqrt((rengas[i + 1].x - rengas[i].x)**2 + (rengas[i + 1].y - rengas[i].y)**2)
+			for i in range(len(rengas))
+		)
+	def painopiste(self):
+		rengas = Rengas(self.pisteet)
+		x = sum(
+			(rengas[i].x + rengas[i + 1].x) * (rengas[i].x * rengas[i + 1].y - rengas[i + 1].x * rengas[i].y)
+			for i in range(len(rengas))
+		) / 6 / self.pinta_ala()
+		y = sum(
+			(rengas[i].y + rengas[i + 1].y) * (rengas[i].x * rengas[i + 1].y - rengas[i + 1].x * rengas[i].y)
+			for i in range(len(rengas))
+		) / 6 / self.pinta_ala()
+		return self.pistetyyppi()(x, y)
+	def pistetyyppi(self):
+		if len(self.pisteet):
+			return type(self.pisteet[0])
+		else:
+			return Piste
+	def piiri_janat(self):
+		rengas = Rengas(self.pisteet)
+		for i in range(len(rengas)):
+			yield Jana(rengas[i], rengas[i + 1])
+	def sisältää_pisteen(self, piste):
+		ulkopiste = self.pistetyyppi()(
+			min(piste.x for piste in self.pisteet) - 1,
+			min(piste.y for piste in self.pisteet) - 1
+		)
+		ulkojana = Jana(piste, ulkopiste)
+		leikkauksia = 0
+		for jana in self.piiri_janat():
+			if jana.leikkauspiste(ulkojana) is not None:
+				leikkauksia += 1
+		return bool(leikkauksia & 1)
+
+class Jana:
+	def __init__(self, alkupiste, päätepiste):
+		self.alkupiste, self.päätepiste = alkupiste, päätepiste
+	def __repr__(self):
+		return 'Jana(%r, %r)' % (self.alkupiste, self.päätepiste)
+	def pituus(self):
+		return hypot(self.alkupiste.x - self.päätepiste.x, self.alkupiste.y - self.päätepiste.y)
+	def leikkauspiste(tämä, toinen):
+		pistetyyppi = type(tämä.alkupiste)
+		x = (tämä.alkupiste.x, tämä.päätepiste.x, toinen.alkupiste.x, toinen.päätepiste.x)
+		y = (tämä.alkupiste.y, tämä.päätepiste.y, toinen.alkupiste.y, toinen.päätepiste.y)
+		try:
+			jakaja = (x[0] - x[1]) * (y[2] - y[3]) - (y[0] - y[1]) * (x[2] - x[3])
+			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
+			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
+			etäisyys = lambda n: (Px - x[n]) ** 2 + (Py - y[n]) ** 2
+			if max(etäisyys(0), etäisyys(1)) <= tämä.pituus() ** 2 and max(etäisyys(2), etäisyys(3)) <= toinen.pituus() ** 2:
+				return pistetyyppi(Px, Py)
+			else:
+				return None
+		except ZeroDivisionError:
+			return None
+
+class Piste:
+	def __init__(self, x, y):
+		self.x, self.y = x, y
+	def __repr__(self):
+		return 'Piste(%r, %r)' % (self.x, self.y)
+
+A = Monikulmio(
+	Piste(2,3),
+	Piste(1,1),
+	Piste(4,0),
+	Piste(6,2),
+	Piste(4,4))
+L1 = Jana(Piste(1, 1), Piste(-1, 5))
+L2 = Jana(Piste(1, 5), Piste(5, 1))

mercurial