Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

time to compute combineUnion #477

Open
akshaynikhare opened this issue Dec 3, 2020 · 4 comments
Open

time to compute combineUnion #477

akshaynikhare opened this issue Dec 3, 2020 · 4 comments

Comments

@akshaynikhare
Copy link

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?

@danmarshall
Copy link
Contributor

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.

@akshaynikhare
Copy link
Author

akshaynikhare commented Dec 4, 2020 via email

@atimmer
Copy link

atimmer commented Feb 10, 2021

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 😁

@akshaynikhare
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants