Skip to content

Commit

Permalink
Merge pull request #21 from softnanolab/feature-translate
Browse files Browse the repository at this point in the history
Feature translate
  • Loading branch information
debeshmandal authored Nov 12, 2020
2 parents c2d17cc + 534e46b commit be81ad0
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 9 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@

name: Coverage

on:
push:
branches:
[master]
on: push

jobs:
coverage:
Expand Down
61 changes: 60 additions & 1 deletion drawNA/oxdna/nucleotide.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
"""
import numpy as np
import pandas as pd
from scipy.spatial.transform import Rotation

from typing import List
from typing import List, Union
import warnings

from .utils import get_rotation_matrix
Expand Down Expand Up @@ -304,4 +305,62 @@ def make_across(self) -> "Nucleotide":
self.across = nucleotide
return nucleotide

def transform(self, matrix: np.ndarray):

vecs = [self.pos_com, self._a1, self._a3, self._v, self._L]

if matrix.shape == (3, 3):
for vec in vecs:
vec = np.dot(matrix, vec.T)


elif matrix.shape == (3, 4):
for vec in vecs:
vec = np.dot(matrix, np.hstack([vec, [1]]))

else:
raise TypeError(
f'Transformation Matrix must have shape (3, 3) '
f'or (3, 4) but has shape {matrix.shape}'
)

return

def translate(self, translation_vector: np.ndarray):

if isinstance(translation_vector, list):
translation_vector = np.array(translation_vector)

if not (translation_vector.shape == (1, 3) or
translation_vector.shape == (3, )):
raise TypeError(
f'Translation vector has the wrong shape '
f'({translation_vector.shape})'
)
self.pos_com += translation_vector
return

def rotate(self, rotator: np.ndarray):

if isinstance(rotator, list):
rotator = np.array(rotator)

# if 1d array with length 3 -> euler angles
if rotator.shape == (1, 3) or rotator.shape == (3, ):
matrix = Rotation.from_euler('xyz', rotator).as_matrix()

# if 1d array with length 4 -> quaternion
elif rotator.shape == (1, 4) or rotator.shape == (4, ):
matrix = Rotation(rotator).as_matrix()

# if 2d array use transform
elif rotator.shape == (3, 3):
matrix = rotator

else:
raise TypeError(
f'Rotator was passed that is not valid:\n{rotator}'
)

self.transform(matrix)
return
15 changes: 15 additions & 0 deletions drawNA/oxdna/strand.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,21 @@ def sequence(self, seq: str):
def copy(self):
return deepcopy(Strand(self._nucleotides))

def transform(self, matrix: np.ndarray):
for nucleotide in self._nucleotides:
nucleotide.transform(matrix)
return

def translate(self, translation_vector: np.ndarray):
for nucleotide in self._nucleotides:
nucleotide.translate(translation_vector)
return

def rotate(self, rotator: np.ndarray):
for nucleotide in self._nucleotides:
nucleotide.rotate(rotator)
return


def generate_helix(
n: int = None,
Expand Down
18 changes: 18 additions & 0 deletions drawNA/oxdna/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,21 @@ def add_strands(self, strand_obj: (list or dict) = None, index: int = None):
raise TypeError(
"add_strands() requires ONE of a list or dictionary of strands"
)

def transform(self, matrix: np.ndarray):
for strand in self._strands:
for nucleotide in strand._nucleotides:
nucleotide.transform(matrix)
return

def translate(self, translation_vector: np.ndarray):
for strand in self._strands:
for nucleotide in strand._nucleotides:
nucleotide.translate(translation_vector)
return

def rotate(self, rotator: np.ndarray):
for strand in self._strands:
for nucleotide in strand._nucleotides:
nucleotide.rotate(rotator)
return
3 changes: 1 addition & 2 deletions drawNA/polygons.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from typing import List

import numpy as np
import meshio
import matplotlib.pyplot as plt
import matplotlib.tri as tri

Expand Down Expand Up @@ -89,7 +88,7 @@ def write_STL(self, fout: str):
triangulation = tri.Triangulation(self.vertices[:, 0], self.vertices[:, 1])
triangles = triangulation.get_masked_triangles()
cells = [("triangle", triangles)]
meshio.write_points_cells(fout, self.vertices, cells)
#meshio.write_points_cells(fout, self.vertices, cells)

def write_PLY(self, fout: str, comments: List[str] = []):
"""
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="drawNA",
version="1.1.0",
version="1.0.1",
author="Shanil Panara & Debesh Mandal",
description="Package for creating origami",
long_description=long_description,
Expand Down
29 changes: 29 additions & 0 deletions test/test_oxdna/test_nucleotide.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,35 @@ def test_Nucleotide_across():
new_2.index = 1
assert nucleotide.across == new_2.index
assert new_2.across == nucleotide.index

