2

I need to draw a line in the following manner:

Example  

For now, it will be only drawn in code, no user input.

My question is, how to draw perpendiculars to a line, if I draw it point by point? (Obviously, this will be the case, because drawing with bezier curves will not give me the possibility to somehow impact the drawing).

The closest answer I found was possibly this one, but I can't reverse the equations to derive C. Also there is no length of the decoration mentioned, so I think this will not work as I'd like it to.

Community
  • 1
  • 1
Angelore
  • 63
  • 4
  • So you will draw the curve using small line segments only ? Do you have some code for the draw already ? – GameAlchemist Dec 24 '14 at 10:46
  • Well, I have one with user input, I will just slightly modify it to draw from point array. http://jsbin.com/zecohezovi/1/edit?html,js,output – Angelore Dec 24 '14 at 11:02

2 Answers2

5

Find the segment perpendicular to another one is quite easy.
Say we have points A, B.
Compute vector AB.
Normalize it to compute NAB (== the 'same' vector, but having a length of 1).
Then if a vector has (x,y) as coordinates, its normal vector has (-y,x) as coordinates, so you can have PNAB easily (PNAB = perpendicular normal vector to AB).

// vector AB
var ABx =  B.x - A.x ;
var ABy =  B.y - A.y ;
var ABLength = Math.sqrt( ABx*ABx + ABy*ABy );
// normalized vector AB
var NABx = ABx / ABLength;
var NABy = ABy / ABLength;
// Perpendicular + normalized vector.
var PNABx = -NABy ;
var PNABy =  NABx ;

last step is to compute D, the point that is at a distance l of A : just add l * PNAB to A :

// compute D = A + l * PNAB
var Dx = A.x + l* PNAB.x;
var Dy = A.y + l *PNAB.y;

Updated JSBIN :

http://jsbin.com/bojozibuvu/1/edit?js,output

Edit : A second step is to draw the decorations at regular distance, since it's Christmas time, here's how i would do it :

http://jsbin.com/gavebucadu/1/edit?js,console,output

function drawDecoratedSegment(A, B, l, runningLength) {
    // vector AB
    var ABx = B.x - A.x;
    var ABy = B.y - A.y;
    var ABLength = Math.sqrt(ABx * ABx + ABy * ABy);
    // normalized vector AB
    var NABx = ABx / ABLength;
    var NABy = ABy / ABLength;
    // Perpendicular + normalized vector.
    var PNAB = {  x: -NABy,  y: NABx    };
    // 
    var C = { x: 0, y: 0    };
    var D = { x: 0, y: 0    };
    //
    drawSegment(A, B);
    // end length of drawn segment
    var endLength = runningLength + ABLength;
    // while we can draw a decoration on this line
    while (lastDecorationPos + decorationSpacing < endLength) {
        // compute relative position of decoration.
        var decRelPos = (lastDecorationPos + decorationSpacing) - runningLength;
        // compute C, the start point of decoration
        C.x = A.x + decRelPos * NABx;
        C.y = A.y + decRelPos * NABy;
        // compute D, the end point of decoration      
        D.x = C.x + l * PNAB.x;
        D.y = C.y + l * PNAB.y;
        // draw
        drawSegment(C, D);
        // iterate
        lastDecorationPos += decorationSpacing;
    }
    return ABLength;
}
GameAlchemist
  • 18,995
  • 7
  • 36
  • 59
  • Upvote for nice answer. If you want to get fancy you could save all the mousemove points and draw the perpendicular ticks at uniform distances from each other. – markE Dec 24 '14 at 19:07
  • 1
    @MarkE : Well after all it's Christmas time, so here we go :-) Yo ! – GameAlchemist Dec 24 '14 at 20:12
1

All you need is direction of curve (or polyline segment) in every point, where you want to draw perpendicular. If direction vector in point P0 is (dx, dy), then perpendicular (left one) will have direction vector (-dy, dx). To draw perpendicular with length Len, use this pseudocode:

Norm = Sqrt(dx*dx + dy*dy)   //use Math.Hypot if available
P1.X = P0.X - Len * dy / Norm
P1.Y = P0.Y + Len * dx / Norm

P.S. If you know direction angle A, then direction vector

(dx, dy) = (Cos(A), Sin(A))

and you don't need to calculate Norm, it is equal to 1.0

MBo
  • 77,366
  • 5
  • 53
  • 86