Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gmc/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.6.4"
__version__ = "1.6.5"
15 changes: 10 additions & 5 deletions gmc/i18n/gmc_ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -522,11 +522,6 @@ before closing?</source>
<source>Polygon Points Deletion</source>
<translation>удаление точек многоугольника</translation>
</message>
<message>
<location filename="../markup_objects/polygon.py" line="330"/>
<source>Polygon Edition</source>
<translation>редактирование многоугольника</translation>
</message>
<message>
<location filename="../markup_objects/rect.py" line="204"/>
<source>Rectangle Creation</source>
Expand Down Expand Up @@ -612,5 +607,15 @@ before closing?</source>
<source>Type</source>
<translation>Тип</translation>
</message>
<message>
<location filename="../markup_objects/polygon.py" line="342"/>
<source>Point Movement</source>
<translation>движение точки</translation>
</message>
<message>
<location filename="../markup_objects/tags.py" line="247"/>
<source>Alt+Click to check single tag</source>
<translation>Alt+Click для выбора единственной метки</translation>
</message>
</context>
</TS>
File renamed without changes.
112 changes: 69 additions & 43 deletions gmc/markup_objects/polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from math import hypot, atan2, degrees, radians, sin, cos
from typing import Any, Callable
from PyQt5.QtCore import Qt, QPointF, QCoreApplication, QRectF
from time import monotonic

