Accumulate translate distance

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Accumulate translate distance

rob338719
Hi, there

I am stuck on a simple accumulation sum problem for weeks. I am working on a project to print alphabets in OPENSCAD, and adding respective linkages to connect the broken pieces inside the letter, and I have achieved some results like this: 

image.png

My ideas is to print individual alphabet so that I can control the rough size of the width of the outlines. I use the following codes to translate each letter block at a regular distance for each individual alphabet, and the distance is the sum of textSize and the spacing between each letter.  

for (i = [0:numChar -1]){
translate([(i*textSize + (i + 1) * textSpace),0,offsetDepth])
       union(){
   //letter print each block
}
}

but I run in to a few letters that are either too thin, like i, and letters that are too fat, such as 'w'. These letters look like this. I tried to make an accumulating variable that deducts some space when an 'i' is encountered or to add extra spacing or w, but I soon realized that you cannot do $dist = $dist - Ispace; in OPENSCAD. I would like to see what alternative ways that can resolve this. Thank you in advance. 

image.png

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Accumulate translate distance

MichaelAtOz
Administrator
One way I used for spacing out holes of different widths, was to have a
vector of the width of each, then use this to get the sum of all the widths
up to the N'th which is then the offset. Easy to add N*letter-gap-spacing
to.

// sumv  - sum the elements in a vector
// usage   sumv(a-vector,sum-to-this-element,<starting-element default=0>)
{zero based elements}
// example sumv([10,20,30,40],2); // = 60      sumv([10,20,30,40],3,2); // =
70
function sumv(v,i,s=0) = (i==s ? v[i] : v[i] + sumv(v,i-1,s));



-----
Admin - email* me if you need anything, or if I've done something stupid...

* click on my MichaelAtOz label, there is a link to email me.

Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. Obviously inclusion of works of previous authors is not included in the above.

The TPP is no simple “trade agreement.”   Fight it! http://www.ourfairdeal.org/   time is running out!
--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Admin - email* me if you need anything,
or if I've done something stupid...
* click on my MichaelAtOz label, there is a link to email me.

Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work.
Obviously inclusion of works of previous authors is not included in the above.


The TPP is no simple “trade agreement.” Fight it! http://www.ourfairdeal.org/ time is running out!
Reply | Threaded
Open this post in threaded view
|

Re: Accumulate translate distance

MichaelPFrey
In reply to this post by rob338719
On 04.01.19 07:16, Song (Rob) Wang wrote:
but I run in to a few letters that are either too thin, like i, and letters that are too fat, such as 'w'. These letters look like this. I tried to make an accumulating variable that deducts some space when an 'i' is encountered or to add extra spacing or w, but I soon realized that you cannot do $dist = $dist - Ispace; in OPENSCAD. I would like to see what alternative ways that can resolve this. Thank you in advance.

You can use a monospaced font:

https://en.wikipedia.org/wiki/Monospaced_font

In a monospaced font, all letters have the same width.

Doing proper font metric with proportional fonts is not a trivial computer science problem.

(there are ways to "cheat", practically simplifying the problem, but rendering fonts is always a compromise - but given that your stencil is artistic in nature, that should not be a big deal for your project)

With kind regards,

Michael Frey


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Accumulate translate distance

JordanBrown
In reply to this post by rob338719

It seems like there are two problems here:

  • How to accumulate widths of characters so as to position subsequent characters, and
  • What the widths of the characters should be.

The first is a more or less straightforward problem in how to write the functions in the ... interesting ... style that OpenSCAD requires.  Arrays, list comprehensions, and recursive functions all seem likely to play a part.

The second is *much* more difficult.

I'm far from an expert, but it seems like the only mechanical solution involves font-specific tables of the appropriate spacing between pair of letters.  Even that is difficult in OpenSCAD; it seems like the only way (in released versions) to translate a character into a number is through the search() function.  (The nightly build has ord().)



_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Accumulate translate distance

rob338719
Hi, Jordan 

Thank you for your replies. I never knew there is such a thing called bad kerning, and after googled it, it seems that is exactly the key issue here.
What I have been working on mainly concerns letters taking significant lesser space like I and J, and some overly fat letters like W and M. 
My current idea is to recognize such letter like below (i cut away other useless parts about the linkages) 
myWord = "HAPPY";
numChar = len(myWord);
textSize = 20;
textSpace = 10;
Wdeductor = letter == "W"? 20:0;

