0

I want to mark points of intersection of two lines in x-y plane on a graph..

Using GraphView in my app, I have plotted 2 series in following manner:

GraphView graph = (GraphView) findViewById(R.id.graph);
graph.getViewport().setScalable(true);
graph.getViewport().setScrollable(true);
graph.getViewport().setScalableY(true);
graph.getViewport().setScrollableY(false);

PointsGraphSeries<DataPoint> series1 = new PointsGraphSeries<>(new DataPoint[]{
        new DataPoint(3, 4),
        new DataPoint(4, 4.1),
        new DataPoint(5, 4.1),
        new DataPoint(6, 4.2),
        new DataPoint(7, 4.2),
        new DataPoint(8, 4.3),
        new DataPoint(9, 4.3),
        new DataPoint(10, 4.4),
        new DataPoint(10, 4.4),
        new DataPoint(10, 4.5),
        new DataPoint(11, 4.5),
        new DataPoint(12, 4.5),
        new DataPoint(12, 4.6),
        new DataPoint(13, 4.6),
        new DataPoint(14, 4.6),
        new DataPoint(15, 4.7),
        new DataPoint(16, 4.8),
        new DataPoint(16, 5.0),
        new DataPoint(17, 5.0),
        new DataPoint(18, 5.1),
        new DataPoint(19, 5.4),
        new DataPoint(20, 5.5),
        new DataPoint(21, 5.6),
        new DataPoint(22, 5.6),
        new DataPoint(25, 5.7),
        new DataPoint(26, 5.7),
        new DataPoint(27, 5.8),
        new DataPoint(28, 5.8),
        new DataPoint(29, 5.9),
        new DataPoint(30, 5.9),
        new DataPoint(30, 6.0),
        new DataPoint(31, 6.0),
        new DataPoint(32, 6.0)
});
graph.addSeries(series1);
series1.setShape(PointsGraphSeries.Shape.POINT);
series1.setColor(Color.BLACK);

PointsGraphSeries<DataPoint> series2 = new PointsGraphSeries<DataPoint>(new DataPoint[]{
        new DataPoint(3, 5),
        new DataPoint(4, 4.9),
        new DataPoint(5, 4.8),
        new DataPoint(6, 4.7),
        new DataPoint(7, 4.6),
        new DataPoint(8, 4.5),
        new DataPoint(9, 4.4),
        new DataPoint(10, 4.3),
        new DataPoint(11, 4.2),
        new DataPoint(12, 4.1),
        new DataPoint(13, 4.0),
        new DataPoint(14, 3.9),
        new DataPoint(15, 3.8),
        new DataPoint(16, 3.7),
        new DataPoint(17, 3.6),
        new DataPoint(18, 3.5),
        new DataPoint(19, 3.4),
        new DataPoint(20, 3.3),
        new DataPoint(21, 3.2),
        new DataPoint(22, 3.1),
        new DataPoint(23, 3.0),
        new DataPoint(24, 2.9),
        new DataPoint(25, 2.7),
        new DataPoint(26, 2.6),
        new DataPoint(27, 2.5),
        new DataPoint(28, 2.4),
        new DataPoint(29, 2.3),
        new DataPoint(30, 2.2),
        new DataPoint(31, 2.1),
        new DataPoint(32, 2.0),
        new DataPoint(33, 1.9),
        new DataPoint(34, 1.8),
        new DataPoint(35, 1.7),
        new DataPoint(36, 1.6),
        new DataPoint(37, 1.5),
        new DataPoint(38, 1.4),
        new DataPoint(39, 1.2),
        new DataPoint(40, 1.1),
        new DataPoint(42, 0.9),
        new DataPoint(43, 0.9),
        new DataPoint(44, 1.0),
        new DataPoint(45, 1.0),
        new DataPoint(46, 1.0),
        new DataPoint(47, 1.0),
        new DataPoint(48, 1.0),
        new DataPoint(49, 1.0),
        new DataPoint(50, 1.0),
        new DataPoint(51, 1.0),
        new DataPoint(52, 1.0),
        new DataPoint(53, 1.0),
        new DataPoint(54, 1.0),
        new DataPoint(55, 1.0),
        new DataPoint(56, 1.0),
        new DataPoint(57, 1.0),
        new DataPoint(58, 1.0),
        new DataPoint(59, 1.0),
        new DataPoint(60, 1.0),
});
graph.addSeries(series2);
series2.setShape(PointsGraphSeries.Shape.POINT);
series2.setColor(Color.MAGENTA);

