Conversation
|
@revarbat - BelfrySCAD generates the doc for text.scad without any problem, but I cannot figure out why it keeps failing here. The message in the error report doesn't clarify the situation. |
f88b538 to
c1f2f1a
Compare
|
Looking at the docs for write() I think that the letterspacing names should perhaps be letter_spacing, letter_space_em and letter_space_ref and they should all work the same way, namely that 0 adds no space, positive adds the designated amount of space and negative removes space. Having 1 be the "adds no space" option seems more confusing and also inconsistent since they don't all work that way. In fact, I feel a little uncertain that I understand exactly what they do...like is it multiplying the space...I think it's confusing. It basically implies that the operation is the incorrect thing that OpenSCAD currently does. It should be laid out as "There are three ways to letter space, either in CAD units, in units of em, or in units of "0" width (or $refchar)" and then they should all be clearly additive, with 0 meaning add no space. Is it right that we have max_width and max_height as the 2nd and 3rd positional parameters instead of box? I was imagining it the other way. The way things are now I wonder if The size section of the docs: I assume that you don't get a warning if you omit size but give em, say. I think you should delete the thing about what happens if it's omitted. Also include in the description of size the .72 relation to the em. Another concern is that you don't clearly indicate that these various options SET the font size. So they need to say something like "Set font size by specifying the height of the capital letter "H" in the font (or $refchar_cap if it is set) " I notice you use "full_height" here but in vfit you use "max" instead of "full". Why would you turn wrap_optimize off? I fed the API to claude and asked for feedback. It didn't say much of use. It did note that indent says it's sometimes ignored (when centering is on or no font selected) and it hopes that you get at least a warning message in this case. I hate it when parameters are silently ignored as I have many times spent tens of minutes trying to debug why a parameter mysteriously has no effect and it turns out it's because some other parameter I didn't notice disabled the parameter I was trying to set. I think that ideally parameters should never be ignored. Claude didn't complain, but I see a bunch of other things that are documented as "ignored if...." which I think should all be asserts. If you ask for something dumb/impossible it should not be quietly ignored. That leads to user frustration and confusion because, as noted, you don't understand WTF is going on and why you change this parameter and nothing seems to happen. The other thing claude complained about was hfit and its interaction with justify. And I agree that the docs as written are puzzling. I don't understand what/how hfit works with justify. I think both of these are kind of confusing as written. The pervasive passive voice doesn't help with clarity here. So maybe something like: hfit = Determines the with box used for anchoring the text: "tight" sets the width to the rendered horizontal width of longest line in the text, "width" sets the width to the What happens if max_width is INF? relation to justification is mysterious so I didn't propose anything there. vfit = Determines the height of the box used for anchoring the text: "tight" sets the height to the actual vertical size of the rendered text, "nominal" sets the box height using the nominal ascender and descender height for the font, and "max" sets the box height usingthe maximum ascender and descender height for the entire font. From reading this it's not clear what "nominal" actually does. The original text said "font set". Is that the max over all fonts (that's what a "set of fonts" seems to be)---but that makes no sense so presumably not. A more detailed discussion of this stuff should probably appear in the description. The text on bounding boxes says "...the wordwrapped text invariably doesn't span the entire dimensions..." If you give 2 dimensions the text won't be tight regardless of word wrapping. I would actually use the word "unlikely" instead of "invariably". I would define the tight bounding box more directly, not just tell the reader to think about it. e.g. "The tight bounding box is the box that exactly contains the rendered text. The user-defined bounds are specified using the As I ponder the above I wonder if making boxes the central thing is the wrong way to explain it. In particular, it seems awkward when it comes to the vertical box extent. And actually does vfit affect how the text fits into the user bounds? Hmm...yes it does. So changing vfit actually changes the text size, not just the box size. It doesn't seem like hfit can have the same effect---it really is just about boxes. (But maybe something to do with justification complicates matters?) The horizontal extent of a block of text is the actual width of the longest line of the rendered text, typically including a small margin defined in the font itself around the glpyh. You can choose between three different ways for defining the vertical extent of a text block. In can be "tight", the actual height of the rendered text. It can be "nominal", where the height of the text takes into account the typical space required for ascenders and descenders in the font, regardless of whether they appear in the specific text. This gives a more uniform and predictable height that doesn't vary from one text block to another. Finally the vertical text extent can be "maximal", where the height is based on the maximum possible vertical space needed for any glyph in the entire font. This may leave a large amount of extra space around most font glyphs depending on the font design. In the examples I checked the difference between nominal and max seemed very small. Is it sometimes big? I originally wrote the above with vfit options called out but then I realized that things are more of a mess because you use this in vfit but you also use it to specify font size, e.g. nom_height= and full_height=, so the concepts need to be defined clearly up front, not only for vfit. Also you need to standardize on "maximal" or "full" for how you want to describe the largest possible vertical size extent. Once you have the above in place it now makes sense to talk about defining the size with reference to the noimal and maximal (or full) text extent. But we now have a problem that hfit and vfit are doing different things even though they have parallel names. That seems like it makes it hard to write a clear doc text. Actually hfit has bugs and also unexpected behavior. If I do The bug is that in this case, the anchoring is wrong. It appears that it ignores hfit, actually, so when hfit="width" I'm supposed to anchor on the user given width but that doesn't happen, it anchors on the text itself. And when max_width is given it anchors on fictional centered text that doesn't exist. Getting back to documenting what happens....I had to do testing to understand what hfit did with "justify" because I couldn't guess it from the docs. It seems like you've overloaded hfit with two unrelated functions. What if I want to justify a text block and have if tight but anchor on the user box? That seems to be impossible. I think you should have a separate boolean, justify_tight=true/false that separately controls this. Docs for justify_last should say: allowed options are "left", "right", "center". And it should be an error if you give something else. (Currently it just does left if you make a typo.) And actually, maybe we have a similar double-use problem with vfit. Or maybe not...I'm uncertain. You're using vfit to determine the anchoring box but also the way we measure text height, which determines what text fits in a space. What if I want to fit the text into the box using "nominal" but then anchor on the text itself. You said on the chat that you already propagate some |
|
Maybe vfit should remain as it is and hfit goes away and we add vanchor and hanchor or something to specify anchoring? Anchoring could also be done as a pair, like anch_box="tight" gives you the tight box, and anch_box="user" gives you the user specified box. And anch_box=["tight","nominal"] specifies the vertical and horizontal in a mixed fashion. Not sure if that is better than a pair of params. |
|
Thank you for the detailed review!
Now that documentation is in place, I'll move onto the bug and the rest of your review later today. |
|
The reason I got to wondering about box= is that right now you would do |
|
Another observation, if I give max_height but not max_width I only get one line, even when max_height is generous and should allow word wrapping. Shouldn't this case wrap to use the allowed vertical space so it fits the text in the minimal width? |
|
Similarly if max_width and max_height are given but no font size I always get one line, but shouldn't it pick the largest font size that fits the text with wrapping into the box? |
No, that's an indeterminate problem. There could be multiple solutions of wrapped lines and font size. If you give a complete box with no font size, the font size is adjusted to fit within whichever limits are hit first. If you want wrapping in such a case, it's best you do it yourself by inserting An oversight on my part is omitting the feature where if you specify only max_height with a font size, then it should try to wrap the text as much as needed to fit into that height. At the extreme end you get one word per line. I have not written that yet. I made a couple of attempts this past week but it's involving some refactoring. |
|
The problem of given a box and no font size, find the largest font size that fits with wrapping can't possibly be indeterminate. Either you can or you can't do it with font size X. There must be a largest size because otherwise you're claiming I can make the font arbitrarily large and it still fits. Now it's a difficult problem that probably requires repeatedly trying to fit the font into the box at different sizes and iteratively locates the largest one that fits. |
|
I see. You're proposing an iteration, in which the font size converges to a value where the wrapped lines don't exceed the bounds in either dimension. It may not be too hard, and may be reasonably fast if an epsilon of 0.1 is allowed. What write() does now is find an exact solution for the font size that would fit the given text constrained by the bounds, and the text can be multi-line text that you have composed using newlines. The question is, what's more useful? Two situations could both be supported by write():
|
|
I think the non-wrap version (already implemented?) is probably more useful to users. |
Addresses #1642. Changes:
write()andwrite3d, and a couple of useful functions to get font sizestext()andtext3d()into text.scadStill TBD:
write_path()