Work on rotate method for geometry objects.

这个提交包含在:
craig-warren
2020-05-18 15:53:51 +01:00
父节点 50890d4b10
当前提交 6ebbe8a730
共有 17 个文件被更改,包括 188 次插入77 次删除

查看文件

@@ -22,12 +22,12 @@ from .cmds_geometry.geometry_objects_read import GeometryObjectsRead
from .cmds_geometry.plate import Plate
from .cmds_geometry.sphere import Sphere
from .cmds_geometry.triangle import Triangle
from .cmds_multiple import (PMLCFS, AddDebyeDispersion, AddDrudeDispersion,
from .cmds_multiuse import (PMLCFS, AddDebyeDispersion, AddDrudeDispersion,
AddLorentzDispersion, GeometryObjectsWrite,
GeometryView, HertzianDipole, MagneticDipole,
Material, Rx, RxArray, Snapshot, SoilPeplinski,
TransmissionLine, VoltageSource, Waveform)
from .cmds_single_use import (Discretisation, Domain, ExcitationFile,
from .cmds_singleuse import (Discretisation, Domain, ExcitationFile,
NumThreads, PMLCells, RxSteps, SrcSteps,
TimeStepStabilityFactor, TimeWindow, Title)
from .gprMax import run as run

查看文件

@@ -1,4 +1,4 @@
# This is where the version number is set and read by setup.py and conf.py (for the docs)
__version__ = '3.2.0b0'
__version__ = '4.0.0b0'
codename = 'Johns whisky choice!'

查看文件

@@ -46,6 +46,13 @@ class Box(UserObjectGeometry):
super().__init__(**kwargs)
self.hash = '#box'
def rotate(self, pts, axis, angle, origin=None):
pts = np.array([[self.kwargs['p1']], [self.kwargs['p1']]])
rotation = UserObjectGeometry.rotate_2point_object
rot_pts = rotation(self, pts, axis, angle, origin)
self.kwargs['p1'] = tuple(rot_pts[0, :])
self.kwargs['p1'] = tuple(rot_pts[1, :])
def create(self, grid, uip):
try:
p1 = self.kwargs['p1']

查看文件

@@ -47,20 +47,54 @@ class UserObjectGeometry:
"""Create the object and add it to the grid."""
pass
def rotate(self, axis, angle):
"""Rotate geometry object.
def rotate_point(self, p, axis, angle, origin=(0, 0, 0)):
"""Rotate a point.
Args:
p (array): coordinates of point (x, y, z)
axis (str): axis about which to perform rotation (x, y, or z)
angle (int): angle of rotation (degrees)
origin (tuple): point about which to perform rotation (x, y, z)
Returns:
p (array): coordinates of rotated point (x, y, z)
"""
orig_p1 = self.kwargs['p1']
orig_p2 = self.kwargs['p2']
p1 = np.array([self.kwargs['p1']])
p2 = np.array([self.kwargs['p2']])
origin = np.array([origin])
# Move point to axis of rotation
p -= origin
# Calculate rotation matrix
r = R.from_euler(axis, angle, degrees=True)
# Apply rotation
p = r.apply(p)
# Move object back to original axis
p += origin
return p
def rotate_2point_object(self, pts, axis, angle, origin=None):
"""Rotate a geometry object that is defined by 2 points.
Args:
pts (array): coordinates of points of object to be rotated
axis (str): axis about which to perform rotation (x, y, or z)
angle (int): angle of rotation (degrees)
origin (tuple): point about which to perform rotation (x, y, z)
Returns:
new_pts (array): coordinates of points of rotated object
"""
# Use origin at centre of object if not given
if not origin:
origin = pts[0,:] + (pts[1,:] - pts[0,:]) / 2
# Check angle value is suitable
angle = int(angle)
if angle < 0 or angle > 360:
logger.exception(self.__str__() + ' angle of rotation must be between 0-360 degrees')
raise ValueError
@@ -68,59 +102,33 @@ class UserObjectGeometry:
logger.exception(self.__str__() + ' angle of rotation must be a multiple of 90 degrees')
raise ValueError
# Check axis is valid
if axis != 'x' and axis != 'y' and axis != 'z':
logger.exception(self.__str__() + ' axis of rotation must be x, y, or z')
raise ValueError
# Coordinates for axis of rotation (centre of object)
offset = p1 + (p2 - p1) / 2
# Save original points
orig_pts = pts
# Move object to axis of rotation
p1 -= offset
p2 -= offset
# Calculate rotation matrix
r = R.from_euler(axis, angle, degrees=True)
# Apply rotation
p1 = r.apply(p1)
p2 = r.apply(p2)
# Move object back to original axis
p1 += offset
p2 += offset
# Rotate points that define object
pts[0, :] = self.rotate_point(pts[0, :], axis, angle, origin)
pts[1, :] = self.rotate_point(pts[1, :], axis, angle, origin)
# Get lower left and upper right coordinates to define new object
tmp = np.concatenate((p1, p2), axis=0)
p1 = np.min(tmp, axis=0)
p2 = np.max(tmp, axis=0)
new_pts = np.zeros(pts.shape)
new_pts[0, :] = np.min(pts, axis=0)
new_pts[1, :] = np.max(pts, axis=0)
# For 2D modes check axis of rotation against mode
# and correct invariant coordinate
# mode = config.get_model_config().mode
mode = 'TMz'
if mode == 'TMx':
if axis == 'y' or axis =='z':
logger.exception(self.__str__() +
' axis of rotation must be x for TMx mode models')
raise ValueError
p1[2] = orig_p1[0]
p2[2] = orig_p2[0]
elif mode == 'TMy':
if axis == 'x' or axis == 'z':
logger.exception(self.__str__() +
' axis of rotation must be x for TMy mode models')
raise ValueError
p1[2] = orig_p1[1]
p2[2] = orig_p2[1]
elif mode == 'TMz':
if axis == 'x' or axis == 'y':
logger.exception(self.__str__() +
' axis of rotation must be x for TMz mode models')
raise ValueError
p1[2] = orig_p1[2]
p2[2] = orig_p2[2]
# Reset coordinates of invariant direction
# - only needed for 2D models, has no effect on 3D models.
if axis =='x':
new_pts[0, 0] = orig_pts[0, 0]
new_pts[1, 0] = orig_pts[1, 0]
elif axis == 'y':
new_pts[0, 1] = orig_pts[0, 1]
new_pts[1, 1] = orig_pts[1, 1]
elif axis == 'z':
new_pts[0, 2] = orig_pts[0, 2]
new_pts[1, 2] = orig_pts[1, 2]
# Write points back to original tuple
self.kwargs['p1'] = tuple(p1)
self.kwargs['p2'] = tuple(p2)
return new_pts

查看文件

@@ -58,6 +58,9 @@ class CylindricalSector(UserObjectGeometry):
super().__init__(**kwargs)
self.hash = '#cylindrical_sector'
def rotate(self, axis, angle, origin=None):
pass
def create(self, grid, uip):
try:

查看文件

@@ -36,6 +36,9 @@ class GeometryObjectsRead(UserObjectGeometry):
super().__init__(**kwargs)
self.hash = '#geometry_objects_read'
def rotate(self, axis, angle, origin=None):
pass
def create(self, G, uip):
"""Create the object and add it to the grid."""
try:

查看文件

@@ -46,6 +46,9 @@ class Sphere(UserObjectGeometry):
super().__init__(**kwargs)
self.hash = '#sphere'
def rotate(self, axis, angle, origin=None):
pass
def create(self, grid, uip):
try:
p1 = self.kwargs['p1']

查看文件

@@ -50,6 +50,10 @@ class Triangle(UserObjectGeometry):
super().__init__(**kwargs)
self.hash = '#triangle'
def rotate(self, axis, angle, origin=None):
logger.debug('Add rotate method.')
pass
def create(self, grid, uip):
try:
up1 = self.kwargs['p1']

查看文件

@@ -48,6 +48,7 @@ class UserObjectMulti:
self.order = None
self.hash = '#example'
self.autotranslate = True
self.rotate_point = UserObjectGeometry.rotate_point
def __str__(self):
"""Readable user string as per hash commands."""
@@ -63,11 +64,11 @@ class UserObjectMulti:
"""Create the object and add it to the grid."""
pass
def rotate(self, axis, angle):
def rotate(self, axis, angle, origin=None):
pass
def params_str(self):
"""Readble string of parameters given to object."""
"""Readable string of parameters given to object."""
return self.hash + ': ' + str(self.kwargs)
@@ -140,6 +141,70 @@ class VoltageSource(UserObjectMulti):
self.order = 2
self.hash = '#voltage_source'
def rotate(self, axis, angle, origin=(0, 0, 0)):
"""Rotate geometry object.
Args:
axis (str): axis about which to perform rotation (x, y, or z)
angle (int): angle of rotation (degrees)
origin (tuple): point about which to perform rotation (x, y, z)
"""
# Check angle value is suitable
angle = int(angle)
if angle < 0 or angle > 360:
logger.exception(
self.__str__() + ' angle of rotation must be between 0-360 degrees')
raise ValueError
if angle % 90 != 0:
logger.exception(
self.__str__() + ' angle of rotation must be a multiple of 90 degrees')
raise ValueError
# Check axis is valid
if axis != 'x' and axis != 'y' and axis != 'z':
logger.exception(self.__str__() +
' axis of rotation must be x, y, or z')
raise ValueError
# Save original point
origp = self.kwargs['p1']
# Rotate point
p = self.rotate_point(self, origp, axis, angle, origin)
p = np.array([p])
# Reset coordinates of invariant direction
# - only needed for 2D models, has no effect on 3D models.
# Set polarisation depending on rotation angle
if axis == 'x':
p[0] = origp[0]
if self.kwargs['polarisation'].lower() == 'y':
if angle == 90 or angle == 270:
self.kwargs['polarisation'] = 'z'
elif self.kwargs['polarisation'].lower() =='z':
if angle == 90 or angle == 270:
self.kwargs['polarisation'] = 'y'
elif axis == 'y':
p[1] = origp[1]
if self.kwargs['polarisation'].lower() == 'x':
if angle == 90 or angle == 270:
self.kwargs['polarisation'] = 'z'
elif self.kwargs['polarisation'].lower() == 'z':
if angle == 90 or angle == 270:
self.kwargs['polarisation'] = 'x'
elif axis == 'z':
p[2] = origp[2]
if self.kwargs['polarisation'].lower() == 'x':
if angle == 90 or angle == 270:
self.kwargs['polarisation'] = 'y'
elif self.kwargs['polarisation'].lower() == 'y':
if angle == 90 or angle == 270:
self.kwargs['polarisation'] = 'x'
# Write point back to original tuple
self.kwargs['p1'] = tuple(p)
def create(self, grid, uip):
try:
p1 = self.kwargs['p1']
@@ -552,7 +617,7 @@ class Rx(UserObjectMulti):
try:
r.ID = self.kwargs['id']
outputs = self.kwargs['outputs']
outputs = [self.kwargs['outputs']]
except KeyError:
# If no ID or outputs are specified, use default
r.ID = r.__class__.__name__ + '(' + str(r.xcoord) + ',' + str(r.ycoord) + ',' + str(r.zcoord) + ')'

查看文件

@@ -55,7 +55,7 @@ class UserObjectSingle:
def create(self, grid, uip):
pass
def rotate(self, axis, angle):
def rotate(self, axis, angle, origin=None):
pass

查看文件

@@ -285,7 +285,24 @@ class GeometryView:
if not materialsonly:
# Information on PML thickness
if G.pmls:
root.set('PMLthickness', list(G.pmlthickness.values()))
# Only render PMLs if they are in the geometry view
pmlstorender = dict.fromkeys(G.pmlthickness, 0)
xmax = G.nx - self.vtk_xfcells
ymax = G.ny - self.vtk_yfcells
zmax = G.nz - self.vtk_zfcells
if G.pmlthickness['x0'] - self.vtk_xscells > 0:
pmlstorender['x0'] = G.pmlthickness['x0']
if G.pmlthickness['y0'] - self.vtk_yscells > 0:
pmlstorender['y0'] = G.pmlthickness['y0']
if G.pmlthickness['z0'] - self.vtk_zscells > 0:
pmlstorender['z0'] = G.pmlthickness['z0']
if self.vtk_xfcells > G.nx - G.pmlthickness['xmax']:
pmlstorender['xmax'] = G.pmlthickness['xmax']
if self.vtk_yfcells > G.ny - G.pmlthickness['ymax']:
pmlstorender['ymax'] = G.pmlthickness['ymax']
if self.vtk_zfcells > G.nz - G.pmlthickness['zmax']:
pmlstorender['zmax'] = G.pmlthickness['zmax']
root.set('PMLthickness', list(pmlstorender.values()))
# Location of sources and receivers
srcs = G.hertziandipoles + G.magneticdipoles + G.voltagesources + G.transmissionlines
if srcs:

查看文件

@@ -18,7 +18,7 @@
import logging
from .cmds_multiple import (PMLCFS, AddDebyeDispersion, AddDrudeDispersion,
from .cmds_multiuse import (PMLCFS, AddDebyeDispersion, AddDrudeDispersion,
AddLorentzDispersion, GeometryObjectsWrite,
GeometryView, HertzianDipole, MagneticDipole,
Material, Rx, RxArray, Snapshot, SoilPeplinski,
@@ -128,7 +128,7 @@ def process_multicmds(multicmds):
if len(tmp) == 3:
rx = Rx(p1=(float(tmp[0]), float(tmp[1]), float(tmp[2])))
else:
rx = Rx(p1=(float(tmp[0]), float(tmp[1]), float(tmp[2])), id=tmp[3], outputs=tmp[4:])
rx = Rx(p1=(float(tmp[0]), float(tmp[1]), float(tmp[2])), id=tmp[3], outputs=' '.join(tmp[4:]))
scene_objects.append(rx)

查看文件

@@ -18,7 +18,7 @@
import logging
from .cmds_single_use import (Discretisation, Domain, ExcitationFile,
from .cmds_singleuse import (Discretisation, Domain, ExcitationFile,
NumThreads, OutputDir, PMLCells, RxSteps,
SrcSteps, TimeStepStabilityFactor, TimeWindow,
Title)

查看文件

@@ -20,8 +20,8 @@ import logging
from .cmds_geometry.cmds_geometry import UserObjectGeometry
from .cmds_geometry.fractal_box_builder import FractalBoxBuilder
from .cmds_multiple import UserObjectMulti
from .cmds_single_use import (Discretisation, Domain, TimeWindow,
from .cmds_multiuse import UserObjectMulti
from .cmds_singleuse import (Discretisation, Domain, TimeWindow,
UserObjectSingle)
from .materials import create_built_in_materials
from .subgrids.user_objects import SubGridBase as SubGridUserBase

查看文件

@@ -32,7 +32,8 @@ class SubGridBase(FDTDGrid):
self.ratio = kwargs['ratio']
if self.ratio % 2 == 0:
raise ValueError('Subgrid Error: Only odd ratios are supported')
logger.exception('Subgrid Error: Only odd ratios are supported')
raise ValueError
# Name of the grid
self.name = kwargs['id']

查看文件

@@ -151,7 +151,7 @@ class SubGridHSG(SubGridBase):
s += f' Working region cells: {self.nwx} x {self.nwy} x {self.nwz}\n'
for h in self.hertziandipoles:
s += f' Hertizian dipole at {h.xcoord} {h.ycoord} {h.zcoord}\n'
s += f' Hertzian dipole at {h.xcoord} {h.ycoord} {h.zcoord}\n'
s += ' ' + str([x for x in self.waveforms
if x.ID == h.waveformID][0]) + '\n'
for r in self.rxs:

查看文件

@@ -23,7 +23,7 @@ import numpy as np
from gprMax import config
from ..cmds_geometry.cmds_geometry import UserObjectGeometry
from ..cmds_multiple import Rx, UserObjectMulti
from ..cmds_multiuse import Rx, UserObjectMulti
from .multi import ReferenceRx as ReferenceRxUser
from .subgrid_hsg import SubGridHSG as SubGridHSGUser
@@ -129,13 +129,13 @@ class SubGridBase(UserObjectMulti):
# Copy over built in materials
sg.materials = [copy(m) for m in grid.materials if m.numID in range(0, grid.n_built_in_materials + 1)]
# Dont mix and match different subgrids
# Don't mix and match different subgrid types
for sg_made in grid.subgrids:
if type(sg) != type(sg_made):
logger.exception(self.__str__() + ' please only use one type of subgrid')
raise ValueError
# Reference the sub grid under the main grid to which it belongs.
# Reference the subgrid under the main grid to which it belongs
grid.subgrids.append(sg)