Java 添加/累积“;“折线图组件”;

Java 添加/累积“;“折线图组件”;,java,algorithm,charts,Java,Algorithm,Charts,我可以想象,有一个算法问题准确地描述了我的问题,但我找不到任何问题。我基本上想做的是: 比如说,我有一些数据结构,其中一个类型为Line的对象包含两个(或更多,但在我的例子中,两个就足够了)类型为Point(x,y)的对象 直线表示折线图中从一点A(x,y)到另一点B(x,y)的直线 现在我有一个这样的行列表。请注意,它们在x坐标中也可能重叠。例如,我有一条从(0,0)到(3,1)的线,还有一条从(2,0)到(3,2)的线。现在,我想“累积”这个直线列表,并得到一个点列表(稍后绘制一个折线图)

我可以想象,有一个算法问题准确地描述了我的问题,但我找不到任何问题。我基本上想做的是:

比如说,我有一些数据结构,其中一个类型为Line的对象包含两个(或更多,但在我的例子中,两个就足够了)类型为Point(x,y)的对象

直线表示折线图中从一点A(x,y)到另一点B(x,y)的直线

现在我有一个这样的行列表。请注意,它们在x坐标中也可能重叠。例如,我有一条从(0,0)到(3,1)的线,还有一条从(2,0)到(3,2)的线。现在,我想“累积”这个直线列表,并得到一个点列表(稍后绘制一个折线图)

对于上面的例子,这意味着我想要{(0,0);(2,0,67);(3,2)}。下面是一幅美丽的图片,希望能让我的问题更加清晰:

背景:我正在编写血液酒精含量水平计算器。我有几种属性的饮料,如:容量、百分比、开始时间、结束时间

我想假设从开始时间到结束时间血液酒精含量水平的线性上升减去这段时间酒精含量的下降。在我看来,现在计算每种饮料的单个“线”是很容易的,但是要得到一个完整的线状图来表示你在整个时间内的血液酒精含量水平,我现在必须将所有这些“线”加在一起


至少这是我的想法,这将是我的方法,如果您有不同的方法/建议,也请让我知道。

