Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
6033766
initial commit
Aug 2, 2021
22f13b2
some fuse work
Aug 2, 2021
5dae549
more work
Aug 3, 2021
9b054c0
more work
Aug 3, 2021
14c732c
more conversion
Aug 3, 2021
efdb6bc
more conversion
Aug 3, 2021
12dd1b0
more conversion
Aug 3, 2021
8be8f96
more conversion
Aug 4, 2021
36b413d
fix airfoils
Aug 4, 2021
f868ede
fix airfoils
Aug 4, 2021
f637f60
return airplane
Aug 4, 2021
9951a31
try drawing
Aug 4, 2021
d797e51
get wing working
Aug 4, 2021
5d464d6
wing working
Aug 4, 2021
bbb7b5d
remove print statements
Aug 4, 2021
4932ae0
cleanup
Aug 4, 2021
a77afe9
fix airfoil but for naca 6
Aug 4, 2021
5816a8d
fix naca6 naming
Aug 5, 2021
c2bd975
add debug
Aug 5, 2021
67e0bb3
fix typo
Aug 5, 2021
5229c3e
try using tip chord
Aug 5, 2021
84872b0
try using tip chord
Aug 5, 2021
67ff354
test hack
Aug 5, 2021
fca9fb9
test hack
Aug 5, 2021
38be2b8
test hack
Aug 5, 2021
c326106
test hack
Aug 5, 2021
598a76c
more hacking
Aug 5, 2021
1b86327
add )
Aug 5, 2021
ede8459
add )
Aug 5, 2021
25e4224
add )
Aug 5, 2021
ff11b21
root/tip work
Aug 5, 2021
06e3010
root/tip work
Aug 5, 2021
53db5a0
root/tip work
Aug 5, 2021
df27a3f
root/tip work
Aug 5, 2021
807fbe4
root/tip work
Aug 5, 2021
8d92c88
root/tip work
Aug 5, 2021
03e441a
fuse radius improvement
Aug 5, 2021
ecbd96d
fuse radius improvement
Aug 5, 2021
f15617e
fuse radius improvement
Aug 5, 2021
8d21264
fuse radius improvement
Aug 5, 2021
39eeb4d
root/tip work
Aug 5, 2021
3c0d590
check rotation
Aug 5, 2021
51b9d42
check rotation
Aug 5, 2021
16f62cf
try rotation matrix
Aug 5, 2021
cb86bd1
try rotation matrix
Aug 5, 2021
45f98c9
try rotation matrix
Aug 5, 2021
a7cac6a
try using geometry surface
Aug 6, 2021
b13e7e5
try using geometry surface
Aug 6, 2021
d1b9dc8
try using geometry surface
Aug 6, 2021
a935837
try using geometry surface
Aug 6, 2021
fdf211a
try using geometry surface
Aug 6, 2021
16d31a6
try using geometry surface
Aug 6, 2021
8c1f051
try using geometry surface
Aug 6, 2021
982315e
try using geometry surface
Aug 6, 2021
f84e2d9
try using geometry surface
Aug 6, 2021
4eda7db
code cleanup
Aug 6, 2021
79ef036
cleanup and add comments
Aug 6, 2021
3d70c07
cleanup and add comments
Aug 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions aerosandbox/tools/openvsp/vsp_read.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Created: Jun 2018, T. St Francis
# Modified: Aug 2021 Michael Shamberger
# Aug 2018, T. St Francis
# Jan 2020, T. MacDonald
# Jul 2020, E. Botero
# Original code taken from Suave project and modified for AeroSandbox

import aerosandbox
from aerosandbox.geometry import Airplane
from aerosandbox.tools.openvsp.vsp_read_fuselage import vsp_read_fuselage
from aerosandbox.tools.openvsp.vsp_read_wing import vsp_read_wing
import aerosandbox.numpy as np

import openvsp as vsp


