geometry.py

Wed, 28 Jun 2017 16:25:17 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Wed, 28 Jun 2017 16:25:17 +0300
changeset 37
5da3315058a2
parent 19
16fa9fb20b32
child 88
3b86597c5a88
permissions
-rw-r--r--

Kavennettu hieman

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
	@property
	def link_to_map(self):
		return 'http://www.openstreetmap.org/#map=19/%f/%f' % (self.leveys, 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