ANTLR postscript tree - antlr4

With antlr4 TestRig you can use -ps to generate a PostScript tree. I can't view my tree.
PostScript:
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 54 48
0.3 setlinewidth
%% x y w h highlight
/highlight {
4 dict begin
/h exch def
/w exch def
/y exch def
/x exch def
gsave
newpath
x y moveto
0 h rlineto % up to left corner
w 0 rlineto % to upper right corner
0 h neg rlineto % to lower right corner
w neg 0 rlineto % back home to lower left corner
closepath
.95 .83 .82 setrgbcolor
fill
grestore
end
} def
/ArialMT findfont 11 scalefont setfont
27,662 32,395 moveto
12,616 15,395 lineto
27,662 32,395 moveto
42,709 15,395 lineto
25,831 37,395 moveto
(r) show
stroke
1,000 5,000 moveto
(hello) show
stroke
33,232 5,000 moveto
(part) show
stroke
%%Trailer
Error in GhostView:
GSview 5.0 2012-01-17
Unknown in Prolog section at line 5:
%% x y w h highlight
GPL Ghostscript 9.07 (2013-02-14)
Copyright (C) 2012 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Displaying DSC file C:/develop/libro/test/arbol.ps without pages
Scanning c:\psfonts for fonts... 0 files, 0 scanned, 0 new fonts.
Can't find (or can't open) font file %rom%Resource/Font/ArialMT.
Can't find (or can't open) font file ArialMT.
Querying operating system for font files...
Didn't find this font on the system!
Substituting font Helvetica for ArialMT.
Loading NimbusSanL-Regu font from %rom%Resource/Font/NimbusSanL-Regu... 3168784 1824261 3249480 1962181 2 done.
Error: /undefined in 27,662
Operand stack:
Execution stack:
%interp_exit .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- false 1 %stopped_push 1932 1 3 %oparray_pop 1931 1 3 %oparray_pop 1915 1 3 %oparray_pop 1803 1 3 %oparray_pop --nostringval-- %errorexec_pop .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval--
Dictionary stack:
--dict:1182/1684(ro)(G)-- --dict:0/20(G)-- --dict:82/200(L)--
Current allocation mode is local
Last OS error: No such file or directory
--- Begin offending input ---
0.3 setlinewidth
%% x y w h highlight
/highlight {
4 dict begin
/h exch def
/w exch def
/y exch def
/x exch def
gsave
newpath
x y moveto
0 h rlineto % up to left corner
w 0 rlineto % to upper right corner
0 h neg rlineto % to lower right corner
w neg 0 rlineto % back home to lower left corner
closepath
.95 .83 .82 setrgbcolor
fill
grestore
end
} def
/ArialMT findfont 11 scalefont setfont
27,662 32,395 moveto
12,616 15,395 lineto
27,662 32,395 moveto
42,709 15,395 lineto
25,831 37,395 moveto
(r) show
stroke
1,000 5,000 moveto
(hello) show
stroke
33,232 5,000 moveto
(part) show
stroke
--- End offending input ---
file offset = 784
gsapi_run_string_continue returns -101

Bon, c'est bien simple, il semble que ANTLR 4 génère les chiffres en fonction de la locale, c'est-à-dire, en français : avec une virgule. Et c'est dommage, parce dans ce cas, PostScript n'en trave que dalle.
The solution to you problem is simple. It seems that ANTLR 4 generates numbers using the locale, i.e. in French, using a comma. It's a pity because PostScript does not understand french (latin?) floating numbers.
You should fill a but report to ANTLR 4.
On Unix, you can temporarily change the locale on bash
export LANG=C

Related

How to fix a problem with Python in PyCharm with black parts of window down and up?