# ----------------------------------------------------------------------
# vsp read
# ----------------------------------------------------------------------
def vsp_read(tag):
"""This reads an OpenVSP vehicle geometry and writes it into a Aerosandbox vehicle format.
Includes wings, fuselages, and propellers.

Assumptions:
1. OpenVSP vehicle is composed of conventionally shaped fuselages, wings, and propellers.
1a. OpenVSP fuselage: generally narrow at nose and tail, wider in center).
1b. Fuselage is designed in VSP as it appears in real life. That is, the VSP model does not rely on
superficial elements such as canopies, stacks, or additional fuselages to cover up internal lofting oddities.
1c. This program will NOT account for multiple geometries comprising the fuselage. For example: a wingbox mounted beneath
is a separate geometry and will NOT be processed.
2. Fuselage origin is located at nose. VSP file origin can be located anywhere, preferably at the forward tip
of the vehicle or in front (to make all X-coordinates of vehicle positive).
3. Written for OpenVSP 3.24

Source:
N/A

Inputs:
1. A tag for an XML file in format .vsp3.

Outputs:
Writes Aerosandbox vehicle

Properties Used:
N/A
"""

vsp.ClearVSPModel()
vsp.ReadVSPFile(tag)

vsp_fuselages = []
vsp_wings = []
vsp_props = []
vsp_geoms = vsp.FindGeoms()
geom_names = []

# The two for-loops below are in anticipation of an OpenVSP API update with a call for GETGEOMTYPE.
# This print function allows user to enter VSP GeomID manually as first argument in vsp_read functions.
print("VSP geometry IDs: ")

# Label each geom type by storing its VSP geom ID.
for geom in vsp_geoms:
geom_name = vsp.GetGeomName(geom)
geom_names.append(geom_name)
print(str(geom_name) + ': ' + geom)

# --------------------------------
# AUTOMATIC VSP ENTRY & PROCESSING
# --------------------------------
for geom in vsp_geoms:
geom_name = vsp.GetGeomTypeName(str(geom))

if geom_name == 'Fuselage':
vsp_fuselages.append(geom)
if geom_name == 'Wing':
vsp_wings.append(geom)
# No aerosandbox propeller geometry class available
#if geom_name == 'Propeller':
# vsp_props.append(geom)

#Read VSP geoms and store in Aerosandbox components
xyz_ref = np.array([0, 0, 0])
fuselages = []
for fuselage_id in vsp_fuselages:
fuselages.append(vsp_read_fuselage(fuselage_id))

wings = []
for wing_id in vsp_wings:
wings.append(vsp_read_wing(wing_id))

return Airplane(tag, xyz_ref, wings, fuselages)
117 changes: 117 additions & 0 deletions aerosandbox/tools/openvsp/vsp_read_fuselage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import aerosandbox
from aerosandbox.geometry import Fuselage
from aerosandbox.geometry import FuselageXSec
import openvsp as vsp
import aerosandbox.numpy as np
from ctypes import *

# ----------------------------------------------------------------------
# vsp read fuselage
# ----------------------------------------------------------------------

def vsp_read_fuselage(fuselage_id):
"""This reads an OpenVSP fuselage geometry and writes it to a aerosandbox fuselage format.

Assumptions:
1. OpenVSP fuselage is "conventionally shaped" (generally narrow at nose and tail, wider in center).
2. Fuselage is designed in VSP as it appears in real life. That is, the VSP model does not rely on
superficial elements such as canopies, stacks, or additional fuselages to cover up internal lofting oddities.
3. This program will NOT account for multiple geometries comprising the fuselage. For example: a wingbox mounted beneath
is a separate geometry and will NOT be processed.
4. Fuselage origin is located at nose. VSP file origin can be located anywhere, preferably at the forward tip
of the vehicle or in front (to make all X-coordinates of vehicle positive).
5. Written for OpenVSP 3.24

Inputs:
0. Pre-loaded VSP vehicle in memory, via vsp_read.
1. VSP 10-digit geom ID for fuselage.

Outputs:
aerosandbox fuselage
"""

