How to do a space-partitioning of the Utah Teapot? - graphics

Having dealt with converting the Bezier Patches into triangles, I need to do a Binary Space Partition in order to draw the projected triangles using the Painter's Algorithm.
I've implemented the algorithm from Wikipedia with much help with the math.
But it's making a Charlie Brown tree! That is most of the nodes have one branch completely empty. The whole strategy is all wrong. Since the teapot is essentially spherical, the entire shape is only on one "side" of any particular component triangle.
So I'm thinking I need partitioning planes arranged more like an apple-corer: all passing through the line of the y-axis. But I'm kind of going off book, you know? What's the best way to partition the teapot?
Here's my bsp-tree generator. It uses other functions posted in the linked question.
Edit: Extra juggling to avoid dictstackoverflow. Complete program available here (requires mat.ps and teapot). The numerical output shows the depth of the tree node under construction.
% helper functions to insert and remove triangles in lists
/unshift { % [ e1 .. eN ] e0 . [ e0 e1 .. eN ]
exch aload length 1 add array astore
} def
/shift { % [ e0 e1 .. eN ] . [ e1 .. eN ] e0
aload length 1 sub array astore exch
} def
/makebsp { % [ triangles ] . bsptree
count =
%5 dict %This is the tree node data structure
<</P[]/PM[]/plane[]/front[]/behind[]/F<<>>/B<<>>>>
begin
dup length 1 le{ % If 0 or 1 triangles
dup length 0 eq { % If 0 triangles
pop % discard
}{ % If 1 triangle
aload pop /P exch def % put triangle in tree node
}ifelse
}{ % length>1
shift /P exch def % P: Partitioning Polygon (triangle)
P transpose aload pop
[1 1 1] 4 array astore % make column vectors of homogeneous coords
/PM exch def
[ % Compute equation of the plane defined by P
PM 0 3 getinterval det
[ PM 0 get PM 2 get PM 3 get ] det
[ PM 0 get PM 1 get PM 3 get ] det
PM 1 3 getinterval det 3 mul
] /plane exch def
% iterate through remaining triangles, testing against plane, adding to lists
/front [] def
/behind [] def
{ %forall [P4 P5 P6] = [[x4 y4 z4][x5 y5 z5][x6 y6 z6]]
/T exch def
T transpose % [[x4 x5 x6][y4 y5 y6][z4 z5 z6]]
{aload pop add add} forall % (x4+x5+x6) (y4+y5+y6) (z4+z5+z6)
plane 2 get mul 3 1 roll % z|C| (x) (y)
plane 1 get mul 3 1 roll % y|B| z|C| (x)
plane 0 get mul % y|B| z|C| x|A|
plane 3 get add add add % Ax+By+Cz+D
0 le { /front front
}{ /behind behind
} ifelse
T unshift def
} forall
%front == ()= behind == flush (%lineedit)(r)file pop
% recursively build F and B nodes from front and behind lists
%/F front makebsp def
front currentdict end exch
makebsp
exch begin /F exch def
%/B behind makebsp def
behind currentdict end exch
makebsp
exch begin /B exch def
/front [] def
/behind [] def
} ifelse
currentdict end
} def
Output:

BSP was invented for geometries like levels in Quake-like games and it may be hard to use for some specific geometry sets. BSP uses one of the existing triangles to split your level, so just imagine how it would behave when you want to use it on a sphere...
For the teapot you could get better results using OCTree, which doesn't need to split your geometry along existing triangles. But I'm not sure how well does it work with the Painter Algorithm.
If you really need to use BSP tree here, then you should pick your triangles carefully. I don't understand all of your code but I don't see this part here. Just iterate over all triangles in your current tree branch and for each of them compute the number of triangles in front of it and at the back. The one that has similar number of front-triangles and back-triangles is usually the best one to be used as a split plane.

I didn't quite do an octree, but I modified the bsp-tree builder to use an explicit list of planes which I filled with axis-aligned planes slicing the space -4 < x,y,z < 4.
/planelist [
0 .2 4 { /x exch def
[ 1 0 0 x ]
[ 1 0 0 x neg ]
[ 0 1 0 x ]
[ 0 1 0 x neg ]
[ 0 0 1 x ]
[ 0 0 1 x neg ]
} for
] def
Postscript program available here (requires mat.ps).
The lighter green artifact is the result of a "preview" shown during construction of the bsp. Once built, subsequent pages (images) are drawn quickly and with no artifact as the camera revolves around the teapot.
The join of the body with the spout and handles (not shown from this angle) still needs work.
With the bsp better behaved, backface culling isn't strictly necessary. But it makes the preview nicer.

