Compute integral of a "map" along a given direction - python

EDIT: this is for Python!
Im trying to compute an integral of a "map" to produce a line density but I want my integration direction to vary based on the map itself. Here is the idea:
Now, the test case that I am using is the following picture:
So I want to integrate along the cross direction of the "plume", and as such my axes are rotated by an angle of around 90 + theta compared to the regular x and y axes, where theta is rotation angle of the plume with respect to the (original) x axis.
I have tried rotating the entire matrix of values using ndimage.rotate and integrate the rotated picture in the normal x and y directions. This does, however, not produce the desired results for the final line density as I lose information regarding the "direction" of the plume (all integrations are done for a northern plume).
I'm sure there must be a way to perform an integration along a specified axis but I can't quite find it.
Thanks in advance!

Related

Algorithm to check if cylinders are overlapping in 3D

I am creating a script to generate cylinders in a 3D space, however, I would like for them to not occupy the same region in space (avoid overlapping).
The cylinders are defined by a start and end point, and all have a fixed radius.
I am storing the existing cylinder in an array called listOfCylinders which is an nDim array of shape (nCylinders, 2Points [start, end], {x,y,z} coordinates of each point)
I was able to cook up:
def detect_overlap(new_start, new_end, listOfCylinders):
starts = listOfCylinders[:, 0]
ends = listOfCylinders[:, 1]
radius = 0.1
# Calculate the distance between the new cylinder and all the existing cylinders
dists = np.linalg.norm(np.cross(new_end - new_start, starts - new_start), axis=1) / np.linalg.norm(new_end - new_start)
# Check if any of the distances are less than the sum of the radii
if np.any(dists < (2*radius)):
return True
# If no overlap or intersection is found, return False
return False
But this is not accountting for situations where there is lateral overlaping.
Does anyone have a good algorithm for this?
Best Regards
WLOG one of the cylinders is vertical (otherwise rotate space). If you look at the projections of the apparent outline onto XY, you see a circle and a rectangle ended with ellipses. (For simplicity of the equations, you can also make the second cylindre parallel to XZ.)
If these 2D shapes do not overlap, your are done. Anyway, the intersection of a circle and an ellipse leads to a quartic equation.
You can repeat this process, exchanging the roles of the two cylinders. This gives a sufficient condition of non-overlap. Unfortunately, I am not sure it is necessary, though there is a direct connection to the plane separation theorem.
For a numerical approach, you can proceed as follows:
move the cylindre in the canonical position;
generate rectangles on the oblique cylindre, by rotation around the axis and using an angular parameter;
for all sides of the rectangles, detect interference with the cylindre (this involves a system of a quadratic inequation and two linear ones, which is quite tractable);
sample the angular parameter densely enough to check for no valid intersection.
I guess that a complete analytical solution is possible, but complex, and might anyway lead to equations that need to be solved numerically.

Convert 2D Array to a 3D Space

I am trying to develop a 3D cube with values from a flat 2D Plane. I am having a lot of difficulty trying to pseudo code it out so I was hoping to get some input from you guys.
I will try my best to express myself through pictures as I am able to visualize what I am trying to achieve.
I have a 2D output based on the black line in this figure:
I have an array with data of amplitude as each index's value i.e (0; 1) -> the 0 is the x coordinate (sample) and 1 as the y coordinate (amplitude) or as another example (~1900; ~0.25).
How do I take this 1 dimensional sequence and extrude it into a 3D picture like below:
Is there perhaps a library that does such? Or am I going about it the wrong way? The data is from a matched filter output of a sonar signal and I wish to visualize the concentration of the intensity versus where it is located in a sample on a 3D plane. The data has peaks that have inclining and declining gradient slopes before a peak.
I cannot seem to wrap my mind around such a task. Is there a library or a term used to associate what I wish to accomplish?
EDIT: I found this https://www.tutorialspoint.com/matplotlib/matplotlib_3d_surface_plot.htm
But it requires all x, y and z points. Whereas I only have x and y. Additionally I need to be able to access every coordinate (x, y, z) to be able to do range and angle estimation from sample (0, 1) (Transmitted sound where power is highest). I would only like to basically see the top of this though on another 2D axis...
EDIT 2: Following up on a comment below, I would like to convert Figure 1 above into the below image using a library if there exists.
Thanks so much in advanced!

Quantify roughness of a 2D surface based on given scatter points geometrically