Update:- No two DataPoints are equal.

How to mark the intersection of two lines/series in graph with a label?

Is it possible using GraphView / MPAndroidChart or any other library?

Any reply/comment/reference to solution would be greatly appreciated.

I want to implement something similar to as shown in this image: enter image description here

The intersections here are marked with red-dot and accompany a label.

Sandeep Yohans
  • 929
  • 1
  • 14
  • 36

2 Answers2

1

Your question is more of an algorithm question on how to find the intersections between the two graphs/series. In the attached code, I changed your two series to a LineGraphSeries and created a third PointGraphSeries series3.

To create the third series I used a simple algorithm to first find the intersections of the two series and then add the trace to the graph.

GraphView graph = findViewById(R.id.graph);

DataPoint[] points1 = new DataPoint[]{
        new DataPoint(3, 4),
        new DataPoint(4, 4.1),
        new DataPoint(5, 4.2),
        new DataPoint(6, 4.3),
        new DataPoint(7, 4.4),
        new DataPoint(8, 4.4),
        new DataPoint(9, 4.4),
        new DataPoint(10, 4.4),
        new DataPoint(11, 4.5),
        new DataPoint(12, 4.5),
        new DataPoint(13, 4.3),
        new DataPoint(14, 4.4),
        new DataPoint(15, 4.5),
        new DataPoint(16, 4.6),
        new DataPoint(17, 5.0),
        new DataPoint(18, 5.1),
        new DataPoint(19, 5.4),
        new DataPoint(20, 5.5),
        new DataPoint(21, 5.6),
        new DataPoint(22, 5.6),
        new DataPoint(25, 5.7),
        new DataPoint(26, 5.7),
        new DataPoint(27, 5.8),
        new DataPoint(28, 5.8),
        new DataPoint(29, 5.9),
        new DataPoint(30, 5.9),
        new DataPoint(31, 6.0),
        new DataPoint(32, 6.0)
};

DataPoint[] points2 = new DataPoint[]{
        new DataPoint(3, 5),
        new DataPoint(4, 4.9),
        new DataPoint(5, 4.8),
        new DataPoint(6, 4.7),
        new DataPoint(7, 4.6),
        new DataPoint(8, 4.5),
        new DataPoint(9, 4.4),
        new DataPoint(10, 4.3),
        new DataPoint(11, 4.2),
        new DataPoint(12, 4.1),
        new DataPoint(13, 4.0),
        new DataPoint(14, 3.9),
        new DataPoint(15, 3.8),
        new DataPoint(16, 3.7),
        new DataPoint(17, 3.6),
        new DataPoint(18, 3.5),
        new DataPoint(19, 3.4),
        new DataPoint(20, 3.3),
        new DataPoint(21, 3.2),
        new DataPoint(22, 3.1),
        new DataPoint(23, 3.0),
        new DataPoint(24, 2.9),
        new DataPoint(25, 2.7),
        new DataPoint(26, 2.6),
        new DataPoint(27, 2.5),
        new DataPoint(28, 2.4),
        new DataPoint(29, 2.3),
        new DataPoint(30, 2.2),
        new DataPoint(31, 2.1),
        new DataPoint(32, 2.0),
        new DataPoint(33, 1.9),
        new DataPoint(34, 1.8),
        new DataPoint(35, 1.7),
        new DataPoint(36, 1.6),
        new DataPoint(37, 1.5),
        new DataPoint(38, 1.4),
        new DataPoint(39, 1.2),
        new DataPoint(40, 1.1),
        new DataPoint(42, 0.9),
        new DataPoint(43, 0.9),
        new DataPoint(44, 1.0),
        new DataPoint(45, 1.0),
        new DataPoint(46, 1.0),
        new DataPoint(47, 1.0),
        new DataPoint(48, 1.0),
        new DataPoint(49, 1.0),
        new DataPoint(50, 1.0),
        new DataPoint(51, 1.0),
        new DataPoint(52, 1.0),
        new DataPoint(53, 1.0),
        new DataPoint(54, 1.0),
        new DataPoint(55, 1.0),
        new DataPoint(56, 1.0),
        new DataPoint(57, 1.0),
        new DataPoint(58, 1.0),
        new DataPoint(59, 1.0),
        new DataPoint(60, 1.0)
};

LineGraphSeries<DataPoint> series1 = new LineGraphSeries<>(points1);
series1.setColor(Color.BLACK);
graph.addSeries(series1);