Another way to improve the BSP for this image is to use a hierarchical decomposition. The teapot isn't just a bunch of bezier surfaces, it has some surfaces that describe the body, some others that describe the handle, the spout, the lid (, the bottom? ).
So the first few levels of the tree ought to be the top-level pieces. Is the handle in front of or behind the body? Is the spout in front of the body? Answers to these questions would be a useful guide for the painter's algorithm.

Related

Shading a triangle in postscript

I want to write some postscript code that will shade a triangle. Here is some code I have cobbled together from a couple of google searches that produces a shaded square:
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 400 400
/square{
0 0 40 40 rectclip
<< /ShadingType 2
/ColorSpace [ /DeviceRGB ]
/Coords [ 0 0 40 40 ]
/Function <<
/FunctionType 2
/Domain [ 0 1 ]
/C0 [ 0.9 0.2 0.0 ]
/C1 [ 0.0 0.2 0.9 ]
/N 1
>>
>>
} bind def
save gsave
200 200 translate 45 rotate
square shfill
grestore restore
100 100 translate 300 rotate
square shfill showpage
Now, if I create a plain text file with this code and give it the filename shade.ps --- the important thing being the .ps --- and double click to open on a mac then the Apple Preview app will open the file and produce a picture with two copies of the shaded square. Great!
But now I want to shade a triangle in a similar way. My goal is to have a few lines of code in the spirit of the above that produces a shaded triangle.
Can anyone help? Is this even the right forum to be asking this question?
Note added 16 Jan 2023: I removed the redundant line of code mentioned in the answer below.
My goal is to draw a Penrose tiling with thin and thick rhombuses and then shade the rhombuses to help give the appearance that they are sloping rooves in the spirit of John Conway's city named Penrasia.
The part that describes the square is this line:
0 0 40 40 rectclip
To change it into a triangle, you'll need to write a function that creates a triangular path and then calls clip on it. This may be easier to understand if you look at an expanded version of rectclip which would look something like this:
/rectclip {
4 dict
/height exch def
/width exch def
/y exch def
/x exch def
x y moveto
width 0 rlineto
0 height rlineto
width neg 0 rlineto
closepath
clip
end
} def
For a triangle, you'll need to do something more like this, depending upon how you want to describe the triangle:
/triclip {
4 dict
/height exch def
/width exch def
/y exch def
/x exch def
x y moveto
width 0 rlineto
width 2 div neg height rlineto
closepath
clip
end
} def
And you'd call this function the same way that rectclip is called in the original.
0 0 40 40 triclip
A more idiomatic way to write the function in PostScript would use stack manipulation to avoid the need for a local dictionary.
/triclip { % x y width height . - ;sets clippath
4 2 roll % |- width height x y
moveto % |- width height
exch dup 0 % |- height width width 0
rlineto % |- height width
2 div neg exch % |- -width/2 height
rlineto % |-
closepath clip
} def
With practice you can start to "read" the stack manipulation part and treat the code instead as several statements and break the lines differently:
/triclip { % x y width height . - ;sets clippath
4 2 roll moveto % width height
exch dup 0 rlineto % height width
2 div neg exch rlineto % -
closepath clip
} def
The important part is the calls to moveto, lineto, closepath, and clip, and the rest is just the "syntax" of PostScript.

The running sequential average of a list of numbers in J