def test_Nucleotide_transform():
nucleotide = Nucleotide(
"A",
np.array([1.0, 0.0, 0.0]),
np.array([1.0, 0.0, 0.0]),
np.array([0.0, 0.0, 1.0]),
)

nucleotide.translate(np.array([10., 0., 0.]))
assert all(nucleotide.pos_com == [11., 0., 0.])

nucleotide.rotate([0., 0., 0., 1.])
nucleotide.rotate([0., 0., 0.])
nucleotide.rotate(
np.array([
[1., 0., 0.],
[0., 1., 0.],
[0., 0., 0.],
])
)

nucleotide.transform(np.array([
[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
]))

return

if __name__ == "__main__":
test_Nucleotide()
Expand Down
61 changes: 61 additions & 0 deletions test/test_oxdna/test_strand.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,67 @@ def test_generate_helix_seq():
assert len(strand.nucleotides) == 10
assert strand.sequence[0:11] == long_seq[0:10]

def test_strand_transform():
strand = Strand(
[
Nucleotide(
"A",
np.array([1.0, 0.0, 0.0]),
np.array([1.0, 0.0, 0.0]),
np.array([0, 0.0, 1.0]),
),
Nucleotide(
"A",
np.array([2.0, 0.0, 0.0]),
np.array([1.0, 0.0, 0.0]),
np.array([0, 0.0, 1.0]),
),
Nucleotide(
"A",
np.array([3.0, 0.0, 0.0]),
np.array([1.0, 0.0, 0.0]),
np.array([0, 0.0, 1.0]),
),
Nucleotide(
"A",
np.array([4.0, 0.0, 0.0]),
np.array([1.0, 0.0, 0.0]),
np.array([0, 0.0, 1.0]),
),
Nucleotide(
"A",
np.array([5.0, 0.0, 0.0]),
np.array([1.0, 0.0, 0.0]),
np.array([0, 0.0, 1.0]),
),
Nucleotide(
"A",
np.array([6.0, 0.0, 0.0]),
np.array([1.0, 0.0, 0.0]),
np.array([0, 0.0, 1.0]),
),
]
)
strand.translate(np.array([10., 0., 0.]))


strand.rotate([0., 0., 0., 1.])
strand.rotate([0., 0., 0.])
strand.rotate(
np.array([
[1., 0., 0.],
[0., 1., 0.],
[0., 0., 0.],
])
)

strand.transform(np.array([
[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
]))
return


if __name__ == "__main__":

Expand Down
19 changes: 19 additions & 0 deletions test/test_oxdna/test_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,25 @@ def test_System():
print(system)
print(system.dataframe)
# system.write_oxDNA()

system.translate(np.array([10., 0., 0.]))


system.rotate([0., 0., 0., 1.])
system.rotate([0., 0., 0.])
system.rotate(
np.array([
[1., 0., 0.],
[0., 1., 0.],
[0., 0., 0.],
])
)

system.transform(np.array([
[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
]))
return


Expand Down
2 changes: 1 addition & 1 deletion test/test_polygons.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def test_BoundaryPolygon():
assert isinstance(square.edges[0], Edge)

# square.plot2D(show=False)
square.write_STL(f"{ROOT}/square.stl")
# square.write_STL(f"{ROOT}/square.stl")
square.write_PLY(f"{ROOT}/square.ply")


Expand Down

0 comments on commit be81ad0

Please sign in to comment.