here's a question that's been bothering me for the last couple of days - my colleague believes this is a well-researched problem, but I couldn't find any papers online (perhaps the key words I used were incorrect).
Given a graph where each vertex corresponds to a surface and an edge exists between two vertices if the corresponding surfaces meet at a line, how would I go about identifying the surfaces that combine to form closed volumes?
So for instance, the adjacency list for a cube (with surfaces numbered 1 to 6) might look something like this:
1 -> [4,2,5,6]
2 -> [1,3,5,6]
3 -> [2,4,5,6]
4 -> [3,1,5,6]
5 -> [1,2,3,4]
6 -> [1,2,3,4]
In addition to this information, I also know if some surfaces have free-edges (i.e those edges are not shared with any other surface) which means I can immediately exclude these surfaces since a surface with a free-edge cannot be part of a cavity boundary. Also, if two surfaces meet, they will meet cleanly at a boundary - no glancing blows etc.
What I hope to be able to do is not just identify that a cavity exists but also to output a mapping between surfaces and the cavities they contain. For instance, in the case of two cubes which meet at an edge (not enough reputation to post an image, so here's a side view):
-----------
| |
| |
| |
---------------------
| |
| |
| |
-----------
...this would be the desired output assuming surfaces 1-6 make up cube ONE and 7-12 make up cube TWO:
Volume 1 -> [1,2,3,4,5,6]
Volume 2 -> [7,8,9,10,11,12]
Note that, in this case, some surfaces have SIX neighbors in the graph while others have only FOUR neighbors.
Any help would be much appreciated!
Yes, this area is known as computational topology. Its central objects are algebraic groups of loops known as homology groups (H1 when loops are formed by 1-dim edges and H2 when we talk about 2-dim faces).
One can analyze such group by forming a homology group matrix. For some queries both H1 and H2 matrices are needed.
When matrix can be re-arranged into independent blocks it means shapes are not interacting. When a single-block homology matrix has ranking N it means shape has N cavities (holes). Simple shape like cube has 0 holes, torus has 1,etc.
One can find C++ and MATLAB open-source packages for these computations.
Hope it gives some helpful keywords.
Related
Is it possible to find all possible directed graphs given a pair of vertices and the information that an edge exists between them? For example if we know the vertices with edge pairs like
1 2
2 3
1 3
The possible directed graphs will be:
1→2, 2→3, 1→3
1→2, 2→3, 3→1
1→2, 3→2, 1→3
1→2, 3→2, 3→1
2→1, 2→3, 1→3
2→1, 2→3, 3→1
2→1, 3→2, 1→3
2→1, 3→2, 3→1
What data-structure to be used here to work with? What can be the working logic?
I was thinking of using adjacency matrix data structure and compute all possible adjacency matrix. Each adjacency matrix will represent a graph. We can use the graph as and when needed for tasks like checking whether cycle is present or not etc.
Apologies that this is more of a discussion than a programming question, but any help will be appreciated
You could maintain one undirected graph data structure G and work with the knowledge that the existence of an edge (u,v) means that there is only one directed edge in a particular instance of digraph possibility D.
If you want to maintain all possible digraphs separately, you would need 2^m many of them, where m is the number of edges. If the vertices and edges are always the same and only the direction is the invariant, then you could maintain 2^m bit-strings, each of length m. Each bit has a 0 or 1 depending on whether the edge (u,v) it corresponds to is u-->v or v<--u. Use the bit string to give direction to the undirected graph suggested above. You just need to generate all 2^m bit strings. Not very efficient... but you can't do better if you need to work with all possibilities.
You could use the bit string to construct a digraph. But, it would be more memory efficient at least to maintain only one bit-string per 'graph' rather than repeating the entire graph data structure with only directional changes. Record bit strings in a hash table: use each edge as a key and then bit value 0/1 depending on direction. Any graph traversal of one of the many possible digraphs D works on undirected G. Then in constant time you can check for incident (undirected) edges of a vertex, which are outgoing/incoming in D. So traversals can occur just as quickly by maintaining only 1 graph object and 1 bit hash table of size 2^m (rather than 2^m graph objects).
I know that there are efficient polygon clipping algorithms out there (e.g., Maillot, Vatti, Greiner-Hormann). However, these algorithms work for arbitrary polygons and although they fit my case, it seems to me that using such general algorithms for a simple case like mine is an overkill.
What I have is two 2D triangles (see figure below) that I want to clip the one against the other. Searching in the web didn't find anything apart from general polygon clipping algorithms.
Q: Is there a specialized algorithm for clipping two 2D triangles?
For two convex shapes the traditional approach is just Sutherland Cohen, but with more or fewer flags.
E.g. in your case:
blue A is outside red AB but inside the other two red edges; give it code 100;
blue B is the same; give it code 100;
blue C is outside red BC but inside the other two so give it code 010.
Starting from A:
code is non-zero, don't include blue A in the output;
looking at edge blue AB, the binary AND is non-zero so don't consider for output;
code for blue B is non-zero, don't include in output;
codes B and C AND to 0 so XOR* them. Gives 110. So find intersections of blue BC with edges red AB and BC, add them to the outpyt list;
code for blue C is non-zero, don't include in output;
codes for blue C and D again indicate to intersect with BC and AB so do so and add to output.
(* or OR them; we've established they share no bits in common so it makes no difference — I think XOR is a little more descriptive in saying that you're looking for differences)
Two methods, effective for convex polygons, are described here - Hoey's algorithm and O'Rourke's algorithm.
(I've used O'Rourke's one for convex quadrilaterals)
Just hints for optimization.
The complete discussion of which edges intersect and which vertexes belong to the final outline only depends on the algebraic areas of the triangles formed by a vertex of one triangle (A) and an edge of the other (B).
There are 9 such triangles, hence 9 areas and 9 signs. Anyway, the three triangles built with the same vertex of (A) have areas that sum to the area of (B), and only 9 - 3 + 1 = 7 areas need to be fully computed.
In addition, an intersection point between two edges is computed from two areas, using a formula like t= S / (S - S'), where t is the parameter along an edge.
So a completely unrolled algorithm can be written as a decision tree of depth 9 (using the 9 signed areas), with every leaf (512 of them !) generating a sequence of vertexes/intersections. There can be at worst 6 intersections.
I am curious how map software (Google/Bing maps) convert a map into a graph in the backend.
Now if we add houses between intersections 1 and 2, then how would the graph change. How do map software keep track of where the houses are?
Do they index the intersection nodes and also have smaller "subnodes" (between 1 and 2 in this case)? Or do they do this by having multiple layers? So when a user enters a home number, it looks up where the home is (i.e. between which vertices the home is located). After that, they simply apply a shortest path algorithm between those two node and at the beginning and the end, they basically make the home node go to one of the main vertices.
Could someone please give me a detailed explanation of how this works? Ultimately I would like to understand how the shortest path is determined given two the "address" of two "homes" (or "subnodes").
I can only speak for GraphHopper, not for the closed source services you mentioned ;)
GraphHopper has nodes (junctions) and edges (connection between those junctions), nearly exactly how your sketch looks like. This is very fast for the routing algorithms as it avoids massive traversal overhead of subnodes. E.g. in an early version we used subnodes everytime the connection was not straight (e.g. curved street) and this was 8 times slower and so we avoided those 'pillar' nodes and only used the 'tower' nodes for routing.
Still you have to deal with two problems:
How to deal with queries starting on the edge at e.g. house number 1? This is solved via introducing virtual nodes for every query (which can contain multiple locations), and you also need the additional virtual edges and hide some real edges. In GraphHopper we create a lightweight wrapper graph around the original graph (called QueryGraph) which handles all this. It then behaves exactly like a normal 'Graph' for every 'RoutingAlgorithm' like Dijkstra or A*. Also it becomes a bit hairy when you have multiple query locations on one edge, e.g. for a route with multiple via points. But I hope you get the main idea. Another idea would be to do the routing for two sources and two targets but initialized with the actual distance not with 0 like it is normally done for the first nodes. But this makes the routing algorithms more complex I guess.
And as already stated, most of the connections between junctions are not straight and you'll have to store this geometry somewhere and use it to draw the route but also to 'snap a location to the closest road' do finally do the actual routing. See LocationIndexTree for code.
Regarding the directed graphs. GraphHopper stores the graph via undirected edges, to handle oneways it stores the access properties for every edge and for every vehicle separately. So we avoid storing two directed edges and all of its properties (name/geometry/..), and make the use case possible "oneway for car and twoway for bike" etc. It additionally allows to traverse an edge in the reverse direction which is important for some algorithms and e.g. the bidirectional Dijkstra. This would not be possible if the graph would be used to model the access property.
Regarding 'nearly exactly how your sketch looks like': node 1, 3, 7 and 8 would not exist as they are 'pillar' nodes. Instead they would only 'exist' in the geometry of the edge.
To represent the connectivity of a road network, you want your directed road segments to be the graph nodes and your intersections to be collections of directed edges. There is a directed edge from X to Y if you can drive along X and then turn onto or continue on Y.
Consider the following example.
a====b====c
|
| <--one way street, down
|
d
An example connectivity graph for this picture follows.
Nodes
ab
ba
bc
cb
bd
Edges
ab -> bc
ab -> bd
cb -> ba
cb -> bd
Note that this encodes the following information:
No U-turns are allowed at the intersection,
because the edges ab -> ba and cb -> bc are omitted.
When coming from the right a left turn onto the vertical road is allowed,
because the edge cb -> bd is included.
With this representation, each node (directed road segment) has as an attribute all of the addresses along its span, each marked at some distance along the directed road segment.
I have a question regarding the maximum flow in a network. I was trying to find a cut set in a graph that could disconnect the source and the destination. I explored all the edge independent paths in the graph from a source to the destination. Next I picked an edge from each of these paths and grouped them together. So basically I enumerated all the possible combinations of taking one edge from each path.
So I have a set of such groups. Does this mean that I have eventually found the cut sets of the network for that particular source and destination? Is this an efficient method?
This sounds like it has exponential complexity. I can't say exactly, because I don't know what "all the edge independent paths" means. For example:
A
|
B
/ \
C D
\ /
E
There are two paths from A to E, but they're not edge independent.
A maximum flow on a graph is dual to a minimum cut, and there are plenty of standard algorithms that can find one in (small) polynomial time. If you're satisfied with any cut at all, just remove all the edges -- this runs in time O(E).
What are your constraints?
I have made a program which builds 3 graphs(arc and node).
The graphs were built based on 2D arrays of 1 and 0.
The first graph is the Ideal Graph which the other two are going to be compared to. I was wandering if there is a way of comparing similarity between two graphs ie How many of the vertices in graph 2 are similar to the vertices in graph 1.
Alternative question:
The graphs were built based on 2D arrays of 1 and 0 so if there is a way of comparing the 2D array for Graph 1 with the array for graph 2 instead than this would solve my problem.
I don't expect you all to put codes up but I'm just trying to understand if there is a method that can do this. And if so how it can be done.
Any help is appreciated greatly!
Hi All,
Just to make it a bit more clear:
I have two 2Dimensional arrays like so:
double [][] MatrixOfOriginalGraph= {{1,1,1,1},
{0,1,0,0},
{0,0,1,0},
{0,0,0,1}};
double [][] MatrixToBeComparedWithOriginal= {{1,0,0,1},
{0,1,1,0},
{0,0,1,1},
{0,0,0,1};
The first array is used to draw the first graph and the second is used to draw the second graph. The first graph is basically a 4 node graph where the first node is connected to all the other nodes. The other nodes are not connected to each other. The second graph is mixed. I want to know how many of the nodes in vertices in graph two are the same as the ones in graph 1.
Thanks,
jetnori.
Hopefully I got you right. You have a graph, and your array MatrixOfOriginalGraph would be a presentation of the following adjacency matrix:
1111
0100
0010
0001
And similarity is defined by similar connections?
Maybe a good starting point could be the Hamming distance between pairs of the nodes, each from one graph?
So
double [][] MatrixOfOriginalGraph= {{1,1,1,1}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1}};
double [][] MatrixToBeComparedWithOriginal= {{1,0,0,1}, {0,1,1,0}, {0,0,1,1}, {0,0,0,1};
would lead to something like
int node1 = computeDistance({0,1,0,0}, {0,1,1,0});
int node2 = computeDistance({1,1,1,1}, {1,0,0,1});
and so on. But keep in mind using the Hamming distance there have to be an equal amount of variables in both compared structures. I don't know whether this is an limitation for your problem. If this would be a limitation you could instead try the Levenshtein distance.
The lesser the distance the similar the nodes. Then you may sum up the Hamming distances of all nodes (well actually you could have just computed the distance over the whole sequence of ones an zeros) or compute mean and deviation and so on, depending what you need or how you define similarity.