Files
create/src/Mod/Draft/importAirfoilDAT.py

225 lines
7.7 KiB
Python

# -*- coding: utf-8 -*-
#***************************************************************************
#* *
#* Copyright (c) 2010 Heiko Jakob <heiko.jakob@gediegos.de> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
__title__="FreeCAD Draft Workbench - Airfoil data importer"
__author__ = "Heiko Jakob <heiko.jakob@gediegos.de>"
## @package importAirfoilDAT
# \ingroup DRAFT
# \brief Airfoil (.dat) file importer
#
# This module provides support for importing airfoil .dat files
import re, FreeCAD, Part, cProfile, os
from FreeCAD import Vector, Base
from FreeCAD import Console as FCC
from Draft import makeWire
if FreeCAD.GuiUp:
from DraftTools import translate
else:
def translate(context, txt):
return txt
if open.__module__ in ['__builtin__', 'io']:
pythonopen = open
useDraftWire = True
def decodeName(name):
"""Decode encoded name.
Parameters
----------
name : str
The string to decode.
Returns
-------
tuple
(string)
A tuple containing the decoded `name` in 'latin1',
otherwise in 'utf8'.
If it fails it returns the original `name`.
"""
try:
decodedName = name
except UnicodeDecodeError:
try:
decodedName = (name.decode("latin1"))
except UnicodeDecodeError:
try:
decodedName = (name.decode("utf8"))
except UnicodeDecodeError:
_msg = ("AirfoilDAT error: "
"couldn't determine character encoding.")
FCC.PrintError(translate("ImportAirfoilDAT", _msg) + "\n")
decodedName = name
return decodedName
def open(filename):
"""Open filename and parse.
Parameters
----------
filename : str
The path to the filename to be opened.
Returns
-------
App::Document
The new FreeCAD document object created, with the parsed information.
"""
docname = os.path.splitext(os.path.basename(filename))[0]
doc = FreeCAD.newDocument(docname)
doc.Label = decodeName(docname[:-4])
process(doc, filename)
def insert(filename, docname):
"""Get an active document and parse.
If no document exists, it is created.
Parameters
----------
filename : str
The path to the filename to be opened.
docname : str
The name of the active App::Document if one exists, or
of the new one created.
Returns
-------
App::Document
The active FreeCAD document, or the document created if none exists,
with the parsed information.
"""
groupname = os.path.splitext(os.path.basename(filename))[0]
try:
doc = FreeCAD.getDocument(docname)
except NameError:
doc = FreeCAD.newDocument(docname)
importgroup = doc.addObject("App::DocumentObjectGroup", groupname)
importgroup.Label = decodeName(groupname)
process(doc, filename)
def process(doc, filename):
"""Process the filename and provide the document with the information.
The common airfoil dat format has many flavors.
This code should work with almost every dialect.
Parameters
----------
filename : str
The path to the filename to be opened.
docname : str
The name of the active App::Document if one exists, or
of the new one created.
Returns
-------
App::Document
The active FreeCAD document, or the document created if none exists,
with the parsed information.
"""
# Regex to identify data rows and throw away unused metadata
regex = re.compile(r'^\s*(?P<xval>(\-|\d*)\.\d+(E\-?\d+)?)\,?\s*(?P<yval>\-?\s*\d*\.\d+(E\-?\d+)?)\s*$')
afile = pythonopen(filename, 'r')
# read the airfoil name which is always at the first line
airfoilname = afile.readline().strip()
coords = []
upside = True
last_x = None
# Collect the data for the upper and the lower side separately if possible
for lin in afile:
curdat = regex.match(lin)
if curdat is not None:
x = float(curdat.group("xval"))
y = float(curdat.group("yval"))
# the normal processing
coords.append(Vector(x, y, 0))
# End of if curdat != None
# End of for lin in file
afile.close()
if len(coords) < 3:
print('Did not find enough coordinates\n')
return
# sometimes coords are divided in upper an lower side
# so that x-coordinate begin new from leading or trailing edge
# check for start coordinates in the middle of list
if coords[0:-1].count(coords[0]) > 1:
flippoint = coords.index(coords[0], 1)
upper = coords[0:flippoint]
lower = coords[flippoint+1:]
lower.reverse()
for i in lower:
upper.append(i)
coords = upper
# do we use the parametric Draft Wire?
if useDraftWire:
obj = makeWire(coords, True)
#obj.label = airfoilname
else:
# alternate solution, uses common Part Faces
lines = []
first_v = None
last_v = None
for v in coords:
if first_v == None:
first_v = v
# End of if first_v == None
# Line between v and last_v if they're not equal
if (last_v is not None) and (last_v != v):
lines.append(Part.makeLine(last_v, v))
# End of if (last_v != None) and (last_v != v)
# The new last_v
last_v = v
# End of for v in upper
# close the wire if needed
if last_v != first_v:
lines.append(Part.makeLine(last_v, first_v))
# End of if last_v != first_v
wire = Part.Wire(lines)
face = Part.Face(wire)
obj = FreeCAD.ActiveDocument.addObject('Part::Feature',airfoilname)
obj.Shape = face
doc.recompute()