算法的主要思想:

  • 将x轴拆分为多个间隔。 定义间隔的点对应于每条线每个点的“x”属性
  • 间隔中包含的行的总和。 现在,我们为每个间隔生成一个新行。该行将是该间隔中包含的行的总和

  • 为了能够对两行进行求和,我们将两行转换为函数(),执行求和并创建新行

  • 任何直线方程的斜率截距形式如下所示:

    y = mx + b
    
    其中:

  • m是直线的斜率
  • b是直线的y截距
  • 通过任意两点
    (x1,y1)
    (x2,y2)
    的直线斜率m由下式给出:

    y = mx + b
    

    直线的y截距b是直线与y轴相交点处的y值。因为对于点
    (x1,y1)
    我们有
    y1=mx1+b
    ,y截距b可以通过以下公式计算:

    b = y1 - mx1
    
    新线点的“x”值将是间隔的限制,“y”值将是将函数应用于“x”值的结果

    代码:(注意:getter/setter是常用的)

    LineFunction:

    public class LineFunction {
    
        private final double m, b;
    
        public LineFunction(Line l) {
            /**
             * y= ((y_b-y_a)/(x_b-x_a))*(x-x_a) + y_a
             * 
             * ((y_b-y_a)/(x_b-x_a))==> m
             * 
             * y = m *(x-x_a)+y_a
             * 
             * y= m*x -m*x_a +y_a
             * 
             * -m*x_a +y_a -> b
             * 
             * y = m*x + b
             */
            double y_a, y_b, x_a, x_b;
            x_a = l.getP1().getX();
            y_a = l.getP1().getY();
            x_b = l.getP2().getX();
            y_b = l.getP2().getY();
            m = (y_b - y_a) / (x_b - x_a);
            b = -m * x_a + y_a;
    
        }
    
        private LineFunction(double m, double b) {
            this.m = m;
            this.b = b;
        }
    
        public double computeFor(double xValue) {
            return this.m * xValue + this.b;
        }
    
        public LineFunction sum(LineFunction other) {
            return new LineFunction(this.m + other.m, this.b + other.b);
        }
    
        @Override
        public String toString() {
            return "y = " + m + "x + " + b;
        }
    }
    
    此类表示类型为y=mx+b的简单函数。基本上,取一行并将其转换为函数

    行:

    此方法返回定义间隔的所有点。积分必须按顺序排列,所以

    public class Point implements Comparable<Point>{
        private long x;
        private double y;
    
        @Override
        public int compareTo(Point o) {
            int cmp1=Long.compare(this.x, o.x);
            return  cmp1 != 0 ? cmp1 : Double.compare(this.y, o.y) ;
        }
    
        @Override
        public String toString() {
            return "(" + x + "," + y + ")";
        }
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + (int) (x ^ (x >>> 32));
            long temp;
            temp = Double.doubleToLongBits(y);
            result = prime * result + (int) (temp ^ (temp >>> 32));
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Point other = (Point) obj;
            if (x != other.x)
                return false;
            if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
                return false;
            return true;
        }
    
    }
    

    如果我遗漏了什么,请不要犹豫,留下评论。

    这是一张美丽的图片,希望能让我的问题更清楚。1.你是微软的绘画艺术家。2.是的,这很清楚。你的图表是连续的还是离散的?。换句话说:可以存在这样一个点:
    (1.023,7.21)
    ?我希望,我把你说对了:为了我的特殊用途,我会将数据类型的时间
    Date
    作为x变量(我使用的库接受这个,我猜,它稍后会被转换为数据类型的时间戳
    long
    )和数据类型
    double
    的血液酒精含量水平作为y变量。我将做以下操作:首先,将行分解为更多行,以便对于每对行,唯一发生的重叠是相等(您可以通过查看每行的开始和结束x来实现)在您的示例中,将第一行分为两部分,x=2时;然后,用相等的起点和终点x对行进行分组,并添加y值以获得每组的一行。@user1684030是否需要将这些行视为行?我的意思是,一条线可以看作是一系列的点吗?你完美地解决了这个问题,因此我将把这条线标记为已解决。然而,我注意到,我想得不够远。我需要的不仅仅是添加图表的部分,我还需要为以后的部分保留偏移量。这里有一张图片来说明我的意思:-我会自己进一步尝试,也许你的解决方案可以帮助我。无论如何,非常感谢!我真的很感谢你们的努力。此外,我正在努力解决酒精的实际降解问题。我想在([图表的开始],0.0)到([一天结束的时间/图表],[计算降级(负数)]之间添加一条“线”,但这样我会得到负面结果。我需要这个“退化线”只有在其他线“变为正”后才能影响它们。很难解释,这个图像可能会有帮助:正如你所看到的,我在思想上犯了一些错误,如果你觉得你浪费了时间,我真的很抱歉…:(您解决了解释的问题,再次感谢您的帮助。@user1684030别担心。我很乐意提供帮助。如果您还需要其他帮助,请创建一个新问题并通知我。我将很乐意回答。
    public class Point implements Comparable<Point>{
        private long x;
        private double y;
    
        @Override
        public int compareTo(Point o) {
            int cmp1=Long.compare(this.x, o.x);
            return  cmp1 != 0 ? cmp1 : Double.compare(this.y, o.y) ;
        }
    
        @Override
        public String toString() {
            return "(" + x + "," + y + ")";
        }
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + (int) (x ^ (x >>> 32));
            long temp;
            temp = Double.doubleToLongBits(y);
            result = prime * result + (int) (temp ^ (temp >>> 32));
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Point other = (Point) obj;
            if (x != other.x)
                return false;
            if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
                return false;
            return true;
        }
    
    }
    
    public static ArrayList<Line> filter(Point p, ArrayList<Line> lines) {
            ArrayList<Line> filtered = new ArrayList<Line>();
            for (Line line : lines)
                if (line.isInInterval(p))
                    filtered.add(line);
    
            return filtered;
        }
    
    public static ArrayList<Line> sumAll(ArrayList<Line> lines) {
            ArrayList<Point> points = getAllPoints(lines);
            ArrayList<Line> result = new ArrayList<>();
    
            for (int i = 0; i < points.size() - 1; i++)
            {
                Point current = points.get(i);
                Point next = points.get(i + 1);
                ArrayList<Line> filtered = filter(current, lines);
                Line acc = new Line(new Point(current.getX(), 0), new Point(
                        next.getX(), 0));
    
                for (Line lf : filtered)
                {
                    acc = acc.sum(lf, current, next);
                }
    
                result.add(acc);
            }
            return result;
        }
    
    public static void main(String[] args) {
            Line l1 = new Line(new Point(0, 0), new Point(3, 1));
            Line l2 = new Line(new Point(2, 0), new Point(3, 1));
    
            Line l3 = new Line(new Point(4, 7), new Point(8, 2));
            Line l4 = new Line(new Point(5, 4), new Point(6, 1));
    
            Line l5 = new Line(new Point(9, 6), new Point(10, 1));
            ArrayList<Line> lines = new ArrayList<Line>();
            lines.add(l1);
            lines.add(l2);
            lines.add(l3);
            lines.add(l4);
            lines.add(l5);
            ArrayList<Line> res = sumAll(lines);
            for (Line line : res)
            {
                System.out.println(line);
            }
    
    
        }
    
    {(0,0.0),(2,0.6666666666666666)}
    {(2,0.666666666666667),(3,2.0)}
    {(3,0.0),(4,0.0)} ----> There's no line in this interval.
    {(4,7.0),(5,5.75)}
    {(5,9.75),(6,5.5)}
    {(6,4.5),(8,2.0)}
    {(8,0.0),(9,0.0)}
    {(9,6.0),(10,1.0)}