(Python) Скрипт, чтобы определить, являются ли (x, y) координаты коллинеарными - получение некоторых ошибок - PullRequest
1 голос
/ 07 марта 2012

как написано в заголовке, я пытаюсь написать программу, которая принимает список (x, y) координат и определяет, коллинеарны ли какие-либо 3 точки (лежат на линии с тем же наклоном)

Я получаю несколько сообщений об ошибках. В существующем состоянии я получаю сообщение «TypeError: объект int не подписан». Если я уберу часть, где collinearityTest вызывает функцию areCollinear, я получу ошибку «index out of range». Я новичок в Python, и просто пытаюсь учиться.

def areCollinear(p1, p2, p3):
    slope1 = (p2[1] - p1[1]) / (p2[0] - p1[0])
    slope2 = (p3[1] - p2[1]) / (p3[0] - p2[0])
    if slope1 == slope2:
        print "Points are colinear"
    else:
        print "Points are NOT colinear, what's the matter with you?"

def collinearityTest(pointList):
    position = 0
    while position >=0 and position < len(pointList):

        for p1 in pointList[position]:
            position = position + 1
            for p2 in pointList[position]:
                position = position + 1
                for p3 in pointList[position]:
                    position = position + 1
                    areCollinear(p1, p2, p3)

pointList = [(10, 20), (55, 18), (10, -45.5), (90, 34), (-34, -67), (10, 99)]

collinearityTest(pointList)

СООБЩЕНИЕ ОБ ОШИБКЕ:

Traceback (most recent call last):
  File "C:\Program Files (x86)\Wing IDE 101 4.1\src\debug\tserver\_sandbox.py", line 23, in <module>
  File "C:\Program Files (x86)\Wing IDE 101 4.1\src\debug\tserver\_sandbox.py", line 19, in collinearityTest
  File "C:\Program Files (x86)\Wing IDE 101 4.1\src\debug\tserver\_sandbox.py", line 2, in areCollinear
    if __name__ == '__main__':
TypeError: 'int' object is not subscriptable

Ответы [ 6 ]

7 голосов
/ 08 марта 2012

Вот более простая и численно более надежная и стабильная функция для проверки коллинеарности трех точек:

def collinear(p0, p1, p2):
    x1, y1 = p1[0] - p0[0], p1[1] - p0[1]
    x2, y2 = p2[0] - p0[0], p2[1] - p0[1]
    return abs(x1 * y2 - x2 * y1) < 1e-12

(Обратите внимание, что было бы лучше не жестко кодировать эпсилон, а делать его относительно длины векторов.)

4 голосов
/ 08 марта 2012

Ошибка

Основная ошибка в том, что вы пытаетесь получить доступ к части int объекта, но это невозможно. Вы можете воспроизвести похожую ошибку следующим образом:

>>> p1 = 1
>>> p1[1]
Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    p1[1]
TypeError: 'int' object is not subscriptable

Другие проблемы

У вас несколько проблем с вашим кодом, особенно две из них:

  1. Деления (вы не используете Python 3.x, поэтому / работает не так, как вы хотите, например, верно следующее: 3/2==1 - вы должны использовать деления, включающие float s или хотя бы используйте from __future__ import division),
  2. Три уровня циклов - это плохая идея из-за сложности, просто используйте itertools.combinations вместо.

Каркас для улучшений

Вы должны просто сделать что-то вроде:

import itertools

for x, y, z in itertools.combinations(pointList, 3):
    # Check if x, y and z lie on the same line,
    # where x, y and z are tuples with two elements each.
    # And remember to use floats in divisions
    # (eg. `slope1 = float(p2[1] - p1[1]) / (p2[0] - p1[0])`)
    pass
2 голосов
/ 08 марта 2012

Ваш код может быть намного чище:

import itertools

def arecolinear(points):
    xdiff1 = float(points[1][0] - points[0][0])
    ydiff1 = float(points[1][1] - points[0][1])
    xdiff2 = float(points[2][0] - points[1][0])
    ydiff2 = float(points[2][1] - points[1][1])

    # infinite slope?
    if xdiff1 == 0 or xdiff2 == 0:
        return xdiff1 == xdiff2
    elif ydiff1/xdiff1 == ydiff2/xdiff2:
        return True
    else:
        return False

pointlist = [(10, 20), (55, 18), (10, -45.5), (90, 34), (-34, -67), (10, 99)]

for points in itertools.combinations(pointlist, 3):
    if arecolinear(points):
        print("Points are colinear")
    else:
        print("Points are NOT colinear")
1 голос
/ 16 декабря 2017

Есть некоторые проблемы с другими ответами, такими как проверка деления на ноль. Вот мое решение, которое использует функцию Python «Все» и может проверить список точек любой длины:

def collinear(Points):
    '''Accepts [(x1, y1), (x2, y2), ...] and returns true if the 
    points are on the same line.'''
    ERR=1.0e-12
    if len(Points)<3:
        return True
    x1, y1 = Points[0]
    x2, y2 = Points[1]
    if x2==x1:
        raise Exception("points are not a function")
    m=(y2-y1)/(x2-x1)
    return all([abs(m*(xi-x1)-yi+y1)<ERR for xi,yi in Points[2:]])
1 голос
/ 08 марта 2012

Я бы использовал itertools.combinations(), но, поскольку вы пытаетесь изучать Python, вот ваша основная проблема: вы идете на уровень глубже pointList, чем вам нужно.

Измененная функция:

def collinearityTest(pointList):
    for p1 in pointList:
        for p2 in pointList:
            if p2 is p1:
                continue
            for p3 in pointList:
                if p3 is p2 or p3 is p1:
                    continue
                areCollinear(p1, p2, p3)

for p1 in pointList даст вам каждый предмет в pointList.Это именно то, что вы хотите.Вы также можете сделать это с индексами (pointList[index]), если хотите.

Снова перейдите к itertools.combinations().

1 голос
/ 08 марта 2012

Итак, вы хотите иметь 3 цикла for, и каждый из них выполняет итерацию по одному и тому же списку точек. Тогда почему у вас есть цикл while? Просто удали это. В этом нет необходимости.

Кроме; pointList[position] - это двумерный кортеж, например (10,20). И, написав for p1 in pointList[position], вы пытаетесь перебрать этот кортеж. То, что вы хотите, это перебирать список. Так что попробуйте for p1 in pointList вместо этого. То есть, удалите угловые скобки, чтобы перебрать список, а не кортеж. Следовательно; Вам также не нужно отслеживать положение.

Так становится

for p1 in pointList:
  for p2 in pointList:
    for p3 in pointList:
        #do something with p1 p2 p3

Подсказка: Вы также можете рассмотреть возможность использования функции areCollinear, возвращающей логическое значение вместо печати чего-либо. На самом деле это не меняет функциональность, но это лучшая практика, так как это делает вашу функцию многократно используемой позже.

...