textSpace = normalSpace - Wdeductor; 
for (i=[0:1:numChar-1]{
letter = myWord[i];
translate ([textSpace, 0 ,0]){
linear_extrude(5)text(letter,textSize)
}

however, this would would not accumulate the distance still. If anyone has a better idea regarding this, I would appreciate immensely.
Thank you for your prompt reply again. 

Warm Regards,


Song WANG(Rob)
Process Engineer

Mobile: +65 92431726
91C Lavender Street, 338719 Singapore




On Sat, 5 Jan 2019 at 01:55, Jordan Brown <[hidden email]> wrote:

It seems like there are two problems here:

  • How to accumulate widths of characters so as to position subsequent characters, and
  • What the widths of the characters should be.

The first is a more or less straightforward problem in how to write the functions in the ... interesting ... style that OpenSCAD requires.  Arrays, list comprehensions, and recursive functions all seem likely to play a part.

The second is *much* more difficult.

I'm far from an expert, but it seems like the only mechanical solution involves font-specific tables of the appropriate spacing between pair of letters.  Even that is difficult in OpenSCAD; it seems like the only way (in released versions) to translate a character into a number is through the search() function.  (The nightly build has ord().)



_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Accumulate translate distance

JordanBrown
On 1/10/2019 10:34 PM, Song (Rob) Wang wrote:
Thank you for your replies. I never knew there is such a thing called bad kerning, and after googled it, it seems that is exactly the key issue here.


The first question is:  will the built-in text() object work for you?  It knows the dimensions of the characters and so can do at least some quality of spacing for you.

If that doesn't work for you, if you have some reason why you have to position each letter individually, the first thing you need is a table of the widths of each character.  (A function for that sure would be nice.)


myWord = "HAPPY";
numChar = len(myWord);
textSize = 20;
textSpace = 10;
Wdeductor = letter == "W"? 20:0;

textSpace = normalSpace - Wdeductor; 
for (i=[0:1:numChar-1]{
letter = myWord[i];
translate ([textSpace, 0 ,0]){
linear_extrude(5)text(letter,textSize)
}

First... you would need to calculate textSpace for each character, and you're calculating it outside the loop.

Here's the two answers I came up with:

// Table of character widths.
// These values approximate the default font for text() on Windows.
// Punctuation and digits left as an exercise for the reader.
widths = [
    ["A", 9],
    ["B", 9],
    ["C", 9],
    ["D", 10],
    ["E", 9],
    ["F", 9],
    ["G", 10],
    ["H", 10],
    ["I", 4],
    ["J", 7],
    ["K", 9],
    ["L", 8],
    ["M", 11],
    ["N", 9],
    ["O", 10],
    ["P", 9],
    ["Q", 10],
    ["R", 10],
    ["S", 9],
    ["T", 9],
    ["U", 9],
    ["V", 9],
    ["W", 13],
    ["X", 9],
    ["Y", 9],
    ["Z", 9],
    ["a", 7.5],
    ["b", 7.5],
    ["c", 7.5],
    ["d", 7.5],
    ["e", 7.5],
    ["f", 4],
    ["g", 7.5],
    ["h", 7.5],
    ["i", 3],
    ["j", 3],
    ["k", 7.5],
    ["l", 3],
    ["m", 11],
    ["n", 7.5],
    ["o", 7.5],
    ["p", 7.5],
    ["q", 7.5],
    ["r", 4.5],
    ["s", 7.5],
    ["t", 4],
    ["u", 7.5],
    ["v", 7],
    ["w", 9],
    ["x", 7],
    ["y", 6.5],
    ["z", 7.5],
];

// Given a character c (as a single-character string), return its width
function cw(c) = widths[search(c, widths, index_col_num=0)[0][0]][1];

// Given a string s and a length n, return the total width of the first n characters of s.  n defaults to the length of s.
function sw(s, n) = let(_n = n != undef ? n : len(s)) _n == 0 ? 0 : sw(s, _n-1) + cw(s[_n-1]);

// Draw a string s using the text defaults.
// This variation calculates the position of each character individually.
// Note that a real implementation would need to allow setting the size of the text, and would need to scale the widths based on the text size.
module text2(s) {
    for (i = [0:len(s)-1]) {
        translate([sw(s, i),0,0]) text(s[i]);
    }
}

// Draw a string using the text defaults.
// This variation positions each character relative to the character before it.
// Again, a real implementation would need to allow for changing the font size.
module text3(s, start) {
    _start = start != undef ? start : 0;
    if (_start <= len(s)) {
        text(s[_start]);
        if (_start+1 <= len(s)) {
            translate([cw(s[_start]),0,0]) text3(s, _start+1);
        }
    }
}

// Test case comparing the spacing generated here with the default spacing.
s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
text(s);
translate([0,12,0]) text2(s);
translate([0,24,0]) text3(s);

---

Note:  with the nightly build you could use ord(), and then the table could be terser and the lookups much faster.



_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org