discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Accumulate translate distance

S(
Song (Rob) Wang
Fri, Jan 4, 2019 6:16 AM

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: 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: image.png]

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: 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: image.png]
M
MichaelAtOz
Fri, Jan 4, 2019 6:35 AM

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/

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/
MF
Michael Frey
Fri, Jan 4, 2019 6:41 AM

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

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
JB
Jordan Brown
Fri, Jan 4, 2019 5:55 PM

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().)

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. * https://www.google.com/search?q=bad+kerning&tbm=isch * https://www.google.com/search?q=keming 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().)
S(
Song (Rob) Wang
Fri, Jan 11, 2019 6:34 AM

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

https://www.linkedin.com/in/rob-song-wang

On Sat, 5 Jan 2019 at 01:55, Jordan Brown openscad@jordan.maileater.net
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.

- https://www.google.com/search?q=bad+kerning&tbm=isch
- https://www.google.com/search?q=keming

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().)

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 <https://www.linkedin.com/in/rob-song-wang> On Sat, 5 Jan 2019 at 01:55, Jordan Brown <openscad@jordan.maileater.net> 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. > > - https://www.google.com/search?q=bad+kerning&tbm=isch > - https://www.google.com/search?q=keming > > 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().) > > >
JB
Jordan Brown
Fri, Jan 11, 2019 6:00 PM

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.

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.