tr: Callable[[str], str] = lambda text: QCoreApplication.translate(
"@default", text
Expand Down Expand Up @@ -75,9 +76,12 @@ def shape(self, close: bool = True) -> QtGui.QPainterPath:
return ps.createStroke(path)

def notify(self, idx: int, pos: QPointF) -> None:
p = self._polygon
p[idx] = pos
self.on_change_polygon(p)
undo = UndoPolygonPointMove(self, idx, pos)
if self.UNDO:
self.scene().undo_stack.push(undo)
else:
undo.redo()
self.on_change_polygon(self._polygon)

def itemChange(
self, change: QtWidgets.QGraphicsItem.GraphicsItemChange, value: Any
Expand All @@ -92,7 +96,6 @@ def itemChange(
def on_start_edit(self) -> None:
self.setFlag(self.GraphicsItemFlag.ItemIsMovable, False)
self.setFlag(self.GraphicsItemFlag.ItemIsSelectable, False)
self._start_edit_polygon = self._polygon[:]
for idx, pos in enumerate(self._polygon):
MoveableDiamond(self, idx, pos)

Expand All @@ -102,15 +105,6 @@ def on_stop_edit(self) -> None:
if scene:
for diamond in self.childItems():
scene.removeItem(diamond)
if self._start_edit_polygon != self._polygon:
undo = UndoPolygonEdit(self, self._start_edit_polygon)
if self.UNDO:
scene.undo_stack.push(undo)
else:
undo.redo()
# is not deleted in UndoPolygonEdit
if hasattr(self, "_start_edit_polygon"):
del self._start_edit_polygon

def on_change_polygon(self, _: QtGui.QPolygonF) -> None:
pass # for overriding
Expand All @@ -129,14 +123,17 @@ def data(self):
class dist_squared:
":returns: distance from segment to a point"

def __new__(cls, a: QPointF, b: QPointF, d: QPointF):
def __new__(
cls, a: QPointF, b: QPointF, d: QPointF
) -> tuple[QPointF, float]:
"a and b segment line; d - the point"
p = b - a
l2 = cls.length(p)
if not l2:
return cls.length(a - d)
return a, cls.length(a - d)
u = max(0.0, min(1.0, cls.add(cls.mul((d - a), p)) / l2))
return cls.length(a + u * p - d)
nearest = a + u * p
return nearest, cls.length(nearest - d)

@staticmethod
def mul(a: QPointF, b: QPointF) -> QPointF:
Expand All @@ -157,15 +154,26 @@ def mouseDoubleClickEvent(self, event: QtWidgets.QGraphicsSceneMouseEvent):
the_point = event.scenePos()
min_dist = 1e900
prev_point = self._polygon[-1]
min_idx = -1
for idx, point in enumerate(self._polygon):
dist = dist_squared(point, prev_point, the_point)
pt, dist = dist_squared(point, prev_point, the_point)
prev_point = point
if dist < min_dist:
min_idx = idx
min_dist = dist
self._polygon.insert(min_idx, the_point)
mid_pt = pt
if min_idx == -1:
return
undo = UndoPolygonAddPoint(self, min_idx, mid_pt)
if self.UNDO:
self.scene().undo_stack.push(undo)
else:
undo.redo()

# ensure new diamond handle appears
self.on_stop_edit()
self.start_edit_nodes()
self.childItems()[min_idx].setSelected(True)
self.update()
else:
MarkupObjectMeta.mouseDoubleClickEvent(self, event)
Expand Down Expand Up @@ -286,7 +294,7 @@ def undo(self) -> None:

class UndoPolygonAddPoint(QtWidgets.QUndoCommand):
def __init__(
self, markup_polygon: MarkupPolygon, idx: int, pos: QPointF
self, markup_polygon: EditableMarkupPolygon, idx: int, pos: QPointF
) -> None:
self._markup_polygon = markup_polygon
self._idx = idx
Expand All @@ -305,48 +313,66 @@ def undo(self) -> None:
mp.update()


class UndoPolygonDelPoints(QtWidgets.QUndoCommand):
class UndoPolygonPointMove(QtWidgets.QUndoCommand):
__slots__ = ("_markup_polygon", "_idx", "_point", "_timestamp")

def __init__(
self, markup_polygon: MarkupPolygon, indices: list[int]
self, markup_polygon: EditableMarkupPolygon, idx: int, point: QPointF
) -> None:
indices.sort(reverse=True)
polygon = markup_polygon._polygon
self._points = [QPointF(polygon[idx]) for idx in indices]
self._markup_polygon = markup_polygon
self._indices = indices
super().__init__(tr("Polygon Points Deletion"))
self._idx = idx
self._point = point
self._timestamp = monotonic()
super().__init__(tr("Point Movement"))

def redo(self) -> None:
mp = self._markup_polygon
for index in self._indices:
mp._polygon.remove(index)
mp, idx = self._markup_polygon, self._idx
diamonds = mp.childItems()
if len(diamonds) == len(mp._polygon):
diamonds[idx].setPos(self._point)
self._point, mp._polygon[idx] = (
QPointF(mp._polygon[idx]),
self._point,
)
mp.update()

def undo(self) -> None:
mp = self._markup_polygon
mp.ensure_edition_canceled()
for idx, point in zip(self._indices[::-1], self._points[::-1]):
mp._polygon.insert(idx, point)
mp.update()
undo = redo

def id(self):
return id(UndoPolygonPointMove) & 0x7FFFFFFF

def mergeWith(self, other: QtWidgets.QUndoCommand | None) -> bool:
if (
isinstance(other, UndoPolygonPointMove)
and other._timestamp - self._timestamp < 0.15
and self._idx == other._idx
and self._markup_polygon is other._markup_polygon
):
self._point = other._point
return True
return False

class UndoPolygonEdit(QtWidgets.QUndoCommand):

class UndoPolygonDelPoints(QtWidgets.QUndoCommand):
def __init__(
self, markup_polygon: MarkupPolygon, prev_polygon: QtGui.QPolygonF
self, markup_polygon: EditableMarkupPolygon, indices: list[int]
) -> None:
indices.sort(reverse=True)
polygon = markup_polygon._polygon
self._points = [QPointF(polygon[idx]) for idx in indices]
self._markup_polygon = markup_polygon
self._prev_polygon = prev_polygon
self._polygon = markup_polygon._polygon[:]
super().__init__(tr("Polygon Edition"))
self._indices = indices
super().__init__(tr("Polygon Points Deletion"))

def redo(self) -> None:
mp = self._markup_polygon
mp.ensure_edition_canceled()
mp._polygon = self._polygon[:]
for idx in self._indices:
mp._polygon.remove(idx)
mp.update()

def undo(self) -> None:
mp = self._markup_polygon
mp.ensure_edition_canceled()
mp._polygon = self._prev_polygon[:]
for idx, point in zip(self._indices[::-1], self._points[::-1]):
mp._polygon.insert(idx, point)
mp.update()
2 changes: 1 addition & 1 deletion gmc/markup_objects/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ def __init__(
self._initial_tags = set(tags)

self._tag_list_widget = tag_list_widget = QtWidgets.QListWidget(
toolTip=tr("Alt+click to check single item"),
toolTip=tr("Alt+Click to check single tag"),
)
tags_label = QtWidgets.QLabel(tr("&Tags:"))
tags_label.setBuddy(tag_list_widget)
Expand Down
Loading