{{ message }}

# Enhancement for Graphics #1702

Closed
opened this issue Nov 12, 2019 · 40 comments
Closed

# Enhancement for Graphics #1702

opened this issue Nov 12, 2019 · 40 comments
Labels

 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 add optimized circle, ellipse add custom-made vector font, check #1824 add quadratic bezier curve, latest 2v05 useJS to drawRectRnd(), chheck conversation 344773/ use JS to draw lines thicker than 1px, check conversation 348275 Updated 05/29/2020 The text was updated successfully, but these errors were encountered:

### MaBecker commented Nov 12, 2019

 extend circle to draw arcs

 extend line with thickness

 extend draw with rotation possibility Use a image and some javascript for rotation, like in this sample http://forum.espruino.com/conversations/344607/#comment15140533 Update: 03/13/2020

### MaBecker commented Nov 12, 2019

 where to find details for this nice feature used in Bangle.js app "GPS Time" ``````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.

### gfwilliams commented Nov 12, 2019

 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 :-(

### MaBecker commented Nov 18, 2019

 process bar, slider .....

### gfwilliams commented Nov 19, 2019

 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

### MaBecker commented Nov 19, 2019

 Yes this UI is very cool 😎

### MaBecker commented Dec 7, 2019

#### Replace optimized Ellipse with standard Bresenham algorithm to remove the spikes.

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:

#### Hershey Fonts

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:

• JSGRAPHICS_FONTSIZE_HERSHEY = 0
• JSGRAPHICS_LINETHICKNESS = 1
• drawLine with line thickness
• setFontHershey(size,thickness)
• graphicsDrawHersheyChar()
• ....

``````// 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

### gfwilliams commented Dec 9, 2019

 Do you have a PR for the new ellipse? ;)

### MaBecker commented Dec 9, 2019

mentioned this issue Dec 10, 2019

### MaBecker commented Dec 11, 2019

 Would like to implement thickness for drawLine. Can you please advise if and how it should be implemented.

### gfwilliams commented Dec 11, 2019

 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.

### gfwilliams commented Dec 11, 2019

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

### MaBecker commented Dec 11, 2019

 Great, thanks for you guiding informations.

### MaBecker commented Dec 12, 2019

 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.

### MaBecker commented Dec 12, 2019

 First result with adding line width to poly segments Fontsize: 66px

### MaBecker commented Dec 12, 2019

 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

### MaBecker commented Dec 12, 2019

 Or as small font with hf = { sx: 1, sy :1, t: 1, k: 2 };

### MaBecker commented Dec 13, 2019

 Maybe add a function like this to handle the style. `````` g.setFontHershey({width: in_px, heigth : in_px, bold : in_px, kerning : in_px}); ``````

### MaBecker commented Dec 13, 2019

 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 } ``````

### gfwilliams commented Dec 13, 2019

 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 :)

### gfwilliams commented Dec 13, 2019

 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.

### MaBecker commented Dec 13, 2019

 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.

### MaBecker commented Dec 16, 2019

 Got a version javascript version running https://gist.github.com/MaBecker/89a8ec3314f456ccfe397593783ec8b4 What about spacing between chars?

### MaBecker commented Dec 16, 2019

 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

### gfwilliams commented Dec 17, 2019

 Are you actually doing what's suggested in #1702 (comment) ? 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

### MaBecker commented Dec 17, 2019

 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.

### MaBecker commented Mar 13, 2020

 draw rectangle with rounded corners http://forum.espruino.com/conversations/344773/ Would be easy to add to firmware.

### gfwilliams commented May 13, 2020

 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

### gfwilliams commented May 13, 2020

 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 ?

### gfwilliams commented May 13, 2020

 Obviously there's still the fillPoly issue. You wouldn't think it'd be so hard to get a reliable polygon fill algorithm!

### MaBecker commented May 13, 2020

 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.

### MaBecker commented May 13, 2020

 I like the look and feel of the chars with debug flag!

### gfwilliams commented May 18, 2020

 Ok, change of plan again. A custom-made vector font seems preferable: #1824

### MaBecker commented Jul 10, 2020

 time to close this ;-)