add mirror button (useful for asymmetric aircraft, like the BV-141)
This commit is contained in:
parent
fdd252e1c5
commit
b1e8917266
1 changed files with 112 additions and 43 deletions
|
@ -58,9 +58,9 @@ Possible variables are:
|
|||
|
||||
Of course, absolute FDM coordinates can then no longer directly be read from Blender's 3D view.
|
||||
The cursor coordinates display in the script area, however, shows the coordinates in YASim space.
|
||||
Note that object names don't contain XML indices but element numbers. YASim_hstab#2 is the third
|
||||
hstab in the whole file, not necessarily in its parent XML group. A floating point part in the
|
||||
object name (e.g. YASim_hstab#2.004) only means that the geometry has been reloaded that often.
|
||||
Note that object names don't contain XML indices but element numbers. YASim_flap0#2 is the third
|
||||
flap0 in the whole file, not necessarily in its parent XML group. A floating point part in the
|
||||
object name (e.g. YASim_flap0#2.004) only means that the geometry has been reloaded that often.
|
||||
It's an unavoidable consequence of how Blender deals with meshes.
|
||||
|
||||
|
||||
|
@ -68,14 +68,14 @@ Elements are displayed as follows:
|
|||
|
||||
cockpit -> monkey head
|
||||
fuselage -> blue "tube" (with only 12 sides for less clutter); center at "a"
|
||||
vstab -> red with yellow flaps
|
||||
wing/mstab/hstab -> green with yellow flaps/spoilers/slats (always 20 cm deep);
|
||||
vstab -> red with yellow controls surfaces (flap0, flap1, slat, spoiler)
|
||||
wing/mstab/hstab -> green with yellow control surfaces (which are always 20 cm deep);
|
||||
symmetric surfaces are only displayed on the left side
|
||||
thrusters (jet/propeller/thruster) -> dashed line from center to actionpt;
|
||||
arrow from actionpt along thrust vector (always 1 m long);
|
||||
propeller circle
|
||||
rotor -> radius and rel_len_blade_start circle, direction arrow,
|
||||
normal and forward vector, one blade at phi0
|
||||
rotor -> radius and rel_len_blade_start circle, normal and forward vector,
|
||||
one blade at phi0 with direction arrow near blade tip
|
||||
gear -> contact point and compression vector (no arrow head)
|
||||
tank -> cube (10 cm side length)
|
||||
weight -> inverted cone
|
||||
|
@ -84,6 +84,11 @@ Elements are displayed as follows:
|
|||
hook -> dashed line for up angle, T-line for down angle
|
||||
launchbar -> dashed line for up angles, T-line for down angles
|
||||
|
||||
|
||||
The Mirror button complements symmetrical surfaces (wing/hstab/mstab) and control surfaces
|
||||
(flap0/flap1/slat/spoiler). This is useful for asymmetrical aircraft, but has the disadvantage
|
||||
that it moves the surfaces' object centers from their usual place, yasim's [x, y, z] value,
|
||||
to [0, 0, 0]. Turning mirroring off restores the object center.
|
||||
"""
|
||||
|
||||
|
||||
|
@ -106,11 +111,12 @@ Elements are displayed as follows:
|
|||
#--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
import Blender, BPyMessages, string, math
|
||||
import Blender, BPyMessages, string, math, os
|
||||
from Blender.Mathutils import *
|
||||
from xml.sax import handler, make_parser
|
||||
|
||||
|
||||
CONFIG = string.split(os.getenv("BLENDER_YASIM_IMPORT") or "")
|
||||
YASIM_MATRIX = Matrix([-1, 0, 0, 0], [0, -1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1])
|
||||
ORIGIN = Vector(0, 0, 0)
|
||||
X = Vector(1, 0, 0)
|
||||
|
@ -119,12 +125,21 @@ Z = Vector(0, 0, 1)
|
|||
DEG2RAD = math.pi / 180
|
||||
RAD2DEG = 180 / math.pi
|
||||
|
||||
NO_EVENT = 0
|
||||
RELOAD_BUTTON = 1
|
||||
CURSOR_BUTTON = 2
|
||||
MIRROR_BUTTON = 3
|
||||
|
||||
|
||||
|
||||
class Global:
|
||||
verbose = "verbose" in CONFIG
|
||||
path = ""
|
||||
matrix = None
|
||||
cursor = ORIGIN
|
||||
last_cursor = Vector(Blender.Window.GetCursorPos())
|
||||
mirror = Blender.Draw.Create(0)
|
||||
|
||||
|
||||
|
||||
class Abort(Exception):
|
||||
|
@ -132,9 +147,11 @@ class Abort(Exception):
|
|||
self.msg = msg
|
||||
|
||||
|
||||
|
||||
def log(msg):
|
||||
#print(msg) # uncomment to get verbose log messages
|
||||
pass
|
||||
if Global.verbose:
|
||||
print(msg)
|
||||
|
||||
|
||||
|
||||
def error(msg):
|
||||
|
@ -142,12 +159,14 @@ def error(msg):
|
|||
Blender.Draw.PupMenu("Error%t|" + msg)
|
||||
|
||||
|
||||
|
||||
def getfloat(attrs, key, default):
|
||||
if attrs.has_key(key):
|
||||
return float(attrs[key])
|
||||
return default
|
||||
|
||||
|
||||
|
||||
def draw_dashed_line(mesh, start, end):
|
||||
w = 0.04
|
||||
step = w * (end - start).normalize()
|
||||
|
@ -161,6 +180,7 @@ def draw_dashed_line(mesh, start, end):
|
|||
mesh.edges.extend([n + 2 * i, n + 2 * i + 1])
|
||||
|
||||
|
||||
|
||||
def draw_arrow(mesh, start, end):
|
||||
v = end - start
|
||||
m = v.toTrackQuat('x', 'z').toMatrix().resize4x4() * TranslationMatrix(start)
|
||||
|
@ -171,6 +191,7 @@ def draw_arrow(mesh, start, end):
|
|||
mesh.edges.extend([[n, n + 1], [n + 1, n + 2], [n + 1, n + 3], [n + 4, n + 5]])
|
||||
|
||||
|
||||
|
||||
def draw_circle(mesh, numpoints, radius, matrix):
|
||||
n = len(mesh.verts)
|
||||
for i in range(numpoints):
|
||||
|
@ -182,6 +203,7 @@ def draw_circle(mesh, numpoints, radius, matrix):
|
|||
mesh.edges.extend([[n + i, n + i1]])
|
||||
|
||||
|
||||
|
||||
class Item:
|
||||
scene = Blender.Scene.GetCurrent()
|
||||
|
||||
|
@ -190,13 +212,21 @@ class Item:
|
|||
for f in mesh.faces:
|
||||
f.mode |= Blender.Mesh.FaceModes.TWOSIDE | Blender.Mesh.FaceModes.OBCOL
|
||||
|
||||
def set_color(self, mesh, name, color):
|
||||
def set_color(self, obj, name, color):
|
||||
mat = Blender.Material.New(name)
|
||||
mat.setRGBCol(color[0], color[1], color[2])
|
||||
mat.setAlpha(color[3])
|
||||
mat.mode |= Blender.Material.Modes.ZTRANSP | Blender.Material.Modes.TRANSPSHADOW
|
||||
obj.transp = True
|
||||
|
||||
mesh = obj.getData(mesh = True)
|
||||
mesh.materials += [mat]
|
||||
|
||||
for f in mesh.faces:
|
||||
f.smooth = True
|
||||
mesh.calcNormals()
|
||||
|
||||
|
||||
|
||||
class Cockpit(Item):
|
||||
def __init__(self, center):
|
||||
|
@ -206,6 +236,7 @@ class Cockpit(Item):
|
|||
obj.setMatrix(TranslationMatrix(center) * Global.matrix)
|
||||
|
||||
|
||||
|
||||
class Tank(Item):
|
||||
def __init__(self, name, center):
|
||||
mesh = Blender.Mesh.Primitives.Cube()
|
||||
|
@ -214,6 +245,7 @@ class Tank(Item):
|
|||
obj.setMatrix(TranslationMatrix(center) * Global.matrix)
|
||||
|
||||
|
||||
|
||||
class Ballast(Item):
|
||||
def __init__(self, name, center):
|
||||
mesh = Blender.Mesh.Primitives.Cylinder()
|
||||
|
@ -222,6 +254,7 @@ class Ballast(Item):
|
|||
obj.setMatrix(TranslationMatrix(center) * Global.matrix)
|
||||
|
||||
|
||||
|
||||
class Weight(Item):
|
||||
def __init__(self, name, center):
|
||||
mesh = Blender.Mesh.Primitives.Cone()
|
||||
|
@ -230,6 +263,7 @@ class Weight(Item):
|
|||
obj.setMatrix(TranslationMatrix(center) * Global.matrix)
|
||||
|
||||
|
||||
|
||||
class Gear(Item):
|
||||
def __init__(self, name, center, compression):
|
||||
mesh = Blender.Mesh.New()
|
||||
|
@ -239,6 +273,7 @@ class Gear(Item):
|
|||
obj.setMatrix(TranslationMatrix(center) * Global.matrix)
|
||||
|
||||
|
||||
|
||||
class Hook(Item):
|
||||
def __init__(self, name, center, length, up_angle, dn_angle):
|
||||
mesh = Blender.Mesh.New()
|
||||
|
@ -252,6 +287,7 @@ class Hook(Item):
|
|||
obj.setMatrix(TranslationMatrix(center) * Global.matrix)
|
||||
|
||||
|
||||
|
||||
class Launchbar(Item):
|
||||
def __init__(self, name, lb, lb_length, hb, hb_length, up_angle, dn_angle):
|
||||
mesh = Blender.Mesh.New()
|
||||
|
@ -266,6 +302,7 @@ class Launchbar(Item):
|
|||
obj.setMatrix(TranslationMatrix(lb) * Global.matrix)
|
||||
|
||||
|
||||
|
||||
class Hitch(Item):
|
||||
def __init__(self, name, center):
|
||||
mesh = Blender.Mesh.Primitives.Circle(8, 0.1)
|
||||
|
@ -273,6 +310,7 @@ class Hitch(Item):
|
|||
obj.setMatrix(RotationMatrix(90, 4, "x") * TranslationMatrix(center) * Global.matrix)
|
||||
|
||||
|
||||
|
||||
class Thrust:
|
||||
def set_actionpt(self, p):
|
||||
self.actionpt = p
|
||||
|
@ -281,6 +319,7 @@ class Thrust:
|
|||
self.thrustvector = d
|
||||
|
||||
|
||||
|
||||
class Thruster(Thrust, Item):
|
||||
def __init__(self, name, center, thrustvector):
|
||||
(self.name, self.center, self.actionpt, self.thrustvector) = (name, center, center, thrustvector)
|
||||
|
@ -294,6 +333,7 @@ class Thruster(Thrust, Item):
|
|||
obj.setMatrix(TranslationMatrix(self.center) * Global.matrix)
|
||||
|
||||
|
||||
|
||||
class Propeller(Thrust, Item):
|
||||
def __init__(self, name, center, radius):
|
||||
(self.name, self.center, self.radius, self.actionpt, self.thrustvector) = (name, center, radius, center, -X)
|
||||
|
@ -313,6 +353,7 @@ class Propeller(Thrust, Item):
|
|||
obj.setMatrix(TranslationMatrix(self.center) * Global.matrix)
|
||||
|
||||
|
||||
|
||||
class Jet(Thrust, Item):
|
||||
def __init__(self, name, center, rotate):
|
||||
(self.name, self.center, self.actionpt) = (name, center, center)
|
||||
|
@ -327,6 +368,7 @@ class Jet(Thrust, Item):
|
|||
obj.setMatrix(TranslationMatrix(self.center) * Global.matrix)
|
||||
|
||||
|
||||
|
||||
class Fuselage(Item):
|
||||
def __init__(self, name, a, b, width, taper, midpoint):
|
||||
numvert = 12
|
||||
|
@ -351,10 +393,10 @@ class Fuselage(Item):
|
|||
mesh.faces.extend([[i + numvert, i1 + numvert, i1 + 2 * numvert, i + 2 * numvert]])
|
||||
|
||||
mesh.verts.extend([ORIGIN, length * X])
|
||||
self.set_color(mesh, name + "mat", [0, 0, 0.5, 0.4])
|
||||
obj = self.scene.objects.new(mesh, name)
|
||||
obj.transp = True
|
||||
obj.setMatrix(axis.toTrackQuat('x', 'y').toMatrix().resize4x4() * TranslationMatrix(a) * Global.matrix)
|
||||
self.set_color(obj, name + "mat", [0, 0, 0.5, 0.4])
|
||||
|
||||
|
||||
|
||||
class Rotor(Item):
|
||||
|
@ -380,12 +422,13 @@ class Rotor(Item):
|
|||
obj.setMatrix(matrix * TranslationMatrix(center) * Global.matrix)
|
||||
|
||||
|
||||
|
||||
class Wing(Item):
|
||||
def __init__(self, name, root, length, chord, incidence, twist, taper, sweep, dihedral):
|
||||
# <1--0--2
|
||||
# \ | /
|
||||
# 4-3-5
|
||||
is_vstab = name.startswith("YASim_vstab")
|
||||
self.is_symmetric = not name.startswith("YASim_vstab#")
|
||||
mesh = Blender.Mesh.New()
|
||||
mesh.verts.extend([ORIGIN, ORIGIN + 0.5 * chord * X, ORIGIN - 0.5 * chord * X])
|
||||
tip = ORIGIN + math.cos(sweep * DEG2RAD) * length * Y - math.sin(sweep * DEG2RAD) * length * X
|
||||
|
@ -394,16 +437,23 @@ class Wing(Item):
|
|||
mesh.verts.extend([tip, tipfore, tipaft])
|
||||
mesh.faces.extend([[0, 1, 4, 3], [2, 0, 3, 5]])
|
||||
|
||||
self.set_color(mesh, name + "mat", [[0, 0.5, 0, 0.5], [0.5, 0, 0, 0.5]][is_vstab])
|
||||
self.make_twosided(mesh)
|
||||
|
||||
obj = self.scene.objects.new(mesh, name)
|
||||
obj.transp = True
|
||||
m = Euler(dihedral, -incidence, 0).toMatrix().resize4x4()
|
||||
m *= TranslationMatrix(root)
|
||||
obj.setMatrix(m * Global.matrix)
|
||||
mesh.transform(Euler(dihedral, -incidence, 0).toMatrix().resize4x4())
|
||||
self.set_color(obj, name + "mat", [[0.5, 0.0, 0, 0.5], [0.0, 0.5, 0, 0.5]][self.is_symmetric])
|
||||
(self.obj, self.mesh) = (obj, mesh)
|
||||
|
||||
if self.is_symmetric and Global.mirror.val:
|
||||
mod = obj.modifiers.append(Blender.Modifier.Type.MIRROR)
|
||||
mod[Blender.Modifier.Settings.AXIS_X] = False
|
||||
mod[Blender.Modifier.Settings.AXIS_Y] = True
|
||||
mod[Blender.Modifier.Settings.AXIS_Z] = False
|
||||
mesh.transform(TranslationMatrix(root)) # must move object center to x axis
|
||||
obj.setMatrix(Global.matrix)
|
||||
else:
|
||||
obj.setMatrix(TranslationMatrix(root) * Global.matrix)
|
||||
|
||||
def add_flap(self, name, start, end):
|
||||
a = Vector(self.mesh.verts[2].co)
|
||||
b = Vector(self.mesh.verts[5].co)
|
||||
|
@ -416,12 +466,18 @@ class Wing(Item):
|
|||
mesh.verts.extend([i0, i1, i0 + c, i1 + c])
|
||||
mesh.faces.extend([[0, 1, 3, 2]])
|
||||
|
||||
self.set_color(mesh, name + "mat", [0.8, 0.8, 0, 0.9])
|
||||
self.make_twosided(mesh)
|
||||
|
||||
obj = self.scene.objects.new(mesh, name)
|
||||
obj.transp = True
|
||||
obj.setMatrix(m)
|
||||
self.set_color(obj, name + "mat", [0.8, 0.8, 0, 0.9])
|
||||
|
||||
if self.is_symmetric and Global.mirror.val:
|
||||
mod = obj.modifiers.append(Blender.Modifier.Type.MIRROR)
|
||||
mod[Blender.Modifier.Settings.AXIS_X] = False
|
||||
mod[Blender.Modifier.Settings.AXIS_Y] = True
|
||||
mod[Blender.Modifier.Settings.AXIS_Z] = False
|
||||
|
||||
|
||||
|
||||
class import_yasim(handler.ContentHandler):
|
||||
|
@ -628,6 +684,7 @@ class import_yasim(handler.ContentHandler):
|
|||
self.items.pop()
|
||||
|
||||
|
||||
|
||||
def extract_matrix(path, tag):
|
||||
v = { 'x': 0.0, 'y': 0.0, 'z': 0.0, 'h': 0.0, 'p': 0.0, 'r': 0.0 }
|
||||
has_offsets = False
|
||||
|
@ -653,14 +710,13 @@ def extract_matrix(path, tag):
|
|||
return matrix
|
||||
|
||||
|
||||
def run_parser(path):
|
||||
|
||||
def load_yasim_config(path):
|
||||
if BPyMessages.Error_NoFile(path):
|
||||
return
|
||||
|
||||
editmode = Blender.Window.EditMode()
|
||||
if editmode:
|
||||
Blender.Window.EditMode(0)
|
||||
Blender.Window.WaitCursor(1)
|
||||
Blender.Window.EditMode(0)
|
||||
|
||||
print(("loading '%s'" % path))
|
||||
try:
|
||||
|
@ -687,61 +743,74 @@ def run_parser(path):
|
|||
|
||||
Blender.Window.RedrawAll()
|
||||
Blender.Window.WaitCursor(0)
|
||||
if editmode:
|
||||
Blender.Window.EditMode(1)
|
||||
|
||||
|
||||
def draw():
|
||||
|
||||
def gui_draw():
|
||||
from Blender import BGL, Draw
|
||||
(width, height) = Blender.Window.GetAreaSize()
|
||||
|
||||
BGL.glClearColor(0.4, 0.4, 0.45, 1)
|
||||
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
|
||||
Draw.PushButton("Reload YASim", 0, 5, 5, 100, 28)
|
||||
Draw.PushButton("Update Cursor", 1, width - 650, 5, 100, 28)
|
||||
|
||||
BGL.glColor3f(1, 1, 1)
|
||||
BGL.glRasterPos2f(5, 55)
|
||||
Draw.Text("FlightGear YASim Import: '%s'" % Global.path)
|
||||
|
||||
BGL.glRasterPos2f(120, 15)
|
||||
Draw.Text(Global.path)
|
||||
Draw.PushButton("Reload", RELOAD_BUTTON, 5, 5, 80, 32, "reload YASim config file")
|
||||
Global.mirror = Draw.Toggle("Mirror", MIRROR_BUTTON, 100, 5, 50, 16, Global.mirror.val, \
|
||||
"show symmetric surfaces on both sides (reloads config)")
|
||||
Draw.PushButton("Update Cursor", CURSOR_BUTTON, width - 650, 5, 100, 32, "update cursor display")
|
||||
|
||||
BGL.glRasterPos2f(width - 530 + Blender.Draw.GetStringWidth("Distance from last") - Blender.Draw.GetStringWidth("Current"), 24)
|
||||
BGL.glRasterPos2f(width - 530 + Blender.Draw.GetStringWidth("Vector from last") - Blender.Draw.GetStringWidth("Current"), 24)
|
||||
Draw.Text("Current cursor pos: x = %+.3f y = %+.3f z = %+.3f" % tuple(Global.cursor))
|
||||
|
||||
c = Global.cursor - Global.last_cursor
|
||||
BGL.glRasterPos2f(width - 530, 7)
|
||||
Draw.Text("Distance from last cursor pos: x = %+.3f y = %+.3f z = %+.3f length = %.3f" % (c[0], c[1], c[2], c.length))
|
||||
Draw.Text("Vector from last cursor pos: x = %+.3f y = %+.3f z = %+.3f length = %.3f" % (c[0], c[1], c[2], c.length))
|
||||
|
||||
|
||||
def event(ev, value):
|
||||
|
||||
def gui_event(ev, value):
|
||||
if ev == Blender.Draw.ESCKEY:
|
||||
Blender.Draw.Exit()
|
||||
|
||||
|
||||
def button(n):
|
||||
if n == 0:
|
||||
run_parser(Global.path)
|
||||
elif n == 1:
|
||||
|
||||
def gui_button(n):
|
||||
if n == NO_EVENT:
|
||||
return
|
||||
|
||||
elif n == RELOAD_BUTTON:
|
||||
load_yasim_config(Global.path)
|
||||
|
||||
elif n == CURSOR_BUTTON:
|
||||
Global.last_cursor = Global.cursor
|
||||
Global.cursor = Vector(Blender.Window.GetCursorPos()) * Global.matrix.invert()
|
||||
d = Global.cursor - Global.last_cursor
|
||||
print(("cursor: x=\"%f\" y=\"%f\" z=\"%f\" dx=%f dy=%f dz=%f length=%f" \
|
||||
% (Global.cursor[0], Global.cursor[1], Global.cursor[2], d[0], d[1], d[2], d.length)))
|
||||
|
||||
elif n == MIRROR_BUTTON:
|
||||
load_yasim_config(Global.path)
|
||||
|
||||
Blender.Draw.Redraw(1)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
log(6 * "\n")
|
||||
registry = Blender.Registry.GetKey("FGYASimImportExport", False)
|
||||
if registry and "path" in registry and Blender.sys.exists(Blender.sys.expandpath(registry["path"])):
|
||||
path = registry["path"]
|
||||
else:
|
||||
path = ""
|
||||
|
||||
|
||||
log(6 * "\n")
|
||||
if Blender.Window.GetScreenInfo(Blender.Window.Types.SCRIPT):
|
||||
Blender.Draw.Register(draw, event, button)
|
||||
Blender.Draw.Register(gui_draw, gui_event, gui_button)
|
||||
|
||||
Blender.Window.FileSelector(load_yasim_config, "Import YASim Configuration File", path)
|
||||
|
||||
Blender.Window.FileSelector(run_parser, "Import YASim Configuration File", path)
|
||||
|
||||
|
||||
main()
|
||||
|
|
Loading…
Add table
Reference in a new issue