diff --git a/src/Model/Geometry/Point.py b/src/Model/Geometry/Point.py index 24c96137..5de3b058 100644 --- a/src/Model/Geometry/Point.py +++ b/src/Model/Geometry/Point.py @@ -58,7 +58,7 @@ class Point(SQLSubModel): self._name = name self.modified() - def point_is_named(self): + def is_named(self): """ Returns: True if the point is named. diff --git a/src/Model/Geometry/PointXYZ.py b/src/Model/Geometry/PointXYZ.py index ad6b92f1..2cc5936e 100644 --- a/src/Model/Geometry/PointXYZ.py +++ b/src/Model/Geometry/PointXYZ.py @@ -368,5 +368,10 @@ class PointXYZ(Point): a = PointXYZ.distance(p1, p2) b = PointXYZ.distance(p2, p3) c = PointXYZ.distance(p3, p1) - s = (a + b + c) / 2 - return (s*(s-a) * (s-b)*(s-c)) ** 0.5 + + s = float((a + b + c) / 2) + res = ( + s * abs(s - a) * abs(s - b) * abs(s - c) + ) ** 0.5 + + return res diff --git a/src/Model/Geometry/Profile.py b/src/Model/Geometry/Profile.py index 45685caa..af1e8f5e 100644 --- a/src/Model/Geometry/Profile.py +++ b/src/Model/Geometry/Profile.py @@ -187,7 +187,7 @@ class Profile(object): The list of named point """ return [point for point in self.points - if point.point_is_named()] + if point.is_named()] def insert_point(self, index: int, point: Point): """Insert point at index. diff --git a/src/Model/Geometry/ProfileXYZ.py b/src/Model/Geometry/ProfileXYZ.py index b6c98cec..6dd2d7d5 100644 --- a/src/Model/Geometry/ProfileXYZ.py +++ b/src/Model/Geometry/ProfileXYZ.py @@ -16,6 +16,8 @@ # -*- coding: utf-8 -*- +import queue +import random import logging import numpy as np from typing import List @@ -929,13 +931,13 @@ class ProfileXYZ(Profile, SQLSubModel): last_point_not_nan = self._last_point_not_nan(points) for index, point in enumerate(points): - if point.point_is_named(): + if point.is_named(): index_first_named_point = index first_named_point = point break for point in reversed(points): - if point.point_is_named(): + if point.is_named(): last_named_point = point break @@ -1009,46 +1011,47 @@ class ProfileXYZ(Profile, SQLSubModel): if (self.nb_points <= np_purge): return - nb_named = 2 # we consider the first and last point as named - area = [0.0] + q_area = queue.PriorityQueue() + deleted = [] - for i in range(1, self.nb_points-1): - if self.point(i).point_is_named(): - area.append(9999999.999) - nb_named += 1 - else: - area.append( + for ind, point in enumerate(self.points): + if (ind == 0) or (ind == self.nb_points - 1): + continue + + if not point.is_named(): + q_area.put(( PointXYZ.areatriangle3d( - self.point(i-1), - self.point(i), - self.point(i+1)) - ) + self.point(ind - 1), + point, + self.point(ind + 1) + ), + ind, + point + )) - area.append(0.0) + while self.nb_points > np_purge and not q_area.empty(): + area, ind, point = q_area.get() - while self.nb_points > max(np_purge, nb_named): - to_rm = np.argmin(area[1:self.nb_points - 1]) + 1 + self.delete_points([point]) + deleted.append(point) - self.delete_i([to_rm]) - area.pop(to_rm) - - for i in [to_rm-1, to_rm]: - if (i == 0): + # Recompute point neighbourhood + for i in [ind-1, ind]: + if (i <= 0) or (i >= self.nb_points - 1): continue - if (i == self.nb_points - 1): - continue - - if self.point(i).point_is_named(): - area[i] = 9999999.999 - else: - area[i] = PointXYZ.areatriangle3d( - self.point(i-1), - self.point(i), - self.point(i+1) - ) + point = self.point(i) + if not point.is_named(): + q_area.put(( + PointXYZ.areatriangle3d( + self.point(i-1), + point, + self.point(i+1) + ), i, point + )) self.modified() + return deleted def shift(self, x, y, z): for p in self._points: diff --git a/src/View/Geometry/Profile/UndoCommand.py b/src/View/Geometry/Profile/UndoCommand.py index 30cc86c9..9a12e243 100644 --- a/src/View/Geometry/Profile/UndoCommand.py +++ b/src/View/Geometry/Profile/UndoCommand.py @@ -202,16 +202,17 @@ class PurgeCommand(QUndoCommand): def __init__(self, profile, np_purge): QUndoCommand.__init__(self) + self._deleted = [] self._profile = profile - self._old = self._profile.points.copy() self._np_purge = np_purge def undo(self): - self._profile._points = self._old.copy() + for point in self._deleted: + point.set_as_not_deleted() self._profile.modified() def redo(self): - self._profile.purge(self._np_purge) + self._deleted = self._profile.purge(self._np_purge) self._profile.modified() diff --git a/src/View/Geometry/UndoCommand.py b/src/View/Geometry/UndoCommand.py index 562bd65d..c0c9a7fc 100644 --- a/src/View/Geometry/UndoCommand.py +++ b/src/View/Geometry/UndoCommand.py @@ -277,18 +277,17 @@ class PurgeCommand(QUndoCommand): self._reach = reach self._np_purge = np_purge - - self._old = [] - for profile in self._reach.profiles: - self._old.append(profile.points.copy()) + self._deleted = {} def undo(self): - for i in range(self._reach.number_profiles): - self._reach.profiles[i]._points = self._old[i].copy() + for profile in self._deleted: + for point in self._deleted[profile]: + point.set_as_not_deleted() + profile.modified() def redo(self): for profile in self._reach._profiles: - profile.purge(self._np_purge) + self._deleted[profile] = profile.purge(self._np_purge) class ChangeReachCommand(QUndoCommand):