#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import numpy
import tempfile
from numpy.linalg import norm
from numpy import sqrt, cross, array, dot
from GWL.GWL_parser import GWLobject, calculateNvoxelsAndInterVoxelDistance
[docs]class Parallelepiped(GWLobject):
'''
A parallelepiped (i.e., a brick, possibly with non-orthogonal axes).
The block will be filled with lines going along e1, in layers in the (e1,e2) plane, stacked along e3.
.. todo:: Document code.
.. todo:: center -> centro...
.. todo:: think up better system for LineNumber, LineDistance, Overlap, VoxelSize, Length. Example:
* set(Length, LineNumber)
* set(LineDistance, LineNumber)
* set(Length, VoxelSize, Overlap)
.. todo:: Finish implementing LineDistance, Overlap in Blender addon somehow. cf design problem above.
.. todo:: Finish implementing start-end point method in Blender addon somehow.
.. todo:: extend Parallelepiped class:
* distorted cube, including triangular ones (interpolate cubic grid onto distorted and then write various paras accordingly) (cf blender's lattice deform algorithm with linear interpolation)
* use known/given voxelsize intelligently based on direction of lines, etc
* power compensation -> period/linedistance compensation based on known/given voxelsize evolution (extend to other objects?)
'''
### attributes:
center_vec3 = numpy.array([0,0,0]) # Center point of the object. No default value.
size_vec3 = numpy.array([1,1,1]) # The lengths of the block edges along each of its three axes. Not really a 3-vector (at least, not in the lattice basis), but it has three components, each of which should be nonzero. No default value.
# The directions of the axes of the block; the lengths of these vectors are ignored. Must be linearly independent. They default to the three lattice directions.
# The block will be filled with lines going along e1, in layers in the (e1,e2) plane, stacked along e3.
e1_vec3 = numpy.array([1,0,0])
e2_vec3 = numpy.array([0,1,0])
e3_vec3 = numpy.array([0,0,1])
LineNumber_vec3 = [5,5,5]
# WARNING: voxelsize and overlap in this class relate to e1,e2,e3 which are chosen by the user, not the usual x,y,z!!!
# TODO: Rename those variables to reflect the dependency on e1,e2,e3 instead of x,y,z. Or create smarter system.
voxelsize_vec3 = numpy.array([0.150,0.150,0.450])
# should the lines all be connected or not
connected = False
# TODO: enable/disable zigzag as well... Towards a single "block/quad" class...
###################################
# to be discarded and replaced by internal or external parameter calculating functions
overlap_vec3 = numpy.array([0,0,0.5])
voxelsize_vec3_xyz = numpy.array([0.150,0.150,0.450])
overlap_vec3_xyz = numpy.array([0,0,0.5])
###################################
def __init__(self):
GWLobject.__init__(self)
[docs] def getNormalizedVectors(self):
self.e1_vec3 = numpy.array(self.e1_vec3)
self.e2_vec3 = numpy.array(self.e2_vec3)
self.e3_vec3 = numpy.array(self.e3_vec3)
e1_vec3_norm = self.e1_vec3/norm(self.e1_vec3)
e2_vec3_norm = self.e2_vec3/norm(self.e2_vec3)
e3_vec3_norm = self.e3_vec3/norm(self.e3_vec3)
return (e1_vec3_norm, e2_vec3_norm, e3_vec3_norm)
[docs] def setSizeFromVectors(self):
self.e1_vec3 = numpy.array(self.e1_vec3)
self.e2_vec3 = numpy.array(self.e2_vec3)
self.e3_vec3 = numpy.array(self.e3_vec3)
self.size_vec3 = numpy.array( [norm(self.e1_vec3), norm(self.e2_vec3), norm(self.e3_vec3)] )
return
[docs] def setFromLine(self, A, B, rod_width, rod_height, orthogonal, orientation):
A = array(A)
B = array(B)
self.center_vec3 = 0.5*(A+B)
size = [norm(B-A), rod_width, rod_height]
self.size_vec3 = numpy.array([size[orientation[0]], size[orientation[1]], size[orientation[2]]])
self.voxelsize_vec3 = numpy.array([self.voxelsize_vec3_xyz[orientation[0]], self.voxelsize_vec3_xyz[orientation[1]], self.voxelsize_vec3_xyz[orientation[2]]])
self.overlap_vec3 = numpy.array([self.overlap_vec3_xyz[orientation[0]], self.overlap_vec3_xyz[orientation[1]], self.overlap_vec3_xyz[orientation[2]]])
#self.size_vec3 = [norm(B-A), rod_width, rod_height]
x = array([1,0,0])
y = array([0,1,0])
z = array([0,0,1])
if norm(B-A)==0:
e1 = x
e2 = y
e3 = z
else:
e1 = B-A
if norm(cross(z,e1)) == 0:
e1 = dot(e1,z)*z
e3 = y # choice based on nanoscribe InvertZAxis system
e2 = cross(e3,e1)
else:
e2 = cross(z,e1)
if orthogonal:
#print('orthogonal')
e3 = cross(e1,e2)
else:
#print('non-orthogonal')
e3 = z
elist = [e1,e2,e3]
self.e1_vec3 = elist[orientation[0]]
self.e2_vec3 = elist[orientation[1]]
self.e3_vec3 = elist[orientation[2]]
return
[docs] def getMinMaxPoints(self):
(e1_vec3_norm, e2_vec3_norm, e3_vec3_norm) = self.getNormalizedVectors()
e1min = self.center_vec3 - self.size_vec3[0]*e1_vec3_norm
e1max = self.center_vec3 + self.size_vec3[0]*e1_vec3_norm
e2min = self.center_vec3 - self.size_vec3[1]*e2_vec3_norm
e2max = self.center_vec3 + self.size_vec3[1]*e2_vec3_norm
e3min = self.center_vec3 - self.size_vec3[2]*e3_vec3_norm
e3max = self.center_vec3 + self.size_vec3[2]*e3_vec3_norm
return (e1min, e1max, e2min, e2max, e3min, e3max)
[docs] def computeVectors(self):
# TODO
(e1min, e1max, e2min, e2max, e3min, e3max) = self.getMinMaxPoints()
self.addLine()
self.addLine()
self.addLine()
return
[docs] def computeOutline(self):
# TODO
self.addLine()
self.addLine()
self.addLine()
self.addLine()
self.addLine()
self.addLine()
self.addLine()
self.addLine()
self.addLine()
self.addLine()
self.addLine()
self.addLine()
return
[docs] def computePoints(self):
self.clear()
#self.e1_vec3 = numpy.array(self.e1_vec3)
#self.e2_vec3 = numpy.array(self.e2_vec3)
#self.e3_vec3 = numpy.array(self.e3_vec3)
#e1_vec3_norm = self.e1_vec3/numpy.linalg.norm(self.e1_vec3)
#e2_vec3_norm = self.e2_vec3/numpy.linalg.norm(self.e2_vec3)
#e3_vec3_norm = self.e3_vec3/numpy.linalg.norm(self.e3_vec3)
(e1_vec3_norm, e2_vec3_norm, e3_vec3_norm) = self.getNormalizedVectors()
self.center_vec3 = numpy.array(self.center_vec3)
#(LineNumber_e2, LineDistance_e2) = calculateNvoxelsAndInterVoxelDistance(Length=self.size_vec3[1], Voxelsize=self.voxelsize_vec3[1], Overlap=self.overlap_vec3[1])
#(LineNumber_e3, LineDistance_e3) = calculateNvoxelsAndInterVoxelDistance(Length=self.size_vec3[2], Voxelsize=self.voxelsize_vec3[2], Overlap=self.overlap_vec3[2])
LineNumber_e1 = self.LineNumber_vec3[0]
LineNumber_e2 = self.LineNumber_vec3[1]
LineNumber_e3 = self.LineNumber_vec3[2]
e2_list = []
L = self.size_vec3[1] #(LineNumber_e2-1)*LineDistance_e2
if LineNumber_e2 > 1:
e2_list = numpy.linspace(-0.5*L, 0.5*L, LineNumber_e2)
else:
e2_list = [0]
e3_list = []
L = self.size_vec3[2] #(LineNumber_e3-1)*LineDistance_e3
if LineNumber_e3 > 1:
e3_list = numpy.linspace(-0.5*L, 0.5*L, LineNumber_e3)
else:
e3_list = [0]
#print(e2_list)
#print(e3_list)
pointList = []
counter = 0
counter_e2 = 0
for e3_factor in e3_list:
for e2_idx in range(len(e2_list)):
if counter_e2%2 == 0:
e2_factor = e2_list[e2_idx]
else:
e2_factor = e2_list[-e2_idx-1]
#print(self.center_vec3)
#print(self.size_vec3[0])
#print(self.voxelsize_vec3[0])
#print((-0.5*(self.size_vec3[0]-self.voxelsize_vec3[0])))
#print(e1_vec3_norm)
#print(e2_vec3_norm)
#print(e3_vec3_norm)
#print(e2_factor)
#print(e3_factor)
#A = self.center_vec3 + (-0.5*(self.size_vec3[0]-self.voxelsize_vec3[0]))*e1_vec3_norm + e2_factor*e2_vec3_norm + e3_factor*e3_vec3_norm
#B = self.center_vec3 + (0.5*(self.size_vec3[0]-self.voxelsize_vec3[0]))*e1_vec3_norm + e2_factor*e2_vec3_norm + e3_factor*e3_vec3_norm
A = self.center_vec3 + (-0.5*self.size_vec3[0])*e1_vec3_norm + e2_factor*e2_vec3_norm + e3_factor*e3_vec3_norm
B = self.center_vec3 + (0.5*self.size_vec3[0])*e1_vec3_norm + e2_factor*e2_vec3_norm + e3_factor*e3_vec3_norm
#print(A)
#print(B)
if counter%2 == 0:
pointList.append(A)
pointList.append(B)
if not self.connected:
self.GWL_voxels.append(pointList)
pointList = []
else:
pointList.append(B)
pointList.append(A)
if not self.connected:
self.GWL_voxels.append(pointList)
pointList = []
counter += 1
counter_e2 += 1
if self.connected:
self.GWL_voxels.append(pointList)
[docs] def writeGWL(self, filename, writingOffset = [0,0,0,0]):
self.computePoints()
GWLobject.writeGWL(self, filename, writingOffset)
return
[docs] def getMeshData(self):
self.computePoints()
return(GWLobject.getMeshData(self))
[docs]def test0():
foo = Parallelepiped()
print(foo.getMeshData())
return
[docs]def test1():
A = [0,0,0]
B = [10,0,0]
orthogonal = False
para = Parallelepiped()
para.LineNumber_vec3 = [3,4,5]
#para.voxelsize_vec3 = [0.1,0.1,0.1]
#para.overlap_vec3 = [0,0,0]
para.setFromLine(A, B,2,3,orthogonal,[0,1,2])
para.computePoints()
para.writeGWL(tempfile.gettempdir()+os.sep+'Parallelepiped_012.gwl')
para.setFromLine(A, B,2,3,orthogonal,[1,2,0])
para.computePoints()
para.writeGWL(tempfile.gettempdir()+os.sep+'Parallelepiped_120.gwl')
para.setFromLine(A, B,2,3,orthogonal,[2,0,1])
para.computePoints()
para.writeGWL(tempfile.gettempdir()+os.sep+'Parallelepiped_201.gwl')
para.setFromLine(A, B,2,3,orthogonal,[0,2,1])
para.computePoints()
para.writeGWL(tempfile.gettempdir()+os.sep+'Parallelepiped_021.gwl')
para.setFromLine(A, B,2,3,orthogonal,[2,1,0])
para.computePoints()
para.writeGWL(tempfile.gettempdir()+os.sep+'Parallelepiped_210.gwl')
para.setFromLine(A, B,2,3,orthogonal,[1,0,2])
para.computePoints()
para.writeGWL(tempfile.gettempdir()+os.sep+'Parallelepiped_102.gwl')
return
if __name__ == "__main__":
test0()
test1()