Here's the code:
import pygame
import random
import sys
from pygame import display
pygame.init() #pokrecemo modul pygame
screen = pygame.display.set_mode((round(800),(600))) #varijabla koju smo nazvali screen #definisemo na rezoluciju 800x600
#pozadina
background = pygame.image.load('background.png') #<a href='https://pngtree.com/so/background'>background png from pngtree.com</a>
pygame.display.set_caption("Osvoji Svemir") # naziv prozora
icon = pygame.image.load('ufo.png') # definisemo ikonicu
pygame.display.set_icon(icon) #pozivamo ikonicu da se pojavi
pygame.display.update()
# Igrac
playerImg = pygame.image.load('spaceship1.png')
playerX = 370
playerY = 500
playerX_change = 0
# Neprijatelj
enemyImg = pygame.image.load('enemy.png')
enemyX = random.randint(0, 800) # ubacio sam random modul kako bi se neprijatelj pojavljivao na drugom mestu uvek
enemyY = random.randint(50, 150) # gornje kordinate su za X, a ove- donje za Y osu- da se na "random"- nasumicno pojavljuju
# defininisemo pozicije igraca naseg malog spejsatla
playerX_change = 0
playerY_change = 1
# definisemo pokrete neprijatelja, malih (u nasem slucaju- plavih)
enemyX_change = 0.4
enemyY_change = 40
def player(x,y):
screen.blit(playerImg, (x, y))
def enemy(x,y):
screen.blit(enemyImg, (x, y))
# Petlja igre (game loop)
running = True
while running:
screen.fill((0, 0, 0)) # prva i osnovna pozadina ekrana ako redom idemo to je (CRVENA,PLAVA, ZELENA) u kodu
#pozadina za igricu (interaktivna pozadina koja je velicine ekrana kojeg smo definisali (800x600) u pixelima
# screen.blit(background, (0, 0))
screen.blit(background, (0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Provera za pritisnute tastere na tastaturi
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -3
# print("Sistem je registrovao da je pritisnuta leva strelica")
if event.key == pygame.K_RIGHT:
playerX_change = 3
# print("Sistem je registrovao da je pritisnuta desna strelica")
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
# print("Sistem ceka unos sa tastature")
# <-- ovaj deo, i ispod definise nas brod i neprijatelje da ne izlaze van ekrana
playerX += playerX_change
if playerX <- 0:
playerX = 0
elif playerX >= 736:
playerX = 736
enemyX += enemyX_change
if enemyX <- 0:
enemyX_change = 0.4
enemyY += enemyY_change
elif enemyX >= 736:
enemyX_change = -0.4
enemyY += enemyY_change
player(playerX, playerY)
enemy(enemyX, enemyY)
pygame.display.update()
What am I so far doing wrong to get down of the window and up about 2cm of black strap...
Comments are on Serbian so like IGRAC = PLAYER, NEPRIJATELJ = ENEMY , but the code is the same...
So far I don't want to move on if there is a bug or I don't know what. I've used 800x600 screen, with icon of 64px in 3 cases, icon for app, player icon and enemy. Also, sometimes enemy (neprijatelj) is moving very odd and slow, and I am getting ERROR MESSAGE WHEN COMPILING:
home/boris/Downloads/Python-3.8.5/python /home/boris/Desktop/OsvajacSvemira/main.py
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
/home/boris/Desktop/OsvajacSvemira/main.py:38: DeprecationWarning: an integer is required (got type float). Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
screen.blit(enemyImg, (x, y))
Process finished with exit code 0
I have new KINGSTONE 4GB of RAM and an i686 processor. So, I am not x64 or a cutting edge developer, I am a old-school guy at least regarding tech using, but, I am working with cutting edge technologies as long as they are x86.
The warning refers to the coordinate argument of blit(). Floating point coordinates would mean that the origin of the Surface is somewhere between the pixels in the window. This does not make much sense. The coordinates are automatically and implicitly truncated, and this is indicated by the warning.
round the coordinates to integral values:
screen.blit(enemyImg, (round(x), round(y)))

From bouding boxes to masks

I have a csv dataframe as follow:
filename width height class xmin ymin xmax ymax
0 1.jpg 2048 1251 1 706 513 743 562
1 10.jpg 1600 980 1 715 157 733 181
2 11.jpg 2828 1828 1 460 1530 482 1557
3 12.jpg 1276 1754 1 846 517 878 563
....
19 10.jpg 1600 980 1 428 83 483 145
I would like to get the masks for every image. I've succeded to get them if there is only one box for each image, however some images have multiple bouding boxes (example 10.jpg). How can I be able to add that bounding box to the mask ?
So far my code is as follow ( works good if image has 1 row ):
for idimage in annotations['filename']:
img = cv2.imread('images/'+idimage)
x1 = annotations[annotations['filename'] == idimage]['xmin'][0]
y1 = annotations[annotations['filename'] == idimage]['ymin'][0]
x2 = annotations[annotations['filename'] == idimage]['xmax'][0]
y2 = annotations[annotations['filename'] == idimage]['ymax'][0]
mask = np.zeros((img.shape[0],img.shape[1])).astype('uint8')
mask[y1:y2, x1:x2] = 1
mask = cv2.imwrite('mask/'+idimage,mask)
Thank you !
Actually, this is wrong:
I've succeded to get them if there is only one box for each image
Your code works only for the first row, because you request index 0. All the other rows fails because the dataframes remember their original index.
In this case, groupby does the trick.
for fn, subdf in annotations.groupby('filename'):
img = cv2.imread('images/'+fn)
mask = np.zeros((img.shape[0],img.shape[1])).astype('uint8')
for _, row in subdf.iterrows():
mask[row['ymin']:row['ymax'], row['xmin']:row['xmax']] = 1
cv2.imwrite('mask/'+fn, mask)
Here groupby allows to iterate over a series of subdataframes with the same 'filename'.
Then in a nested loop iterrows is used to iterate over each row of each subdataframe in order to extract the value and build the mask.
As you see, the mask is buildt each iteration of the outer loop, leaving the inner loop to "paint" different rectangles of the mask, one rectangle for each row of the subdataframe.
EDIT
A similar but slightly faster solution for the inner loop, instead of iterrows is:
for x1, y1, x2, y2 in zip(subdf['xmin'], subdf['ymin'], subdf['xmax'], subdf['ymax']):
mask[y1:y2, x1:x2] = 1
If you have a large amount of rows may be useful.

'and', 'or' for python unequal statement between strings

I am reading a text file using python. Each line will be read if the first character does not equal to # or #. The content of the text is pasted in the end.
This works:
if line[0] != '#' and line[0] != '#':
value=float(line[3:8])
But this does not work:
if line[0] != ('#' and '#'):
value=float(line[3:8])
ValueError: could not convert string to float: 'his f'
This also does not work:
if line[0] != ('#' or '#'):
value=float(line[3:8])
ValueError: could not convert string to float: ' tit'
So why both or and and not work?
The content of the text file:
# This file was created Wed Feb 21 12:32:25 2018
# Created by:
# :-) GROMACS - gmx do_dssp, VERSION 5.1.1 (-:
#
# Executable: /shared/ucl/apps/gromacs/5.1.1/intel-2015-update2/bin//gmx
# Data prefix: /shared/ucl/apps/gromacs/5.1.1/intel-2015-update2
# Command line:
# gmx do_dssp -f md_0_1_noPBC.xtc -s md_0_1.tpr -ssdump ssdump.dat -map ss.map -o ss.xpm -sc scount.xvg -a area.xpm -ta totarea.xvg -aa averarea.xvg -tu ns
# gmx do_dssp is part of G R O M A C S:
#
# Gnomes, ROck Monsters And Chili Sauce
#
# title "Secondary Structure"
# xaxis label "Time (ns)"
# yaxis label "Number of Residues"
#TYPE xy
# subtitle "Structure = A-Helix + B-Sheet + B-Bridge + Turn"
# view 0.15, 0.15, 0.75, 0.85
# legend on
# legend box on
# legend loctype view
# legend 0.78, 0.8
# legend length 2
# s0 legend "Structure"
# s1 legend "Coil"
# s2 legend "B-Sheet"
# s3 legend "B-Bridge"
# s4 legend "Bend"
# s5 legend "Turn"
# s6 legend "A-Helix"
# s7 legend "3-Helix"
# s8 legend "5-Helix"
0 278 106 199 10 44 60 9 15 0
0.1 267 118 203 7 52 47 10 6 0
0.2 245 144 175 8 54 51 11 0 0
0.3 264 118 192 8 58 56 8 3 0
line[0] not in ['#' , '#'] will do the trick.
It checks if line[0] exists in a given array.

How to center rotated text on page in PostScript

I put text Sample on every PDF page using the following PostScript code:
<<
/EndPage {
exch pop 2 lt {
gsave
/Arial-Bold 120 selectfont
.5 setgray 100 100 moveto 45 rotate (Sample) show
grestore
true}
{false}
ifelse
} bind
>> setpagedevice
This puts text on [100; 100] position. But I need to center this text (accounting text is rotated).
How do I align this 45° rotated text in the center of a page?
You can use false charpath flattenpath pathbbox to get the bounding box of the text.
If the currentpoint is 0 0 when you do this, then the lower-left coordinates will be pretty close to 0 0, so the upper-right coordinates describe the width and height of the text. So you just move to the desired center-point and back-up by making a relative move to (-width/2, -height/2).
Since the center of rotation is also the center-point, you need to translate there before rotating.
%!
/w 612 def
/h 792 def
/Helvetica-Bold 120 selectfont
w .5 mul h .5 mul translate
0 0 moveto
(Sample) false charpath flattenpath pathbbox % llX llY urX urY
4 2 roll pop pop % urX urY
0 0 moveto
45 rotate
-.5 mul exch -.5 mul exch % -wid/2 -ht/2
rmoveto
(Sample) show
For more accuracy, replace 4 2 roll pop pop with
exch % llX llY urY urX
4 1 roll % urX llX llY urY
exch sub % urX llX urY-llY
3 1 roll % urY-llY urX llX
sub exch % urX-llX urY-llY
And then the point can be anywhere (but there does need to be a currentpoint since charpath builds a path just like show does, even though pathbbox destroys it immediately; so you need some kind of moveto).

How to "trap" my surface patches to prevent the background from bleeding through the cracks?

In response to a challenge in comp.lang.postscript, I'm working-up my 3D chops trying to render a cylinder as projected rectangular patches. But I'm still seeing the wire-frame even after I comment-out the line-drawing, because the patches don't butt-up flush.
The cylinder is modeled along the z-axis by double-looping over z (-2 .. 2, step 4/N) and theta (0 .. 360, step 360/N). The four points of the rectangle are:
v1 = (Rcos T, Rsin T, z)
v4 = (Rcos T, Rsin T, z+dz)
v2 = (Rcos (T+dT), Rsin (T+dt), z)
v3 = (Rcos (T+dT), Rsin (T+dt), z+dz)
Then we apply a model->world rotation to all four points. Then we take the vectors v1->v4 and v1->v2 and do a cross product to get the normal vector for the patch. Take a dot product with the eye vector to check if the patch is on "this side" of the shape; if not, skip the drawing and procede to the next patch (fall off the bottom of the loop). Then we apply a perspective projection to each point and draw the quadrilateral with regular postscript 2D moveto and lineto. One last calculation on the normal vector to set the graylevel and then fill.
So the question is: Is there a usual way to deal with this? Is it a 3D problem or just a numerical problem (floating-point round-off kind of stuff)? Do I just add a little fudge-factor to my dz and dT when calculating the points? Or stroke the edges explicitly? These last 2 options both produce the desired result but I can't say that I'm satisfied with them. While each make be used on an individual illustration, it doesn't really solve the problem, you know?
I took a dump of the points being used. Here's the first few from N=12.
It appears to me that, as predicted, v2 and v3 coincide precisely with v1 and v4 of the next piece on the band. These are the 2D "user coordinates" passed to moveto and lineto to produce the individual quadrilaterals. Since the CTM doesn't change, these points should map to the same pixels, right? So it does appear to be a very similar issue to the linked question. But I'm using Postscript precisely because I don't want to muck-about with writing my own rasterization routine :). I really think that the solution from the linked question, mapped to Postscript, would be to reverse the orientation of alternating checkerboard squares, at least for even N. That way, all corresponding edges are drawn in the same direction (as each other).
[-2.64550757 2.08465409]
[-3.00470281 1.69015563]
[-2.7090168 1.69015563]
[-2.38403082 2.08465409]
[-3.00470281 1.69015563]
[-3.28940701 0.936108589]
[-2.96660638 0.936108589]
[-2.7090168 1.69015563]
[-3.28940701 0.936108589]
[-3.4 -0.0666666701]
[-3.0666666 -0.0666666701]
[-2.96660638 0.936108589]
[-3.4 -0.0666666701]
[-3.28940701 -1.05890918]
[-2.96660638 -1.05890918]
[-3.0666666 -0.0666666701]
[-3.28940701 -1.05890918]
[-3.00470281 -1.78584146]
[-2.7090168 -1.78584146]
[-2.96660638 -1.05890918]
I've added a simple light model and tweaked it to bring out more mids. Jpeg output doesn't exhibit the problem, presumably due to the lossy compression. So here's a PNG snapshot.
The effect is much more apparent if I use the eye-vector as the light source. Here's xpost on the left showing the problem and gs on the right showing a modification where dz and dt are multiplied by a fudge factor of 1.06.
And the code: [Do not use this code. There is an error in the matmul routine. Corrected routines available here. Completed challenge available here.]
%!
%A shaded cylinder! Woohoo!
%(mat.ps) run
%!
%mat.ps
%Matrix and Vector math routines
/.error where { pop /signalerror { .error } def } if
/dot { % u v
2 copy length exch length ne {
/dot cvx /undefinedresult signalerror
} if
% u v
0 % u v sum
0 1 3 index length 1 sub { % u v sum i
3 index 1 index get exch % u v sum u_i i
3 index exch get % u v sum u_i v_i
mul add % u v sum
} for % u v sum
3 1 roll pop pop % sum
} bind def
% [ x1 x2 x3 ] [ y1 y2 y3 ] cross [ x2*y3-y2*x3 x3*y1-x1*y3 x1*y2-x2*y1 ]
/cross { % u v
dup length 3 ne
2 index length 3 ne or {
/cross cvx /undefinedresult signalerror
} if
% u v
exch aload pop 4 3 roll aload pop % x1 x2 x3 y1 y2 y3
[
5 index 2 index mul % ... [ x2*y3
3 index 6 index mul sub % ... [ x2*y3-y2*x3
5 index 5 index mul % ... [ x2*y3-y2*x3 x3*y1
8 index 4 index mul sub % ... [ x2*y3-y2*x3 x3*y1-x1*y3
8 index 5 index mul % ... [ x2*y3-y2*x3 x3*y1-x1*y3 x1*y2
8 index 7 index mul sub % ... [ x2*y3-y2*x3 x3*y1-x1*y3 x1*y2-x2*y1
]
7 1 roll 6 { pop } repeat
} bind def
/transpose { STATICDICT begin
/A exch def
/M A length def
/N A 0 get length def
[
0 1 N 1 sub { /n exch def
[
0 1 M 1 sub { /m exch def
A m get n get
} for
]
} for
]
end } dup 0 6 dict put def
/matmul { STATICDICT begin
/B exch def
B 0 get type /arraytype ne { /B [B] def } if
/A exch def
A 0 get type /arraytype ne { /A [A] def } if
/Q B length def
/R B 0 get length def
/P A length def
Q A 0 get length ne {
/A A transpose def
/P A length def
Q A 0 get length ne {
A B end /matmul cvx /undefinedresult signalerror
} if
} if
[
0 1 R 1 sub { /r exch def
[
0 1 P 1 sub { /p exch def
0
0 1 Q 1 sub { /q exch def
A p get q get
B q get r get mul
add
} for
} for
]
} for
]
end } dup 0 10 dict put def
%u v {operator} vop u(op)v
%apply a binary operator to corresponding elements
%in two vectors producing a third vector as result
/vop { 1 dict begin
/op exch def
2 copy length exch length ne {
/vop cvx end /undefinedresult signalerror
} if
[ 3 1 roll % [ u v
0 1 2 index length 1 sub { % [ ... u v i
3 copy exch pop get % u v i u_i
3 copy pop get % u v i u_i v_i
op exch pop % u v u_i(op)v_i
3 1 roll % u_i(op)v_i u v
} for % [ ... u v
pop pop ]
end } def
%length of a vector
/mag { 0 exch { dup mul add } forall } def
% x y z ang -> x y' z'
/rotx { 3 dict begin
/theta exch def
/z exch def
/y exch def
y theta cos mul
z theta sin mul sub
y theta sin mul
z theta cos mul add
end } def
% x y z ang -> x' y z'
/roty { 4 dict begin
/theta exch def
/z exch def
/y exch def
/x exch def
x theta cos mul
z theta sin mul add
y
x theta sin mul neg
z theta cos mul add
end } def
% x y z ang -> x' y' z
/rotz { 4 dict begin
/theta exch def
/z exch def
/y exch def
/x exch def
x theta cos mul
y theta sin mul sub
x theta sin mul
y theta cos mul add
z
end } def
% x y z -> x' y' z'
/model {
%ang roty
%ang .25 mul rotx
%alpha rotz
beta roty
gamma rotx
} def
% Eye coords
/ex .1 def
/ey .1 def
/ez 5 def
/eyedir [ex ey ez]
dup mag [ exch dup dup ]{div} vop
def
% x y z -> X Y
/project {
3 dict begin
/z exch def
/y exch def
/x exch def
1 ez z sub div
x ez mul z ex mul sub
1 index mul
y ez mul z ey mul sub
3 2 roll mul
end } def
/light
[ 3 -7 -2 1 ]
dup mag [ exch dup dup dup ]{div} vop
def
/Ia .4 def % Incident Ambient Intensity
/Ka .4 def % Ambient Diffuse reflection constant
/Il .5 def % Incident intensity of Lightsource
/Kd .3 def % Diffuse reflection constant
%h R N
/cylinder { 20 dict begin
/N exch def
/R exch def
/h exch def
/dz 1 N div def
/dt 360 dz mul def
/hdz h dz mul def
0 dz 1 dz sub {
h mul h 2 div sub /z exch def
0 dt 360 { /t exch def
/v1 [ t cos R mul
t sin R mul
z ] def
/v4 [ v1 aload pop pop
z hdz add ] def
/t t dt add def
/v2 [ t cos R mul
t sin R mul
z ] def
/v3 [ v2 aload pop pop
z hdz add ] def
[ v1 v2 v3 v4 ] {
aload 4 1 roll model 4 3 roll astore pop
} forall
/normal v4 v1 {sub} vop
v2 v1 {sub} vop
cross def
/nlen normal mag def
/normal normal [nlen nlen nlen] {div} vop def
[normal aload pop 1] [eyedir aload pop 1] dot 0 lt {
/action { moveto /action { lineto } def } def
[ v1 v2 v3 v4 ]
{ aload pop project action }
forall
closepath
% gsave
[normal aload pop 1]
light
%[ex ey ez neg 1] %"radiant"
dot
Il Kd mul mul
Ia Ka mul add
setgray
fill
% grestore
% stroke
} if
} for
} for
end } def
300 400 translate
280 dup dup moveto
dup neg dup neg lineto
dup neg dup lineto
dup neg lineto closepath .6 setgray fill
1 70 dup dup scale div setlinewidth
%/beta 0 def
%/gamma 0 def
%4 2 50 cylinder
/beta 90 def
/gamma 0 def
4 2 50 cylinder
%/beta 0 def
%/gamma 90 def
%4 2 50 cylinder
showpage
Alright, I've come up with something that sits a little easier in the gut.
6% fudging just feels to horrible to bear.
But Ken suggested that rounding could be involved. That means taking control of the rounding should gain one some measure of control over the problem. And it looks like it's true.
So I tried prepending all moveto and lineto calls with a call to prep:
/prep {
transform
%2 {
% exch
%floor
round
%ceiling
%2 mul cvi 2 div %round
%} repeat
itransform
} def
The comments show the various pieces I tried. Rounding on both device coordinates eliminated all horizontal bleed-lines and leaves very thin vertical bleeds. This seems to make sense assuming Ghostscript rasterizes by horizontal scanlines: it has an easier time with the horizontal ones with just a little help, but near-verticals are tougher.
But then I combined this with fudging. And I found that rounding just the device-y 'ordinate and fudging the patch dimensions by 2% eliminates all bleeds. It really lit up this batcave.
2% is an acceptable level of fudging, I think. (?)
Unfortunately, all the above requires tweaking when you adjust the value of N (the number of slices). The simplest fix to cover the whole surface is to stroke the edges in the same color as the fill. The only difficult point here is making sure the linewidth is appropriate for the scale. And the easy way to do that is to set them both together. For very high resolutions, this should probably be adjusted in some way to account for N.
1 70 dup dup scale div setlinewidth
Here's one of the images generated by the final program, a Steinmetz solid with coordinate axes and random colors, in a slightly skewed perspective (its right foot sticks out a little).

Resources