Related
I'm using Python 3.7.
There is a set of points.
I generate Delaunay triangulation through these points.
import numpy as np
points = np.array([[0, 0], [0, 1.1], [1, 0], [1, 1], [1.5, 0.6], [1.2, 0.5], [1.7, 0.9], [1.1, 0.1]])
from scipy.spatial import Delaunay
tri = Delaunay(points)
How can I remove some edges through the edge length threshold?
How to plot the new Delaunay triangulation (after remove the edges)?
My idea is generating edge index through the point. Like,
[e1, (0,0),(1,0),e1_length], [e2, (0,0),(1,1),e2_length], ...
We need to make three operations: convert triangles from Delaunay object to the set of edges (with removing duplicates), calculate length for each edge and select edges which meets the criterion.
Creating set of edges and calculation of lengths:
def less_first(a, b):
return [a,b] if a < b else [b,a]
def delaunay2edges(tri):
list_of_edges = []
for triangle in tri.simplices:
for e1, e2 in [[0,1],[1,2],[2,0]]: # for all edges of triangle
list_of_edges.append(less_first(triangle[e1],triangle[e2])) # always lesser index first
array_of_edges = np.unique(list_of_edges, axis=0) # remove duplicates
list_of_lengths = []
for p1,p2 in array_of_edges:
x1, y1 = tri.points[p1]
x2, y2 = tri.points[p2]
list_of_lengths.append((x1-x2)**2 + (y1-y2)**2)
array_of_lengths = np.sqrt(np.array(list_of_lengths))
return array_of_edges, array_of_lengths
edges, lengths = delaunay2edges(tri)
Selecting edges by criterion (length > 0.5 for example):
criterion = np.argwhere(lengths > 0.5).flatten()
selected_edges = edges[criterion]
print('Removed', len(edges) - len(selected_edges), 'edges')
Plotting:
import matplotlib.pyplot as plt
plt.triplot(tri.points[:,0], tri.points[:,1], tri.simplices, color='red')
x_lines = []
y_lines = []
for p1,p2 in selected_edges:
x1,y1 = points[p1]
x2,y2 = points[p2]
plt.plot([x1,x2],[y1,y2], color='blue')
plt.scatter(points[:,0],points[:,1])
plt.show()
I have two copies of the same molecule as .xyz file. This means that each atom is has X, Y and Z coordinates. However, you can rotate the molecule and obtain different coordinates for each atom, although the relative positions are the same and the molecule remains the same. I want to align the two molecules using three atoms as reference points. However, I am struggling to completely align the two molecules.
Firstly, I align both molecules by translation for a single atom. Then, I am doing two subsequent rotation using rotation matrices as explained elsewhere. For some reason, I need to take the negative of the cross product of both vectors and use a sinus instead of a cosinus to get both structures to be perfectly aligned (I discovered this after a lot of trial and error).
For the second rotation, I project both vectors I want to align on a plane defined by the rotation vector. This is necessary because I don't want to rotate along the cross product of the two vectors to align, since that would disalign the rest of the molecule. Instead, I rotate along the two already aligned vectors. The project allows me to find the angle in the plane between the two vectors, and thus the rotation necessary.
However, this code does not properly align the two molecules.
"group1[0]" contains the XYZ coordinates of the three atoms to align in a list. Likewise for "group2[0]" and the structure 2.
#Point 1: align the functional groups to the origin
O1 = np.array(coords1[group1[0][0]])
O2 = np.array(coords2[group2[0][0]])
mat_2 = np.zeros((len(atoms2), 3))
for ind, c in enumerate(coords1):
coords1[ind] = np.array(c) - O1
for ind, c in enumerate(coords2):
coords2[ind] = np.array(c) - O2
mat_2[ind] = coords2[ind]
#Point 2: align according to a first vector
v1 = np.array(coords1[group1[0][1]])#Since atom 1 is the origin, the coordinates is the vector already
v2 = np.array(coords2[group2[0][1]])#Since atom 1 is the origin, the coordinates is the vector already
v1 = v1/np.linalg.norm(v1)
v2 = v2/np.linalg.norm(v2)
#Let v be the axis of rotation
v = -np.cross(v1, v2)#why do I need a minus here?
if np.linalg.norm(v) != 0:
a = np.arccos(np.dot(v1, v2)/(np.linalg.norm(v1)*np.linalg.norm(v2)))
#c = np.dot(v1, v2)*np.cos(a)
c = np.dot(v1, v2)*np.sin(a)#The internet says cos, but this works perfectly
vx = np.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]])
rot_mat = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + vx + vx.dot(vx)*(1-c)/(1-c**2)
mat_2 = np.array(mat_2)
R_mat_rot = np.matmul(rot_mat, mat_2.T).T
else:
exit(0)
coords3 = R_mat_rot.copy()
#I get exactly what I want up until here
#Point 3: Rotate along atom2-atom1 (v1) to align the third atom
v = -v1.copy()
v2 = np.array(coords3[group2[0][2]]) - np.array(coords3[group2[0][0]]) #Since atom 1 is the origin, the coordinates is the vector already
v2 = v2/np.linalg.norm(v2)
v1 = np.array(coords1[group1[0][2]]) - np.array(coords1[group1[0][0]]) #Since atom 1 is the origin, the coordinates is the vector already
v1 = v1/np.linalg.norm(v1)
if np.linalg.norm(v) != 0:
#consider v to be the vector normal to a plane
#we want the projection of v1 and v2 unto that plane
vp1 = np.cross(v, np.cross(v1, v)) - np.array(coords1[group1[0][0]])
vp1 = vp1/np.linalg.norm(vp1)
vp2 = np.cross(v, np.cross(v2, v)) - np.array(coords3[group2[0][0]])
vp2 = vp2/np.linalg.norm(vp2)
#we find the angle between those vectors on the plane
a = np.arccos(np.dot(vp1, vp2))/(np.linalg.norm(vp1)*np.linalg.norm(vp2))
#rotation of that amount
c = np.dot(v1, v2)*np.cos(a)
vx = np.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]])
rot_mat = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + vx + np.dot(vx, vx)*(1-c)/(1-c**2)
R_mat_rot = np.matmul(rot_mat, coords3.T).T
coords4 = R_mat_rot.copy()#Final coordinates
so i'm trying to render a 2D mesh using vtk (in python). I have a list
of tuples containing all the points and also a list of tuples containing the
points of each cell. Just to experiment, I tried to create a polydata object
of a square with 4 elements and render it, but i ended up with this:
I would like it to show the lines connecting the nodes (like a wireframe)
instead of solid square..
This is the code to produce the image above:
def main2():
#Array of vectors containing the coordinates of each point
nodes = np.array([[0, 0, 0], [1, 0, 0], [2, 0, 0], [2, 1, 0], [2, 2, 0],
[1, 2, 0], [0, 2, 0], [0, 1, 0], [1, 1, 0]])
#Array of tuples containing the nodes correspondent of each element
elements = np.array([(0, 1, 8, 7), (7, 8, 5, 6), (1, 2, 3, 8), (8, 3, 4,
5)])
#Make the building blocks of polyData attributes
Mesh = vtk.vtkPolyData()
Points = vtk.vtkPoints()
Cells = vtk.vtkCellArray()
#Load the point and cell's attributes
for i in range(len(nodes)):
Points.InsertPoint(i, nodes[i])
for i in range(len(elements)):
Cells.InsertNextCell(mkVtkIdList(elements[i]))
#Assign pieces to vtkPolyData
Mesh.SetPoints(Points)
Mesh.SetPolys(Cells)
#Mapping the whole thing
MeshMapper = vtk.vtkPolyDataMapper()
if vtk.VTK_MAJOR_VERSION <= 5:
MeshMapper.SetInput(Mesh)
else:
MeshMapper.SetInputData(Mesh)
#Create an actor
MeshActor = vtk.vtkActor()
MeshActor.SetMapper(MeshMapper)
#Rendering Stuff
camera = vtk.vtkCamera()
camera.SetPosition(1,1,1)
camera.SetFocalPoint(0,0,0)
renderer = vtk.vtkRenderer()
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(renderer)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
renderer.AddActor(MeshActor)
renderer.SetActiveCamera(camera)
renderer.ResetCamera()
renderer.SetBackground(1,1,1)
renWin.SetSize(300,300)
#Interact with data
renWin.Render()
iren.Start()
main2()
I would also like to know if it's possible to have a gridline as the
background of the render window, instead of a black color, just like this:
Thanks in advance!
You can use MeshActor.GetProperty().SetRepresentationToWireframe() (https://www.vtk.org/doc/nightly/html/classvtkProperty.html#a2a4bdf2f46dc499ead4011024eddde5c) to render the actor as wireframe, or MeshActor.GetProperty().SetEdgeVisibility(True) to render it as solid with edges rendered as lines.
Regarding the render window background, I don't know.
Thanks to #MafiaSkafia I created what I was looking for, 2D grid for 3D purposes, maybe someone will be looking for something like this too.
# plane
planeSource = vtk.vtkPlaneSource()
planeSource.SetOrigin(-100.0, -100.0, 0.0)
# planeSource.SetNormal(0.0, 0.0, 1.0)
planeSource.SetResolution(100,100)
planeSource.SetPoint1(100.0,-100.0,0.0)
planeSource.SetPoint2(-100.0,100.0,0.0)
planeSource.Update()
plane = planeSource.GetOutput()
# Create a mapper and actor
mapperP = vtk.vtkPolyDataMapper()
mapperP.SetInputData(plane)
actorP = vtk.vtkActor()
actorP.SetMapper(mapperP)
actorP.GetProperty().SetColor(0,0,0)
actorP.GetProperty().EdgeVisibilityOn() # showing mesh
actorP.GetProperty().SetEdgeColor(1,1,1)
actorP.GetProperty().SetOpacity(0.2) # transparency
...
renderer.AddActor(actorP)
I have a set of images over which polygons are drawn. I have the points of those polygons and I draw these using Shapely and check whether certain points from an eye tracker fall into the polygons.
Now, some of those images are mirrored but I do not have the coordinates of the polygons drawn in them. How can I flip the polygons horizontally? Is there a way to do this with Shapely?
if you want to reflect a polygon with respect to a vertical axis, i.e., to flip them horizontally, one option would be to use the scale transformation (using negative unit scaling factor) provided by shapely.affinity or to use a custom transformation:
from shapely.affinity import scale
from shapely.ops import transform
from shapely.geometry import Polygon
def reflection(x0):
return lambda x, y: (2*x0 - x, y)
P = Polygon([[0, 0], [1, 1], [1, 2], [0, 1]])
print(P)
#POLYGON ((0 0, 1 1, 1 2, 0 1, 0 0))
Q1 = scale(P, xfact = -1, origin = (1, 0))
Q2 = transform(reflection(1), P)
print(Q1)
#POLYGON ((2 0, 1 1, 1 2, 2 1, 2 0))
print(Q2)
#POLYGON ((2 0, 1 1, 1 2, 2 1, 2 0))
by multiplying [[1,0], [0,-1]], You can get the vertically flipped shape. (I tested this on jupyter notebook)
pts = np.array([[153, 347],
[161, 323],
[179, 305],
[195, 315],
[184, 331],
[177, 357]])
display(Polygon(pts))
display(Polygon(pts.dot([[1,0],[0,-1]])))
And If you multiply [[-1,0],[0,1]], you will get horizontally flipped shape.
Refer linear transformation to understand why this works.
A very simple question:
how to compute efficiently in Python (or Cython) the following quantity.
Given the list of polygons in 3D (polygon
There is a list of polygons given in the following form:
vertex = np.array([[0, 0, 0], [0, 0, 1], [0, 1, 0],[1, 0, 0],[0.5, 0.5, 0.5]], order = 'F').T
polygons = np.array([3, 0, 1, 2, 4, 1, 2, 3 ,4])
i.e. polygon is a 1D array, which contains entries of the form [N,i1,i2,i3,i4,...],
N is the number of vertices in a polygons and then the id numbers of the vertices in the vertex array (in the example above there is one triangle with 3 vertices [0,1,2] and one polygon with 4 vertices [1,2,3,4]
I need to compute the information: a list of all edges and for each edge the information
which faces contain this edge.
And I need to do it fast: the number of vertices can be large.
Update
The polygon is closed, i.e. a polygon [4, 0, 1, 5, 7] means that there are 4 vertices and edges are 0-1, 1-5, 5-7, 7-0
The face is a synonim to polygon in fact.
Dunno if this is the fastest option, most probably not, but it works. I think the slowest part is edges.index((v, polygon[i + 1])) where we have to find if this edge is already in list. Vertex array is not really needed since edge is a pair of vertex indexes. I used face_index as a reference to polygon index since you didn't write what face is.
vertex = [[0,0,0], [0,0,1], [0,1,0],[1,0,0],[0.5,0.5,0.5]]
polygons = [3,0,1,2,4,1,2,3,4]
_polygons = polygons
edges = []
faces = []
face_index = 0
while _polygons:
polygon = _polygons[1:_polygons[0] + 1]
polygon.append(polygon[0])
_polygons = _polygons[_polygons[0] + 1:]
for i, v in enumerate(polygon[0:-1]):
if not (v, polygon[i + 1]) in edges:
edges.append((v, polygon[i + 1]))
faces.append([face_index, ])
else:
faces[edges.index((v, polygon[i + 1]))].append(face_index)
face_index += 1
edges = map(lambda edge, face: (edge, face), edges, faces)
print edges
<<< [((0, 1), [0]), ((1, 2), [0, 1]), ((2, 0), [0]), ((2, 3), [1]), ((3, 4), [1]), ((4, 1), [1])]
You can make it faster by removing line polygon.append(polygon[0]) and append first vertice of polygon to vertices list in polygon manually, which shouldn't be a problem.
I mean change polygons = [3,0,1,2,4,1,2,3,4] into polygons = [3,0,1,2,0,4,1,2,3,4,1].
PS Try to use PEP8. It is a code typing style. It says that you should put a space after every comma in iterables so it's eaasier to read.