Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find max height-width of irregular shape drawn on HTML 5 canvas

I've been doing some image processing recently, and am looking for a javascript solution to determine the longest line segment that is entirely within a non-regular shape. To sum it up, the line segment should be the longest line segment that touches the shape and not overlaps or moves outside of the shape.

Here are the steps which I have followed

step 1:

enter image description here

step 2:

enter image description here

step 3:

enter image description here

as shown in step 3 Blue line indicates max length. It is working perfectly to determine the length of regular shapes, but in case of irregular shapes it is not working (also in the case of 3 points).

To calculate length first I have taken points (which are mouse coordinates on the canvas down event.

Here is the snippet for Canvas down :

function getXY(e) {
    var el = document.getElementById('canvas');
    var rect = el.getBoundingClientRect();
    /* console.log("widht "+$("#canvas").width());
    console.log("heihgt "+$("#canvas").height());
    console.log("X "+Math.round(e.clientX - rect.left));
    console.log("y "+Math.round(e.clientY - rect.top));*/
    return {
        x: Math.round(e.clientX - rect.left),
        y: Math.round(e.clientY - rect.top)
    }
}


 $('#canvas').mousedown(function(e) {
        var can = document.getElementById("canvas");
        var ctx = can.getContext('2d');
        if (condition == 1) {
            if (e.which == 1) {
                //store the points on mousedown
                var poss = getXY(e);
                i = i + 1;
                if (firstX == poss.x && firstY == poss.y) {
                    console.log(" inside if  poss.x===" + poss.x + " poss.y===" + poss.y);
                    //$('#crop').click();
                } else {
                    console.log(" inside else  poss.x===" + poss.x + " poss.y===" + poss.y);
                    points.push(Math.round(poss.x), Math.round(poss.y));
                    pointsforline.push({ "x": Math.round(poss.x), "y": Math.round(poss.y) });
                    xarray.push(poss.x);
                    yarray.push(poss.y);
                    sendpoints.push(Math.round(poss.x), Math.round(poss.y));
                    if(points.length >= 6){
                        $('#fixMarkingBtn').show();
                    }
                }

                // Type 1 using array


                 if(points.length == 6  && sendpoints.length ==6 ){
                 $('#fixMarkingBtn').show();
                 }

                // Type 2 using counter

               /* if (i == 3) {
                    $('#fixMarkingBtn').show();
                }*/

                if (i == 1) {
                    $('#undoMarkingBtn').show();
                    $('#resetMarkingBtn').show();
                    firstX = poss.x;
                    firstY = poss.y;
                    //change is here
                    Xmax = poss.x;
                    Ymax = poss.y;
                    Xmin = poss.x;
                    Ymin = poss.y;
                    minX1 = poss.x;
                    maxY1 = poss.y;
                    minX1 = poss.x;
                    minY1 = poss.y;

                }
                if (poss.x < Xmin) {
                    Xmin = poss.x;
                    minY1 = poss.y;
                }
                if (poss.x > Xmax) {
                    Xmax = poss.x;
                    maxY1 = poss.y;
                }
                if (poss.y < Ymin) {
                    Ymin = poss.y;
                    minX1 = poss.x;
                }
                if (poss.y > Ymax) {
                    Ymax = poss.y;
                    maxX1 = poss.x;
                }
                ctx.globalCompositeOperation = 'source-over';
                var oldposx = $('#oldposx').html();
                var oldposy = $('#oldposy').html();
                var posx = $('#posx').html();
                var posy = $('#posy').html();
                ctx.beginPath();
                ctx.lineWidth = 13;
                ctx.moveTo(oldposx, oldposy);
                if (oldposx != '') {
                    ctx.lineTo(posx, posy);
                    ctx.stroke();
                }
                $('#oldposx').html(poss.x);
                $('#oldposy').html(poss.y);
            }
            ctx.fillStyle = 'red';
            ctx.strokeStyle = 'red';
            ctx.fillRect(posx, posy, 10, 10);
            $('#posx').html(posx);
            $('#posy').html(posy);
        } //condition

    });

here is the code I have used (point of problem) :

function calMaxMin() {
    for (var i = 0; i < points.length; i += 2) {
        if (i == 0) {
            Xmax = points[i];
            Ymax = points[i + 1];
            Xmin = points[i];
            Ymin = points[i + 1];
            minX1 = points[i];
            maxY1 = points[i + 1];
            minX1 = points[i];
            minY1 = points[i + 1];
        }
        if (points[i] < Xmin) {
            Xmin = points[i];
            minY1 = points[i + 1];
        }
        if (points[i] > Xmax) {
            Xmax = points[i];
            maxY1 = points[i + 1];
        }
        if (points[i + 1] < Ymin) {
            Ymin = points[i + 1];
            minX1 = points[i];
        }
        if (points[i + 1] > Ymax) {
            Ymax = points[i + 1];
            maxX1 = points[i];
        }    
    }
}

Problem image 1

enter image description here

Problem image 2 (what I'm getting right now)

enter image description here

Expected output

enter image description here

Any help would be appreciated.

Thanks in advance!

like image 933
Jigar Shah Avatar asked Nov 17 '17 11:11

Jigar Shah


People also ask

How to set height and width of canvas in HTML5?

To set the height and width canvas HTML5 has two attributes: Height: With the help of Height attribute we can set the height. Width: With the help of Width attribute we can set the width.

How many pixels is a canvas in HTML5?

By default, the height of a canvas element is set to 150 pixels, and the width is set to 300 pixels. We can create many shapes like rectangle, circle, squares, cone, and other custom shapes. HTML5 provides us many elements to create different shapes like Canvas curves and Canvas paths.

How do I use HTML5 canvas to draw?

Using HTML5 Canvas effectively requires a strong foundation in drawing, coloring, and transforming basic two-dimensional shapes. While the selection of built-in shapes is relatively limited, we can draw any shape we desire using a series of line segments called paths , which we will discuss in the upcoming section Using Paths to Create Lines.

What is a canvas element?

The canvas element is just like any other block-level element on a web page, consisting of height and width definitions. By default, the height of a canvas element is set to 150 pixels, and the width is set to 300 pixels. We can create many shapes like rectangle, circle, squares, cone, and other custom shapes.


1 Answers

The problem's complexity changes when you switch from a convex polygon to a concave polygon: you need to check for intersections and "grow" candidate segments.

With a convex polygon, you have one candidate set, defined by all segments (p1, p2), (p1, p3), ..., (p2, p3), ..., (pn-1, pn), wherein the longest of those candidates is the result:

This example has a total 10 candidates. You simply select the longest one.


When you include concave polygons you must modify the candidate segments to stretch to the edges of the polygon and exclude any segments that intersect the polygon.

The red segments are excluded. The green segments are the modified ones. There are more complicated cases not depicted as well.

NOTE: I've had to play quite a bit with this math in the past and will be linking to functions of an old JavaScript library I built. Points are represented as { x: number, y: number} and polygons as arrays of points.

Segments can be excluded for two reasons:

  1. Either endpoint starts with the segment leaving the polygon. You can test this by getting the global angle of the candidate segment (from said endpoint) and the global angles of the two adjacent polygon edges and checking if the candidate segment's angle falls between those two.

  2. The candidate segment intersects any of the edges (inclusive of edge endpoints).

Extension of segments is somewhat complicated:

  1. Find all segments wherein either endpoint is a concave vertex of the polygon. Include it twice if both endpoints are concave.

  2. For said (segment, endpoint) pairs, stretch the segment through the endpoint a long distance (like 10000000) via polar projection.

    1. Detect all intersection points of the elongated segment with the polygon.

    2. Find the intersection point that is nearest the unmodified endpoint. This intersection point and the unmodified endpoint is the new candidate segment.

The result is the longest remaining candidate segment.

HINT: Might I recommend using GeoGebra for diagramming (I am in no way affiliated)?

like image 166
vox Avatar answered Oct 27 '22 12:10

vox