Files
2025-06-10 01:16:09 +08:00

76 lines
2.1 KiB
Python

import copy
from dataclasses import dataclass
from math import sqrt
from Common.CEnum import BI_DIR, TREND_LINE_SIDE
@dataclass
class Point:
x: int
y: float
def cal_slope(self, p):
return (self.y-p.y)/(self.x-p.x) if self.x != p.x else float("inf")
@dataclass
class Line:
p: Point
slope: float
def cal_dis(self, p):
return abs(self.slope*p.x - p.y + self.p.y - self.slope*self.p.x) / sqrt(self.slope**2 + 1)
class CTrendLine:
def __init__(self, lst, side=TREND_LINE_SIDE.OUTSIDE):
self.line = None
self.side = side
self.cal(lst)
def cal(self, lst):
bench = float('inf')
if self.side == TREND_LINE_SIDE.INSIDE:
all_p = [Point(bi.get_begin_klu().idx, bi.get_begin_val()) for bi in lst[-1::-2]]
else:
all_p = [Point(bi.get_end_klu().idx, bi.get_end_val()) for bi in lst[-1::-2]]
c_p = copy.copy(all_p)
while True:
line, idx = cal_tl(c_p, lst[-1].dir, self.side)
dis = sum(line.cal_dis(p) for p in all_p)
if dis < bench:
bench = dis
self.line = line
c_p = c_p[idx:]
if len(c_p) == 1:
break
def init_peak_slope(_dir, side):
if side == TREND_LINE_SIDE.INSIDE:
return 0
elif _dir == BI_DIR.UP:
return float("inf")
else:
return -float("inf")
def cal_tl(c_p, _dir, side):
p = c_p[0]
peak_slope = init_peak_slope(_dir, side)
idx = 1
for point_idx, p2 in enumerate(c_p[1:]):
slope = p.cal_slope(p2)
if (_dir == BI_DIR.UP and slope < 0) or (_dir == BI_DIR.DOWN and slope > 0):
continue
if side == TREND_LINE_SIDE.INSIDE:
if (_dir == BI_DIR.UP and slope > peak_slope) or (_dir == BI_DIR.DOWN and slope < peak_slope):
peak_slope = slope
idx = point_idx+1
else:
if (_dir == BI_DIR.UP and slope < peak_slope) or (_dir == BI_DIR.DOWN and slope > peak_slope):
peak_slope = slope
idx = point_idx+1
return Line(p, peak_slope), idx