maker.js icon indicating copy to clipboard operation
maker.js copied to clipboard

time to compute combineUnion

Open akshaynikhare opened this issue 3 years ago • 4 comments

we are building a too for a Vinyl printing shop and we need to optmize a lot of text in a model. few of our font have complicated geometry like below , and the text overlap, we are using "combineUnionfor" for every letter in the text , but its taking too long to get an output , image

so the Question is does combineUnion take this long to compute the path (very long about 20-30 seconds for the below code which can be tested in playgraound )

here is my code

var makerjs = require('makerjs');
var computeLayout = require('opentype-layout');
function DraftText(font, text, fontSize) `{`
        var textModel = { models: {} };
        var scale = 1 / font.unitsPerEm * fontSize;
        var layoutOptions = {
            lineHeight: 1 * font.unitsPerEm,
            width: 500 / scale
        };
        var layout = computeLayout(font, text, layoutOptions);
        layout.glyphs.forEach((glyph,i) => {
            var character = makerjs.models.Text.glyphToModel(glyph.data, fontSize);
            character.origin = makerjs.point.scale(glyph.position, scale);
            makerjs.model.simplify(character, { pointMatchingDistance: 0.001 });
            makerjs.model.combineUnion(textModel, character);
            makerjs.model.addModel(textModel, character, i);
         });
        return textModel;
    }
function Nameplate(font,font_scale, text,icon ) {
   var textModel = DraftText(font, text, font_scale);
   this.models = {
        text: textModel
   };
   makerjs.model.zero(this);
   this.units = makerjs.unitType.Millimeter;
}
Nameplate.metaParameters = [
    { title: "font", type: "font", value: '*' },
    { title: "font size", type: "range", min: 10, max: 200, value:  20},
    { title: "text", type: "text", value: 'Hello World! This box should start word-wrapping!' }
];
module.exports = Nameplate;

am i doing something wrong?

akshaynikhare avatar Dec 03 '20 21:12 akshaynikhare

Hello, no it's nothing you are doing wrong. Currently it is a brute force naïve O-squared implementation. I have been working on a solution to this for a while, but I do not have release-ready results yet. If you're brave enough to try, see the https://github.com/microsoft/maker.js/tree/combine-sweep-expand-wip branch.

The workaround you can do now is to cache as much as possible. Perhaps offline you can run kerning pairs of characters to see which overlap and which do not, and grab pre-computed characters instead of a "live" union. Hopefully that makes sense.

danmarshall avatar Dec 04 '20 01:12 danmarshall

Can we not make the complete process GPU based it will increase the time to process.

On Fri, Dec 4, 2020, 06:31 Dan Marshall [email protected] wrote:

Hello, no it's nothing you are doing wrong. Currently it is a brute force naïve O-squared implementation. I have been working on a solution to this for a while, but I do not have release-ready results yet. If you're brave enough to try, see the https://github.com/microsoft/maker.js/tree/combine-sweep-expand-wip branch.

The workaround you can do now is to cache as much as possible. Perhaps offline you can run kerning pairs of characters to see which overlap and which do not, and grab pre-computed characters instead of a "live" union. Hopefully that makes sense.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/microsoft/maker.js/issues/477#issuecomment-738481838, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACKGLGD7FFKT57QAM6CN2OTSTAYH7ANCNFSM4UMSCRZQ .

akshaynikhare avatar Dec 04 '20 05:12 akshaynikhare

Sharing this in case someone else runs into this. When you don't know if the font requires combining, the combineUnion calculations are wasted most of the time. In most fonts, letters are very well separated. This can be improved by first comparing the 'bounding box' of the letters before combining them into one model. Like this:

for ( let i = 1; i < size; i++ ) {
	let extend1 = makerjs.measure.modelExtents( { models: combinedModels } );
	let extend2 = makerjs.measure.modelExtents( models[ i ] );

	// When the model extension is not an object, assume it is a space.
	// It also assumes that the first character is not a space.
	// So before this function, the text should have been trimmed.
	if ( ! isObject( extend2 ) ) {
		continue;
	}

	// Combining is very slow, so first check if the measurements are overlapping.
	// If they don't overlap, we are guaranteed that we don't have to combine.
	if ( makerjs.measure.isMeasurementOverlapping( extend1, extend2 ) ) {
		makerjs.model.combineUnion( { models: combinedModels }, models[i] )
	}

	combinedModels = {
		...combinedModels,
		[ i ]: models[ i ],
	}
}

This cool trick also exists in the some of the code of Maker.JS 😁

atimmer avatar Feb 10 '21 11:02 atimmer

@atimmer this might work for some of the font, which is actually good , i will try this in my code 🤞

akshaynikhare avatar Apr 04 '21 15:04 akshaynikhare