LineGraphSeries<DataPoint> series2 = new LineGraphSeries<>(points2);
series2.setColor(Color.MAGENTA);
graph.addSeries(series2);

// Third graph that is based on the intersections
PointsGraphSeries<DataPoint> series3 = new PointsGraphSeries<>();
series3.setShape(PointsGraphSeries.Shape.POINT);
series3.setColor(Color.RED);

for (DataPoint point1 : points1) {
    for (DataPoint point2 : points2) {
        if (point1.getX() == point2.getX()
                && point1.getY() == point2.getY()) {
            series3.appendData(point1, true, points1.length);
        }

    }
}
graph.addSeries(series3);

enter image description here

svahidhoss
  • 333
  • 2
  • 11
  • 1
    If this has answered your question, can you mark it as the answer? Thanks! – svahidhoss Aug 21 '18 at 14:15
  • I am waiting for more replies, will do it if dont't get any. – Sandeep Yohans Aug 26 '18 at 17:21
  • As per your solutions, the intersection is marked if and only if both the series have a data point with equal x and y values. Can you guide me to some algorithm which I need to implement for this problem? – Sandeep Yohans Sep 04 '18 at 12:36
  • The provided algorithm resolves your problem. I am not sure which part are you talking about. Are you talking about the labels? – svahidhoss Sep 05 '18 at 15:03
  • For example, in the above data, if no two data points are equal and the closest points we have near intersection is (9, 4.4) and (9,4.5) then this algorithm will not work. In my app I do not have equal datapoints. – Sandeep Yohans Sep 06 '18 at 03:53
  • This is a separate question. Please post that question and specify what kind of range are you looking for. I will be more than happy to help. – svahidhoss Sep 07 '18 at 22:01
  • Is it ok if I modify the datapoints in this question instead of posting a new question? – Sandeep Yohans Sep 08 '18 at 02:05
-1

Thank you @svahidhoss for your post. It helped me find solution for the problem.

I have used your sample and added if condition for cases when no DataPoints are equal.

Below is the solution:

            DataPoint[] pointsA = new DataPoint[]{
            new DataPoint(1, 2500),
            new DataPoint(2, 2500),
            new DataPoint(3, 2500),
            new DataPoint(4, 2500),
            new DataPoint(5, 3000),
            new DataPoint(6, 3000),
            new DataPoint(7, 3000),
            new DataPoint(8, 3000),
            new DataPoint(9, 3500),
            new DataPoint(10, 3500),
            new DataPoint(11, 3500),
            new DataPoint(12, 3500),
            new DataPoint(13, 4000),
            new DataPoint(14, 4000),
            new DataPoint(15, 4000),
            new DataPoint(16, 4000),
            new DataPoint(17, 4500),
            new DataPoint(18, 4500),
            new DataPoint(19, 4500),
            new DataPoint(20, 4500),
            new DataPoint(21, 5000),
            new DataPoint(22, 5000),
            new DataPoint(23, 5000),
            new DataPoint(24, 5500),
            new DataPoint(25, 5500),
            new DataPoint(26, 5700),
            new DataPoint(27, 6000)
    };

    DataPoint[] pointsB = new DataPoint[]{
            new DataPoint(1, 3500),
            new DataPoint(2, 3400),
            new DataPoint(3, 3300),
            new DataPoint(4, 3200),
            new DataPoint(5, 3200),
            new DataPoint(6, 3200),
            new DataPoint(7, 3100),
            new DataPoint(8, 3100),
            new DataPoint(9, 3000),
            new DataPoint(10, 3000),
            new DataPoint(11, 3000),
            new DataPoint(12, 3000),
            new DataPoint(13, 3000),
            new DataPoint(14, 3000),
            new DataPoint(15, 3000),
            new DataPoint(16, 3000),
            new DataPoint(17, 3000),
            new DataPoint(18, 3000),
            new DataPoint(19, 3000),
            new DataPoint(20, 2900),
            new DataPoint(21, 2900),
            new DataPoint(22, 2800),
            new DataPoint(23, 2800),
            new DataPoint(24, 2700),
            new DataPoint(25, 2700),
            new DataPoint(26, 2600)
    };