I'm trying to generate the Sierpinski triangle (chaos game version) in J. The general iterative algorithm to generate it, given 3 vertices, is:
point = (0, 0)
loop:
v = randomly pick one of the 3 vertices
point = (point + v) / 2
draw point
I'm trying to create the idiomatic version in J. So far this is what I have:
load 'plot'
numpoints =: 200000
verticesx =: 0 0.5 1
verticesy =: 0 , (2 o. 0.5) , 0
rolls =: ?. numpoints$3
pointsx =: -:#+ /\. rolls { verticesx
pointsy =: -:#+ /\. rolls { verticesy
'point' plot pointsx ; pointsy
This works, but I'm not sure I understand what's going on with -:#+ /\.. I think it's only working because of a mathematical quirk. I was trying to make a dyadic average function that would run as an accumulation through the list of points in the same way that + does in +/ \ i. 10, but I couldn't get anything like that to work. How would I do that?
Update:
To be clear, I'm trying to create a binary function avg that I could use in this way:
avg /\ randompoints
avg =: -:#+ doesn't work with this, for some reason. So I think what I'm having trouble with is properly defining an avg function with the proper variadicity.
To be as close to the algorithm as possible, I would probably do something like this:
v =: 3 2$ 0 0 0.5, (2 o. 0.5), 1 0
ps =: 1 2 $ (?3) { v
next =: 4 :'y,((?x){v) -:#+ ({: y)'
ps =: (3&next)^:20000 ps
'point' plot ({.;{:) |: ps
but your version is much more efficient.

rotation graphics in post script

I was wondering how can I rotate a graphic, say a rectangular by certain angle in post script.
Or at least is there any way to draw a very bold ! like, with an angle !?
I have list of sentence around a circle, so each or in 1 direction, and now, I would like to put each in a rectangular and make hyperlink for them.
The power of Postscript is its ruthless pursuit of the ideal of "delayed binding". The implementation of rotations is no exception. It works by making use of a more general tool, the Affine Transformation Matrix.
You can rotate both text and graphics (because text IS graphics) because all user specified coordinates are first multiplied through this matrix to produce device coordinates.
To perform all the necessary tricks (scaling, rotation, shear, translation), we first have to extend the 2d points to 3d points on the plane z=1 (don't ask me why; read Bill Casselman's Mathematical Illustrations or the Adobe Blue Book for more).
[ x [ a b 0
y * c d 0 = [ x' y' 1 ] = [ ax+cy+e bx+dy+f 1 ]
1 ] e f 1 ]
Since the 3rd column of the matrix is always [ 0 0 1 ] it is omitted from the external representation, and the matrix is described in postscript as:
[ a b c d e f ]
So when you use a coordinate pair for, say, a moveto operator, moveto first transforms it to device coordinates, x' = ax+by+e, y' = cx+dy+f, before adding a <</move [x' y']>> element to the current path.
Change the matrix: change the "meaning" of user coordinates.
The identity matrix is this:
[ 1 0 0 1 0 0 ] % x' = x, y' = y
To scale, replace the 1s with x and y scaling factors:
[ Sx 0 0 Sy 0 0 ] % x' = Sx*x, y' = Sy*y
To translate, replace e and f with the x and y translation offsets:
[ 1 0 0 1 Tx Ty ] % x' = x+Tx, y' = y+Ty
To rotate, replace a,b,c,d with sin and cos scaling and shearing factors:
[ cosW sinW -sinW cosW 0 0 ] % x' = x*cosW-y*sinW, y' = x*sinW+y*cosW, where W is angle(degrees) from x-axis
You "install" this matrix with concat which takes the Current Tranformation Matrix (CTM), multiplies it by your new matrix, and uses the product as the new CTM. So translate, rotate, and scale are just "convenience functions" which could be implemented like this:
/translate { [ 1 0 0 1 7 -2 roll ] concat } def
/scale { [ 3 1 roll 0 0 3 -1 roll 0 0 ] concat } def
/rotate { [ exch dup cos exch sin dup neg 2 index 0 0 ] concat } def
Since the CTM is part of the graphics state, you can use the graphics state stack to manipulate your transformations in a hierarchical manner:
/box { % x y w h %create a path in the shape of a box w*h with lower left corner at x,y
4 2 roll moveto
exch dup 3 1 roll
0 rlineto
0 exch rlineto
neg 0 rlineto
closepath
} def
/Courier 10 selectfont
100 100 100 100 box stroke % draw an oriented box
120 120 moveto (inside) show
gsave
150 150 translate % make the center of the box the new 0,0 point
45 rotate % rotate CCW 45 degrees
0 0 100 100 box stroke % a rotated, shifted box
20 20 moveto (inside) show
grestore
100 200 100 100 box stroke % another box, just north of the first, in the original coordinte system
120 220 moveto (inside) show
This produces the following image:
(source: googlecode.com)
I haven't used PostScript for a long time, but as I remember you could just use "rotate".
% do some steps
% ...
% ...
20 20 moveto % go to new position
30 /Times-Roman SetFont % select active font
45 rotate % set direction to diagonal
(Something)show % print text "Something"
showpage % show it all
cheers Kris
Postscript renders graphics in a given context - and it is this context that can be rotated (or scaled/translated) before drawing. Therefore any element on the image can be transformed as one wishes, all you have to do is to perform the necessary context transforms beforehand.
However, unfortunately, while I can give you an idea of it in this writing, i is a fundamental concept of Postscript, and you won't be able to do any real work in it without understanding that first. I suggest reading a brief tutorial such as the one in http://paulbourke.net/dataformats/postscript/ .
So, the "rotate" name is a function that does rotate the graphcis context - you use rotate, before drawing anything you want (rendering text also being "drawing" in this case).
%!PS
(Helvetica) findfont 12 scalefont setfont %select a font to use
300 300 translate % sets the orign at 300,300 points from the bottom left of page
/start 5 def % creates variable for keeping track of horizontal position of text
36 % pushes number of repeats on the stack
{
start 5 moveto % places cursor on the starting position
(postscript) show % renders the string in the starting position, within the current context
/start start 3 add def % increases the value on the variable
10 rotate % rotates the context 10 degrees clockwise (around the 300,300 new origin)
} repeat
showpage % renders whole page

Metric 3d reconstruction

I'm trying to reconstruct 3D points from 2D image correspondences. My camera is calibrated. The test images are of a checkered cube and correspondences are hand picked. Radial distortion is removed. After triangulation the construction seems to be wrong however. The X and Y values seem to be correct, but the Z values are about the same and do not differentiate along the cube. The 3D points look like as if the points were flattened along the Z-axis.
What is going wrong in the Z values? Do the points need to be normalized or changed from image coordinates at any point, say before the fundamental matrix is computed? (If this is too vague I can explain my general process or elaborate on parts)
Update
Given:
x1 = P1 * X and x2 = P2 * X
x1, x2 being the first and second image points and X being the 3d point.
However, I have found that x1 is not close to the actual hand picked value but x2 is in fact close.
How I compute projection matrices:
P1 = [eye(3), zeros(3,1)];
P2 = K * [R, t];
Update II
Calibration results after optimization (with uncertainties)
% Focal Length: fc = [ 699.13458 701.11196 ] ± [ 1.05092 1.08272 ]
% Principal point: cc = [ 393.51797 304.05914 ] ± [ 1.61832 1.27604 ]
% Skew: alpha_c = [ 0.00180 ] ± [ 0.00042 ] => angle of pixel axes = 89.89661 ± 0.02379 degrees
% Distortion: kc = [ 0.05867 -0.28214 0.00131 0.00244 0.35651 ] ± [ 0.01228 0.09805 0.00060 0.00083 0.22340 ]
% Pixel error: err = [ 0.19975 0.23023 ]
%
% Note: The numerical errors are approximately three times the standard
% deviations (for reference).
-
K =
699.1346 1.2584 393.5180
0 701.1120 304.0591
0 0 1.0000
E =
0.3692 -0.8351 -4.0017
0.3881 -1.6743 -6.5774
4.5508 6.3663 0.2764
R =
-0.9852 0.0712 -0.1561
-0.0967 -0.9820 0.1624
0.1417 -0.1751 -0.9743
t =
0.7942
-0.5761
0.1935
P1 =
1 0 0 0
0 1 0 0
0 0 1 0
P2 =
-633.1409 -20.3941 -492.3047 630.6410
-24.6964 -741.7198 -182.3506 -345.0670
0.1417 -0.1751 -0.9743 0.1935
C1 =
0
0
0
1
C2 =
0.6993
-0.5883
0.4060
1.0000
% new points using cpselect
%x1
input_points =
422.7500 260.2500
384.2500 238.7500
339.7500 211.7500
298.7500 186.7500
452.7500 236.2500
412.2500 214.2500
368.7500 191.2500
329.7500 165.2500
482.7500 210.2500
443.2500 189.2500
402.2500 166.2500
362.7500 143.2500
510.7500 186.7500
466.7500 165.7500
425.7500 144.2500
392.2500 125.7500
403.2500 369.7500
367.7500 345.2500
330.2500 319.7500
296.2500 297.7500
406.7500 341.2500
365.7500 316.2500
331.2500 293.2500
295.2500 270.2500
414.2500 306.7500
370.2500 281.2500
333.2500 257.7500
296.7500 232.7500
434.7500 341.2500
441.7500 312.7500
446.2500 282.2500
462.7500 311.2500
466.7500 286.2500
475.2500 252.2500
481.7500 292.7500
490.2500 262.7500
498.2500 232.7500
%x2
base_points =
393.2500 311.7500
358.7500 282.7500
319.7500 249.2500
284.2500 216.2500
431.7500 285.2500
395.7500 256.2500
356.7500 223.7500
320.2500 194.2500
474.7500 254.7500
437.7500 226.2500
398.7500 197.2500
362.7500 168.7500
511.2500 227.7500
471.2500 196.7500
432.7500 169.7500
400.2500 145.7500
388.2500 404.2500
357.2500 373.2500
326.7500 343.2500
297.2500 318.7500
387.7500 381.7500
356.2500 351.7500
323.2500 321.7500
291.7500 292.7500
390.7500 352.7500
357.2500 323.2500
320.2500 291.2500
287.2500 258.7500
427.7500 376.7500
429.7500 351.7500
431.7500 324.2500
462.7500 345.7500
463.7500 325.2500
470.7500 295.2500
491.7500 325.2500
497.7500 298.2500
504.7500 270.2500
Update III
See answer for corrections. Answers computed above were using the wrong variables/values.
** Note all reference are to Multiple View Geometry in Computer Vision by Hartley and Zisserman.
OK, so there were a couple bugs:
When computing the essential matrix (p. 257-259) the author mentions the correct R,t pair from the set of four R,t (Result 9.19) is the one where the 3D points lay in front of both cameras (Fig. 9.12, a) but doesn't mention how one computes this. By chance I was re-reading chapter 6 and discovered that 6.2.3 (p.162) discusses depth of points and Result 6.1 is the equation needed to be applied to get the correct R and t.
In my implementation of the optimal triangulation method (Algorithm 12.1 (p.318)) in step 2 I had T2^-1' * F * T1^-1 where I needed to have (T2^-1)' * F * T1^-1. The former translates the -1.I wanted, and in the latter, to translate the inverted the T2 matrix (foiled again by MATLAB!).
Finally, I wasn't computing P1 correctly, it should have been P1 = K * [eye(3),zeros(3,1)];. I forgot to multiple by the calibration matrix K.
Hope this helps future passerby's !
It may be that your points are in a degenerate configuration. Try to add a couple of points from the scene that don't belong to the cube and see how it goes.
More information required:
What is t? The baseline might be too small for parallax.
What is the disparity between x1 and x2?
Are you confident about the accuracy of the calibration (I'm assuming you used the Stereo part of the Bouguet Toolbox)?
When you say the correspondences are hand-picked, do you mean you selected the corresponding points on the image or did you use an interest point detector on the two images are then set the correspondences?
I'm sure we can resolve this problem :)

How can you get the height metric of a string in PostScript?

You can obtain the width of a string in the current font with stringwidth and although this actually pushes offset coordinates on the stack, the y-value always seems to be useless. Is there a way to determine the exact height of a string, that may or may not include descenders?
stringwidth, as it says, doesn't return string's height. (In all cases I looked at, the second integer on the stack after executing stringwidth was 0 -- for strings that run in horizontal direction.) stringwidth gives the relative coordinates of the currentpoint after executing a (string) show.
The PLRM has this to say about stringwidth:
Note that the width returned by stringwidth is defined as movement of the current
point. It has nothing to do with the dimensions of the glyph outlines.
So what would work to take into account the string's height? The magic words to read up about in PRLM are charpath and pathbbox. Try this:
%!
/Helvetica findfont 60 scalefont setfont
200 700 4 0 360 arc fill
200 700 moveto (test test) dup
true charpath pathbbox
3 -1 roll sub 2 div neg 3 1 roll sub 2 div exch
1 0 0 setrgbcolor
200 700 moveto rmoveto show showpage
It calculates the string's (printed in red) height and uses that info to try and center a small filled circle (printed in black) into the center of its bounding box:
I have already answered this in How to determine string height in PostScript?, but it is useful here also.
Just adding to pipitas answer:
/textheight {
gsave % save graphic context
{
100 100 moveto % move to some point
(HÍpg) true charpath pathbbox % gets text path bounding box (LLx LLy URx URy)
exch pop 3 -1 roll pop % keeps LLy and URy
exch sub % URy - LLy
}
stopped % did the last block fail?
{
pop pop % get rid of "stopped" junk
currentfont /FontMatrix get 3 get % gets alternative text height
}
if
grestore % restore graphic context
} bind def
/jumpTextLine {
textheight 1.25 mul % gets textheight and adds 1/4
0 exch neg rmoveto % move down only in Y axis
} bind def
The method expects that some font is already set. It works over the selected font (setfont) and its size (scalefont).
I use (HÍpg) to get the biggest bounding box possible, using accentuated uppercase characters and "below line" characters. The result is good enough.
The alternative approach steals from dreamlax's answer -- some fonts do not support charpath operator.
Saving and restoring the graphic context keeps the current point in place, so it has no impact over the "flow" of your document.
Hope I've helped.
This seems to work most of the time:
/fontheight { currentfont /FontMatrix get 3 get } bind def
/lineheight { fontheight 1.2 mul } bind def
It won't work for all /FontTypes.

Resources