How to design a simple code to automatically quantify a 2D rough surface based on given scatter points geometrically? For example, to use a number, r=0 for a smooth surface, r=1 for a very rough surface and the surface is in between smooth and rough when 0 < r < 1.
To more explicitly illustrate this question, the attached figure below is used to show several sketches of 2D rough surfaces. The dots are the scattered points with given coordinates. Accordingly, every two adjacent dots can be connected and a normal vector of each segment can be computed (marked with arrow). I would like to design a function like
def roughness(x, y):
...
return r
where x and y are sequences of coordinates of each scatter point. For example, in case (a), x=[0,1,2,3,4,5,6], y=[0,1,0,1,0,1,0]; in case (b), x=[0,1,2,3,4,5], y=[0,0,0,0,0,0]. When we call the function roughness(x, y), we will get r=1 (very rough) for case (a) and r=0 (smooth) for case (b). Maybe r=0.5 (medium) for case (d). The question is refined to what appropriate components do we need to put inside the function roughness?
Some initial thoughts:
Roughness of a surface is a local concept, which we only consider within a specific range of area, i.e. only with several local points around the location of interest. To use mean of local normal vectors? This may fail: (a) and (b) are with the same mean, (0,1), but (a) is rough surface and (b) is smooth surface. To use variance of local normal vectors? This may also fail: (c) and (d) are with the same variance, but (c) is rougher than (d).
maybe something like this:
import numpy as np
def roughness(x, y):
# angles between successive points
t = np.arctan2(np.diff(y), np.diff(x))
# differences between angles
ts = np.sin(t)
tc = np.cos(t)
dt = ts[1:] * tc[:-1] - tc[1:] * ts[:-1]
# sum of squares
return np.sum(dt**2) / len(dt)
would give you something like you're asking?
Maybe you should consider a protocol definition:
1) geometric definition of the surface first
2) grant unto that geometric surface intrinsic properties.
2.a) step function can be based on quadratic curve between two peaks or two troughs with their concatenated point as the focus of the 'roughness quadratic' using the slope to define roughness in analogy to the science behind road speed-bumps.
2.b) elliptical objects can be defined by a combination of deformation analysis with centered circles on the incongruity within the body. This can be solved in many ways analogous to step functions.
2.c) flat lines: select points that deviate from the mean and do a Newtonian around with a window of 5-20 concatenated points or what ever is clever.
3) define a proper threshold that fits what ever intuition you are defining as "roughness" or apply conventions of any professional field to your liking.
This branched approach might be quicker to program, but I am certain this solution can be refactored into a Euclidean construct of 3-point ellipticals, if someone is up for a geometry problem.
The mathematical definitions of many surface parameters can be found here, which can be easily put into numpy:
https://www.keyence.com/ss/products/microscope/roughness/surface/parameters.jsp
Image (d) shows a challenge: basically you want to flatten the shape before doing the calculation. This requires prior knowledge of the type of geometry you want to fit. I found an app Gwyddion that can do this in 3D, but it can only interface with Python 2.7, not 3.
If you know which base shape lies underneath:
fit the known shape
calculate the arc distance between each two points
remap the numbers by subtracting 1) from the original data and assigning new coordinates according to 2)
perform normal 2D/3D roughness calculations

Translate 3D points along arbitrary plane

I'm working with 3D PDB coordinates. I first use numpy.linalg.lstsq to solve the least squares equation, essentially giving me the coefficients of the plane (I think). I can view the plane using matplotlib, and it appears to be correct. I would like to be able to translate my 3D coordinates along the plane given by the least squares solution. For example, I would like to be able to translate points in the (X,Y) of the new plane. Would it be easier to rotate the points to be in the plane where (0,0,1) is the normal?
If I understand you question right you have a fixed point and want to move it on a plane where you have the normal vector.
Lets suppose your normal vector n is (0,0,1) and your point p is (1,1,1).
If we want to stay in the plane our translation vector t has to be normal to the normal vector.(n*t=0) where * is for the scalar product.
You said you want to keep z constant so we set t_z = 0. Then lets say you want to move your point by t_x = 1. Now you just have to solve the equation: 0*1+0*t_y+1*0=0 for t_y wich in this case is arbitraty because the equation is already 0. So your translation vector for t_x = 1 and t_z = 0 is t = (1,t_y,0).
In the general case you just fix as many coordinates of t as you need and calculate the remaining one with nt=0 equation.
That should not be too hard to implement.
So in one sentence: as long as the translation vector is perpendicular to your normal vector(nt=0) you remain in the same plane.

3D rotations to connect balls and cylinders

