Closed MaBecker closed 4 years ago
extend line with thickness
Use a image and some javascript for rotation, like in this sample
http://forum.espruino.com/conversations/344607/#comment15140533
Update: 03/13/2020
setInterval(function() {
g.drawImage(img,48,48,{scale:1.5,rotate:Math.sin(getTime()*2)/2});
},100);
this would nice to have for poly functions.
https://banglejs.com/reference#l_Graphics_drawImage
Those definitely seem like good things to add.
I was considering maybe moving to a better fillPoly (that could do irregular polys) then handling drawLine using that. The real bonus of a line width is you could use the HersheyText line fonts, which scale really nicely
At the moment I use this workaround, which allows to scale and translate a array with pairs of points..
function translate(x, y, p) {
p.forEach((e, i) => {
p[i] += (i % 2) ? y : x;
});
return p;
}
function scale(x, y, p) {
p.forEach((e, i) => {
p[i] *= (i % 2) ? y : x;
});
return p;
}
var plStop = [0,0,20,0,20,20,0,20];
//g.fillPoly(translate(40,170,scale(2,2,plStop)));
g.fillPoly(translate(40,170,scale(2,2,plStop.slice())));
var plPlay = [0,0,20,10,0,20];
//g.fillPoly(translate(160,170,scale(2,2,plPlay)));
g.fillPoly(translate(160,170,scale(2,2,plPlay.slice())));
Updated: Pass a copy of the array using .slice(), otherwise the original array is updated :-(
allObjects has a UI library that looks really promising which just needs adding to the EspruinoDocs repo with all his documentation - I just haven't had the time so far
Yes this UI is very cool 😎
Eye draw test on Bangle.js
Source
g.clear();
g.setColor(1,1,1).fillEllipse(40,60,120+80,180);
g.setColor(0,0,1).fillCircle(120,120,50);
g.setColor(0,0,0).fillCircle(120,120,20);
g.setColor(1,1,1).fillCircle(112,112,5);
Result:
Started with diving into the hershey world. This is extremely cool. http://coopertype.org/event/the_hershey_fonts https://emergent.unpythonic.net/software/hershey http://paulbourke.net/dataformats/hershey/
And now starting to code in javascript to figure out how simple this can be to implement into Graphics library.
implement:
Add a sample
// 1
p1 = [15,22,[ 6,5, 8,4, 11,1, 11,22 ]];
// 2
p2 = [ 15,22, [4,6, 4,5, 5,3, 6,2, 8,1, 12,1, 14,2, 15,3, 16,5, 16,7, 15,9, 13,12, 3,22, 17,22 ]];
g.clear();
var translate = (tx, ty, p) => p.map((v, i)=> v + ((i&1) ? ty : tx));
var scale = (sx, sy, p) => p.map((v, i) => (v * ((i&1) ? sy : sx)+0.5) |0 );
function drawLine(x1,y1,x2,y2,thickness){
var p = [];
var angle = Math.atan2(y2-y1,x2-x1);
cosP = Math.cos(angle+Math.PI/2);
cosM = Math.cos(angle-Math.PI/2);
sinP = Math.sin(angle+Math.PI/2);
sinM = Math.sin(angle-Math.PI/2);
p[0] = (x1 + thickness*cosP +0.5)|0;
p[1] = (y1 + thickness*sinP +0.5)|0;
p[2] = (x1 + thickness*cosM +0.5)|0;
p[3] = (y1 + thickness*sinM +0.5)|0;
p[4] = (x2 + thickness*cosM +0.5)|0;
p[5] = (y2 + thickness*sinM +0.5)|0;
p[6] = (x2 + thickness*cosP +0.5)|0;
p[7] = (y2 + thickness*sinP +0.5)|0;
g.fillPoly(p,true);
}
var p = translate(75,75,scale(3,3,p2[2]));
var t = 3;
g.clear();
for(i=0; i < p.length-2;i += 2){
console.log(p[i+0],p[i+1],p[i+2],p[i+3]);
drawLine(p[i+0],p[i+1],p[i+2],p[i+3],t);
g.fillCircle(p[i+0],p[i+1],t);
g.fillCircle(p[i+2],p[i+3],t);
}
adding circles makes it look smoother.
Edit:
compare with existing vector font
Do you have a PR for the new ellipse? ;)
Yep, just added pr #1720
Would like to implement thickness for drawLine. Can you please advise if and how it should be implemented.
Sounds like a good plan. I'd store lineThickness the same way we do fontAlign/etc in graphics, then check in drawPoly and run a separate bit of code. It should be ifdef'd with SAVE_ON_FLASH though.
The easy way to do it would be to draw each line segment as a poly as you've done, but I think that's going to be too slow if we want to replace Vector with Hershey fonts (which I guess is the main goal?) as there'd be loads of overdraw, and really we want to work on the whole polyline
The actual integration with graphics would take a while and would be a waste of your time, so if you could come up with an algorithm that would turn a polyline into a filled poly then I could integrate it. Even doing the algorithm in JS would work.
Something line this - you'd need to generate the red points:
In your code above i notice you're taking the angle and the using sin and cos, but that's very slow and you can actually just use the difference between coordinates:
dx = x2-x1;
dy = y2-y1;
d = sqrt(dx*dx + dy*dy);
dx = dx*lineWidth/d;
dy = dy*lineWidth/d;
// then [dy,-dx] is 90 degrees, [-dy,dx] is the other way
// [dx,dy] is in-line, so [(dx+dy)/2, (dy-dx)/2]
You can even compare dx/dy with the next dx/dy using a cross product in order to work out which way the line bends (and how much) to figure out if points need adding or removing.
... only saw your update with the Hershey font you printed while writing this. It looks great - it's hard to see how anyone would complain if the font changed :)
Great, thanks for you guiding informations.
Just a short update on testing hershey font using a C-Style Coordinate array for the SIMPLEX character set instead of decoding jhf.
Mirrored and move chars to have same height and baseline. Also adjusted some points for a nice shape.
Started with numbers 0 - 9, scaling 1.5
/*
var hfl = [
width, heigth, numLines,
[ fist line x,y ],
...
[ last line x,y ]
];
*/
......
// /* 1 Ascii 49 */
[
6, 22, 1,
[0, 5, 2, 3, 5, 0, 5, 21]
],
function to setLineWith
function setLineWidth(x1, y1, x2, y2, lw) {
var dx = x2 - x1;
var dy = y2 - y1;
var d = Math.sqrt(dx * dx + dy * dy);
dx = dx * lw / d;
dy = dy * lw / d;
return [
// rounding
x1 - (dx + dy) / 2, y1 - (dy - dx) / 2,
x1 - dx, y1 -dy,
x1 + (dy - dx) / 2, y1 - (dx + dy) / 2,
x1 + dy, y1 - dx,
x2 + dy, y2 - dx,
// rounding
x2 + (dx + dy) / 2, y2 + (dy - dx) / 2,
x2 + dx, y2 + dy,
x2 - (dy - dx) / 2, y2 + (dx + dy) / 2,
x2 - dy, y2 + dx,
x1 - dy, y1 + dx
];
}
g.fillPoly(setLineWidth(20,20,100,200,5));
Not sure about those six rounding lines.
First result with adding line width to poly segments
Fontsize: 66px
working with scaling, thickness and kerning every one can create his individual look
hf = { sx: 2.5, sy :5, t: 5, k: 5 }; sx : font width sy : font height, default 22px t: thickness in px k : kerning in px
Or as small font with hf = { sx: 1, sy :1, t: 1, k: 2 };
Maybe add a function like this to handle the style.
g.setFontHershey({width: in_px, heigth : in_px, bold : in_px, kerning : in_px});
Before starting to convert hershey font files to header file, some advise for output format would be helpful to create eg hershey_romans_font.h
static const unsigned char hersheyFontPolys[] IN_FLASH_MEMORY = {
// Character code 32
...
// Character code 255
}
Nice! About the rounding, try changing x1 - (dx + dy) / 2, y1 - (dy - dx) / 2,
to x1 - (dx + dy) * 0.71, y1 - (dy - dx) * 0.71,
- it should make it more rounded :)
In other fonts I've had one array for character data, one array for # of points. It means you have to iterate through to find each character, but it immediately shaves 100 bytes off the structure because you can use 8 bits rather than 16 for the length.
In other fonts I've had one array for character data, one array for # of points
Yes, seem to be the easiest way to implement it, like you did for the vector font.
Got a version javascript version running
https://gist.github.com/MaBecker/89a8ec3314f456ccfe397593783ec8b4
What about spacing between chars?
Decided to use different factor for drawing the rounded edges.
Is there a solution to handle yellow marked section, because of the slope the width is to small
Are you actually doing what's suggested in https://github.com/espruino/Espruino/issues/1702#issuecomment-564541847 ? Looks like you might just be producing one polygon per line segment?
Doing one big poly would go a long way towards fixing those glitches, but I had considered maybe making the internal poly fill algorithm take coordinates that were 16x bigger (so 16 = 1 pixel, 32 = 2, etc) would help with issues like this
Looks like you might just be producing one polygon per line segment?
Yes, just started working on this :)
making the internal poly fill algorithm take coordinates that were 16x bigger (so 16 = 1 pixel, 32 = 2, etc) would help with issues like this
Good point, will include it.
Just added this pr https://github.com/espruino/Espruino/pull/1757 for g.quadraticBezier()
http://forum.espruino.com/conversations/344773/
Would be easy to add to firmware.
Here's my attempt at Hershey rendering - creating one big poly rather than one per line:
https://www.espruino.com/ide/emulator.html?gist=663f7d6e280e33511881a3dfff2ee30f&upload
Still a few edge cases, but reasonably quick and significantly less overdraw.
Wow, just tested, very nice!
Have you thought about about chars > 127 and < 256 ?
Edit: Even still quick enough on a Bangle.js
It'll be much quicker when it's converted to C too :)
Potentially we could add them, yes. Euros and degrees at least.
One of the reasons for doing this was to reduce flash usage though so I don't want to bump it up too much!
I'm not 100% on the characters but it strikes me that for many of them we could maybe hardcode it? So Ü = U + umlaut ?
Obviously there's still the fillPoly issue. You wouldn't think it'd be so hard to get a reliable polygon fill algorithm!
I'm not 100% on the characters but it strikes me that for many of them we could maybe hardcode it? So Ü = U + umlaut ?
Yes they are called Umlaute äöüÄÖÜ plus €ß°
ü = u + umlaut Ü = U + same as umlaut, just on a different position €: parts from O plus two lines ß: parts of 3 plus a line
I was spending many hours scanning other graphic libs for a smart, short, quick and working algorithm, without success. fillPoly is not as simple as it looks.
I like the look and feel of the chars with debug flag!
Ok, change of plan again. A custom-made vector font seems preferable: https://github.com/espruino/Espruino/issues/1824
time to close this ;-)
This is just a collection of function that came in my mind when working with the excellent library.
For a better readability, will try to write one comment for each enhancement
Updated 05/29/2020