print("Converting fuselage: " + fuselage_id)
# get total length of fuselage
total_length = vsp.GetParmVal(fuselage_id, 'Length', 'Design')

# read the xsec data
xsec_root_id = vsp.GetXSecSurf(fuselage_id, 0)
xsec_num = vsp.GetNumXSec(xsec_root_id)
xsecs = []
for increment in range(0, xsec_num):
xsecs.append(getVspXSec(xsec_root_id, xsec_num, total_length, increment))
# get the name
if vsp.GetGeomName(fuselage_id):
tag = vsp.GetGeomName(fuselage_id)
else:
tag = 'FuselageGeom'
# get leading edge
xyz_le = np.array([0, 0, 0])
xyz_le[0] = vsp.GetParmVal(fuselage_id, 'X_Location', 'XForm')
xyz_le[1] = vsp.GetParmVal(fuselage_id, 'Y_Location', 'XForm')
xyz_le[2] = vsp.GetParmVal(fuselage_id, 'Z_Location', 'XForm')
# create the fuselage
return Fuselage(tag, xyz_le, xsecs)

# Get Fuselage segments
def getVspXSec(xsec_root_id, xsec_num, total_length, increment):
print(" Processing xsec: " + str(increment))
# Create the segment
#
xsec = vsp.GetXSec(xsec_root_id, increment) # VSP XSec ID.
xyz_c = getXsecCenter(xsec)
print(" center: " + str(xyz_c))

X_Loc_P = vsp.GetXSecParm(xsec, 'XLocPercent')
Y_Loc_P = vsp.GetXSecParm(xsec, 'YLocPercent')
Z_Loc_P = vsp.GetXSecParm(xsec, 'ZLocPercent')

height = vsp.GetXSecHeight(xsec)
width = vsp.GetXSecWidth(xsec)
percent_x_location = vsp.GetParmVal(X_Loc_P) # Along fuselage length.
percent_y_location = vsp.GetParmVal(Y_Loc_P)
percent_z_location = vsp.GetParmVal(Z_Loc_P ) # Vertical deviation of fuselage center.
effective_diameter = (height+width)/2.
radius = effective_diameter/2.

#xsec shape not supported for aerosandbox FuselageXSec
#shape = vsp.GetXSecShape(segment.vsp_data.xsec_id)
#shape_dict = {0:'point',1:'circle',2:'ellipse',3:'super ellipse',4:'rounded rectangle',5:'general fuse',6:'fuse file'}
#vsp_data.shape = shape_dict[shape]
return FuselageXSec(xyz_c, radius)

def getXsecCenter(xsec):
x = []
y = []
z = []
for increment in np.linspace(0,1,100):
point = vsp.ComputeXSecPnt(xsec, increment) # get xsec point at leading edge of tip chord
p = (c_double * 3).from_address(int(np.ctypeslib.as_array(point.data())))
x.append(p[0])
y.append(p[1])
z.append(p[2])
return np.array([sum(x) / len(x), sum(y) / len(y), sum(z) / len(z)])


def get_fuselage_height(fuselage, location):
"""This linearly estimates fuselage height at any percentage point (0,100) along fuselage length.

Inputs:
0. Pre-loaded VSP vehicle in memory, via vsp_read.
1. Suave fuselage [object], containing fuselage.vsp_data.xsec_num in its data structure.
2. Fuselage percentage point [float].

Outputs:
height [m]
"""
for jj in range(1, fuselage.vsp_data.xsec_num): # Begin at second section, working toward tail.
if fuselage.Segments[jj].percent_x_location>=location and fuselage.Segments[jj-1].percent_x_location<location:
# Find two sections on either side (or including) the desired fuselage length percentage.
a = fuselage.Segments[jj].percent_x_location
b = fuselage.Segments[jj-1].percent_x_location
a_height = fuselage.Segments[jj].height # Linear approximation.
b_height = fuselage.Segments[jj-1].height
slope = (a_height - b_height)/(a-b)
height = ((location-b)*(slope)) + (b_height)
break
return height
Loading