I've been tasked with writing a python based plugin for a graph drawing program that generates an STL model of a graph. A graph being an object made up of vertices and edges, where a vertex is represented by a 3D ball (a tessellated icosahedron), and an edge is represented with a cylinder that connects with two balls at either end. The end result of the 3D model is that it will get dumped out to an STL file for 3D printing. I'm able to generate the 3D models for the balls and cylinders without any issues, but I'm having some issues generating the overall model, and getting the balls and cylinders to connect properly.
My original idea was to create tessellated icosahedrons at the origin, then translate them out to the positions of the vertices. This works fine. I then, for each edge, I would create a cylinder at the origin, rotate it to the correct angle so that it points in the correct direction, then translate it to the midpoint between the two vertices so that the ends of the cylinders are embedded in the icosahedrons. This is where things are going wrong. I'm having some difficulties getting the rotations correct. To calculate the rotations, I'm doing the following:
First, I find the angle between the two points as follows (where source and target are both vertices in the graph, belonging to the edge that I'm currently processing):
deltaX = source.x - target.x
deltaY = source.y - target.y
deltaZ = source.z - target.z
xyAngle = math.atan2(deltaX, deltaY)
xzAngle = math.atan2(deltaX, deltaZ)
yzAngle = math.atan2(deltaY, deltaZ)
The angles being calculated seem reasonable, and as far as I can tell, do actually represent the angle between the vertices. For example, if I have a vertex at (1, 1, 0) and another vertex at (3, 3, 0), the angle edge connecting them does show up as a 45 degree angle between the two vertices. (That, or -135 degrees, depending which vertex is the source and which is the target).
Once I have the angles calculated, I create a cylinder and rotate it by the angles that have been calculated, like so, using some other classes that I've created:
c = cylinder()
c.createCylinder(edgeThickness, edgeLength)
c.rotateX(-yzAngle)
c.rotateY(xzAngle)
c.rotateZ(-xyAngle)
c.translate(edgePosition.x, edgePosition.y, edgePosition.z)
(Where edgePosition is the midpoint between the two vertices in the graph, edgeThickness is the radius of the cylinder being created, and edgeLength is the distance between the two vertices).
As mentioned, its the rotating of the cylinders that doesn't work as expected. It seems to do the correct rotation on the x/y plane, but as soon as an edge has vertices that differ in all three components (x, y, and z), the rotation fails. Here's an example of a graph that differs in the x, and y components, but not in the z component:
And here's the resulting STL file, as seen in Makerware (which is used to send the 3D models to the 3D printer):
(The extra cylinder looking bit in the bottom left is something I've currently left in for testing purposes - a cylinder that points in the direction of the z axis, located at the origin).
If I take that same graph and move the middle vertex out in the z axis, so now all the edges involve angles in all three axis, I get a result something like the following:
As show in the app:
The resulting STL file, as show in Makerware:
...and that same model as viewed from the side:
As you can see, the cylinders definitely aren't meeting up with the balls like I thought they would. My question is this: Is my approach to doing this flawed, or is it some small but critical mistake that I'm making somewhere in my rotations? I'm pretty sure it isn't a problem with the rotation functions themselves, as I've been able to independently verify that they work as expected. I also tried creating a rotate function that takes in a yaw, pitch, and roll and does all three at once, and it seemed to generate the same result, like so:
c.rotateYawPitchRoll(xzAngle, -yzAngle, -xyAngle)
So... anyone have any ideas on what I might be doing wrong?
UPDATE: As joojaa pointed out, it was a combination of calculating the correct angles as well as the order that they were applied. In order to get things working, I first calculate the rotation on the x axis, as follows:
zyAngle = math.atan2(deltaVector.z, deltaVector.y)
where deltaVector is the difference between the target and source vectors. This rotation is not yet applied though! The next step is to calculate the rotation on the y axis, as follows:
angle = vector.angleBetweenVectors(vector(target.x - source.x, target.y - source.y, target.z - source.z), vector(target.x - source.x, target.y - source.y, 0.0))
Once both rotations are calculated, they are then applied... in the reverse order! First, the x, then the y:
c.rotateY(angle)
c.rotateX(-zyAngle) #... where c is a cylinder object
There still seems to be a few bugs, but this seems to at least work for a simple test case.
Rotation happens in successive order, so the angles affect each other. It is not possible to use a Euler model to rotate them at once. This is why you can not just calculate the rotations based on the first static situation. Just imagine turning a cube so that it is standing on its corner upright. Yes the first rotation is 45 but the second is not since the cube is already turned by that time (draw a each step of the sequence and see what happens). Space rotations aren't trivial.
So you need to rotate one angle then re calculate the second angle and so forth. This is also why your first rotation works right. You only need 2 rotations unless your interested in making sure the rotation around the shaft has a certain direction.
I would suggest you use axis angles or matrices instead to do this. Mainly because in axis angles this is trivial the angle is the dot between the along tube start and end vectors and the axis is the cross between those 2. You can then convert those to Euler angles if you need. But probably you can just use the matrix directly. For ideas on how conversions and how the rotation could directly be calculated see: transformations.py by Christoph Gohlke. Also see the accompanying c source.
I think i need to expand this answer a bit
There is a really easy way out for this question that sidesteps all your and many other persons problems. The answer is do not use Euler angle rotation. Ive used a lot of brainpower to try to explain Euler rotations to problems that are ultimately solved more easily without Euler rotations. To justify i will leave just one reason for this if you want more think up of some more answers.
The reason most to use Euler rotation sequences is that you probably don't understand Euler angles. There are in fact only a handful of situations where they are good. No self respecting programmer uses Euler rotations to solve this issue. What you do is you use vector math instead.
So you have the direction vector from the source to target which is usually calculated:
along = normalize(target-source)
this is simply one of your matrix rows (or column notation is up to model maker), the one that corresponds to your cylinders original direction (the rows are just x y z w), then you need another vector perpendicular to this one. Choose a arbitrary vector like up (or left if your along is pointing close to up). cross product this up vector by your along for the second row direction. and finally put your source as the last row with 1 in the last column. Done fully formed affine matrix describing the cylinders prition. Much easier to understand since you can draw the vectors.
There are shorter ways but this one is easy to understand.

Categories