-
Notifications
You must be signed in to change notification settings - Fork 129
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
Added text wrapping, consolidated text operations into new file #1542
base: master
Are you sure you want to change the base?
Conversation
I'm not sure if there is anything that needs editing in .openscad_docsgenrc for adding this new file, but I recommend checking it out. |
Typo "paragraph" in docs. Should indent function bodies. For consistency probably "text_array" instead of "textarray". (Note: before BOSL2 I never used underscores; that was Revar's requirement.) The text_array_boundingbox function doesn't return a bounding box, only a width and height. Maybe it should be renamed text_array_size? The array_text() module maybe should be rolled into text()? That is, if you pass a string it calls the current code and if you pass an array of strings or array of array of strings (?) it calls the new code. Also, this module doesn't have any attachable handling, which is bad. You should always call attachable() unless there's some very compelling reason you can't, in which case you need to manually support a bunch of stuff---so many things actually that half of them are missing from text() because I didn't realize I needed to add them there. But in particular, take a look at text(). Do you see all the stuff in there that sets $ variables and so on. If you don't call attachable you need to do all that stuff...and more. (Take a look at attachable and what it does when it creates the main child object and then the rest of the children. All that should be happening in text....and in array_text().) If array_text stays as a separate module I'm not sure about the name. Maybe it should be text_array() if it stays separate? But also, it should be grouped with text() as a rendering module in the docs. Maybe this is obvious, but we always need to think about laying our our code in the way that makes the most sense for a user reading the docs, NOT the way that makes the most sense for a programming reading the code! |
Hmmm. Relatively new no-arg version of attachable() may eliminate need to avoid attachable(), though some manual setting may still be necessary for $ variables. There's at least one line ending with ':' where the ':' could go to the next line. |
It looks like using attachable() with no args can indeed replace the stuff currently in text() and text3d() and provides added functionality. It looks to me like you have basically reimplemented the anchoring transform for a box instead of just invoking attachable() in array_text(), so it seems like you ought to be able to just invoke attachable with a size arg. |
The main reason, I think, why text() and text3d() don't do it that way is that they are designed to work in the stable OpenSCAD where we do not know the dimensions of the text. |
I note that the text() implementation can't have things attached to it, in fact the docs for text() state "You cannot attach children to text." All that's needed is to for it to be attachable with an anchor. That's what I was going for too. I tested it, and there's one example using the anchor. Merging array_text() into text() might save me the trouble of having to figure out attachments again. There may be a complication in that with multi-line text, How is a bounding box defined if not with width and height? Those are the dimensions of the box. The position of the box depends on the anchor. I could call it something besides bounding box, maybe I tend never to use underscores in variable names, just in module and function names. Not a problem to change, however. |
The reason you cannot attach children to text is that we don't know where the text is because we don't know it's size, so it is simply impossible to implement attachment. This is not true for text_array because you are assuming you have its dimensions, so what reason is there to not support attachment by just using attachable, which makes your code much simpler....and even more so when you consider what you'd need to add to make everything work without it. All the other attachable features need to work, so you need to make sure that tagging, highlighting, colors and attachment and so on all work. As I said, text() and text3d() are actually broken right now because highlighting and ghosting don't work. A bounding box is a size and position. As you say, this depends on the box position, hence it doesn't make sense to say you're producing a bounding box. Native OpenSCAD and hence also BOSL2 use "size" to refer to the dimensions of rectangles and cubes so the name should be text_array_size(). As I said, I don't use underscores at all...except in BOSL2 where we use them in all user-facing identifiers to separate all words. Merging array_text() into text() will not save you any effort because you're going to have to do it as a simple two-way conditional, where you invoke the old code if the old OpenSCAD is running and you have a single string, otherwise you invoke the new code. Keep in mind that attachable does a ton of stuff. If you want attach() to work right you need to make sure you have set all the right $ variables, for example, and set a geometry type. Getting all of that right is much harder than just invoking attachable(), and in this case no weird anchor overrides are required, so it's straight forward. The poor man's quasi-anchoring currently available in text() and text3d() is not something to aspire to. It's a workaround hack. This does raise a question, though, about anchoring consistency across versions. You can ban children like we do right now, but that seems a bit unfortunate. One would actually like to be able to do things like |
The only way to get the bounding box is to use textmetrics, which doesn't exist in 2021.01. Perhaps text() could be modified to use this and then the full attachment capabilities would be possible. Because the bounding box (which I shall rename to text_array_size) is a rectangle, and that's all we're concerned about for the purpose of attachments, how about for now I make the attachments the same as with square()? The more I think about it, the more I think array_text() should be separate from text(). There are minor differences that could lead to confusion if mashed together into the same module:
P.S. Instead of repurposing |
I think you're right that we should not wrap the new functionality into text(). I was losing sight of the fact that text() is a native openscad command. Your command should be a complete replacement for text and I'm not sure what it should be called, but I feel like it shouldn't have "array" in the name. It's just the new better command for doing text, like we have rect as an alternative to square and cuboid as an alternative to cube. There should probably also be a 3d version like text3d. I don't understand what the line_spacing parameter does. There should be a correct line spacing, which should be the default. The "spacing" parameter is also probably something questionable that perhaps isn't needed. Adding space between letters in a font is typographically bad generally speaking. The font was designed with the correct spacing. But the spacing parameter adds a multiplier which creates a ridiculous look. There's no reason you'd ever want to use it. If you actually wanted to screw up the font by spacing letters apart I think you'd want to add a fixed amount between each letter, not a proportional amount. It might also be appropriate for a BOSL2 font replacement module to fix the 0.72 factor bug in the font sizes. I'm not sure about that, though. |
The latest commit has some It works fine for snapshot OpenSCAD, but for 2021.01 it has weird behavior with parameters changing values. Try this test in a snapshot and in 2021.01.
The |
The default is I frequently make use of the |
Line spacing (also known as line height) is indeed commonly used and quite important for having the ability to control it effectively.
As an application and web developer with a UX background, I would disagree. There are valid use cases - for example, increasing letter spacing for buttons or headlines to enhance visibility and clarity. |
@amatulic For what it's worth, I’d love to see a version of
|
@Jasonkoolman - everything is already finished with respect to text justification, centering, line wrapping etc. The problem now is that we're considering making all of this into a wholesale replacement for BOSL2's existing However, when I made this PR I never intended to replace |
Thanks for the clarification! I’m not sure I fully understand the complexity of anchoring. In my mind, I’m imagining an extruded 2D shape with a rectangular bounding box. Are you thinking about adding anchors to the individual ‘faces’ of characters/glyphs, something of that nature? |
@Jasonkoolman - the anchors and attachment points would be at the center, corners, and edges of the text bounding box, as well as the left, center, and right ends of the text baseline. |
I took a break from this mainly because I'm having trouble reconciling what we need to do. In the meantime I finished a PR for isosurfaces and metaballs. Questions for @adrianVmariano
Something to think about for 3D text: in this golf ball stencil I designed, the text isn't just extruded, each character is extruded with scaling so that each character glyph occupies a solid angle of the sphere rather than a rectangular prism, resulting in elements of each glyph being mostly perpendicular to the sphere surface. New modules like text_cylinder() and text_sphere() might be useful with this sort of scaling. But for now I want to focus on the 2D problem. |
https://stackoverflow.com/questions/2090302/word-wrap-algorithms-for-japanese indicates that it may have wildly different wrapping conventions, and since we don't understand all those things, it seems like it should wait for a user request from someone who does. Arabic and Hebrew both have words formed from groups of letters separated by spaces that get wrapped the normal way, so supporting right to left seems reasonable. It belatedly occurs to me that people write English in ttb direction sometimes. I'm inclined to say that word wrapping is not important for this case---people don't write paragraphs that way, usually just a single line. So...that again leaves just horizontal text. I read your question again, though and maybe you're asking for how the UI specifies direction? If that's what you want, I think that direction_primary and direction_secondary is too verbose. I'd favor your other proposal, which I assume was meant to be a string option. There is the question about whether abbreviated defaults are permitted, though, like "ttb" is the default if you only give "ltr" or "rtl". I think that would make sense. This is probably worth bringing up on the chat to see if anyone has a better idea.
5 and 6. I asked Jordan what he thought about specifying size and he suggested a case I hadn't thought of, but which I think we should support, which is creating a text that fits into a specified box. That is, you scale the font so the text fits. So it could be that you give no font size but you give a box size and then the text is made to fit into the box. I'm not sure how you'd decide on the number of lines. This whole category seems like it needs additional consideration. You could just specify the actual height. You could specify just the actual width. You could specify the height of the nominal ascender that is given by font metrics, though we might want to check if that seems to match up with anything. I recall vaguely some confusion in the past about what those values actually meant. But maybe it was the "max" values that were confusing. One thing I think we absolutely should provide is a way to specify fonts using the conventional font size, which means giving the font size as the OpenSCAD size multiplied by 0.72. This is how fonts are specified in every other system in the world and is the universal standard for describing font sizing. Another thing to be alert to is that if we provide a measure based on actual text size then two piece of text with the "same" size won't actually be the same size, and so they won't mate together. So it's important to have a clear distinction between setting font size and setting text size. Jordan also said this: Spacing around text is tricky. I just wrote a general name tag program (eg for luggage tags) and found, for instance, that I wanted to adjust spacing based on whether the text had descenders - and if it did, I wanted extra spacing above the text for symmetry.
However, Jordan noted that OpensCAD requests all fonts at a fixed size. (He said 1000 units.) This means that potentially fonts in OpenSCAD will not be well formed and we might possibly be abusing the fonts systematically in OpenSCAD when using them at smaller sizes. This suggests that there might possibly be an application for letter spacing in these fonts. But the way OpenSCAD does it is clearly wrong, where it inserts space after a letter that is proportional to the letter: If we're going to support letterspacing or tracking I think the right way to do it is to insert a fixed constant space between every pair of letters. That space should probably be specified in units of em so it's tied to the font size. This would need to be done manually by the code, where each letter is positioned and the extra space added. And then there's the problem of ligatures. If you break the font up into letters you'll break the ligatures, since you don't know where they are. This was one issue I had with path_text where there was really no way to preserve ligatures. |
To me this makes no sense at all, sorry. When I look at the font spec data, I see nothing in there corresponding to that ratio. The ascender is typically less in proportion to the total font height. When I google for 72% in the context of fonts, I find nothing to support the notion that this practice even exists, let alone being a worldwide standard. I feel we should do away with it altogether. To most people it's obscure, if it exists at all. If they request a font size, they expect a character glyph to be that height. |
@adrianVmariano Regarding letter spacing: At the Chamber of Commerce, we leverage letter spacing to enhance readability in specific use cases, a practice supported by A/B testing and user research. For instance, wider letter spacing has proven effective in improving comprehension and usability. I’d also like to reference Figma's definition of letter spacing, which states:
That said, I agree that most fonts are already configured with well-optimized spacing by their designers, and manually adjusting tracking can sometimes feel unnecessary or overly complex. In many cases, it’s best to trust the typeface and use it as intended unless there’s a specific need. I enjoyed the quote you shared - it’s a fun take, but I’m not sure how realistic it is in today’s design landscape. No offence, just sharing my honest opinion. Keep up the great work, and thanks for this beautiful library! |
@Jasonkoolman I open to the possibility that I'm missing something here (and generally speaking). The sources I found generally seemed to suggest that for lower case text there was a "right" letter spacing and that deviations in either direction resulted in decreased readability. The notion that you can improve readability by increasing letter spacing would then depend on whether the baseline letter spacing is the "right" one. If the font is properly designed, its letter spacing should be the right one, and modifying the letter spacing will make it worse. If increasing letter spacing always makes fonts easier to read it raises a question about why all fonts are mis-designed so that they are harder to read than necessary. There's another possibility, which is that increasing letter spacing helps people with dyslexia but hurts comprehension for people without. Has that been tested? Certainly, the examples I've seen labeled as "too much space" appear harder to read to me, not easier. (I am not dyslexic, and I read a LOT.) It is obviouis that increasing letter spacing will at some point decrease readability. I looked for something about dyslexia and found this https://www.bdadyslexia.org.uk/advice/employers/creating-a-dyslexia-friendly-workplace/dyslexia-friendly-style-guide which is oddly hard to read for a site on readability. They claim that letter spacing of "35%" of average letter width makes text readable for dyslexics. I don't know what that means. If it means add 35% of the average letter width between every letter I'm pretty sure that will result in something dramatically less readable for non-dyslexics, because it will separate the letters too much and break up the word form. Reading does not involve looking at the individual letters. "A study of 61 sixth-grade children, 29 of whom had dyslexia, found that students with dyslexia needed larger letter spacing to identify letters than do students without dyslexia." Reading is not "identifying letters". But it could suggest that only dyslexics benefit from increased letter spacing. It appears that serif fonts are easier to read in print, but sans serif fonts are easier to read for dyslexics, so that appears to be an example where the thing best for accessibility is not the universal best. On screens, it appears that due to limitations of resolution, sans serif fonts have generally been found easier to read. (I wonder if this is still true on modern smartphones whose dpi resolution can be 460 ppi.) I know that I have a personal preference for reading serif fonts in print, but I'm not sure if that's just due to familiarity or what. In the OpenSCAD context, there is the question of what capabilities we should actually provide. If fonts are mis-designed or being abused because of how they are scaled, then tracking may be advantageous. There may also be some artificial reasons to increase tracking, such as to space letters apart far enough so that low resolution 3d printing creates a clear separation. For this reason, supporting increased letter spacing may be sensible. But it would need to be done "manually" rather than through the font engine, and would break ligatures. There are plenty of fonts without ligatures, though. I do wonder about how ligatures and tracking are expected to interact. Nobody ever mentions ligatures when discussing tracking. The other question is, what is the unit to use for specifying the space to add. Should it be absolute units, or relative to the font size? Nobody is very clear on the right way to specify tracking. And a "percentage of average letter width" is a pretty horrible measure to try to apply, especially when generalizing to Chinese, or thai. |
From my perspective (making fonts for 3D printing) letter spacing is totally irrelevant to readability, and 100% relevant to printability. The default spacing, especially for small fonts, is always too small, like less than a line width, which is really bad for printing engraved text in the top or bottom of a part. It matters also when printing text on the side of a part, to prevent characters from running together. In any case, I think it is best to let OpenSCAD's internal text spacing to take care of things. That's what my word wrapping algorithm does already, you specify a letter spacing other than 1.0 if you want, and the textmetrics account for it. If it breaks ligatures, I don't know, and it's none of my business to know or care, I assume OpenSCAD handles this with spacings greater than 1. This has worked very well for me so far in other projects where I had to wrap text around objects, it just comes out well with spacing=1.1 usually. I get the point about holding off on vertical word-wrapping; some vertical Japanese text has no spaces at all, even though it may have some punctuation. Other vertical text I've seen does use spaces, and these would make sense to word-wrap. |
You absolutely cannot let OpenSCAD's internal "spacing" argument take care of anything. We shouldn't even pass through to that argument. It's completely broken, absolute garbage. It adds space that is proportional to the letter that occurred before. This is WRONG, it looks terrible, isn't readable, and doesn't fit the 3d printing needs either, where you'd want to add an extrusion width gap or something like that. Jordan was mystified by this implementation and can't imagine why anybody would have implemented it that way. Do you not think that "timing" looks odd in the above example I posted? To me it reads as 3 words, "Tim", "in" and "g". The space added between letters needs to be constant. So if letterspacing adjustment is to be done, it needs to be done manually by the code, not relying on OpenSCAD's broken implementation. It may be the case that given 3d printing needs, the right way to specify additional space would be in absolute units rather than in font-dependent units. I'm not sure. Perhaps both options could be permitted. |
@adrianVmariano You’re probably right that the use cases for letter spacing are exceptions to the rule. I’ve also come across contradictory information online, and it’s possible that we avoid applying letter spacing exclusively to lowercase letters—I’d need to confirm with the designers. For what it’s worth, I came across a similar discussion about multiline text on the OpenSCAD GitHub repo. I’ve written a simple |
@Jasonkoolman for 3D printing applications I have always needed to apply letter spacing, because by default, text is too close together to resolve properly on a 3D printer. Letter spacing was implemented in this PR as using OpenSCAD's internal spacing, which Adrian has convinced me is the wrong approach, and I'm fixing that up today. This PR also handles multi-line text -- it has to, because the original point of this PR was to provide automatic word-wrapping -- with left, right, center, and full justification. As is, this PR could be merged into BOSL2 to add a new capability without affecting anything else, but now we've decided to replace BOSL2's existing text() features with a new more robust write() feature that would include wordwrapping, and fix OpenSCAD's spacing issues while we're at it. A minor complication to all this is the need to support the obsolete 2021.01. I wish OpenSCAD would have another stable release. I still use 2021.01 for error verification but I rarely encounter anyone else who uses it in everyday work. |
@amatulic That could very well be true. I’ve built quite a few scripts involving text (the latest being StampMaker, which is currently trending). So far, they seem to work well with the default letter spacing for 3D printing.
I agree. This is a frustrating limitation that hampers innovation. While I truly enjoy working with OpenSCAD, the slow progress and lack of modern package management, roadmapping, and efficient release cycles are concerning. Still, it doesn’t stop us from pushing the boundaries and creating some incredible projects, which this library is certainly doing. Your |
@Jasonkoolman - well with large fonts like in that stamp, I agree the default spacing is fine. Most of my projects involve small fonts down to 4 mm, and I even have a font I customized to help me print that small. Another complication here is feature creep for things I hadn't planned but I think are a good idea, like instead of specifying a font size, you specify a box dimension and some text, with a margin, and the function finds the font size and positioning to fit the text the box with that margin, wrapping if needed. |
@Jasonkoolman It may take a bit longer, but I'm confident that we'll have a nice capability once this is ready. I think it's OK to make the new function available only in OpenSCAD versions that have textmetrics. |
Thank you. That makes things tidier. |
There's too much of this that just wouldn't work without textmetrics. Just have it throw an error with a message to the effect that write() is only supported in OpenSCAD versions that have textmetrics, versions XXX and above. |
Re-tested examples, did some minor grammar fixing in comments.