FlorisSteenkamp / MAT

Medial Axis Transform - Library
119 stars 23 forks source link

How to extract the points of SAT and follow the original order of a font-stroke? #3

Closed met-pub closed 4 years ago

met-pub commented 5 years ago

This is the font-stroke of character "乚" (though in SVG coordinates it is y-opposite): M 192 794 L 192 128 C 192 6 235 -23 374 -23 L 702 -23 C 843 -23 870 33 886 209 C 867 214 838 226 820 237 C 808 79 793 40 703 40 L 371 40 C 279 40 261 57 261 126 L 261 794 Z

Using this MAT tool, I can extract the SAT with a lot of SVG paths (but the order is wrong). What I wanna do is extracting the points of SAT (not paths) by following the original order, ie. from the first point near (192, 794).

How to do that? Thanks.

met-pub commented 5 years ago

Actually, this is what I'm looking for (but for nodejs): https://postgis.net/docs/ST_ApproximateMedialAxis.html

FlorisSteenkamp commented 4 years ago

Typically the cpNode (the traversal starting point representing a SAT point) of a Mat object is from the largest inscribed circle of the shape.

The code below will get you to a 'terminating end' or leaf point, however it could be any leaf point.

// assuming you have a Mat object here called 'sat'
let cpNode = sat.cpNode;
while (!cpNode.isTerminating()) {
    cpNode = cpNode.next
}
sat = new Mat(cpNode, undefined);

//... continue using 'sat' as you would before

If you really wish to start from about the same point as how the original shape was drawn you could find the cpNode with defining boundary point closest to that point first, as in (using Typescript here):

let startPoint = [192, 794]; // using your example here
let _cpNode = sat.cpNode;
let cpNode_: CpNode;
let bestSquaredDistance = Number.POSITIVE_INFINITY;
traverseEdges(_cpNode, cpNode => {
    let p = cpNode.cp.pointOnShape.p;
    // get squared Euclidean norm
    let sd = (startPoint[0] - p[0])**2 + (startPoint[1] - p[1])**2; 
    if (sd < bestSquaredDistance) {
        bestSquaredDistance = sd;
        cpNode_ = cpNode;
    }
});

sat = new Mat(cpNode_, undefined);

//... continue using 'sat' as you would before

But font outline glyphs are not (as far as I know) drawn to start from any specific point.

Also, if you are not going to use the paths of the SAT (typically quadratic bezier curves, but could also be lines or cubics) then you will compromise on accuracy so it might be advisable to sample several points on the path curves as needed. (Of course, if you only want a coarse representation you could simply use the endpoints of the path curves).

Hope that helps.

met-pub commented 4 years ago

Thanks, that really helps.