I'm trying to generate layout information for a graph where all of the elements must be laid out in a grid. I would like all coordinates to be integer multiples of the grid-box size.
For example, if I have a grid made up of 1 inch squares, I would like all node coordinates to be a multiple of 72 (the number of points in an inch, if I'm not mistaken). I like the hierarchical layout of dot, so if possible, that's the tool I'd like to use.
I've looked over the element attribute list several times, and I haven't figured out how to do this.
Edit:
The reason I've chosen GraphViz is that it can perform layout, then return that information as text. Other tools seem to just want to render a graph, but I want to render it elsewhere, and I just need to get the layout information.
I believe the Graph::Easy perl module can be used to layout dot files into grids.
http://bloodgate.com/perl/graph/manual/index.html
http://search.cpan.org/~tels/Graph-Easy/bin/graph-easy
Edit:
I'm not sure if this is your desired output, but by playing with the column width of the nodes I can produce:
+------------------+
| A |
+------------------+
| |
| |
v v
+------------++----+
| A1 || A2 |
+------------++----+
| |
| |
v v
+-----++-----+
| A1B || A1A |
+-----++-----+
graph { flow: down; }
[ A ] {columns: 8;}
[ A ] -> { start: south; end: north; } [ A1 ]
[ A ] -> { start: south; end: north; } [ A2 ]
[ A1 ] -> { start: south; end: north;} [ A1A ]
[ A1 ] -> { start: south; end: north;} [ A1B ]
Also I believe it is possible to set the exact space on the grid that the node sits.
Related
I am using turfjs and leaflet to plot a grid and label each square in this fashion:
[A0,A1,...,A23]
[B0,B1,...,B23]
[C0,C1,...,C23]
End goal:
To know what are the coordinates of the corner points of each cell. I mean, I want to know what are the coordinates of the 4 corners of A0 ( and the other cells ).This will then be fed to a json file with something like this:
[
{"A0": [
["x","y"],
["x","y"],
["x","y"],
["x","y"]
]},
{"A1": [
["x","y"],
["x","y"],
["x","y"],
["x","y"]
]}
]
Then, my app will ask the GPS from the device and learn which "square" i'm in.
I have managed to plot the squares ( fiddle, but could not label them or even summon a click to console to find out what are the corner coordinates. I have console'd out the layers but i'm not sure if the plot of the geoJson layer is plotted from left to right. I have concluded each layer spits out 5 coordinates which I suspect that is the information I require but there is a 5th coordinate which does not make sense to be in a square grid cell, unless the 3rd coordinate is the center...
I was able to figure out the mystery of the GeoJson layer in leaflet.
The coordinates are returned like this:
[ 0, 3 , 6 ]
[ 1, 4 , 7 ]
[ 2, 5 , 8 ]
//will label this way:
A0 = 0 ( coordinate sets at 0 )
A1 = 1 ( coordinate sets at 1 )
A2 = 2
B0 = 3
B1 = 4
B2 = 5
...
I still don't know why there is a 5th coordinate in each layer plotted by leaflet. but this is good enough for me. I can know label them as I want.
Thank you for the help.
I'm trying to expand upon this rectangular layout example. The goal is to generate a similar layout but with a dynamic distribution of nodes (within reason, say no more than 20 per row) along both the top and bottom. (For now, the sides will always be 3 nodes.)
My current simplified base example uses this code:
digraph {
rankdir="LR";
node [group=top];
aa -> ab -> ac -> ad -> ae -> af -> ba;
{ rank="same"; ba -> bb -> ca; }
node [group=bot];
da -> cc -> cb -> ca [ dir="back" ];
{ rank="same"; aa -> db -> da [ dir="back"]; }
}
Output:
All the SO solutions I've come across suggest using invisible nodes, but that doesn't seem practical as I'll have math out the least common multiple, space the nodes accordingly, and create an invisible edge to lock them in place. I'd like to leave that as a last resort if there aren't better options out there.
Have tried several other approaches like calculating and setting minlen separately for each edge, playing with settings like clusterrank, nodesep, ranksep, constraint.
Any other ideas on how to equally space the nodes along the top and bottom sides of the layout?
(I'm not tied to GraphViz. Alternative software libraries are welcome. Preferably free and with a Python API.)
dot will always try to figure out the "right" hierarchical position of a node, so "equally spacing" is meaningless within one graph. In order to get a node to a specific position, you will always have to tell dot about that position. Empty nodes give a large amount of flexibility, but can be cumbersome.
In your case, you could calculate the nodes that should be vertically aligned, and simply use another rank = same instruction. Admittedly, this is not the real answer to your question (as I think such answer does not exist) but maybe an improvement over the empty node approach:
digraph {
rankdir="LR";
node [group=top];
aa -> ab -> ac -> ad -> ae -> af -> ba;
{ rank="same"; ba -> bb -> ca; }
node [group=bot];
da -> cc -> cb -> ca [ dir="back" ];
{ rank="same"; aa -> db -> da [ dir="back"]; }
// this leads to a manually fixed "equal spacing":
{ rank = same; ac cc }
{ rank = same; ae cb }
}
which gives you
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.
Im looking to piggyback a float value on a 4x4 matrix im transfering. The matrix in question is used for various xyz vector transforms. As far as i understand the first 3x3 of the matrix facilitates the rotation and scale transforms with the 4th value of the first 3 rows offset the pivot of the transform and the first 3 elements of the bottom row do the positional offset but what does the last element do? As far as i've seen it is always 1 and does absolutely nothing, is there any harm in me making a good use of it?
If (as your question suggests) the convention is that points are column vectors, and the last elements of the first 3 rows determine the translation, then the first 3 elements of the bottom row are not a positional offset: the 4th row of a transformation matrix is used for perspective projection, which is how the camera maps 3D points onto the 2D viewport. A sketch of how the 4x4 matrix is used to map points:
result = 4x4 matrix * point
[ x' ] [ Rxx Rxy Rxz Tx ] [ x ]
[ ] [ ] [ ] -> R** is the rotation/scaling matrix
[ y' ] [ Ryx Ryy Ryz Ty ] [ y ]
[ ] = [ ] * [ ] T* is the translation vector
[ z' ] [ Rzx Rzy Rzz Tz ] [ z ]
[ ] [ ] [ ] P* fixes the camera projection plane
[ w' ] [ Px Py Pz Pw ] [ w ]
-> x' = dot_product3([Rxx,Rxy,Rxz], [x,y,z]) + Tx * w
-> y' = dot_product3([Ryx,Ryy,Ryz], [x,y,z]) + Ty * w
-> z' = dot_product3([Rzx,Rzy,Rzz], [x,y,z]) + Tz * w
-> w' = dot_product4([Px,Py,Pz,Pw], [x,y,z,w])
The final step in the 3D point -> 2D screen mapping is to divide by the 4th (w') coordinate -- so, for standard geometric transformations, the last row should generally be [0,0,0,1], which leaves the w coordinate unchanged.
If the first 3 elements of the bottom row are not 0, the matrix will typically generate a weird, nonuniform distortion of the 3D space. And, although it is possible to use the last element as a uniform inverse scaling factor, it is probably better to do your scaling with the upper left 3x3 submatrix, and leave the bottom row exclusively for the camera.
I am new to graphviz and am just wondering how to determine the relative node positioning in a graph. For example, if I want to draw a simple triangle 'abc', with node 'a' being at the top and nodes 'b' and 'c' on the same level at the bottom, how should I tell graphviz to lay out the nodes as desired?
I tried the following:
graph G
{
node [shape="circle"];
edge [lblstyle="auto"];
{rank=min; "a"}
a -- b [label = "-"];
a -- c [label = "-"];
{rank=same; "b" "c"}
b -- c [label = "+"];
}
but the output positions nodes 'a' and 'b' on the same level at the top, with node 'c' at the bottom.
In addition, is it possible to draw two such triangles side-by-side (with a nice appropriate space in between) in the same graph? if so, how is it implemented?
Thanks a lot.
but the output positions nodes 'a' and 'b' on the same level at the
top, with node 'c' at the bottom.
I actually get a on top, centered above b and c (see image).
Your markup, slightly simplified (what's lblstyle ?), seems to achieve what you want when rendered with dot:
graph G
{
node[shape=circle];
a -- b [label = "-"];
a -- c [label = "-"];
{rank=same; b -- c [label="+"];}
}
What version of graphviz do you use?
And to have two triangles side by side:
graph G
{
node[shape=circle];
edge[label="-"];
a -- b;
a -- c;
{rank=same; b -- c [label="+"];}
d -- e;
d -- f;
{rank=same; e -- f [label="+"];}
}
However, if things get more complex, it may be difficult to have graphviz layout everything exactly as one would like. That's actually the strength of graphviz - applying layout algorithms in order to not have a user intervene.