虽然我经常使用StackOverflow,但这是我在这里的第一篇帖子:)
我试图在一个给定的点集中找到矩形,只使用函数,避免任何循环。 为了使它更简单,只需要平行于反网格的矩形
我的问题是,有没有办法减少条件,以确定四个点是否是函数形式的矩形(参见函数get_rectangles())
itertools.composition()需要很多时间
这是我创建的,有一个main()要测试:
import itertools as it
from functools import *
###function to obtain the square distance given two points
def distancia2(point1, point2):
return ((point1[0] - point2[0])**2 + (point1[1] - point2[1])**2)
###function that returns the 6 possible square distances between four points sorted
def distancias(four_points):
u1 = distancia2(four_points[0], four_points[1])
u2 = distancia2(four_points[2], four_points[1])
u3 = distancia2(four_points[2], four_points[3])
u4 = distancia2(four_points[3], four_points[0])
u5 = distancia2(four_points[0], four_points[2])
u6 = distancia2(four_points[1], four_points[3])
return sorted([u1, u2, u3, u4, u5, u6])
#condition for being a rectangle (grid oriented)
## lista is in the way of tupple of tupples
## i.e. lista = ((4,1),(5,1),(4,8),(5,8))
## return True if the four points can form a rectangle
def esrectangulo(lista):
#CONDITION 1
## is parallel to the grid, so only two values of x and
## two values of y are required for define the four points
## dos_valoresX is the unic x values in the points == 2
##
## ( reduce(lambda ac, list: ac + [list[0]] if not list[0] in ac else ac,lista,[]) )
## ( here reduce is used to make a list of unic values in the list )
dos_valoresX = len(reduce(lambda ac, list: ac + [list[0]] if not list[0] in ac else ac,
lista,
[])) == 2
dos_valoresY = len(reduce(lambda ac, list: ac + [list[1]] if not list[1] in ac else ac,
lista,
[])) == 2
cond_oriented = dos_valoresX and dos_valoresY
#CONDITION 2
## There should be only three different distances in the six possible distances between points
## or 2 in square case
seis_distancias = distancias(lista)
dist_distintas = reduce(lambda xs , alist: xs + [alist] if not alist in xs else xs ,seis_distancias,[])
solo_hay_tresodos = len(dist_distintas) == 3 or len(dist_distintas) == 2
#CONDITION 3
## The longest distance has to be equal to Pitagoras theorem using
## other distances
pitagoras = (seis_distancias[5] == seis_distancias[1] + seis_distancias[3])
return True if solo_hay_tresodos and pitagoras and cond_oriented else False
# Function returns the list of points to form rectangles in the list points
# point list is an aray of points tuples
# [(x1,y1),(x2,y2),(x3,y3)...]
def get_rectangles(pnts):
# first, we filter the unic points
points = list(reduce(lambda ac, p: ac + [p] if not p in ac else ac, pnts, []))
# vertical and horizontal lines which contain more than one point
# they are the possible rectangle points
rectas_verticales = list(filter(lambda x: True if [p[0] for p in points].count(x) > 1 else False,
reduce(lambda ac, list: ac + [list[0]] if not list[0] in ac else ac,
points,
[])))
rectas_horizontales = list(filter(lambda x: True if [p[1] for p in points].count(x) > 1 else False,
reduce(lambda ac, list: ac + [list[1]] if not list[1] in ac else ac,
points,
[])))
# filter all the points in these lines
# puntos_inter = interested points
def in_some_line(p):
return True if p[0] in rectas_verticales and p[1] in rectas_horizontales else False
puntos_inter = list(filter(in_some_line ,points))
# rectangulos is an array of groups of four points which are rectangles on the grid
# it.combinations(puntos_inter,4) creates all posible combinations of four points in puntos_iter
# itertools library
rectangulos = list(filter(esrectangulo,it.combinations(puntos_inter,4)))
#return and ortogonal h. and v. lines
return rectangulos, rectas_horizontales, rectas_verticales
# FOR TESTIING
def main():
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import operator
import random
#GENERATION OF RANDOM POINTS
tam, n = 30, 100
random_points = [(random.randint(1, tam), random.randint(1, tam)) for x in range(n)]
print('points: ', random_points)
[rectangles, hor_lines, ver_lines] = get_rectangles(random_points)
print('rectangles: ', rectangles)
#we can make a small plot with matplotlib for representation
def random_color():
rgbl = [random.random() for x in range(3)]
return tuple(rgbl)
fig, ax = plt.subplots()
for i in range(0, len(rectangles)):
rectangle = sorted(rectangles[i],key= operator.itemgetter(1,0))
rectangle[2], rectangle[3] = rectangle[3], rectangle[2]
print(rectangle)
ax.add_patch(mpatches.Polygon(rectangle, alpha=0.7, facecolor= 'None', edgecolor=random_color(),linewidth=2.))
plt.scatter(x=list(map(lambda l: l[0],random_points)),y=list(map(lambda l: l[1],random_points)), s=10.,marker='o',c='k',alpha=0.3)
plt.show()
if __name__ == "__main__":
main()
目前没有回答
相关问题 更多 >
编程相关推荐