class Polygon(Figure): """ Многоугольник """ def __init__(self, a, b, c): self.points = Deq() self.points.push_first(b) if b.is_light(a, c): self.points.push_first(a) self.points.push_last(c) else: self.points.push_last(a) self.points.push_first(c) self._perimeter = a.dist(b) + b.dist(c) + c.dist(a) self._area = abs(R2Point.area(a, b, c)) def perimeter(self): return self._perimeter def area(self): return self._area # добавление новой точки def add(self, t): # поиск освещённого ребра for n in range(self.points.size()): if t.is_light(self.points.last(), self.points.first()): break self.points.push_last(self.points.pop_first()) # хотя бы одно освещённое ребро есть if t.is_light(self.points.last(), self.points.first()): # учёт удаления ребра, соединяющего конец и начало дека self._perimeter -= self.points.first().dist(self.points.last()) self._area += abs( R2Point.area(t, self.points.last(), self.points.first())) # удаление освещённых рёбер из начала дека p = self.points.pop_first() while t.is_light(p, self.points.first()): self._perimeter -= p.dist(self.points.first()) self._area += abs(R2Point.area(t, p, self.points.first())) p = self.points.pop_first() self.points.push_first(p) # удаление освещённых рёбер из конца дека p = self.points.pop_last() while t.is_light(self.points.last(), p): self._perimeter -= p.dist(self.points.last()) self._area += abs(R2Point.area(t, p, self.points.last())) p = self.points.pop_last() self.points.push_last(p) # добавление двух новых рёбер self._perimeter += t.dist(self.points.first()) + \ t.dist(self.points.last()) self.points.push_first(t) return self
class Polygon(Figure): """ Многоугольник """ def __init__(self, a, b, c): self.points = Deq() self.points.push_first(b) if b.is_light(a, c): self.points.push_first(a) self.points.push_last(c) else: self.points.push_last(a) self.points.push_first(c) self._perimeter = a.dist(b) + b.dist(c) + c.dist(a) self._area = abs(R2Point.area(a, b, c)) # подсчет велины g которая включает сумму искомых нами сегментов self._g = support.lenght(a, b) + support.lenght(b, c) \ + support.lenght(c, a) def perimeter(self): return float(self._perimeter) def area(self): return self._area def g(self): return self._g # добавление новой точки def add(self, t): # поиск освещённого ребра for n in range(self.points.size()): if t.is_light(self.points.last(), self.points.first()): break self.points.push_last(self.points.pop_first()) # хотя бы одно освещённое ребро есть if t.is_light(self.points.last(), self.points.first()): # учёт удаления ребра, соединяющего конец и начало дека self._perimeter -= float(self.points.first().dist( self.points.last())) self._g -= support.lenght(self.points.first(), self.points.last()) self._area += abs( R2Point.area(t, self.points.last(), self.points.first())) # удаление освещённых рёбер из начала дека p = self.points.pop_first() while t.is_light(p, self.points.first()): self._g -= support.lenght(p, self.points.first()) self._perimeter -= float(p.dist(self.points.first())) self._area += abs(R2Point.area(t, p, self.points.first())) p = self.points.pop_first() self.points.push_first(p) # удаление освещённых рёбер из конца дека p = self.points.pop_last() while t.is_light(self.points.last(), p): self._g -= support.lenght(p, self.points.last()) self._perimeter -= float(p.dist(self.points.last())) self._area += abs(R2Point.area(t, p, self.points.last())) p = self.points.pop_last() self.points.push_last(p) # добавление двух новых рёбер self._perimeter += float( t.dist(self.points.first()) + t.dist(self.points.last())) self._g += \ support.lenght(t, self. points.first()) + support.lenght(t, self. points.last()) self.points.push_first(t) return self
class Rectangle: """ Обчный прямоугольник, общую площадь с которым нужно найти """ # Вершины прямоугольника внутри которого ищется общая площадь с выпуклой оболочкой # Задаем по умолчанию хоть какое-то значение (квадарт, площадью 4.0) verts = [ R2Point(-1.0, -1.0), R2Point(1.0, -1.0), R2Point(1.0, 1.0), R2Point(-1.0, 1.0) ] def __init__(self, a=None, b=None): self.common_points = Deq( ) # Общие точки прямоугольника и выпуклой оболочки (Дек) self._common_perimeter = 0 # Общий периметр (так уж за одно посчитаем) self._common_area = 0 # Общая площадь - то, что нужно найти в задаче! # Указываем вершины прямоугольника self.set_verts(a, b) def set_verts(self, a, b): """ Назначаем противоположные вершины прямоугольника """ # Если в конструкторе указаны противоположные точки, то размеры прямоугольника меняем: if a is not None: self.verts[0] = a if b is not None: self.verts[2] = b # Вычисляем противоположные вершины self.calc_other_vertex() return self.verts def calc_other_vertex(self): """ Считаем противоположные вершины прямоугольника, если имеются две других противоположных """ self.verts[1].x = self.verts[2].x self.verts[1].y = self.verts[0].y self.verts[3].x = self.verts[0].x self.verts[3].y = self.verts[2].y return self.verts def common_area(self): """ Возвращаем общую площадь """ return self._common_area def common_perimeter(self): """ Возвращаем общие периметр """ return self._common_perimeter def add_crossing(self, a, b): """ Найти пересекающиеся точки с нашим прямоугольником и ребром, образованным точками [a, b] """ # Добавляем точки конца отрезка в список общих точек, если они внутри self.add_outside(a) self.add_outside(b) crossing_points = [] crossing_points_bottom = self.find_crossing_seg( a, b, self.verts[0], self.verts[1]) crossing_points_right = self.find_crossing_seg(a, b, self.verts[1], self.verts[2]) crossing_points_top = self.find_crossing_seg(a, b, self.verts[2], self.verts[3]) crossing_points_left = self.find_crossing_seg(a, b, self.verts[3], self.verts[0]) if crossing_points_bottom is not None: crossing_points.append(crossing_points_bottom[0]) crossing_points.append(crossing_points_bottom[1]) #print("AddOK1") if crossing_points_right is not None: crossing_points.append(crossing_points_right[0]) crossing_points.append(crossing_points_right[1]) #print("AddOK2") if crossing_points_top is not None: crossing_points.append(crossing_points_top[0]) crossing_points.append(crossing_points_top[1]) #print("AddOK3") if crossing_points_left is not None: crossing_points.append(crossing_points_left[0]) crossing_points.append(crossing_points_left[1]) #print("AddOK4") # Оставляем только уникальные точки for point in crossing_points: #print('Checking point:', point) #print(self.add_common_point(point)) self.add_common_point(point) #print('Rect Deque (crossing point):', self.common_points.size()) #print('Common area (crossing point):', self.common_area()) def add_inside(self, a, b, c): """ Проверяем вершины прямоугольника, которые попали внутрь выпуклой оболочки и добавляем их в общие точки Этот метод нужен тогда, когда общих пересечений у выпуклой оболочки нет, но сами вершины прямоугольника являются точками, которые надо учитывать Передаются три новых точки выпуклой оболочки, которые дают нам новую площадь """ for i in range(4): if self.verts[i].is_inside_of_triang(a, b, c): self.add_common_point(self.verts[i]) #print('a:',a) #print('b:',b) #print('c:',c) #print('Rect Deque (inner point):', self.common_points.size()) #print('Common area (inner point):', self.common_area()) def add_outside(self, a): """ Проверяем, является ли наш прямоугольник внешним по отношению к точке выпуклой оболочки Т.е. другими словами, лежит ли точка "a" внутри нашего прямоугольника. И если да, то добавляем ее в список общих точек """ # метод R2Point для проверки лежит ли точка внутри правильного прямоугольника # аргументы - противопоолжные вершины этого прямоугольника if a.is_inside(self.verts[0], self.verts[2]): self.add_common_point(a) #print('Rect Deque (outer point):', self.common_points.size()) #print('Common area (outer point):', self.common_area()) def find_crossing_seg(self, a, b, q, p): """ Находим пересечение двух отрезков [a,b] и [q, p]. Возвращает общее пересечение - отрезок (если совпадает, то точка) """ return R2Point.seg2seg(a, b, q, p) # добавление новой точки в массив точек общей площади def add_common_point(self, t): # Если такая точка уже есть, то ничего не делаем #print('Common Points Before:', self.common_points) if t in self.common_points: return self # Поначалу просто наберем хотя бы одну точку if self.common_points.size() == 0: self.common_points.push_first(t) # Потом добавляем в конец другую точку if self.common_points.size() == 1: self.common_points.push_last(t) # Если у нас есть две точки, то добавляя третью нам надо расширить отрезок, удалив серединную точку if self.common_points.size() == 2: # Если точки лежат на одной прямой if not R2Point.is_triangle(t, self.common_points.first(), self.common_points.last()): # Проверяем, находится ли точка начала дека внутри отрезка if self.common_points.first().is_inside( t, self.common_points.last()): self.common_points.pop_first() self.common_points.push_first( t) # Если да, то заменяем на добавляемую точку # или если точка конца дека находится внутри отрезка elif self.common_points.last().is_inside( t, self.common_points.first()): self.common_points.pop_last() self.common_points.push_last(t) # Если же у нас уже накопилось более трех точек, то ищем площадь if self.common_points.size() >= 2: # поиск освещённого ребра for n in range(self.common_points.size()): if t.is_light(self.common_points.last(), self.common_points.first()): break self.common_points.push_last(self.common_points.pop_first()) # хотя бы одно освещённое ребро есть (если не внутри) if t.is_light(self.common_points.last(), self.common_points.first()): # учёт удаления ребра, соединяющего конец и начало дека self._common_perimeter -= self.common_points.first().dist( self.common_points.last()) area = abs( R2Point.area(t, self.common_points.last(), self.common_points.first())) self._common_area += area # удаление освещённых рёбер из начала дека #print('OK1:',self.common_points) #print('OK1_first:',self.common_points.first()) #print('OK1_last:',self.common_points.last()) #print('OK1_size:',self.common_points.size()) p = self.common_points.pop_first() #print('OK2:',self.common_points) #print('OK3:',p) #print('OK4:',self.common_points.array[0]) while t.is_light(p, self.common_points.first()): self._common_perimeter -= p.dist( self.common_points.first()) self._common_area += abs( R2Point.area(t, p, self.common_points.first())) p = self.common_points.pop_first() #print('OK5_p:', p) #print('OK5_after_p:', self.common_points) self.common_points.push_first(p) # удаление освещённых рёбер из конца дека p = self.common_points.pop_last() while t.is_light(self.common_points.last(), p): self._common_perimeter -= p.dist(self.common_points.last()) self._common_area += abs( R2Point.area(t, p, self.common_points.last())) p = self.common_points.pop_last() self.common_points.push_last(p) # добавление двух новых рёбер self._common_perimeter += t.dist(self.common_points.first()) + \ t.dist(self.common_points.last()) self.common_points.push_first(t) #print('Common Points After:', self.common_points) return self
class Polygon(Figure): """ Многоугольник """ def __init__(self, a, b, c): self.points = Deq() self.points.push_first(b) if b.is_light(a, c): self.points.push_first(a) self.points.push_last(c) else: self.points.push_last(a) self.points.push_first(c) self._perimeter = a.dist(b) + b.dist(c) + c.dist(a) self._area = abs(R2Point.area(a, b, c)) self._g = a.dist(self.fixed_point) + b.dist(self.fixed_point) + \ c.dist(self.fixed_point) self.rectangle.add_crossing( b, c) # Проверяем, пересекает ли отрезок какую-либо из граней self.rectangle.add_crossing( b, a) # Проверяем, пересекает ли отрезок какую-либо из граней self.rectangle.add_crossing( a, c) # Проверяем, пересекает ли отрезок какую-либо из граней # Добавляем в Дек вершины прямоугольника, которые находятся внутри выпуклой оболочки, # чтобы корректно считать площадь, если НЕТ пересечения self.rectangle.add_inside(a, b, c) def perimeter(self): return self._perimeter def area(self): return self._area def g(self): return self._g def g73(self): """ Возвращаем общую площадь прямоугольника и выпуклой оболочки """ return self.rectangle.common_area() # добавление новой точки def add(self, t): # поиск освещённого ребра for n in range(self.points.size()): if t.is_light(self.points.last(), self.points.first()): break self.points.push_last(self.points.pop_first()) # хотя бы одно освещённое ребро есть if t.is_light(self.points.last(), self.points.first()): # учёт удаления ребра, соединяющего конец и начало дека self._perimeter -= self.points.first().dist(self.points.last()) self._area += abs( R2Point.area(t, self.points.last(), self.points.first())) #print('OK11', t) #print('OK12', self.points.first()) #print('OK13', self.points.last()) self.rectangle.add_crossing(t, self.points.first( )) # Проверяем, пересекает ли отрезок какую-либо из граней self.rectangle.add_crossing(t, self.points.last( )) # Проверяем, пересекает ли отрезок какую-либо из граней # Добавляем в Дек вершины прямоугольника, которые находятся внутри выпуклой оболочки, # чтобы корректно считать площадь, если НЕТ пересечения self.rectangle.add_inside(self.points.first(), self.points.last(), t) # удаление освещённых рёбер из начала дека p = self.points.pop_first() while t.is_light(p, self.points.first()): self._perimeter -= p.dist(self.points.first()) self._area += abs(R2Point.area(t, p, self.points.first())) self._g -= p.dist(self.fixed_point) p = self.points.pop_first() self.points.push_first(p) # удаление освещённых рёбер из конца дека p = self.points.pop_last() while t.is_light(self.points.last(), p): self._perimeter -= p.dist(self.points.last()) self._area += abs(R2Point.area(t, p, self.points.last())) self._g -= p.dist(self.fixed_point) p = self.points.pop_last() self.points.push_last(p) # добавление двух новых рёбер self._perimeter += t.dist(self.points.first()) + \ t.dist(self.points.last()) self.points.push_first(t) self._g += t.dist(self.fixed_point) self.rectangle.add_crossing( self.points.first(), t) # Проверяем, пересекает ли отрезок какую-либо из граней self.rectangle.add_crossing( self.points.last(), t) # Проверяем, пересекает ли отрезок какую-либо из граней # Добавляем в Дек вершины прямоугольника, которые находятся внутри выпуклой оболочки, # чтобы корректно считать площадь, если НЕТ пересечения self.rectangle.add_inside(self.points.first(), self.points.last(), t) return self