PointsGraphSeries<DataPoint> seriesX = new PointsGraphSeries<>();
    seriesX.setShape(PointsGraphSeries.Shape.TRIANGLE);
    seriesX.setColor(Color.BLUE);
    seriesX.setTitle("This is X");
    plottedX = false;

    // If series has at least 1 equal DataPoint
    for (DataPoint a : pointsA) {
        for (DataPoint b : pointsB) {
            if (a.getX() == b.getX() && a.getY() == b.getY()) {
                seriesX.appendData(a, true, pointsB.length);
                plottedX = true;
            }
        }
    }
    /**
    * If exact pair of x and y is not available in both
    */
    if (!plottedX) {
        DataPoint plot = findIntersection(pointsA, pointsB);

        if (flagIfFoundX) {
            seriesX.appendData(plot, true, pointsB.length);
            flagIfFoundX = false;
        }
    }

/**
 * Method to check whether two line segments intersect with each other
 * https://www.geeksforgeeks.org/program-for-point-of-intersection-of-two-lines/
 */
public DataPoint findIntersection(DataPoint[] line1, DataPoint[] line2) {

    /**
     * https://www.geeksforgeeks.org/program-for-point-of-intersection-of-two-lines/
     *
     * determinant = a1 * b2 - a2 * b1
     * if (determinant == 0) {
     *     // Lines are parallel
     * }
     * else {
     *     x = (c1*b2 - c2*b1) / determinant
     *     y = (a1*c2 - a2*c1) / determinant
     * }
     * ---------
     * Example:
     * ---------
     * Input : A = (1, 1), B = (4, 4)
     *         C = (1, 8), D = (2, 4)
     * Output : The intersection of the given lines
     *          AB and CD is: (2.4, 2.4)
     *
     * Input : A = (0, 1), B = (0, 4)
     *         C = (1, 8), D = (1, 4)
     * Output : The given lines AB and CD are parallel.
     */


    for (int i = 0; i < line1.length; i++) {
        int nextI = i;
        nextI++;
        if (nextI == line1.length) break;

        for (int j = 0; j < line2.length; j++) {
            int nextJ = j;
            nextJ++;
            if (nextJ == line2.length) break;
            DataPoint d = checkIntersecting(line1[i], line1[nextI], line2[j], line2[nextJ]);
            if (flagIfFoundX) {
                return d;
            }
        }
    }
    return null;
}

/**
 * Method to check whether segment AB and segment CD intersect with each other
 * https://www.geeksforgeeks.org/program-for-point-of-intersection-of-two-lines/
 *
 * @param A point A of segment AB
 * @param B point B of segment AB
 * @param C point C of segment CD
 * @param D point D of segment CD
 * @return DataPoint null if segments are not intersecting
 * otherwise intersection point
 */
public DataPoint checkIntersecting(DataPoint A, DataPoint B,
                                   DataPoint C, DataPoint D) {
    // Line AB represented as a1x + b1y = c1
    double a1 = B.getY() - A.getY();
    double b1 = A.getX() - B.getX();
    double c1 = a1 * (A.getX()) + b1 * (A.getY());

    // Line CD represented as a2x + b2y = c2
    double a2 = D.getY() - C.getY();
    double b2 = C.getX() - D.getX();
    double c2 = a2 * (C.getX()) + b2 * (C.getY());

    double determinant = a1 * b2 - a2 * b1;

    if (determinant == 0) {
       // The lines are parallel. This is simplified
       // by returning a pair of FLT_MAX
       // return new DataPoint(Double.MAX_VALUE, Double.MAX_VALUE);
        return null;
    } else {
        double x = (b2 * c1 - b1 * c2) / determinant;
        double y = (a1 * c2 - a2 * c1) / determinant;

        // check if the point lies on given line segment
        /* To check if "x" is between "a" and "b";

          int m = (a+b)/2;

          if(Math.abs(x-m) <= (Math.abs(a-m)))
          {

          }
         */
        double mx1 = (A.getX()+B.getX()) / 2;
        double mx2 = (C.getX()+D.getX()) / 2;
        double my1 = (A.getY()+B.getY()) / 2;
        double my2 = (C.getY()+D.getY()) / 2;
        if (Math.abs(x-mx1) <= Math.abs(A.getX()-mx1)
                && Math.abs(x-mx2) <= Math.abs(C.getX()-mx2)
                && Math.abs(y-my1) <= Math.abs(A.getY()-my1)
                && Math.abs(y-my2) <= Math.abs(C.getY()-my2)) {
            flagIfFoundX = true;
            return new DataPoint(x, y);
        }
        return null;
    }
}
Sandeep Yohans
  • 929
  • 1
  • 14
  • 36