Let's say we have a field of descrete cells (2d array or table). We have some finite path inside of it with no self-crossings and no diagonal connections. The particle starts its way in the point A and follows the pattern to the point B. One step can be done in the finite amount of time = t. So the time for the whole path will be T = t * l, where l = number of cells in the path. But! We have some cells in the field marked as 'h' and 'v'. If the particle hit the 'h' cell then it divides into 3 particles. One continue moving by the path. Second starts to move left from the 'h' cell to the left border of the field. Third starts to move right from the 'h' cell to the right border of the field. Analogically with the 'v' cell, but instead of left/right, another 2 particles start move up/down. All particles are moving simultaneously with the same speed. Additional particles can collect 'h' and 'v' too and also can be divided and spawn more particles. Need to write function in Lua that calculates time from the moment of first particle starts its way to the moment of all particles finished their ways. See related illustation. Note that once 'h' or 'v' cell have been collected it becomes a simple cell and other particles doesn't divide if hitting it.
There's not much of an algorithm that can be done here apart from the direct running of the simulations.
There can be no apriori knowledge of the simulation time since the movement of different particles alters the conditions for other particle movement (as in during harvest act).
If the v and h tiles remained after the interaction process then you could just perform a simple raytracing i.e. scan the route, find v and h tiles scan the lines drawn from v andh tiles, find v,h or border tiles, calculate the longest path, draw lines from newfound v,h and scan those, and so on until all lines hit the border or lock into loop. To ignore looped results you could memorize which tiles have been already visited by currently examined ray and its predecessors.
Obviously, as special tiles (v,h) can only prolong the simulation time, the result from above would give upper limit of time in simulation with disappearing special tiles. To calculate the exact runtime, you'd need to take into account the moment in time at which a particular tile is triggered. Surely, it is possible to do that with rays, but a little of thought is needed that it'd be an equivalent to a direct simulation of particles.
The code for that is pretty simple and I will only briefly outline algorithm:
%make array for particlesenter code here
particles={}
%define initial particle route
route={{x1,y1},{x2,y2},...}
%probably you should have your field defined somewhere here too
v_tiles={{x1,y1},{x2,y2}...}
h_tiles=...
%make particle, possible implementations are numerous really
%for example it could be represented by its position
%and a function which gives next position, based on current one
%for main particle it could search the route table for a current position and return next element,
%or just use external counter variable to keep track of propagation
particle={position={x,y}, propagator=function({x,y}) ....}
%put that into particles array obviously
%initialize counter
T=0
%run a cycle until there are particles
while #particles>0 do
%perform a single step for all the particles
for _,p in pairs(particles) do
%move them all
p.position=p.propagator(p.position)
endfor
%then check them all
for i,p in pairs(particles) do
%check for special tiles
if is_v(p.position) then
%make new particle
table.insert(particles,{
position={p.position.x, p.position.y+1},
%for secondary particles propagator would be just a constant addition to a single coordinate
propagator=function(pos) return {pos.x,pos.y+1} end
})
%make second new particle
%same for h tiles
if is_h(p.position) then ...
%check for border tile
if is_border(p.position) then
%remove those that are at the border
table.remove...
%for the original particle you'd have to check
%whether it has reached destination
%probably you should check that somewhere around here too
endfo
%do what we're here for: increase counter
T=T+1
endwhile
%when this reaches the end T will be the answer
It is good that when you're solving the problems in lua, you have machine powerful enough to not worry about memory footprint and just fire away with the variable size array. But for the current task it is possible to get rough upper limit for memory as : 1+2*( num_v+num_h ).
Once again, in direct simulation you might have less particles, but since every interaction with special tile removes special tile and adds a pair of particles, you will never have more than that.
Related
In physics simulations (for example n-body systems) it is sometimes necessary to keep track of which particles (points in 3D space) are close enough to interact (within some cutoff distance d) in some kind of index. However, particles can move around, so it is necessary to update the index, ideally on the fly without recomputing it entirely. Also, for efficiency in calculating interactions it is necessary to keep the list of interacting particles in the form of tiles: a tile is a fixed size array (eg 32x32) where the rows and columns are particles, and almost every row-particle is close enough to interact with almost every column particle (and the array keeps track of which ones actually do interact).
What algorithms may be used to do this?
Here is a more detailed description of the problem:
Initial construction: Given a list of points in 3D space (on the order of a few thousand to a few million, stored as array of floats), produce a list of tiles of a fixed size (NxN), where each tile has two lists of points (N row points and N column points), and a boolean array NxN which describes whether the interaction between each row and column particle should be calculated, and for which:
a. every pair of points p1,p2 for which distance(p1,p2) < d is found in at least one tile and marked as being calculated (no missing interactions), and
b. if any pair of points is in more than one tile, it is only marked as being calculated in the boolean array in at most one tile (no duplicates),
and also the number of tiles is relatively small if possible (but this is less important than being able to update the tiles efficiently)
Update step: If the positions of the points change slightly (by much less than d), update the list of tiles in the fastest way possible so that they still meet the same conditions a and b (this step is repeated many times)
It is okay to keep any necessary data structures that help with this, for example the bounding boxes of each tile, or a spatial index like a quadtree. It is probably too slow to calculate all particle pairwise distances for every update step (and in any case we only care about particles which are close, so we can skip most possible pairs of distances just by sorting along a single dimension for example). Also it is probably too slow to keep a full (quadtree or similar) index of all particle positions. On the other hand is perfectly fine to construct the tiles on a regular grid of some kind. The density of particles per unit volume in 3D space is roughly constant, so the tiles can probably be built from (essentially) fixed size bounding boxes.
To give an example of the typical scale/properties of this kind of problem, suppose there is 1 million particles, which are arranged as a random packing of spheres of diameter 1 unit into a cube with of size roughly 100x100x100. Suppose the cutoff distance is 5 units, so typically each particle would be interacting with (2*5)**3 or ~1000 other particles or so. The tile size is 32x32. There are roughly 1e+9 interacting pairs of particles, so the minimum possible number of tiles is ~1e+6. Now assume each time the positions change, the particles move a distance around 0.0001 unit in a random direction, but always in a way such that they are at least 1 unit away from any other particle and the typical density of particles per unit volume stays the same. There would typically be many millions of position update steps like that. The number of newly created pairs of interactions per step due to the movement is (back of the envelope) (10**2 * 6 * 0.0001 / 10**3) * 1e+9 = 60000, so one update step can be handled in principle by marking 60000 particles as non-interacting in their original tiles, and adding at most 60000 new tiles (mostly empty - one per pair of newly interacting particles). This would rapidly get to a point where most tiles are empty, so it is definitely necessary to combine/merge tiles somehow pretty often - but how to do it without a full rebuild of the tile list?
P.S. It is probably useful to describe how this differs from the typical spatial index (eg octrees) scenario: a. we only care about grouping close by points together into tiles, not looking up which points are in an arbitrary bounding box or which points are closest to a query point - a bit closer to clustering that querying and b. the density of points in space is pretty constant and c. the index has to be updated very often, but most moves are tiny
Not sure my reasoning is sound, but here's an idea:
Divide your space into a grid of 3d cubes, like this in three dimensions:
The cubes have a side length of d. Then do the following:
Assign all points to all cubes in which they're contained; this is fast since you can derive a point's cube from just their coordinates
Now check the following:
Mark all points in the top left of your cube as colliding; they're less than d apart. Further, every "quarter cube" in space is only the top left quarter of exactly one cube, so you won't check the same pair twice.
Check fo collisions of type (p, q), where p is a point in the top left quartile, and q is a point not in the top left quartile. In this way, you will check collision between every two points again at most once, because very pair of quantiles is checked exactly once.
Since every pair of points is either in the same quartile or in neihgbouring quartiles, they'll be checked by the first or the second algorithm. Further, since points are approximately distributed evenly, your runtime is much less than n^2 (n=no points); in aggregate, it's k^2 (k = no points per quartile, which appears to be approximately constant).
In an update step, you only need to check:
if a point crossed a boundary of a box, which should be fast since you can look at one coordinate at a time, and box' boundaries are a simple multiple of d/2
check for collisions of the points as above
To create the tiles, divide the space into a second grid of (non-overlapping) cubes whose width is chosen s.t. the average count of centers between two particles that almost interact with each other that fall into a given cube is less than the width of your tiles (i.e. 32). Since each particle is expected to interact with 300-500 particles, the width will be much smaller than d.
Then, while checking for interactions in step 1 & 2, assigne particle interactions to these new cubes according to the coordinates of the center of their interaction. Assign one tile per cube, and mark interacting particles assigned to that cube in the tile. Visualization:
Further optimizations might be to consider the distance of a point's closest neighbour within a cube, and derive from that how many update steps are needed at least to change the collision status of that point; then ignore that point for this many steps.
I suggest the following algorithm. E.g we have cube 1x1x1 and the cutoff distance is 0.001
Let's choose three base anchor points: (0,0,0) (0,1,0) (1,0,0)
Associate array of size 1000 ( 1 / 0.001) with each anchor point
Add three numbers into each regular point. We will store the distance between the given point and each anchor point inside these fields
At the same time this distance will be used as an index in an array inside the anchor point. E.g. 0.4324 means index 432.
Let's store the set of points inside of each three arrays
Calculate distance between the regular point and each anchor point every time when update point
Move point between sets in arrays during the update
The given structures will give you an easy way to find all closer points: it is the intersection between three sets. And we choose these sets based on the distance between point and anchor points.
In short, it is the intersection between three spheres. Maybe you need to apply additional filtering for the result if you want to erase the corners of this intersection.
Consider using the Barnes-Hut algorithm or something similar. A simulation in 2D would use a quadtree data structure to store particles, and a 3D simulation would use an octree.
The benefit of using a a tree structure is that it stores the particles in a way that nearby particles can be found quickly by traversing the tree, and far-away particles are in traversal paths that can be ignored.
Wikipedia has a good description of the algorithm:
The Barnes–Hut tree
In a three-dimensional n-body simulation, the Barnes–Hut algorithm recursively divides the n bodies into groups by storing them in an octree (or a quad-tree in a 2D simulation). Each node in this tree represents a region of the three-dimensional space. The topmost node represents the whole space, and its eight children represent the eight octants of the space. The space is recursively subdivided into octants until each subdivision contains 0 or 1 bodies (some regions do not have bodies in all of their octants). There are two types of nodes in the octree: internal and external nodes. An external node has no children and is either empty or represents a single body. Each internal node represents the group of bodies beneath it, and stores the center of mass and the total mass of all its children bodies.
demo
https://leetcode.com/problems/trapping-rain-water-ii/
Given an m x n matrix of positive integers representing the height of
each unit cell in a 2D elevation map, compute the volume of water it
is able to trap after raining.
A slight addition is if there's a hole in it and whole platform is in air? How much can it actually store?
While i can look for bounding region around the hole and calculate how much water is wasted there, i can only define a rectangular bounding region (Case 1), but for the second case how can you locate and calculate water in this region:
If i just look for rectangular region which consists the bounding region defined by grey lines, calculate water stored in here then subtract from total, water stored in green region will be removed which shouldn't be. And the bigger problem what if it doesn't exist at all?
Or is there any approach i'm missing, any and all suggestions are welcome.
Here’ the approach that worked for me.
I was looking at separate cells, not regions.
Let a[i][j] be the total height of combined stone (or whatever material is it) and water above it.
Then we have:
a[i][j] = max(height[i][j], min(a[i+1][j], a[i][j+1], a[i-1][j], a[i][j-1]))
The “max” part is to prevent the value from being less than the stone part. And the “min” part is to make sure that water is held by the adjacent cells.
For boundaries the water level is zero so a[i][j] = height[i][j]. For other cells we can start with a very big number.
To illustrate this a little bit: suppose you know for sure that the water level for an adjacent cell can't be more than 7 (for example). Then the water level for your current cell also can't be more than 7: there's literally nothing to hold the water from flowing in direction of that adjacent cell.
By the way, if you have a "hole" in a cell then a[i][j] = 0 since no water can be accumulated there.
We can repeatedly apply that formula as kind of “relaxation” until it’s no longer possible. When it’s no longer possible we have our final configuration and we just need to calculate the water volume.
For procedure to be efficient we can go from top to bottom applying:
a[i][j] = max(height[i][j], min(a[i-1][j], a[i][j-1]))
and then from bottom to top applying:
a[i][j] = max(height[i][j], min(a[i+1][j], a[i][j+1]))
repeating it again an again while at least one cell value changes.
I have a 3D "cubical" matrix, with some cells filled and others empty. A closed region enclosed by filled cells represents a hollow shape. For example, the matrix could have cells filled in such a way that together they form the surface of a hollow sphere. Now, I want an efficient way to fill the interior of this sphere: if a cell C0 is surrounded in all directions by filled cells (filled cell in any direction need not be an immediate neighbor of C0), then fill C0.
A naive way would be the following :-
For each cell, scan in the +X, -X, +Y, -Y, +Z, -Z direction, and see
if you encounter a filled cell in each and every direction.
If a filled cell is encountered in each and every direction, then fill this
cell (as it is part of the interior of some shape).
If you reach the end of grid even in one direction without encountering any filled
cell, then the cell under consideration is not interior to any shape,
and should remain unfilled.
The complexity of above approach is O(n^4), where dimension of 3D grid is n*n*n.
An optimization could be to as follows :-
If for an unfilled cell C[x][y][z], we encountered one filled cell
each in all the 6 directions, then not only C[x][y][z] needs to
be filled, it is also guaranteed that all the cells which we scanned
just now (i.e. {in +X direction, all cells C[x][y][z], C[x+1][y][z],
C[x+2][y][z], ..., till the first filled cell}, similarly for -X, +Y,
-Y, +Z, -Z direction) must be part of the interior of some shape, and hence must be filled.
Another could be as follows :-
If for an unfilled cell C[x][y][z], we DO NOT encounter any filled
cell in, say, +X direction, then not only will C[x][y][z] remain
unfilled, it is also guaranteed that all the cells which we scanned
just now (i.e. in +X direction, all cells C[x][y][z], C[x+1][y][z],
C[x+2][y][z], ..., till the end of grid) must be part of the exterior
and hence, must remain unfilled.
Can someone suggest a more efficient approach to this problem? Even simple optimizations like above, which might not reduce the order of time complexity, are welcome.
You are dealing with 3D Flood Fill. See detailed Wikipedia article http://en.m.wikipedia.org/wiki/Flood_fill
Ok, as this is a closed hollow shapes, we can simply use a BFS or DFS to solve the problem.
BFS:
Starting with an empty queue, add to the queue any cell that lies inside the hollow shape. From the top of the queue, pop out one cell, fill this cell and check 6 other neighbors of this cell, if this neighbor is not filled, add it to the queue, else just ignore this cell. Continue this process until the queue is empty.
The remaining problem is to find a cell that located inside the hollow shape, one trick is the you need to find the cell located at the corner of the shape, which has at least three filled neighbors.
Time complexity is O(number of needed to filled cell * 6 direction need to check)
Tip to move to 6 direction:
int[] x = {0,0,0,0,1,-1};
int[] y = {0,0,1,-1,0,0};
int[] z = {1,-1,0,0,0,0};
Point p = // point in space with three dimension x,y,z
for(int i = 0; i < 6; i++){
int a = p.x + x[i];
int b = p.y + y[i];
int c = p.z + z[i];
}
For each cell, scan in the +X, -X, +Y, -Y, +Z, -Z direction, and see if you encounter a filled cell in each and every direction.
If a filled cell is encountered in each and every direction, then fill this cell (as it is part of the interior of some shape).
The above statement is incorrect unless you are only dealing with convex hulls. The image below shows that the point in question is not enclosed in the blue shape but it will still intersect in all (x,y,z) directions.
Instead, to handle the general case of finding hollowed shapes, you can add all cells to a Set. Then start at a boundary cell. The cell at the boundary is part of a hollowed shape if it is filled, otherwise it is part of a background (non-filled) shape.
Then, similar to #Pham Trung's answer, you can traverse outward in all directions until you have traversed all cells that are within the shape, ignoring the colored cells at the boundaries. Choose another cell at the boundary of the previous shape and start the process over until all cells are traversed.
In the end you will have each cell labeled as either part of a hollow shape or the background.
Just for completeness, two more. YMMV depending on a lot of factors.
1. Find the surface
If you are dealing with a large number of voxels, one optimisation possibility would be to find the border surface of the hollow. This can be done as in Pham Trung's answer but only accepting cells which have at least one of their 6 neighbours filled.
After the border surface has been determined, it can be filled line-by-line using 1D fills, as the directions "inside" and "outside" are known.
This method keeps the set size much smaller if you have a large number of voxels (scales as n^2 instead of n^3). Set lookups are usually very fast, but if the set does not fit into RAM, they slow down a lot.
2. Slice to 2D
Another possibility would be to slice the shape into 2D slices and connect the resulting cavities layer-by-layer. Then only two slices need to be kept in memory at the same time.
The principal idea is to give every separate connected 2D region an own identifier and then find its connections to the already known regions in the neighbouring layer. After handling all layers, connected 3D regions remain.
The challenging part is to find the best algorithm to connect the 2D regions in neighbouring layers. It seems that this method is fast with simple shapes (few disconnected regions in the 2D slices) but slow with complex shapes ("wormholes in tree"). Also, a quick algorithm to find a single common point in two sets is needed. (I.e. no full set intersection is required, just the information whether the sets have at least one common point or not.)
Again, if your sets are of reasonable size, the trivial algorithm described by Pham Trung is probably the best choice.
If I tile squares, and the squares can be defined by their coordinates, how can I simplify shapes made of multiple squares into vectors that define each edge of the entire shape? Pseudo-code or general terms are fine.
The first thing I can think of is (probably not the most efficient way) :
1) Get the bounding box of your entire tiling - which is min(x), min(y) to max(x), max(y) for all x and y of your tiles
2) For every row, start with STATE==EMPTY, iterate over each column : STATE changes to FULL when you hit a square, and EMPTY when you find a hole. Every time STATE goes from EMPTY to FULL, save the left hand line segment of that square and every time STATE goes from FULL to EMPTY, save the right hand line segment of that square.
3) Repeat above in the Y axis
Now you have a set containing only the outermost line segments, you can combine those that are co-linear etc and get the overall shape.
This will work for non-convex shapes and also if you have holes in your tiling.
I'm looking for an algorithm that would move a point around an arbitrary closed polygon that is not self-crossing in N time. For example, move a point smoothly around a circle in 3 seconds.
1) Calculate the polygon's perimeter (or estimate it if exact time of circling
is not critical)
2) divide the perimieter by the time desired for circling
3) move point around polygon at this speed.
Edit following ire and curses' comment.
Maybe I read the question too literally, I fail to see the difficulty or the points raised by ire_and_curses.
The following describes more specifically the logic I imagine for step #3. A more exact description would require knowing details about the coordinate system, the structure used to describe the polygon, and indication abou the desired/allowed animation refreshing frequency.
The "travellng point" which goes around the polygon would start on any edge of the polygop (maybe on a vertex, as so to make the start and end point more obvious) and would stay on an edge at all time.
From this starting point, be it predetermined or randomly selected), the traveling point would move towards towards a vertex, at the calculated speed. Once there it would go towards the other vertex of the edge it just arrived to, and proceed till it returns to the starting point.
The equations for calculating the points on a given edge are the same that for tracing a polygon: simple trig or even pythagoras (*). The visual effect is based on refreshing the position of the traveling point at least 15 times or so per second. The refresh frequency (or rather its period) can be used to determine the distance of two consecutive points of the animation.
The only less trivial task is to detect the end of a given edge, i.e. when the traveling point needs to "turn" to follow the next edge. On these occasions, a fractional travel distance needs to be computed so that the next point in the animation is on the next edge. Special mention also for extremely short edges, as these may require the fractional distance logic to be repeated (or done differently).
Sorry for such a verbose explanation for a rather straight forward literally ;-) algorithm...
Correction: as pointed out by Jefromi in comment for other response, all that is needed with regard to the tracing is merely to decompose the x and y components of the motion. Although we do need Pythagoras for calculating the distance between each vertex for the perimeter calculation, and we do need to extrapolate because the number of animation steps on an edge is not [necessarily] a integer.
For the record, a circle is not a polygon--it's the limit of a regular polygon as the number of sides go to infinity, but it's not a polygon. What I'm giving you isn't going to work if you don't have defined points.
Assuming you have your polygon stored in some format like a list of adjacent vertices, do a O(n) check to calculate the perimeter by iterating through them and computing the distance between each point. Divide that by the time to get the velocity that you should travel.
Now, if you want to compute the path, iterate back through your vertices again and calculate from your current position where your actual position should be on the next timestep, whatever your refresh time step may be (if you need to move down a different edge, calculate how much time it would take to get to the end of your first edge, then continue on from there..). To travel along the edge, decompose your velocity vector into its components (because you know the slope of the edge from its two endpoints).
A little code might answer this with fewer words (though I'm probably too late for any votes here). Below is Python code that moves a point around a polygon at constant speed.
from turtle import *
import numpy as nx
import time
total_time = 10. # time in seconds
step_time = .02 # time for graphics to make each step
# define the polygone by the corner points
# repeat the start point for a closed polygon
p = nx.array([[0.,0.], [0.,200.], [50.,150.], [200.,200.], [200.,0.], [0.,0.]])
perim = sum([nx.sqrt(sum((p[i]-p[i+1])**2)) for i in range(len(p)-1)])
distance_per_step = (step_time/total_time)*perim
seg_start = p[0] # segment start point
goto(seg_start[0], seg_start[1]) # start the graphic at this point
for i in range(len(p)-1):
seg_end = p[i+1] # final point on the segment
seg_len = nx.sqrt(sum((seg_start-seg_end)**2))
n_steps_this_segment = int(seg_len/distance_per_step)
step = (seg_end-seg_start)/n_steps_this_segment # the vector step
#
last_point = seg_start
for i in range(n_steps_this_segment):
x = last_point + step
goto(x[0], x[1])
last_point = x
time.sleep(step_time)
seg_start = seg_end
Here I calculated the step size from the step_time (anticipating an graphics delay) but one could calculate the step size, from whatever was needed, for example, the desired speed.