xflr5-6.09-06/000755 001750 000144 00000000000 12251146522 014266 5ustar00techwinderusers000000 000000 xflr5-6.09-06/doxygen/000755 001750 000144 00000000000 12246405674 015755 5ustar00techwinderusers000000 000000 xflr5-6.09-06/doxygen/Doxyfile000644 001750 000144 00000233523 12246405674 017473 0ustar00techwinderusers000000 000000 # Doxyfile 1.8.2 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = xflr5 # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 6.09.06 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "A tool for the design of Airfoils, Wings and Planes" # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = /home/techwinder/aero/all_XFLR5/xflr5-6.09-06/images/xflr5_128.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = /home/techwinder/aero/all_XFLR5/xflr5-6.09-06/doxygen # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. Note that you specify absolute paths here, but also # relative paths, which will be relative from the directory where doxygen is # started. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding # "class=itcl::class" will allow you to use the command class in the # itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, # and language is one of the parsers supported by doxygen: IDL, Java, # Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, # C++. For instance to make doxygen treat .inc files as Fortran files (default # is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note # that for custom extensions you also need to set FILE_PATTERNS otherwise the # files are not read by doxygen. EXTENSION_MAPPING = # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all # comments according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you # can mix doxygen, HTML, and XML commands with Markdown formatting. # Disable only in case of backward compatibilities issues. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented classes, # or namespaces to their corresponding documentation. Such a link can be # prevented in individual cases by by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES (the # default) will make doxygen replace the get and set methods by a property in # the documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields will be shown inline in the documentation # of the scope in which they are defined (i.e. file, namespace, or group # documentation), provided this scope is documented. If set to NO (the default), # structs, classes, and unions are shown on a separate page (for HTML and Man # pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 0 # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given # their name and scope. Since this can be an expensive process and often the # same symbol appear multiple times in the code, doxygen keeps a cache of # pre-resolved symbols. If the cache is too small doxygen will become slower. # If the cache is too large, memory is wasted. The cache size is given by this # formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = YES # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = /home/techwinder/aero/all_XFLR5/xflr5-6.09-06/src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.markdown \ *.md \ *.mm \ *.dox \ *.py \ *.f90 \ *.f \ *.for \ *.vhd \ *.vhdl # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If left blank doxygen will # generate a default style sheet. Note that it is recommended to use # HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this # tag will in the future become obsolete. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional # user-defined cascading style sheet that is included after the standard # style sheets created by doxygen. Using this option one can overrule # certain style aspects. This is preferred over using HTML_STYLESHEET # since it does not replace the standard style sheet and is therefor more # robust against future updates. Doxygen will copy the style sheet file to # the output directory. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 99 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of # entries shown in the various tree structured indices initially; the user # can expand and collapse entries dynamically later on. Doxygen will expand # the tree to such a level that at most the specified number of entries are # visible (unless a fully collapsed tree already exceeds this amount). # So setting the number of entries 1 will produce a full collapsed tree by # default. 0 is a special value representing an infinite number of entries # and will result in a full expanded tree by default. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely # identify the documentation publisher. This should be a reverse domain-name # style string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) # at top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. Since the tabs have the same information as the # navigation tree you can set this option to NO if you already set # GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. # Since the tree basically has the same information as the tab index you # could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you may also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to # the MathJax Content Delivery Network so you can quickly see the result without # installing MathJax. However, it is strongly recommended to install a local # copy of MathJax from http://www.mathjax.org before deployment. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. For each # tag file the location of the external documentation should be added. The # format of a tag file without this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths # or URLs. Note that each tag file must have a unique name (where the name does # NOT include the path). If a tag file is not located in the directory in which # doxygen is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If the UML_LOOK tag is enabled, the fields and methods are shown inside # the class node. If there are many fields or methods and many nodes the # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS # threshold limits the number of items for each type to make the size more # managable. Set this to 0 for no limit. Note that the threshold may be # exceeded by 50% before the limit is enforced. UML_LIMIT_NUM_FIELDS = 10 # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES xflr5-6.09-06/translations/000755 001750 000144 00000000000 12251145347 017013 5ustar00techwinderusers000000 000000 xflr5-6.09-06/translations/xflr5v6.ts000755 001750 000144 00001535614 12247544275 020731 0ustar00techwinderusers000000 000000 AFoilGridDlg Grid Options Neutral Line X-Scale X Major Grid Y Major Grid X Minor Grid Y Minor Grid Accept Cancel Apply AFoilTableDlg Foil Table Columns Foil Name Thickness Thickness max. position Camber Camber max. position Number of points Trailing edge flap angle Trailing edge hinge x-position Trailing edge hinge y-position Leading edge flap angle Leading edge hinge x-position Leading edge hinge y-position OK Cancel AboutQ5 Copyright (C) M. Drela and H. Youngren 2000 - XFoil v6.94 Copyright (C) Matthieu Scherrer 2004 - Miarex v1.00 About XFLR5 Copyright (C) Andre Deperrois 2003-2013 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. This program has been developed exclusively for the analysis of model aircraft Any other usage is strongly disapproved Program distributed under the terms of the GNU General Public License German translation by Martin Willner Japanese translation by IKUSU, Koichi Akabe, Misatus, dynamicsoar, hide253 icchy_07, ina111, ohayo_cycling, ohisa_64, ozawa64. French translation by Jean-Luc Coulon OK BatchDlg Iter Current foil only Foil list Foil Selection Type 1 Type 2 Type 3 Type 4 Analysis Type Batch foil analysis Range Re List Edit List Min Max Increment Batch Variables Specify Alpha Cl From Zero Spec = Analysis Range NCrit= Forced transitions Initialize BLs between polars Store OpPoints Close Analyze Skip Opp Skip Polar Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid ...skipped after %1 iterations ...unconverged after %1 iterations Analysis interrupted CpCalc: local speed too large Compressibility corrections invalid Reynolds = Mach = ...converged after %1 iterations ...skipped after %1 iterations ...unconverged after %1 iterations Top transition location (x/c) Bottom transition location (x/c) Alpha = Cl = Re.sqrt(Cl) = Ma.sqrt(Cl) = Re.Cl = Cancel Cl = %1 Analyzing Analysis completed BatchThreadDlg Multi-threaded batch analysis Foil Selection Current foil only Foil list Batch Variables Range Re List Edit List Min Max Increment NCrit= Analysis Range Specify: Alpha Cl From Zero Spec = Forced Transitions Top transition location (x/c) Bottom transition location (x/c) Initialize BLs between polars Update polar view Update the polar graphs after the completion of each foil/polar pair Close Analyze CL Cancel BodyGridDlg Body Grid Dialog Grid Parameters Show Scales Main Grid Minor Grid Body Grid Frame Grid OK Cancel BodyScaleDlg Body Scale Dialog Whole Body Frame Only Scale Factor X Scale Y Scale Z Scale OK Cancel BodyTransDlg Body Translation Frame Only X Translation Y Translation Z Translation OK Cancel CAddDlg Local Panel Refinement Angle Criterion Type of Spline Refinement X Limits From To Uniform Arc Length Total Added MaxAngle At Panel Accept Cancel Apply Warning Unrecognized foil format Total number of points is %1 (added %1 points to original foil) Maximum panel angle is %1 at panel position %1 Maximum panel angle is %1 deg DisplaySettingsDlg General Display Settings All Graph Settings Graph Settings Background Color Text Color Font Reverse zoom direction using mouse wheel Enable 3D transparency OK Cancel EditPlrDlg Polar Points Edition Delete All Points Delete Point OK Cancel FlapDlg Flap Dlg L.E. Flap T.E. Flap Flap Angle + is down Hinge X Position % Chord Hinge Y Position % Thickness OK Cancel Apply Warning The trailing edge hinge must be downstream of the leading edge hinge FoilCoordDlg Apply Foil Coordinates Insert Point Delete Point Restore OK Cancel FoilGeomDlg Foil Geometry Value %Chord 0% 10% Max x-pos 100% Camber Thickness OK Cancel Restore Warning Panel number cannot exceed 300 FoilPolarDlg Foil Polar Definition Automatic User Defined Analysis Name Type 1 Type 2 Type 3 Type 4 Analysis Type Plane Data Chord Mass Span Aerodynamic Data Unit International Imperial Re = Mach = Reynolds and Mach Numbers OK Cancel Free transitions (e^n) method Forced transition: NCrit= TripLocation (top) TripLocation (bot) Transition settings Analysis parameters for Reynolds = Re.sqrt(Cl) = Ma.sqrt(Cl) = Re.Cl = Alpha = FoilSelectionDlg Foil Selection OK Cancel GL3DScales 3D Scales Settings Auto Scales Min Max Cp Scale Lift Drag Velocity Vector Scales L.E. T.E. Y-Line X-axis points 1st segment X factor X-Offset Z-Offset Streamline length Start Streamline at Streamlines Apply GL3dBodyDlg Body Edition Scale Grid Setup Reset Scales Show Current Frame Only Undo Redo Export Body Geometry to File Export Body Definition to File Import Body Definition from File Translate Frame %1 Scale = %1 NPanels Body Dlg Exit Insert Point Remove Point Cancels the last modification Restores the last cancelled modification Define Inertia Save the Body ? Axes Light Surfaces Outline Panels Masses Pick Center Clip Plane Other Actions... Save and Close Cancel Flat Panels BSplines x Hoop Degree BodyName Enter here a short description for the body Description: X View Y View Z View Iso View Panel bunch Frames Frame Positions Points Current Frame Definition Context Menu GL3dWingDlg Warning Warning : Panel sequence is inconsistent The first section cannot be deleted Symetric Right Side Left Side Insert Before Wing Edition Reset Scales Insert after Delete section Reset section Import Wing from File... Export Wing to File... Section Please enter a name for the wing Too many spanwise panels. The maximum number is Only 10 flaps x 2 will be handled Question Uniform Cosine Sine -Sine y ( chord ( offset ( The maximum number of panels has been reached No insertion possible before the first section Wing Description Save the changes ? Undefined WingName Wing Span Area Projected Span Projected Area X View Y View Z View Iso View Insert after section Insert before section Number of VLM Panels Number of 3D Panels Mean Geom. Chord Mean Aero Chord MAC Span Pos Aspect ratio Taper Ratio Root to Tip Sweep Number of Flaps Enter here a short description for the wing Description: Axes Light Surfaces Outline Panels Foil Names Masses Pick Center Activate the button, then click on the object to center it in the viewport; alternatively, double click on the object Reset Clip Plane Reset Mesh Scale Wing Inertia... Import Wing Export Wing Save and Close Cancel GLLightDlg OpenGL Light Options Diffuse Ambient Specular Light Intensity Red Green Blue Light Color x y z Light Position Emissions Shininess Material Color Material Cull Faces Smooth Quads Depth Test Smooth Shading Local View Options Close Reset Defaults Light GraphDlg Graph Settings X - Chord Q - Speed X - chord Cp Alpha Cl Cd Cd x 10000 Cdp Cm Xtr1 Xtr2 HMom Cpmin Cl/Cd |Cl|^(3/2)/Cd 1/Cl^1/2 Re XCp Y - span Induced Angle Total Angle Local lift coef. Local Lift C.Cl/M.A.C. Airfoil viscous drag coef. Induced drag coef. Total drag coef. Local Drag C.Cd/M.A.C. Airfoil Pitching moment coef. Total Pitching moment coef. Geom. Pitching moment coef. Reynolds Top Transition x-pos% Bottom Transition x-pos% Centre of Pressure x-pos% Bending moment Lift coef. Viscous drag coef. Total pitching moment coef. Viscous pitching moment coef. Induced pitching moment coef. Total rolling moment coef. Total yawing moment coef. Viscous yawing moment coef. Induced yawing moment coef. Glide ratio Cl/Cd Power factor Cl^(3/2)/Cd 1/Rt(Cl) FX (Drag) FY (Side force) FZ (Lift) Vx Vz VInf Descent angle atan(Cd/Cl) Pitching Moment Rolling Moment Yawing Moment Centre of pressure X-Pos Centre of pressure Y-Pos Centre of pressure Z-Pos m.g.Vz Efficiency (XCp-Xcg)/MAC Control Variable Cy - Lateral force coef. Neutral Point x-position Phugoid Frequency Phugoid Damping Short Period Frequency Short Period Damping Dutch Roll Frequency Dutch Roll Damping Roll Damping Spiral Damping Restore OK Cancel Apply YAxis vs. XAxis Title Label Font Color Set Title Font Set Label Font Title Color Label Color Fonts Graph Background Graph Border BackGround X Axis Y Axis Min Max Origin Unit Auto Scale Inverted Axis Axis Style X Major Grid Y Major Grid X Minor Grid Y Minor Grid Auto Unit Variables Scales Axis and Grids Fonts and BackGround ImportObjectDlg Import Object Select the wing to import Select the body to import OK Cancel InertiaDlg Inertia Properties Mass x y z Description Wing Mass: Body Mass: Volume Mass: %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! This is a calculation form for a rough order of magnitude for the inertia tensor. Export Mass Properties Insert Before Delete Point Mass Inertia properties for AVL Mass File (*.mass) %1 %2 %3 %4 %5 %6 %7 %8 %9 %10! Inertia of both left and right wings %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Body inertia %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Body's inertia Refer to the Guidelines for explanations. Object Mass - Volume only, excluding point masses Wing Mass= Component inertias Main Wing Second Wing Elevator Fin Body Additional Point Masses Total Mass = Volume + point masses Total Mass= OK Cancel Center of gravity Inertia in CoG Frame Export to AVL InterpolateFoilsDlg Interpolate Foils Camb1 Camb2 Camb3 Thick1 Thick2 Thick3 OK Cancel Camb.=%1 at x=%1 Thick.=%1 InverseOptionsDlg XInverse Style Reference Foil Modified Foil Spline Reflected Curve OK Cancel LECircleDlg L.E. Circle r= % Chord Show OK Cancel LEDlg Leading Edge Approximate new/old ratio for L.E. radius ratio Blending Distance from L.E. % chord OK Cancel Apply Warning Unrecognized foil format Panel number cannot exceed 300 LLTAnalysisDlg LLT Analysis Iterations Launching analysis.... Max iterations = %1 Alpha precision = %1 deg Relaxation factor = %1 Number of stations = %1 Analysis cancelled on user request.... Calculating Alpha = %1... ...negative Lift... Aborting ...converged after %1 iterations ...unconverged after %2 iterations Alpha = %1, skipped after %2 iterations QInf = %1 skipped after %2 iterations Skip Cancel Analysis completed ...some points are outside the flight envelope ...some points are unconverged Close Initializing analysis... Calculating QInf = %1... ...unconverged after %1 iterations LinePickerDlg Line Picker Style Width Color OK Cancel MainFrame Save the project before exit ? New Project Save and close the current project, create a new project Close the Project Save and close the current project &Open... Open an existing file &Insert Project... Insert an existing project in the current project &Direct Foil Design Open Foil Design application &XFoil Inverse Design Open XFoil inverse analysis application &XFoil Mixed Inverse Design Open XFoil Mixed Inverse analysis application &XFoil Direct Analysis Open XFoil direct analysis application &Wing and Plane Design Open Wing/plane design and analysis application Save Save the project to disk Save the current project under a new name Define the units for this project Define the default language for the application Restore toolbars Restores the toolbars to their original state Save View to Image File Saves the current view to a file on disk General Display Settings Export Graph Export the current graph data to a text file Restores the graph's x and y scales E&xit Exit the application &Guidelines Show the guidelines for some help &About More information about XFLR5 About Qt Properties Show the properties of the currently selected polar Grid Options Define the grid settings for the view Store Splines as Foil Store the current splines in the foil database Splines Params Define parameters for the splines : degree, number of out points Export Splines To File New Splines Reset the splines Zoom in Zoom the view by drawing a rectangle in the client area Reset X Scale Resets the scale to fit the current screen width Undo Redo Show All Foils Hide All Foils Delete... Rename... Export... Show Current Foil Hide Current Foil Reset Y Scale Reset Scales Resets the x and y scales to screen size Zoom Less Zoom Y Scale Only Zoom Y scale Only De-rotate the Foil Normalize the Foil Refine Locally Refine Globally Cancels the last modification Restores the last cancelled modification Edit Foil Coordinates Scale camber and thickness Set T.E. Gap Set L.E. Radius Show LE Circle Show Legend Set Flap Interpolate Foils Naca Foils Set Table Columns Reset column widths Load background image Clear background image &View F&oil &Splines Context Menu Options Switch to the Operating point view Switch to the Polar view Switch to stability analysis post-processing Switch to the 3D view Switch to the Cp view Define the style and color preferences for the 3D view Define which type of polars should be shown or hidden Define the scales for the 3D display of lift, moment, drag, and downwash Define the light options in 3D view Half Wing Rename the currently selected object Edit Body... Edit the body of the currently selected plane Export the current plane or wing to a text file in the format required by AVL Export the current operating point to a text or csv file Reset the legend position to its default value Reset the wing scale to its default value Scale the dimensions of the currently selected wing Manage objects Rename or delete the planes and wings stored in the database Import a polar from a text file Define the inertia for the current plane or wing Hide all the curves except for the one corresponding to the currently selected operating point Show the graph curves of all operating points Hide the graph curves of all operating points Delete all the operating points of all planes and polars Show the curves of all the operating points of the currently selected polar Hide the curves of all the operating points of the currently selected polar Delete all the operating points of the currently selected polar Show the theoretical optimal elliptic lift curve on all graphs for which the selected variable is the local lift Show XCG location Show the position of the center of gravity defined in the analysis Show the graph curves for the elevator Show the graph curves for the fin Show the graph curves for the second wing Define an analysis for the current wing or plane Modify the analysis parameters of this polar Define a Stability Analysis Define a stability analysis for the current wing or plane Define Graph Settings Define the settings for the selected graph Display only the first graph Display only the second graph Display only the third graph Display only the fourth graph Reset the scale of the current operating point graph Reset the scales of all four operating point graphs Reset the scales of all four polar graphs Define the settings of all four operating point graphs Define the settings of all four polar graphs Hide all the polar curves associated to the currently selected wing or plane Show all the polar curves associated to the currently selected wing or plane Delete all the polars associated to the currently selected wing or plane Hide all the polar curves of all wings and planes Show all the polar curves of all wings and planes Hide all the operating point curves of the currently selected wing or plane Show all the operating point curves of the currently selected wing or plane Delete all the operating points of the currently selected wing or plane Delete the currently selected wing or plane Duplicate the currently selected wing or plane Save the currently selected wing or plane as a new separate project Rename the currently selected polar Export the currently selected polar to a text or csv file Delete all the points of the currently selected polar, but keep the analysis settings Delete the currently selected polar Delete the currently selected operating point Define the settings for LLT, VLM and Panel analysis &Analysis Define an Analysis Batch Analysis Current Foil XFLR5 v6 Project File (*.wpa);;XFLR5 v5 Project File (*.*) Foil 3D Scales &File &? OpPoint view Show Operating point view Polar view Show Polar view 3D Color Preferences Polar Filter 3D Light Options Define a New Wing Shows a dialogbox for editing a new wing definition Define a New Plane Shows a dialogbox to create a new plane definition Edit... Shows a dialogbox to edit the currently selected wing or plane Show Elevator Curve View Log File Exit will revert to default settings at the next session Show the properties of the currently selected operating point Foil Actions Stability OpPoint View Polar View Time Response Vew Root Locus View Switch to root locus view 3D View Cp View Export to AVL... Reset Legend Position Reset Wing Scale Scale Wing Import Polar Define Inertia Show Current OpPoint Only Show All OpPoints Hide All OpPoints Delete All OpPoints Show Associated OpPoints Hide Associated OpPoints Delete Associated OpPoints Show Elliptic Curve Show Fin Curve Show Second Wing Curve Display the first two graphs Display all four graphs Highlight Current OpPoint Highlights on the polar curve the currently selected operating point Reset All Graph Scales All Graph Settings Hide Associated Polars Show Only Associated Polars Show Associated Polars Delete Associated Polars Hide All Polars Show All Polars Duplicate... Save as Project... Export ... Reset ... Delete ... Advanced Settings... &Wing-Plane Current UFO &Polars Current Polar Graphs &OpPoint Current OpPoint Current Graph UFO Ready All Polar Graph Settings Reset All Polar Graph Scales Set Style... Delete associated polars Delete all the polars associated to this foil Show only associated polars Show associated polars Hide associated polars Save associated polars Hide associated OpPoints Show associated OpPoints Delete associated OpPoints Export associated OpPoints Defines a single analysis/polar Launches a batch of analysis calculation for a specified range or list of Reynolds numbers Multi-threaded Batch Analysis Launches a batch of analysis calculation using all available computer CPU cores Delete Deletes the currently selected polar Reset Deletes the contents of the currently selected polar Edit Remove the unconverged or erroneaous points of the currently selected polar Export Export all polars Define Styles Define the style for the boundary layer and the pressure arrows Manage Foils Rename Show Panels Show the foil's panels Reset Foil Scale Resets the foil's scale to original size Show Inviscid Curve Display the Opp's inviscid curve Neutral Line Show Current Opp Only Show All Opps Hide All Opps Reset XFoil XFoil Advanced Settings Tip : you don't want to use that option... Duplicate Cp Variable Sets Cp vs. chord graph Q Variable Sets Speed vs. chord graph Export Cur. XFoil Results Max. Shear Coefficient Bottom Side D* and Theta Top Side D* and Theta Log(Re_Theta) Re_Theta Amplification Ratio Dissipation Coefficient Skin Friction Coefficient Edge Velocity Kinematic Shape Parameter Import XFoil Polar &Foil &Design Polar Graphs Operating Points Cp Graph Current XFoil Results Store Foil Store Foil in database Extract Foil Extract a Foil from the database for modification Define the styles for this view Resets the scale to fit the screen size Insert Control Point Remove Control Point Show Q-Initial Show Q-Spec Show Q-Viscous Show Points Show Reflected Zoom X Scale Zoom X Scale Only Zoom Y Scale &Graph Full Inverse Mixed Inverse XInverse Are you sure you want to delete and all associated OpPoints and Polars ? Question Could not read the file Info Save the current project ? Text File (*.txt);;Comma Separated Values (*.csv) Open File Project file (*.wpa) Warning XFLR5 file (*.dat *.plr *.wpa) The project has been saved Enter the foil's new name Default Settings Your system does not provide support for OpenGL. XFLR5 will not operate correctly. Save Project As... Save Options Define the save options for operating points Units... Language... Reset Default Settings Define the color and font options for all views and graphs Reset Graph Scales Two Graphs All Graphs Graph 1 Graph 2 Graph 3 Graph 4 Define Cp Graph Settings Two Polar Graphs All Polar Graphs Cl vs. Cd Cl vs.Alpha Cl vs. Xtr. Cm vs.Alpha Glide ratio vs. alpha Analysis Reset foil scale Error reading the file Saved the valid part Are you sure you want to reset the default settings ? The settings will be reset at the next session Nothing to save Save the Project File XFLR5 Project File (*.wpa) Could not open the file for writing Save Image Unidentified Operating Point Obsolete format, cannot read A foil of that name already exists Please enter a new name &%1 %2 Foil Error : no points ManageFoilsDlg Foil Management Delete Rename Export Foil Close Name Thickness (%) at (%) Camber (%) Points TE Flap ( TE XHinge TE YHinge LE Flap ( LE XHinge LE YHinge Foils Foil File (*.dat) ManageUFOsDlg Object Management Delete Rename Close Description: Name Span Area M.A.C. AR TR Rt-Tip Sweep Tail Volume UFOs Are you sure you want to delete the plane : Are you sure you want to delete the wing : Question ModDlg Modification OK Cancel Save as new NacaFoilDlg NACA Foils 4 or 5 digits Number of Panels OK Cancel Illegal NACA Number NewNameDlg OK Cancel ObjectPropsDlg OK Polar Properties Operating Point Properties PanelAnalysisDlg 3D Panel Analysis Warning Solving the problem... Adding the wake's contribution... Computing On-Body Speeds... Creating source strengths... Calculating aerodynamic coefficients in the far field plane Calculating point Computing Plane for alpha=%1 Computing Plane for QInf=%1 Calculating aerodynamic coefficients... Calculating wing... Calculating body... Type 1 - Fixed speed polar Type 2 - Fixed lift polar Type 4 - Fixed angle of attack polar Type 7 - Stability polar Performing asymmetric calculation : Counted %1 panel elements Singular Matrix.... Aborting calculation... Cancel Found a negative lift for Alpha=%1.... skipping the angle... Performing symmetric calculation Launching 3D Panel Analysis.... Launching VLM1 Analysis.... Launching VLM2 Analysis.... Using Dirichlet boundary conditions Using Neumann boundary conditions Warning: The wing and elevator lie in the same plane z= It is recommended to slightly offset the wing or the elevator to avoid numerical instabilities Panel Analysis completed successfully Panel Analysis completed ... Errors encountered Close Processing Alpha= %1 Wake iteration %1 PertDlg Pertubation Dialog Restore Apply OK Cancel Cn List PlaneDlg Plane Editor Warning Total number of wing panels =%1 Max Number =%2 A reduction of the number of wing panels is required Save the changes ? Question Plane Name Enter here a short description for the plane Description: Plane Inertia Plane Description Define Import Export x= z= Tilt Angle= Main Wing Biplane Wing 2 Elevator Fin Double Fin Two-sided Fin y= Body Warning: Including the body in the analysis is not recommended. Check the guidelines for explanations. Wing Area = Wing Span = Elev. Area = Elev. Lever Arm = Fin Area = TailVolume = Total Panels = OK Cancel PolarFilterDlg Polar Filter Show polar types Type 1 Type 2 Type 3 Type 4 Type 5 Type 6 Type 7 OK Cancel ProgressDlg Progress Cancel QAFoil Spline foil Foil has been de-rotated by %1 degrees Foil has been normalized from %1 to 1.000 Warning At least two foils are required Export Foil Foil File (*.dat) Spline Foil Too many output points on upper surface Max =%1 Too many output points on lower surface Max =%1 Export Splines Text File (*.dat) X-Scale = %1 Y-Scale = %1 x = %1 y = %1 Open Image File Question Discard changes to Splines ? Name Thickness (%) at (%) Camber (%) Points TE Flap ( TE XHinge TE YHinge LE Flap ( LE XHinge LE YHinge Show Centerline Style Foils The minimum number of control points has been reached for this spline degree QMiarex Cl x Cp Warning Not enough memory to store the OpPoint The modification will erase all results associated to this Plane. Continue ? Induced Angle Total Angle Local lift Airfoil drag Induced drag Total drag Local drag Cm Airfoil Time = Are you sure you want to delete the polars associated to : Cl = Cm = ICn = %1 PCn = %2 ICn=, %1,PCn=, %2 Polar properties Real Imag/2.pi Cm total Re Top Trans x-Pos % Bot Trans x-Pos % CP x-Pos % BM ( Point is out of the flight envelope Alpha = %1 Efficiency = %1 Cl/Cd = %1 GCm = %1 Please define a wing or a plane object before running a calculation Please define an analysis/polar before running a calculation Could not find the wing's foil ... Aborting Calculation Are you sure you want to delete the plane : Are you sure you want to delete the wing : Question Are you sure you want to delete the polar : The modification will erase all results associated to this Wing. Continue ? Export Wing OpPoint Text File (*.txt);;Comma Separated Values (*.csv) Cd = %1 ICd = %2 PCd = %3 Cd=,%1,ICd=, %2,PCd=, %3 Bend. = Flap Export Polar Open File UFO Polar Format (*.*) Could not read the file No UFO with the name could be found. The polar(s) will not be stored Enter the new name for the wing polar : Are you sure you want to reset the content of the polar : abcdefghijklmnopqrstuvwxyz012345678 abcdefghijklmnopqrstuvwxyz01234567 Cp Graph Current Plane Current Wing Current Object Control polars are not supported in XFLR5 v6. Please use stability polars instead. Main Wing Cp Coefficients Wing Cp Coefficients Panel CtrlPt.x CtrlPt.y CtrlPt.z Cp Panel,CtrlPt.x,CtrlPt.y,CtrlPt.z,Cp Cp Coefficients Strip %1 Export UFO AVL Text File (*.avl) Project The modification will erase all polar results associated to this Plane. Continue ? Wing Span = xyProj. Span = Wing Area = xyProj. Area = Plane Mass = Wing Load = Tail Volume = Root Chord = MAC = TipTwist = Aspect Ratio = Taper Ratio = Root-Tip Sweep = V = %1 No unit defined for speed... Lift Coef. = %1 Drag Coef. = %1 Rolling Moment Coef. = %1 Induced Moment Coef = %1 Profile Yawing Moment = %1 Flap %1 Moment =%2 Top transition Bottom transition Centre of Pressure Moment ref. location Enter the new name for the Plane : Enter the new name for the wing : Enter the new name for the Polar: Sequence Start= End= D= Init LLT Store OpPoint Analyze Analysis settings Lift Ind. Drag Visc. Drag Trans. Moment Downw. Surf. Vel. Stream Animate Display Curve Panel Forces Display the force 1/2.rho.V2.S.Cp acting on the panel Results Points item Style Width Color Curve settings Span Position Keep Reset Cp Sections Axes Light Surfaces Outline Panels Foil Names Vortices Masses X View Y View Z View Iso View Pick Center Activate the button, then click on the object to center it in the viewport; alternatively, double click on the object Clip: OpenGL color format is not recognized... Sorry Cannot (yet ?) save 8 bit depth opengl screen images... Sorry Cannot (yet ?) save 16 bit depth opengl screen images... Sorry Unidentified bit depth... Sorry QObject dihedral twist foil X-panels X-dist Y-panels Y-dist Wing definition X Y Re Mach CL CD Cm Cdp Cpmn XCP Top Transition Bot Transition T.E. Flap moment L.E. Flap moment Type Fixed speed Fixed lift Fixed angle of attack Reynolds number Mach number Re.Cl Cd Cd x 10000 Xtr1 Xtr2 HMom Cpmin Cl/Cd |Cl|^(3/2)/Cd 1/Rt(Cl) XCp Alpha NCrit Forced top trans. Forced bottom trans. Number of data points Re List i Cn Ci Wing 2nd Wing Elevator Fin Plane Name Spline Foil CpCalc: local speed too larger Compressibility corrections invalid Calculating unit vorticity distributions ... Warning: High does not work well on rotated foils Current chordline angle: %1 proceeding anyway... The max number of polar points has been reached Body Name Export Body Definition Text Format (*.txt) Export Body Geometry Text File (*.txt);;Comma Separated Values (*.csv) Choose the length unit to read this file : Open File All files (*.*) Could not read the file Warning Multiple file loading only available for airfoil files. Non *.dat files will be ignored. Error reading Frames have different number of side points Please select a Frame before inserting a point Stability analysis VInf = Alpha = LLT 3D-Panels 3D-Panels/VLM1 3D-Panels/VLM2 VInf Mass Control value XNP YCP ZCP VCD ICD CX CY Cl ICm VCm ICn VCn Non-dimensional Stability Derivatives: CXu CLu Cmu CXa CLa Cma CXq CLq Cmq CYb Clb Cnb CYp Clp Cnp CYr Clr Cnr Non-dimensional Control Derivatives: CXd CYd CZd Cld Cmd Cnd CL/CD CL^(3/2)/CD 1/Rt(CL) Fx (N) Fx (lbf) Fy (N) Fy (lbf) Fz (N) Fz (lbf) Vx Vz V Gamma Pitching Moment Rolling Moment Yawing Moment XCP YCP ZCP BM m.g.Vz (W) Efficiency ctrl Ph. Freq(Hz) Ph. Damping SP Freq (Hz) SP Damping DR Freq(Hz) DR Damping Roll Damping Spiral Damping CoG.x CoG.z B.C. = Dirichlet B.C. = Neumann Analysis type Viscous Inviscid Body option Body Panels Ignored Ref. Area = Data points Beta Planform area Projected area Tilted geometry Ground height Density = Viscosity = iblpan : *** bl array overflow Increase IVX to at least %1 *** iblsys: bl system array overflow. *** Unrecognized foil format ... Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid mrchdu: convergence failed at %1 , side %2, res =%3 Side %1 ... mrchue: inverse mode at %1 hk =%2 mrchue: convergence failed at %1, side %2, res = %3 mrcl: illegal Re(cls) dependence trigger, Setting fixed Re mrcl: illegal Mach(cls) dependence trigger Setting fixed Mach mrcl: Cl too low for chosen Mach(Cl) dependence artificially limiting mach to 0.99 mrcl: cl too low for chosen Re(Cl) dependence artificially limiting Re to %1 PanGen: buffer airfoil not available. Paneling convergence failed. Continuing anyway... Panel: Too many panels. Increase IQX Calculating source influence matrix ... Initializing bl ... Side %1, forced transition at x/c = %2 %3 Side %1, free transition at x/c = %2 %3 scheck: bad value for small panels (stol > 0.3) setexp: cannot fill array. n too small Setexp: Convergence failed. Continuing anyway ... Sinvrt: spline inversion failed, input value returned Specal: MInf convergence failed Speccl: cl convergence failed splind: array overflow, increase nmax stfind: Stagnation point not found. Continuing ... trchek2 - n2 convergence failed *** stagnation point is past trip on side %1 Calculating wake trajectory ... XYWake: array size (IWX) too small. Last wake point index reduced. Wing Name Could not open the file for reading Total number of wing sections exceeds MAXSPANSECTIONS. Wing will be truncated. Unable to import wing definition Could not open the file for writing Span pos = %1 Span pos = %1 , A+Ai+Twist = %1 could not be interpolated , A+Ai+Twist = %1 is outside the flight envelope , Cl = %1 could not be interpolated , Cl = %1 is outside the flight envelope setbl: xtr??? n1=%1 n2=%2: Wing Span = %1 XYProj. Span = %1 X_CG = %1 Wing Area = %1 XYProj. Area = %1 Plane Mass = %1 Wing Load = %1 Tail Volume = %1 Root Chord = %1 M.A.C. = %1 Tip Twist = %1 Aspect Ratio = %1 Taper Ratio = %1 Root-Tip Sweep = %1 V = %1 Alpha = %1 Sideslip = %1 Bank = %1 Control pos. = %1 CL/CD = %1 Cl = %1 Cm = %1 Cn = %1 X_NP = %1 X_CP = %1 X_CG = %1 Point is out of the flight envelope mesh panels CL = %1 CD = %1 Efficiency = %1 Point x y Upper side points Lower side points Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid Cl = %1 ...converged after %1 iterations ...unconverged after %1 iterations Continuous foils for surface do not have the same initial flap angle... aborting QXDirect Cp Q Not enough threads available for multithreading Warning Top Bot Max Shear Top Shear Top Shear eq Bot Shear Bot Shear eq X Cp Graph Polar Graph Cm Graph Cz Graph Tr Graph User Graph Cf Cd' Are you sure you want to delete the Operating Point Question Are you sure you want to delete the polar : and all the associated OpPoints ? Are you sure you want to delete polars and OpPoints associated to The foil has been de-rotated by %1 degrees Export Current XFoil Results Text File (*.txt);;Comma Separated Values (*.csv) Top Side x Hk Ue/Vinf Cf Cd A/A0 D* Theta CTq x,Hk,Ue/Vinf,Cf,Cd,A/A0,D*,Theta,CTq Bottom Side Export Directory Export Foil Foil File (*.dat) Export OpPoint Export Polar Open File XFoil Polar Format (*.*) Could not read the file No Foil with the name could be found. The polar(s) will not be stored JavaFoil Polar Format (*.*) At least two foils are required The foil has been normalized from %1 to 1.000 Enter the new name for the foil polar : Polar File Polar File (*.plr) Thickness = %1 Max. Thick.pos. = %1 Max. Camber = %1 Max. Camber pos. = %1 Number of Panels = %1 Flap Angle = %1 XHinge = %1 YHinge = %1 TE Hinge Moment/span = 123456789 Polar Type = %1 Re.sqrt(Cl) = M.sqrt(Cl) = %1 Forced Upper Trans. = %1 Forced Lower Trans. = %1 Alpha = %1 Cl = %1 Cm = %1 Cd = %1 L/D = %1 Upper Trans. = %1 Lower Trans. = %1 TE Hinge Moment/span = %1 LE Hinge Moment/span = %1 Cl Re Sequence Start= End= D= Viscous Init BL Store Opp Analyze Analysis settings Show BL Show Pressure Animate Display Polar properties Curve Points Style Width Color Graph Curve Settings abcopy: buffer airfoil not available Target segment cannot include stagnation point in mixed-inverse QXInverse x/c Q/Vinf Q Graph Must mark off target segment first Converged Unconverged Modified Warning Unrecognized foil format The minimum number of control points has been reached for this spline degree Drag points to modify splines, Apply, and Execute to generate the new geometry Mark target segment for modification Mark spline endpoints Alpha = Cl = Mark target segment for smoothing, or type 'Return' to smooth the entire distribution Base Mod. Thickness = %1% Max.Thick.pos. = %1% Max. Camber = %1% Alpha = %1 Cl = %1 Q - Reference Q - Specification Q - Viscous Reflected Alpha Cl Specification ShowSpline Tangent Spline New Spline Apply Spline Reset QSpec Pert Modification Smooth QSpec Hannig Filter Filter parameter Smoothing T.E. Angle T.E. Gap dx/c T.E. Gap dy/c Symmetric foil Constraints Execute Cl = Mark for modification End Point Constraint Smooth Max Iterations Foil ReListDlg Reynolds Number List Insert Delete OK Cancel RenameDlg Rename Enter the new name Existing Names: OK Cancel Overwrite Note : Overwrite will delete Opps and reset polars Enter a name Warning Must enter a name Do you wish to overwrite Question SaveOptionsDlg Save Options Save: Foil Operating Points Wing and Plane Operating Points OK Cancel SplineCtrlsDlg Spline Parameters Upper side Lower side Spline degree Output Symetric foil Point Weight = OK Cancel Warning The spline degree must be less than the number of control points StabPolarDlg Stability Polar Definition Control Name Controls Wing Tilt ( Elevator Tilt Wing Flap angle %1 Elevator Flap %1 Fin Flap %1 Warning Mass must be non-zero for type 7 polars Must enter a name Wing Name Auto Analysis Name Polar Name b = f = Use plane inertia VLM 3D Panels Wing analysis methods Mix 3D Panels/VLM Note: + sign means trailing edge down Gain Viscous Analysis Note : the analysis may be of the viscous type only if all the flap controls are inactive Plane and Flight Data Unit International Imperial Aerodynamic Data Wing Planform Area Wing Planform Area projected on xy plane Reference Area for Aero Coefficients Plane analysis methods Ignore Body Panels OK Cancel StabViewDlg Stability View Params Longitudinal Lateral Stability direction Initial Conditions Response Forced Response Initial conditions Modal Response Modal response Define the total time range for the graphs Define the time step for the resolution of the differential equations Re-calculate the currently selected curve with the user-specified input data Add a new curve to the graphs, using the current user-specified input Rename the currently selected curve Delete the currently selected curve Time Graph Params Mode Selection Eigenvalues F1 = z = Mode properties <small>Mode Properties: Total Time Operating point modes Speed Amplitude Animate Restart Time Step = s Animation Time (s) Angle Controls Control function Enter the function of the control vs. time Curve Settings Recalc. Add Rename Delete Press Ctrl+H to highlight the mode on the root locus plot u0= w0= q0= v0= p0= r0= New curve TEGapDlg T.E. Gap T.E. Gap Value % chord Blending Distance from L.E. OK Cancel Apply Warning Unrecognized foil format Panel number cannot exceed 300 TranslatorDlg Language settings English Warning The change will take effect at the next session Select the application's default language: OK Cancel The directory does not exist TwoDPanelDlg Global Panel Refinement Number of Panels Panel Bunching Parameter TE/LE Panel Density Ratio Refined area/LE Panel Density Ratio Top Side Refined Area x/c limits Bottom Side Refined Area x/c limits OK Cancel Apply Warning Unrecognized foil format The total number of panels cannot exceed %1 UnitsDlg Select units for this project : Units Dialog Length Area Speed Mass Force Moment Define the project units OK Cancel W3dPrefsDlg 3D Styles Axis Outline VLM Mesh Top transition Bottom transition Lift Moments Induced Drag Viscous Drag Downwash WakePanels Streamlines Masses Show Wake Panels Close Reset Defaults WAdvancedDlg Wing Analysis Advanced Settings View Log File after errors Reset Wake between each angle Store points outside the polar mesh All Analysis VLM and Panel Methods Core Size VLM Method Ignore wing panels with span < Horseshoe vortex Ring vortex Vortex Position Control Point Position Lifting Line Method Relax. factor Alpha Precision Max. Iterations Number of spanwise stations 3D Panel boundary conditions OK Cancel Reset Defaults WPolarDlg Analysis Definition Warning Must enter a name for the polar Wing Name Auto Analysis Name Polar Name Type 1 (Fixed Speed) Type 2 (Fixed Lift) Type 4 (Fixed aoa) Polar Type Free Stream Speed = Inertia properties Use plane inertia Plane Mass = X_CoG = Z_CoG = Plane and Flight Data Wing Loading = 0.033 kg/dm2 SRe RRe QInfCl Flight Characteristics Mass must be non-zero for type 2 polars LLT VLM 3D Panels Wing analysis methods Mix 3D Panels/VLM Unit International Imperial Vinf.sqrt(Cl) = Aerodynamic Data Viscous Tilt. Geom. Options Ground Effect Height = Wing Planform Wing Planform Area Wing Planform projected on xy plane Wing Planform Area projected on xy plane Reference Area and Span for Aero Coefficients Reference Area for Aero Coefficients Ignore Body Panels OK Cancel Root Re = Tip Re = Root Re.sqrt(Cl) = Tip Re.sqrt(Cl) = Wing Loading = WingDelegate Uniform Cosine Sine -Sine WingScaleDlg Scale Wing Dlg Span Scaling Chord Scaling Sweep Scaling Twist Scaling Reference New Ratio OK Cancel XDirectStyleDlg XDirect Styles Neutral Line Boundary Layer Pressure OK Defaults Cancel XFoilAdvancedDlg XFoil Settings VAccel Iteration Limit Re-initialize BLs after an unconverged iteration Show full log report for an XFoil analysis OK Cancel XFoilAnalysisDlg XFoil Analysis Iter Skip Cancel Alpha = %1 Alfa = %1 ........ Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid Cl = %1 Cl = %1 ........ Initializing viscous analysis ... CpCalc: local speed too large Compressibility corrections invalid Solving BL system ... Iteration %1 ... unconverged after %1 iterations --------- Unconverged ----------- converged after %1 iterations Close xflr5-6.09-06/translations/xflr5v6_de.ts000755 001750 000144 00001767773 12247544275 021416 0ustar00techwinderusers000000 000000 AFoilGridDlg Grid Options Gitter Optionen Neutral Line Neutrale-Linie X-Scale X-Skalierung X Major Grid X-Hauptgitter Y Major Grid Y-Hauptgitter X Minor Grid X-Untergitter Y Minor Grid Y-Untergitter Accept Bestätigen Cancel Abbrechen Apply Anwenden AFoilTableDlg Foil Table Columns Profil Tabellen Spalten Foil Name Profil Name Thickness Dicke(thickness) Thickness max. position Position maximale Dicke Camber Wölbung(camber) Camber max. position Position maximale Wölbung Number of points Anzahl der Punkte Trailing edge flap angle Hinterkanten Flap Winkel Trailing edge hinge x-position Hinterkanten Flap Anschlags x-Position Trailing edge hinge y-position Hinterkanten Flap Anschlags y-Position Leading edge flap angle Vorderknten Flap WInkel Leading edge hinge x-position Vorderkanten Flap Anschlags x-Position Leading edge hinge y-position Vorderkanten Flap Anschlags y-Position OK OK Cancel Abbrechen AboutQ5 Copyright (C) M. Drela and H. Youngren 2000 - XFoil v6.94 Copyright (C) Matthieu Scherrer 2004 - Miarex v1.00 About XFLR5 Über XFLR5 Copyright (C) Andre Deperrois 2003-2013 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. This program has been developed exclusively for the analysis of model aircraft Any other usage is strongly disapproved Program distributed under the terms of the GNU General Public License German translation by Martin Willner Japanese translation by IKUSU, Koichi Akabe, Misatus, dynamicsoar, hide253 icchy_07, ina111, ohayo_cycling, ohisa_64, ozawa64. French translation by Jean-Luc Coulon OK BatchDlg Iter Current foil only Nur aktuelles Profil Foil list Profil Liste Foil Selection Profil Auswahl Type 1 Type 1 Type 2 Type 2 Type 3 Type 3 Type 4 Type 4 Analysis Type Analyse Methode Batch foil analysis Range Bereich Re List Re Liste Edit List Liste bearbeiten Min Max Increment Schrittweite Batch Variables Batch Variablen Specify Spezifizieren Alpha Alpha Cl Cl From Zero Von Null Spec = Analysis Range Analyse Bereich NCrit= Forced transitions Erzwungener Umschlag Trip Location (top) Umschlagspunk (oben) Trip Location (bottom) Umschlagspunkt (unten) Transitions Data Umschlagsdaten Initialize BLs between polars Grenzschicht zwischen Polaren neu initialisieren Store OpPoints OpPoints speichern Close Schließen Analyze analysieren Skip Opp Opp überspringen Skip Polar Polar überspringen Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid Ungültige Analyse Einstellungen\nCpCalc: Lokale Geschwindigkeit zu groß!\nKorrekturen ungültig Warning Warnung ...converged after %1 iterations ...Konvergenz nach %1 Iterationen ...skipped after %1 iterations ...übersprungen nach %1 Iterationen ...unconverged after %1 iterations ... keine Konvergenz nach %1 Iterationen Analysis interrupted Analyse unterbrochen Invalid Analysis Settings CPCALC: local speed too large Compressibility corrections invalid Ungültige Analyse Einstellungen\nCPCALC: lokale Geschwindigkeit zu hoch\nKorrekturen ungültig CpCalc: local speed too large Compressibility corrections invalid CpCalc: Lokale Geschwindigkeit zu hoch\nKorrekturen ungültig Reynolds = Mach = ...converged after %1 iterations ...Konvergenz nach %1 Iterationen ...skipped after %1 iterations ...übersprungen nach %1 Iterationen ...unconverged after %1 iterations ... keine Konvergenz nach %1 Iterationen Batch analysis for Batch Analyse für Top transition location (x/c) Bottom transition location (x/c) Alpha = Cl = Cl = Re.sqrt(Cl) = Ma.sqrt(Cl) = Re.Cl = Cancel Abbrechen Cl = %1 Cl = %1 Analyzing Analysiere Analysis completed Analyse vollständig BatchThreadDlg Multi-threaded batch analysis Foil Selection Profil Auswahl Current foil only Nur aktuelles Profil Foil list Profil Liste Batch Variables Batch Variablen Range Bereich Re List Re Liste Edit List Liste bearbeiten Min Max Increment Schrittweite NCrit= Analysis Range Analyse Bereich Specify: Alpha Alpha Cl Cl From Zero Von Null Spec = Forced Transitions Top transition location (x/c) Bottom transition location (x/c) Initialize BLs between polars Grenzschicht zwischen Polaren neu initialisieren Update polar view Update the polar graphs after the completion of each foil/polar pair Close Schließen Analyze CL Cancel Abbrechen BodyGridDlg Body Grid Dialog Rumpf Gitter Dialog Grid Parameters Gitter Parameter Show Scales Zeige Skalierungen Main Grid Hauptgitter Minor Grid Untergitter Body Grid Rumpfgitter Frame Grid Rahmengitter OK Ok Cancel Abbrechen BodyScaleDlg Body Scale Dialog Rumpf Skalierungsdialog Whole Body Gesamter Rumpf Frame Only Nur Rahmen Scale Factor Skalierungsfaktor X Scale X-Skalierung Y Scale Y-Skalierung Z Scale Z-Skalierung OK Ok Cancel Abbrechen BodyTransDlg Body Translation Rumpf Verschiebung Frame Only Nur Rahmen X Translation X-Verschiebung Y Translation Y-Verschiebung Z Translation Z-Verschiebung OK Ok Cancel Abbrechen CAddDlg Local Panel Refinement Lokale Panel Verfeinerung Angle Criterion Winkelkriterium Type of Spline Art der Spline Refinement X Limits Verfeinerung X Grenzen From Von To nach Uniform gleichmäßig Arc Length Bogenlänge Total Gesamt Added hinzugefügt MaxAngle Maximal Winkel At Panel bei Panel Accept Bestätigen Cancel Abbrechen Apply Anwenden Warning Warnung Unrecognized foil format Unbekannts Profil Format Total number of points is %1 Gesamtzahl der Punkte ist %1 (added %1 points to original foil) (%1 Punkte hinzugefügt) Maximum panel angle is %1 Maximaler Panel Winkel ist %1 at panel position %1 bei Panel Position %1 Maximum panel angle is %1 deg Maximaler Panel Winkel ist %1 CSurface Warning Warnung Continous foils for surface do not have the same initial flap angle... aborting Continous foils for surface do not have the same initial flap angle... aborting CpScaleDlg CpScale Settings CpScale Einstellungen Auto Scales Automatische Skalierung Done Fertig CtrlPolarDlg Control Polar Definition Kontroll-Polar Definition Control Name Kontroll-Name Active (1/0) Aktiv (1/0) Controls Steuert Wing Tilt ( Flächen Neigung(tilt) ( Elevator Tilt Höhenruder Neigung(tilt) Wing Flap angle %1 Flächen Klappen-Winkel %1 Elevator Flap %1 Höhenruder Klappen-Winkel %1 No Active Control. Continue ? Keine aktiven Kontrollen. Vorsetzen? Question Frage Warning Warnung Must enter a name Sie müssen einen Namen eingeben The polar's name already exists Der Polar-Name existier bereits Wing Name Tragflächen Name Auto Analysis Name Name der automatischen Analyse Polar Name Polaren Name Type 5 (Fixed Speed) Type 5 (fixe Geschwindigkeit) Type 6 (Fixed Lift) Type 6 (Fixer Auftrieb) Viscous Reibung Polar Type Polaren Typ Free Stream Speed Freie Strömungsgeschwindigkeit Plane Mass Flugzeug Gewicht Note 3 : the analysis may be of the viscous type only if all the flap controls are inactive Hinweis 3: Die Analyse ist nur dann mit Reibung wenn die Klappen inaktiv sind Plane Weight Modellgewicht Plane and Flight Data Modell und Flugdaten Unit Einheit International International Imperial Imperial Aerodynamic Data Aerodynamische Daten Wing Planform Area Trangflächen Grundform Fläche Wing Planform Area projected on xy plane Trangflächen Grundform Fläche auf XY Ebene projeziert Reference Area for Aero Coefficients Referenzfläche für aerodynamische Koeffizienten Note 1 : the analysis is necessarily of type VLM1 Hinweis 1: Die Analyse ist notwendigerweise vom Typ VLM1 Note 2 : if the control for XCmRef is inactive, then the minimal value will be used for the analysis Hinweis 2: Wenn die Kontrolle für XCmRef inaktiv ist dann wird der Minimalwert für die Analyse verwendet Note 3 : the analysis may be of the vicous type only if all the flap controls are inactive Hinweis 3: Die Analyse ist nur dann mit Reibung wenn die Klappen Kontrollen inaktiv sind OK Ok Cancel Abbrechen DisplaySettingsDlg General Display Settings Allgemeine Display Einstellungen All Graph Settings Alle Graphen Einstellungen Graph Settings Graphen Einstellungen Background Color Hintergrundfarbe Text Color Textfarbe Font Schriftart Reverse zoom direction using mouse wheel Enable 3D transparency OK Cancel Abbrechen Warning Warnung EditPlrDlg Polar Points Edition Polar Punkte Verwalten Delete All Points Alle Punkte löschen Delete Point Punkt löschen OK Ok Cancel Abbrechen FlapDlg Flap Dlg Klappen Dialog L.E. Flap L.E (Vorderkanten) Klappe T.E. Flap T.E.(Hinterkanten) Klappe Flap Angle Klappen Winkel + is down Hinge X Position Aufhängungs X-Position % Chord % Chord (Flügeltiefe) Hinge Y Position Aufhängungs Y-Position % Thickness % Dicke OK Ok Cancel Abbrechen Apply Anwenden Warning Warnung The trailing edge hinge must be downstream of the leading edge hinge Die Hinterkante muss nach der Vorderkante angeströmt werden FoilCoordDlg Apply Anwenden Foil Coordinates Profil Koordinaten Insert Point Punkt einfügen Delete Point Punkt löschen Restore Wiederherstellen OK Ok Cancel Abbrechen FoilGeomDlg Foil Geometry Profil Geometrie Value Wert %Chord 0% 10% Max x-pos Maximale X-Position 100% Camber Wölbung(camber) Thickness Dicke(thickness) OK Ok Cancel Abbrechen Restore Wiederherstellen Warning Warnung Panel number cannot exceed 300 Panel Anzahl kann nicht größer 300 sein FoilPolarDlg Foil Polar Definition Profil Polar Definition Automatic Automatisch User Defined Benutzerdefiniert Analysis Name Analyse Methode Type 1 Type 1 Type 2 Type 2 Type 3 Type 3 Type 4 Type 4 Analysis Type Analyse Methode Plane Data Chord Mass Span Aerodynamic Data Aerodynamische Daten Unit Einheit International International Imperial Imperial Re = Mach = Reynolds and Mach Numbers Aerodynamic data Aerodynamische Daten OK Ok Cancel Abbrechen Free transitions (e^n) method Forced transition: Erzwungener Umschlag: NCrit= TripLocation (top) Umschlagspunk (oben) TripLocation (bot) Umschlagspunkt (unten) Transition settings Umschlags-Einstellungen Analysis parameters for Analyse Werte für Reynolds = Re.sqrt(Cl) = Ma.sqrt(Cl) = Re.Cl = Alpha = FoilSelectionDlg Foil Selection Profil Auswahl OK Ok Cancel Abbrechen GL3DScales 3D Scales Settings 3D Skalierungs Einstellungen Auto Scales Automatische Skalierung Min Max Cp Scale Cp Skalierung Lift Auftrieb (Lift) Drag Widerstand (Drag) Velocity Geschwindigkeit Vector Scales Vektoren Skalierung L.E. L.E (Vorderkante) T.E. T.E.(Hinterkante) Y-Line Y-Linie X-axis points Punkte der X-Achse 1st segment 1. Segment X factor X Faktor X-Offset X-Abstand (offset) Z-Offset Z-Abstand(offset) Streamline length Stromlinien Länge Start Streamline at Stromlinien starten bei Streamlines Apply Anwenden GL3dBodyDlg Body Edition Rumpf Bearbeitung Insert Einfügen Remove Entfernen Scale Skalieren Grid Setup Gitter Verwalten Reset Scales Skalierungen zurücksetzen Show Current Frame Only Zeige nur aktuellen Rahmen Inertia... Trägheit... Undo Rückgängig Cancels the last modifiction made to the body Überspringt die letzte Änderung am Rumpf Redo Wiederherstellen Restores the last cancelled modification made to the body Stellt die letzte Änderung am Rumpf wieder her Export Body Geometry to File Rumpf Geometrie in File exportieren Export Body Definition to File Rumpf Definitionen in File exportieren Import Body Definition from File Rumpf Definitonen von File importieren Translate übersetzen Resolution cannot exceed %1 Auflösung kann %1 nicht übersteigen Warning Warnung Frame %1 Rahmen %1 Scale = %1 Skalierung = %1 NPanels NPanels Body Dlg Exit Rumpfverwaltung Exit Insert Point Punkt einfügen Remove Point Save the Body ? Rumpf speichern? Axes Axen Light Licht Surfaces Oberflächen Outline Kontur Panels Panele Masses X X Y Y Z Z Iso Iso Pick Center Zentrum auswählen Clip Plane Schnittebene Other Andere Actions... Aktionen... Save and Close speichern und schliessen Cancel Abbrechen Flat Panels Flache Panels BSplines BSplines x x Hoop Degree Grad BodyName Rupf-Name Enter here a short description for the body Geben Sie eine Beschreibung für den Rumpf an Description: Beschreibung: Cancels the last modification Restores the last cancelled modification Define Inertia Trägheit definieren X View Y View Z View Iso View Panel bunch Frames Rahmen Frame Positions Rahmen Position Points Punkte Current Frame Definition Aktuelle Rahmen Definition Context Menu Befehlsübersicht GL3dWingDlg Warning Warnung Warning : Panel sequence is inconsistent Warnung: Panel Sequenz ist inkonsistent The first section cannot be deleted Der erste Abschnitt kann nicht gelöscht werden Insert after section Insert before section Symetric symetrisch Right Side rechte Seite Left Side linke Seite Insert Before Davor einfügen Wing Edition Tragflächen Bearbeitung Reset Scales Skalierungen zurücksetzen Insert after danach einfügen Delete section Abschnitt löschen Reset section Import Wing from File... Export Wing to File... Section Abschnitt Please enter a name for the wing Bitte geben Sie einen Name für die Tragfläche an Too many spanwise panels. The maximum number is Too many panels Reduce the mesh size Zu viele Panele\nBitte reduzieren sie die Gittergröße Only 10 flaps x 2 will be handled Es werden nur 10 Klappen x2 verwaltet Question Frage Uniform Gleichmäßig Cosine COSinus Sine SINus -Sine -SINus y ( chord ( Flügeltiefe ( offset ( Abstand ( The maximum number of panels has been reached Die Maximalanzahl von Panels wurde erreicht No insertion possible before the first section Kein einfügen vor dieser Position ist möglich Wing Description Tragflächenbeschreibung Save the changes ? Änderungen speichern? Number of VLM Panels X View Y View Z View Iso View Insert after section %1 Einfügen nach Abschnitt %1 Insert before section %1 Einfügen vor dem Abschnitt %1 Delete section %1 Löschen von Abschnitt %1 Undefined Undefiniert Insert After danach einfügen Delete Section Abschnitt löschen WingName Tragflächen Name Wing Span Trangflächen-Spannweite Area Fläche Projected Span Projizierte Spannweite Projected Area Projizierte Fläche Max is Maximum ist Volume Volumen Total VLM Panels Anzahl der gesamten LVM Panels Number of 3D Panels Gesamtzahl der 3D Panels Max is 1000 Max ist 1000 Max is 2000 Max ist 2000 Mean Geom. Chord Mittlere Geometrische Flügeltiefe Mean Aero Chord Mittlere Aerodynamische Flügeltiefe MAC Span Pos M.A.C. Spantenposition Aspect ratio Streckungs Verhältnis Taper Ratio Aufweitungsverhältnis Root to Tip Sweep Wurzel-Spitzen Rückfall (Root to Tip sweep) Number of Flaps Anzahl der Klappen Enter here a short description for the wing Kurzbeschreibung der Tragfläche Description: Beschreibung: Axes Axen Light Licht Surfaces Oberflächen Outline Kontur Panels Panels Foil Names Profil Namen Masses X X Y Y Iso Isometrisch Pick Center Zentrum auswählen Activate the button, then click on the object to center it in the viewport; alternatively, double click on the object Doppelklick auf das Objekt um es zu zentrieren Reset Zurücksetzen Clip Plane Ebenenschnitt Reset Mesh Gitter zurücksetzen Scale Wing Tragfläche skalieren Inertia... Trägheit... Import Wing Export Wing Save and Close speichern und schliessen Cancel Abbrechen Context Menu Befehlsübersicht GLLightDlg OpenGL Light Options OpenGL Lichtoptionen Diffuse diffus Ambient Umgebung Specular Specular Light Intensity Licht Intensität Red Rot Green Grün Blue Blau Light Color Licht Farbe x x y z Light Position Licht Position Emissions Ausstoß Shininess Glanz Material Material Color Material Materialfarbe Cull Faces Fläche ausbessern (cull) Smooth Quads Depth Test Tiefentest Smooth Shading glatte Schattierung Local View Lokale Ansicht Options Optionen Close Schließen Reset Defaults Standardwerte zurücksetzen Light Licht GraphDlg Graph Settings Graphen Einstellungen X - Chord X - Abschnitt Q - Speed Q - Geschwindigkeit X - chord X - Abschnitt Cp Cp Alpha Alpha Cl Cl Cd Cd Cd x 10000 Cd x 10000 Cdp Cdp Cm Cm Xtr1 Xtr1 Xtr2 Xtr2 HMom HMom Cpmin Cpmin Cl/Cd Cl/Cd |Cl|^(3/2)/Cd |Cl|^(3/2)/Cd 1/Cl^1/2 Re Re XCp XCp Y - span Induced Angle Induzierter Winkel (induced angle) Total Angle Gesamter Winkel Local lift coef. Lokaler Auftriebs Koeffizient. Local Lift C.Cl/M.A.C. Airfoil viscous drag coef. Induced drag coef. Total drag coef. Local Drag C.Cd/M.A.C. Airfoil Pitching moment coef. Total Pitching moment coef. Geom. Pitching moment coef. Reynolds Top Transition x-pos% Umschlagspunkt Oben (Top Trans x-Pos) % Bottom Transition x-pos% Umschlagspunkt unten (Bot Trans x-Pos ) % Centre of Pressure x-pos% Druckounkt (CoP) X-Position% Bending moment Biegemoment Lift coef. Viscous drag coef. Total pitching moment coef. Viscous pitching moment coef. Reibungsbehafter Kippmoment Koeffizient Induced pitching moment coef. Kippmoment Koeffizeint aufgund des induzierten Widerstandes Total rolling moment coef. Gesamt Rollmoment Koeffizient Total yawing moment coef. Gesamter Giermoment Koeffizient Viscous yawing moment coef. Reibungsbehafteter Giermoment Koeffizient Induced yawing moment coef. Induzierter Widerstand Giermoment Koeffizient Glide ratio Cl/Cd Gleitverhältnis Cl/Cd Power factor Cl^(3/2)/Cd Leistungsfaktor Cl^(3/2)/Cd 1/Rt(Cl) 1/Rt(Cl) FX (Drag) FY (Side force) FZ (Lift) Lift Auftrieb Drag Widerstand Vx Vz VInf Descent angle atan(Cd/Cl) Gleitwinkel atan(Cd/Cl) Pitching Moment Kippmoment Rolling Moment Rollmoment Yawing Moment Giermoment Centre of pressure X-Pos Druckpunkt X-Pos Centre of pressure Y-Pos Druckpunkt Y-Pos Centre of pressure Z-Pos m.g.Vz Efficiency Effizienz (XCp-Xcg)/MAC Control Variable Kontroll-Variable Cy - Lateral force coef. Neutral Point x-position Neutralpunkt x-Position Phugoid Frequency Phugoid Damping Short Period Frequency Short Period Damping Dutch Roll Frequency Dutch Roll Damping Roll Damping Spiral Damping Restore Wiederherstellen OK Ok Cancel Abbrechen Apply Anwenden YAxis vs. XAxis Title Titel Label Bezeichnung Legend Legende Font Schriftart Color Farbe Set Title Font Setze Titel Font Set Label Font Setze Beschriftungs Font Set Legend Font Setze Legenden Font Title Color Titel Farbe Label Color Beschreiftungs Farbe Legend Color Legenden Farbe Fonts Schriftart Graph Background Hintergrundfarbe Graph Border Randfarbe BackGround Hintergrund X Axis X-Achse Y Axis Y-Achse Min Max Origin Ursprung Unit Einheit Auto Scale Automatische Skalierung Inverted Axis Invertierte Achsen Axis Style Achsen Gestalltung X Major Grid X-Hauptgitter Y Major Grid Y-Hauptgitter X Minor Grid X-Untergitter Y Minor Grid Y-Untergitter Auto Unit Automatische Skalierung Variables Variablen Scales Skalierungen Axis and Grids Achsen und Gitter Fonts and BackGround Schriftart und Hintergrund ImportObjectDlg Import Object Select the wing to import Tragfläche für Imort auswählen Select the body to import OK Cancel Abbrechen ImportWingDlg Import Wing Dialog Tragflächen Import Select the wing to import Tragfläche für Imort auswählen OK Ok Cancel Abbrechen InertiaDlg Inertia Properties Trägheits Eigenschaften Description %1 Beschreibung %1 Mass Massa x x y z Description Beschreibung Wing Mass: Tragflächen Masse: Body Mass: Rumpf Masse: Volume Mass: Volumsmassa: %1 %2 %3 %4 %5 %6 %7 ! Inertia of both left and right wings %1 %2 %3 %4 %5 %6 %7 ! Trägheit der linken und rechten Tragfläche %1 %2 %3 %4 %5 %6 %7 ! Body inertia %1 %2 %3 %4 %5 %6 %7 ! Rumpf Trägheit %1 %2 %3 %4 %5 %6 %7 ! Main wing's inertia %1 %2 %3 %4 %5 %6 %7 ! Tragflächen Trägheit %1 %2 %3 %4 %5 %6 %7 ! Second wing's inertia %1 %2 %3 %4 %5 %6 %7 ! 2. Tragfläche Trägheit %1 %2 %3 %4 %5 %6 %7 ! Elevator's inertia %1 %2 %3 %4 %5 %6 %7 ! Höhenruder Trägheit %1 %2 %3 %4 %5 %6 %7 ! Fin's inertia %1 %2 %3 %4 %5 %6 %7 ! Seitenruder Trägheit %1 %2 %3 %4 %5 %6 %7 ! Body's inertia %1 %2 %3 %4 %5 %6 %7 ! Körper Trägheit This is a calculation form for a rough order of magnitude for the inertia tensor. Die Berechnung ist nur eine grobe Überschlagsrechnung für den Trägheitstensor. Export Mass Properties Massen Eigenschaften exportieren Insert Before Davor einfügen Delete Löschen Point Mass Inertia properties for Trängsheits Eigenschaften für AVL Mass File (*.mass) %1 %2 %3 %4 %5 %6 %7 %8 %9 %10! Inertia of both left and right wings %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Body inertia %1 %2 %3 %4 %5 %6 %7 ! Rumpf Trägheit {1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ?} %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Main wing's inertia %1 %2 %3 %4 %5 %6 %7 ! Tragflächen Trägheit {1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ?} %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Second wing's inertia %1 %2 %3 %4 %5 %6 %7 ! 2. Tragfläche Trägheit {1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ?} %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Elevator's inertia %1 %2 %3 %4 %5 %6 %7 ! Höhenruder Trägheit {1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ?} %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Fin's inertia %1 %2 %3 %4 %5 %6 %7 ! Seitenruder Trägheit {1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ?} %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Body's inertia %1 %2 %3 %4 %5 %6 %7 ! Körper Trägheit {1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ?} Refer to the Guidelines for explanations. Bitte lesen Sie das Handbuch für Details. Object Mass - Volume only, excluding point masses Wing Mass= Tragflächen Masse = Component inertias Trägheit der Bestandteile Main Wing Haupt-Tragfläche Second Wing 2. Tragfläche Elevator Höhenruder Fin Seitenruder Body Rumpf Additional Point Masses Total Mass = Volume + point masses Gesamt Masse = Volumen + Punkt Massen Total Mass= Gesamt Masse = OK Ok Cancel Abbrechen Center of gravity Schwerpunkt %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Inertia in CoG Frame Trägheit im Rahmen des Schwerpunktes Additional Point Masses: Zusätzliche Punktmassen: Export to AVL Nach AVL exportieren Close Schließen InterpolateFoilsDlg Interpolate Foils Profile interpolieren Camb1 Camb2 Camb3 Thick1 Thick2 Thick3 New Foil Name Neuer Profilname Interpolated Foil Interpolierte Tragfläche OK Ok Cancel Abbrechen Camb.=%1 at x=%1 bei x=%1 Thick.=%1 Dicke =%1 at x=%5.1f bei x=%5.1f InverseOptionsDlg XInverse Style Reference Foil Referenz Profil Modified Foil Modifiziertes Profil Spline Spline Reflected Curve Reflektierte Kurve OK Ok Cancel Abbrechen LECircleDlg L.E. Circle Vorderkanten (L.E.) Kreis r= % Chord % Profiltiefe Show Anzeigen OK Ok Cancel Abbrechen LEDlg Leading Edge Vorderkante New approximate L.E. new/old ratio Neue Näherung der Vorderkante (L.E.) neu/alt Verhältnis Approximate new/old ratio for L.E. radius ratio Verhältnis Blending Distance from L.E. Biegeabstand von der Vorderkante % chord % Profiltiefe OK Ok Cancel Abbrechen Apply Anwenden Warning Warnung Unrecognized foil format Unbekannts Profil Format Panel number cannot exceed 300 Panel Anzahl kann nicht größer 300 sein LLTAnalysisDlg LLT Analysis LLT Analyse Iterations Iterationen Launching analysis.... Starte Analyse.... Max iterations = %1 Maximale Iterationen = %1 Alpha precision = %1 deg Alpha Genauigkeit = %1 deg Relaxation factor = %1 Relaxation Faktor = %1 Number of stations = %1 Anzahl der Stützpunkte = %1 Analysis cancelled on user request.... Analyse auf Wunsch des Benutzers abgebrochen Calculating Alpha = %1... Berechne Alpha = %1... ...negative Lift... Aborting ...negativer Auftrieb...abbruch ...converged after %1 iterations ...Konvergenz nach %1 Iterationen ...unconverged after %2 iterations ...keine Konvergenz nach %2 Iterationen Alpha = %1, skipped after %2 iterations Alpha = %1, übersprungen nach %2 Iterationen QInf = %1 skipped after %2 iterations QInf = %1 übersprungen nach %2 Iterationen Skip überspringen Cancel Abbrechen Analysis completed Analyse beendet ...some points are outside the flight envelope ...einige Punkte sind außerhalb des Flugbereiches! ...some points are unconverged ...einige Punkte sind nicht konvergiert Close Schließen Initializing analysis... Starte Analyse... Calculating QInf = %1... Berechne QInf = %1... ...unconverged after %1 iterations ... keine Konvergenz nach %1 Iterationen LinePickerDlg Line Picker Style Darstellung Width Breite Color Farbe OK Ok Cancel Abbrechen MainFrame Save the project before exit ? Projekt vor verlassen speichern? New Project Neues Projekt Ctrl+N Ctrl+N Save and close the current project, create a new project Aktuelles Projekt peichern und schliessen, erzeugt neues Projekt Close the Project Aktuelles Projekt schliessen Ctrl+W Ctrl+W Save and close the current project Aktuelles Projekt speichern und schliessen &Open... &Öffnen... Ctrl+O Ctrl+O Open an existing file Bestehenden File öffnen &Insert Project... Projekt e&infügen... Insert an existing project in the current project Bestehendes Projekt in aktives Projekt einfügen &Direct Foil Design &Direct Foil Design Ctrl+1 Ctrl+1 Open Foil Design application Öffne Profil Design Applikation &XFoil Inverse Design &XFoil Inverse Design Ctrl+3 Ctrl+3 Open XFoil inverse analysis application Öffnen XFoil invserse Analyse Applikation &XFoil Mixed Inverse Design &Xfoil Mixed Inverse Design Ctrl+4 Ctrl+4 Open XFoil Mixed Inverse analysis application Öffne XFoil mixed Inverse Analyse Applikation &XFoil Direct Analysis &XFoil Direct Aanalyse Ctrl+5 Ctrl+5 Open XFoil direct analysis application Öffne XFoil direkt Analyse Applikation &Wing and Plane Design &Tragfläche und Modell Design Ctrl+6 Ctrl+6 Open Wing/plane design and analysis application Öffne Tragfläche/Modell Design und Analyse Applikation Save speichern Ctrl+S Ctrl+5 Save the project to disk Projekt speichern Save Project As... Speichern als... Save the current project under a new name Aktuelles Projekt unter neuem Namen speichern Save Options Speicher Optionen Define units... Einheiten definieren... Define the units for this project Einheiten für dieses Projekt definieren Language... Sprache... Define the default language for the application Standardsprache Restore toolbars Toolbars wiederherstellen Restores the toolbars to their original state Toolbars Positionen wiederherstellen Save View to Image File Speichere Ansicht in Bilddatei Ctrl+I Ctrl+I Saves the current view to a file on disk Aktuelle Ansicht in Datei speichern Reset Default Settings Auf Standardeinstellungen zurücksetzen will revert to default settings at the next session Die Standardeinstellungen werden beim Neustart verwendet. General Display Settings Allgemeine Display Einstellungen Export Graph Graphen exportieren Export the current graph data to a text file Graph Daten in Text-File exportieren Reset Graph Scales (R) Graph Skalierung zurücksetzen (R) Restores the graph's x and y scales X und Y Skalierung zurücksetzen E&xit B&eenden Ctrl+Q Ctrl+Q Exit the application Applikation beenden &Guidelines &Richtlinien Show the guidelines for some help Zeige die Richtlinen an &About &Info QFLR5 QFLR5 Grid Options Gitter Optionen Define the grid settings for the view Gitter Einstellungen für die Ansicht Use Splines Splines verwenden Define a foil using one B-Spline for each foil side Profile mit B-Splines für jede Seite erstellen Use Splined Points Bnutze Splines Points Define a foil using one 3rd order B-Spline between two control points Profile mit B-Splines 3. Ordnung mit 2 Kontrollpunkten erstellen Store Splines as Foil Profil als Splines speichern Store the current splines in the foil database Aktuelles Profil als Splines in der Profildatenbank speichern Splines Params Splines Parameter Define parameters for the splines : degree, number of out points Definition der Splines Parameter: Winkel, Anzahl der Punkte Export Splines To File Splines in File exportieren New Splines Neue Splines Reset the splines Splines zurücksetzen Zoom in Hineinzoomen Zoom the view by drawing a rectangle in the client area Zoomen durch auswahl eines Rechteckes in der Ansicht Reset X Scale X-Skalierung zurücksetzen Resets the scale to fit the current screen width Skalierung auf Ansichtsbreite zurücksetzen Undo Rückgängig Cancels the last modifiction made to the splines Letzte Änderung an den Splines zurücksetzten Redo Wiederherstellen Restores the last cancelled modifiction made to the splines Stellt die letzte Änderung an den Splines wieder her Show All Foils Zeige alle Profile Hide All Foils Ausblenden aller Profile Delete... Löschen... Rename... Umbenennen... Export... Exportieren... Show Current Foil Zeige aktuelles Profil Hide Current Foil Ausblenden des aktuellen Profils Reset Y Scale Y-Skalierung zurücksetzen Reset Scales (R) Skalierung zurücksetzen (R) F&oil Pr&ofil Two Graphs Zwei Graphen All Graphs Alle Graphen Graph 1 Graph 2 Graph 3 Graph 4 &Body Rumpf(&B) Foi&l Profi&l &Operating Points Arbeitspunkte(&O) Reset foil scale (R) Profil Skalierung zurücksetzen (R) Resets the x and y scales to screen size X- und Y- Skalierung auf Ansichts zurücksetzen &About XFLR5 &Info Zoom Less Herauszoomen Zoom Y Scale Only Nur Y-Skalierung zoomen Zoom Y scale Only Nur Y-Skalierung zoomen De-rotate the Foil Entdrehen des Profils Normalize the Foil Normalisieren des Profils Refine Locally Lokales redefinieren Refine Globally GLobales redefinieren Edit Foil Coordinates Profil Koordinaten editieren Scale camber and thickness Wölbung und Dicke skalieren Set T.E. Gap Setzen der Hinterkanten Spalte (T.E.) Set L.E. Radius Setzen des Vorderkaten Radius (L.E) Show LE Circle Zeigen Vorderkanten Kreis (L.E) Show Legend Legende anzeigen Set Flap Setze Klappen Interpolate Foils Profile interpolieren Naca Foils NACA Profile &View &Ansicht &Foil Design &Profil Design &Splines &Splines Context Menu Befehlsübersicht Current Foil Aktuelles Profil Foil Profil 3D Scales 3D Skalierung &File &Datei &? &? OpPoint view Arbeitspunt Ansicht Show Operating point view Zeige Arbeitspunkt Ansicht F5 F5 Polar view Polaren Ansicht Show Polar view Zeige Polaren Ansicht F8 f8 3D view 3D Ansicht Show 3D view Zeige 3D Ansicht F4 f4 Cp view Cp Ansicht Show Cp view Zeige Cp Ansicht F9 f9 3D Color Preferences 3D Farb Einstellungen Polar Filter Polaren Filter 3D Light Options 3D Licht Einstellungen Define a New Wing Definiere eine neue Tragfläche Shows a dialogbox for editing a new wing definition Zeigt einen Dialog zum Erstellen einer neuen Tragfläche F3 F3 Define a New Plane Definiere ein neues Modell Shows a dialogbox to create a new plane definition Zeit einen Dialog zum Erstellen eines neuen Modelles Ctrl+F3 Ctrl+F3 Edit... Bearbeiten... Shows a dialogbox to edit the currently selected wing or plane Zeigt einen Dialog zum Editieren der aktuellen Tragfläche oder des Modelles Shift+F3 Shift+F3 Define a New Body Neuen Rumpf erstellen Shows a dialogbox for editing a new body definition Zeigt einen Dialog zum Erstellen eines neuen Rumpfes Show Elevator Curve Zeige Höhenruder Kurve Define an Analysis (F6) Analyse definierten (F6) Define a Control Analysis (Ctrl+F6) Kontroll Analyse definieren (Ctrl+F6) Batch Analysis (Shift+F6) Batch Analyse (Shift+F6) View Log File Logfile anzeigen Edit Current Aktuellen editieren Exit Beenden &New Project &Neues Projekt &Close the Project Projekt schiessen (&c) Insert Pro&ject... Pro&jekt einfügen... Direct &Foil Design Direktes Pro&fil Design XFoil &Inverse Design XFoil &Inverse Design &Save &Speichern Save Project &As... Projekt speichern &als... Save O&ptions O&ptionen speichern &Language... Sprache(&L) &Reset Default Settings Einstellungen zu&rücksetzen Foil &Design Profil &Design Shift+F10 Shift+F10 Export Body Definition Rupfdefinition exportieren Export a body definition to a text file Rumpfdefinition in Text-File exportieren Export Body Geometry Rupfgeometrie exportieren Export a body geometry at different cross sections to a text file Exportieren des Rumpfgeometrie an einer Schnittstelle in einen Text-File Import Body Rumpf importieren Import a body definition from a text file Rumpfdefinition von Text-File importieren Manage Bodies Rümpfe verwalten Manage the body list : Rename, Duplicate, Delete Verwalten der Rumpfliste: Umbenennen, Duplizieren, Löschen Export to AVL... Als AVL exportieren... Reset Legend Position Legendenposition zurücksetzen Reset Wing Scale Trangflächen Skalierung zurücksetzen Scale Wing Trangfläche skalieren Manage UFOs UFOs Verwalten F7 f7 Import Polar Polaren importieren Define Inertia Trägheit definieren Show Current OpPoint Only Zeige nur aktuellen Arbeitspunkt Show All OpPoints Zeige alle Arbeitspunkte Hide All OpPoints Ausblenden aller Arbeitspunkte Delete All OpPoints Lösche alle Arbeitspunkte Show Associated OpPoints Zeige zugehörige Arbeitspunkte Hide Associated OpPoints Verbede zugehörige Arbeitspunkte Delete Associated OpPoints Lösche zugehörige Arbeitspunkte Show Elliptic Curve Zeige elliptische Kurve Show XCmRef location Zeige XCmRef Position Show Fin Curve Zeige Fin Kurve Show Second Wing Curve Zeige 2. Trangflächen Kurve Define Graph Settings (G) Bestimme Graphen Einstellungen (G) Two OpPoint Graphs (T) Zwei Arbeitspunkte Graphen (T) All OpPoint Graphs (A) Alle Arbeitspunkte Graphen (A) Wing Graph 1 (1) Trangflächen Graph 1 (1) Wing Graph 2 (2) Trangflächen Graph 2 (2) Wing Graph 3 (3) Trangflächen Graph 3 (3) Wing Graph 4 (4) Trangflächen Graph 4 (4) Two Polar Graphs (T) Zwei Polaren Graphen (T) All Polar Graphs (A) Alle Polaren Graphen (A) Polar Graph 1 (1) Polar Graph 1 (1) Polar Graph 2 (2) Polar Graph 2 (2) Polar Graph 3 (3) Polar Graph 3 (3) Polar Graph 4 (4) Polar Graph 4 (4) Reset Graph Scales Graph Skalierung zurücksetzen Reset All Graph Scales Alle Graphen Skalierungen zurücksetzen All Graph Settings Alle Graphen Einstellungen Hide Associated Polars Verberge zugehörige Polaren Show Associated Polars Zeige zugehörige Polaren Delete Associated Polars Lösche zugehörige Polaren Hide All Polars Verberge alle Polaren Show All Polars Zeige alle Polaren F2 F2 Duplicate... Duplizieren... Save as Project... Speiche Projekt als... Edit ... Bearbeiten... Export ... Exportieren... Reset ... Zurücksetzen... Delete ... Löschen... Advanced Settings... Erweiterte Einstellungen... &Wing-Plane &Tragfläche-Rumpf Current UFO Aktuelles UFO Body Rumpf Current Body Aktueller Rumpf &Polars &Polaren Current Polar Aktuelle Polare Graphs Graphen &OpPoint &Arbeitspunkt Current OpPoint Aktueller Arbeitspunkt Current Graph Aktueller Graph UFO UFO Ready Bereit Define Cp Graph Settings (G) Bestimme Cp-Graph Einstellungen (G) All Polar Graph Settings Alle Polaren-Graphen Einstellungen Reset All Polar Graph Scales Alle Polaren Skalierungen zurücksetzen Reset Legend Position (R) Legenden Position zurücksetzen (R) Cl vs. Cd (1) Cl vs. Cd (1) Cl vs.Alpha (2) Cl vs.Alpha (2) Cl vs. Xtr. (3) Cl vs. Xtr. (3) Cm vs.Alpha (4) Cm vs.Alpha (4) Glide ratio vs. alpha (5) Glide ratio vs. alpha (5) Set Style... Gestaltung einrichten... Delete associated polars Lösche zugehörige Polaren Delete all the polars associated to this foil Lösche alle Polaren welche dieser Tragfläche zugehörig sind Show only associated polars Show associated polars Zeige zugehörige Polaren Hide associated polars Verberge zugehörige Polaren Save associated polars Zugehörige Polaren speichern Hide associated OpPoints Verberge zugehörige Arbeitspunkte Show associated OpPoints Zeige zugehörige Arbeitspunkte Delete associated OpPoints Lösche zugehörige Arbeitspunkte Export associated OpPoints Defines a single analysis/polar Definieren einer Analyse/Polare Launches a batch of analysis calculation for a specified range or list of Reynolds numbers Startet Massenanalyse über eine Reynolds-Zahlen Bereich Multi-threaded Batch Analysis Launches a batch of analysis calculation using all available computer CPU cores Delete Löschen Deletes the currently selected polar Löschen der ausgewählten Polare Reset Zurücksetzen Deletes the contents of the currently selected polar Löchen des Inhaltes der ausgewählten Polare Edit Bearbeiten Remove the unconverged or erroneaous points of the currently selected polar Löschen aller unkonvergierten oder fehlerhaften Punkte der ausgewählten Polare Export Exportieren Export all polars Alle Polaren exportieren Define Styles Gestalltung einrichten Define the style for the boundary layer and the pressure arrows Gestalltung der Grenzschicht und der Druck-Pfeile Manage Foils Profile verwalten Rename Umbenennen Show Panels Zeige Paneele Show the foil's panels Zeige die Profil Paneele Reset Foil Scale Profil Skalierung zurücksetzen Resets the foil's scale to original size Profil original Skalierung wiederherstellen Show Inviscid Curve Zeige Inviscid-Kurve Display the Opp's inviscid curve Zeige die Inviscid-Kurve des Arbeitspunktes Neutral Line Neutrale-Linie Show Current Opp Only Zeige nur aktuellen Arbeitspunkt Show All Opps Zeige alle Arbeitspunkte Hide All Opps Ausblenden aller Arbeitspunkte Reset XFoil Xfoil zurücksetzen XFoil Advanced Settings Erweiterte XFoil Einstellungen Tip : you don't want to use that option... Tipp:Glauben Sie uns, Sie wollen diese Option nicht nutzen ;-)... Duplicate Duplizieren Cp Variable Cp Variablen Sets Cp vs. chord graph Cp vs. Sehne (Chord) Graphen Einstellungen Q Variable Q-Variable Sets Speed vs. chord graph Geschwindigkeit(Speed) vs. Sehne(Chord) Graphen Einstellungen Export Cur. XFoil Results Aktuelle XFoil Resultate exportieren Max. Shear Coefficient Maximaler Scherungs (Shear) Koeffizient Bottom Side D* and Theta Unterseiten D* und Theta Top Side D* and Theta Oberseiten D* und Theta Log(Re_Theta) Log(Re_Theta) Re_Theta Re_Theta Amplification Ratio Verstärkungsverhältnis (Amplification Ratio) Dissipation Coefficient Leistungsverlusst Koeffizient (Dissipation Coefficient) Skin Friction Coefficient Aussenhaut -Reibungs-Koeffizient (Skin Friction) Edge Velocity Grenzgeschwindigkeit (Edge Velocity) Kinematic Shape Parameter Kinematischer Form Parameter (Kinematic shape) Import JavaFoil Polar JavaFoil Parameter importiern Import XFoil Polar XFoil Polare importieren &Foil &Profil Foil Actions Profile Aktionen Stability Stabilität OpPoint View Arbeitspunt Ansicht Polar View Polaren Ansicht Shift+F8 Shift+F8 3D View 3D Ansicht Cp View Cp Ansicht &Design &Design Polar Graphs Polar Graphen Operating Points Arbeitspunkte Cp Graph Cp-Graph Current XFoil Results Aktuelle XFoil Resultate Design Operations Design Tätigkeiten Store Foil Profil speichern Store Foil in database Profil in Datenbank speichern Extract Foil Profil entnehmen Extract a Foil from the database for modification Profil aus Datenbank für Änderungen entnehmen Define the styles for this view Gestalltung für diese Ansicht einstellen Resets the scale to fit the screen size Skalierung auf Ansichtsbreite zurücksetzen Insert Control Point Kontrollpunkt einfügen Remove Control Point Kontrollpunkt löschen Show Q-Initial Q-Initial anzeigen Show Q-Spec Q-Spec anzeigen Show Q-Viscous Q-Viscous anzeigen Show Points Punkte anzeigen Show Reflected Zeige reflektierete Zoom X Scale X-Skalierung zoomen Zoom X Scale Only Nur X-Skalierung zoomen Zoom Y Scale Y-Skalierung zoomen &Graph &Graph Full Inverse Voll-Invers Mixed Inverse Gemischt-Invers XInverse XInvers Are you sure you want to delete Löschen von Are you sure you want to delete Löschen von and all associated OpPoints and Polars ? und aller zugehörigen Arbeitspunkte und Polaren? Question Frage Could not read the file File konnte nicht gelesen werden Info Info Save the current project ? Aktuelles Projekt speichern? Text File (*.txt);;Comma Separated Values (*.csv) Text File (*.txt);;Comma Separated Values (*.csv) Open File Datei öffnen Project file (*.wpa) Project file (*.wpa) Warning Warnung XFLR5 file (*.dat *.plr *.wpa) XFLR5 file (*.dat *.plr *.wpa) The project Das Projekt has been saved wurde gespeichert Enter the foil's new name Geben Sie den neuen Profil-Namen ein Default Settings Standardwerte Your system does not provide support for OpenGL. XFLR5 will not operate correctly. Define the save options for operating points Speicherpunkte für Arbeitspunkte festlegen Units... Einheiten... Define the color and font options for all views and graphs Farben und Fonts für alle Graphen More information about XFLR5 Mehr information üner XFLR5 About Qt Über QT Properties Eigenschaften Show the properties of the currently selected polar Eigneschalften der ausgewählten Polaren Reset Scales Skalierungen zurücksetzen Set Table Columns Setze Tabellen Spalten Reset column widths Spaltenbreite zurücksetzen Load background image Lade Hintergrundbild Clear background image Hintergrundbild löschen Options Optionen Switch to the Operating point view Zur Arbeitspunkt Ansicht wechseln Switch to the Polar view Zur Polaren Ansicht wechseln Stability Analysis Stabilitäts Analyse Switch to stability analysis post-processing Zur Analyse post-processing wechseln Root Locus View Switch to root locus view Switch to the 3D view Zur 3D-Ansicht wechseln Switch to the Cp view Zur Cp-Ansicht wechseln Define the style and color preferences for the 3D view Style und Farben für die 3D Ansicht einstellen Define which type of polars should be shown or hidden Welche Polaren sollen angezeigt/versteckt werden Define the scales for the 3D display of lift, moment, drag, and downwash Skalierungen für 3D Ansicht von Auftrieb, Momenten, Widerstand und Downwash Define the light options in 3D view Lichteinstellungen in der 3D Ansicht Half Wing Rename the currently selected object Objekt umbenennen Edit Body... Edit the body of the currently selected plane Rumpf des aktuellen Flugzeuges editieren Export the current plane or wing to a text file in the format required by AVL Exportiere Flugmodell oder Tragfläche als AVL Text File Export the current operating point to a text or csv file Exportiere aktuellen Arbeitspunkt als Text oder CSV File Reset the legend position to its default value Legendenposition zurücksetzen Reset the wing scale to its default value Tragflächenskalierung zurücksetzen Scale the dimensions of the currently selected wing Dimensionen der Tragfläche skalieren Manage objects Objekte verwalten Rename or delete the planes and wings stored in the database Modelle oder Tragflächen in der Datenbank umbenennen oder löschen Import a polar from a text file Polare von Text File importieren Define the inertia for the current plane or wing Trägheitsmomente für aktuelles Modell oder Tragfläche definieren Hide all the curves except for the one corresponding to the currently selected operating point Alle Kurven ausser jene für den aktuellen Arbeitspunkt verbergen Show the graph curves of all operating points Zeige Graphen für alle Arbeitspunkte Hide the graph curves of all operating points Verberge Graphen für alle Arbeitspunkte Delete all the operating points of all planes and polars Lösche alle Arbeitspunkte für alle Modelle und Polaren Show the curves of all the operating points of the currently selected polar Zeige alle Kurven für alle Arbeitspunkte der aktuellen Polare Hide the curves of all the operating points of the currently selected polar Verberge alle Kurven der Arbeitspunkte der aktuellen polare Delete all the operating points of the currently selected polar Lösche alle Arbeitspunkte der aktuellen Polare Show the theoretical optimal elliptic lift curve on all graphs for which the selected variable is the local lift Show XCG location Zeige XCG Position Show the position of the center of gravity defined in the analysis Zeige COG Position in der Analyse Show the graph curves for the elevator Zeige Graphen-Kurve für das Höhenruder Show the graph curves for the fin Zeige Graphen-Kurve für das Seitenruder Show the graph curves for the second wing Zeige Graphen-Kurve für die zweite Tragfläche Define an analysis for the current wing or plane Erstelle eine Analyse für das aktuelle Modell oder Tragfläche Modify the analysis parameters of this polar Define a Stability Analysis Erstelle eine Stabilitäts Analyse Define a stability analysis for the current wing or plane Erstelle eine Stabilitäts Analyse für das aktuelle Modell oder Tragfläche Define Graph Settings Bestimme Graphen Einstellungen Define the settings for the selected graph Einstellungen für aktuellen Graphen Display the first two operating point graphs Zeige die ersten zwei Arbeitspunkte Display all four operating point graphs Zeige alle vier Arbeitspunkte Display only the first graph Zeige nur den ersten Graphen Display only the second graph Zeige nur den zweiten Graphen Display only the third graph Zeige nur den dritten Graphen Display only the fourth graph Zeige nur der vierten Graphen Highlight Current OpPoint Aktuellen Arbeitspunkt hervorheben Highlights on the polar curve the currently selected operating point Reset the scale of the current operating point graph Skalierung des aktuellen Arbeitspunkten-Graphen zurücksetzen Reset the scales of all four operating point graphs Skalierung aller Graphen zurücksetzen Reset the scales of all four polar graphs Skalierung aller Polar-Graphen zurücksetzen Define the settings of all four operating point graphs Einstellungen für alle vier Arbeitspunkt-Graphen Define the settings of all four polar graphs Einstellungen für alle vier Polaren-Graphen Hide all the polar curves associated to the currently selected wing or plane Verberge alle Polar Kurven des aktuellen Modelles oder Tragfläche Show Only Associated Polars Show all the polar curves associated to the currently selected wing or plane Zeige alle Polar-Kurven für aktuelles Modell oder Tragfläche Delete all the polars associated to the currently selected wing or plane Lösche alle Polaren des aktuellen Modelles oder Tragfläche Hide all the polar curves of all wings and planes Verberge alle Polaren für alle Modelle und Tragflächen Show all the polar curves of all wings and planes Zeige alle Polaren von allen Modellen und Tragflächen Hide all the operating point curves of the currently selected wing or plane Verberge alle Arbeitspunkt-Kurven für aktuelles Modell der Tragfläche Show all the operating point curves of the currently selected wing or plane Zeige alle Arbeitspunkt-Kurven für aktuelles Modell der Tragfläche Delete all the operating points of the currently selected wing or plane Lösche alle Arbeitspunkt-Kurven für aktuelles Modell der Tragfläche Delete the currently selected wing or plane Lösche ausgewähltes Modell oder Tragfläche Duplicate the currently selected wing or plane Dupliziere ausgewähltes Modell oder Tragfläche Save the currently selected wing or plane as a new separate project Speichere ausgewähltes Modell oder Tragfläche in ein neues Projekt Rename the currently selected polar Ausgewwählte Polare umbenennen Edit the points of the currently selected polar Punkte der aktuellen Polaren ändern Export the currently selected polar to a text or csv file Exportiere aktuelle Polare als Text oder CSV File Delete all the points of the currently selected polar, but keep the analysis settings Lösche alle Punkte der aktuellen Polare; Einstellunge beibehalten Delete the currently selected polar Lösche die aktuelle Polare Delete the currently selected operating point Lösche den aktuellen Arbeitspunkt Define the settings for LLT, VLM and Panel analysis &Analysis Define an Analysis Analyse definieren Show the properties of the currently selected operating point Cancels the last modification Restores the last cancelled modification Time Response Vew Display the first two graphs Display all four graphs Define Cp Graph Settings Bestimme CP-Graph Einstellungen Two Polar Graphs Zwei Polar-Graphen All Polar Graphs Alle Polar Graphen Cl vs. Cd Cl vs.Alpha Cl vs. Xtr. Cm vs.Alpha Glide ratio vs. alpha Batch Analysis Analysis Analyse Reset foil scale Profil Skalierung zurücksetzen Are you sure you want to delete Sind Sie sicher das Sie löschen wollen Error reading the file Saved the valid part Are you sure you want to reset the default settings ? Wirklich auf die Standardwerte zurücksetzen? The settings will be reset at the next session Die Einstellungen werden beim Neustart zurückgesetzt Nothing to save Nichts zu speichern Save the Project File Projekt File speichern XFLR5 Project File (*.wpa) XFLR5 Project File (*.wpa) Could not open the file for writing Kann Datei zum Schreiben nicht öffnen Save Image Bild speichern Unidentified Operating Point Unbekannter Arbeitspunkt Obsolete format, cannot read Veraltetes Format, lesen nicht möglich XFLR5 v6 Project File (*.wpa);;XFLR5 v5 Project File (*.*) QFLR5 v5.00 Project File (*.wpa);;XFLR5 v4.00 Project File (*.wpa) QFLR5 v5.00 Project File (*.wpa);;XFLR5 v4.00 Project File (*.wpa) A foil of that name already exists Please enter a new name Profil mit diesem Namen existiert schon. Bitte neuen Namen eingeben &%1 %2 &%1 %2 Foil Error : no points Profil Fehler: keine Punkte ManageBodiesDlg Body Management Rumpf Verwaltung New Neu Edit Bearbeiten Rename Umbenennen Delete Löschen Duplicate Duplizieren Export Definition Definition exportieren Export Geometry Geometrie exportieren Close Schließen Description: Beschreibung: The body Der Rumpf is in use by a plane. Delete Anyhow? wird von einem Modell verwendet! Trotzdem löschen? Question Frage Are you sure you want to delete the body : Sind Sie sicher das Sie den Rumpf löschen wollen : The modification will erase all results for the planes using this body. Continue ? Die Änderung löscht alle Resulate für das Modell mit diesem Rumpf. Weitermachen? ManageFoilsDlg Foil Management Profil Verwaltung Delete Löschen Rename Umbenennen Export Foil Profil exportieren Close Schließen Name Name Thickness (%) Dicke(%) at (%) bei (%) Camber (%) Wölbung (%) Points Punkte TE Flap ( T.E.(Hinterkanten) Klappe ( TE XHinge Hinterkaten X-Position der Aufhängung (TE XHinge) TE YHinge Hinterkaten Y-Position der Aufhängung (TE YHinge) LE Flap ( L.E (Vorderkanten) Klappe ( LE XHinge Vorderkaten X-Position der Aufhängung (LE XHinge) LE YHinge Vorderkaten Y-Position der Aufhängung (LE YHinge) Foils Profile Foil File (*.dat) Profil File (*.dat) ManageUFOsDlg UFO Management UFO Verwaltung Delete Löschen Rename Umbenennen Close Schließen Description: Beschreibung: Name Name Wing Span Trangflächen-Spannweite Object Management Span Area Fläche M.A.C. AR Streckung (AR) TR Aufweitungsverhältnis (TR) Rt-Tip Sweep Wurzel-Spitzen Rückfall (Root-Tip Sweep) Tail Volume Heck-Volumen UFOs UFOs Are you sure you want to delete the plane : Sind Sie sicher das Sie das Modell löschen wollen: Are you sure you want to delete the wing : Sind Sie sicher das sie die Tragfläche löschen wollen: Question Frage ManualInertiaDlg Cancel Abbrechen ModDlg Modification Modifikation OK OK Cancel Abbrechen Save as new Als Neu speichern NacaFoilDlg NACA Foils NACA Profile 4 or 5 digits 4 oder 5 Stellen Number of Panels Anzahl der Panels OK Ok Cancel Abbrechen Illegal NACA Number Ungültige NACA Nummer NewNameDlg OK OK Cancel Abbrechen ObjectPropsDlg OK Polar Properties Polar Eigenschaften Operating Point Properties PanelAnalysisDlg 3D Panel Analysis 3D Panel Analyse Warning Warnung The number of points to be calculated will be limited to 100 Die Anzahl der Punkte die berechnet werden sind auf 100 limitiert Solving the problem... Löse das Problem... Failed to create the matrix.... Matrix konnte nicht erstellt werden.... Failed to create RHS Vector.... RHS Vektor konnte nicht erstellt werden.... Failed to add the wake contribution.... Wirbelbeitrag konnte nicht hinzugefügt werden.... Singular matrix - aborting.... Ainguläre Matrix...abbruch.... Failed to compute aerodynamics.... Konnte Aerodynamik nicht berechnen.... Creating the influence matrix... Erstelle die Einfluß-Matrix... Creating RHS vector... Erzeuge RHS Vektor... Adding the wake's contribution... Füge den Wirbelbeitrag hinzu.... Found a negative lift for Alpha=%1.... skipping the angle... Computing On-Body Speeds... Berechne Am-Körper Geschwindigkeiten... Calculating speeds to balance the weight Berechne Geschwindigkeit um Gewicht auszugleichen Found a negative lift for Alpha=%1.... skipping the angle... Negativer Auftrieb für Alpha=%1 .... überspringe den Winkel... Computing Plane for alpha=%1 Berechne Plane für alpha=%1 Computing Plane for QInf=%1 Berechne Plane für QInf=%1 Calculating aerodynamic coefficients... Berechen Aerodynamische Koeffizienten... Calculating wing... Berechne Tragfläche... Calculating second wing... Berechne 2. Tragfläche... Calculating elevator... Berechne Höhenruder... Calculating fin... Berechne Seitenruder... Calculating wing... Calculating body... Berechne Rumpf... Main wing is asymmetric Tragfläche ist asymmetrisch Sideslip is asymmetric Drift ist asymmetrisch 2nd wing is asymmetric 2. Tragfläche ist asymmetrisch Elevator is asymmetric Höhenruder ist asymmetrisch A fin is considered asymmetric Ein Seitenruder wird als asymmetrisch angenommen Creating source strengths... Calculating aerodynamic coefficients in the far field plane Calculating point Perfoming symmetric calculation Führe symmetrie Berechnungen aus Performing symmetric calculation Performing asymmetric calculation : Führe symmetrie Berechnungen aus: Counted %1 panel elements %1 Panel Elemente wurden gezählt Relaxing the wake... Entspanne den Wirbel... Singular Matrix.... Aborting calculation... Type 1 - Fixed speed polar Type 1 (Fixe Geschwindigkeit) Type 2 - Fixed lift polar Type 2 (Fixer Auftrieb) Type 4 - Fixed angle of attack polar Type 4 - Fixer AoA Type 7 - Stability polar Type 7 - Stabilitäts Polare Failed to create matrix.... Matrix konnte nicht erstellt werden.... Calculating induced angles... Berechne induzierte Anstellwinkel... Cancel Abbrechen Solving the linear system... Löse das lineare Gleichungssystem... Singular Matrix.... Aborting calculation... Ainguläre Matrix...abbruch.... Launching 3D Panel Analysis.... Starte 3D Panel Analyse.... Launching VLM1 Analysis.... Starte VLM1 Analayse Launching VLM2 Analysis.... Starte VLM2 Analyse Using Dirichlet boundary conditions Verwende Dirichlet Randbedingungen Using Neumann boundary conditions Verwende Neumann Randbedingungen Warning: The wing and elevator lie in the same plane z= Warnung: Tragfläche und Höhenruder liegen in der selben Ebene z= It is recommended to slightly offset the wing or the elevator to avoid numerical instabilities Es wird empfohlen Tragfläche und Höhenruder leicht zu versetzen (Numerische Stabilität) Type %1 Analysis Analyse Methode Panel Analysis completed successfully Panel Analyse erfolgreich abgeschlossen Panel Analysis completed ... Errors encountered Panel Analyse abgeschlossen...Fehler wurden festgestellt Close Schließen Processing Alpha= %1 Verarbeite Alpha=%1 Wake iteration %1 Wirbel Iteration %1 Failed to compute aerodynamic coefficients.... Konnte Aerodynamik Koeffizienten nicht berechnen.... PertDlg Pertubation Dialog Störungs Dialog Restore Wiederherstellen Apply Anwenden OK Ok Cancel Abbrechen Cn List Cn Liste PlaneDlg Plane Editor Flugzeug Editor Total number of VLM panels =%1 Max Number =%2 A reduction of the number of VLM panels is required Gesamtzahl der VLM Panele=%1 Maximale Anzahl=%2 Panels müssen reduziert werden Warning Warnung Total number of wing panels =%1 Max Number =%2 A reduction of the number of wing panels is required Gesamtzahl der Flügel Panele = %1 Maximalzahl = %2 Bitte reduzieren Sie die Anzahl Save the changes ? Änderungen speichern? Question Frage Plane Name Flugzeugname Enter here a short description for the plane Geben Sie eine Beschreibung für das Flugzeug an Description: Beschreibung: Plane Inertia Flugzeug Trägheit Plane Description Flugzeug Beschreibung Define Definiere Import Importieren Export Exportieren x= z= Tilt Angle= Main Wing Haupt-Tragfläche Biplane Doppeldecker Wing 2 Tragfläche 2 Elevator Höhenruder Fin Seitenruder Double Fin Doppeltes Seitenruder Two-sided Fin Zweiseitiges Seitenruder y= Body Rumpf Warning: Including the body in the analysis is not recommended. Check the guidelines for explanations. Edit... Bearbeiten... Wing Area = Flügel Fläche= Wing Span = Trangflächen-Spannweite = Elev. Area = Höhenruder Fläche = Elev. Lever Arm = Höhenruder Hebelarm = Fin Area = Seitenruderfläche = TailVolume = Total Panels = Gesamtzahl der Panels = OK Ok Cancel Abbrechen PolarFilterDlg Polar Filter Polaren Filter Show polar types Zeige Polaren Typen Type 1 Type 1 Type 2 Type 2 Type 3 Type 3 Type 4 Type 4 Type 5 Type 5 Type 6 Type 6 Type 7 Type 7 OK Ok Cancel Abbrechen PolarPropsDlg Polar Properties Polar Eigenschaften OK OK Analysis Type Analyse Methode Alpha Alpha NCrit NCrit ProgressDlg Progress Vortschritt Cancel Abbrechen QAFoil Spline foil Spline Profil Foil has been de-rotated by %1 degrees Profil wurde um %1 Grad entdreht Foil has been normalized from %1 to 1.000 Profile wurde von %1 auf 1000 normalisiert Warning Warnung At least two foils are required Es werden mind.zwei Profile benötigt Export Foil Profil exportieren Foil File (*.dat) Profil File (*.dat) Spline Foil Spline Profil Too many output points on upper surface Max =%1 Zuviele Punkte auf der Oberseite Max = %1 Too many output points on lower surface Max =%1 Zu viele Punkte auf der Unterseite Max = %1 Export Splines Splines exportieren Text File (*.dat) Text Datei (*.dat) X-Scale = %1 X-Skalierung = %1 Y-Scale = %1 Y-Skalierung = %1 x = %1 y = %1 Open Image File Öffne Bilddatei The minimum number of control points has been reached for this spline degree Question Frage Discard changes to Splines ? Änderungen verwerfen? Show Foil Profil anzeigen Show Centerline Mittenlinie anzeigen Show Points Punkte anzeigen Rename Umbenennen Delete Löschen Duplicate Duplizieren Export Exportieren Design... Design... Splines Splines Splined points Splined Punkte Name Name Thickness (%) Dicke(%) at (%) bei (%) Camber (%) Wölbung (%) Points Punkte TE Flap ( T.E.(Hinterkanten) Klappe ( TE XHinge Hinterkaten X-Position der Aufhängung (TE XHinge) TE YHinge Hinterkaten Y-Position der Aufhängung (TE YHinge) LE Flap ( L.E (Vorderkanten) Klappe ( LE XHinge Vorderkaten X-Position der Aufhängung (LE XHinge) LE YHinge Vorderkaten Y-Position der Aufhängung (LE YHinge) Show Anzeigen Centerline Mittenlinie Style Style Foils Profile QMiarex Cd Cd Cl Cl Alpha Alpha Cn Cn VCn VCn ICn ICn Cl/Cd Cl/Cd x x Cp Cp Real Real Imag/2.pi Warning Warnung Not enough memory to store the OpPoint Nicht genug Speicher um Arbeitspunkt zu speichern Wing2_ Wing2_ Elevator_ Elevator_ Fin_ Fin_ The modification will erase all results associated to this Plane. Continue ? Die Änderung löscht alle Resulate für das Modell. Weitermachen? Induced Angle Induzierter Winkel (induced angle) Total Angle Gesamter Winkel Local lift Lokaler Auftrieb (local lift) Airfoil drag Profilwiderstand (foil drag) Induced drag Induzierter Widerstand (induced drag) Total drag Gesamtwiderstand (total drag) Local drag Lokaler Widerstand (local drag) Cm Airfoil Cm Profil Cm Cm Cm total Re Re Top Trans x-Pos % Umschlagspunkt Oben (Top Trans x-Pos) % Bot Trans x-Pos % Umschlagspunkt unten (Bot Trans x-Pos ) % CP x-Pos % CP x-Pos % BM ( BM ( Wing Span = %1 Spannweite = %1 XYProj. Span = %1 Projezierte Spannweite in XY = %1 Wing Area = %1 Tragflächeninhalt = %1 XYProj. Area = %1 Projezierter Tragflächeninhalt in XY = %1 Plane Weight = %1 Modellgewicht =%1 Wing Load = %1 Tragflächenbelastung =%1 Tail Volume = %1 Heck-Volumen = %1 Root Chord = %1 Wurzel-Profiltiefe =%1 M.A.C. = %1 M.A.C. = %1 Tip Twist = %1 Verwindung bei Spitze (Tip-Twist) =%1 Aspect Ratio = %1 Streckung =%1 Taper Ratio = %1 Aufweitungsverhältnis (TR) =%1 Root-Tip Sweep = %1 Wurzel-Spitzen Rückfall (Root-Tip Sweep)=%1 Point is out of the flight envelope Punkte sind ausserhalb des Flugleistungsbereichs QInf = %1 QInf = %1 Alpha = %1 Alpha = %1 CL = %1 CL = %1 CD = %1 CD = %1 Efficiency = %1 Effizienz =%1 Cl/Cd = %1 Cl/Cd = %1 GCm = %1 GCm = %1 Rolling Moment = %1 Rollmoment = %1 Induced Moment = %1 Induziertes Momement = %1 Airfoil Yawing Moment = %1 Giermoment = %1 XCP = %1 XCP = %1 Flap Moment[%1] = %2 Klappen Moment[%1] = %2 Creating Elements... please Wait Erzeuge Elemente...bitte warten The total number of panels is %1 The Max Number is %2 A reduction of the number of panels is required Die Gesamtzahl der Paneele ist %1 Die Maximalzahl ist %2 Reduzieren sie die Anzahl der Paneele Please define a wing or a plane object before running a calculation Bitte definieren Sie eine Tragfläche oder ein Modell bevor Sie die Berechnung durchführen Please define an analysis/polar before running a calculation Bitte definieren Sie eine Analyse/Polare bevor Sie eine Berechnung durchführen Could not find the wing's foil Kann das Profil der Tragfläche nicht finden :-( ... Aborting Calculation ... Berechnung wurde abgebrochen Could not find the elevator's foil Kann das Profil des Höhenruders nicht finden Could not find the fin's foil Kann das Profil des Seitenruders nicht finden Control polars are not supported in XFLR5 v6. Please use stability polars instead. Are you sure you want to delete the plane : Sind Sie sicher das Sie das Modell löschen wollen: Are you sure you want to delete the wing : Sind Sie sicher das sie die Tragfläche löschen wollen: Question Frage Are you sure you want to delete the polar : Sind Sie sicher das Sie die Polare löschen wollen : The modification will erase all results for the planes using this body. Continue ? Die Änderung löscht alle Resulate für das Modell mit diesem Rumpf. Weitermachen? The modification will erase all results associated to this Wing. Continue ? Die Änderung löscht alle Resulate für diese Tragfläche. Weitermachen? Export Wing OpPoint Arbeitspunkt der Tragfläche exportieren Text File (*.txt);;Comma Separated Values (*.csv) Text File (*.txt);;Comma Separated Values (*.csv) QInf = QInf = Alpha = Alpha = Cl = Cl = Cy = Cy = Cd = %1 ICd = %2 PCd = %3 Cd = %1 ICd = %2 PCd = %3 Cd=,%1,ICd=, %2,PCd=, %3 Cd=,%1,ICd=, %2,PCd=, %3 GCm = GCm = GRm = GRm = IYm = %1 PYm = %2 IYm = %1 PYm = %2 IYm=, %1,PYm=, %2 IYm=, %1,PYm=, %2 XCP = %1 YCP = %2 XCP = %1 YCP = %2 XCP=, %1, YCP=, %2 XCP=, %1, YCP=, %2 Bend. = Bend. = Main Wing Data Haupt-Tragflächen Daten Flap Klappe moment = Moment = Export Polar Polare exportieren Open File Datei öffnen UFO Polar Format (*.*) UFO Polar Format (*.*) Could not read the file File konnte nicht gelesen werden No UFO with the name Kein UFO mit diesem Namen could be found. The polar(s) will not be stored kann nicht gefunden werden. Die Polare(n) werden nicht gespeichert Enter the new name for the wing polar : Geben Sie einen neuen Namen für die Polare der Tragfläche an: Are you sure you want to reset the content of the polar : Sind Sie sicher das Sie den Inhalt der Polare zurücksetzen wollen: abcdefghijklmnopqrstuvwxyz012345678 abcdefghijklmnopqrstuvwxyz012345678 Wing Span = %1 Spannweite = %1 xyProj. Span = %1 Projezierte Spannweite in XY = %1 Wing Area = %1 Tragflächeninhalt = %1 xyProj. Area = %1 Projezierter Tragflächeninhalt in XY = %1 Plane Weight = %1 Modellgewicht =%1 Wing Load = %1 Tragflächenbelastung =%1 Tail Volume = %1 Heck-Volumen = %1 Root Chord = %1 Wurzel-Profiltiefe =%1 MAC = %1 M.A.C. = %1 TipTwist = %1 deg Verwindung bei Spitze (Tip-Twist) =%1 Highlight OpPoint OpPoints hervorheben Aspect Ratio = %1 Streckung =%1 Wing Graph 1 Trangflächen Graph 1 Wing Graph 2 Trangflächen Graph 2 Wing Graph 3 Trangflächen Graph 3 Wing Graph 4 Trangflächen Graph 4 Wing Polar Graph 1 Tragflächen Polar Graph 1 Wing Polar Graph 2 Tragflächen Polar Graph 2 Wing Polar Graph 3 Tragflächen Polar Graph 3 Wing Polar Graph 4 Tragflächen Polar Graph 4 Cp Graph Cp-Graph Wing Span = %1 Spannweite = %1 XYProj. Span = %1 Projezierte Spannweite in XY = %1 Wing Area = %1 Tragflächeninhalt = %1 XYProj. Area = %1 Projezierter Tragflächeninhalt in XY = %1 Plane Mass = %1 Modellgewicht =%1 Wing Load = %1 Tragflächenbelastung =%1 Tail Volume = %1 Heck-Volumen = %1 Root Chord = %1 Wurzel-Profiltiefe =%1 M.A.C. = %1 M.A.C. = %1 Tip Twist = %1 Verwindung bei Spitze (Tip-Twist) =%1 Taper Ratio = %1 Aufweitungsverhältnis (TR) =%1 Root-Tip Sweep = %1 Wurzel-Spitzen Rückfall (Root-Tip Sweep)=%1 Are you sure you want to delete the plane's polars? Sind Sie sicher das Sie die Polaren und die Arbeitspunkte löschen wollen Are you sure you want to delete the wing's polars? Sind Sie sicher das Sie die Polaren und die Arbeitspunkte löschen wollen Secondary Wing Data Zeige 2. Trangflächen Kurve Elevator Data Höhenruder Daten Fin Data Seitenruder Daten Main Wing Cp Coefficients Haupttragflächen Cp-Koeffizienten Wing Cp Coefficients Tragflächen Cp-Koeffizienten Panel CtrlPt.x CtrlPt.y CtrlPt.z Cp Panel,CtrlPt.x,CtrlPt.y,CtrlPt.z,Cp Strip %1 Wing2 Cp Coefficients 2.Tragflächen Cp-Koeffizienten Elevator Cp Coefficients Höhenruder Cp-Koeffizienten Fin Cp Coefficients Seitenruder Cp-Koeffizienten Export UFO UFO Exportieren AVL Text File (*.avl) UFO Polar Format (*.*) Project Projekt Taper Ratio = %1 Aufweitungsverhältnis (TR) =%1 Root-Tip Sweep = %1 deg Wurzel-Spitzen Rückfall (Root-Tip Sweep)=%1 abcdefghijklmnopqrstuvwxyz01234567 abcdefghijklmnopqrstuvwxyz01234567 xyProj. Span = %1 Projezierte Spannweite in XY = %1 xyProj. Area = %1 Projezierter Tragflächeninhalt in XY = %1 MAC = %1 M.A.C. = %1 The polar already exists Die Polare existiert bereits Are you sure you want to delete the polars associated to : Sind Sie sicher das Sie die Polaren löschen wollen: Cl = Cm = ICn = %1 PCn = %2 ICn=, %1,PCn=, %2 Cp Coefficients Cp Koeffizienten The modification will erase all polar results associated to this Plane. Continue ? Die Änderung löscht alle Polaren Resulate für das Modell. Weitermachen? V = %1 No unit defined for speed... Keine Einheit für Geschwindigkeit defoniert... Lift Coef. = %1 Auftriebskoeffizient =%1 Drag Coef. = %1 Widerstandskoeffizient = %1 Rolling Moment Coef. = %1 Rollmoment Koeffizient = %1 Induced Moment Coef = %1 Induzierter Momementen Koeffizient = %1 Profile Yawing Moment = %1 Giermoment Koeffizient = %1 Flap %1 Moment =%2 Klappen %1 Moment = %2 Top transition Oberer Umschlagspunkt Bottom transition Unterer Umschlagspunkt Centre of Pressure Druckpunkt (Center of Pressure) Moment ref. location Momenten Referenz Punkt (moment ref location) _Wing _Wing _Wing2 _Wing2 _Elev _Elev _Fin _Fin Enter the new name for the Body : Geben Sie einen neuen Namen für den Rumpf ein: The body Der Rumpf is used by one or more planes. Overwrite anyway ? (Results will be lost) wird von einem oder mehr Modellen verwendet. Trotzdem überschreiben? (Resultate gehen verloren) Enter the new name for the Plane : Geben Sie einen neuen Namen für das Modell ein: Enter the new name for the wing : Geben Sie einen Namen für die Tragfläche ein: Cannot overwrite current plane Kann aktuelles Modell nicht überschreiben Sequence Sequenz Start= Start= End= Ende= D= D= Init LLT Initialisiere LLT Store OpPoint Arbeitspunkte speichern Analyze Analysiere Analysis settings Analyse Einstellungen 1/2 wing 1/2 Tragfläche Lift Auftrieb Ind. Drag Induzierter Widerstand (induced drag) Visc. Drag Reibungswiderstand Trans. Übergang. Moment Moment Downw. Abwind. Surf. Vel. Oberflächengeschwindigkeit. Stream Strömung Animate Animation Display Darstellung X View Y View Z View Iso View Pitching Moment Kippmoment Rolling Moment Rollmoment Yawing Moment Giermoment Curve Kurve Points Punkte item Gegenstand Style Gestalltung Width Breite Color Farbe Curve settings Kurven Einstellung Span Position Spanten Position Keep Erhalten Reset Zurücksetzen Cp Sections Cp Abschnitte Wing Span = Trangflächen-Spannweite = Current Plane Current Wing Current Object Time = Zeit = Cp Coefficients xyProj. Span = Projezierte Spannweite = Wing Area = Flügel Fläche= xyProj. Area = Projezierter Tragflächeninhalt = Plane Mass = Flugzeugmasse= Wing Load = Tragflächenbelastung = Tail Volume = Heck-Volumen = Root Chord = Wurzel-Profiltiefe = MAC = TipTwist = Flügelspitzen Verwindung = Aspect Ratio = Streckungs Verhältnis = Taper Ratio = Aufweitungsverhältnis = Root-Tip Sweep = Wurzel-Spitzen Rückfall (Root-Tip Sweep) = Enter the new name for the Polar: Panel Forces Display the force 1/2.rho.V2.S.Cp acting on the panel Results Polar properties Polar Eigenschaften Axes Axen Light Licht Surfaces Oberflächen Outline Kontur Panels Paneele Foil Names Profil Namen Vortices Wirbel Masses Pick Center Zentrum auswählen Activate the button, then click on the object to center it in the viewport; alternatively, double click on the object Doppelklick auf das Objekt um es zu zentrieren Clip: Abschneiden: VCd VCd ICd ICd VYm VYm IYm IYm Cl^(3/2)/Cd Cl^(3/2)/Cd 1/Rt(Cl) 1/Rt(Cl) Lift (N) Auftrieb (N) Lift (lbf) Auftrieb (lbf) Drag (N) Widerstand (N) Drag (lbf) Widerstand (lbf) Vx Vx Vz Vz V V Gamma Gamma PM PM RM RM YM YM XCP XCP YCP YCP BM BM m.g.Vz (W) m.g.Vz (W) Efficiency Effizienz (XCp-XCG)/MAC(%) (XCp-XCG)/MAC(%) ctrl ctrl CY CY OpenGL color format is not recognized... Sorry Cannot (yet ?) save 8 bit depth opengl screen images... Sorry Kann 8bit OpenGL Bilder nicht speichern...Sorry Cannot (yet ?) save 16 bit depth opengl screen images... Sorry Kann 16bit OpenGL Bilder nicht speichern...Sorry Unidentified bit depth... Sorry Undefinierte Farbtiefe...Sorry QObject dihedral V-Form twist Verwindung foil Profil X-panels X-Paneele X-dist X-Abstand Y-panels Y-Paneele Y-dist Y-Abstand Wing definition Tragflächen Definition Foil coordinates Profil-Koordinaten X X Y Y Re Re Mach Mach CL CD Cm Cm Cdp Cdp Cpmn XCP Top Transition Bot Transition T.E. Flap moment L.E. Flap moment Type Type Fixed speed Fixe Geschwindigkeit Fixed lift Fixer Auftrieb Fixed angle of attack Fixer Anstelwinkel Reynolds number Reynolds Zahl Mach number Mach Zahl Re.Cl Cd Cd Cd x 10000 Cd x 10000 Xtr1 Xtr1 Xtr2 Xtr2 HMom HMom Cpmin Cpmin Cl/Cd Cl/Cd |Cl|^(3/2)/Cd |Cl|^(3/2)/Cd 1/Rt(Cl) 1/Rt(Cl) XCp XCp Alpha Alpha NCrit NCrit Forced top trans. Erzwungener Umschlag Oben Forced bottom trans. Erzwungener Umschlag Unten Number of data points Anzahl der Datenpunkte Re List Re Liste i i Cn Cn Ci Ci Wing Tragfläche 2nd Wing Tragfläche 2 Elevator Höhenruder Fin Seitenruder Plane Name Flugzeugname Splined Points Foil Splined Punkte Profil Spline Foil Spline Profil CpCalc: local speed too larger Compressibility corrections invalid Calculating unit vorticity distributions ... Warning: High does not work well on rotated foils Current chordline angle: %1 proceeding anyway... The max number of polar points has been reached Maximale Anzahl von Polar-Punkten wurde erreicht BodyName Rupf-Name Body Name Export Body Definition Rupfdefinition exportieren Text Format (*.txt) UFO Polar Format (*.*) Export Body Geometry Text File (*.txt);;Comma Separated Values (*.csv) Text File (*.txt);;Comma Separated Values (*.csv) Choose the length unit to read this file : Wählen Sie die Längeneinheit um diese Datei zu lesen: Open File Datei öffnen All files (*.*) Text file (*.txt) UFO Polar Format (*.*) Could not read the file File konnte nicht gelesen werden Warning Warnung Multiple file loading only available for airfoil files. Non *.dat files will be ignored. Error reading Fehler beim Lesen Frames have different number of side points Rahmen haben unteschiedliche Anzahl von Seitenpunkten Error Fehler Please select a Frame before inserting a point Bitte wählen Sie einen Rahmen bevor Sie einen Punkt einfügen Stability analysis Stabilitäts Analyse VInf = Alpha = Method Methode LLT LLT 3D-Panels 3D-Panels/VLM1 3D-Panels/VLM2 VInf Mass Masse Control value XNP YCP ZCP VCD ICD CX CY CY Cl Cl ICm VCm ICn ICn VCn VCn Non-dimensional Stability Derivatives: CXu CLu Cmu CXa CLa Cma CXq CLq Cmq CYb Clb Cnb CYp Clp Cnp CYr Clr Cnr Non-dimensional Control Derivatives: CXd CYd CZd Cld Cmd Cnd CL/CD CL^(3/2)/CD 1/Rt(CL) Fx (N) Fx (lbf) Fy (N) Fy (lbf) Fz (N) Fz (lbf) Vx Vx Vz Vz V V Gamma Gamma Pitching Moment Kippmoment Rolling Moment Rollmoment Yawing Moment Giermoment XCP XCP YCP YCP ZCP BM BM m.g.Vz (W) m.g.Vz (W) Efficiency Effizienz ctrl ctrl Ph. Freq(Hz) Ph. Damping SP Freq (Hz) SP Damping DR Freq(Hz) DR Damping Roll Damping Spiral Damping CoG.x CoG.z B.C. = Dirichlet B.C. = Neumann Analysis type Analyse Methode Viscous Reibung Inviscid Reibungslos Body option Body Panels Ignored Ref. Area = Data points Datenpunkte Beta Planform area Grundform Fläche Projected area Projizierte Fläche Tilted geometry Verdrehte Geometrie Ground height Höhe über Grund Density = Dichte = Viscosity = Reibung = iblpan : *** bl array overflow Increase IVX to at least %1 *** iblsys: bl system array overflow. *** Unrecognized foil format Unbekannts Profil Format ... Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid ...Ungültige Analyse Einstellungen CpCalc: lokale Geschwindigkeit zu groß Kompressions-Korrekturen ungültig mrchdu: convergence failed at %1 , side %2, res =%3 Side %1 ... mrchue: inverse mode at %1 hk =%2 mrchue: convergence failed at %1, side %2, res = %3 mrcl: illegal Re(cls) dependence trigger, Setting fixed Re mrcl: illegal Mach(cls) dependence trigger Setting fixed Mach mrcl: Cl too low for chosen Mach(Cl) dependence artificially limiting mach to 0.99 mrcl: cl too low for chosen Re(Cl) dependence artificially limiting Re to %1 PanGen: buffer airfoil not available. Paneling convergence failed. Continuing anyway... Panel: Too many panels. Increase IQX Calculating source influence matrix ... Initializing bl ... Side %1, forced transition at x/c = %2 %3 Side %1, free transition at x/c = %2 %3 scheck: bad value for small panels (stol > 0.3) setexp: cannot fill array. n too small Setexp: Convergence failed. Continuing anyway ... Sinvrt: spline inversion failed, input value returned Specal: MInf convergence failed Speccl: cl convergence failed splind: array overflow, increase nmax stfind: Stagnation point not found. Continuing ... trchek2 - n2 convergence failed *** stagnation point is past trip on side %1 Calculating wake trajectory ... XYWake: array size (IWX) too small. Last wake point index reduced. Description %1 Beschreibung %1 Wing Name Tragflächen Name Could not open the file for reading Total number of wing sections exceeds MAXSPANSECTIONS. Wing will be truncated. Unable to import wing definition Could not open the file for writing Kann Datei zum Schreiben nicht öffnen Span pos = %1 Span pos = %1 , A+Ai+Twist = %1 could not be interpolated , A+Ai+Twist = %1 is outside the flight envelope , Cl = %1 could not be interpolated , Cl = %1 is outside the flight envelope setbl: xtr??? n1=%1 n2=%2: Wing Span = %1 Spannweite = %1 XYProj. Span = %1 Projezierte Spannweite in XY = %1 X_CG = %1 Wing Area = %1 Tragflächeninhalt = %1 XYProj. Area = %1 Projezierter Tragflächeninhalt in XY = %1 Plane Mass = %1 Modell Masse = %1 Wing Load = %1 Tragflächenbelastung =%1 Tail Volume = %1 Heck-Volumen = %1 Root Chord = %1 Wurzel-Profiltiefe =%1 M.A.C. = %1 M.A.C. = %1 Tip Twist = %1 Verwindung bei Spitze (Tip-Twist) =%1 Aspect Ratio = %1 Streckung =%1 Taper Ratio = %1 Aufweitungsverhältnis (TR) =%1 Root-Tip Sweep = %1 Wurzel-Spitzen Rückfall (Root-Tip Sweep)=%1 Control position = %1 Kontrollpunkt Position = %1 Angle of Attack = %1 Anstellwinkel (aoa) =%1 Sideslip = %1 Slip = %1 Speed = %1 Geschwindigkeit = %1 mesh panels V = %1 Alpha = %1 Alpha = %1 Sideslip = %1 Bank = %1 Control pos. = %1 CL/CD = %1 Cl = %1 Cl = %1 Cm = %1 Cn = %1 X_NP = %1 X_CP = %1 X_CG = %1 Point is out of the flight envelope Punkte sind ausserhalb des Flugleistungsbereichs QInf = %1 QInf = %1 Alpha = %1 Alpha = %1 CL = %1 CL = %1 CD = %1 CD = %1 Efficiency = %1 Effizienz =%1 Cl/Cd = %1 Cl/Cd = %1 GCm = %1 GCm = %1 Rolling Moment = %1 Rollmoment = %1 Induced Moment = %1 Induziertes Momement = %1 Airfoil Yawing Moment = %1 Giermoment = %1 XCP = %1 XCP = %1 Flap Moment[%1] = %2 Klappen Moment[%1] = %2 Point Punkt x x y Upper side points Lower side points Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid Ungültige Analyse Einstellungen\nCpCalc: Lokale Geschwindigkeit zu groß!\nKorrekturen ungültig Cl = %1 Cl = %1 ...converged after %1 iterations ...Konvergenz nach %1 Iterationen ...unconverged after %1 iterations ... keine Konvergenz nach %1 Iterationen Continuous foils for surface do not have the same initial flap angle... aborting QXDirect Cp Cp Q Q Not enough threads available for multithreading Warning Warnung Unrecognized foil format Unbekannts Profil Format ... Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid ...Ungültige Analyse Einstellungen CpCalc: lokale Geschwindigkeit zu groß Kompressions-Korrekturen ungültig Top Oben Bot Unten Max Shear Maximale Scherung Top Shear Obere Scherung Top Shear eq Obere Scherung eq Bot Shear Untere Scherung Bot Shear eq Untere Scherung eq Are you sure you want to delete the Operating Point Sind Sie sicher das Sie den Arbeitspunkt löschen wollen X X Cp Graph Cp-Graph Polar Graph Polar Graphen Cm Graph Cz Graph Tr Graph User Graph ... Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid ...Ungültige Analyse Einstellungen CpCalc: lokale Geschwindigkeit zu groß Kompressions-Korrekturen ungültig Cf Cd' Are you sure you want to delete the Operating Point Sind Sie sicher das Sie den Arbeitspunkt löschen wollen Question Frage Are you sure you want to delete the polar : Sind Sie sicher das Sie die Polare : and all the associated OpPoints ? und alle Arbeitspunkte löschen wollen? Are you sure you want to delete polars and OpPoints Sind Sie sicher das Sie die Polaren und die Arbeitspunkte löschen wollen associated to zugehörig zu The foil has been de-rotated by %1 degrees Das Profile wurde entdreht um %1 Grad Export Current XFoil Results Aktuelle XFoil Resultate exportieren Text File (*.txt);;Comma Separated Values (*.csv) Text File (*.txt);;Comma Separated Values (*.csv) Top Side x Hk Ue/Vinf Cf Cd A/A0 D* Theta CTq x,Hk,Ue/Vinf,Cf,Cd,A/A0,D*,Theta,CTq Bottom Side Export Directory Export Foil Profil exportieren Foil File (*.dat) Profil File (*.dat) Export OpPoint Arbeitspunkt exportieren Export Polar Polare exportieren Open File Datei öffnen XFoil Polar Format (*.*) UFO Polar Format (*.*) Could not read the file File konnte nicht gelesen werden No Foil with the name Kein Profil mit diesem Namen could be found. The polar(s) will not be stored Die Polare(n) wird nicht gespeichert Error reading at line xx. The polar(s) will not be stored Fehler beim Lesen in Zeile xx. Die Polare(b) wird nicht gespeichert JavaFoil Polar Format (*.*) JavaFoil Polar Format (*.*) At least two foils are required Es werden mind.zwei Profile benötigt The foil has been normalized from %1 to 1.000 Das Profil wurde normalisiert von %1 auf 1.000 Enter the new name for the foil polar : Geben Sie einen neuen Namen für die Polare der Tragfläche an: Polar File Polaren Datei Polar File (*.plr) Polar File (*.plr) Thickness = %1 Dicke =%1 Max.Thick.pos. = %1 Position der maximalen Dicke =%1 Max. Camber = %1 Maximale Wölbung =%1 Number of Panels = %1 Anzahl der Paneele = %1 Thickness = %1 Dicke =%1 Max. Thick.pos. = %1 Position der maximalen Dicke =%1 Max. Camber = %1 Maximale Wölbung =%1 Max. Camber pos. = %1 Position maximale Wölbung =%1 Number of Panels = %1 Anzahl der Paneele = %1 Flap Angle = %1 Klappen Winkel = %1 XHinge = %1 X-Anschlag =%1 YHinge = %1 Y-Anschlag =%1 TE Hinge Moment/span = 123456789 TE Hinge Moment/span = 123456789 Polar Type = %1 Polar Typ = %1 Re.sqrt(Cl) = Re sqrt(Cl)= M.sqrt(Cl) = %1 Forced Upper Trans. = %1 Erzwungener oberer Umschlag = %1 Forced Lower Trans. = %1 Erzwungener unterer Umschlag = %1 Alpha = %1 Alpha = %1 Cl = %1 Cl = %1 Cm = %1 Cm = %1 Cd = %1 Cd = %1 L/D = %1 L/D = %1 Upper Trans. = %1 Oberer Umschlag = %1 Lower Trans. = %1 Unterer Umschlag = %1 TE Hinge Moment/span = %1 TE Hinge Moment/span = %1 LE Hinge Moment/span = %1 LE Hinge Moment/span = %1 Alpha Alpha Cl Cl Cd Cd Cd x 10000 Cd x 10000 Cdp Cdp Cm Cm Xtr1 Xtr1 Xtr2 Xtr2 HMom HMom Cpmin Cpmin Cl/Cd Cl/Cd |Cl|^(3/2)/Cd |Cl|^(3/2)/Cd 1/Rt(Cl) 1/Rt(Cl) Re Re XCp XCp Sequence Sequenz Start= Start= End= Ende= D= D= Viscous Reibung Init BL Grenzschicht initialisieren Store Opp Arbeit speichern Analyze analysieren Analysis settings Analyse Einstellungen Show BL Grenzschicht anzeigen Show Pressure Druck anzeigen Highlight Current OpPoint Aktuellen Arbeitspunkt hervorheben Highlights the currently selected OpPoint, if any, on the currently selected polar curve Hebt den aktuellen OpPoint hervor Animate Animation Display Darstellung Polar properties Polaren Eigenschaft Curve Kurve Points Punkte Style Gestalltung Width Breite Color Farbe Graph Curve Settings Graphen Kurven Einstellungen abcopy: buffer airfoil not available abcopy: Buffer Profil nicht verfügbar Target segment cannot include stagnation point in mixed-inverse QXInverse x/c x/c Q/Vinf Q/Vinf Q Graph Q Graph Must mark off target segment first Nicht-Ziel Segmente müsse zuerst markiert werden Converged Konvergiert Unconverged Nicht-Konvergiert Modified Modifiziert Warning Warnung Unrecognized foil format Unbekannts Profil Format The minimum number of control points has been reached for this spline degree Drag points to modify splines, Apply, and Execute to generate the new geometry Punkte verschieben um Splines zu ändern; dann "zuweisen" und "ausführen" um neue Geometrie zu erzeugen Mark target segment for modification Ziel-Segmente für Änderung markieren Mark spline endpoints Spline-Endpunkte markieren Alpha = Alpha = Cl = Cl = Mark target segment for smoothing, or type 'Return' to smooth the entire distribution Ziel-Segmente für glättung markieren, oder "Eingabe" drücken um gesamte Verteilung zu glätten Base Base Mod. Mod. Thickness = %1% Dicke =%1% Max.Thick.pos. = %1% Position der maximalen Dicke =%1% Max. Camber = %1% Maximale Wölbung =%1% Alpha = %1 Alpha = %1 Cl = %1 Cl = %1 Q - Reference Q - Reference Q - Specification Q - Specification Q - Viscous Q - Reibung Reflected Refkeltiert Alpha Alpha Cl Cl Specification Spzifikation ShowSpline Zeige Spline Tangent Spline Tangenten Spline New Spline Neue Spline Apply Spline Spine anwenden Reset QSpec QSpec zurücksetzen Pert Verteilung Modification Modifikation Smooth QSpec QSpec glätten Hannig Filter Hannig Filter Filter parameter Filter Parameter Smoothing Glättung T.E. Angle Hinterkanten Winkel (T.E. Angle) T.E. Gap dx/c Hinterkanten Spalt (dx/c) T.E. Gap dy/c Hinterkanten Spalt (dy/c) Symmetric foil Symmetrisches Profil Constraints Randbedingungen Execute Ausführen Cl = Cl = Mark for modification Für Änderungen markieren End Point Constraint Endpunkt Randbedingungen Smooth Glätten Max Iterations Maximale Iterationen Foil Profil ReListDlg Reynolds Number List Reynolds Number Liste Insert Einfügen Delete Löschen OK Ok Cancel Abbrechen RenameDlg Rename Umbenennen Enter the new name Geben Sie einen neuen Namen ein Existing Names: Existierende Namen: OK Ok Cancel Abbrechen Overwrite Überschreiben Note : Overwrite will delete Opps and reset polars Hinweis: Überschreiben löscht Opps und setzt Polaren zurück Enter a name Namen eingebent Warning Warnung Must enter a name Sie müssen einen Namen eingeben Do you wish to overwrite Wirklich überschreiben? Question Frage SaveOptionsDlg Save Options Optionen speichern Save: Speichern: Foil Operating Points Profil Arbeitspunkte Wing and Plane Operating Points Trangflächen und Flugzeug Arbeitspunkte OK Ok Cancel Abbrechen SplineCtrlsDlg Spline Parameters Spline Parameter Upper side Oberseite Lower side Unterseite Point Weight = Warning Warnung The spline degree must be less than the number of control points Spline degree Grad der Spine Output Ausgabe Symetric foil Symetrische Tragfläche Upper Surface Oberseite Lower Surface Unterseite OK Ok Cancel Abbrechen StabAnalysisDlg Warning Warnung Cancel Abbrechen StabPolarDlg Stability Polar Definition Satbilitäts Polar Definition Plane analysis methods Control Name Kontroll-Name Active (1/0) Aktiv (1/0) Controls Kontrollen Wing Tilt ( Flächen Neigung(tilt) ( Elevator Tilt Höhenruder Neigung(tilt) Wing Flap angle %1 Flächen Klappen-Winkel %1 Elevator Flap %1 Höhenruder Klappen-Winkel %1 Fin Flap %1 Mass must be non-zero for type 7 polars Use plane inertia Verwende Modell Trägheit VLM 3D Panels 3D Paneele Wing analysis methods Mix 3D Panels/VLM Ignore Body Panels Note: + sign means trailing edge down Gain No Active Control. Continue ? Keine aktiven Kontrollen. Vorsetzen? Question Frage Warning Warnung Must enter a name Sie müssen einen Namen eingeben The polar's name already exists Der Polar-Name existier bereits Wing Name Tragflächen Name Auto Analysis Name Name der automatischen Analyse Polar Name Polaren Name b = f = Define Inertia Trägheit definieren Viscous Analysis Analyse mit Reibung Note : the analysis may be of the viscous type only if all the flap controls are inactive Plane and Flight Data Modell und Flugdaten Unit Einheit International International Imperial Imperial Aerodynamic Data Aerodynamische Daten Wing Planform Area Trangflächen Grundform Fläche Wing Planform Area projected on xy plane Trangflächen Grundform Fläche auf XY Ebene projeziert Reference Area for Aero Coefficients Referenzfläche für aerodynamische Koeffizienten Note 1 : the analysis is necessarily of type VLM1 Hinweis 1: Die Analyse ist notwendigerweise vom Typ VLM1 Note 2 : the analysis may be of the viscous type only if all the flap controls are inactive Hinweis 3: Die Analyse ist nur dann mit Reibung wenn die Klappen inaktiv sind {2 ?} OK Cancel Abbrechen StabViewDlg Stability View Params Parameter der Stabilitäts-Ansicht Control Name Kontroll-Name Controls Steuert Wing Tilt ( Flächen Neigung(tilt) ( Elevator Tilt Höhenruder Neigung(tilt) Wing Flap angle %1 Flächen Klappen-Winkel %1 Elevator Flap %1 Höhenruder Klappen-Winkel %1 Time View Zeit-Ansicht Longitudinal Lateral Stability direction Stabilitäts Richtung Initial Conditions Response Forced Response Initial conditions Keep Erhalten Reset Zurücksetzen Curve Kurve Modal Response Modal response Define the total time range for the graphs Zeitfenster für den Graphen Define the time step for the resolution of the differential equations Zeitschritte für die Auflösung der Differenzialgleichungen Re-calculate the currently selected curve with the user-specified input data Neuberechnung der ausgewählten Kurve mit Benutzerdaten Add a new curve to the graphs, using the current user-specified input Neue Kurve hinzufügen Rename the currently selected curve Ausgewählte Kurve umbenennen Delete the currently selected curve Ausgewählte Kurve löschen Time Graph Params Zeitgraph Parameter Mode Selection Mode Auswahl Eigenvalues F1 = z = Mode properties <small>Mode Properties: Total Time Gesamtzeit Operating point modes Speed Geschwindigkeit Amplitude Amplitude Animate Animation Restart Neustart Time Step = Zeitschritt = s Animation Animation Time (s) Angle Control function Enter the function of the control vs. time Curve Settings Recalc. Neuberechnung Add Hinzufügen Rename Umbenennen Delete Löschen Press Ctrl+H to highlight the mode on the root locus plot u0= w0= q0= v0= p0= r0= New curve Neue Kurve TEGapDlg T.E. Gap Hinterkanten Spalt T.E. Gap Value Hinterkanten Spalt Wert % chord % Profiltiefe Blending Distance from L.E. Biegeabstand von der Vorderkante OK Ok Cancel Abbrechen Apply Anwenden Warning Warnung Unrecognized foil format Unbekannts Profil Format Panel number cannot exceed 300 Panel Anzahl kann 300 nich übersteigen TranslatorDlg Language settings Sprache English Deutsch Warning Warnung The change will take effect at the next session Die Änderung wird erst nach dem Neustart wirksam Select the application's default language: Wählen Sie die Standardsprache: OK Ok Cancel Abbrechen The directory Verzeichniss does not exist existiert nicht does not exist existiert nicht TwoDPanelDlg Global Panel Refinement Globale Panel Verfeinerung Number of Panels Anzahl der Panele Panel Bunching Parameter TE/LE Panel Density Ratio Refined area/LE Panel Density Ratio Top Side Refined Area x/c limits Bottom Side Refined Area x/c limits OK Ok Cancel Abbrechen Apply Anwenden Warning Warnung Unrecognized foil format Unbekannts Profil Format The total number of panels cannot exceed %1 Die gesamte Paneele Anzahl kann %1 nicht überschreiten UnitsDlg Select units for this project : Einheiten für dieses Projekt definieren : Units Dialog Einheiten definieren... Length Länge Area Fläche Speed Geschwindigkeit Mass Masse Weight Gewicht Force Kraft Moment Moment Define the project units Einheiten für dieses Projekt definieren OK Ok Cancel Abbrechen BodyName Rupf-Name Export Body Definition Rupfdefinition exportieren Text Format (*.txt) UFO Polar Format (*.*) Export Body Geometry Rumpfgeometrie exportieren Text File (*.txt);;Comma Separated Values (*.csv) Text File (*.txt);;Comma Separated Values (*.csv) Choose the length unit to read this file : Wählen Sie die Längeneinheit um diese Datei zu lesen: Open File Datei öffnen Text file (*.txt) UFO Polar Format (*.*) Could not read the file File konnte nicht gelesen werden Warning Warnung Error reading Fehler beim Lesen Frames have different number of side points Rahmen haben unteschiedliche Anzahl von Seitenpunkten Error Fehler Please select a Frame before inserting a point Bitte wählen Sie einen Rahmen bevor Sie einen Punkt einfügen VLMAnalysisDlg VLM Analysis VLM Analyse Warning Warnung The number of points to be calculated will be limited to 100 Die Anzahl der Punkte die berechnet werden sind auf 100 limitiert Solving the problem... Löse das Problem... Failed to create the matrix.... Matrix konnte nicht erstellt werden.... Singular matrix - aborting.... Ainguläre Matrix...abbruch.... Sideslip is asymmetric Drift ist asymmetrisch Main wing is asymmetric Tragfläche ist asymmetrisch 2nd wing is asymmetric 2. Tragfläche ist asymmetrisch Elevator is asymmetric Höhenruder ist asymmetrisch A fin is considered asymmetric Ein Seitenruder wird als asymmetrisch angenommen Perfoming symmetric calculation Führe symmetrie Berechnungen aus Performing asymmetric calculation : Führe symmetrie Berechnungen aus: Failed to create matrix.... Matrix konnte nicht erstellt werden.... Cancel Abbrechen Type %1 Analysis Analyse Methode Close Schließen Solving the linear system... Löse das lineare Gleichungssystem... Singular Matrix.... Aborting calculation... Ainguläre Matrix...abbruch.... Calculating speeds to balance the weight Berechne Geschwindigkeit um Gewicht auszugleichen Found a negative lift for Alpha=%1.... skipping the angle... Negativer Auftrieb für Alpha=%1 .... überspringe den Winkel... W3dPrefsDlg 3D Styles 3D Gestalltung Axis Axen Outline Kontur VLM Mesh VLM Gitter Top transition Oberer Umschlagspunkt Bottom transition Unterer Umschlagspunkt Lift Auftrieb Moments Momente Induced Drag Induzierter Widerstand (induced drag) Viscous Drag Reibungswiderstand Downwash Abwind WakePanels Wirbel Panele Streamlines Masses Show Wake Panels Zeige Wirbelpanele Close Schließen Reset Defaults Standardwerte zurücksetzen OK Ok Cancel Abbrechen WAdvancedDlg Wing Analysis Advanced Settings Trangflächenanalyse erweiterte Einstellungen View Log File after errors Zeige Log-File nach Fehlern Reset Wake between each angle Wirbel nach jedem Winkel zurücksetzten Store points outside the polar mesh Speichere Punkte ausserhalb der Polaren Gitters All Analysis Gesamtanalyse VLM and Panel Methods VLM und Panel Methoden Core Size VLM Method VLM Methode Ignore wing panels with span < Ignoriere Panel mit Spannweite < Horseshoe vortex Ring vortex Vortex Position Vortex Position Control Point Position Kontrollpunkt Position Lifting Line Method Traglinienverfahren Relax. factor Alpha Precision Max. Iterations Maximale Iterationen Number of spanwise stations Anzahl der Stützpunkte 3D Panel boundary conditions OK Ok Cancel Abbrechen Reset Defaults Standardwerte zurücksetzen WPolarDlg Analysis Definition Analyse Definition Warning Warnung The number of chordwise VLM-panels across the span is not uniform Panel method is disabled Die Anzahl der Sehnen VLM-Paneele über den Spant ist nicht gleichförmig Paneelen Methode ist nicht verfügbar Must enter a name for the polar Sie müssen einen Namen für die Polare eingeben The polar's name already exists Der Polaren-Name existier bereits Mass must be non-zero for type 2 polars Wing Name Tragflächen Name Auto Analysis Name Name der automatischen Analyse Wing analysis methods Vinf.sqrt(Cl) = Polar Name Polaren Name Type 1 (Fixed Speed) Type 1 (Fixe Geschwindigkeit) Type 2 (Fixed Lift) Type 2 (Fixer Auftrieb) Type 4 (Fixed aoa) Type 4 (Fixer Anstellwinkel aoa) Polar Type Polaren Typ Free Stream Speed Freie Strömungsgeschwindigkeit Plane Weight Modellgewicht Mom. ref. location Momenten Referenz Punkt Position (moment ref location) Angle of Attack Anstellwinkel (aoa) Side Slip Driftwinkel Free Stream Speed = Freie Strömungsgeschwindigkeit = Plane Mass = Flugzeugmasse= X_CoG = Z_CoG = Plane and Flight Data Modell und Flugdaten Inertia properties Use plane inertia Verwende Modell Trägheit Wing Loading = 0.033 kg/dm2 SRe RRe QInfCl Flight Characteristics Flug Merkmale LLT LLT VLM1 : Classic VLM1 : Classic VLM2 : Quads VLM2 : Quads 3D Panels 3D Paneele Unit Einheit International International Imperial Imperial Aerodynamic Data Aerodynamische Daten Viscous Reibung Tilt. Geom. Geometrie verdrehen. Wake Roll-up Anfahrtswirbel (wake roll-up) Wake... Wirbel... VLM Mix 3D Panels/VLM Options Optionen Ignore Body Panels Ground Effect Bodeneffekt Height = Höhe = Wing Planform Wing Planform Area Trangflächen Grundform Fläche Wing Planform projected on xy plane Wing Planform Area projected on xy plane Trangflächen Grundform Fläche auf XY Ebene Reference Area and Span for Aero Coefficients Reference Area for Aero Coefficients Referenzfläche für aerodynamische Koeffizienten OK Ok Cancel Abbrechen Root Re = Wurzel Re = Tip Re = Spitzen Re = Qinf.sqrt(Cl) = Qinf.sqrt(Cl) = Root Re.sqrt(Cl) = Wurzel Re sqrt(Cl) = Tip Re.sqrt(Cl) = Spitzen Re sqrt(Cl)= Wing Loading = Tragflächenbelastung = WingDelegate Uniform Gleichmäßig Cosine COSinus Sine SINus -Sine -SINus WingScaleDlg Scale Wing Dlg Tragfläche skalieren Span Scaling Spannweitenskalierung Chord Scaling Wurzeltiefenskalierung Sweep Scaling Rückfallskalierung Twist Scaling Verwindungsskalierung Reference Referenz New Neu Ratio Verhältnis OK Ok Cancel Abbrechen XDirectStyleDlg XDirect Styles XDirect Gestaltung Neutral Line Neutrale-Linie Boundary Layer Grenzschicht Pressure Druck OK Ok Defaults Standardwerte Cancel Abbrechen XFoilAdvancedDlg XFoil Settings XFoil Einstellungen VAccel Iteration Limit Maximale Iterationen Re-initialize BLs after an unconverged iteration Grenzschicht bei nicht-konvergenz neu initialisieren Show full log report for an XFoil analysis Zeige gesamten Logfile nach Analyse OK Ok Cancel Abbrechen XFoilAnalysisDlg XFoil Analysis XFoil Analyse Iter Iteration Skip überspringen Cancel Abbrechen Alpha = %1 Alpha = %1 Alfa = %1 ........ Alpha = %1 .......... Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid Cl = %1 Cl = %1 Cl = %1 ........ Initializing viscous analysis ... CpCalc: local speed too large Compressibility corrections invalid Solving BL system ... Iteration %1 ... unconverged after %1 iterations --------- Unconverged ----------- converged after %1 iterations Close Schließen xflr5-6.09-06/translations/xflr5v6_fr.ts000755 001750 000144 00001630523 12247705420 021402 0ustar00techwinderusers000000 000000 AFoilGridDlg Accept Accepter Cancel Abandonner Apply Appliquer Grid Options Options de grille Neutral Line Ligne neutre X-Scale Échelle X X Major Grid Grille principale en X Y Major Grid Grille principale en Y X Minor Grid Grille secondaire en X Y Minor Grid Grille secondaire en Y AFoilTableDlg Foil Table Columns Colonne du tableau des profils Foil Name Nom du profil Thickness Épaisseur Thickness max. position Position de l'épaisseur max. Camber Cambrure Camber max. position Position de l'épaisseur max. Number of points Nombre de panneaux Trailing edge flap angle Angle du volet du bord de fuite Trailing edge hinge x-position Position en X de la charnière du BF Trailing edge hinge y-position Position en Y de la charnière du BF Leading edge flap angle Angle du volet du bord d'attaque Leading edge hinge x-position Position en X de la charnière du BA Leading edge hinge y-position Position en Y de la charnière du BA OK Accepter Cancel Abandonner AboutQ5 Copyright (C) M. Drela and H. Youngren 2000 - XFoil v6.94 Copyright (C) M. Drela et H. Youngren 2000 - XFoil v6.94 Copyright (C) Matthieu Scherrer 2004 - Miarex v1.00 Copyright (C) Matthieu Scherrer 2004 - Miarex v1.00 About XFLR5 A propos de XFLR5 Copyright (C) Andre Deperrois 2003-2012 Copyright (C) Andre Deperrois 2003-2012 Copyright (C) Andre Deperrois 2003-2013 Copyright (C) Andre Deperrois 2003-2013 This program is distributed in the hope that it will be useful, Ce programme est distribué avec l'espoir qu'il sera utile, but WITHOUT ANY WARRANTY; without even the implied warranty of mais SANS AUCUNE GARANTIE, sans même la garantie implicite d'une MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. QUELCONQUE VALEUR MARCHANDE ou de l'ADÉQUATION À UN BESOIN PARTICULIER. This program has been developed exclusively for the analysis of model aircraft Ce programme a été développé exclusivement pour l'analyse de modèles réduits Any other usage is strongly disapproved Toute autre utilisation est fortement déconseillée Program distributed under the terms of the GNU General Public License Ce programme est distribué selon les termes de la Licence Publique Générale GNU (GPL) German translation by Martin Willner Traduction allemande par Martin Willner German translation by Martin Willner (mjw@mjw.co.at) Traduction allemande par Martin Willner (mjw@mjw.co.at) Japanese translation by IKUSU, Koichi Akabe, Misatus, dynamicsoar, hide253 Traductiion japonaise de IKUSU, Koichi Akabe, Misatus, dynamicsoar, hide253 icchy_07, ina111, ohayo_cycling, ohisa_64, ozawa64. French translation by Jean-Luc Coulon Traduction française par Jean-Luc Coulon OK Accepter BatchDlg Analyze Analyser Analysis Type Type d'analyse Batch Variables Variables de traitement Analysis Range Plage d'analyse Iter Itération Current foil only Profil actif seulement Foil list Liste des profils Foil Selection Sélection du profil Batch foil analysis Analyse de profils par lots Range Plage Re List Liste de Re Edit List Éditer la liste Min Min Max Max Increment Pas Specify Spécifier From Zero Depuis zéro Spec = Spéc = NCrit= NCrit= Forced transitions Transitions forcées Initialize BLs between polars Initialiser la couche limite entre les polaires Close Fermer Skip Opp Sauter l'OpPoint Skip Polar Sauter la polaire Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid Paramètres d'analyse incorrects CpCalc : vitesse locale trop élevée Les corrections de compressibilité ne sont pas valables Cancel Abandonner ...unconverged after %1 iterations ...pas de convergence après %1 itérations ...converged after %1 iterations ...convergence après %1 itérations ...skipped after %1 iterations ...sauté après %1 itérations ...unconverged after %1 iterations ...pas de convergence après %1 itérations Analyzing Analyse du profil Analysis completed Analyse terminée Type 1 Type 1 Type 2 Type 2 Type 3 Type 3 Type 4 Type 4 Top transition location (x/c) Emplacement de la transition supérieure (x/c) Bottom transition location (x/c) Emplacement de la transition inférieure (x/c) Store OpPoints Enregistrer les OpPoints Alpha Alpha Cl Cz ...skipped after %1 iterations ...sauté après %1 itérations Analysis interrupted Analyse interrompue CpCalc: local speed too large Compressibility corrections invalid CpCalc : vitesse locale trop élevée Les corrections de compressibilité ne sont pas valables Alpha = Alpha = Cl = Cz = Reynolds = Reynolds = Mach = Mach = Re.sqrt(Cl) = Re.sqrt(Cz) = Ma.sqrt(Cl) = Ma.sqrt(Cz) = Re.Cl = Re.Cz = Cl = %1 Cz = %1 BatchThreadDlg Multi-threaded batch analysis Analyse multi-processeurs Foil Selection Sélection du profil Current foil only Profil actif seulement Foil list Liste des profils Batch Variables Variables de traitement Range Plage Re List Liste de Re Edit List Éditer la liste Min Min Max Max Increment Pas NCrit= NCrit= Analysis Range Plage d'analyse Specify: Spécifier: Alpha Alpha Cl Cz From Zero Depuis zéro Spec = Spéc = Forced Transitions Transitions forcées Top transition location (x/c) Emplacement de la transition supérieure (x/c) Bottom transition location (x/c) Emplacement de la transition inférieure (x/c) Initialize BLs between polars Initialiser la couche limite entre les polaires Update polar view Mettre à jour la vue Update the polar graphs after the completion of each foil/polar pair Mettre à jour les diagrammes polaires après chaque calcul d'une paire profil/polaire Close Fermer Analyze Analyser CL CZ Cancel Abandonner BodyGridDlg Show Scales Afficher les échelles Main Grid Grille principale Minor Grid Grille secondaire Body Grid Grille du fuselage Frame Grid Grille de la structure OK Accepter Cancel Abandonner Body Grid Dialog Dialogue de la grille de fuselage Grid Parameters Paramètres de la grille BodyScaleDlg OK Accepter Cancel Abandonner Whole Body Ensemble du fuselage Frame Only Cadre uniquement Scale Factor Facteur d'échelle X Scale Échelle X Y Scale Échelle Y Z Scale Échelle Z Body Scale Dialog Dialogue d'échelle du fuselage BodyTransDlg Frame Only Cadre uniquement X Translation Translation X Y Translation Translation Y Z Translation Translation Z Body Translation Translation du fuselage OK Accepter Cancel Abandonner CAddDlg Accept Accepter Cancel Abandonner Apply Appliquer Warning Attention Local Panel Refinement Amélioration locale du profil Type of Spline Type de spline Refinement X Limits Limites d'amélioration en X From De To À Uniform Uniforme Arc Length Longueur d'arc Total Total Added Ajouté MaxAngle AngleMax Unrecognized foil format Format de profil non reconnu Total number of points is %1 Le nombre total de points est de %1 (added %1 points to original foil) (%1 points ajoutés au profil d'origine) Maximum panel angle is %1 L'angle maximum du panneau est de %1 at panel position %1 a la position %1 du panneau Maximum panel angle is %1 deg L'angle maximum du panneau est de %1 deg Angle Criterion Critère d'angle At Panel Au panneau DisplaySettingsDlg General Display Settings Paramètres généraux d'affichage All Graph Settings Paramètres pour tous les diagrammes Graph Settings Paramètres du diagramme Background Color Couleur de fond Text Color Couleur du texte Font Police Use Stylesheets Utiliser les feuilles de style Reverse zoom direction using mouse wheel Inverser le sens du zoom lors de l’utilisation de la molette de la souris Enable 3D transparency Activer la transparence 3D OK Accepter Cancel Abandonner EditPlrDlg Polar Points Edition Éditer les points de la polaire Delete All Points Supprimer tous les points Delete Point Supprimer un point OK Accepter Cancel Abandonner FlapDlg Flap Dlg Définition des volets OK Accepter Cancel Abandonner Apply Appliquer Warning Attention The trailing edge hinge must be downstream of the leading edge hinge L'articulation de bord de fuite doit se trouver en dessous de l'articulation de bord d'attaque L.E. Flap Volet de bord d'attaque T.E. Flap Volet de bord de fuite Flap Angle Angle du volet + is down + vers le bas Hinge X Position Position en X de l'articulation % Chord % corde Hinge Y Position Position en Y de l'articulation % Thickness % épaisseur FoilCoordDlg Apply Appliquer Foil Coordinates Coordonnées du profil Insert Point Insérer un point Delete Point Supprimer un point Restore Restaurer OK Accepter Cancel Abandonner FoilGeomDlg OK Accepter Cancel Abandonner Warning Attention Camber Cambrure Thickness Épaisseur Value Valeur %Chord % corde 0% 0% Max x-pos Pos max en x Restore Restaurer Panel number cannot exceed 300 Le nombre de panneaux ne peut dépasser 300 10% 10% 100% 100% Foil Geometry Géométrie du profil FoilPolarDlg OK Accepter Cancel Abandonner Analysis Name Nom de l'analyse Analysis Type Type d'analyse Transition settings Paramètres de transition Foil Polar Definition Définition de la polaire du profil Automatic Automatique User Defined Définie par l'utilisateur Type 1 Type 1 Type 2 Type 2 Type 3 Type 3 Type 4 Type 4 Plane Data Données avion Chord Corde Mass Masse Span Envergure Aerodynamic Data Données aérodynamiques Unit Unités International International Imperial Impérial Re = Re = Mach = Mach = Reynolds and Mach Numbers Nombre de Reynolds et de Mach Free transitions (e^n) method Méthode des transitions libres (e^n) Forced transition: Transition forcée : NCrit= NCrit= TripLocation (top) Point de transition (supérieur) TripLocation (bot) Point de transition (inférieur) Analysis parameters for Paramètres d'analyse pour Reynolds = Reynolds = Re.sqrt(Cl) = Re.sqrt(Cz) = Ma.sqrt(Cl) = Ma.sqrt(Cz) = Re.Cl = Re.Cz = Alpha = Alpha = FoilSelectionDlg OK Accepter Cancel Abandonner Foil Selection Sélection du profil GL3DScales Apply Appliquer Auto Scales Échelles automatiques Cp Scale Échelle Cp Lift Portance Drag Traînée Velocity Vitesse Streamlines Lignes de courant Vector Scales Échelles des vecteurs L.E. Bord d'attaque T.E. Bord de fuite Y-Line Ligne Y X-axis points points sur l'axe X 1st segment 1er segment X factor Facteur X X-Offset Décalage X Z-Offset Décalage Z Streamline length Longueur de la ligne de courant Start Streamline at Démarrer la ligne de courant à 3D Scales Settings Définitions des échelles 3D Min Min Max Max GL3dBodyDlg Undo Défaire Cancels the last modifiction made to the body Supprimer la dernière modification faite au fuselage Redo Refaire Restores the last cancelled modification made to the body Restaurer la dernière modification annulée faite au fuselage Export Body Geometry to File Exporter la géométrie du fuselage vers un fichier Export Body Definition to File Exporter la définition du fuselage vers un fichier Import Body Definition from File Importer la définition du fuselage depuis un fichier NPanels NbPanneaux Other Autre Save and Close Enregistrer et fermer Cancel Abandonner Body Edition Édition de fuselage Scale Échelle Grid Setup Configuration de la grille Reset Scales Réinitialiser les échelles Show Current Frame Only N'afficher que la structure en cours Translate Translation Description: Description : Frame %1 Cadre %1 Cancels the last modification Annule la dernière modif. Restores the last cancelled modification Rétablit la dernière annulation Define Inertia Définir l'inertie Scale = %1 Échelle = %1 Body Dlg Exit Quitter le dialogue de fuselage Save the Body ? Enregistrer le fuselage ? Axes Axes Light Éclairage Surfaces Surfaces Outline Contour Panels Panneaux Masses Masses Pick Center Choisir le centre Clip Plane Tronquer l'avion Actions... Actions... Flat Panels Panneaux plats BSplines Splines B x x Hoop Coupe Degree Ordre BodyName NomFuselage Insert Point Insérer un point Remove Point Supprimer le point X View Vue X Y View Vue Y Z View Vue Z Iso View Vue ISO Enter here a short description for the body Entrer ici une courte description pour le fuselage Panel bunch Frames Cadres Frame Positions Emplacement des cadres Points Points Current Frame Definition Définition du cadre sélectionné Context Menu Menu contextuel GL3dWingDlg Warning Attention Warning : Panel sequence is inconsistent Attention : la séquence de panneaux n'est pas cohérente The first section cannot be deleted La première section ne peut pas être supprimée Symetric Symétrique Right Side Côté droit Left Side Côté gauche Insert Before Insérer avant Number of VLM Panels Nombre de panneaux Reset Mesh Réinitialiser le maillage Scale Wing Mise à l'échelle de l'aile Import Wing Importer une aile Export Wing Exporter une aile Save and Close Enregistrer et quitter Cancel Abandonner Wing Edition Édition de l'aile Reset Scales Réinitialiser les échelles Insert after Insérer après Delete section Supprimer la section Reset section Réinitialiser la section Import Wing from File... Importer une aile depuis un fichier Export Wing to File... Exporter une aile vers un fichier Section Section Please enter a name for the wing Veuillez entrer un nom pour l'aile Too many spanwise panels. The maximum number is Trop de panneaux sur l’envergure. Le nombre maximum est de Too many panels Reduce the mesh size Trop de panneaux Réduisez la taille du maillage Only 10 flaps x 2 will be handled Seuls 10 volets x2 peuvent être pris en compte chord ( corde ( offset ( décalage ( The maximum number of panels has been reached Le nombre maximum de panneaux a été atteint No insertion possible before the first section Il n'est pas possible d'insérer avant la première section Wing Span Envergure de l'aile Area Surface Projected Span Envergure projetée Projected Area Surface projetée Total VLM Panels Nombre total de panneaux VLM Number of 3D Panels Nombre de panneaux 3D Mean Geom. Chord Corde géométrique moyenne Mean Aero Chord Corde aéro moyenne MAC Span Pos Position sur l'envergure de la CAM Aspect ratio Allongement Taper Ratio Effilement Root to Tip Sweep Flèche de l'emplanture au saumon Number of Flaps Nombre de volets Axes Axes Light Éclairage Surfaces Surfaces Outline Contour Panels Panneaux Foil Names Nom des profils Masses Masses X View Vue X Y View Vue Y Z View Vue Z Iso View Vue ISO Pick Center Sélectionner le centre Activate the button, then click on the object to center it in the viewport; alternatively, double click on the object Activer le bouton, cliquer ensuitre sur l’objet pour le centrer dans la vue ; vous pouvez aussi faire un double-clic sur l’objet Reset Réinitialiser Clip Plane Tronquer l'avion Question Question y ( y ( Enter here a short description for the wing Entrez ici une courte description de l'aile Description: Description : Inertia... Inertie... Save the changes ? Enregistrer les modifications ? Uniform Uniforme Cosine Cosinus Sine Sinus -Sine -Sinus Wing Description Description de l'aile Insert after section Insérer après la section Insert before section Insérer avant la section Undefined Non défini WingName NomAile Max is Le maximum est GLLightDlg Close Fermer Reset Defaults Réinitialiser aux valeurs par défaut OpenGL Light Options Options d'éclairage OpenGL Light Intensity Intensité lumineuse Red Rouge Green Vert Blue Bleu Light Color Couleur de l'éclairage Light Position Position de l'éclairage Diffuse Diffuse Ambient Ambiante Specular Spéculaire Emissions Émissive Shininess Brillance Material Matériau Color Material Couleur du matériau Cull Faces Faces sélectionnées Depth Test Test de profondeur Smooth Shading Lisser les ombres Local View Vue locale Options Options Light Lumière x x y y z z Smooth Quads Lisser les Quads GraphDlg OK Accepter Cancel Abandonner Apply Appliquer Graph Settings Paramètres du diagramme X - Chord X - Corde Q - Speed Q - Vitesse X - chord X - corde Cp Cp Induced Angle Angle induit Total Angle Angle total Local lift coef. Coef. de portance locale Local Lift C.Cl/M.A.C. Portance locale C.Cz/CAM Airfoil viscous drag coef. Coef traînée visqueuse profil Induced drag coef. Coef traînée induite Total drag coef. Coef traînée totale Local Drag C.Cd/M.A.C. Traînée locale C.Cx/CAM Airfoil Pitching moment coef. Coef moment tangage profil Total Pitching moment coef. Coef moment total tangage Top Transition x-pos% % pos. x transition supérieure Bottom Transition x-pos% % pos. x transition inférieure Centre of Pressure x-pos% % position x du centre de pression Bending moment Moment de flexion Lift coef. Coef de portance Viscous drag coef. Coef de traînée visqueuse Total pitching moment coef. Coef moment total tangage Total rolling moment coef. Coef moment de roulis total Total yawing moment coef. Coef moment lacet total Viscous yawing moment coef. Coef moment lacet visqueux Induced yawing moment coef. Coef moment lacet induit Glide ratio Cl/Cd Finesse Cz/Cx Power factor Cl^(3/2)/Cd Facteur de vitesse mini. Cz^(3/2)/Cx 1/Rt(Cl) 1/Rt(Cz) Vx Vx Vz Vz VInf VInf Descent angle atan(Cd/Cl) Angle de descente atan(Cx/Cz) Pitching Moment Moment de tangage Rolling Moment Moment de roulis Yawing Moment Moment de lacet Centre of pressure X-Pos Centre de pression X-Pos Centre of pressure Y-Pos Centre de pression Y-Pos Centre of pressure Z-Pos Centre de pression Z-Pos m.g.Vz m.g.Vz Efficiency Rendement Control Variable Variable de contrôle Cy - Lateral force coef. Cy - Coef de force latérale Alpha Alpha FX (Drag) FX(Trainée) FY (Side force) FY(Force latérale) FZ (Lift) FZ (Portance) (XCp-Xcg)/MAC (XCp-Xcg)/CAM Phugoid Frequency Fréquence de la phugoïde Phugoid Damping Amortissement de la phugoïde Short Period Frequency Fréquence du mode d'incidence Short Period Damping Amortissement du mode d'incidence Dutch Roll Frequency Fréquence du roulis hollandais Dutch Roll Damping Amortissement du roulis hollandais Roll Damping Amortissement en roulis Spiral Damping Amortissement en spirale Restore Restaurer YAxis Axe Y XAxis Axe X Set Title Font Définir la police du titre Set Label Font Définir la police des étiquettes Title Color Couleur du titre Label Color Couleur des étiquettes Fonts Polices Graph Background Arrière-plan du diagramme Graph Border Bordure du diagramme BackGround Arrière-plan X Axis Axe X Y Axis Axe Y Min Min Max Max Origin Origine Unit Unités Auto Scale Échelle automatique Inverted Axis Axes inversés Axis Style Style des axes X Major Grid Grille principale en X Y Major Grid Grille principale en Y X Minor Grid Grille secondaire en X Y Minor Grid Grille secondaire en Y Variables Variables Scales Échelles Axis and Grids Axes et grilles Fonts and BackGround Polices et arrières-plans Cl Cz Cd Cx Cd x 10000 Cx x 10000 Cdp Cxp Cm Cm Xtr1 Xtr1 Xtr2 Xtr2 HMom HMom Cpmin Cpmin Cl/Cd Cz/Cx |Cl|^(3/2)/Cd |Cz|^(3/2)/Cx 1/Cl^1/2 1/Cz^1/2 Re Re XCp XCp Reynolds Reynolds Neutral Point x-position Position x du point neutre vs. vs. Title Titre Label Étiquette Font Police Color Couleur Auto Unit Unités automatiques Viscous pitching moment coef. Coefficient de moment de tangage visqueux Induced pitching moment coef. Coefficient de moment de tangage induit Y - span Y - envergure ImportObjectDlg Import Object Importer un objet Select the wing to import Sélectionner l'aile à importer Select the body to import Sélectionner le fuselage à importer OK Accepter Cancel Abandonner ImportWingDlg OK Accepter Cancel Abandonner Import Wing Dialog Dialogue d'importation d'aile Select the wing to import sélectionner l'aile à importer InertiaDlg Inertia Properties Propriétés d'inertie Mass Masse x x y y z z Description Description %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Center of gravity Centre de gravité Export to AVL Exporter vers AVL Refer to the Guidelines for explanations. Se référer au fichier d'explications. Insert Before Insérer avant Delete Supprimer Point Mass Masses ponctuelles Wing Mass: Masse de l'aile : Inertia properties for Propriétés d'inertie de Body Mass: Masse du fuselage : Volume Mass: Masse du volume : Export Mass Properties Exporter les propriétés de masse AVL Mass File (*.mass) Fichier de masse AVL (*.mass) %1 %2 %3 %4 %5 %6 %7 %8 %9 %10! Inertia of both left and right wings %1 %2 %3 %4 %5 %6 %7 %8 %9 %10! Inertia des ailes droite et gauche %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Body inertia %1 %2 %3 %4 %5 %6 %7 ! Inertie du fuselage %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Body's inertia %1 %2 %3 %4 %5 %6 %7 ! Inertie du fuselage This is a calculation form for a rough order of magnitude for the inertia tensor. Ceci est un formulaire de calcul permettant d’obtenir un ordre de grandeur grossier du tenseur d’inertie. Object Mass - Volume only, excluding point masses Masse de l'objet - Volume uniquement, les masses ponctuelles sont exclues Wing Mass= Masse de l'aile = Inertia in CoG Frame Inertie dans le repère lié au centre de gravité Component inertias Main Wing Aile principale Second Wing Seconde aile Elevator Stabilisateur horizontal Fin Dérive Body Fuselage Additional Point Masses Masses ponctuelles supplémentaires Total Mass = Volume + point masses Masse totale : volume + masses ponctuelle Total Mass= Masse totale = OK Accepter Cancel Abandonner InterpolateFoilsDlg OK Accepter Cancel Abandonner Interpolate Foils Interpoler les profils New Foil Name Nom du nouveau profil Interpolated Foil Profil interpolé Camb1 Camb1 Camb2 Camb2 Camb3 Camb3 Thick1 Épais1 Thick2 Épais2 Thick3 Épais3 Camb.=%1 Camb.=%1 at x=%1 à x=%1 Thick.=%1 Épaiss.=%1 InverseOptionsDlg XInverse Style Style Xinverse Reference Foil Profil de référence Modified Foil Profil modifié Spline Spline Reflected Curve Courbe réfléchie OK Accepter Cancel Abandonner LECircleDlg OK Accepter Cancel Abandonner Show Afficher % Chord % corde L.E. Circle Cercle de BA r= r= LEDlg OK Accepter Cancel Abandonner Apply Appliquer Warning Attention Leading Edge Bord d'attaque Approximate new/old ratio for L.E. radius Rapport du nouveau rayon/ancien ratio rapport Blending Distance from L.E. Distance de transition depuis le BA % chord % corde Unrecognized foil format Format de profil non reconnu Panel number cannot exceed 300 Le nombre de panneaux ne peut dépasser 300 LLTAnalysisDlg LLT Analysis Analyse LLT Iterations Itérations abs abs Launching analysis.... Lancement de l'analyse... Max iterations = %1 Nombre max d'itération... = %1 Alpha precision = %1 deg Précision de Alpha = %1 ° Number of stations = %1 Nombre de stations = %1 Relaxation factor = %1 Facteur de relaxation = %1 Analysis cancelled on user request.... Analyse interrompue à le demande de l'utilisateur... Calculating Alpha = %1... Calcul de Alpha = %1... ...negative Lift... Aborting ...portance négative... Interruption ...converged after %1 iterations ...convergence après %1 itérations ...unconverged after %2 iterations ...pas de convergence après %2 itérations QInf = %1 skipped after %2 iterations QInf = %1 sauté après %2 itérations Alpha = %1, skipped after %2 iterations Alpha = %1, sauté après %2 itérations Skip Sauter Cancel Abandonner Analysis completed Analyse terminée ...some points are outside the flight envelope ...certains points sont situés hors du domaine de vol ...some points are unconverged ...certains points n'ont pas convergé Close Fermer Initializing analysis... Initialisation de l'analyse... Calculating QInf = %1... Calcul de QInf = %1... ...unconverged after %1 iterations ...pas de convergence après %1 itérations LinePickerDlg OK Accepter Cancel Abandonner Style Style Width Largeur Color Couleur Line Picker Sélection des lignes MainFrame Save the project before exit ? Enregistrer le projet avant de quitter ? New Project Nouveau projet Save and close the current project, create a new project Enregistrer le projet et quitter, créer un nouveau projet Close the Project Fermer le projet Save and close the current project Enregistrer et quitter le projet en cours &Open... &Ouvrir... Open an existing file Ouvrir un fichier existant &Insert Project... Insérer un projet Insert an existing project in the current project Insérer un projet existant dans le projet en cours &Direct Foil Design Conception directe de profil Open Foil Design application Ouvrir l'application de conception de profil &XFoil Inverse Design Conception inverse de profil Open XFoil inverse analysis application Ouvrir l'application d'analyse inverse XFoil &XFoil Mixed Inverse Design Conception inverse mixte de profil Open XFoil Mixed Inverse analysis application Ouvrir l'application XFoil d'analyse inverse mixte &XFoil Direct Analysis Analyse directe XFoil Open XFoil direct analysis application Ouvrir l'application d'analyse directe XFoil &Wing and Plane Design &Conception d'aile et d'avion Open Wing/plane design and analysis application Ouvrir l'application de conception et d'analyse d'aile et d'avion About Qt À propos de Qt Save &Enregistrer Save the project to disk Enregistrer le projet sur disque Save Project As... Sauvegarder sous... Save the current project under a new name Enregistrer le projet en cours en utilisant un nouveau nom Save Options Options de sauvegarde Define the units for this project Définir les unités pour ce projet Language... Langage Restore toolbars Restaurer les barre d'outils Restores the toolbars to their original state Restaurer les barres d'outils dans leur état d'origine Save View to Image File Enregistrer la vue sous forme d'un fichier image Saves the current view to a file on disk Enregistrer la vue en cours vers un fichier sur le disque Reset Default Settings Rétablir les paramètres par défaut General Display Settings Paramètres généraux d'affichage Export Graph Exporter le diagramme Export the current graph data to a text file Exporter les données du diagramme actif dans un fichier texte Reset Graph Scales Réinitialiser les échelles du diagramme Restores the graph's x and y scales Restaurer les échelles x et y du diagramme E&xit &Quitter Exit the application Quitter l'application &Guidelines &Manuel utilisateur Show the guidelines for some help Afficher les lignes guides afin de faciliter la tâche &About &À propos Grid Options Options de grille Define the grid settings for the view Définir les paramètres de grille pour la vue Use Splines Utiliser les splines Define a foil using one B-Spline for each foil side Définir un profil à l'aide de B-Splines pour l'intrados et l'extrados Store the current splines in the foil database Enregistrer les splines actives dans la base de données des profils Splines Params Paramètres des splines Define parameters for the splines : degree, number of out points Définir les paramètres des splines : degré, nombre de points de sortie Export Splines To File Exporter les splines vers un fichier New Splines Nouvelles splines Reset the splines Réinitialiser les splines Zoom in Zoomer Zoom the view by drawing a rectangle in the client area Zoomer la vue en traçant un rectangle dans la zone cliente Reset X Scale Réinitialiser l'échelle X Resets the scale to fit the current screen width Réinitialiser l'échelle de manière à s'adapter à la largeur de l'écran Undo Défaire Cancels the last modifiction made to the splines Abandonner les dernière modification faite aux splines Redo Refaire Restores the last cancelled modifiction made to the splines Restaurer la dernière modification faite aux splines Show All Foils Afficher tous les profils Hide All Foils Cacher tous les profils Delete... Supprimer... Rename... Renommer... Export... Exporter... Show Current Foil Afficher le profil actif Hide Current Foil Cacher le profil actif Reset Y Scale Réinitialiser l'échelle Y Reset Scales Réinitialiser les échelles Resets the x and y scales to screen size Réinitialiser les échelles x et y à la taille de l'écran Zoom Less Zoom inférieur Zoom Y Scale Only Ne zoomer que l'axe Y Zoom Y scale Only Ne zoomer que l'axe Y De-rotate the Foil Annuler la rotation du profil Normalize the Foil Normaliser le profil Refine Locally Améliorer localement Refine Globally Améliorer globalement Cancels the last modification Annule la dernière modif. Restores the last cancelled modification Rétablit la dernière annulation Edit Foil Coordinates Éditer les coordonnées du profil Scale camber and thickness Modifier la cambrure et l'épaisseur Set T.E. Gap Définir la fente de bord de fuite Set L.E. Radius Définir le rayon de bord d'attaque Show LE Circle Afficher le cercle de bord d'attaque Set Flap Définir les volets Interpolate Foils Interpoler les profils Naca Foils Profils NACA Set Table Columns Colonne du tableau des profils Reset column widths Réinitialiser la largeur des colonnes Load background image Charger l’image d’arrière plan Clear background image Effacer l’image d’arrière-plan &View &Afficher F&oil &Profil &Splines &Splines Context Menu Menu contextuel Options Options Switch to the Operating point view Passer en mode visualisation des points de fonctionnement Switch to the Polar view Passer en mode visualisation des polaires Switch to stability analysis post-processing Passer en vue analyse de stabilité Switch to the 3D view Passer en vue 3D Switch to the Cp view Passer en mode visualisation des courpes de pression Define the style and color preferences for the 3D view Définir les styles et couleurs de la vue 3D Define which type of polars should be shown or hidden Définir quels types de polaires doivent être montrés ou cachés Define the scales for the 3D display of lift, moment, drag, and downwash Définir les échelles pour la portance, les moments, la traînée et les vecteurs vitesse en vue 3D Define the light options in 3D view Définir les options de luminosité en vue 3D Rename the currently selected object Renommer l'objet actif Edit Body... Éditer le fuselage Edit the body of the currently selected plane Editer le fuselage de l'avion actif Export the current plane or wing to a text file in the format required by AVL Exporter l'avion ou l'aile actif dans un fichier texte au format AVL Export the current operating point to a text or csv file Exporter le point de fonctionnement actif dans un fichier texte ou csv Reset the legend position to its default value Rétablir la position par défaut de la légende du diagramme Reset the wing scale to its default value Rétablir l'échelle de l'aile à sa valeur par défaut Scale the dimensions of the currently selected wing Redimensionner par homothétie les dimensions de l'aile active Manage objects Gérer les objets Rename or delete the planes and wings stored in the database Renommer les ailes et avion enregistrer dans la base de donnée Import a polar from a text file Importer une polaire à partir d'un fichier texte Define the inertia for the current plane or wing Définir les paramètres d'inertie pour l'aile ou l'avion actif Hide all the curves except for the one corresponding to the currently selected operating point Masquer toutes les courbes à l'exception de celle du point de fonctionnement actif Show the graph curves of all operating points Afficher les courbes pour tous les points de fonctionnement Hide the graph curves of all operating points Masquer les courbes de tous les points de fonctionnement Delete all the operating points of all planes and polars Détruire toues les points de fonctionnement des avions et polaires Show the curves of all the operating points of the currently selected polar Afficher les courbes de tous les points de fonctionnement de la polaire active Hide the curves of all the operating points of the currently selected polar Masquer les courbes de tous les points de fonctionnement de la polaire active Delete all the operating points of the currently selected polar Détruire tous les points de fonctionnement de la polaire active Show the theoretical optimal elliptic lift curve on all graphs for which the selected variable is the local lift Afficher la courve elliptique théorique pour tous les diagrammes pour lesquels la variable portance locale est sélectionnée Show XCG location Position du CG Show the position of the center of gravity defined in the analysis Afficher la position du CG définie dans l'analyse Show the graph curves for the elevator Afficher les courbes correspondant au stabilisateur horizontal Show the graph curves for the fin Afficher les courbes correspondant à la dérive Show the graph curves for the second wing Afficher les courbes correspondant à la deuxième aile Define an analysis for the current wing or plane Définir une analyse pour l'aile ou l'avion actif Modify the analysis parameters of this polar Modifier les paramètres d’analyse de cette polaire Define a Stability Analysis Analyse de stabilité Define a stability analysis for the current wing or plane Définir une analyse de stabiité pour l'aile ou l'avion actif Define Graph Settings Paramètres du diagramme Define the settings for the selected graph Définir les paramètres du graphe sélectionné Display the first two operating point graphs Afficher les deux premiers diagrammes de point de fonctionnement Display all four operating point graphs Afficher les quatres diagrammes pour les points de fonctionnement Display only the first graph Afficher seulement le premier diagramme Display only the second graph Afficher seulement le second diagramme Display only the third graph Afficher seulement le troisième diagramme Display only the fourth graph Afficher seulement le quatrième diagramme Reset the scale of the current operating point graph Rétablir les échelles par défaut du diagramme Reset the scales of all four operating point graphs Rétablir les échelles par défaut de tous les diagrammes Reset the scales of all four polar graphs Rétablir les échelles par défaut de tous les diagrammes de polaires Define the settings of all four operating point graphs Rétablir les paramètres pour les quatre diagrammes Define the settings of all four polar graphs Rétablir les paramètres pour les quatre diagrammes Hide all the polar curves associated to the currently selected wing or plane Masquer toutes les polaires associées à l'aile ou l'avion actif Show all the polar curves associated to the currently selected wing or plane Afficher toutes les polaires associées à l'aile ou l'avion actif Delete all the polars associated to the currently selected wing or plane Détruire toutes les polaires associées à l'aile ou l'avion actif Hide all the polar curves of all wings and planes Masquer toutes les polaires associées à toutes les ailes et tous les avions Show all the polar curves of all wings and planes Afficher toutes les polaires associées à toutes les ailes et tous les avions Hide all the operating point curves of the currently selected wing or plane Masquer tous les points de fonctionnement associés à l'aile ou l'avion actif Show all the operating point curves of the currently selected wing or plane afficherer tous les points de fonctionnement associés à l'aile ou l'avion actif Delete all the operating points of the currently selected wing or plane Détruire tous les points de fonctionnement associés à l'aile ou l'avion actif Delete the currently selected wing or plane Détruire l'aile ou l'avion actif Duplicate the currently selected wing or plane Dupliquer l'aile ou l'avion actif Save the currently selected wing or plane as a new separate project Sauvegarder l'aile ou l'avion actif dans un projet séparé Rename the currently selected polar Renommer la polaire active Export the currently selected polar to a text or csv file Exporter la polaire active vers un fichier texte ou csv Delete all the points of the currently selected polar, but keep the analysis settings Détruire tous les points de la polaire active, mais conserver les paramètres d'analyse Delete the currently selected polar Détruire la polaire active Delete the currently selected operating point Détruire le point de fonctionnement actif Define the settings for LLT, VLM and Panel analysis Définir les paramètres d'analyse pour la LLT, la VLM et la méthode de panneaux 3D &Analysis &Analyse Define an Analysis Définir une analyse Batch Analysis Analyse par lot Current Foil Profil actif Foil Actions Actions sur profil Foil Profil 3D Scales Échelles 3D Stability Stabilité &File &Fichier &? &? OpPoint View Vue OpPoint Polar View Vue Polaires 3D View Vue 3D Cp View Vue Cp OpPoint view Vue OpPoint Show Operating point view Afficher la vue des OpPoints Polar view Vue polaire Show Polar view Afficher la vue polaire 3D Color Preferences Préférences de couleurs 3D Show the properties of the currently selected operating point Afficher les propriétés du point de fonctionnement actuellement sélectionné Time Response Vew Vue de la réponse temporelle Root Locus View Vue du lieu des racines Switch to root locus view Aller à la vue du lieu des racines Polar Filter Filtre de polaire 3D Light Options Options d'éclairage 3D Define a New Wing Définir une nouvelle aile Shows a dialogbox for editing a new wing definition Afficher une boîte de dialogue pour éditer la définition d'une nouvelle aile Half Wing Demi-aile Define a New Plane Définir un nouvel avion Shows a dialogbox to create a new plane definition Afficher un boîte de dialogue pour définir un nouvel avion Edit... Éditer... Shows a dialogbox to edit the currently selected wing or plane Afficher une boîte de dialogue pour éditer l'aile ou l'avion actuellement sélectionné Define a New Body Définir un nouveau fuselage Shows a dialogbox for editing a new body definition Afficher une boîte de dialogue pour éditer un nouveau fuselage Edit Current Éditer le fuselage actif Export Body Definition Exporter la définition du fuselage Export a body definition to a text file Exporter la définition du fuselage vers un fichier texte Export Body Geometry Exporter la géométrie du fuselage Export a body geometry at different cross sections to a text file Exporter la géométrie du fuselage selon différentes coupes vers un fichier texte Import Body Importer un fuselage Import a body definition from a text file Importer une définition de fuselage depuis un fichier texte Manage Bodies Gérer les fuselages Manage the body list : Rename, Duplicate, Delete Gérer la liste des fuselage : Renommer, Dupliquer, Supprimer Export to AVL... Exporter en AVL... Reset Legend Position Réinitialiser la position de la légende Reset Wing Scale Réinitialiser l'échelle de l'aile Scale Wing Redimensionner l'aile Show Current OpPoint Only N'afficher que l'OpPoint actif Show All OpPoints Afficher tous les OpPoints Hide All OpPoints Cacher tous les OpPoints Delete All OpPoints Supprimer tous les OpPoints Show Associated OpPoints Afficher les OpPoints associés Hide Associated OpPoints Cacher les OpPoints associés Delete Associated OpPoints Supprimer les OpPoints associés Show Elliptic Curve Afficher la courbe elliptique Show Fin Curve Afficher la courbe de la dérive Show Second Wing Curve Afficher la courbe de la seconde aile Display the first two graphs Afficher les deux premiers diagrammes Display all four graphs Afficher les quatre diagrammes Highlight Current OpPoint Mettre en évidence l'OpPoint actif Highlights on the polar curve the currently selected operating point Mettre en évidence sur la courbe polaire le point de fonctionnement actuellement sélectionné Reset All Graph Scales Réinitialiser toutes les échelles de diagrammes All Graph Settings Tous les paramètres du diagramme Hide Associated Polars Masquer les polaires associées Show Only Associated Polars Ne montrer que les polaires associées Show Associated Polars Afficher les polaires associées Delete Associated Polars Supprimer les polaires associées Hide All Polars Masquer toutes les polaires Show All Polars Afficher toutes les polaires Duplicate... Dupliquer... Save as Project... Enregistrer sous forme de projet... Export ... Exporter... Reset ... Réinitialiser... Delete ... Supprimer... Advanced Settings... Paramètres avancés... &Wing-Plane Aile-A&vion Current UFO OVNI actif Current Body Fuselage actif &Polars Polai&res Current Polar Polaire active Graphs Diagrammes &OpPoint &OpPoint Current OpPoint OpPoint actif Current Graph Diagramme actif UFO OVNI Ready Prêt All Polar Graph Settings Paramètres de tous les diagrammes polaires Reset All Polar Graph Scales Réinitialiser les échelles de tous les diagrammes polaires Set Style... Définir le style... Delete associated polars Supprimer les polaires associées Delete all the polars associated to this foil Supprimer toutes les polaires associées à ce profil Show only associated polars Ne montrer que les polaires associées Show associated polars Afficher les polaires associées Hide associated polars Cacher les polaires associées Save associated polars Enregistrer les polaires associées Hide associated OpPoints Cacher les OpPoints associés Show associated OpPoints Afficher les OpPoints associés Delete associated OpPoints Supprimer les OpPoints associés Export associated OpPoints Exporter les OpPoints associés Defines a single analysis/polar Définir une analyse/polaire unique Launches a batch of analysis calculation for a specified range or list of Reynolds numbers Lancer un lots de calcul d'analyses pour la plage indiquée de nombre de Reynolds Multi-threaded Batch Analysis Analyse par lots multi-processeurs Launches a batch of analysis calculation using all available computer CPU cores Lancer un calcul d’analyse par lots en utilisant tous les coeurs disponibles des processeurs de l'ordinateur Delete Supprimer Deletes the currently selected polar Supprimer la polaire sélectionnée Reset Réinitialiser Deletes the contents of the currently selected polar Supprimer le contenu de la polaire active Edit Éditer Remove the unconverged or erroneaous points of the currently selected polar Supprimer les points erronés ou sans convergence de la polaire active Export Exporter Export all polars Exporter toutes les polaires Define Styles Définir les styles Define the style for the boundary layer and the pressure arrows Définir le style de la couche limite et des flèches de pression Manage Foils Gérer les profils Rename Renommer Show Panels Afficher les panneaux Show the foil's panels Afficher les profils des panneaux Reset Foil Scale Réinitialiser les dimensions du profil Resets the foil's scale to original size Réinitialiser les dimensions du profil à sa taille d'origine Show Inviscid Curve Afficher la courbe non visqueuse Display the Opp's inviscid curve Afficher les points de fonctionnement de la courbe non visqueuse Neutral Line Ligne neutre Show Current Opp Only OpPoint actif seulement Show All Opps Afficher tous les points de fonctionnement Hide All Opps Masquer tous les points de fonctionnement Reset XFoil Réinitialiser XFoil XFoil Advanced Settings Paramètres avancés de XFoil Tip : you don't want to use that option... Astuce : ne pas utiliser cette option... View Log File Afficher le fichier journal Duplicate Dupliquer Cp Variable Variable Cp Sets Cp vs. chord graph Définir le diagramme de Cp en fonction de la corde Q Variable Variable Q Sets Speed vs. chord graph Définir le diagramme de la vitesse en fonction de la corde Export Cur. XFoil Results Exporter les résultats actifs de XFoil Max. Shear Coefficient Coefficient de cisaillement maximum Bottom Side D* and Theta D* et Theta de la face inférieure Top Side D* and Theta D* et Theta de la face supérieure Log(Re_Theta) Log(Re_Theta) Re_Theta Re_Theta Amplification Ratio Rapport d'amplification Dissipation Coefficient Coefficient de dissipation Skin Friction Coefficient Coefficient de friction de la peau Edge Velocity Vélocité de bord &Foil &Profil &Design &Conception Polar Graphs Diagrammes polaires Operating Points &OpPoints Cp Graph Diagramme Cp Current XFoil Results Résultats actifs de XFoil Store Foil Enregistrer le profil Store Foil in database Enregistrer le profil dans la base de données Extract Foil Extraire un profil Extract a Foil from the database for modification Extraire un profil de la base de données pour modification Define the styles for this view Définir les styles de cette vue Resets the scale to fit the screen size Réinitialiser l'échelle pour s'adapter à la taille de l'écran Insert Control Point Insérer un point de contrôle Remove Control Point Supprimer un point de contrôle Show Q-Initial Afficher Q initiale Show Q-Viscous Afficher Q visqueux Show Points Afficher les points Show Reflected Afficher le symétrique Zoom X Scale Zoomer l'échelle X Zoom X Scale Only Ne zoomer que l'échelle X Zoom Y Scale Zoomer l'échelle Y &Graph &Diagramme Full Inverse Inverse complète Mixed Inverse Inverse mixte XInverse X inverse Question Question Error reading the file Erreur lors de la lecture du fichier A foil of that name already exists Please enter a new name Il existe déjà un profil portant ce nom Veuillez entrer un autre nom and all associated OpPoints and Polars ? et tous les OpPoints et polaires associés ? &Body &Fuselage Could not read the file Lecture du fichier impossible Save the current project ? Faut-il enregistrer le projet actuel ? Text File (*.txt);;Comma Separated Values (*.csv) Fichier texte (*.txt), valeurs séparées apr des virgules (*.csv) Open File Ouvrir le fichier Project file (*.wpa) Fichier de projet (*.wpa) Warning Attention Are you sure you want to delete Êtes vous xûr de vouloir supprimer XFLR5 file (*.dat *.plr *.wpa) Fichier XFLR5 (*.dat *.plr *.wpa) The project Le projet has been saved n'a pas été enregistré Enter the foil's new name Entrer le nouveau nom du profil Nothing to save Rien à enregistrer Your system does not provide support for OpenGL. XFLR5 will not operate correctly. Votre système ne prend pas en charge OpenGl. XFLR5 ne foncitonnera pas correctement Define the save options for operating points Définir les options de sauvegarde pour les points de fonctionnement Units... Unités Define the color and font options for all views and graphs Définir le style pour tous les graphes simultanément More information about XFLR5 En savoir plus sur XFLR5 Properties Propriétés Show the properties of the currently selected polar Afficher les propriétés de la polaire active Two Graphs Deux Diagrammes All Graphs Tous diagrammes Graph 1 Diagramme 1 Graph 2 Diagramme 2 Graph 3 Diagramme 3 Graph 4 Diagramme 4 Define Cp Graph Settings Paramètres du graphe des Cp Two Polar Graphs Deux diagrammes de polaires All Polar Graphs Tous diagrammees de polaires Cl vs. Cd Cl vs.Alpha Cl vs. Xtr. Cm vs.Alpha Glide ratio vs. alpha Finesse = f(alpha) Analysis Analyse Reset foil scale Rétablir l'échelle du profil Saved the valid part Sauvegarder la partie valide Save the Project File Enregistrer le fichier de projet XFLR5 Project File (*.wpa) Fichier de projet de XFLR5 (*.wpa) Could not open the file for writing Impossible d'ouvrir le fichier en écriture Save Image Enregistrer l'image Unidentified Operating Point Point de fonctionnement non identifié Obsolete format, cannot read Format dépassé : lecture impossible XFLR5 v6 Project File (*.wpa);;XFLR5 v5 Project File (*.*) &%1 %2 &%1 %2 Foil Error : no points Erreur de profil : pas de point Kinematic Shape Parameter Paramètre cinématique de forme Show Q-Spec Afficher Q-Spec Info Info Import Polar Importer une polaire Import XFoil Polar Importer une polaire XFoil Store Splines as Foil Enregistrer les splines en tant que profil Define the default language for the application Définir la langue par défaut de l'application Show Legend Afficher la légende Show Elevator Curve Afficher la courbe du stabilisateur horizontal Define Inertia Définir l'inertie will revert to default settings at the next session les paramètres seront réinitialisés à leur valeur par défaut lors de la prochaine session Default Settings Paramètres par défaut Are you sure you want to reset the default settings ? Êtes-vous certain de vouloir réinitialiser les paramètres à leurs valeurs par défaut ? The settings will be reset at the next session Les paramètres seront réinitialisés lors de la prochaine session Exit Quitter ManageBodiesDlg Body Management Gestion des fuselages New Nouveau Edit Éditer Rename Renommer Delete Supprimer Duplicate Dupliquer Export Definition Exporter la définition Export Geometry Exporter la géométrie Close Fermer The body Le fuselage is in use by a plane. Delete Anyhow? est utilisé par un avion. Faut-il néanmoins le supprimer ? Question Question Are you sure you want to delete the body : Étes-vous certain de vouloir supprimer ce fuselage : The modification will erase all results for the planes using this body. Continue ? La modification va effacer tous les résultats pour les avions utilisant ce fuselage. Poursuivre cependant ? Description: Description : ManageFoilsDlg Foil Management Gestion des profils Delete Supprimer Rename Renommer Export Foil Exporter le profil Close Fermer Name Nom Thickness (%) Épaisseur (%) at (%) à (%) Camber (%) Cambrure (%) Points Points TE XHinge X articulation BF TE YHinge Y articulation BF LE XHinge X articulation BA LE YHinge Position Y articulation BA Foils Profils Foil File (*.dat) Fichier de profil (*.dat) TE Flap ( Volet de bord de fuite ( LE Flap ( Volet de bord d'attaque ( ManageUFOsDlg Object Management Gestion des objets Delete Supprimer Rename Renommer Close Fermer Name Nom Span Envergure Area Surface M.A.C. C.A.M. AR Allongement TR Effilement Rt-Tip Sweep Flèche empl.-extr Tail Volume Volume de stab. UFOs OVNI Are you sure you want to delete the plane : Étes-vous certain de vouloir supprimer l'avion : Are you sure you want to delete the wing : Étes-vous certain de vouloir supprimer l'aile : Question Question Description: Description : ModDlg OK Accepter Cancel Abandonner Save as new Enregistrer comme nouveau Modification Modification NacaFoilDlg NACA Foils Profils NACA 4 or 5 digits 4 ou 5 chiffres Number of Panels Nombre de panneaux OK Accepter Cancel Abandonner Illegal NACA Number Nombre NACA non valable NewNameDlg OK Accepter Cancel Abandonner ObjectPropsDlg OK Accepter Polar Properties Propriétés de la polaire Operating Point Properties Propriétés du pt de fonctionnement PanelAnalysisDlg Warning Attention 3D Panel Analysis Analyse par panneaux 3D Solving the problem... Résolution du problème... Adding the wake's contribution... Ajout de la contribution du sillage... Computing On-Body Speeds... Calcul des vitesses sur la surface des corps... Computing Plane for alpha=%1 Calcul de l'avion pour alpha=%1 Computing Plane for QInf=%1 Calcul de l'avion pour Qinf=%1 Calculating aerodynamic coefficients... Calcul des coefficients aérodynamiques... Creating source strengths... Calculating aerodynamic coefficients in the far field plane Calcul des coefficients aerodynamiques en champ éloigné Calculating point Calcul du point Calculating wing... Calcil de l'aile... Calculating body... Calcul du fuselage... Type 1 - Fixed speed polar Type 1 Polaire à vitessse constante Type 2 - Fixed lift polar Type 2 Polaire à portance constante Type 4 - Fixed angle of attack polar Type 4 Polaire à angle d'attaque constant Type 7 - Stability polar Type 7 Polaire de stabilité Performing asymmetric calculation : Exécution des calculs asymétriques : Counted %1 panel elements %1 éléments de panneaux ont été dénombrés Relaxing the wake... Relaxation du sillage... Singular Matrix.... Aborting calculation... Matrice singulière.... Interruption du calcul... Cancel Abandonner Found a negative lift for Alpha=%1.... skipping the angle... Portance négative trouvée pour Alpha=%1.... angle sauté... Performing symmetric calculation Exécution d'un calcul symétrique Solving the problem... Résolution du problème... Launching 3D Panel Analysis.... Lancement de l'analyse des Panneaux 3D.... Launching VLM1 Analysis.... Lancement de l'analyse VLM1... Launching VLM2 Analysis.... Lancement de l'analyse VLM2... Using Dirichlet boundary conditions Using Neumann boundary conditions Utilisation des conditions aux limites de Neumann Warning: The wing and elevator lie in the same plane z= Avertissement : L'aile et le stabilisateur sont dans le même plan défini par z = It is recommended to slightly offset the wing or the elevator to avoid numerical instabilities Il est recommandé de décaler légèrement l'aile ou le stabilisateur Panel Analysis completed successfully L'analyse des panneaux s'est terminée avec succès Panel Analysis completed ... Errors encountered Analyse des panneaux terminée ... Des erreurs ont été rencontrées Close Fermer Processing Alpha= %1 Traitement de Alpha= %1 Wake iteration %1 Itération de sillage %1 PertDlg Restore Restaurer Apply Appliquer OK Accepter Cancel Abandonner Cn List Liste Cn Pertubation Dialog Dialogue de perturbation PlaneDlg Warning Attention Save the changes ? Enregistrer les modifications ? OK Accepter Cancel Abandonner Total number of VLM panels =%1 Max Number =%2 A reduction of the number of VLM panels is required Nombre total de panneaux VLM =%1 Nombre maxi =%2 Il faut réduite le nombre de panneaux VLM Total number of wing panels =%1 Max Number =%2 A reduction of the number of wing panels is required Nombre total de panneaux d'aile =%1 Nombre max =%2 Il faut réduire le nombre de panneaux d'aile Question Question Plane Name Nom de l'avion Define Définir Import Importer Export Exporter Tilt Angle= Angle de calage = Main Wing Aile principale Biplane Biplan Wing 2 Aile 2 Elevator Stabilisateur horizontal Fin Dérive Double Fin Double dérive Body Fuselage Warning: Including the body in the analysis is not recommended. Check the guidelines for explanations. Avertissement: Inclure le fuselage dans l'analyse est déconseillé. Se référer aux guidelines pour plus d'explications. Edit... Éditer... Wing Area = Surface alaire = Wing Span = Envergure de l'aile = Elev. Area = Surface du stabilisateur = Elev. Lever Arm = Bras de levier du stab = TailVolume = Volume de stab. = Total Panels = Nombre total de panneaux = Plane Editor Éditeur d'avion Fin Area = Aire de la dérive = x= x = z= z = y= y = Enter here a short description for the plane Entrez ici une courte description de l'avion Description: Description : Plane Description Description de l'avion Plane Inertia Inertie de l'avion Two-sided Fin Dérive composée de deux surfaces PolarFilterDlg Polar Filter Filtre des polaires Show polar types Afficher les types de polaires Type 1 Type 1 Type 2 Type 2 Type 3 Type 3 Type 4 Type 4 Type 5 Type 5 Type 6 Type 6 Type 7 Type 7 OK Accepter Cancel Abandonner ProgressDlg Progress Avancement Cancel Abandonner QAFoil Warning Attention Spline foil Profile en spline Name Nom Thickness (%) Épaisseur (%) at (%) à (%) Camber (%) Cambrure (%) Points Points TE Flap ( Volet de bord de fuite ( TE XHinge Position X articulation BF TE YHinge Position Y articulation BF LE Flap ( Volet de bord d'attaque ( LE XHinge Position X articulation BA LE YHinge Position Y articulation BA Foil has been de-rotated by %1 degrees Le profil a été pivoté de %1 degrés Foil has been normalized from %1 to 1.000 Le profil a été normalisé de %1 à 1.000 At least two foils are required Il faut au moins deux profils Export Foil Exporter le profil Foil File (*.dat) Fichier de profil (*.dat) Spline Foil Profile en spline Too many output points on upper surface Max =%1 Trop de points de sortie à la surface supérieure Max = %1 Too many output points on lower surface Max =%1 Trop de point de sortie à la surface inférieure Max = %1 Export Splines Exporter les splines Text File (*.dat) fichier texte (*.dat) X-Scale = %1 Échelle X = %1 Y-Scale = %1 Échelle Y = %1 x = %1 x = %1 y = %1 y = %1 Show Afficher Centerline Courbure Style Style Open Image File Ouvrir un fichier image The minimum number of control points has been reached for this spline degree Le nombre minimum de point de contrôle a été atteint pour ce degré de spline Question Question Discard changes to Splines ? Abandonner les modifications des splines ? Foils Profils QMiarex Cd Cx Cl Cz Alpha Alpha x x Cp Cp Real Réel Imag/2.pi Imag/2.pi Warning Attention Not enough memory to store the OpPoint Mémoire insuffisante pour enregistrer l'OpPoint The modification will erase all results associated to this Plane. Continue ? La modification va supprimer toues les résultats associés à cet avion. Poursuivre néanmoins ? Induced Angle Angle induit Total Angle Angle total Local lift Portance locale Airfoil drag Traînée de profil Induced drag Traînée induite Total drag Traînée totale Local drag Traînée locale Cm Airfoil Cm du profil Cm Cm Re Re Top Trans x-Pos % % x pos. transition sup. Bot Trans x-Pos % % x pos. transition inf. CP x-Pos % Pos x CP % BM ( Point is out of the flight envelope Le point se trouve en dehors de l'enveloppe de vol Time = Temps = Cl = Cl = Cm = Cm = ICn = %1 PCn = %2 ICn = %1 PCn = %2 ICn=, %1,PCn=, %2 ICn=, %1,PCn=, %2 Alpha = %1 Alpha = %1 Efficiency = %1 Rendement = %1 Cl/Cd = %1 Cz/Cx = %1 GCm = %1 GCm = %1 Please define a wing or a plane object before running a calculation Veuillez définir un objet aile ou avion avant de lancer un calcul Please define an analysis/polar before running a calculation Veuillez définir une analyse et une polaire avant de lancer un calcul Could not find the wing's foil Profil de l'aile introuvable ... Aborting Calculation ... Abandon des calculs Control polars are not supported in XFLR5 v6. Please use stability polars instead. Les polaires de contrôle ne sont plus maintenues dans la v6.\nUtiliser les polaires de stabilité à la place. Are you sure you want to delete the plane : Êtes-vous certain de vouloir supprimer l'avion : Are you sure you want to delete the wing : Êtes-vous certain de vouloir supprimer l'aile : Question Question Are you sure you want to delete the polar : Êtes-vous certain de vouloir supprimer la polaire : The modification will erase all results for the planes using this body. Continue ? La modification va effacer tous les résultats pour les avions qui utilisent ce fuselage. Poursuivre néanmoins ? The modification will erase all results associated to this Wing. Continue ? La modification va effacer tous les résultats associés à cette aile. Poursuivre néanmoins ? Export Wing OpPoint Exporter l'OpPoint de l'aile Text File (*.txt);;Comma Separated Values (*.csv) Fichier texte (*.txt), valeurs séparées par des virgules (*.csv) Cd = %1 ICd = %2 PCd = %3 Cx = %1 ICx = %2 PCx = %3 Cd=,%1,ICd=, %2,PCd=, %3 Cx=,%1,ICx=, %2,PCx=, %3 Bend. = Flexion = Flap Volet Cm total Cm total Wing Polar Graph 1 Diagramme polaire 1 de l'aile Wing Polar Graph 2 Diagramme polaire 2 de l'aile Wing Polar Graph 3 Diagramme polaire 3 de l'aile Wing Polar Graph 4 Diagramme polaire 4 de l'aile Cp Graph Diagramme Cp Are you sure you want to delete the polars associated to : Êtes-vous certain de vouloir supprimer les polaires associées à : XCP = %1 YCP = %2 ZCP = %3 XCP = %1 YCP = %2 ZCP = %3 XNP = %1 XNP = %1 XNP=, %1 XNP=, %1 Main Wing Cp Coefficients Coefficients Cp de l'aile principale Wing Cp Coefficients Coefficients Cp de l'aile Panel CtrlPt.x CtrlPt.y CtrlPt.z Cp Panneau CtrlPt.x CtrlPt.y CtrlPt.z Cp Panel,CtrlPt.x,CtrlPt.y,CtrlPt.z,Cp Panneau,CtrlPt.x,CtrlPt.y,CtrlPt.z,Cp Cp Coefficients Coefficients Cp Strip %1 Bande %1 Export Polar Exporter la polaire Export UFO Exporter l'OVNI AVL Text File (*.avl) Fichier texte AVL (*.avl) Project Projet Open File Ouvrir le fichier UFO Polar Format (*.*) Format de polaire d'OVNI (*.*) Could not read the file Impossible de lire le fichier No UFO with the name Aucun OVNI portant ce nom could be found. The polar(s) will not be stored n'a pu être trouvé. Les polaires ne seront pas enregistrées Enter the new name for the wing polar : Enter le nouveau nom pour la polaire de l'aile : Are you sure you want to reset the content of the polar : Êtes-vous certain de vouloir réinitialiser le contenu de la polaire : abcdefghijklmnopqrstuvwxyz012345678 abcdefghijklmnopqrstuvwxyz012345678 abcdefghijklmnopqrstuvwxyz01234567 abcdefghijklmnopqrstuvwxyz01234567 V = %1 V = %1 No unit defined for speed... Pas d'unité définie pour la vitesse... Lift Coef. = %1 Coef. de portance. = %1 Drag Coef. = %1 Coef. de traînée. = %1 Rolling Moment Coef. = %1 Coef. de moment de roulis = %1 Induced Moment Coef = %1 Coef. de moment induit = %1 Profile Yawing Moment = %1 Moment de lacet du profil = %1 Flap %1 Moment =%2 Moment du volet %1 = %2 Top transition Transition supérieure Bottom transition Transition inférieure Centre of Pressure Centre de pression Moment ref. location Emplacement du centre de gravité Enter the new name for the Body : Entrez un nouveau nom pour le fuselage : The body Le fuselage is used by one or more planes. Overwrite anyway ? (Results will be lost) est utilisé par au moins un modèle. L'écraser cependant ? (Les résultats seront perdus) Enter the new name for the Plane : Entrer un nouveau nom pour l'avion : Enter the new name for the wing : Entrez un nouveau nom pour l'aile : Enter the new name for the Polar: Entrer le nouveau nom de la polaire : Sequence Séquence Start= Départ= End= Fin= D= D= Init LLT Initialisation LLT Store OpPoint Enregistrer l'OpPoint Analyze Analyser Analysis settings Paramètres d'analyse Lift Portance Ind. Drag Traînée induite Visc. Drag Traînée visq. Trans. Transition Moment Moment Downw. Déflexion Surf. Vel. Vitesse en surf. Stream Lignes de courant Animate Animer Display Afficher Polar properties Propriétés de la polaire Curve Courbe Points Points item Élément Style Style Width Largeur Color Couleur Curve settings Paramètres de la courbe Span Position Position sur l'envergure Keep Conserver Reset Réinitialiser Cp Sections Sections Cp Activate the button, then click on the object to center it in the viewport; alternatively, double click on the object Activer le bouton, cliquer ensuitre sur l’objet pour le centrer dans la vue ; vous pouvez aussi faire un double-clic sur l’objet VCD VCD ICD ICD CD CD Cn Cn VCn VCn ICn ICn CL/CD CZ/CX CL^(3/2)/CD CZ^(3/2)/CX 1/Rt(CL) 1/Rt(CZ) Fx (N) Fx (N) Fx (lbf) Fx (lbf) Fy (N) Fy (N) Fy (lbf) Fy (lbf) Fz (N) Fz (N) Fz (lbf) Fz (lbf) Pitching Moment Moment de tangage Rolling Moment Moment de roulis Yawing Moment Moment de lacet Wing Span = Envergure = Current Plane Avion actif Current Wing Aile active Current Object Objet actif The total number of panels is %1. The Max Number is %2. A reduction of the number of panels is required Le nombre total de panneaux es %1. Le nombre maximum est %2. Une réduction du nombre de panneaux est nécessaire The modification will erase all polar results associated to this Plane. Continue ? Cette modification va effacer tous les résultats des polaires associés à cet avion. Faut-il poursuivre cependant ? xyProj. Span = Envergure projetée = Wing Area = Aire de l'aile = xyProj. Area = Aire projetée = Plane Mass = Masse de l’appareil = Wing Load = Charge ailaire = Tail Volume = Volume de stab. = Root Chord = Corde d'emplanture = MAC = C.A.M. = TipTwist = Vrillage au saumon = Aspect Ratio = Allongement = Taper Ratio = Effilement = Root-Tip Sweep = Flèche moyenne = Panel Forces Forces sur panneaux Display the force 1/2.rho.V2.S.Cp acting on the panel Visualiser la force 1/2.rho.V2.S.Cp agissant sur le panneau Results Résultats XCP=, %1, YCP=, %2, ZCP=, %3 XCP=, %1, YCP=, %2, ZCP=, %3 Axes Axes Light Éclairage Surfaces Surfaces Outline Contour Panels Panneaux Foil Names Nom des profils Vortices Tourbillons Masses Masses X View X View Y View Vue Y Z View Vue Z Iso View Vue ISO Pick Center Choisir le centre Clip: Tronquer : CL CZ VCm VCm ICm ICm Vx Vx Vz Vz V V Gamma Gamma XCP XCP YCP YCP BM BM m.g.Vz (W) m.g.Vz (W) Efficiency Rendement (XCp-XCG)/MAC(%) (XCp-XCG)/CAM(%) ctrl ctrl CY CY XNP XNP Ph. Freq(Hz) Fréq Ph. (Hz) Ph. Damping Amortiss. Ph. SP Freq (Hz) Fréqu. mode d'incidence (Hz) SP Damping Amortis. mode d'incidence DR Freq(Hz) Fréq. roulis hol. (Hz) DR Damping Amort. roulis hol. Roll Damping Amort. mode roulis Spiral Damping Amortis. mode spirale OpenGL color format is not recognized... Sorry Les formats de couleur OpenGL ne sont pas reconnus... Désolé Cannot (yet ?) save 8 bit depth opengl screen images... Sorry Il n'est pas (encore) possible d'enregistrer des recopies d'écran opengl sur 8 bits. Désolé... Cannot (yet ?) save 16 bit depth opengl screen images... Sorry Il n'est pas (encore) possible d'enregistrer des recopies d'écran opengl sur 16 bits. Désolé... Unidentified bit depth... Sorry Profondeur de bits non identifiée. Désolé.... QObject Re Re Mach Mach CL CZ CD CX Cm Cm Cdp Cxp Cpmn XCP XCP Top Transition Transition sup. Bot Transition Transition inf. T.E. Flap moment Moment de volet de bord de fuite L.E. Flap moment Moment de volet de bord d’attaque Type Type Fixed speed Vitesse fixée Fixed lift Portance fixée Fixed angle of attack Angle d'attaque fixé Reynolds number Nombre de Reynolds Mach number Nombre de Mach Re.Cl Re.Cz Cd Cx Cd x 10000 Cx x 10000 Xtr1 Xtr1 Xtr2 Xtr2 HMom HMom Cpmin Cpmin Cl/Cd Cz/Cx |Cl|^(3/2)/Cd |Cz|^(3/2)/Cx 1/Rt(Cl) 1/Rt(Cz) XCp XCp Alpha Alpha NCrit NCrit Forced top trans. Position de transition forcée sur extrados Forced bottom trans. Position de transition forcée sur intrados Number of data points Nombre de points Re List Liste de Re Foil coordinates Coordonnées du profil X X Y Y i i Cn Cn Ci Cz dihedral dièdre twist vrillage foil profil X-panels Panneaux X X-dist Dist. X Y-panels Panneaux Y Y-dist Dist. Y Wing definition Définition de l'aile Wing Aile 2nd Wing 2ème aile Elevator Stabilisateur horizontal Fin Dérive Plane Name Nom de l'avion Spline Foil Profile en spline Description %1 Description %1 Wing Name Nom de l'aile Could not open the file for reading Fichier non lisible Total number of wing sections exceeds MAXSPANSECTIONS. Wing will be truncated. Nombre excessif de sections d'aile Unable to import wing definition Echec de l'import d'aile Could not open the file for writing Impossible d'ouvrir le fichier en écriture Span pos = %1 pos. sur l’envergure = %1 , Cl = %1 could not be interpolated , Cz = %1 n'a pas pu être interpolé , Cl = %1 is outside the flight envelope , Cz = %1 se trouve hors du domaine de vol Warning: High does not work well on rotated foils Attention : High ne fonctionne pas bien avec les profils pivotés Current chordline angle: %1 proceeding anyway... Angle actuel de la ligne de corde : %1 Poursuite cependant... The max number of polar points has been reached Le nombre maximum de polaires est atteint Export Body Definition Exporter la définition du fuselage Text Format (*.txt) Format texte (*.txt) Export Body Geometry Exporter la géométrie du fuselage Text File (*.txt);;Comma Separated Values (*.csv) Fichier texte (*.txt);;Format CSV (*.csv) Choose the length unit to read this file : Choisir l'unité de longueur pour lire ce fichier : Open File Ouvrir le fichier All files (*.*) Tous les fichiers (*.*) Could not read the file Impossible de lire le ficher Warning Attention Multiple file loading only available for airfoil files. Non *.dat files will be ignored. Chargement multiple de fichiers autorisé seulement pour les profils. Body Name Nom du fuselage Error reading Erreur de lecture Frames have different number of side points Les cadres ont un nombre de points par face différent Please select a Frame before inserting a point Veuillez sélectionner un cadre avant d'insérer un point Stability analysis Analyse de stabilité VInf = VInf = Alpha = Alpha = LLT LLT 3D-Panels Panneaux 3D 3D-Panels/VLM1 Panneaux 3D/VLM1 3D-Panels/VLM2 Panneaux 3D/VLM2 VInf VInf Mass Masse Control value Valeur du paramètre XNP XNP YCP YCP ZCP ZCP VCD VCX ICD ICX CX CY CY Cl Cz ICm ICm VCm VCm ICn ICn VCn VCn Non-dimensional Stability Derivatives: Dérivées de stabilité adimensionnelles CXu CLu Cmu CXa CLa Cma CXq CLq Cmq CYb Clb Cnb CYp Clp Cnp CYr Clr Cnr Non-dimensional Control Derivatives: Dérivées de contrôle adimensionnelles CXd CYd CZd Cld Cmd Cnd CL/CD CZ/CX CL^(3/2)/CD CZ^(3/2)/CX 1/Rt(CL) 1/Rt(CZ) Fx (N) Fx (N) Fx (lbf) Fx (lbf) Fy (N) Fy (N) Fy (lbf) Fy (lbf) Fz (N) Fz (N) Fz (lbf) Fz (lbf) Vx Vx Vz Vz V V Gamma Gamma Pitching Moment Moment de tangage Rolling Moment Moment de roulis Yawing Moment Moment de lacet XCP XCP YCP YCP ZCP ZCP BM BM m.g.Vz (W) m.g.Vz (W) Efficiency Rendement ctrl ctrl Ph. Freq(Hz) Fréq Ph. (Hz) Ph. Damping Amortiss. Ph. SP Freq (Hz) Fréqu. mode d'incidence (Hz) SP Damping Amortis. mode d'incidence DR Freq(Hz) Fréq. roulis hol. (Hz) DR Damping Amort. roulis hol. Roll Damping Roulis amorti Spiral Damping Mode spiral CoG.x CG.x CoG.z CG.z B.C. = Dirichlet Cond. limites = Dirichlet B.C. = Neumann Cond. limites = Neumann Analysis type Type d'analyse Viscous Visqueux Inviscid Non visqueux Body option Option fuselage Body Panels Ignored Panneaux de fuselage omis Ref. Area = Aire de référence = Data points Points de données Beta Beta Planform area Aire développée Projected area Aire projetée Tilted geometry Géométrie inclinée Ground height Hauteur au sol Density = Densité = Viscosity = Viscosité = iblpan : *** bl array overflow iblpan : *** débordement du tableau bl CpCalc: local speed too larger Compressibility corrections invalid CpCalc : vitesse locale trop élevée Les corrections de compressibilité ne sont pas valables Calculating unit vorticity distributions ... ...Calcul des circulations unitaires Increase IVX to at least %1 Augmenter IVX à au moins %1 *** iblsys: bl system array overflow. *** *** iblsys: débordement du tableau système bl. *** Unrecognized foil format Format inconnu ... Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid ...Paramètres d'analyse incorrects CpCalc : vitesse locale trop élevée Les corrections de compressibilité ne sont pas valables mrchdu: convergence failed at %1 , side %2, res =%3 mrchdu : échec de la convergence à %1, face %2, res =%3 Side %1 ... Face %1 ... mrchue: inverse mode at %1 hk =%2 mrchue : mode inverse à %1 hk =%2 mrchue: convergence failed at %1, side %2, res = %3 mrchue : échec de la convergence à %1, face %2, res = %3 mrcl: illegal Re(cls) dependence trigger, Setting fixed Re mrcl: illegal Mach(cls) dependence trigger Setting fixed Mach mrcl: Cl too low for chosen Mach(Cl) dependence mrcl : Cz trop faible pour la dépendance Mach(Cz) choisie artificially limiting mach to 0.99 limitation artificielle du nombre de mach à 0.99 mrcl: cl too low for chosen Re(Cl) dependence mrcl : Cz trop faible pour la dépendance Re(Cz) choisie artificially limiting Re to %1 limitation artificielle de Re à %1 PanGen: buffer airfoil not available. PanGen : pas de profil en mémoire Paneling convergence failed. Continuing anyway... Échec de convergence de la mise en panneaux. Poursuite cependant... Panel: Too many panels. Increase IQX Panel : trop de panneaux, augmentez IQX Calculating source influence matrix ... Création de la matrice source d'influence... Initializing bl ... Initialisation de la couche limite... setbl: xtr??? n1=%1 n2=%2: Side %1, forced transition at x/c = %2 %3 Face %1, transition forcée à x/c = %2 %3 Side %1, free transition at x/c = %2 %3 Face %1, transition libre à x/c = %2 %3 scheck: bad value for small panels (stol > 0.3) scheck : valeur incorrecte pour les petits panneaux (stol > 0.3) setexp: cannot fill array. n too small setexp : impossible de remplir le tableau, n est trop faible Setexp: Convergence failed. Continuing anyway ... Setexp : Échec de la convergence. Poursuite cependant ... Sinvrt: spline inversion failed, input value returned Sinvrt : échec de l'inversion de la spline, la valeur d'entrée a été retournée Specal: MInf convergence failed Specal : échec de la convergence de MInf Speccl: cl convergence failed Speccl: échec de la convergence de Cz splind: array overflow, increase nmax splind: débordement du tableau, augmenter nmax stfind: Stagnation point not found. Continuing ... stfind : Point de stagnation non trouvé. Poursuite ... trchek2 - n2 convergence failed trchek2 - échec de la convergence de n2 *** stagnation point is past trip on side %1 *** le point de stagnation point se trouve après la transition sur la face %1 Calculating wake trajectory ... Calcul de la trajectoire du sillage ... XYWake: array size (IWX) too small. Last wake point index reduced. XYWake : dimensions du tableau (IWX) trop faibles. L'index du dernier point de sillage a été réduit. Wing Span = %1 Envergure de l'aile = %1 XYProj. Span = %1 Envergure projetée = %1 X_CG = %1 X_CG = %1 Wing Area = %1 Surface alaire = %1 XYProj. Area = %1 Surface projetée = %1 Plane Mass = %1 Masse de l'avion = %1 Wing Load = %1 Charge alaire = %1 Tail Volume = %1 Volume de stab. = %1 Root Chord = %1 Corde d'emplanture = %1 M.A.C. = %1 C.A.M. = %1 Tip Twist = %1 Vrillage au saumon = %1 Aspect Ratio = %1 Allongement = %1 Taper Ratio = %1 Effilement = %1 Root-Tip Sweep = %1 Flèche = %1 Point is out of the flight envelope Le point se trouve en dehors de l'enveloppe de vol V = %1 V = %1 Alpha = %1 Alpha = %1 Sideslip = %1 Dérapage = %1 Bank = %1 Roulis = %1 Control pos. = %1 Pos. contrôle = %1 CL/CD = %1 CZ/CX = %1 CL = %1 CZ = %1 mesh panels panneaux CD = %1 CX = %1 Efficiency = %1 Rendement = %1 Cl = %1 Cz = %1 Cm = %1 Cm = %1 Cn = %1 Cn = %1 X_NP = %1 X_NP = %1 X_CP = %1 X_CP = %1 X_CG = %1 X_CG = %1 Point Point x x y y Upper side points Points d'extrados Lower side points Points d'intrados Span pos = %1 Position envergure = %1 , A+Ai+Twist = %1 could not be interpolated , A+Ai+Twist = %1 is outside the flight envelope Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid Cl = %1 Cz = %1 ...converged after %1 iterations ...convergence après %1 itérations ...unconverged after %1 iterations ...pas de convergence après %1 itérations Continuous foils for surface do not have the same initial flap angle... aborting Les profils continus de la surface n'ont pas le même angle initial... Abandon QXDirect Warning Attention abcopy: buffer airfoil not available abcopy : tampon du profil non disponible Target segment cannot include stagnation point in mixed-inverse Le segment cible ne peut comporter de point de stagnation dans le mode inverse mixte Cp Cp Q Q Top Dessus Bot Dessous Max Shear Cisaillement maximum Top Shear Cisaillement supérieur Top Shear eq Eq. cisaillement supérieur Bot Shear Cisaillement inférieur Bot Shear eq Eq. cisaillement inférieur Question Question Are you sure you want to delete polars and OpPoints Êtes-vous certain de vouloir supprimer les polaires et les OpPoints associated to associés à The foil has been de-rotated by %1 degrees Le profil a été pivoté de %1 degrés Export Current XFoil Results Exporter les résultats actuels de XFoil Text File (*.txt);;Comma Separated Values (*.csv) Fichier texte (*.txt), valeurs séparées par des virgules (*.csv) Export Directory Répertoire d'exportation Export Foil Exporter le profil Foil File (*.dat) Fichier de profil (*.dat) Export OpPoint Exporter l'OpPoint Export Polar Exporter la polaire At least two foils are required Il faut au moins deux profils The foil has been normalized from %1 to 1.000 Le profil a été normalisé de %1 à 1.000 Polar File Fichier de polaire Polar File (*.plr) Fichier de polaire (*.plr) TE Hinge Moment/span = 123456789 Moment de l'articulation de BA / envergure = 123456789 Polar Type = %1 Type de polaire = %1 Forced Upper Trans. = %1 Transition sup forcée = %1 Forced Lower Trans. = %1 Transition sup forcée = %1 Cl = %1 Cz = %1 Cm = %1 Cm = %1 Cd = %1 Cx = %1 L/D = %1 Z/X = %1 Upper Trans. = %1 Transit. sup.. = %1 Lower Trans. = %1 Transit. inf.. = %1 TE Hinge Moment/span = %1 Moment de l'articulation de BA / envergure = %1 LE Hinge Moment/span = %1 Moment de l'articulation de BF / envergure = %1 Alpha Alpha Cl Cz Cd Cx Cd x 10000 Cx x 10000 Cdp Cxp Cm Cm Xtr1 Xtr1 Xtr2 Xtr2 HMom HMom Cpmin Cpmin Cl/Cd Cz/Cx |Cl|^(3/2)/Cd |Cz|^(3/2)/Cx 1/Rt(Cl) 1/Rt(Cz) Re Re XCp XCp Sequence Séquence Start= Départ= End= Fin= D= D= Viscous Visqueux Init BL Init couche limite Store Opp Enregistrer l'OpPoint Analyze Analyser Analysis settings Paramètres d'analyse Show BL Afficher la couche limite Show Pressure Afficher les pressions Animate Animer Display Afficher Curve Courbe Points Points Graph Curve Settings Paramètres de la courbe du diagramme Are you sure you want to delete the polar : Êtes-vous certain de vouloir supprimer la polaire : Are you sure you want to delete the Operating Point Êtes-vous certain de vouloir supprimer le point de fonctionnement and all the associated OpPoints ? et les OpPoints associés ? Open File Ouvrir le fichier XFoil Polar Format (*.*) Format de polaire XFoil (*.*) Could not read the file Lecture du fichier impossible No Foil with the name Aucun profile ayant le nom could be found. The polar(s) will not be stored n'a pu être trouvé. Les polaires ne seront pas enregistrées JavaFoil Polar Format (*.*) Format de polaire JavaFoil (*.*) Thickness = %1 Épaisseur = %1 Max. Thick.pos. = %1 Position de l'épaisseur max. = %1 Max. Camber = %1 Cambrure max = %1 Max. Camber pos. = %1 Position de cambrure max. = %1 Number of Panels = %1 Nombre de panneaux = %1 Flap Angle = %1 Angle de volet = %1 XHinge = %1 X articulation = %1 YHinge = %1 Y articulation = %1 Alpha = %1 Alpha = %1 Polar properties Propriétés de la polaire Style Style Width Largeur Color Couleur X X Cp Graph Diagramme Cp Polar Graph Diagramme polaire Cm Graph Diagramme Cm Cz Graph Diagramme Cz Tr Graph Diagramme Tr User Graph Diagramme utilisateur Not enough threads available for multithreading Nombre de processeurs insuffisant pour faire un traitement multi-processeurs Cf Cf Cd' Cx' Top Side Face supérieure x Hk Ue/Vinf Cf Cd A/A0 D* Theta CTq x Hk Ue/Vinf Cf Cx A/A0 D* Theta CTq x,Hk,Ue/Vinf,Cf,Cd,A/A0,D*,Theta,CTq x,Hk,Ue/Vinf,Cf,Cx,A/A0,D*,Theta,CTq Enter the new name for the foil polar : Enter le nouveau nom pour la polaire du profil : Re.sqrt(Cl) = Re.sqrt(Cz) = M.sqrt(Cl) = %1 M.sqrt(Cz) = %1 Bottom Side Surface inférieure QXInverse x/c x/c Q/Vinf Q/Vinf Must mark off target segment first Il faut d'abord démarquer du segment cible Converged Convergé Unconverged Non convergé Modified Modifié Warning Attention Unrecognized foil format Format de profil inconnu The minimum number of control points has been reached for this spline degree Le nombre minimum de points de contrôle a été atteint pour ce degré de spline Drag points to modify splines, Apply, and Execute to generate the new geometry Glissez les points pour modifier les splines. Appliquer et Exécuter pour créer la nouvelle géométrie Mark target segment for modification Marquer le segment cible à modifier Mark spline endpoints Marquer les points d'extrémité de la spline Alpha = Alpha = Cl = Cz = Mark target segment for smoothing, or type 'Return' to smooth the entire distribution Marquer pour lissage le segment cible ou pressez Entrée pour lisser toute la distribution Alpha = %1 Alpha = %1 Cl = %1 Cz = %1 Q - Reference Q - Référence Q - Specification Q - Spécification Q - Viscous Q - Visqueux Reflected Réfléchi Alpha Alpha Cl Cz Specification Spécification ShowSpline Afficher spline Tangent Spline Spline tangente New Spline Nouvelle spline Apply Spline Appliquer la spline Reset QSpec Réinitialiser QSpec Pert Perturbation Modification Modification Smooth QSpec Lisser QSpec Hannig Filter Filtre de Hannig Filter parameter Paramètres du filtre T.E. Angle Angle du bord de fuite T.E. Gap dx/c dx/c de la fente de BF T.E. Gap dy/c dy/c de la fente de BF Symmetric foil Profil symétrique Constraints Contraintes Execute Exécuter Cl = Cz = Mark for modification Marquer comme devant être modifié End Point Constraint Contrainte du point de fin Smooth Lisser Max Iterations Nombre maximum d'itérations Foil Profil Base Base Mod. Mod. Thickness = %1% Épaisseur = %1% Max.Thick.pos. = %1% Position de l'épaisseur max. = %1% Max. Camber = %1% Cambrure max = %1% Smoothing Lissage Q Graph Diagramme Q ReListDlg Insert Insérer Delete Supprimer OK Accepter Cancel Abandonner Reynolds Number List Liste des nombres de Reynolds RenameDlg Enter the new name Entrer le nouveau nom OK Accepter Cancel Abandonner Overwrite Écraser Warning Attention Must enter a name Il faut entrer un nom Rename Renommer Existing Names: Noms existants : Do you wish to overwrite Voulez-vous écraser Question Question Enter a name Entrer un nom Note : Overwrite will delete Opps and reset polars Note : écraser va supprimer les points de fonctionnement et réinitialiser les polaires SaveOptionsDlg Save Options Enregistrer les options Save: Enregistrer : Foil Operating Points Points de fonctionnement du profil Wing and Plane Operating Points Points de fonctionnement de l'avion et de l'aile OK Accepter Cancel Abandonner SplineCtrlsDlg Spline Parameters Paramètres de la spline Upper side Face supérieure Lower side Face inférieure Spline degree Ordre de la spline Output Sortie Symetric foil Profil sylétrique Point Weight = Poids du point = OK Accepter Cancel Abandonner Warning Attention The spline degree must be less than the number of control points Le degré de cette spline doit être inférieur au nombre de points de contrôle StabPolarDlg Stability Polar Definition Définition de la polaire de stabilité Control Name Nom du contrôle Controls Contrôles Wing Tilt ( Inclinaison de l'aile ( Elevator Tilt Inclinaison du stab Wing Flap angle %1 Angle %1 du volet de l'aile Elevator Flap %1 Volet %1 de la profondeur Fin Flap %1 Use plane inertia Utiliser l'inertie de l'avion VLM VLM 3D Panels Panneaux 3D Mix 3D Panels/VLM Mixte panneaux 3D/VLM Warning Attention Mass must be non-zero for type 7 polars La masse doit être non nulle pour les polaires de type 7 Must enter a name Il faut entrer un nom Wing Name Nom de l'aile Auto Analysis Name Nom automatique pour la polaire Polar Name Nom de la polaire b = f = Viscous Analysis Analyse visqueuse Note : the analysis may be of the viscous type only if all the flap controls are inactive Note : l’analyse ne peut être de type visqueux que si toutes les commandes de volets sont inactives Plane and Flight Data Données de l'appareil et du vol Unit Unités International International Imperial Impérial Ignore Body Panels Ignorer les panneaux de fuselage Note: + sign means trailing edge down Note: le signe + signifie un bord de fuite qui s'abaisse Gain Gain Aerodynamic Data Données aérodynamiques Wing Planform Area Surface projetée de l'aile Wing Planform Area projected on xy plane Surface de l'aile projetée sur le plan xy Reference Area for Aero Coefficients Aire de référence pour les coef. aérodynamiques Wing analysis methods Méthodes d'analyse Plane analysis methods Méthodes d'analyse OK Accepter Cancel Abandonner StabViewDlg Stability View Params Paramètres de la vue de stabilité Longitudinal Longitudinal Lateral Latéral Stability direction Direction de stabilité Initial Conditions Response Réponse à conditions initiales Forced Response Réponse forcée Initial conditions Conditions initiales Modal Response Réponse modale Modal response Réponse modale Define the total time range for the graphs Définir la durée totale pour les diagrammes Define the time step for the resolution of the differential equations Définir l'incrément de temps pour la résolution des équations différentielles Re-calculate the currently selected curve with the user-specified input data Récalculer la courbe avec les nouvelles données d'entrée Add a new curve to the graphs, using the current user-specified input Ajouter une nouvelle courbe au diagramme, en utilisant les données d'entrée courantes Rename the currently selected curve Renommer la courbe active Delete the currently selected curve Supprimer la courbeacitve Time Graph Params Paramètres des diagrammes temporels Mode Selection Sélection du mode Eigenvalues Valeurs propres F1 = z = Mode properties Propriétés du mode <small>Mode Properties: <small>Propriétés du mode: Total Time Temps total Operating point modes Modes de points de fonctionnement Speed Vitesse Amplitude Amplitude Animate Animer Restart Recommencer Time Step = Incrément de temps = s Animation Animation Time (s) Temps (s) Angle Angle Controls Contrôles Mode Properties: Propriétés modales Control function Fonction de contrôle Enter the function of the control vs. time Entrer la fonction de la commande en fonction du temps Curve Settings Paramètres de la courbe Recalc. Recalculer Add Ajouter Rename Renommer Delete Supprimer Press Ctrl+H to highlight the mode on the root locus plot Taper Ctrl+H pour mettre en évidence le mode du graphique du lieu de la racine u0= w0= q0= v0= p0= r0= New curve Nouvelle courbe TEGapDlg OK Accepter Cancel Abandonner Apply Appliquer Warning Attention T.E. Gap Fente de bord de fuite T.E. Gap Value Valeur de la fente de bord de fuite % chord % corde Blending Distance from L.E. Distance de transition depuis le BA Unrecognized foil format Format de profil inconnu Panel number cannot exceed 300 Le nombre de panneaux ne peut dépasser 300 TranslatorDlg Language settings Paramètres de langue English Français Warning Attention The change will take effect at the next session Les modifications seront prises en compte à la session suivante Select the application's default language: Définir la langue par défaut de l'application OK Accepter Cancel Abandonner The directory Le répertoire does not exist n'existe pas does not exist n'existe pas TwoDPanelDlg OK Accepter Cancel Abandonner Apply Appliquer Warning Attention Global Panel Refinement Amélioration globale du profil Number of Panels Nombre de panneaux Panel Bunching Parameter Facteur de regroupement des panneaux TE/LE Panel Density Ratio Rapport de densité des panneaux BF / BA Refined area/LE Panel Density Ratio Surface améliorée/Rapport de densité des panneaux de bord d'attaque Top Side Refined Area x/c limits Limites x/c de la surface supérieure améliorée Bottom Side Refined Area x/c limits Limites x/c de la surface inférieure améliorée Unrecognized foil format Format de profil non reconnu The total number of panels cannot exceed %1 Le nombre maximum de panneaux ne peut dépasser %1 UnitsDlg OK Accepter Cancel Abandonner Select units for this project : Sélection des unités pour ce projet : Units Dialog Dialogue des unités Length Longueur Area Surface Speed Vitesse Mass Masse Force Force Moment Moment Define the project units Définir les unités du projet W3dPrefsDlg OK Accepter Cancel Abandonner 3D Styles Styles 3D Axis Axes Outline Contour VLM Mesh Maillage VLM Top transition Transition supérieure Bottom transition Transition inférieure Lift Portance Moments Moments Induced Drag Traînée induite Viscous Drag Traînée visqueuse Downwash Déflexion de sillage WakePanels PanneauxSillage Streamlines Lignes de courant Masses Masses Show Wake Panels Afficher les panneaux de sillage Close Fermer Reset Defaults Réinitialiser aux valeurs par défaut WAdvancedDlg OK Accepter Cancel Abandonner Reset Defaults Réinitialiser aux valeurs par défaut Wing Analysis Advanced Settings Paramètres avancée d'analyse de l'aile View Log File after errors Afficher le fichier journal en cas d'erreur Reset Wake between each angle Réinitialiser le sillage entre chaque angle Store points outside the polar mesh Enregistrer les points hors du maillage polaire All Analysis Toutes les analyses VLM and Panel Methods Méthodes VLM et de panneaux VLM Method Méthode VLM Ignore wing panels with span < Ignorer les panneaux d'aile d'une envergure < Horseshoe vortex Tourbillon en fer à cheval Ring vortex Tourbillon quadrilatère Vortex Position Position des tourbillons Control Point Position Position du point de contrôle Lifting Line Method Méthode de la ligne portante (LLM) Alpha Precision Précision de alpha Max. Iterations Nombre max d'itérations Number of spanwise stations Nombre de stations sur l'envergure 3D Panel boundary conditions Conditions aux limites pour l'analyse 3D Relax. factor Relaxation Core Size Rayon de coupure WPolarDlg Warning Attention Must enter a name for the polar Il faut entrer un nom pour la polaire Wing Name Nom de l'aile Auto Analysis Name Nom automatique pour l'analyse Polar Name Nom de la polaire Type 1 (Fixed Speed) Type 1 (vitesse constante) Type 2 (Fixed Lift) Type 2 (portance constante) Type 4 (Fixed aoa) Type 4 (angle d'attaque constant) Polar Type Type de polaire Plane and Flight Data Données de l'appareil et du vol Flight Characteristics Caractéristiques de vol LLT LLT 3D Panels Panneaux 3D Unit Unités International International Imperial Impérial Aerodynamic Data Données aérodynamiques Viscous Visqueux Tilt. Geom. Angle de calage Options Options Ignore Body Panels Ignorer les panneaux du fuselage Ground Effect Effet de sol Height = Hauteur = OK Accepter Cancel Abandonner Root Re = Re à l'emplanture = Tip Re = Re au saumon = Root Re.sqrt(Cl) = Re emplanture.sqrt(Cz) = Tip Re.sqrt(Cl) = Re saumon.sqrt(Cz) = Wing Loading = Charge alaire = Analysis Definition Définition d'analyse Mass must be non-zero for type 2 polars La masse doit être non nulle pour les polaires de type 2 Free Stream Speed = Vitesse = Inertia properties Propriétés d'inertie Use plane inertia Utiliser l'inertie de l'avion Plane Mass = Masse de l’appareil = X_CoG = X_CoG = Z_CoG = Z_CoG = VLM VLM Wing analysis methods Méthodes d'analyse Mix 3D Panels/VLM Méthode mixte panneaux 3D/VLM Wing Planform Surface développée Wing Planform projected on xy plane Surface projetée sur le plan xy Vinf.sqrt(Cl) = Vinf.sqrt(Cz) = Reference Area and Span for Aero Coefficients Surface de référence et envergure pour les coefficients aérodynamiques Wing Loading = 0.033 kg/dm2 Charge alaire = 0.033 kg/dm2 SRe SRe RRe RRe QInfCl QInfCz WingDelegate Uniform Uniforme Cosine Cosinus Sine Sinus -Sine -Sinus WingScaleDlg OK Accepter Cancel Abandonner Scale Wing Dlg Dimensionnement de l'aile Span Scaling Envergure Chord Scaling Corde Sweep Scaling Flèche Twist Scaling Vrillage Reference Référence New Nouvelle valeur Ratio Rapport XDirectStyleDlg OK Accepter Defaults Valeurs par défaut Cancel Abandonner XDirect Styles Styles XDirect Neutral Line Ligne neutre Boundary Layer Couche limite Pressure Pression XFoilAdvancedDlg OK Accepter Cancel Abandonner XFoil Settings Paramètres de XFoil VAccel VAccel Iteration Limit Limitation du nombre d'itérations Re-initialize BLs after an unconverged iteration Réinitialiser la couche limite après une itération n'ayant pas convergé Show full log report for an XFoil analysis Afficher le journal complet pour une analyse XFoil XFoilAnalysisDlg XFoil Analysis Analyse XFoil Skip Sauter Cancel Abandonner Iter Itér. Alfa = %1 ........ Alpha = %1 ........ Cl = %1 Cz = %1 Cl = %1 ........ Cz = %1 ........ Initializing viscous analysis ... Initialisation de l'analyse visqueuse... Solving BL system ... Résolution du système de couche limite... --------- Unconverged ----------- --------- Pas de convergence ----------- unconverged after %1 iterations pas de convergence après %1 itérations Alpha = %1 Alpha = %1 Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid Paramètres d'analyse incorrects CpCalc : vitesse locale trop élevée Les corrections de compressibilité ne sont pas valables CpCalc: local speed too large Compressibility corrections invalid CpCalc : vitesse locale trop élevée Les corrections de compressibilité ne sont pas valables Iteration %1 ... Itération %1 ... converged after %1 iterations convergence après %1 itérations Close Fermer xflr5-6.09-06/translations/xflr5v6_ja.ts000644 001750 000144 00001070163 12246405674 021367 0ustar00techwinderusers000000 000000 AFoilGridDlg Grid Options グリッドの設定 Neutral Line 軸線 X-Scale X軸目盛り X Major Grid X軸主軸 Y Major Grid Y軸主軸 X Minor Grid X軸副軸 Y Minor Grid Y軸副軸 Accept 承諾 Cancel キャンセル Apply 適用 AFoilTableDlg Foil Table Columns 翼型表の列 Foil Name 翼型名 Thickness 厚さ Thickness max. position 最大翼厚位置 Camber キャンバー Camber max. position 最大キャンバー位置 Number of points 制御点数 Trailing edge flap angle 後縁フラップ角 Trailing edge hinge x-position 後縁ヒンジX方向位置 Trailing edge hinge y-position 後縁ヒンジY方向位置 Leading edge flap angle 前縁フラップ角 Leading edge hinge x-position 前縁ヒンジX方向位置 Leading edge hinge y-position 前縁ヒンジY方向位置 OK OK Cancel キャンセル AboutQ5 Copyright (C) M. Drela and H. Youngren 2000 - XFoil v6.94 Copyright (C) M. Drela and H. Youngren 2000 - XFoil v6.94 Copyright (C) Matthieu Scherrer 2004 - Miarex v1.00 Copyright(C) Matthieu Scherrer 2004 - Miarex v1.00 About XFLR5 XFLR5 について Copyright (C) Andre Deperrois 2003-2012 This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. This program has been developed exclusively for the analysis of model aircraft This program has been developed exclusively for the analysis of model aircraft Any other usage is strongly disapproved Any other usage is strongly disapproved Program distributed under the terms of the GNU General Public License Program distributed under the terms of the GNU General Public License German translation by Martin Willner (mjw@mjw.co.at) German translation by Martin Willner (mjw@mjw.co.at) Japanese translation by IKUSU, Koichi Akabe, Misatus, dynamicsoar, hide253 icchy_07, ina111, ohayo_cycling, ohisa_64, ozawa64. French translation by Jean-Luc Coulon French translation by Jean-Luc Coulon OK BatchDlg Iter 反復回数 Current foil only 現在の翼型のみ Foil list 翼型リスト Foil Selection 翼型選択 Type 1 タイプ 1 Type 2 タイプ 2 Type 3 タイプ 3 Type 4 タイプ 4 Analysis Type 解析タイプ Batch foil analysis 翼型解析バッチ処理 Range 範囲 Re List Reリスト Edit List リストを編集 Min 最小 Max 最大 Increment 増分 Batch Variables バッチ変数 Specify 設定: Alpha 迎え角 Cl Cl From Zero 0から開始 Spec = Analysis Range 解析範囲 NCrit= NCrit= Forced transitions 強制遷移 Initialize BLs between polars ポーラーカーブごとに境界層を初期化 Store OpPoints 動作点の保存 Close 閉じる Analyze 解析 Skip Opp 解析点をスキップ Skip Polar ポーラーカーブをスキップ Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid 解析条件が無効 局所速度が過大 圧縮補正が無効 ...skipped after %1 iterations ...%1回の反復後にスキップされました ...unconverged after %1 iterations ...%1回の反復で収束しませんでした Analysis interrupted 解析は中断されました CpCalc: local speed too large Compressibility corrections invalid Cp計算において局所速度が過大 圧縮補正が無効 Reynolds = レイノルズ数 = Mach = マッハ数 = ...converged after %1 iterations ...%1回の反復で収束しました ...skipped after %1 iterations ...%1回の反復後にスキップされました ...unconverged after %1 iterations ...%1回の反復で収束しませんでした Top transition location (x/c) 上面遷移位置(x/c) Bottom transition location (x/c) 下面遷移位置(x/c) Alpha = 迎え角 = Cl = Cl = Re.sqrt(Cl) = Re.sqrt(Cl) = Ma.sqrt(Cl) = Ma.sqrt(Cl) = Re.Cl = Re.Cl = Cancel キャンセル Cl = %1 Cl = %1 Analyzing 解析中 Analysis completed 解析完了 BatchThreadDlg Multi-threaded batch analysis 翼型解析マルチスレッドバッチ処理 Foil Selection 翼型選択 Current foil only 現在の翼型のみ Foil list 翼型リスト Batch Variables バッチ変数 Range 範囲 Re List Reリスト Edit List Reリストを編集 Min 最小 Max 最大 Increment 増分 NCrit= NCrit= Analysis Range 解析範囲 Specify: 明記する Alpha 迎え角 Cl Cl From Zero 0から開始 Spec = Forced Transitions 強制遷移 Top transition location (x/c) 上面遷移位置(x/c) Bottom transition location (x/c) 下面遷移位置(x/c) Initialize BLs between polars ポーラーカーブごとに境界層を初期化 Update polar view ポーラーカーブの表示を更新 Update the polar graphs after the completion of each foil/polar pair 翼型と曲線のペア完了したときにグラフを更新します Close 閉じる Analyze 解析 CL CL Cancel キャンセル BodyGridDlg Body Grid Dialog Grid Parameters グリッドの設定 Show Scales スケールを表示 Main Grid 主グリッド Minor Grid 補助グリッド Body Grid Frame Grid OK OK Cancel キャンセル BodyScaleDlg Body Scale Dialog Whole Body 機体全体 Frame Only フレームのみ Scale Factor X Scale X軸スケール Y Scale Y軸スケール Z Scale Z軸スケール OK OK Cancel キャンセル BodyTransDlg Body Translation 平行移動 Frame Only フレーム指定 X Translation X方向 Y Translation Y方向 Z Translation Z方向 OK OK Cancel キャンセル CAddDlg Local Panel Refinement メッシュの局所的な改良 Angle Criterion Type of Spline スプラインのタイプ Refinement X Limits リファイン位置(X座標の範囲) From From To To Uniform 一様 Arc Length 弧の長さ Total 合計 Added MaxAngle 最大角度 At Panel Accept 同意 Cancel キャンセル Apply 適用 Warning 警告 Unrecognized foil format 読み込めない翼型フォーマット Total number of points is %1 点の数:%1 (added %1 points to original foil) (元の翼型に %1 点が追加されました) Maximum panel angle is %1 パネルの角度は最大で %1 at panel position %1 @ パネル位置 %1 Maximum panel angle is %1 deg パネルの角度は最大で %1 度 DisplaySettingsDlg General Display Settings 表示設定 All Graph Settings すべてのグラフの設定 Graph Settings グラフ設定 Background Color 背景色 Text Color 文字色 Font フォント Reverse zoom direction using mouse wheel マウスホイールでズームする方向を逆にする Enable 3D transparency OK Cancel キャンセル Use Stylesheets EditPlrDlg Polar Points Edition グラフの点の編集 Delete All Points 全ての点を削除 Delete Point 選択点の削除 OK OK Cancel キャンセル FlapDlg Flap Dlg フラップダイアログ L.E. Flap 前縁フラップ T.E. Flap 後縁フラップ Flap Angle フラップ角 + is down Hinge X Position ヒンジX方向位置 % Chord % コード Hinge Y Position ヒンジY方向位置 % Thickness % 翼厚 OK OK Cancel キャンセル Apply 適用 Warning 警告 The trailing edge hinge must be downstream of the leading edge hinge 後縁ヒンジは前縁ヒンジの下流になければなりません FoilCoordDlg Apply 適用 Foil Coordinates 翼型の座標 Insert Point 点の挿入 Delete Point 点の削除 Restore 元に戻す OK OK Cancel キャンセル FoilGeomDlg Foil Geometry キャンバーと翼厚の変更 Value %Chord %コード長 0% 0% 10% 10% Max x-pos 最大位置(x) 100% 100% Camber キャンバー Thickness 翼厚 OK OK Cancel キャンセル Restore 元に戻す Warning 警告 Panel number cannot exceed 300 パネル数は300を超えることはできません FoilPolarDlg Foil Polar Definition Automatic 自動 User Defined ユーザー定義 Analysis Name 解析名 Type 1 タイプ 1 Type 2 タイプ 2 Type 3 タイプ 3 Type 4 タイプ 4 Analysis Type 解析タイプ Plane Data Chord Mass 質量 Span Aerodynamic Data 空気力学的データ Unit 単位 International Imperial ヤード・ポンド法 Re = レイノルズ数 = Mach = Reynolds and Mach Numbers OK Cancel キャンセル Free transitions (e^n) method 自由遷移(e^n)法 Forced transition: 強制遷移: NCrit= TripLocation (top) トリップ位置(上面) TripLocation (bot) トリップ位置(下面) Transition settings 遷移設定 Analysis parameters for 解析パラメータ Reynolds = Re.sqrt(Cl) = Ma.sqrt(Cl) = Re.Cl = Alpha = 迎え角 = FoilSelectionDlg Foil Selection 翼型選択 OK OK Cancel キャンセル GL3DScales 3D Scales Settings 3Dスケール設定 Auto Scales 自動スケール Min 最小 Max 最大 Cp Scale Lift 揚力 Drag 抗力 Velocity 速度 Vector Scales ベクトルスケール L.E. 前縁 T.E. 後縁 Y-Line Y軸上っっz X-axis points 1st segment 第一区間 X factor X-Offset X軸オフセット Z-Offset Z軸オフセット Streamline length 流線の長さ Start Streamline at 流線の開始点: Streamlines Apply GL3dBodyDlg Body Edition ボディの編集 Scale 拡大縮小 Grid Setup グリッドの設定 Reset Scales 縮尺をリセット Show Current Frame Only 現在のフレームのみを表示 Undo 元に戻す Cancels the last modifiction made to the body 機体に対して最後にした変更を取り消します Redo やり直す Restores the last cancelled modification made to the body 最後に取り消しをした機体に対する変更をやり直します Export Body Geometry to File ボディ形状をファイルに書きだす Export Body Definition to File ボディの定義をファイルへ書き出す Import Body Definition from File Translate 移動 Frame %1 フレーム %1 Scale = %1 スケール = %1 NPanels Body Dlg Exit Insert Point 点の挿入 Remove Point 点の削除 Save the Body ? 機体を保存しますか? Axes Light Surfaces Outline アウトライン Panels パネル Masses 質量 Pick Center 中心に移動 Clip Plane Other その他 Actions... アクション... Save and Close 保存して閉じる Cancel キャンセル Flat Panels 平面パネル BSplines Bスプライン曲線 x Hoop Degree 角度 BodyName Enter here a short description for the body ボディの説明 Description: 説明: X View X軸表示 Y View Y軸表示 Z View Z軸表示 Iso View 等角表示 Panel bunch Frames フレーム Frame Positions フレームの位置 Points Current Frame Definition 選択中のフレーム Context Menu コンテキストメニュー Define Inertia 慣性の設定 GL3dWingDlg Warning 警告 Warning : Panel sequence is inconsistent The first section cannot be deleted 最初のセクションは削除できません Symetric 対称な Right Side 右サイド Left Side 左サイド Insert Before Wing Edition 主翼の編集 Reset Scales 縮尺をリセット Insert after Delete section 選択されたセクションを削除 Section セクション Please enter a name for the wing 翼に名前を入力して下さい Too many spanwise panels. The maximum number is Too many panels Reduce the mesh size パネルの数が多すぎます.メッシュのサイズを減らして下さい. Only 10 flaps x 2 will be handled フラップは片翼につき10枚まで扱えます Question 確認 Uniform Cosine Sine -Sine y ( y( chord ( 翼弦長 offset ( オフセット( The maximum number of panels has been reached パネルの最大数に達しました No insertion possible before the first section 最初のセクションの前に挿入することはできません Wing Description 主翼の説明 Save the changes ? 変更点を保存しますか? Undefined 未定義 WingName 翼名称 Wing Span 翼スパン Area 翼面積 Projected Span 投影翼スパン Projected Area 投影翼面積 Max is 最大: X View X軸表示 Y View Y軸表示 Z View Z軸表示 Iso View 等角表示 Total VLM Panels 総VLMパネル数 Insert after section 後ろに挿入 セクション Insert before section 前に挿入 セクション Number of 3D Panels 3Dパネルの数 Mean Geom. Chord 幾何平均翼弦 Mean Aero Chord 空力平均翼弦 MAC Span Pos MACスパン方向位置 Aspect ratio アスペクト比 Taper Ratio テーパー比 Root to Tip Sweep 後退角 Number of Flaps フラップの数 Enter here a short description for the wing 翼の説明 Description: 説明: Axes Light Surfaces Outline アウトライン Panels パネル Foil Names Masses 質量 Pick Center 中心に移動 Activate the button, then click on the object to center it in the viewport; alternatively, double click on the object ボタンを有効にしてからオブジェクト上の点をクリックして画面の中央に移動します ; もしくはオブジェクト上の点をダブルクリックしてください Reset リセット Clip Plane Reset Mesh メッシュ切り直し Scale Wing 翼を拡大縮小 Inertia... 慣性の設定... Save and Close 保存して閉じる Cancel キャンセル Reset section Import Wing from File... Export Wing to File... Import Wing Export Wing GLLightDlg OpenGL Light Options OpenGL 照明オプション Diffuse 拡散 Ambient 環境光量 Specular 反射 Light Intensity 光強度 Red Green Blue Light Color ライトの色 x x y y z z Light Position ライト位置 Emissions 放射 Shininess 輝き Material 素材 Color Material 色をつける Cull Faces 面の抜粋 Smooth Quads Depth Test 深度テスト Smooth Shading スムースシェーディング Local View ローカルビュー Options オプション Close 閉じる Reset Defaults 初期値に戻す Light ライト GraphDlg Graph Settings グラフ設定 X - Chord X - コード長 Q - Speed Q−スピード X - chord Cp Cp Alpha 迎え角 Cl Cl Cd Cd Cd x 10000 Cd x 10000 Cdp Cdp Cm Cm Xtr1 Xtr1 Xtr2 Xtr2 HMom HMom Cpmin Cpmin Cl/Cd Cl/Cd |Cl|^(3/2)/Cd |Cl|^(3/2)/Cd 1/Cl^1/2 1/Cl^1/2 Re Re XCp XCp Y - span Y - スパン Induced Angle 誘導迎え角 Total Angle 総迎え角 Local lift coef. 局所揚力係数 Local Lift C.Cl/M.A.C. Airfoil viscous drag coef. 翼型粘性抗力 Induced drag coef. 誘導抗力係数 Total drag coef. 抗力係数の合計 Local Drag C.Cd/M.A.C. Airfoil Pitching moment coef. 翼型ピッチングモーメント係数 Total Pitching moment coef. 総ピッチングモーメント係数 Reynolds レイノルズ数 Top Transition x-pos% 上面遷移位置 x-pos% Bottom Transition x-pos% 下面遷移位置 x-pos% Centre of Pressure x-pos% 圧力中心位置 x-pos% Bending moment 曲げモーメント Lift coef. 揚力係数 Viscous drag coef. 粘性抗力係数 Total pitching moment coef. 総ピッチングモーメント係数 Viscous pitching moment coef. 粘性ピッチングモーメント係数 Induced pitching moment coef. 誘導ピッチングモーメント係数 Total rolling moment coef. 総ローリングモーメント係数 Total yawing moment coef. 総ヨーイングモーメント係数 Viscous yawing moment coef. 粘性ヨーイングモーメント係数 Induced yawing moment coef. 誘導ヨーイングモーメント係数 Glide ratio Cl/Cd 滑空比 Cl/Cd Power factor Cl^(3/2)/Cd 1/Rt(Cl) 1/Rt(Cl) FX (Drag) FY (Side force) FZ (Lift) Vx Vx Vz Vz VInf Descent angle atan(Cd/Cl) 降下角 atan(Cd/Cl) Pitching Moment Rolling Moment Yawing Moment Centre of pressure X-Pos 圧力中心 X-Pos Centre of pressure Y-Pos 圧力中心 Y-Pos m.g.Vz m.g.Vz Efficiency (XCp-Xcg)/MAC (XCp-Xcg)/MAC Control Variable 変数コントロール Cy - Lateral force coef. Cy - 横力係数 Neutral Point x-position 中立点のx位置 Phugoid Frequency Phugoid Damping フゴイドダンピング Short Period Frequency 短周期モード Short Period Damping 短周期モード減衰項 Dutch Roll Frequency ダッチロール周波数 Dutch Roll Damping ダッチロール減衰項 Roll Damping Spiral Damping Restore OK Cancel キャンセル Apply YAxis Y軸 vs. vs. XAxis X軸 Title タイトル Label ラベル Font Color Set Title Font タイトルのフォント設定 Set Label Font ラベルフォント設定 Title Color タイトルの色 Label Color ラベルの色 Fonts フォント Graph Background グラフ背景 Graph Border グラフの境界 BackGround 背景 X Axis X軸 Y Axis Y軸 Min 最小 Max 最大 Origin 原点 Unit 単位 Auto Scale 自動スケール Inverted Axis Axis Style 軸のスタイル X Major Grid Y Major Grid X Minor Grid Y Minor Grid Auto Unit 自動編成 Variables 変数 Scales Axis and Grids 軸とグリッド Fonts and BackGround フォントと背景 Centre of pressure Z-Pos ImportWingDlg Import Wing Dialog Select the wing to import OK OK Cancel キャンセル InertiaDlg Inertia Properties 慣性のプロパティ Mass 質量 x x y y z z Description 説明 Wing Mass: 翼の質量: Body Mass: ボディの質量: Volume Mass: %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! This is a calculation form for a rough order of magnitude for the inertia tensor. Export Mass Properties Insert Before Delete 削除 Point Mass 点質量 Inertia properties for AVL Mass File (*.mass) AVL Mass File (*.mass) %1 %2 %3 %4 %5 %6 %7 %8 %9 %10! Inertia of both left and right wings %1 %2 %3 %4 %5 %6 %7 %8 %9 %10! 両翼の慣性 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Body inertia %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Body's inertia Refer to the Guidelines for explanations. 詳細はガイドラインを参照してください。 Object Mass - Volume only, excluding point masses オブジェクトの質量(おもりの質量は含まない) Wing Mass= 翼の質量= Component inertias 部品の慣性 Main Wing Second Wing Elevator Fin Body Additional Point Masses 追加の点質量 Total Mass = Volume + point masses 全質量=体積からの質量+点の質量 Total Mass= 全質量= OK Cancel キャンセル Center of gravity 重心 Inertia in CoG Frame Export to AVL AVLに書き出す InterpolateFoilsDlg Interpolate Foils 翼型の合成 Camb1 キャンバー1 Camb2 キャンバー2 Camb3 キャンバー3 Thick1 厚み1 Thick2 厚み2 Thick3 厚み3 New Foil Name Interpolated Foil 合成された翼型 OK OK Cancel キャンセル Camb.=%1 キャンバー =%1 at x=%1 x=%1 において Thick.=%1 最大翼厚 =%1 InverseOptionsDlg XInverse Style Reference Foil 参照翼型 Modified Foil 翼型を改良する Spline Reflected Curve OK OK Cancel キャンセル LECircleDlg L.E. Circle 前縁半径 r= r= % Chord % コード長 Show 表示 OK OK Cancel キャンセル LEDlg Leading Edge 前縁 Approximate new/old ratio for L.E. radius ratio 比率 Blending Distance from L.E. % chord % コード長 OK OK Cancel キャンセル Apply 適用 Warning 警告 Unrecognized foil format 読み込めない翼型フォーマット Panel number cannot exceed 300 メッシュの数は300を超えることができない LLTAnalysisDlg LLT Analysis LLT 解析 Iterations 反復回数 abs 絶対値 Launching analysis.... 解析開始... Max iterations = %1 最大反復回数 = %1 Alpha precision = %1 deg 迎え角精度 = %1 deg Relaxation factor = %1 緩和係数 = %1 Number of stations = %1 測定点数=%1 Analysis cancelled on user request.... ユーザーの要求によって解析はキャンセルされました... Calculating Alpha = %1... 計算中のAlpha = %1... ...negative Lift... Aborting ...負の揚力...中断 ...converged after %1 iterations ...%1回の反復後に収束しました ...unconverged after %2 iterations ...%2回の反復後に収束しませんでした Alpha = %1, skipped after %2 iterations α = %1, %2回繰り返した後スキップ QInf = %1 skipped after %2 iterations Skip スキップ Cancel キャンセル Analysis completed 解析完了 ...some points are outside the flight envelope ...いくつかの点でフライトエンベロープを外れました ...some points are unconverged ...いくつかの点で未収束です Close 閉じる Initializing analysis... 解析の初期化中... Calculating QInf = %1... 計算中のQInf = %1... ...unconverged after %1 iterations ...%1 回の反復後に収束しませんでした LinePickerDlg Line Picker 線を選択 Style スタイル Width Color OK OK Cancel キャンセル MainFrame Save the project before exit ? 終了前にプロジェクトを保存しますか? New Project 新規プロジェクト Save and close the current project, create a new project 現在のプロジェクトを保存・終了し、新しいプロジェクトを作成します Close the Project プロジェクトを閉じる Save and close the current project 現在のプロジェクトを保存・終了します &Open... 開く(&O)... Open an existing file 既存のファイルを開く &Insert Project... プロジェクトの挿入(&I)... Insert an existing project in the current project 既存のプロジェクトを現在のプロジェクトに挿入します &Direct Foil Design 翼型を直接設計(&D) Open Foil Design application 翼型設計アプリケーションを開く &XFoil Inverse Design XFoil 逆設計(&X) Open XFoil inverse analysis application XFoil 逆解析アプリケーションを開く &XFoil Mixed Inverse Design XFoil 混合逆設計(&X) Open XFoil Mixed Inverse analysis application XFoil 混合逆解析アプリケーションを開く &XFoil Direct Analysis XFoil 順解析(&X) Open XFoil direct analysis application XFoil 順解析アプリケーションを開く &Wing and Plane Design 翼と機体の設計(&W) Open Wing/plane design and analysis application 翼/機体設計と解析アプリケーションを開く Save 保存 Save the project to disk ディスクにプロジェクトを保存します Save the current project under a new name 現在のプロジェクトを新しい名前で保存します Define the units for this project このプロジェクトの単位を設定します Define the default language for the application アプリケーションの既定の言語を設定します Restore toolbars ツールバーを復元 Restores the toolbars to their original state ツールバーを初期設定に戻します Save View to Image File 表示内容を画像ファイルに保存 Saves the current view to a file on disk 現在の画面をディスク上のファイルに保存します General Display Settings 表示設定 Export Graph グラフのエクスポート Export the current graph data to a text file 現在のグラフデータをテキストファイルにエクスポート Restores the graph's x and y scales グラフのXとYのスケールを戻す E&xit 終了(&X) Exit the application アプリケーションを終了します &Guidelines ガイドライン(&G) Show the guidelines for some help ヘルプとしてガイドラインを表示します &About 情報(&A) More information about XFLR5 XFLR5についての情報 About Qt Qt について Properties プロパティ Show the properties of the currently selected polar 現在選択中のグラフのプロパティを表示します Grid Options グリッドオプション Define the grid settings for the view グリッドの表示設定をします Use Splines スプライン曲線を使用 Define a foil using one B-Spline for each foil side 翼の上下面に対してB-スプライン曲線を使用して翼型を定義します Store Splines as Foil スプライン曲線を翼型として保存 Store the current splines in the foil database 現在のスプライン曲線を翼型データベースに保存 Splines Params スプライン曲線のパラメータ Define parameters for the splines : degree, number of out points スプライン曲線のパラメータの定義 : 次数、制御点 Export Splines To File スプライン曲線をファイルにエクスポート New Splines 新規スプライン曲線 Reset the splines スプライン曲線をリセットします Zoom in 拡大 Zoom the view by drawing a rectangle in the client area 長方形を書いた範囲を拡大して表示します Reset X Scale X軸目盛りのリセット Resets the scale to fit the current screen width ウィンドウ幅にズーム Undo 元に戻す Cancels the last modifiction made to the splines スプラインに対して最後にした変更を取り消します Redo やり直す Restores the last cancelled modifiction made to the splines 最後に取り消しをしたスプラインに対する変更をやり直します Show All Foils すべての翼型を表示 Hide All Foils すべての翼型を非表示 Delete... 削除... Rename... 名称変更... Export... エクスポート... Show Current Foil 現在の翼型を表示 Hide Current Foil 現在の翼型を非表示 Reset Y Scale Y軸目盛りのリセット Reset Scales 縮尺をリセット Resets the x and y scales to screen size X軸Y軸をウィンドウ幅に合わせます Zoom Less 縮小 Zoom Y Scale Only Y方向のみ拡大 Zoom Y scale Only Y方向のみ拡大します De-rotate the Foil Normalize the Foil 翼型の正規化 Refine Locally Refine Globally Edit Foil Coordinates 翼型の座標編集 Scale camber and thickness キャンバー・翼厚の変更 Set T.E. Gap 後縁のギャップ設定 Set L.E. Radius 前縁半径設定 Show LE Circle 前縁半径の表示 Show Legend 凡例を表示 Set Flap フラップの設定 Interpolate Foils Naca Foils Naca翼型 Set Table Columns 表の列をセットする Reset column widths Load background image 背景画像の読み込み Clear background image 背景画像のクリア &View 表示(&V) F&oil 翼型(&O) &Splines スプライン曲線(&S) Context Menu コンテキストメニュー Options オプション Switch to the Operating point view 動作点表示に切り替えます Switch to the Polar view グラフ表示に切り替えます Switch to stability analysis post-processing 安定性解析のポストプロセスに切り替えます Switch to the 3D view 3D表示に切り替えます Switch to the Cp view Cp表示に切り替えます Define the style and color preferences for the 3D view 3D表示のスタイルと色を設定します Define which type of polars should be shown or hidden Define the scales for the 3D display of lift, moment, drag, and downwash Define the light options in 3D view 3Dビューの光源を設定 Half Wing 翼の半分 Rename the currently selected object Edit the body of the currently selected plane Export the current plane or wing to a text file in the format required by AVL AVL対応フォーマットで選択中の機体をテキストファイルに書き出します Export the current operating point to a text or csv file 選択中の解析点をテキストファイル又はcsvファイルに書き出します Reset the legend position to its default value 凡例位置をデフォルトに戻します Reset the wing scale to its default value 翼の拡大率を元に戻す Scale the dimensions of the currently selected wing Manage objects オブジェクトの管理 Rename or delete the planes and wings stored in the database データベースに保存された飛行機または翼の削除・名前の変更 Import a polar from a text file テキストファイルからポーラーを読み込みます Define the inertia for the current plane or wing 選択中の機体の慣性プロパティを設定します Hide all the curves except for the one corresponding to the currently selected operating point 選択中の解析点以外の曲線をすべて非表示にします Show the graph curves of all operating points 全ての計算点のグラフの曲線を表示 Hide the graph curves of all operating points 全ての計算点のグラフの曲線を非表示 Delete all the operating points of all planes and polars 全ての飛行機と曲線の計算点を削除 Show the curves of all the operating points of the currently selected polar 選択しているグラフの全計算点の曲線を表示 Hide the curves of all the operating points of the currently selected polar 選択しているグラフの全計算点の曲線を非表示 Delete all the operating points of the currently selected polar 選択しているグラフの全計算点の曲線を削除 Show the theoretical optimal elliptic lift curve on all graphs for which the selected variable is the local lift 選択している局所揚力を変数としたすべてのグラフに理想楕円揚力曲線を表示 Show XCG location XCGの位置を表示 Show the position of the center of gravity defined in the analysis 解析によって得られた重心の位置を表示 Show the graph curves for the elevator Show the graph curves for the fin 垂直尾翼のグラフを表示 Show the graph curves for the second wing 2番目の翼のグラフを表示 Define an analysis for the current wing or plane Modify the analysis parameters of this polar Define a Stability Analysis Define a stability analysis for the current wing or plane 現在の翼または飛行機に対する安定性解析を定義 Define Graph Settings グラフのセッティング Define the settings for the selected graph 現在選択されているグラフのセッティング Display only the first graph 最初のグラフのみ表示 Display only the second graph 2番目のグラフのみ表示 Display only the third graph 3番目のグラフのみを表示 Display only the fourth graph 4番目のグラフのみを表示 Reset the scale of the current operating point graph 現在の実行点のグラフ目盛りを元に戻す Reset the scales of all four operating point graphs Reset the scales of all four polar graphs すべての特性曲線のグラフ目盛りを元に戻す Define the settings of all four operating point graphs Define the settings of all four polar graphs 特性曲線の一括設定 Hide all the polar curves associated to the currently selected wing or plane Show all the polar curves associated to the currently selected wing or plane Delete all the polars associated to the currently selected wing or plane Hide all the polar curves of all wings and planes Show all the polar curves of all wings and planes Hide all the operating point curves of the currently selected wing or plane Show all the operating point curves of the currently selected wing or plane Delete all the operating points of the currently selected wing or plane 現在選択されている翼または飛行機に関する全ての動作点曲線を消去する Delete the currently selected wing or plane Duplicate the currently selected wing or plane Save the currently selected wing or plane as a new separate project 現在選択されている翼あるいは機体を新規プロジェクトとして保存 Rename the currently selected polar Export the currently selected polar to a text or csv file 現在選択されている特性曲線をテキストファイルまたはcsvファイルとして書き出す Delete all the points of the currently selected polar, but keep the analysis settings Delete the currently selected polar Delete the currently selected operating point Define the settings for LLT, VLM and Panel analysis &Body 胴体(&B) &Analysis 解析(&A) Define an Analysis 解析の定義 Batch Analysis バッチ処理 Current Foil 選択中の翼型 XFLR5 v6 Project File (*.wpa);;XFLR5 v5 Project File (*.*) XFLR5 v6 Project File (*.wpa);;XFLR5 v5 Project File (*.*) Foil 3D Scales 3Dスケール &File ファイル(&F) &? ヘルプ(&?) OpPoint view 動作点表示 Show Operating point view 動作点を表示します Polar view グラフ Show Polar view グラフを表示します 3D Color Preferences 3Dの色選択 Polar Filter 3D Light Options 3Dの照明オプション Define a New Wing 新しい翼を定義 Shows a dialogbox for editing a new wing definition 新しい翼を編集するダイアログを表示します Define a New Plane 新しい機体 Shows a dialogbox to create a new plane definition 新しい機体を作るダイアログを表示します Edit... 編集... Shows a dialogbox to edit the currently selected wing or plane 選択中の翼・機体を編集するダイアログを表示します Define a New Body 新しい胴体を定義 Shows a dialogbox for editing a new body definition 新しい機体の編集ダイアログの表示 Show Elevator Curve エレベータカーブの表示 View Log File ログファイルを表示 Edit Current 現在の機体を編集 Exit 終了 will revert to default settings at the next session 次のセッションで既定の設定に戻します Show the properties of the currently selected operating point 選択中の計算点の特性を表示 Foil Actions Stability 安定性 OpPoint View 動作点 Polar View グラフ Time Response Vew 時間応答 Root Locus View 根軌跡 Switch to root locus view 根軌跡へ切り替え 3D View 3D表示 Cp View Cp表示 Export Body Definition 胴体の定義をエクスポート Export a body definition to a text file 胴体をテキストファイル形式でエクスポートします Export Body Geometry 胴体の形状をエクスポート Export a body geometry at different cross sections to a text file 胴体の断面形状をテキストファイルにエクスポートします Import Body 胴体をインポート Import a body definition from a text file テキストファイルから胴体の定義をインポートします Manage Bodies 機体を管理 Manage the body list : Rename, Duplicate, Delete 胴体リストの管理 : 名前の変更、複製、削除 Export to AVL... AVL形式でエクスポート... Reset Legend Position 凡例位置を元に戻す Reset Wing Scale 翼の拡大率をリセット Scale Wing 翼を拡大縮小 Import Polar ポーラーカーブのインポート Define Inertia 慣性の設定 Show Current OpPoint Only 現在の計算点のみを表示 Show All OpPoints すべての動作点を表示 Hide All OpPoints すべての動作点を非表示 Delete All OpPoints すべての動作点を削除 Show Associated OpPoints 関連する計算点を表示 Hide Associated OpPoints 関連する計算点を非表示 Delete Associated OpPoints 関連する計算点を消去 Show Elliptic Curve Show Fin Curve Show Second Wing Curve Display the first two graphs Display all four graphs Highlight Current OpPoint Highlights on the polar curve the currently selected operating point Reset All Graph Scales 全てのグラフの縮尺を元に戻す All Graph Settings Hide Associated Polars Show Associated Polars Delete Associated Polars 関連極座標の消去 Hide All Polars すべてのポーラーカーブを隠す Show All Polars すべてのポーラーカーブを表示 Duplicate... 複製... Save as Project... プロジェクトとして保存... Export ... エクスポート ... Reset ... リセット ... Delete ... 削除 ... Advanced Settings... 拡張設定... &Wing-Plane 翼-機体(&W) Current UFO Current Body 選択中の胴体 &Polars グラフ(&P) Current Polar 選択中のポーラーカーブ Graphs グラフ &OpPoint 動作点(&O) Current OpPoint 選択中の動作点 Current Graph 選択中のグラフ UFO Ready 準備完了 All Polar Graph Settings グラフの設定 Reset All Polar Graph Scales すべてのグラフのスケールをリセット Set Style... スタイル設定... Delete associated polars 関連付けられたポーラーカーブの削除 Delete all the polars associated to this foil 翼型に関連付けられたすべてのポーラーカーブを削除します Show associated polars 関連付けられたポーラーカーブの表示 Hide associated polars 関連付けられたポーラーカーブを隠す Save associated polars 関連極座標の保存 Hide associated OpPoints 関連付けられた動作点を隠す Show associated OpPoints 関連付けられたポーラーカーブの表示 Delete associated OpPoints 関連付けられた動作点の削除 Defines a single analysis/polar Launches a batch of analysis calculation for a specified range or list of Reynolds numbers 指定した範囲やレイノルズ数リストにおいて解析計算のバッチ処理を開始します Multi-threaded Batch Analysis マルチスレッドバッチ処理解析 Launches a batch of analysis calculation using all available computer CPU cores 使用可能なすべてのCPUコアを使った解析計算のバッチ処理を開始します Delete 削除 Deletes the currently selected polar 選択中のポーラーカーブを削除します Reset Deletes the contents of the currently selected polar Edit 編集 Remove the unconverged or erroneaous points of the currently selected polar Export Export all polars 全てのポーラーカーブをエクスポートします Define Styles スタイル設定 Define the style for the boundary layer and the pressure arrows 境界層と圧力矢印のスタイルを設定します Manage Foils 翼型の管理 Rename 名称変更 Show Panels パネルの表示 Show the foil's panels 翼型のパネルを表示します Reset Foil Scale 翼型のスケールのリセット Resets the foil's scale to original size 翼型のスケールを元のサイズにリセットします Show Inviscid Curve 非粘性曲線の表示 Display the Opp's inviscid curve 動作点における非粘性曲線を表示します Neutral Line 軸線 Show Current Opp Only 選択中の動作点のみ表示 Show All Opps 全ての動作点を表示 Hide All Opps 全ての動作点を隠す Reset XFoil XFoilをリセット XFoil Advanced Settings XFoilの詳細設定 Tip : you don't want to use that option... Duplicate 複製 Cp Variable Cpの変数 Sets Cp vs. chord graph Q Variable Sets Speed vs. chord graph 速度-翼弦長グラフを設定 Export Cur. XFoil Results Max. Shear Coefficient 最大せん断力係数 Bottom Side D* and Theta Top Side D* and Theta Log(Re_Theta) Log(Re_Theta) Re_Theta Re_Theta Amplification Ratio 応答倍率 Dissipation Coefficient 散逸係数 Skin Friction Coefficient 表面摩擦係数 Edge Velocity エッジ速度 Kinematic Shape Parameter Import XFoil Polar &Foil 翼型(&F) &Design 設計(&D) Polar Graphs ポーラーカーブ Operating Points 動作点 Cp Graph Cpグラフ Current XFoil Results 現在のXfoilの結果 Store Foil 翼型を記録 Store Foil in database 翼型をデータベースに記録します Extract Foil Extract a Foil from the database for modification Define the styles for this view Resets the scale to fit the screen size 画面サイズに合わせてスケールをリセット Insert Control Point 操作点の挿入 Remove Control Point 操作点の削除 Show Q-Initial Show Q-Spec Show Q-Viscous Show Points 点を表示 Show Reflected Zoom X Scale Zoom X Scale Only X方向のみ拡大 Zoom Y Scale Y方向を拡大 &Graph グラフ(&G) Full Inverse Mixed Inverse XInverse Are you sure you want to delete 本当に削除してもよろしいですか? and all associated OpPoints and Polars ? と、関連するすべての操作点、極性を削除しますか? Question 確認 Could not read the file ファイルを読み込めませんでした Info 情報 Save the current project ? 現在のプロジェクトを保存しますか? Text File (*.txt);;Comma Separated Values (*.csv) テキストファイル (*.txt);;カンマ区切り (*.csv) Open File ファイルを開く Project file (*.wpa) プロジェクトファイル (*.wpa) Warning 警告 XFLR5 file (*.dat *.plr *.wpa) XFLR5 ファイル (*.dat *.plr *.wpa) The project プロジェクト has been saved は保存されました Enter the foil's new name 翼型の新しい名前を入れてください Default Settings 初期設定 Your system does not provide support for OpenGL. XFLR5 will not operate correctly. あなたの環境ではOpenGLのサポートが提供されていません XFLR5は正常に動作しません. Save Project As... プロジェクトを別名で保存... Save Options 保存オプション Define the save options for operating points 計算点のための保存オプションを設定 Units... 単位の設定... Language... 言語... Reset Default Settings 初期設定に戻す Define the color and font options for all views and graphs すべての表示とグラフの色とフォントを設定します Reset Graph Scales グラフの縮尺をリセット Two Graphs 2つのグラフ All Graphs 全てのグラフ Graph 1 グラフ1 Graph 2 グラフ2 Graph 3 グラフ3 Graph 4 グラフ4 Define Cp Graph Settings Cpグラフの設定 Two Polar Graphs グラフを2つ表示 All Polar Graphs 全てのグラフを表示 Cl vs. Cd 揚抗比 Cl vs.Alpha Cl-α Cl vs. Xtr. Cl-Xtr Cm vs.Alpha Cm-α Glide ratio vs. alpha 揚抗比-α Analysis 解析 Reset foil scale 翼型の縮尺をリセット Error reading the file Are you sure you want to reset the default settings ? 本当に初期設定に戻しますか? The settings will be reset at the next session 次のセッションで既定の設定に戻します Nothing to save 保存するものがありません Save the Project File プロジェクトファイルを保存 XFLR5 Project File (*.wpa) XFLR5 プロジェクトファイル (*.wpa) Could not open the file for writing Save Image 画像を保存 Unidentified Operating Point Obsolete format, cannot read A foil of that name already exists Please enter a new name &%1 %2 &%1 %2 Foil Error : no points Show Only Associated Polars Show only associated polars Export associated OpPoints Saved the valid part ManageBodiesDlg Body Management 機体の管理 New 新規 Edit 編集 Rename 名称変更 Delete 削除 Duplicate 複製 Export Definition 機体定義をエクスポート Export Geometry 形状をエクスポート Close 閉じる Description: 説明: The body 胴体 is in use by a plane. Delete Anyhow? は機体に使われています それでも削除しますか? Question 確認 Are you sure you want to delete the body : 機体を本当に削除しますか : The modification will erase all results for the planes using this body. Continue ? 変更すると、このボディを使用する機体の計算結果が全て消去されます。 続行しますか? ManageFoilsDlg Foil Management 翼型管理 Delete 削除 Rename 名称変更 Export Foil 翼型をエクスポート Close 閉じる Name 名称 Thickness (%) 翼厚 (%) at (%) 位置(%) Camber (%) キャンバー (%) Points TE Flap ( 後縁フラップ ( TE XHinge 後縁のX軸ヒンジ TE YHinge 後縁のY軸ヒンジ LE Flap ( 前縁フラップ ( LE XHinge 前縁のX軸ヒンジ LE YHinge 前縁のY軸ヒンジ Foils 翼型 Foil File (*.dat) 翼型ファイル (*.dat) ManageUFOsDlg Object Management オブジェクト管理 Delete 削除 Rename 名称変更 Close 閉じる Description: 説明: Name 名称 Span Area 翼面積 M.A.C. 空力平均翼弦 AR アスペクト比 TR テーパー比 Rt-Tip Sweep Tail Volume 尾翼容積 UFOs Are you sure you want to delete the plane : 本当にこの飛行機を削除してもよろしいですか? Are you sure you want to delete the wing : 本当にこの翼を削除してもよろしいですか? Question 確認 ModDlg Modification 修正 OK OK Cancel キャンセル Save as new 名前を付けて保存 NacaFoilDlg NACA Foils NACA翼型 4 or 5 digits 4, 5桁の番号 Number of Panels パネル数 OK OK Cancel キャンセル Illegal NACA Number 不正なNACA番号 NewNameDlg OK OK Cancel キャンセル ObjectPropsDlg OK OK Polar Properties Operating Point Properties PanelAnalysisDlg 3D Panel Analysis 3Dパネル解析 Warning 警告 Solving the problem... 解析中... Adding the wake's contribution... Computing On-Body Speeds... Creating source strengths... Calculating aerodynamic coefficients in the far field plane Calculating point 計算点 Computing Plane for alpha=%1 Computing Plane for QInf=%1 Calculating aerodynamic coefficients... Calculating wing... Calculating body... Type 1 - Fixed speed polar タイプ1 - 速度一定のポーラー Type 2 - Fixed lift polar タイプ2 : 揚力一定のポーラー Type 4 - Fixed angle of attack polar タイプ4 : 迎角一定のポーラー Type 7 - Stability polar タイプ7:安定性ポーラー Performing asymmetric calculation : Counted %1 panel elements Relaxing the wake... Singular Matrix.... Aborting calculation... Cancel キャンセル Found a negative lift for Alpha=%1.... skipping the angle... 負揚力値がα=%1において見つかりました…スキップ中… Performing symmetric calculation Solving the problem... 解析中... Launching 3D Panel Analysis.... 3Dパネル解析を開始しています... Launching VLM1 Analysis.... VLM1解析を開始しています... Launching VLM2 Analysis.... VLM2解析を開始しています... Using Dirichlet boundary conditions ディリクレ境界条件の使用 Using Neumann boundary conditions ノイマン境界条件の使用 Warning: The wing and elevator lie in the same plane z= It is recommended to slightly offset the wing or the elevator to avoid numerical instabilities 数値的不安定性を回避するため,翼とエレベータを少しオフセットすることを推奨します Panel Analysis completed successfully パネル解析が完了しました Panel Analysis completed ... Errors encountered パネル解析が完了しました 解析中にいくつかのエラーが発生しました Close 閉じる Processing Alpha= %1 Wake iteration %1 PertDlg Pertubation Dialog Restore 復元 Apply 適用 OK OK Cancel キャンセル Cn List PlaneDlg Plane Editor 飛行機設計者 Total number of VLM panels =%1 Max Number =%2 A reduction of the number of VLM panels is required Warning 警告 Total number of wing panels =%1 Max Number =%2 A reduction of the number of wing panels is required Save the changes ? 変更点を保存しますか? Question 確認 Plane Name Enter here a short description for the plane Description: 説明: Plane Inertia 飛行機の慣性 Plane Description 飛行機の詳細 Define 定義 Import Export エクスポート x= x= z= z= Tilt Angle= 傾きの角度 Main Wing 主翼 Biplane 複葉機 Wing 2 翼2 Elevator エレベーター Fin 垂直尾翼 Double Fin 2つのフィン Two-sided Fin V字尾翼 y= y= Body ボディ Warning: Including the body in the analysis is not recommended. Check the guidelines for explanations. Edit... 編集... Wing Area = 翼面積 = Wing Span = 翼のスパン = Elev. Area = エレベータの面積 = Elev. Lever Arm = エレベータモーメントアーム = Fin Area = 垂直尾翼面積 = TailVolume = 尾翼容積 = Total Panels = パネル総数= OK Cancel キャンセル PolarFilterDlg Polar Filter グラフのフィルタ Show polar types Type 1 タイプ 1 Type 2 タイプ 2 Type 3 タイプ 3 Type 4 タイプ 4 Type 5 タイプ 5 Type 6 タイプ 6 Type 7 タイプ 7 OK OK Cancel キャンセル ProgressDlg Progress 進行状況 Cancel キャンセル QAFoil Spline foil スプラインで結ばれた翼型 Foil has been de-rotated by %1 degrees Foil has been normalized from %1 to 1.000 翼型は%1 から1.000に規格化される Warning 警告 At least two foils are required 少なくとも2つ以上の翼型が必要です Export Foil 翼型をエクスポート Foil File (*.dat) 翼型ファイル (*.dat) Spline Foil スプライン翼型 Too many output points on upper surface Max =%1 上面にある入力点が多すぎます 最大=%1 Too many output points on lower surface Max =%1 下面にある入力点が多すぎます 最大=%1 Export Splines スプライン曲線のエクスポート Text File (*.dat) テキストファイル (*.dat) X-Scale = %1 縮尺(X) = %1 Y-Scale = %1 縮尺(Y) = %1 x = %1 x = %1 y = %1 y = %1 Open Image File イメージファイルを開く Question 確認 Discard changes to Splines ? スプライン曲線への変更を破棄しますか? Name Thickness (%) 翼厚 (%) at (%) 位置(%) Camber (%) キャンバー (%) Points TE Flap ( 後縁フラップ ( TE XHinge 後縁のX軸ヒンジ TE YHinge 後縁のY軸ヒンジ LE Flap ( 前縁フラップ ( LE XHinge 前縁のX軸ヒンジ LE YHinge 前縁のY軸ヒンジ Show 表示 Centerline 中央線 Style スタイル Foils 翼型 The minimum number of control points has been reached for this spline degree QMiarex Cl Alpha 迎え角 Cn VCn ICn x Cp Warning 警告 Not enough memory to store the OpPoint 十分なメモリがありません The modification will erase all results associated to this Plane. Continue ? この修正を行うと、この飛行機に関する全ての解析結果が消えてしまいます。 続行しますか? Induced Angle 誘導迎え角 Total Angle Local lift 局所揚力 Airfoil drag 形状抗力 Induced drag 誘導抗力 Total drag 総抗力 Local drag 局所抗力 Cm Airfoil Cm Airfoil Time = 時間= Are you sure you want to delete the polars associated to : 関連付けられたグラフを消してよろしいですか : Cl = Cl = Cm = モーメント係数= ICn = %1 PCn = %2 ICn = %1 PCn = %2 ICn=, %1,PCn=, %2 ICn=, %1,PCn=, %2 XNP = %1 XNP = %1 XNP=, %1 XNP=, %1 Polar properties Cm Real Real Imag/2.pi Im/2.pi Cm total 総Cm Re Top Trans x-Pos % 上面の遷移位置 % Bot Trans x-Pos % 下面の遷移位置 % CP x-Pos % 風圧中心位置 % BM ( BM ( Point is out of the flight envelope Alpha = %1 Alpha = %1 Efficiency = %1 Cl/Cd = %1 Cl/Cd = %1 GCm = %1 GCm = %1 Please define a wing or a plane object before running a calculation 計算実行前に翼もしくは飛行機のオブジェクトを定義して下さい Please define an analysis/polar before running a calculation 計算実行前に解析の定義を行って下さい Could not find the wing's foil 翼型が見つかりません ... Aborting Calculation ... 計算を中断しています Are you sure you want to delete the plane : Are you sure you want to delete the wing : Question 確認 Are you sure you want to delete the polar : この曲線を消去してもよろしいですか? The modification will erase all results for the planes using this body. Continue ? The modification will erase all results associated to this Wing. Continue ? 変更すると、この翼に関係する計算結果が全て消去されます。 続行しますか? Export Wing OpPoint 翼の計算点の書き出し Text File (*.txt);;Comma Separated Values (*.csv) テキストファイル (*.txt);;カンマ区切り (*.csv) Cd = %1 ICd = %2 PCd = %3 Cd = %1 ICd = %2 PCd = %3 Cd=,%1,ICd=, %2,PCd=, %3 Cd=,%1,ICd=, %2,PCd=, %3 XCP = %1 YCP = %2 XCP = %1 YCP = %2 XCP=, %1, YCP=, %2 XCP=, %1, YCP=, %2 Bend. = Bend. = Flap フラップ Export Polar Open File ファイルを開く UFO Polar Format (*.*) UFO Polar Format (*.*) Could not read the file ファイルを読み込めませんでした No UFO with the name 名前を持った飛行機がありません。 could be found. The polar(s) will not be stored Enter the new name for the wing polar : Are you sure you want to reset the content of the polar : abcdefghijklmnopqrstuvwxyz012345678 abcdefghijklmnopqrstuvwxyz012345678 abcdefghijklmnopqrstuvwxyz01234567 abcdefghijklmnopqrstuvwxyz01234567 VCm ICm Wing Polar Graph 1 Wing Polar Graph 2 Wing Polar Graph 3 Wing Polar Graph 4 Cp Graph Cpグラフ Current Plane 現在の飛行機 Current Wing 現在の翼 Current Object 現在のオブジェクト The total number of panels is %1. The Max Number is %2. A reduction of the number of panels is required 合計パネル数は%1です。最大パネル数は%2です。 パネル数を減らして下さい。 Control polars are not supported in XFLR5 v6. Please use stability polars instead. Main Wing Cp Coefficients Wing Cp Coefficients 翼のCp係数 Panel CtrlPt.x CtrlPt.y CtrlPt.z Cp Panel CtrlPt.x CtrlPt.y CtrlPt.z Cp Panel,CtrlPt.x,CtrlPt.y,CtrlPt.z,Cp Panel,CtrlPt.x,CtrlPt.y,CtrlPt.z,Cp Cp Coefficients Strip %1 Strip %1 Export UFO 飛行機のエクスポート AVL Text File (*.avl) AVL テキストファイル (*.avl) Project 投影面 The modification will erase all polar results associated to this Plane. Continue ? 変更はこの飛行機に関連する全てのポーラーの結果を消去します. 続けますか? Wing Span = 翼幅 = xyProj. Span = xy平面に投影したスパン = Wing Area = 翼面積= xyProj. Area = xy平面に投影した面積 = Plane Mass = 機体重量 = Wing Load = 翼面加重 = Tail Volume = 尾翼容積 = Root Chord = 翼根の翼弦長 = MAC = 空力平均翼弦= TipTwist = 翼端捻り上げ = Aspect Ratio = アスペクト比 = Taper Ratio = テーパー比 = Root-Tip Sweep = V = %1 No unit defined for speed... 速度の単位が設定されていません Lift Coef. = %1 揚力係数= Drag Coef. = %1 抗力係数= Rolling Moment Coef. = %1 ロールモーメント係数= Induced Moment Coef = %1 Profile Yawing Moment = %1 Flap %1 Moment =%2 Top transition 上面の遷移 Bottom transition 下面の遷移 Centre of Pressure 風圧中心 Moment ref. location モーメント参照位置 Enter the new name for the Body : 胴体の新しい名前を入力してください : The body 胴体 is used by one or more planes. Overwrite anyway ? (Results will be lost) は他の飛行機で用いられています。 上書きしますか?(結果は失われます) Enter the new name for the Plane : 機体の新しい名前を入力してください : Enter the new name for the wing : 翼の新しい名前を入力してください : Enter the new name for the Polar: Sequence Start= 開始= End= 終了= D= Init LLT Init LLT Store OpPoint Store OpPoint Analyze 解析 Analysis settings 解析設定 Lift 揚力 Ind. Drag 誘導抗力 Visc. Drag 粘性抵抗 Trans. 遷移 Moment モーメント Downw. Downw. Surf. Vel. 表面速度 Stream 気流 Animate アニメーション表示 Display 表示 VCD ICD CD CL/CD 揚抗比 CL^(3/2)/CD CL^(3/2)/CD 1/Rt(CL) 1/Rt(CL) Fx (N) Fx (lbf) Fy (N) Fy (lbf) Fz (N) Fz (lbf) Pitching Moment Rolling Moment Yawing Moment Curve Panel Forces Panel Forces Display the force 1/2.rho.V2.S.Cp acting on the panel パネルに働く 1/2.rho.V2.S.Cp の力を表示 Results 計算結果 Points item 項目 Style スタイル Width Color Curve settings グラフの設定 Span Position 翼の位置 Keep Keep Reset Cp Sections Axes Light Surfaces Outline アウトライン Panels Foil Names Vortices 渦(複数形) Masses 質量 X View X軸表示 Y View Y軸表示 Z View Z軸表示 Iso View 等角表示 Pick Center 中心に移動 Activate the button, then click on the object to center it in the viewport; alternatively, double click on the object ボタンを有効にしてからオブジェクト上の点をクリックして画面の中央に移動します ; もしくはオブジェクト上の点をダブルクリックしてください Clip: CL Vx Vx Vz Vz V V Gamma ガンマ XCP XCP YCP YCP BM BM m.g.Vz (W) m.g.Vz (W) Efficiency (XCp-XCG)/MAC(%) (XCp-XCG)/MAC(%) ctrl ctrl CY XNP Ph. Freq(Hz) Ph. Freq(Hz) Ph. Damping Ph. Damping SP Freq (Hz) SP Freq (Hz) SP Damping SP Damping DR Freq(Hz) DR Freq(Hz) DR Damping DR Damping Roll Damping Spiral Damping OpenGL color format is not recognized... Sorry OpenGLのカラーフォーマットが認識されません.ごめんなさい. Cannot (yet ?) save 8 bit depth opengl screen images... Sorry Cannot (yet ?) save 16 bit depth opengl screen images... Sorry 16ビットOpenGlイメージを保存出来ません… Unidentified bit depth... Sorry QObject dihedral 上反角 twist ねじれ foil 翼型 X-panels X方向パネル分割 X-dist Y-panels Y方向パネル分割 Y-dist Wing definition 翼の定義 Foil coordinates 翼型の座標系 X X Y Re Re Mach マッハ数 CL CL CD CD Cm Cm Cdp Cdp Cpmn Cpmn XCP XCP Top Transition 上面での遷移 Bot Transition 下面での遷移 T.E. Flap moment 後縁フラップのモーメント L.E. Flap moment 前縁フラップのモーメント Type 種類 Fixed speed 速度固定 Fixed lift 揚力固定 Fixed angle of attack 迎角固定 Reynolds number レイノルズ数 Mach number マッハ数 Re.Cl Re.Cl Alpha 迎え角 NCrit NCrit Forced top trans. 上面の強制遷移 Forced bottom trans. 下面の強制遷移 Number of data points データ点数 Re List Reリスト i i Cn Cn Ci Ci Wing 2nd Wing 2番目の翼 Elevator エレベーター Fin 垂直尾翼 Plane Name 飛行機の名前 Spline Foil スプライン翼型 CpCalc: local speed too larger Compressibility corrections invalid Calculating unit vorticity distributions ... Warning: High does not work well on rotated foils Current chordline angle: %1 proceeding anyway... The max number of polar points has been reached 極曲線の点の数が上限に達しました Body Name 胴体の名前 Export Body Definition 胴体の定義をエクスポート Text Format (*.txt) テキストフォーマット (*.txt) Export Body Geometry 胴体の形状をエクスポート Text File (*.txt);;Comma Separated Values (*.csv) テキストファイル (*.txt);;カンマ区切り (*.csv) Choose the length unit to read this file : このファイルを読み込むには長さの単位を選択してください : Open File ファイルを開く All files (*.*) すべてのファイル (*.*) Could not read the file ファイルを読み込めませんでした Warning 警告 Error reading 読み込みエラーです Frames have different number of side points Please select a Frame before inserting a point 点を挿入する前に、フレームを選択して下さい Stability analysis 安定性解析 VInf = VInf = Alpha = LLT 3D-Panels 3次元パネル 3D-Panels/VLM1 3D-Panels/VLM1 3D-Panels/VLM2 3D-Panels/VLM2 VInf Mass Control value XNP YCP YCP VCD ICD CX CX CY Cl ICm VCm ICn VCn Non-dimensional Stability Derivatives: 無次元安定微係数 CXu CXu CLu CLu Cmu Cmu CXa CXa CLa CLa Cma Cma CXq CXq CLq CLq Cmq Cmq CYb CYb Clb Clb Cnb Cnb CYp CYp Clp Clp Cnp Cnp CYr CYr Clr Clr Cnr Cnr Non-dimensional Control Derivatives: CXd CXd CYd CYd CZd CZd Cld Cld Cmd Cmd Cnd Cnd CoG.x x重心 CoG.z z重心 B.C. = Dirichlet 境界条件=ディリクレ条件 B.C. = Neumann 境界条件=ノイマン条件 Analysis type 解析の種類 Viscous 粘性 Inviscid 非粘性 Ref. Area = 参照エリア= Data points データ点 Beta Beta Planform area 幾何翼面積 Projected area 投映面積 Tilted geometry 傾けられた構造 Ground height 高度 Density = 密度= Viscosity = 粘性= iblpan : *** bl array overflow Increase IVX to at least %1 *** iblsys: bl system array overflow. *** Unrecognized foil format 読み込めない翼型フォーマット ... Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid mrchdu: convergence failed at %1 , side %2, res =%3 Side %1 ... mrchue: inverse mode at %1 hk =%2 mrchue: convergence failed at %1, side %2, res = %3 mrcl: illegal Re(cls) dependence trigger, Setting fixed Re mrcl: illegal Mach(cls) dependence trigger Setting fixed Mach mrcl: Cl too low for chosen Mach(Cl) dependence artificially limiting mach to 0.99 mrcl: cl too low for chosen Re(Cl) dependence artificially limiting Re to %1 PanGen: buffer airfoil not available. Paneling convergence failed. Continuing anyway... Panel: Too many panels. Increase IQX Calculating source influence matrix ... Initializing bl ... Side %1, forced transition at x/c = %2 %3 Side %1, free transition at x/c = %2 %3 scheck: bad value for small panels (stol > 0.3) setexp: cannot fill array. n too small Setexp: Convergence failed. Continuing anyway ... Sinvrt: spline inversion failed, input value returned Specal: MInf convergence failed Speccl: cl convergence failed splind: array overflow, increase nmax stfind: Stagnation point not found. Continuing ... trchek2 - n2 convergence failed *** stagnation point is past trip on side %1 Calculating wake trajectory ... XYWake: array size (IWX) too small. Last wake point index reduced. Description %1 Wing Name 翼の名前 Span pos = %1 Span pos = %1 Span pos = %1 , A+Ai+Twist = %1 could not be interpolated , A+Ai+Twist = %1 は補間されませんでした , A+Ai+Twist = %1 is outside the flight envelope , Cl = %1 could not be interpolated , Cl = %1 は補間されませんでした , Cl = %1 is outside the flight envelope setbl: xtr??? n1=%1 n2=%2: Wing Span = %1 Wing Span = %1 XYProj. Span = %1 XYProj. Span = %1 X_CG = %1 X_CG = %1 Wing Area = %1 Wing Area = %1 XYProj. Area = %1 XY投映翼面積 = %1 Plane Mass = %1 主翼重量 = %1 Wing Load = %1 翼面荷重 = %1 Tail Volume = %1 水平尾翼容積 = %1 Root Chord = %1 翼根の翼弦長 = %1 M.A.C. = %1 空力平均翼弦= Tip Twist = %1 翼端捩り= Aspect Ratio = %1 アスペクト比= Taper Ratio = %1 テーパー比= Root-Tip Sweep = %1 翼端捻り下げ = %1 V = %1 Alpha = %1 Sideslip = %1 横滑り = %1 Bank = %1 バンク = %1 Control pos. = %1 CL/CD = %1 Cl = %1 Cm = %1 モーメント係数= Cn = %1 Cn = %1 X_NP = %1 X_NP = %1 X_CP = %1 X_CP = %1 X_CG = %1 X_CG = %1 Point is out of the flight envelope CL = %1 CD = %1 Efficiency = %1 Point x y Upper side points 上面の点 Lower side points 下面の点 Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid Cl = %1 ...converged after %1 iterations ...%1回の反復で収束しました ...unconverged after %1 iterations ...%1回の反復で収束しませんでした Continuous foils for surface do not have the same initial flap angle... aborting ZCP Cd Cd x 10000 Xtr1 {1?} Xtr2 HMom Cpmin Cl/Cd |Cl|^(3/2)/Cd 1/Rt(Cl) XCp CL/CD 揚抗比 CL^(3/2)/CD CL^(3/2)/CD 1/Rt(CL) 1/Rt(CL) Fx (N) Fx (lbf) Fy (N) Fy (lbf) Fz (N) Fz (lbf) Vx Vx Vz Vz V V Gamma ガンマ Pitching Moment Rolling Moment Yawing Moment XCP XCP YCP YCP ZCP BM BM m.g.Vz (W) m.g.Vz (W) Efficiency ctrl ctrl Ph. Freq(Hz) Ph. Freq(Hz) Ph. Damping Ph. Damping SP Freq (Hz) SP Freq (Hz) SP Damping SP Damping DR Freq(Hz) DR Freq(Hz) DR Damping DR Damping Roll Damping Spiral Damping Body option Body Panels Ignored Could not open the file for reading Total number of wing sections exceeds MAXSPANSECTIONS. Wing will be truncated. Unable to import wing definition Could not open the file for writing Multiple file loading only available for airfoil files. Non *.dat files will be ignored. QXDirect Cp Cp Q Q Not enough threads available for multithreading マルチスレッドするのに十分なスレッドがありません Warning 警告 Top 上面 Bot 下面 Max Shear 最大せん断力 Top Shear Top Shear eq Bot Shear Bot Shear eq X X Cp Graph Cpグラフ Polar Graph ポーラーカーブ Cm Graph Cmグラフ Cz Graph Czグラフ Tr Graph Trグラフ User Graph ユーザーグラフ Cf Cf Cd' Cd' Are you sure you want to delete the Operating Point 本当に動作点を削除しますか Question 確認 Are you sure you want to delete the polar : 本当に極曲線を消去しますか? : and all the associated OpPoints ? Are you sure you want to delete polars and OpPoints associated to The foil has been de-rotated by %1 degrees Export Current XFoil Results 現在のXfoilの結果をエクスポート Text File (*.txt);;Comma Separated Values (*.csv) テキストファイル (*.txt);;カンマ区切り (*.csv) Top Side x Hk Ue/Vinf Cf Cd A/A0 D* Theta CTq x,Hk,Ue/Vinf,Cf,Cd,A/A0,D*,Theta,CTq Bottom Side Export Directory ディレクトリを書き出す Export Foil 翼型をエクスポート Foil File (*.dat) 翼型ファイル (*.dat) Export OpPoint Export Polar Open File ファイルを開く XFoil Polar Format (*.*) XFoil Polar Format (*.*) Could not read the file ファイルを読み込めませんでした No Foil with the name could be found. The polar(s) will not be stored 見つかりません。曲線は保存されません。 JavaFoil Polar Format (*.*) JavaFoil Polar Format (*.*) At least two foils are required 少なくとも2つ以上の翼型が必要です The foil has been normalized from %1 to 1.000 Enter the new name for the foil polar : 翼型曲線の新しい名前を入力して下さい: Polar File Polar File (*.plr) Polar File (*.plr) Thickness = %1 翼厚 = %1 Max. Thick.pos. = %1 最大翼厚位置 = %1 Max. Camber = %1 最大キャンバ = %1 Max. Camber pos. = %1 最大キャンバ位置 = %1 Number of Panels = %1 パネル数 = %1 Flap Angle = %1 フラップ角度 = %1 XHinge = %1 XHinge = %1 YHinge = %1 YHinge = %1 TE Hinge Moment/span = 123456789 TE Hinge Moment/span = 123456789 Polar Type = %1 Polar Type = %1 Re.sqrt(Cl) = Re.sqrt(Cl) = M.sqrt(Cl) = %1 M.sqrt(Cl) = %1 Forced Upper Trans. = %1 上面強制遷移 = %1 Forced Lower Trans. = %1 下面強制遷移 =%1 Alpha = %1 迎え角 = %1 Cl = %1 Cl = %1 Cm = %1 Cm = %1 Cd = %1 Cd = %1 L/D = %1 L/D = %1 Upper Trans. = %1 上面遷移 = %1 Lower Trans. = %1 下面遷移 = %1 TE Hinge Moment/span = %1 後縁ヒンジモーメント/スパン = %1 LE Hinge Moment/span = %1 前縁ヒンジモーメント/スパン = %1 Alpha 迎え角 Cl Cd Cd x 10000 Cdp Cm Xtr1 Xtr2 HMom Cpmin Cl/Cd |Cl|^(3/2)/Cd 1/Rt(Cl) Re XCp Sequence Start= 開始= End= 終了= D= Viscous 粘性 Init BL 初期境界層 Store Opp Store Opp Analyze 解析 Analysis settings 解析設定 Show BL 境界層を表示 Show Pressure 圧力分布を表示 Animate アニメーション表示 Display 表示 Polar properties Curve Points Style スタイル Width Color Graph Curve Settings グラフ曲線の設定 abcopy: buffer airfoil not available Target segment cannot include stagnation point in mixed-inverse Bottom Side QXInverse x/c x/c Q/Vinf Q/Vinf Q Graph Q グラフ Must mark off target segment first Converged 収束 Unconverged 発散 Modified Warning 警告 Unrecognized foil format 読み込めない翼型フォーマット The minimum number of control points has been reached for this spline degree Drag points to modify splines, Apply, and Execute to generate the new geometry Mark target segment for modification Mark spline endpoints Alpha = 迎え角 = Cl = Cl = Mark target segment for smoothing, or type 'Return' to smooth the entire distribution Base Mod. Thickness = %1% 厚さ = %1% Max.Thick.pos. = %1% 最大翼厚位置 = %1% Max. Camber = %1% 最大キャンバー = %1% Alpha = %1 Cl = %1 Q - Reference Q - Specification Q - Viscous Reflected Alpha 迎え角 Cl Specification ShowSpline スプラインを表示 Tangent Spline New Spline New Spline Apply Spline スプラインを適用 Reset QSpec Pert Modification Smooth QSpec Hannig Filter Filter parameter Smoothing スムージング T.E. Angle 後縁角度 T.E. Gap dx/c T.E. Gap dy/c Symmetric foil 対称翼型 Constraints Execute 実行 Cl = Mark for modification End Point Constraint Smooth 平滑化 Max Iterations 最大繰り返し数 Foil 翼型 ReListDlg Reynolds Number List レイノルズ数リスト Insert 挿入 Delete 削除 OK OK Cancel キャンセル RenameDlg Rename 名称変更 Enter the new name 新しい名前の入力 Existing Names: 既存の名前: OK OK Cancel キャンセル Overwrite 上書き Note : Overwrite will delete Opps and reset polars 注意:上書きは実行点を消去し,ポーラーをリセットする. Enter a name 名前を入力 Warning 警告 Must enter a name 名前を入力してください Do you wish to overwrite 上書きしますか? Question 確認 SaveOptionsDlg Save Options 保存オプション Save: 保存: Foil Operating Points 翼型の動作点 Wing and Plane Operating Points 翼・機体の動作点 OK OK Cancel キャンセル SplineCtrlsDlg Spline Parameters スプライン曲線のパラメータ Upper side 上面 Lower side 下面 Spline degree スプライン曲線の次数 Output 出力点 Symetric foil 対称翼 Point Weight = OK Cancel キャンセル Warning 警告 The spline degree must be less than the number of control points StabPolarDlg Stability Polar Definition Control Name Controls Wing Tilt ( 主翼の傾き( Elevator Tilt 水平尾翼の傾き Wing Flap angle %1 Elevator Flap %1 主翼フラップ角 %1 Fin Flap %1 垂直尾翼フラップ %1 Warning 警告 Mass must be non-zero for type 7 polars タイプ7解析においては質量は正値でなければなりません Must enter a name 名前を入力してください Wing Name 翼の名前 Auto Analysis Name 解析データの名前を自動設定にする Polar Name 特性曲線の名前 b = b = f = f = Use plane inertia 機体の慣性値を適用 VLM 3D Panels 3Dパネル法 Wing analysis methods 翼の解析方法 Mix 3D Panels/VLM 3Dパネル法とVLM法の混合 Note: + sign means trailing edge down 注意: + の表示は後縁のダウン方向を意味します Gain ゲイン Viscous Analysis 粘性解析 Note : the analysis may be of the viscous type only if all the flap controls are inactive 注意 : 全てのフラップを動かさない場合のみ 粘性タイプの解析を用いてもよい Plane and Flight Data 機体と飛行データ Unit 単位 International Imperial ヤード・ポンド法 Aerodynamic Data 空気力学的データ Wing Planform Area 翼の幾何的面積 Wing Planform Area projected on xy plane xy平面に投影された翼の幾何的面積 Reference Area for Aero Coefficients 空力効率に引用される翼面積 Plane analysis methods 機体の解析方法 OK Cancel キャンセル Ignore Body Panels StabViewDlg Stability View Params Longitudinal Lateral Stability direction 安定方向 Initial Conditions Response 初期状態反応 Forced Response 強制反応 Initial conditions 初期条件 Modal Response Modal response Define the total time range for the graphs グラフの時間レンジを定義せよ Define the time step for the resolution of the differential equations 微分方程式の分解能のための時間ステップの設定 Re-calculate the currently selected curve with the user-specified input data ユーザ指定入力データを用いて現在選択されている曲線を再計算 Add a new curve to the graphs, using the current user-specified input 現在のユーザ指定入力データを用いてグラフに新しい曲線を追加 Rename the currently selected curve 現在選択されている曲線の名前を変更 Delete the currently selected curve 現在選択されている曲線を削除 Time Graph Params 時間発展グラフパラメータ Mode Selection モード選択 Eigenvalues 固有値 F1 = F1 = z = z = Mode properties モデルの特性 Total Time 総時間 Operating point modes Speed 対気速度 Amplitude 振幅 Animate アニメーション表示 Restart リスタート Time Step = 時間間隔= s s Animation アニメーション Time (s) 時間(秒) Angle Controls Mode Properties: Control function Enter the function of the control vs. time Curve Settings 曲線設定 Recalc. 再計算 Add 追加 Rename 名称変更 Delete 削除 Press Ctrl+H to highlight the mode on the root locus plot Ctrl+H で根軌跡上のモードをハイライト u0= u0= w0= w0= q0= q0= v0= v0= p0= p0= r0= r0= New curve 新しい曲線 <small>Mode Properties: TEGapDlg T.E. Gap 後縁の隙間 T.E. Gap Value 後縁の隙間の値 % chord % コード長 Blending Distance from L.E. OK OK Cancel キャンセル Apply 適用 Warning 警告 Unrecognized foil format 読み込めない翼型フォーマット Panel number cannot exceed 300 メッシュの数は300を超えることができません TranslatorDlg Language settings 言語設定 English 日本語 Warning 警告 The change will take effect at the next session 変更は次のセッションから有効になります Select the application's default language: アプリケーションの既定の言語を選択してください: OK OK Cancel キャンセル The directory ディレクトリ does not exist は存在しません does not exist TwoDPanelDlg Global Panel Refinement Number of Panels メッシュ数 Panel Bunching Parameter TE/LE Panel Density Ratio 後縁/前縁パネル密度比 Refined area/LE Panel Density Ratio Top Side Refined Area x/c limits Bottom Side Refined Area x/c limits OK OK Cancel キャンセル Apply 適用 Warning 警告 Unrecognized foil format 読み込めない翼型フォーマット The total number of panels cannot exceed %1 合計メッシュ数は%1を超えることはできません UnitsDlg Select units for this project : このプロジェクトの単位系を選択してください : Units Dialog 単位ダイアログ Length 長さ Area 面積 Speed 速さ Mass 質量 Force Moment モーメント Define the project units プロジェクトの単位の定義 OK OK Cancel キャンセル W3dPrefsDlg 3D Styles 3D スタイル Axis Outline アウトライン VLM Mesh VLMメッシュ Top transition 上面の遷移 Bottom transition 下面の遷移 Lift 揚力 Moments モーメント Induced Drag 誘導抗力 Viscous Drag 粘性抗力 Downwash 吹き下ろし WakePanels 後流のメッシュ Streamlines Masses 質量 Show Wake Panels 後流のメッシュを表示 OK OK Cancel キャンセル WAdvancedDlg Wing Analysis Advanced Settings 翼解析の高度な設定 View Log File after errors エラーの後にログファイルを表示 Reset Wake between each angle 各角度の計算ごとに後流をリセット Store points outside the polar mesh All Analysis 全ての解析 VLM and Panel Methods VLM及びパネル法 Core Size VLM Method VLM法 Ignore wing panels with span < Horseshoe vortex 馬蹄形渦 Ring vortex 渦輪 Vortex Position 渦位置 Control Point Position Lifting Line Method 揚力線理論 Relax. factor 緩和係数 Alpha Precision Max. Iterations 最大反復回数 Number of spanwise stations 3D Panel boundary conditions 3D Panel法の境界条件 OK OK Cancel キャンセル Reset Defaults 初期値に戻す WPolarDlg Analysis Definition 解析の定義 Warning 警告 Must enter a name for the polar 曲線の名前を入力して下さい Wing Name 翼の名前 Auto Analysis Name 解析データの名前を自動設定にする Polar Name 特性曲線の名前 Type 1 (Fixed Speed) タイプ1(速度一定) Type 2 (Fixed Lift) タイプ2(揚力一定) Type 4 (Fixed aoa) タイプ4(迎角一定) Polar Type グラフの種類 Free Stream Speed = 自由流れの速度 = Inertia properties 慣性データ Use plane inertia 機体の慣性値を適用 Plane Mass = 機体重量 = X_CoG = 重心のX座標= Z_CoG = 重心のZ座標値= Plane and Flight Data 機体と飛行データ Wing Loading = 0.033 kg/dm2 翼面荷重=0.033 kg/dm2 SRe SRe RRe RRe QInfCl QInfCl Flight Characteristics 飛行特性 Mass must be non-zero for type 2 polars タイプ2で解析を行う場合は、質量を正の値にしてください。 LLT VLM 3D Panels 3Dパネル法 Wing analysis methods 翼の解析方法 Mix 3D Panels/VLM 3Dパネル法とVLM法の混合 Unit 単位 International Imperial ヤード・ポンド法 Vinf.sqrt(Cl) = Vinf.sqrt(Cl) = Aerodynamic Data 空気力学的データ Viscous Tilt. Geom. Options オプション Ground Effect 地面効果 Height = 高さ= Wing Planform 翼平面型 Wing Planform projected on xy plane XY平面に投影された翼平面型 Reference Area and Span for Aero Coefficients 空力微係数の基準面積およびスパン OK Cancel キャンセル Root Re = 翼根のRe Tip Re = 翼端のRe Root Re.sqrt(Cl) = Root Re.sqrt(Cl) = Tip Re.sqrt(Cl) = Tip Re.sqrt(Cl) = Wing Loading = 翼面荷重 Ignore Body Panels WingDelegate Uniform 一様 Cosine Cos Sine Sin -Sine WingScaleDlg Scale Wing Dlg Span Scaling 全長のスケール Chord Scaling Sweep Scaling Twist Scaling Reference 元の値 New 新規 Ratio OK OK Cancel キャンセル XDirectStyleDlg XDirect Styles Neutral Line 軸線 Boundary Layer 境界層 Pressure 圧力 OK OK Defaults デフォルト Cancel キャンセル XFoilAdvancedDlg XFoil Settings XFoil 設定 VAccel Iteration Limit 反復回数上限 Re-initialize BLs after an unconverged iteration 反復計算で収束しない場合境界層を再初期化 Show full log report for an XFoil analysis XFoil 解析の全てのログを表示 OK OK Cancel キャンセル XFoilAnalysisDlg XFoil Analysis XFoil 解析 Iter 反復 Skip スキップ Cancel キャンセル Alpha = %1 迎角 = %1 Alfa = %1 ........ 迎角 = %1 ....... Invalid Analysis Settings CpCalc: local speed too large Compressibility corrections invalid 解析条件が無効 局所速度が過大 圧縮補正が無効 Cl = %1 Cl = %1 Cl = %1 ........ Initializing viscous analysis ... 初期化粘性解析... CpCalc: local speed too large Compressibility corrections invalid Cp計算において局所速度が過大 圧縮補正が無効 Solving BL system ... 境界層系を計算中... Iteration %1 ... 反復 %1 回目... unconverged after %1 iterations 反復%1回で収束しませんでした --------- Unconverged ----------- --------- 未収束 ----------- converged after %1 iterations 反復%1回で収束しました Close 閉じる xflr5-6.09-06/src/000755 001750 000144 00000000000 12250656031 015055 5ustar00techwinderusers000000 000000 xflr5-6.09-06/src/graph/000755 001750 000144 00000000000 12250154041 016150 5ustar00techwinderusers000000 000000 xflr5-6.09-06/src/graph/Graph.h000644 001750 000144 00000015636 12247174404 017410 0ustar00techwinderusers000000 000000 /**************************************************************************** Graph Classes Copyright (C) 2003 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef GRAPH_H #define GRAPH_H #include #include #include #include #include #include #include "../objects/CRectangle.h" #include "Curve.h" class Graph { friend class GLGraph; friend class QGraph; friend class GraphWidget; friend class QXDirect; public: bool GetAutoX(); bool GetAutoY(); bool GetAutoXMin(); bool GetAutoYMin(); bool GetBorder(); bool GetInverted(); bool IsInDrawRect(CVector const &pt); bool IsInDrawRect(int const &x, int const &y); bool IsInDrawRect(QPoint const &pt); bool Init(); double ClientTox(int x); double ClientToy(int y); double ClientTox(double x); double ClientToy(double y); int xToClient(double x); int yToClient(double y); void CopySettings(Graph* pGraph, bool bScales=true); void DeselectPoint(); Curve * GetCurvePoint(const int &xClt, const int &yClt, int &nSel); Curve * GetClosestPoint(double const &x, double const &y, double &xSel, double &ySel, int &nSel); void ResetLimits(); void ResetCurves(); void Scale(double zoom); void Scalex(double zoom); void Scaley(double zoom); void SetAutoXMinUnit(bool bAuto); void SetAutoYMinUnit(bool bAuto); void SetAutoXUnit(); void SetAutoYUnit(); void SetAxisData(int s, int w, QColor clr); void SetBkColor(QColor cr); void SetBorderColor(QColor crBorder); void SetBorder(bool bBorder); void SetBorderStyle(int s); void SetBorderWidth(int w); void SetDrawRect(CRectangle &Rect); void SetDrawRect(QRect &Rect); void SetMargin(int m); void SetMargin(double m); void SetInverted(bool bInverted); void SetType(int type); void SetXTitle(QString str); void SetYTitle(QString str); void SetX0(double f); void SetXMax(double f); void SetXMin(double f); void SetXMinorUnit(double f); void SetXUnit(double f); void SetY0(double f); void SetYMax(double f); void SetYMin(double f); void SetYMinorUnit(double f); void SetYUnit(double f); void SetXMajGrid(bool const &state, QColor const &clr, int const &style, int const &width); void SetYMajGrid(bool const &state, QColor const &clr, int const &style, int const &width); void SetXMinGrid(bool state, bool bAuto, QColor clr, int style, int width, double unit = -1.0); void SetYMinGrid(bool state, bool bAuto, QColor clr, int style, int width, double unit = -1.0); void SetAuto(bool bAuto); void SetAutoX(bool bAuto); void SetAutoY(bool bAuto); void SetLogPixelsY(int n); void SetAxisColor(QColor crColor); void SetAxisStyle(int nStyle); void SetAxisWidth(int Width); void SetTitleColor(QColor crColor); void SetLabelColor(QColor crColor); void SetTitleLogFont(QFont *plgft); void SetLabelLogFont(QFont *plgft); void SetWindow(double x1, double x2, double y1, double y2); QColor GetAxisColor(); QColor GetBorderColor(); QColor GetBackColor(); QColor GetTitleColor(); QColor GetLabelColor(); int GetBorderStyle(); int GetCurveCount(); int GetLogPixelsY(); int GetMargin(); int GetAxisStyle(); int GetAxisWidth(); int GetBorderWidth(); int GetXVariable(); int GetYVariable(); void SetVariables(int const & X, int const & Y); void SetXVariable(int const & X); void SetYVariable(int const & Y); double GetX0(); double GetXMin(); double GetXMax(); double GetXUnit(); double GetY0(); double GetYMin(); double GetYMax(); double GetYUnit(); double GetXScale(); double GetYScale(); bool GetXMajGrid(); bool GetYMajGrid(); bool GetXMinGrid(); bool GetYMinGrid(); bool SelectPoint(QString const &CurveName, int sel); bool SetXScale(); bool SetYScale(); void SetXMajGrid(bool const &bGrid); void SetYMajGrid(bool const &bGrid); void SetXMinGrid(bool const &bGrid); void SetYMinGrid(bool const &bGrid); void GetXMajGrid(bool &bstate, QColor &clr, int &style, int &width); void GetYMajGrid(bool &bstate, QColor &clr, int &style, int &width); void GetXMinGrid(bool &bstate, bool &bAuto, QColor &clr, int &style, int &width, double &unit); void GetYMinGrid(bool &bstate, bool &bAuto, QColor &clr, int &style, int &width, double &unit); void GetXTitle(QString &str); void GetYTitle(QString &str); void GetTitleLogFont(QFont *plgft); void GetLabelLogFont(QFont *plgft); void GetClientRect(QRect &Rect); void SetDefaults(); void SetGraphName(QString GraphName); void GetGraphName(QString &GraphName); QString GetGraphName(); Curve* GetCurve(int nIndex); Curve* GetCurve(QString CurveTitle); Curve* AddCurve(); void DeleteCurve(int index); void DeleteCurve(Curve *pCurve); void DeleteCurve(QString CurveTitle); void DeleteCurves(); void ResetXLimits(); void ResetYLimits(); Graph(); virtual ~Graph(); static QColor m_CurveColors[10]; private: QString m_GraphName; int m_Type; int m_LogPixelsY; QRect m_rCltRect; //in screen coordinates CRectangle m_rDrawRect; //in viewport coordinated bool m_bXMajGrid, m_bXMinGrid; bool m_bYMajGrid, m_bYMinGrid; bool m_bXAutoMinGrid, m_bYAutoMinGrid; bool m_bYInverted; bool m_bAutoX, m_bAutoY; bool m_bBorder; int m_AxisStyle;// axis style int m_AxisWidth;// axis width int m_XMajStyle, m_YMajStyle; int m_XMajWidth, m_YMajWidth; QColor m_XMajClr, m_YMajClr; int m_XMinStyle, m_YMinStyle; int m_XMinWidth, m_YMinWidth; QColor m_XMinClr, m_YMinClr; double m_XMinorUnit,m_YMinorUnit; QString m_XTitle; QString m_YTitle; QList m_oaCurves; QPoint m_ptoffset; //in screen coordinates, w.r.t. the client area int exp_x, exp_y; double xo, yo; double xunit, yunit; double xmin, ymin, xmax, ymax; double Cxmin, Cxmax, Cymin, Cymax; double m_scalex, m_scaley; double m_h, m_w; //graph width and height int m_iMargin; QColor m_AxisColor; QFont m_TitleFont; QFont m_LabelFont; QColor m_TitleColor; QColor m_LabelColor; QColor m_BkColor; QColor m_BorderColor; int m_BorderStyle; int m_BorderWidth; int m_X, m_Y; //index of X and Y variables }; #endif xflr5-6.09-06/src/graph/GraphWidget.cpp000644 001750 000144 00000004321 12247174404 021074 0ustar00techwinderusers000000 000000 /**************************************************************************** GraphWidget Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "GraphWidget.h" #include #include #include #include GraphWidget::GraphWidget() { m_TitlePosition.setX(0); m_TitlePosition.setY(0); m_GraphTitle = ""; } void GraphWidget::SetTitle(QString &Title, QPoint &Place) { m_GraphTitle = Title; m_TitlePosition = Place; } void GraphWidget::paintEvent(QPaintEvent * event ) { if(!m_pGraph) return; QPainter painter(this); painter.save(); QBrush Bck(m_pGraph->m_BkColor); painter.fillRect(event->rect(), Bck); painter.setBackgroundMode(Qt::OpaqueMode); painter.setBackground(Bck); QRect rect(10, 20, 80, 60); QPen mypen; mypen.setColor(QColor(255,0,0)); mypen.setWidth(1); mypen.setStyle(Qt::SolidLine); painter.setPen(mypen); painter.drawLine(39,78,200,302); m_pGraph->DrawGraph(painter); QPen BorderPen; BorderPen.setColor(m_pGraph->m_BorderColor); BorderPen.setWidth(3); painter.setPen(BorderPen); painter.setBrush(Qt::NoBrush); painter.drawRect(QRect(0, 0, width() - 1, height() - 1)); painter.drawText(m_TitlePosition, m_GraphTitle); painter.restore(); } void GraphWidget::resizeEvent ( QResizeEvent * event ) { QRect r = rect(); if(m_pGraph) m_pGraph->SetDrawRect(r); } xflr5-6.09-06/src/graph/GraphWidget.h000644 001750 000144 00000003005 12247174404 020537 0ustar00techwinderusers000000 000000 /**************************************************************************** GraphWidget Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef GRAPHWIDGET_H #define GRAPHWIDGET_H #include #include "QGraph.h" class GraphWidget : public QWidget { friend class XFoilAnalysisDlg; friend class LLTAnalysisDlg; friend class BatchDlg; public: GraphWidget(); protected: void paintEvent(QPaintEvent *event); void resizeEvent (QResizeEvent *event); void SetTitle(QString &Title, QPoint &Place); /* QWidget *ScalePage; QWidget *AxisPage; QWidget *FontPage; QWidget *BackPage;*/ QPoint m_TitlePosition; QString m_GraphTitle; QGraph *m_pGraph; }; #endif // GRAPHWIDGET_H xflr5-6.09-06/src/graph/GraphDlg.h000644 001750 000144 00000006674 12247174404 020041 0ustar00techwinderusers000000 000000 /**************************************************************************** GraphDlg Classes Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef GRAPHDLG_H #define GRAPHDLG_H #include #include #include #include #include #include "../graph/Graph.h" #include "../misc/DoubleEdit.h" #include "../misc/ColorButton.h" #include "../misc/LineBtn.h" class GraphDlg : public QDialog { Q_OBJECT friend class Graph; public: GraphDlg(QWidget *pParent=NULL); void SetParams(); private slots: void OnOK(); void OnApply(); void OnTitleFont(); void OnLabelFont(); void OnTitleColor(); void OnLabelColor(); void OnRestoreParams(); void OnAutoX(); void OnAutoY(); void OnAutoMinGrid(); void OnAxisStyle(); void OnXMajGridStyle(); void OnXMinGridStyle(); void OnYMajGridStyle(); void OnYMinGridStyle(); void OnXMajGridShow(int state); void OnYMajGridShow(int state); void OnXMinGridShow(int state); void OnYMinGridShow(int state); void OnGraphBorder(int state); void OnGraphBackColor(); void OnBorderStyle(); void OnYInverted(); void OnActivePage(int index); void OnVariableChanged(); private: void keyPressEvent(QKeyEvent *event); void SetupLayout(); void SetButtonColors(); void SetApplied(bool bApplied); void Connect(); void FillVariableList(); QTabWidget *m_pTabWidget; QWidget *ScalePage, *FontPage, *GridPage; QWidget *VariablePage; QListWidget *m_pctrlXSel, *m_pctrlYSel; QPushButton *OKButton,*CancelButton, *RestoreButton, *ApplyButton; QPushButton *m_pctrlTitleButton, *m_pctrlLabelButton; QPushButton*m_pctrlTitleClr, *m_pctrlLabelClr; QLabel *m_pctrlTitleLabel, *m_pctrlLabelLabel; QCheckBox *m_pctrlXAuto, *m_pctrlYAuto, *m_pctrlYInverted; DoubleEdit *m_pctrlXMin, *m_pctrlXMax, *m_pctrlXOrigin,*m_pctrlXUnit; DoubleEdit *m_pctrlYMin, *m_pctrlYMax, *m_pctrlYOrigin,*m_pctrlYUnit; QCheckBox *m_pctrlXMajGridShow, *m_pctrlYMajGridShow, *m_pctrlXMinGridShow, *m_pctrlYMinGridShow; QCheckBox *m_pctrlAutoXMinUnit, *m_pctrlAutoYMinUnit; LineBtn *m_pctrlAxisStyle, *m_pctrlXMajGridStyle, *m_pctrlYMajGridStyle, *m_pctrlXMinGridStyle, *m_pctrlYMinGridStyle; DoubleEdit *m_pctrlXMinorUnit, *m_pctrlYMinorUnit; QCheckBox *m_pctrlGraphBorder; ColorButton *m_pctrlGraphBack; LineBtn *m_pctrlBorderStyle; QFont *m_pTitleFont, *m_pLabelFont; bool m_bApplied; public: Graph *m_pGraph, *m_pMemGraph; Graph *m_GraphArray[30]; int m_NGraph; int m_XSel, m_YSel; int m_iGraphType; bool m_bVariableChanged; static int s_ActivePage; static void *s_pMainFrame; }; #endif // GRAPHDLG_H xflr5-6.09-06/src/graph/QGraph.cpp000644 001750 000144 00000060140 12247174405 020053 0ustar00techwinderusers000000 000000 /**************************************************************************** QGraph Classes Copyright (C) 2008-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "QGraph.h" #include "../globals.h" #include #include #include QGraph::QGraph() { m_bHighlightPoint = false; m_iMargin = 10; m_rCltRect.setRect(0,0, 200, 300); SetDefaults(); } QGraph::~QGraph() { DeleteCurves(); } void QGraph::DrawGraph(QRect const &rect, QPainter &painter) { m_rCltRect = rect; DrawGraph(painter); } void QGraph::DrawGraph(QPainter &painter) { static QColor color; painter.save(); // Draw Border if(m_bBorder) color = m_BorderColor; else color = m_BkColor; QPen BorderPen(color); BorderPen.setStyle(GetStyle(m_BorderStyle)); BorderPen.setWidth(m_BorderWidth); painter.setPen(BorderPen); painter.fillRect(m_rCltRect, m_BkColor); painter.drawRect(m_rCltRect); Init(); painter.setClipRect(m_rCltRect); painter.setBackgroundMode(Qt::TransparentMode); if(m_bXMinGrid) DrawXMinGrid(painter); if(m_bYMinGrid) DrawYMinGrid(painter); if(m_bXMajGrid) DrawXMajGrid(painter); if(m_bYMajGrid) DrawYMajGrid(painter); DrawAxes(painter); DrawXTicks(painter); DrawYTicks(painter); for (int nc=0; nc < m_oaCurves.size(); nc++) DrawCurve(nc,painter); DrawTitles(painter); painter.setClipping(false); painter.restore(); } void QGraph::DrawCurve(int nIndex, QPainter &painter) { painter.save(); static double scaley; static int i, ptside; static QPoint From, To, Min, Max; static QRect rViewRect; ptside = 2; Curve* pCurve = GetCurve(nIndex); scaley = m_scaley; QBrush FillBrush(m_BkColor); painter.setBrush(FillBrush); QPen CurvePen(pCurve->color()); CurvePen.setStyle(GetStyle(pCurve->style())); CurvePen.setWidth((int)pCurve->width()); painter.setPen(CurvePen); Min.setX(int(xmin/m_scalex) +m_ptoffset.x()); Min.setY(int(ymin/scaley) +m_ptoffset.y()); Max.setX(int(xmax/m_scalex) +m_ptoffset.x()); Max.setY(int(ymax/scaley) +m_ptoffset.y()); rViewRect.setTopLeft(Min); rViewRect.setBottomRight(Max); if(pCurve->size()>=1) { From.setX(int(pCurve->x[0]/m_scalex+m_ptoffset.x())); From.setY(int(pCurve->y[0]/scaley +m_ptoffset.y())); if(pCurve->IsVisible()) { for (i=1; isize();i++) { To.setX(int(pCurve->x[i]/m_scalex+m_ptoffset.x())); To.setY(int(pCurve->y[i]/scaley +m_ptoffset.y())); painter.drawLine(From, To); From = To; } } if(pCurve->PointsVisible()) { for (i=0; isize();i++) { if(pCurve->selected() !=i) painter.drawRect(int(pCurve->x[i]/m_scalex+m_ptoffset.x())-ptside, int(pCurve->y[i]/ scaley+m_ptoffset.y())-ptside, 2*ptside,2*ptside); } } } if(m_bHighlightPoint) { int point = pCurve->selected(); if(point>=0) { //highlight QColor HighColor(0,40, 150); CurvePen.setWidth((int)pCurve->width()); CurvePen.setColor(HighColor); painter.setPen(CurvePen); To.setX(int(pCurve->x[point]/m_scalex+m_ptoffset.x())); To.setY(int(pCurve->y[point]/scaley +m_ptoffset.y())); painter.drawRect(To.x()-ptside-1,To.y()-ptside-1, 2*(ptside+1),2*(ptside+1)); } } painter.restore(); } void QGraph::DrawAxes(QPainter &painter) { static double xp, yp, scaley; static QPen AxesPen; scaley = m_scaley; painter.save(); AxesPen.setColor(m_AxisColor); AxesPen.setStyle(GetStyle(m_AxisStyle)); AxesPen.setWidth(m_AxisWidth); painter.setPen(AxesPen); //vertical axis if(xo>=xmin && xo<=xmax) xp = xo; else if(xo>xmax) xp = xmax; else xp = xmin; painter.drawLine((int)(xp/m_scalex) + m_ptoffset.x(), (int)(ymin/scaley) + m_ptoffset.y(), (int)(xp/m_scalex) + m_ptoffset.x(), (int)(ymax/scaley) + m_ptoffset.y()); //horizontal axis if(yo>=ymin && yo<=ymax) yp = yo; else if(yo>ymax) yp = ymax; else yp = ymin; painter.drawLine((int)(xmin/m_scalex) +m_ptoffset.x(), (int)(yp/scaley) + m_ptoffset.y(), (int)(xmax/m_scalex) +m_ptoffset.x(), (int)( yp/scaley) + m_ptoffset.y()); painter.restore(); } void QGraph::DrawTitles(QPainter &painter) { //draws the x & y axis name static double scaley; static int XPosXTitle, YPosXTitle, XPosYTitle, YPosYTitle; static double xp, yp; scaley = m_scaley; painter.save(); XPosXTitle = 5; YPosXTitle = -10; XPosYTitle = -5; YPosYTitle = 5; if(xo>=xmin && xo<=xmax) xp = xo; else if(xo>xmax) xp = xmax; else xp = xmin; if(yo>=ymin && yo<=ymax) yp = yo; else if(yo>ymax) yp = ymax; else yp = ymin; painter.setFont(m_TitleFont); QPen TitlePen(m_TitleColor); painter.setPen(TitlePen); painter.drawText( (int)(xmax/m_scalex) + m_ptoffset.x() + XPosXTitle, (int)(yp /scaley) + m_ptoffset.y() + YPosXTitle, m_XTitle); painter.drawText( m_ptoffset.x() + (int)(xp/m_scalex) + XPosYTitle, m_rCltRect.top() + m_iMargin - YPosYTitle, m_YTitle); painter.restore(); } void QGraph::DrawXTicks(QPainter &painter) { static double main, scaley, xt, yp; static int exp, TickSize, height, yExpOff, xMainOff, nx; exp=0; if(qAbs(xunit)<0.00000001) return; if(qAbs(xmax-xmin)/xunit>30.0) return; scaley = m_scaley; painter.save(); QString strLabel, strLabelExp; QFontMetrics fm(m_LabelFont); painter.setFont(m_LabelFont); TickSize = 5; height = fm.height()/2; yExpOff = height/2; xMainOff = 14; QPen LabelPen(m_AxisColor); LabelPen.setStyle(GetStyle(m_AxisStyle)); LabelPen.setWidth(m_AxisWidth); painter.setPen(LabelPen); xt = xo-(xo-xmin);//one tick at the origin nx = (int)((xo-xmin)/xunit); xt = xo - nx*xunit; if(yo>=ymin && yo<=ymax) yp = yo; else if(yo>ymax) yp = ymax; else yp = ymin; while(xt<=xmax*1.0001) { //Draw ticks if(xt>=xmin) { painter.setPen(LabelPen); painter.drawLine(int(xt/m_scalex) + m_ptoffset.x(),int(yp/scaley) +TickSize + m_ptoffset.y(), int(xt/m_scalex) + m_ptoffset.x(),int(yp/scaley) + m_ptoffset.y()); painter.setPen(m_LabelColor); if(exp_x>=4 || exp_x<=-4) { main = xt; ExpFormat(main, exp); strLabel = QString("%1 10").arg(main,5,'f',2); painter.drawText(int(xt/m_scalex) - fm.width(strLabel)/2 +m_ptoffset.x(), int(yp/scaley) + TickSize*2 +height +m_ptoffset.y(), strLabel); strLabelExp = QString("%1").arg(exp); painter.drawText(int(xt/m_scalex) + fm.width(strLabel)/2 +m_ptoffset.x(), int(yp/scaley) + TickSize*2 +height-yExpOff +m_ptoffset.y(), strLabelExp); } else { if(exp_x>0) strLabel = QString("%1").arg(xt,0,'f',0); else if (exp_x>=-1) strLabel = QString("%1").arg(xt,6,'f',1); else if (exp_x>=-2) strLabel = QString("%1").arg(xt,6,'f',2); else if (exp_x>=-3) strLabel = QString("%1").arg(xt,6,'f',3); painter.drawText((int)(xt/m_scalex) - fm.width(strLabel)/2 + m_ptoffset.x(), (int)(yp/scaley) + TickSize*2 +height + m_ptoffset.y(), strLabel); } } xt += xunit ; } painter.restore(); } void QGraph::DrawYTicks(QPainter &painter) { static double scaley, xp, main, yt; static int TickSize, xExpOff, fmheight, fmheight2, fmheight4, exp; if(qAbs(xunit)<0.00000001) return; if(qAbs(ymax-ymin)/yunit>30.0) return; scaley = m_scaley; painter.save(); QString strLabel, strLabelExp; exp = 0; QFontMetrics fm(m_LabelFont); painter.setFont(m_LabelFont); fmheight = fm.height(); fmheight2 = (int)(fmheight/2); fmheight4 = (int)(fmheight/4); TickSize = 5; xExpOff = 7; QPen LabelPen(m_AxisColor); LabelPen.setStyle(GetStyle(m_AxisStyle)); LabelPen.setWidth(m_AxisWidth); if(xo>=xmin && xo<=xmax) xp = xo; else if(xo>xmax) xp = xmax; else xp = xmin; yt = yo-int((yo-ymin)*1.0001/yunit)*yunit;//one tick at the origin while(yt<=ymax*1.0001) { //Draw ticks if(yt>=ymin) { painter.setPen(LabelPen); painter.drawLine((int)(xp/m_scalex) +m_ptoffset.x(), (int)(yt/scaley) +m_ptoffset.y(), (int)(xp/m_scalex)-TickSize +m_ptoffset.x(), (int)(yt/scaley) +m_ptoffset.y()); painter.setPen(m_LabelColor); if(exp_y>=3 || exp_y<=-3) { main = yt; ExpFormat(main, exp); /* if(qAbs(yt)<1.e-7) { main = 0.0; exp = 0; }*/ strLabel = QString("%1 10").arg(main,5,'f',2); strLabelExp = QString("%1").arg(exp); painter.drawText((int)(xp/m_scalex) - fm.width(strLabel)-TickSize*3 + m_ptoffset.x(), (int)(yt/scaley) + fmheight4 + m_ptoffset.y(), strLabel); if(exp_y>=3) { painter.drawText(int(xp/m_scalex) -TickSize*3 + m_ptoffset.x(), int(yt/scaley) + m_ptoffset.y(), strLabelExp); } else { painter.drawText(int(xp/m_scalex) -TickSize*3 + 2 + m_ptoffset.x(), int(yt/scaley) + m_ptoffset.y(), strLabelExp); } } else { if(exp_y>=0) strLabel = QString("%1").arg(yt,6,'f',0); else if (exp_y>=-1) strLabel = QString("%1").arg(yt,6,'f',1); else if (exp_y>=-2) strLabel = QString("%1").arg(yt,6,'f',2); else if (exp_y>=-3) strLabel = QString("%1").arg(yt,6,'f',3); painter.drawText((int)(xp/m_scalex) - fm.width(strLabel)-TickSize*2 +m_ptoffset.x(), (int)(yt/scaley) + fmheight4 +m_ptoffset.y(), strLabel); } } yt += yunit ; } painter.restore(); } void QGraph::DrawXMajGrid(QPainter &painter) { double scaley = m_scaley; if(qAbs(xunit)<0.00000001) return; if(qAbs(xmax-xmin)/xunit>30.0) return; painter.save(); int YMin, YMax; QPen GridPen(m_XMajClr); GridPen.setStyle(GetStyle(m_XMajStyle)); GridPen.setWidth(m_XMajWidth); painter.setPen(GridPen); YMin = (int)(ymin/scaley) + m_ptoffset.y(); YMax = (int)(ymax/scaley) + m_ptoffset.y(); double xt = xo-int((xo-xmin)*1.0001/xunit)*xunit;//one tick at the origin while(xt<=xmax*1.001) { if(xt>=xmin) { painter.drawLine(int(xt/m_scalex) + m_ptoffset.x(), YMin, int(xt/m_scalex) + m_ptoffset.x(), YMax); } xt += xunit ; } painter.restore(); } void QGraph::DrawYMajGrid(QPainter &painter) { double scaley = m_scaley; if(qAbs(yunit)<0.00000001) return; if(qAbs(ymax-ymin)/yunit>30.0) return; painter.save(); int width; if(m_YMajWidth<=1) width = 1; QPen GridPen(m_YMajClr); GridPen.setStyle(GetStyle(m_YMajStyle)); GridPen.setWidth(width); painter.setPen(GridPen); double yt = yo-int((yo-ymin)*1.0001/yunit)*yunit;//one tick at the origin int XMin = qMax((int)(xmin/m_scalex + m_ptoffset.x()), m_rCltRect.left()); int XMax = qMin((int)(xmax/m_scalex + m_ptoffset.x()), m_rCltRect.right()); while(yt<=ymax*1.0001) { if(yt>=ymin) { painter.drawLine(XMin, (int)(yt/scaley) + m_ptoffset.y(), XMax, (int)(yt/scaley) + m_ptoffset.y()); } yt += yunit ; } painter.restore(); } void QGraph::DrawXMinGrid(QPainter &painter) { double scaley = m_scaley; if(qAbs(xunit)<0.00000001) return; if(qAbs(m_XMinorUnit)<0.00000001) return; if(qAbs(xmax-xmin)/xunit>30.0) return; if(qAbs(xmax-xmin)/m_XMinorUnit>100.0) return; int YMin, YMax; painter.save(); QPen GridPen(m_XMinClr); GridPen.setStyle(GetStyle(m_XMinStyle)); GridPen.setWidth(m_XMinWidth); painter.setPen(GridPen); YMin = (int)(ymin/scaley)+ m_ptoffset.y(); YMax = (int)(ymax/scaley)+ m_ptoffset.y(); double xDelta = m_XMinorUnit; double xt = xo-int((xo-xmin)*1.0001/xDelta)*xDelta;//one tick at the origin while(xt<=xmax*1.001) { if(xt>=xmin) { painter.drawLine(int(xt/m_scalex) + m_ptoffset.x(), YMin, int(xt/m_scalex) + m_ptoffset.x(), YMax); } xt += xDelta; } painter.restore(); } void QGraph::DrawYMinGrid(QPainter &painter) { double scaley = m_scaley; if(qAbs(yunit)<0.00000001) return; if(qAbs(m_YMinorUnit)<0.00000001) return; if(qAbs(ymax-ymin)/yunit>30.0) return; if(qAbs(ymax-ymin)/m_YMinorUnit>100.0) return; painter.save(); QPen GridPen(m_YMinClr); GridPen.setStyle(GetStyle(m_YMinStyle)); GridPen.setWidth(m_YMinWidth); painter.setPen(GridPen); double yDelta = m_YMinorUnit; double yt = yo-int((yo-ymin)*1.0001/yDelta)*yDelta;//one tick at the origin int XMin = qMax((int)(xmin/m_scalex + m_ptoffset.x()), m_rCltRect.left()); int XMax = qMin((int)(xmax/m_scalex + m_ptoffset.x()), m_rCltRect.right()); while(yt<=ymax*1.0001) { if(yt>=ymin) { painter.drawLine(XMin, (int)(yt/scaley) + m_ptoffset.y(), XMax, (int)(yt/scaley) + m_ptoffset.y()); } yt += yDelta ; } painter.restore(); } void QGraph::DrawLegend(QPainter &painter, QPoint &Place, QFont &LegendFont, QColor &LegendColor) { painter.save(); int LegendSize, ypos; QString strong; LegendSize = 30; ypos = 12; painter.setFont(LegendFont); Curve* pCurve; QPen TextPen(LegendColor); QPen LegendPen(Qt::gray); int npos = 0; for (int nc=0; nc< m_oaCurves.size(); nc++) { pCurve = (Curve*) m_oaCurves[nc]; if(pCurve->IsVisible()) { pCurve->title(strong); if(pCurve->size()>0 && strong.length())//is there anything to draw ? { LegendPen.setColor(pCurve->color()); LegendPen.setStyle(GetStyle(pCurve->style())); LegendPen.setWidth(pCurve->width()); painter.setPen(LegendPen); painter.drawLine(Place.x(), Place.y() + ypos*npos, Place.x() + (int)(LegendSize), Place.y() + ypos*npos); painter.setPen(TextPen); painter.drawText(Place.x() + (int)(1.5*LegendSize), Place.y() + ypos*npos+(int)(ypos/2), strong); npos++; } } } painter.restore(); } void QGraph::ExpFormat(double &f, int &exp) { if (f==0.0) { exp = 0; f = 0.0; return; } double f1 = qAbs(f); if(f1<1) exp = (int)log10(f1)-1; else exp = (int)log10(f1); f = f/pow(10.0,exp); } void QGraph::ExportToFile(QFile &XFile, enumTextFileType FileType) { int i,j, maxpoints; Curve *pCurve; QString strong; QTextStream out(&XFile); maxpoints = 0; for(i=0; isize()); pCurve->title(strong); if(FileType==TXT) out << " "<size()) { if(FileType==TXT) strong= QString("%1 %2 ") .arg(pCurve->x[j],13,'g',7).arg(pCurve->y[j],13,'g',7); else strong= QString("%1, %2, , ") .arg(pCurve->x[j],13,'g',7).arg(pCurve->y[j],13,'g',7); } else { if(FileType==TXT) strong= " "; else strong= ", , , "; } out << strong; } out<<"\n"; //end of data line } out<<"\n"; //end of file XFile.close(); } QPoint QGraph::GetOffset() { return m_ptoffset; } void QGraph::Highlight(QPainter &painter, Curve *pCurve, int ref) { if(!pCurve) return; if(ref<0 || ref>pCurve->size()-1) return; painter.save(); int x = int(pCurve->x[ref]/m_scalex) +m_ptoffset.x(); int y = int(pCurve->y[ref]/m_scaley) +m_ptoffset.y(); QPen HighlightPen(QColor(255,100,100)); HighlightPen.setWidth(2); painter.setPen(HighlightPen); QRect r(x-3,y-3,6,6); painter.drawRect(r); painter.restore(); } void QGraph::SaveSettings(QSettings *pSettings) { QFont lgft; QColor clr; int k,s,w; bool ba, bs; double f; pSettings->beginGroup(m_GraphName); { //read variables clr = GetAxisColor(); pSettings->setValue("AxisColorRed", clr.red()); pSettings->setValue("AxisColorGreen",clr.green()); pSettings->setValue("AxisColorBlue", clr.blue()); k = GetAxisStyle(); pSettings->setValue("AxisStyle", k); k = GetAxisWidth(); pSettings->setValue("AxisWidth", k); clr = GetTitleColor(); pSettings->setValue("TitleColorRed", clr.red()); pSettings->setValue("TitleColorGreen",clr.green()); pSettings->setValue("TitleColorBlue", clr.blue()); clr = GetLabelColor(); pSettings->setValue("LabelColorRed", clr.red()); pSettings->setValue("LabelColorGreen",clr.green()); pSettings->setValue("LabelColorBlue", clr.blue()); GetTitleLogFont(&lgft); pSettings->setValue("TitleFontName", lgft.family()); pSettings->setValue("TitleFontSize", lgft.pointSize()); pSettings->setValue("TitleFontItalic", lgft.italic()); pSettings->setValue("TitleFontBold", lgft.bold()); GetLabelLogFont(&lgft); pSettings->setValue("LabelFontName", lgft.family()); pSettings->setValue("LabelFontSize", lgft.pointSize()); pSettings->setValue("LabelFontItalic", lgft.italic()); pSettings->setValue("LabelFontBold", lgft.bold()); GetXMajGrid(bs,clr,s,w); pSettings->setValue("XMajGridColorRed", clr.red()); pSettings->setValue("XMajGridColorGreen",clr.green()); pSettings->setValue("XMajGridColorBlue", clr.blue()); pSettings->setValue("XMajGridShow",bs); pSettings->setValue("XMajGridStyle",s); pSettings->setValue("XMajGridWidth",w); GetYMajGrid(bs,clr,s,w); pSettings->setValue("YMajGridColorRed", clr.red()); pSettings->setValue("YMajGridColorGreen",clr.green()); pSettings->setValue("YMajGridColorBlue", clr.blue()); pSettings->setValue("YMajGridShow",bs); pSettings->setValue("YMajGridStyle",s); pSettings->setValue("YMajGridWidth",w); GetXMinGrid(bs,ba,clr,s,w,f); pSettings->setValue("XMinGridColorRed", clr.red()); pSettings->setValue("XMinGridColorGreen",clr.green()); pSettings->setValue("XMinGridColorBlue", clr.blue()); pSettings->setValue("XMinGridAuto",ba); pSettings->setValue("XMinGridShow",bs); pSettings->setValue("XMinGridStyle",s); pSettings->setValue("XMinGridWidth",w); pSettings->setValue("XMinGridUnit",f); GetYMinGrid(bs,ba,clr,s,w,f); pSettings->setValue("YMinGridColorRed", clr.red()); pSettings->setValue("YMinGridColorGreen",clr.green()); pSettings->setValue("YMinGridColorBlue", clr.blue()); pSettings->setValue("YMinGridAuto",ba); pSettings->setValue("YMinGridShow",bs); pSettings->setValue("YMinGridStyle",s); pSettings->setValue("YMinGridWidth",w); pSettings->setValue("YMinGridUnit",f); clr = GetBorderColor(); s = GetBorderStyle(); w = GetBorderWidth(); pSettings->setValue("BorderColorRed", clr.red()); pSettings->setValue("BorderColorGreen", clr.green()); pSettings->setValue("BorderColorBlue", clr.blue()); pSettings->setValue("BorderStyle", s); pSettings->setValue("BorderWidth", w); pSettings->setValue("BorderShow", m_bBorder); clr = GetBackColor(); pSettings->setValue("BackColorRed", clr.red()); pSettings->setValue("BackColorGreen", clr.green()); pSettings->setValue("BackColorBlue", clr.blue()); pSettings->setValue("Inverted", m_bYInverted); pSettings->setValue("XVariable", m_X); pSettings->setValue("YVariable", m_Y); } pSettings->endGroup(); } void QGraph::LoadSettings(QSettings *pSettings) { int k; QFont lgft; bool bs, ba; int s,w; int r,g,b; double f; pSettings->beginGroup(m_GraphName); { //read variables r = pSettings->value("AxisColorRed",255).toInt(); g = pSettings->value("AxisColorGreen",255).toInt(); b = pSettings->value("AxisColorBlue",255).toInt(); SetAxisColor(QColor(r,g,b)); k = pSettings->value("AxisStyle",0).toInt(); SetAxisStyle(k); k = pSettings->value("AxisWidth",1).toInt(); SetAxisWidth(k); r = pSettings->value("TitleColorRed",255).toInt(); g = pSettings->value("TitleColorGreen",255).toInt(); b = pSettings->value("TitleColorBlue",255).toInt(); SetTitleColor(QColor(r,g,b)); r = pSettings->value("LabelColorRed",255).toInt(); g = pSettings->value("LabelColorGreen",255).toInt(); b = pSettings->value("LabelColorBlue",255).toInt(); SetLabelColor(QColor(r,g,b)); lgft = QFont(pSettings->value("TitleFontName","Comic Sans MS").toString()); lgft.setPointSize(pSettings->value("TitleFontSize",8).toInt()); lgft.setItalic(pSettings->value("TitleFontItalic", false).toBool()); lgft.setBold(pSettings->value("TitleFontBold", false).toBool()); SetTitleLogFont(&lgft); lgft = QFont(pSettings->value("LabelFontName","Comic Sans MS").toString()); lgft.setPointSize(pSettings->value("LabelFontSize",8).toInt()); lgft.setItalic(pSettings->value("LabelFontItalic", false).toBool()); lgft.setBold(pSettings->value("LabelFontBold", false).toBool()); SetLabelLogFont(&lgft); r = pSettings->value("XMajGridColorRed",90).toInt(); g = pSettings->value("XMajGridColorGreen",90).toInt(); b = pSettings->value("XMajGridColorBlue",90).toInt(); bs = pSettings->value("XMajGridShow",true).toBool(); s = pSettings->value("XMajGridStyle",1).toInt(); w = pSettings->value("XMajGridWidth",1).toInt(); SetXMajGrid(bs,QColor(r,g,b),s,w); r = pSettings->value("YMajGridColorRed",90).toInt(); g = pSettings->value("YMajGridColorGreen",90).toInt(); b = pSettings->value("YMajGridColorBlue",90).toInt(); bs = pSettings->value("YMajGridShow",true).toBool(); s = pSettings->value("YMajGridStyle",1).toInt(); w = pSettings->value("YMajGridWidth",1).toInt(); SetYMajGrid(bs,QColor(r,g,b),s,w); r = pSettings->value("XMinGridColorRed",50).toInt(); g = pSettings->value("XMinGridColorGreen",50).toInt(); b = pSettings->value("XMinGridColorBlue",50).toInt(); ba = pSettings->value("XMinGridAuto",true).toBool(); bs = pSettings->value("XMinGridShow",false).toBool(); s = pSettings->value("XMinGridStyle",2).toInt(); w = pSettings->value("XMinGridWidth",1).toInt(); f = pSettings->value("XMinGridUnit", 0.01).toDouble(); SetXMinGrid(bs,ba,QColor(r,g,b),s,w,f); r = pSettings->value("YMinGridColorRed",50).toInt(); g = pSettings->value("YMinGridColorGreen",50).toInt(); b = pSettings->value("YMinGridColorBlue",50).toInt(); ba = pSettings->value("YMinGridAuto",true).toBool(); bs = pSettings->value("YMinGridShow",false).toBool(); s = pSettings->value("YMinGridStyle",2).toInt(); w = pSettings->value("YMinGridWidth",1).toInt(); f = pSettings->value("YMinGridUnit",0.01).toDouble(); SetYMinGrid(bs,ba,QColor(r,g,b),s,w,f); r = pSettings->value("BorderColorRed",200).toInt(); g = pSettings->value("BorderColorGreen",200).toInt(); b = pSettings->value("BorderColorBlue",200).toInt(); s = pSettings->value("BorderStyle",0).toInt(); w = pSettings->value("BorderWidth",2).toInt(); m_bBorder = pSettings->value("BorderShow", true).toBool(); SetBorderColor(QColor(r,g,b)); SetBorderStyle(s); SetBorderWidth(w); r = pSettings->value("BackColorRed",0).toInt(); g = pSettings->value("BackColorGreen",20).toInt(); b = pSettings->value("BackColorBlue",20).toInt(); SetBkColor(QColor(r,g,b)); m_bYInverted = pSettings->value("Inverted", false).toBool(); m_X = pSettings->value("XVariable",1).toInt(); m_Y = pSettings->value("YVariable",0).toInt(); } pSettings->endGroup(); } xflr5-6.09-06/src/graph/QGraph.h000644 001750 000144 00000004112 12247174404 017514 0ustar00techwinderusers000000 000000 /**************************************************************************** QGraph Classes Copyright (C) 2008-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef QGraph_H #define QGraph_H #include "Graph.h" #include "Curve.h" #include "../objects/CRectangle.h" #include #include #include class QGraph : public Graph { public: QGraph(); virtual ~QGraph(); void DrawGraph(QRect const & rect, QPainter &painter); void DrawGraph(QPainter &painter); void DrawAxes(QPainter &painter); void DrawCurve(int nIndex, QPainter &painter); void DrawLegend(QPainter &painter, QPoint &Place, QFont &LegendFont, QColor &LegendColor); void DrawTitles(QPainter &painter); void DrawXMinGrid(QPainter &painter); void DrawYMinGrid(QPainter &painter); void DrawXMajGrid(QPainter &painter); void DrawYMajGrid(QPainter &painter); void DrawXTicks(QPainter &painter); void DrawYTicks(QPainter &painter); void ExpFormat(double &f, int &exp); void ExportToFile(QFile &XFile, enumTextFileType FileType); void Highlight(QPainter &painter, Curve *pCurve, int ref); void LoadSettings(QSettings *pSettings); void SaveSettings(QSettings *pSettings); QPoint GetOffset(); public: void *m_pParent; bool m_bHighlightPoint; }; #endif xflr5-6.09-06/src/graph/Curve.h000644 001750 000144 00000011550 12247174404 017422 0ustar00techwinderusers000000 000000 /**************************************************************************** Curve Class Copyright (C) 2003-2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file * * This file implements the Curve object for the graphs. * */ #ifndef CURVE_H #define CURVE_H #include "../params.h" #include "../objects/CVector.h" #include #include /** * @class Curve * This class defines the curve object used by the Graph class. */ class Curve { friend class Graph; friend class QGraph; public: Curve(); int AppendPoint(double xn, double yn); /** * Resets the content of the curve. */ void clear() { x.clear(); y.clear(); } int closestPoint(double xs, double ys, double &dist); void closestPoint(double xs, double ys, double &dist, int &n); void closestPoint(double const &xs, double const &ys, double &xSel, double &ySel, double &dist, int &nSel); void CopyData(Curve *pCurve); void Duplicate(Curve *pCurve); /** * Return the index of the currently selected point *@param the index of the currently selected point */ int selected(){return m_iSelected;} CVector point(int ref); /** * Sets the visibility of the points in the graphs *@param bShow true if the points are to be displayed, false otherwise */ void ShowPoints(bool bShow){m_bShowPoints = bShow;} /** * Sets the visibility of the curve in the graphs *@param bVisible true if the curve is to be displayed, false otherwise */ void SetVisible(bool bVisible){m_bIsVisible = bVisible;} /** * Sets the curve's color * @param clr the new QColor value for the curve */ void SetColor(QColor clr){CurveColor = clr;} /** * Sets the curve's style * @param nStyle the index of the new curve's style */ void SetStyle(int nStyle){ CurveStyle = nStyle;} /** * Sets the index of the currently selected point of this curve * @param n the point to select */ void SetSelected(int n){ m_iSelected = n;} /** *Sets the curve's width *@param nWidth the new curve's width in pixels **/ void SetWidth(int nWidth){CurveWidth = nWidth;} /** * Sets the curve title *@param Title the new curve's title */ void SetTitle(QString Title){ m_CurveName = Title;} /** Return the visibility of the curve as a boolean. */ bool IsVisible() {return m_bIsVisible;} /** Return the visibility of the points as a boolean. */ bool PointsVisible() {return m_bShowPoints; } /** Returns the Curve's number of points. */ int size() {return x.count();} /** Returns the Curve's number of points. */ int count() {return x.size();} /** Returns the Curve style*/ int style() {return CurveStyle;} /** Returns the Curve width*/ int width() {return CurveWidth;} /** Returns the Curve color*/ QColor color() {return CurveColor;} /** Returns the Curve's title */ void title(QString &string) {string = m_CurveName;} /** Returns the Curve's title */ QString title(){ return m_CurveName;} double xMin(); double xMax(); double yMin(); double yMax(); public: // Curve Data QVarLengthArray x; /**< the array of the points x-coordinates */ QVarLengthArray y; /**< the array of the points y-coordinates */ private: bool m_bIsVisible; /**< true if the curve is visible */ bool m_bShowPoints; /**< true if the curve's points are visible */ QColor CurveColor; /**< the curve's display color */ QString m_CurveName; /**< the curves's name */ int CurveStyle; /**< the index of the curve's display style */ int CurveWidth; /**< the width of the curve's display */ int m_iSelected; /**< the index of the curve's currently selected point, or -1 if none is selected */ void *m_pParentGraph; /**< a pointer to the parent graph to which this curve belongs */ }; #endif xflr5-6.09-06/src/graph/GraphDlg.cpp000644 001750 000144 00000105005 12247425645 020366 0ustar00techwinderusers000000 000000 /**************************************************************************** GraphDlg Classes Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "GraphDlg.h" #include "../misc/LinePickerDlg.h" #include "../mainframe.h" #include #include #include #include #include #include int GraphDlg::s_ActivePage; void *GraphDlg::s_pMainFrame; GraphDlg::GraphDlg(QWidget *pParent): QDialog(pParent) { setWindowTitle(tr("Graph Settings")); m_iGraphType = 1; m_pMemGraph = NULL; m_pGraph = NULL; m_NGraph = 0 ; m_bApplied = true; m_bVariableChanged = false; m_XSel = 0; m_YSel = 1; m_pTitleFont = m_pLabelFont = NULL; SetupLayout(); Connect(); } void GraphDlg::Connect() { connect(m_pctrlTitleClr, SIGNAL(clicked()), this, SLOT(OnTitleColor())); connect(m_pctrlLabelClr, SIGNAL(clicked()), this, SLOT(OnLabelColor())); connect(m_pctrlTitleButton, SIGNAL(clicked()), this, SLOT(OnTitleFont())); connect(m_pctrlLabelButton, SIGNAL(clicked()), this, SLOT(OnLabelFont())); connect(m_pctrlXAuto, SIGNAL(clicked()), this, SLOT(OnAutoX())); connect(m_pctrlYAuto, SIGNAL(clicked()), this, SLOT(OnAutoY())); connect(m_pctrlYInverted, SIGNAL(clicked()), this, SLOT(OnYInverted())); connect(m_pctrlXMajGridShow, SIGNAL(stateChanged(int)), this, SLOT(OnXMajGridShow(int))); connect(m_pctrlYMajGridShow, SIGNAL(stateChanged(int)), this, SLOT(OnYMajGridShow(int))); connect(m_pctrlXMinGridShow, SIGNAL(stateChanged(int)), this, SLOT(OnXMinGridShow(int))); connect(m_pctrlYMinGridShow, SIGNAL(stateChanged(int)), this, SLOT(OnYMinGridShow(int))); connect(m_pctrlAxisStyle, SIGNAL(clickedLB()), this, SLOT(OnAxisStyle())); connect(m_pctrlXMajGridStyle, SIGNAL(clickedLB()), this, SLOT(OnXMajGridStyle())); connect(m_pctrlYMajGridStyle, SIGNAL(clickedLB()), this, SLOT(OnYMajGridStyle())); connect(m_pctrlXMinGridStyle, SIGNAL(clickedLB()), this, SLOT(OnXMinGridStyle())); connect(m_pctrlYMinGridStyle, SIGNAL(clickedLB()), this, SLOT(OnYMinGridStyle())); connect(m_pctrlAutoXMinUnit, SIGNAL(clicked()), this, SLOT(OnAutoMinGrid())); connect(m_pctrlAutoYMinUnit, SIGNAL(clicked()), this, SLOT(OnAutoMinGrid())); connect(m_pctrlGraphBorder, SIGNAL(stateChanged(int)), this, SLOT(OnGraphBorder(int))); connect(m_pctrlGraphBack, SIGNAL(clicked()), this, SLOT(OnGraphBackColor())); connect(m_pctrlBorderStyle, SIGNAL(clicked()), this, SLOT(OnBorderStyle())); /* connect(m_pctrlXSel, SIGNAL(itemActivated ( QListWidgetItem*)), SLOT(OnVariableChanged())); connect(m_pctrlYSel, SIGNAL(itemActivated ( QListWidgetItem*)), SLOT(OnVariableChanged())); connect(m_pctrlXSel, SIGNAL(itemClicked ( QListWidgetItem*)), SLOT(OnVariableChanged())); connect(m_pctrlYSel, SIGNAL(itemClicked ( QListWidgetItem*)), SLOT(OnVariableChanged()));*/ connect(m_pctrlXSel, SIGNAL(itemSelectionChanged()), SLOT(OnVariableChanged())); connect(m_pctrlYSel, SIGNAL(itemSelectionChanged()), SLOT(OnVariableChanged())); connect(m_pctrlXSel, SIGNAL(itemDoubleClicked (QListWidgetItem *)), SLOT(OnOK())); connect(m_pctrlYSel, SIGNAL(itemDoubleClicked (QListWidgetItem *)), SLOT(OnOK())); connect(RestoreButton, SIGNAL(clicked()),this, SLOT(OnRestoreParams())); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(ApplyButton, SIGNAL(clicked()), this, SLOT(OnApply())); } void GraphDlg::FillVariableList() { m_pctrlXSel->clear(); m_pctrlYSel->clear(); if(m_iGraphType == 31) { m_pctrlXSel->addItem(tr("X - Chord")); m_pctrlYSel->addItem(tr("Q - Speed")); } else if(m_iGraphType==51) { //foil oppoint graph variables m_pctrlXSel->addItem(tr("X - chord")); m_pctrlYSel->addItem(tr("Cp")); m_pctrlYSel->addItem(tr("Q - Speed")); } else if(m_iGraphType==52) { //foil polar graph variables m_pctrlXSel->addItem(tr("Alpha")); m_pctrlXSel->addItem(tr("Cl")); m_pctrlXSel->addItem(tr("Cd")); m_pctrlXSel->addItem(tr("Cd x 10000")); m_pctrlXSel->addItem(tr("Cdp")); m_pctrlXSel->addItem(tr("Cm")); m_pctrlXSel->addItem(tr("Xtr1")); m_pctrlXSel->addItem(tr("Xtr2")); m_pctrlXSel->addItem(tr("HMom")); m_pctrlXSel->addItem(tr("Cpmin")); m_pctrlXSel->addItem(tr("Cl/Cd")); m_pctrlXSel->addItem(tr("|Cl|^(3/2)/Cd")); m_pctrlXSel->addItem(tr("1/Cl^1/2")); m_pctrlXSel->addItem(tr("Re")); m_pctrlXSel->addItem(tr("XCp")); m_pctrlYSel->addItem(tr("Alpha")); m_pctrlYSel->addItem(tr("Cl")); m_pctrlYSel->addItem(tr("Cd")); m_pctrlYSel->addItem(tr("Cd x 10000")); m_pctrlYSel->addItem(tr("Cdp")); m_pctrlYSel->addItem(tr("Cm")); m_pctrlYSel->addItem(tr("Xtr1")); m_pctrlYSel->addItem(tr("Xtr2")); m_pctrlYSel->addItem(tr("HMom")); m_pctrlYSel->addItem(tr("Cpmin")); m_pctrlYSel->addItem(tr("Cl/Cd")); m_pctrlYSel->addItem(tr("|Cl|^(3/2)/Cd")); m_pctrlYSel->addItem(tr("1/Cl^1/2")); m_pctrlYSel->addItem(tr("Re")); m_pctrlYSel->addItem(tr("XCp")); } else if(m_iGraphType==61) { //wing graph variable m_pctrlXSel->addItem(tr("Y - span")); m_pctrlYSel->addItem(tr("Induced Angle")); //0 m_pctrlYSel->addItem(tr("Total Angle")); //1 m_pctrlYSel->addItem(tr("Local lift coef.")); //2 m_pctrlYSel->addItem(tr("Local Lift C.Cl/M.A.C.")); //3 m_pctrlYSel->addItem(tr("Airfoil viscous drag coef.")); //4 m_pctrlYSel->addItem(tr("Induced drag coef.")); //5 m_pctrlYSel->addItem(tr("Total drag coef.")); //6 m_pctrlYSel->addItem(tr("Local Drag C.Cd/M.A.C.")); //7 m_pctrlYSel->addItem(tr("Airfoil Pitching moment coef.")); //8 m_pctrlYSel->addItem(tr("Total Pitching moment coef.")); //9 m_pctrlYSel->addItem(tr("Reynolds")); //10 m_pctrlYSel->addItem(tr("Top Transition x-pos%")); //11 m_pctrlYSel->addItem(tr("Bottom Transition x-pos%")); //12 m_pctrlYSel->addItem(tr("Centre of Pressure x-pos%")); //13 m_pctrlYSel->addItem(tr("Bending moment")); //14 } else if(m_iGraphType == 62) { //WingPolar Graph Variables m_pctrlXSel->addItem(tr("Alpha")); //0 m_pctrlXSel->addItem(tr("Lift coef.")); //1 m_pctrlXSel->addItem(tr("Viscous drag coef.")); //2 m_pctrlXSel->addItem(tr("Induced drag coef.")); //3 m_pctrlXSel->addItem(tr("Total drag coef.")); //4 m_pctrlXSel->addItem(tr("Total pitching moment coef."));//5 m_pctrlXSel->addItem(tr("Viscous pitching moment coef."));//6 m_pctrlXSel->addItem(tr("Induced pitching moment coef."));//7 m_pctrlXSel->addItem(tr("Total rolling moment coef.")); //8 m_pctrlXSel->addItem(tr("Total yawing moment coef.")); //9 m_pctrlXSel->addItem(tr("Viscous yawing moment coef."));//10 m_pctrlXSel->addItem(tr("Induced yawing moment coef."));//11 m_pctrlXSel->addItem(tr("Glide ratio Cl/Cd")); //12 m_pctrlXSel->addItem(tr("Power factor Cl^(3/2)/Cd")); //13 m_pctrlXSel->addItem(tr("1/Rt(Cl)")); //14 m_pctrlXSel->addItem(tr("FX (Drag)")); //15 m_pctrlXSel->addItem(tr("FY (Side force)")); //16 m_pctrlXSel->addItem(tr("FZ (Lift)")); //17 m_pctrlXSel->addItem(tr("Vx")); //18 m_pctrlXSel->addItem(tr("Vz")); //19 m_pctrlXSel->addItem(tr("VInf")); //20 m_pctrlXSel->addItem(tr("Descent angle atan(Cd/Cl)")); //21 m_pctrlXSel->addItem(tr("Pitching Moment")); //22 m_pctrlXSel->addItem(tr("Rolling Moment")); //23 m_pctrlXSel->addItem(tr("Yawing Moment")); //24 m_pctrlXSel->addItem(tr("Centre of pressure X-Pos")); //25 m_pctrlXSel->addItem(tr("Centre of pressure Y-Pos")); //26 m_pctrlXSel->addItem(tr("Centre of pressure Z-Pos")); //27 m_pctrlXSel->addItem(tr("Bending moment")); //28 m_pctrlXSel->addItem(tr("m.g.Vz")); //29 m_pctrlXSel->addItem(tr("Efficiency")); //30 m_pctrlXSel->addItem(tr("(XCp-Xcg)/MAC")); //31 m_pctrlXSel->addItem(tr("Control Variable")); //32 m_pctrlXSel->addItem(tr("Cy - Lateral force coef.")); //33 m_pctrlXSel->addItem(tr("Neutral Point x-position")); //34 m_pctrlXSel->addItem(tr("Phugoid Frequency")); //35 m_pctrlXSel->addItem(tr("Phugoid Damping")); //36 m_pctrlXSel->addItem(tr("Short Period Frequency")); //37 m_pctrlXSel->addItem(tr("Short Period Damping")); //38 m_pctrlXSel->addItem(tr("Dutch Roll Frequency")); //39 m_pctrlXSel->addItem(tr("Dutch Roll Damping")); //40 m_pctrlXSel->addItem(tr("Roll Damping")); //41 m_pctrlXSel->addItem(tr("Spiral Damping")); //42 //Y variable m_pctrlYSel->addItem(tr("Alpha")); //0 m_pctrlYSel->addItem(tr("Lift coef.")); //1 m_pctrlYSel->addItem(tr("Viscous drag coef.")); //2 m_pctrlYSel->addItem(tr("Induced drag coef.")); //3 m_pctrlYSel->addItem(tr("Total drag coef.")); //4 m_pctrlYSel->addItem(tr("Total pitching moment coef."));//5 m_pctrlYSel->addItem(tr("Viscous pitching moment coef."));//6 m_pctrlYSel->addItem(tr("Induced pitching moment coef."));//7 m_pctrlYSel->addItem(tr("Total rolling moment coef.")); //8 m_pctrlYSel->addItem(tr("Total yawing moment coef.")); //9 m_pctrlYSel->addItem(tr("Viscous yawing moment coef."));//10 m_pctrlYSel->addItem(tr("Induced yawing moment coef."));//11 m_pctrlYSel->addItem(tr("Glide ratio Cl/Cd")); //12 m_pctrlYSel->addItem(tr("Power factor Cl^(3/2)/Cd")); //13 m_pctrlYSel->addItem(tr("1/Rt(Cl)")); //14 m_pctrlYSel->addItem(tr("FX (Drag)")); //15 m_pctrlYSel->addItem(tr("FY (Side force)")); //16 m_pctrlYSel->addItem(tr("FZ (Lift)")); //17 m_pctrlYSel->addItem(tr("Vx")); //18 m_pctrlYSel->addItem(tr("Vz")); //19 m_pctrlYSel->addItem(tr("VInf")); //20 m_pctrlYSel->addItem(tr("Descent angle atan(Cd/Cl)")); //21 m_pctrlYSel->addItem(tr("Pitching Moment")); //22 m_pctrlYSel->addItem(tr("Rolling Moment")); //23 m_pctrlYSel->addItem(tr("Yawing Moment")); //24 m_pctrlYSel->addItem(tr("Centre of pressure X-Pos")); //25 m_pctrlYSel->addItem(tr("Centre of pressure Y-Pos")); //26 m_pctrlYSel->addItem(tr("Centre of pressure Z-Pos")); //27 m_pctrlYSel->addItem(tr("Bending moment")); //28 m_pctrlYSel->addItem(tr("m.g.Vz")); //29 m_pctrlYSel->addItem(tr("Efficiency")); //30 m_pctrlYSel->addItem(tr("(XCp-Xcg)/MAC")); //31 m_pctrlYSel->addItem(tr("Control Variable")); //32 m_pctrlYSel->addItem(tr("Cy - Lateral force coef.")); //33 m_pctrlYSel->addItem(tr("Neutral Point x-position")); //34 m_pctrlYSel->addItem(tr("Phugoid Frequency")); //35 m_pctrlYSel->addItem(tr("Phugoid Damping")); //36 m_pctrlYSel->addItem(tr("Short Period Frequency")); //37 m_pctrlYSel->addItem(tr("Short Period Damping")); //38 m_pctrlYSel->addItem(tr("Dutch Roll Frequency")); //39 m_pctrlYSel->addItem(tr("Dutch Roll Damping")); //40 m_pctrlYSel->addItem(tr("Roll Damping")); //41 m_pctrlYSel->addItem(tr("Spiral Damping")); //42 } else if(m_iGraphType == 64) { m_pctrlXSel->addItem(tr("X - Chord")); m_pctrlYSel->addItem(tr("Cp")); } m_pctrlXSel->adjustSize(); m_pctrlYSel->adjustSize(); } void GraphDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App // Generate the foil instead switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OKButton->setFocus(); } else { QDialog::accept(); } break; } case Qt::Key_Escape: { reject(); break; } default: event->ignore(); } } void GraphDlg::OnActivePage(int index) { s_ActivePage = index; ApplyButton->setEnabled(m_pTabWidget->currentIndex()!=0); } void GraphDlg::OnApply() { m_pGraph->SetAutoX(m_pctrlXAuto->isChecked()); m_pGraph->SetXMin(m_pctrlXMin->Value()); m_pGraph->SetXMax(m_pctrlXMax->Value()); m_pGraph->SetX0(m_pctrlXOrigin->Value()); m_pGraph->SetXUnit(m_pctrlXUnit->Value()); m_pGraph->SetAutoY(m_pctrlYAuto->isChecked()); m_pGraph->SetYMin(m_pctrlYMin->Value()); m_pGraph->SetYMax(m_pctrlYMax->Value()); m_pGraph->SetY0(m_pctrlYOrigin->Value()); m_pGraph->SetYUnit(m_pctrlYUnit->Value()); double MinUnit; if(!m_pctrlAutoXMinUnit->isChecked()) { MinUnit = m_pctrlXMinorUnit->Value(); m_pGraph->SetXMinorUnit(MinUnit); } if(!m_pctrlAutoYMinUnit->isChecked()) { MinUnit = m_pctrlYMinorUnit->Value(); m_pGraph->SetYMinorUnit(MinUnit); } m_pGraph->SetInverted(m_pctrlYInverted->isChecked()); for(int i=0; iCopySettings(m_pGraph); } MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->UpdateView(); SetApplied(true); } void GraphDlg::OnAutoMinGrid() { bool bAuto; bAuto = m_pctrlAutoXMinUnit->isChecked(); m_pGraph->SetAutoXMinUnit(bAuto); m_pctrlXMinorUnit->setEnabled(!bAuto); bAuto = m_pctrlAutoYMinUnit->isChecked(); m_pGraph->SetAutoYMinUnit(bAuto); m_pctrlYMinorUnit->setEnabled(!bAuto); } void GraphDlg::OnAutoX() { bool bAuto = m_pctrlXAuto->checkState() == Qt::Checked; m_pctrlXMin->setEnabled(!bAuto); m_pctrlXMax->setEnabled(!bAuto); m_pctrlXUnit->setEnabled(!bAuto); m_pctrlXOrigin->setEnabled(!bAuto); SetApplied(false); } void GraphDlg::OnAutoY() { bool bAuto = m_pctrlYAuto->checkState() == Qt::Checked; m_pctrlYMin->setEnabled(!bAuto); m_pctrlYMax->setEnabled(!bAuto); m_pctrlYUnit->setEnabled(!bAuto); m_pctrlYOrigin->setEnabled(!bAuto); SetApplied(false); } void GraphDlg::OnAxisStyle() { LinePickerDlg dlg(this); dlg.InitDialog(m_pGraph->GetAxisStyle(), m_pGraph->GetAxisWidth(), m_pGraph->GetAxisColor()); if(QDialog::Accepted==dlg.exec()) { m_pGraph->SetAxisData(dlg.GetStyle(), dlg.GetWidth(), dlg.GetColor()); m_pctrlAxisStyle->SetStyle(dlg.GetStyle()); m_pctrlAxisStyle->SetWidth(dlg.GetWidth()); m_pctrlAxisStyle->SetColor(dlg.GetColor()); SetApplied(false); } } void GraphDlg::OnBorderStyle() { LinePickerDlg dlg(this); int s,w; QColor color; s = m_pGraph->GetBorderStyle(); w = m_pGraph->GetBorderWidth(); color = m_pGraph->GetBorderColor(); dlg.InitDialog(s,w,color); if(QDialog::Accepted==dlg.exec()) { m_pGraph->SetBorderColor(dlg.GetColor()); m_pGraph->SetBorderStyle(dlg.GetStyle()); m_pGraph->SetBorderWidth(dlg.GetWidth()); m_pctrlBorderStyle->SetStyle(dlg.GetStyle()); m_pctrlBorderStyle->SetWidth(dlg.GetWidth()); m_pctrlBorderStyle->SetColor(dlg.GetColor()); SetApplied(false); } } void GraphDlg::OnGraphBorder(int state) { bool bShow = (state==Qt::Checked); m_pGraph->SetBorder(bShow); SetApplied(false); } void GraphDlg::OnGraphBackColor() { QColor BkColor = m_pGraph->GetBackColor(); BkColor = QColorDialog::getColor(BkColor); if(BkColor.isValid()) m_pGraph->SetBkColor(BkColor); m_pctrlGraphBack->SetColor(m_pGraph->GetBackColor()); SetButtonColors(); SetApplied(false); } void GraphDlg::OnLabelColor() { QColor color = m_pGraph->GetLabelColor(); m_pGraph->SetLabelColor(QColorDialog::getRgba(color.rgba())); QPalette palette = m_pctrlLabelClr->palette(); QColor listColor = palette.color(QPalette::Button); if(listColor.isValid()) { // palette.setColor(QPalette::Background, m_pGraph->GetBackColor()); palette.setColor(QPalette::Button, m_pGraph->GetBackColor()); palette.setColor(QPalette::ButtonText, m_pGraph->GetLabelColor()); m_pctrlLabelClr->setPalette(palette); // m_pctrlLabelClr->setAutoFillBackground(true); } SetApplied(false); } void GraphDlg::OnLabelFont() { bool ok; QFont LabelFont("Courier"); m_pGraph->GetLabelLogFont(&LabelFont); QFont font = QFontDialog::getFont(&ok, LabelFont, this); if (ok) { m_pctrlLabelButton->setFont(font); m_pctrlLabelButton->setText(font.family()); m_pGraph->SetLabelLogFont(&font); SetApplied(false); } } void GraphDlg::OnOK() { m_pGraph->SetAutoX(m_pctrlXAuto->isChecked()); m_pGraph->SetXMin(m_pctrlXMin->Value()); m_pGraph->SetXMax(m_pctrlXMax->Value()); m_pGraph->SetX0(m_pctrlXOrigin->Value()); m_pGraph->SetXUnit(m_pctrlXUnit->Value()); m_pGraph->SetAutoY(m_pctrlYAuto->isChecked()); m_pGraph->SetYMin(m_pctrlYMin->Value()); m_pGraph->SetYMax(m_pctrlYMax->Value()); m_pGraph->SetY0(m_pctrlYOrigin->Value()); m_pGraph->SetYUnit(m_pctrlYUnit->Value()); double MinUnit; if(!m_pctrlAutoXMinUnit->isChecked()) { MinUnit = m_pctrlXMinorUnit->Value(); m_pGraph->SetXMinorUnit(MinUnit); m_pGraph->SetAutoXMinUnit(false); } else m_pGraph->SetAutoXMinUnit(true); if(!m_pctrlAutoYMinUnit->isChecked()) { MinUnit = m_pctrlYMinorUnit->Value(); m_pGraph->SetYMinorUnit(MinUnit); m_pGraph->SetAutoYMinUnit(false); } else m_pGraph->SetAutoYMinUnit(true); for(int i=0; iCopySettings(m_pGraph); } m_XSel = m_pctrlXSel->currentRow(); m_YSel = m_pctrlYSel->currentRow(); m_pGraph->SetVariables(m_pctrlXSel->currentRow(), m_pctrlYSel->currentRow()); accept(); } void GraphDlg::OnRestoreParams() { m_pGraph->CopySettings(m_pMemGraph); for(int i=0; iCopySettings(m_pMemGraph); } SetParams(); SetApplied(true); MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->UpdateView(); } void GraphDlg::OnTitleColor() { QColor color = m_pGraph->GetTitleColor(); m_pGraph->SetTitleColor(QColorDialog::getRgba(color.rgba())); QPalette palette = m_pctrlTitleClr->palette(); QColor listColor = palette.color(QPalette::Button); if(listColor.isValid()) { // palette.setColor(QPalette::Background, m_pGraph->GetBackColor()); palette.setColor(QPalette::Button, m_pGraph->GetBackColor()); palette.setColor(QPalette::ButtonText, m_pGraph->GetTitleColor()); m_pctrlTitleClr->setPalette(palette); // m_pctrlTitleClr->setAutoFillBackground(true); } SetApplied(false); } void GraphDlg::OnTitleFont() { bool ok; QFont TitleFont("Arial"); m_pGraph->GetTitleLogFont(&TitleFont); QFont font = QFontDialog::getFont(&ok, TitleFont, this); if (ok) { m_pctrlTitleButton->setFont(font); m_pctrlTitleButton->setText(font.family()); m_pGraph->SetTitleLogFont(&font); SetApplied(false); } } void GraphDlg::OnVariableChanged() { m_bVariableChanged = true; } void GraphDlg::OnXMajGridStyle() { LinePickerDlg dlg(this); int s,w; QColor color; bool bShow; m_pGraph->GetXMajGrid(bShow,color,s,w); dlg.InitDialog(s,w,color); if(QDialog::Accepted==dlg.exec()) { m_pGraph->SetXMajGrid(bShow, dlg.GetColor(), dlg.GetStyle(), dlg.GetWidth()); m_pctrlXMajGridStyle->SetStyle(dlg.GetStyle()); m_pctrlXMajGridStyle->SetWidth(dlg.GetWidth()); m_pctrlXMajGridStyle->SetColor(dlg.GetColor()); SetApplied(false); } } void GraphDlg::OnXMinGridStyle() { LinePickerDlg dlg(this); int s,w; QColor color; bool bShow, bAuto; double unit; m_pGraph->GetXMinGrid(bShow, bAuto,color,s,w,unit); dlg.InitDialog(s,w,color); if(QDialog::Accepted==dlg.exec()) { m_pGraph->SetXMinGrid(bShow, bAuto, dlg.GetColor(), dlg.GetStyle(), dlg.GetWidth(),unit); m_pctrlXMinGridStyle->SetStyle(dlg.GetStyle()); m_pctrlXMinGridStyle->SetWidth(dlg.GetWidth()); m_pctrlXMinGridStyle->SetColor(dlg.GetColor()); SetApplied(false); } } void GraphDlg::OnXMajGridShow(int state) { bool bShow = (state==Qt::Checked); m_pGraph->SetXMajGrid(bShow); m_pctrlXMajGridStyle->setEnabled(bShow); SetApplied(false); } void GraphDlg::OnXMinGridShow(int state) { bool bShow = (state==Qt::Checked); m_pGraph->SetXMinGrid(bShow); m_pctrlXMinGridStyle->setEnabled(bShow); m_pctrlAutoXMinUnit->setEnabled(bShow); m_pctrlXMinorUnit->setEnabled(bShow && !m_pGraph->GetAutoXMin()); SetApplied(false); } void GraphDlg::OnYInverted() { m_pGraph->SetInverted(m_pctrlYInverted->checkState() == Qt::Checked); SetApplied(false); } void GraphDlg::OnYMajGridShow(int state) { bool bShow = (state==Qt::Checked); m_pGraph->SetYMajGrid(bShow); m_pctrlYMajGridStyle->setEnabled(bShow); SetApplied(false); } void GraphDlg::OnYMajGridStyle() { LinePickerDlg dlg(this); int s,w; QColor color; bool bShow; m_pGraph->GetYMajGrid(bShow,color,s,w); dlg.InitDialog(s,w,color); if(QDialog::Accepted==dlg.exec()) { m_pGraph->SetYMajGrid(bShow, dlg.GetColor(), dlg.GetStyle(), dlg.GetWidth()); m_pctrlYMajGridStyle->SetStyle(dlg.GetStyle()); m_pctrlYMajGridStyle->SetWidth(dlg.GetWidth()); m_pctrlYMajGridStyle->SetColor(dlg.GetColor()); } } void GraphDlg::OnYMinGridShow(int state) { bool bShow = (state==Qt::Checked); m_pGraph->SetYMinGrid(bShow); m_pctrlYMinGridStyle->setEnabled(bShow); m_pctrlAutoYMinUnit->setEnabled(bShow); m_pctrlYMinorUnit->setEnabled(bShow && !m_pGraph->GetAutoYMin()); SetApplied(false); } void GraphDlg::OnYMinGridStyle() { LinePickerDlg dlg(this); int s,w; QColor color; bool bShow, bAuto; double unit; m_pGraph->GetYMinGrid(bShow, bAuto,color,s,w,unit); dlg.InitDialog(s,w,color); if(QDialog::Accepted==dlg.exec()) { m_pGraph->SetYMinGrid(bShow, bAuto, dlg.GetColor(), dlg.GetStyle(), dlg.GetWidth(),unit); m_pctrlYMinGridStyle->SetStyle(dlg.GetStyle()); m_pctrlYMinGridStyle->SetWidth(dlg.GetWidth()); m_pctrlYMinGridStyle->SetColor(dlg.GetColor()); SetApplied(false); } } void GraphDlg::SetApplied(bool bApplied) { m_bApplied = bApplied; // ApplyButton->setEnabled(!bApplied); } void GraphDlg::SetButtonColors() { QPalette palette = m_pctrlTitleClr->palette(); QColor listColor = palette.color(QPalette::Button); if(listColor.isValid()) { // palette.setColor(QPalette::Background, m_pGraph->GetBackColor()); palette.setColor(QPalette::Button, m_pGraph->GetBackColor()); palette.setColor(QPalette::ButtonText, m_pGraph->GetTitleColor()); m_pctrlTitleClr->setPalette(palette); palette.setColor(QPalette::ButtonText, m_pGraph->GetLabelColor()); m_pctrlLabelClr->setPalette(palette); } } void GraphDlg::SetParams() { m_pctrlXAuto->setChecked(m_pGraph->GetAutoX()); m_pctrlYAuto->setChecked(m_pGraph->GetAutoY()); m_pctrlXMin->SetValue(m_pGraph->GetXMin()); m_pctrlXMax->SetValue(m_pGraph->GetXMax()); m_pctrlXOrigin->SetValue(m_pGraph->GetX0()); m_pctrlXUnit->SetValue(m_pGraph->GetXUnit()); m_pctrlYMin->SetValue(m_pGraph->GetYMin()); m_pctrlYMax->SetValue(m_pGraph->GetYMax()); m_pctrlYOrigin->SetValue(m_pGraph->GetY0()); m_pctrlYUnit->SetValue(m_pGraph->GetYUnit()); OnAutoX(); OnAutoY(); SetButtonColors(); QFont font; m_pGraph->GetLabelLogFont(&font); m_pctrlLabelButton->setText(font.family()); m_pctrlLabelButton->setFont(font); m_pGraph->GetTitleLogFont(&font); m_pctrlTitleButton->setText(font.family()); m_pctrlTitleButton->setFont(font); bool bState, bAuto; QColor color; int style, width; double unit; m_pGraph->GetXMajGrid(bState, color, style, width); m_pctrlXMajGridShow->setChecked(bState); m_pctrlXMajGridStyle->SetColor(color); m_pctrlXMajGridStyle->SetStyle(style); m_pctrlXMajGridStyle->SetWidth(width); m_pctrlXMajGridStyle->setEnabled(bState); m_pGraph->GetXMinGrid(bState, bAuto,color, style, width, unit); m_pctrlXMinGridShow->setChecked(bState); m_pctrlXMinGridStyle->SetColor(color); m_pctrlXMinGridStyle->SetStyle(style); m_pctrlXMinGridStyle->SetWidth(width); m_pctrlXMinGridStyle->setEnabled(bState); m_pctrlXMinorUnit->SetValue(unit); m_pctrlAutoXMinUnit->setChecked(bAuto); m_pctrlAutoXMinUnit->setEnabled(bState); m_pctrlXMinorUnit->setEnabled(!bAuto && bState); m_pGraph->GetYMajGrid(bState, color, style, width); m_pctrlYMajGridShow->setChecked(bState); m_pctrlYMajGridStyle->SetColor(color); m_pctrlYMajGridStyle->SetStyle(style); m_pctrlYMajGridStyle->SetWidth(width); m_pctrlYMajGridStyle->setEnabled(bState); m_pGraph->GetYMinGrid(bState, bAuto,color, style, width, unit); m_pctrlYMinGridShow->setChecked(bState); m_pctrlYMinGridStyle->SetColor(color); m_pctrlYMinGridStyle->SetStyle(style); m_pctrlYMinGridStyle->SetWidth(width); m_pctrlYMinGridStyle->setEnabled(bState); m_pctrlYMinorUnit->SetValue(unit); m_pctrlAutoYMinUnit->setChecked(bAuto); m_pctrlAutoYMinUnit->setEnabled(bState); m_pctrlYMinorUnit->setEnabled(!bAuto && bState); m_pctrlAxisStyle->SetColor(m_pGraph->GetAxisColor()); m_pctrlAxisStyle->SetStyle(m_pGraph->GetAxisStyle()); m_pctrlAxisStyle->SetWidth(m_pGraph->GetAxisWidth()); m_pctrlGraphBorder->setChecked(m_pGraph->GetBorder()); m_pctrlBorderStyle->SetColor(m_pGraph->GetBorderColor()); m_pctrlBorderStyle->SetStyle(m_pGraph->GetBorderStyle()); m_pctrlBorderStyle->SetWidth(m_pGraph->GetBorderWidth()); m_pctrlGraphBack->SetColor(m_pGraph->GetBackColor()); m_pctrlYInverted->setChecked(m_pGraph->GetInverted()); FillVariableList(); m_pctrlXSel->setCurrentRow(m_pGraph->GetXVariable()); m_pctrlYSel->setCurrentRow(m_pGraph->GetYVariable()); m_bVariableChanged = false; SetApplied(true); ApplyButton->setEnabled(m_pTabWidget->currentIndex()!=0); } void GraphDlg::SetupLayout() { QHBoxLayout *CommandButtons = new QHBoxLayout; { RestoreButton = new QPushButton(tr("Restore")); OKButton = new QPushButton(tr("OK")); OKButton->setAutoDefault(true); CancelButton = new QPushButton(tr("Cancel")); CancelButton->setAutoDefault(false); ApplyButton = new QPushButton(tr("Apply")); ApplyButton->setAutoDefault(false); CommandButtons->addStretch(1); CommandButtons->addWidget(RestoreButton); CommandButtons->addStretch(1); CommandButtons->addWidget(ApplyButton); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); } m_pTabWidget = new QTabWidget(this); ScalePage = new QWidget(this); GridPage = new QWidget(this); FontPage = new QWidget(this); VariablePage = new QWidget(this); //________Variable Page______________________ QVBoxLayout *VariablePageLayout = new QVBoxLayout(this); { QHBoxLayout *AxisNamesLayout = new QHBoxLayout; { QLabel *YAxis = new QLabel(tr("YAxis")); QLabel *vs = new QLabel(tr("vs.")); QLabel *XAxis = new QLabel(tr("XAxis")); AxisNamesLayout->addStretch(1); AxisNamesLayout->addWidget(YAxis); AxisNamesLayout->addStretch(1); AxisNamesLayout->addWidget(vs); AxisNamesLayout->addStretch(1); AxisNamesLayout->addWidget(XAxis); AxisNamesLayout->addStretch(1); } QHBoxLayout *VariableBoxLayout = new QHBoxLayout; { m_pctrlXSel = new QListWidget; m_pctrlYSel = new QListWidget; VariableBoxLayout->addWidget(m_pctrlYSel); VariableBoxLayout->addWidget(m_pctrlXSel); } VariablePageLayout->addLayout(AxisNamesLayout); VariablePageLayout->addLayout(VariableBoxLayout); } VariablePage->setLayout(VariablePageLayout); //________Font Page______________________ QVBoxLayout *FontPageLayout = new QVBoxLayout; { QGroupBox *FontBox = new QGroupBox(tr("Fonts")); { QGridLayout *FontButtonsLayout = new QGridLayout; { QLabel *lab1 = new QLabel(tr("Title")); QLabel *lab2 = new QLabel(tr("Label")); QLabel *lab402 = new QLabel(tr("Font")); QLabel *lab403 = new QLabel(tr("Color")); lab1->setAlignment(Qt::AlignRight|Qt::AlignVCenter); lab2->setAlignment(Qt::AlignRight|Qt::AlignVCenter); lab402->setAlignment(Qt::AlignCenter|Qt::AlignVCenter); lab403->setAlignment(Qt::AlignCenter|Qt::AlignVCenter); FontButtonsLayout->addWidget(lab402,1,2); FontButtonsLayout->addWidget(lab403,1,3); FontButtonsLayout->addWidget(lab1,2,1); FontButtonsLayout->addWidget(lab2,3,1); m_pctrlTitleButton = new QPushButton(tr("Set Title Font")); m_pctrlLabelButton = new QPushButton(tr("Set Label Font")); FontButtonsLayout->addWidget(m_pctrlTitleButton,2,2); FontButtonsLayout->addWidget(m_pctrlLabelButton,3,2); m_pctrlTitleClr = new QPushButton(tr("Title Color")); m_pctrlLabelClr = new QPushButton(tr("Label Color")); FontButtonsLayout->addWidget(m_pctrlTitleClr,2,3); FontButtonsLayout->addWidget(m_pctrlLabelClr,3,3); } FontBox->setLayout(FontButtonsLayout); } QGroupBox *BackBox = new QGroupBox(tr("BackGround")); { QGridLayout *BackDataLayout = new QGridLayout; { QLabel *GraphBackLabel = new QLabel(tr("Graph Background")); GraphBackLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlGraphBorder = new QCheckBox(tr("Graph Border")); m_pctrlGraphBack = new ColorButton; m_pctrlGraphBack->setMinimumWidth(100); m_pctrlBorderStyle = new LineBtn(this); m_pctrlBorderStyle->setMinimumWidth(100); BackDataLayout->addWidget(GraphBackLabel,1,1); BackDataLayout->addWidget(m_pctrlGraphBorder,2,1,1,1,Qt::AlignRight | Qt::AlignVCenter); BackDataLayout->addWidget(m_pctrlGraphBack,1,2); BackDataLayout->addWidget(m_pctrlBorderStyle,2,2); BackDataLayout->setColumnStretch(0,1); } BackBox->setLayout(BackDataLayout); } FontPageLayout->addWidget(FontBox); FontPageLayout->addStretch(1); FontPageLayout->addWidget(BackBox); FontPageLayout->addStretch(1); } FontPage->setLayout(FontPageLayout); //________End Font Page______________________ //________Scale Page______________________ QGridLayout *ScalePageLayout = new QGridLayout; { QLabel *XAxis2 = new QLabel(tr("X Axis")); QLabel *YAxis2 = new QLabel(tr("Y Axis")); XAxis2->setAlignment(Qt::AlignCenter); YAxis2->setAlignment(Qt::AlignCenter); QLabel *MinLabel = new QLabel(tr("Min")); QLabel *MaxLabel = new QLabel(tr("Max")); QLabel *OriginLabel = new QLabel(tr("Origin")); QLabel *UnitLabel = new QLabel(tr("Unit")); MinLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); MaxLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); OriginLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); UnitLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); // ScaleData->addStretch(1); ScalePageLayout->addWidget(MinLabel,4,1); ScalePageLayout->addWidget(MaxLabel,5,1); ScalePageLayout->addWidget(OriginLabel,6,1); ScalePageLayout->addWidget(UnitLabel,7,1); m_pctrlXAuto = new QCheckBox(tr("Auto Scale")); m_pctrlXMin = new DoubleEdit; m_pctrlXMax = new DoubleEdit; m_pctrlXOrigin = new DoubleEdit; m_pctrlXUnit = new DoubleEdit; ScalePageLayout->addWidget(XAxis2,1,2); ScalePageLayout->addWidget(m_pctrlXAuto,3,2); ScalePageLayout->addWidget(m_pctrlXMin,4,2); ScalePageLayout->addWidget(m_pctrlXMax,5,2); ScalePageLayout->addWidget(m_pctrlXOrigin,6,2); ScalePageLayout->addWidget(m_pctrlXUnit,7,2); m_pctrlYInverted = new QCheckBox(tr("Inverted Axis")); m_pctrlYAuto = new QCheckBox(tr("Auto Scale")); m_pctrlYMin = new DoubleEdit; m_pctrlYMax = new DoubleEdit; m_pctrlYOrigin = new DoubleEdit; m_pctrlYUnit = new DoubleEdit; ScalePageLayout->addWidget(YAxis2,1,3); ScalePageLayout->addWidget(m_pctrlYInverted,2,3); ScalePageLayout->addWidget(m_pctrlYAuto,3,3); ScalePageLayout->addWidget(m_pctrlYMin,4,3); ScalePageLayout->addWidget(m_pctrlYMax,5,3); ScalePageLayout->addWidget(m_pctrlYOrigin,6,3); ScalePageLayout->addWidget(m_pctrlYUnit,7,3); } ScalePage->setLayout(ScalePageLayout); //________End Scale Page______________________ //________Axis Page______________________ QGridLayout *AxisDataLayout = new QGridLayout; { AxisDataLayout->setRowStretch(0,1); QLabel *AxisStyleLabel = new QLabel(tr("Axis Style")); m_pctrlXMajGridShow = new QCheckBox(tr("X Major Grid")); m_pctrlYMajGridShow = new QCheckBox(tr("Y Major Grid")); m_pctrlXMinGridShow = new QCheckBox(tr("X Minor Grid")); m_pctrlYMinGridShow = new QCheckBox(tr("Y Minor Grid")); m_pctrlAutoXMinUnit = new QCheckBox(tr("Auto Unit")); m_pctrlAutoYMinUnit = new QCheckBox(tr("Auto Unit")); m_pctrlAxisStyle = new LineBtn(this); m_pctrlXMajGridStyle = new LineBtn(this); m_pctrlYMajGridStyle = new LineBtn(this); m_pctrlXMinGridStyle = new LineBtn(this); m_pctrlYMinGridStyle = new LineBtn(this); m_pctrlXMinorUnit = new DoubleEdit; m_pctrlYMinorUnit = new DoubleEdit; AxisDataLayout->addWidget(AxisStyleLabel,1,1); AxisDataLayout->addWidget(m_pctrlXMajGridShow,2,1); AxisDataLayout->addWidget(m_pctrlYMajGridShow,3,1); AxisDataLayout->addWidget(m_pctrlXMinGridShow,4,1); AxisDataLayout->addWidget(m_pctrlYMinGridShow,5,1); AxisDataLayout->addWidget(m_pctrlAxisStyle,1,2); AxisDataLayout->addWidget(m_pctrlXMajGridStyle,2,2); AxisDataLayout->addWidget(m_pctrlYMajGridStyle,3,2); AxisDataLayout->addWidget(m_pctrlXMinGridStyle,4,2); AxisDataLayout->addWidget(m_pctrlYMinGridStyle,5,2); AxisDataLayout->addWidget(m_pctrlAutoXMinUnit,4,3); AxisDataLayout->addWidget(m_pctrlAutoYMinUnit,5,3); AxisDataLayout->addWidget(m_pctrlXMinorUnit,4,4); AxisDataLayout->addWidget(m_pctrlYMinorUnit,5,4); } GridPage->setLayout(AxisDataLayout); //________End Axis Page______________________ m_pTabWidget->addTab(VariablePage, tr("Variables")); m_pTabWidget->addTab(ScalePage, tr("Scales")); m_pTabWidget->addTab(GridPage, tr("Axis and Grids")); m_pTabWidget->addTab(FontPage, tr("Fonts and BackGround")); m_pTabWidget->setCurrentIndex(s_ActivePage); connect(m_pTabWidget, SIGNAL(currentChanged (int)), this, SLOT(OnActivePage(int))); QVBoxLayout *mainLayout = new QVBoxLayout; { mainLayout->addWidget(m_pTabWidget); mainLayout->addLayout(CommandButtons); } setLayout(mainLayout); } xflr5-6.09-06/src/graph/Graph.cpp000644 001750 000144 00000060001 12250154041 017712 0ustar00techwinderusers000000 000000 /**************************************************************************** Graph Classes Copyright (C) 2003-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "Graph.h" #include //static variables must be initialized in C++ QColor Graph::m_CurveColors[10]; Graph::Graph() { //Type is used to determine automatic scales m_Type = 1; m_X = 0; m_Y = 1; xmin = .0; xmax = .10; ymin = .0; ymax = .10; xunit = 0.1; yunit = 0.1; xo = 0.0; yo = 0.0; m_XMinorUnit = 0.01; m_YMinorUnit = 0.01; m_scalex = 0.1; m_scaley = 0.1; Cxmin = 0.0; Cxmax = 1.0; Cymin = 0.0; Cymax = 1.0; exp_x = 0; exp_y = 0; m_bYInverted = false; m_bAutoX = true; m_bAutoY = true; m_bXAutoMinGrid = true; m_bYAutoMinGrid = true; m_bBorder = true; m_ptoffset.rx() = 0; m_ptoffset.ry() = 0; m_CurveColors[0] = QColor(255, 0, 0); m_CurveColors[1] = QColor( 0, 0, 255); m_CurveColors[2] = QColor( 0, 255, 0); m_CurveColors[3] = QColor(255, 255, 0); m_CurveColors[4] = QColor( 0, 255, 255); m_CurveColors[5] = QColor(255, 0, 255); m_CurveColors[6] = QColor(255, 125, 70); m_CurveColors[7] = QColor( 70, 125, 255); m_CurveColors[8] = QColor(125, 255, 70); m_CurveColors[9] = QColor(255, 70, 200); m_AxisStyle = 0; m_AxisWidth = 1; m_BorderStyle = 0; m_BorderWidth = 2; m_XMajStyle = 0; m_XMajWidth = 1; m_XMinStyle = 1; m_XMinWidth = 1; m_YMajStyle = 0; m_YMajWidth = 1; m_YMinStyle = 1; m_YMinWidth = 1; m_LogPixelsY = 0; m_iMargin= 44; m_h = 0; m_w = 0; m_rDrawRect.SetRectEmpty(); SetDefaults(); } Graph::~Graph() { } Curve* Graph::AddCurve() { Curve *pCurve = new Curve(); if(pCurve) { int nIndex = m_oaCurves.size(); pCurve->SetColor(m_CurveColors[nIndex%10]); pCurve->SetStyle(0); pCurve->m_pParentGraph = this; m_oaCurves.append(pCurve); } return pCurve; } double Graph::ClientTox(double x) { return (x-m_ptoffset.x())*m_scalex; } double Graph::ClientToy(double y) { return (y-m_ptoffset.y())*m_scaley; } double Graph::ClientTox(int x) { return ((double)x-(double)m_ptoffset.x())*m_scalex; } double Graph::ClientToy(int y) { return ((double)y-(double)m_ptoffset.y())*m_scaley; } void Graph::CopySettings(Graph *pGraph, bool bScales) { if(bScales) { xmin = pGraph->xmin; xmax = pGraph->xmax; xo = pGraph->xo; xunit = pGraph->xunit; ymin = pGraph->ymin; ymax = pGraph->ymax; yo = pGraph->yo; yunit = pGraph->yunit; m_scalex = pGraph->m_scalex; m_scaley = pGraph->m_scaley; } m_AxisColor = pGraph->m_AxisColor; m_BkColor = pGraph->m_BkColor; m_bBorder = pGraph->m_bBorder; m_BorderColor = pGraph->m_BorderColor; m_BorderStyle = pGraph->m_BorderStyle; m_BorderWidth = pGraph->m_BorderWidth; m_LabelColor = pGraph->m_LabelColor; m_LabelFont = pGraph->m_LabelFont; m_TitleColor = pGraph->m_TitleColor; m_TitleFont = pGraph->m_TitleFont; m_AxisStyle = pGraph->m_AxisStyle; m_AxisWidth = pGraph->m_AxisWidth; m_XMajClr = pGraph->m_XMajClr; m_XMajStyle = pGraph->m_XMajStyle; m_XMajWidth = pGraph->m_XMajWidth; m_XMinClr = pGraph->m_XMinClr; m_XMinStyle = pGraph->m_XMinStyle; m_XMinWidth = pGraph->m_XMinWidth; m_YMajClr = pGraph->m_YMajClr; m_YMajStyle = pGraph->m_YMajStyle; m_YMajWidth = pGraph->m_YMajWidth; m_YMinClr = pGraph->m_YMinClr; m_YMinStyle = pGraph->m_YMinStyle; m_YMinWidth = pGraph->m_YMinWidth; m_bAutoX = pGraph->m_bAutoX; m_bAutoY = pGraph->m_bAutoY; m_bXAutoMinGrid = pGraph->m_bXAutoMinGrid; m_bYAutoMinGrid = pGraph->m_bYAutoMinGrid; m_bYInverted = pGraph->m_bYInverted; m_bXMajGrid = pGraph->m_bXMajGrid; m_bXMinGrid = pGraph->m_bXMinGrid; m_bYMajGrid = pGraph->m_bYMajGrid; m_bYMinGrid = pGraph->m_bYMinGrid; m_bBorder = pGraph->m_bBorder; } void Graph::DeleteCurve(int index) { Curve * pCurve = GetCurve(index); m_oaCurves.removeAt(index); delete pCurve; } void Graph::DeleteCurve(Curve *pCurve) { Curve *pOldCurve = NULL; for(int i=0; im_CurveName==CurveTitle) { m_oaCurves.removeAt(i); delete pOldCurve; return; } } } void Graph::DeleteCurves() { int nIndex = (int)m_oaCurves.size(); for (int i=nIndex-1; i>=0;i--) delete GetCurve(i); m_oaCurves.clear();//removes the pointers if (m_bAutoX && !m_Type) { xmin = 0.0; xmax = 0.1; } if (m_bAutoY && !m_Type){ ymin = 0.0; ymax = 0.1; } } //___________________Start Gets______________________________________________________________ int Graph::GetCurveCount() { return (int)m_oaCurves.size(); } QColor Graph::GetLabelColor() { return m_LabelColor; } QColor Graph::GetAxisColor() { return m_AxisColor; } QColor Graph::GetBorderColor() { return m_BorderColor; } QColor Graph::GetBackColor() { return m_BkColor; } int Graph::GetAxisStyle() { return m_AxisStyle; } int Graph::GetAxisWidth() { return m_AxisWidth; } bool Graph::GetAutoX() { return m_bAutoX; } bool Graph::GetAutoY() { return m_bAutoY; } bool Graph::GetAutoXMin() { return m_bXAutoMinGrid; } bool Graph::GetAutoYMin() { return m_bYAutoMinGrid; } bool Graph::GetBorder() { return m_bBorder; } int Graph::GetBorderStyle() { return m_BorderStyle; } int Graph::GetBorderWidth() { return m_BorderWidth; } void Graph::GetClientRect(QRect &Rect) { Rect = m_rCltRect; } Curve* Graph::GetCurve(int nIndex) { if(m_oaCurves.size()>nIndex) return (Curve*)m_oaCurves[nIndex]; else return NULL; } Curve* Graph::GetCurve(QString CurveTitle) { QString strong; Curve * pCurve; for(int i=0; ititle(strong); if(strong==CurveTitle) return pCurve; } } return NULL; } bool Graph::GetInverted() { if(m_bYInverted) return true; else return false; } int Graph::GetLogPixelsY() { return m_LogPixelsY; } int Graph::GetMargin() { return m_iMargin; } void Graph::GetTitleLogFont(QFont *plgft) { *plgft = m_TitleFont; } void Graph::GetLabelLogFont(QFont *plgft) { *plgft = m_LabelFont; } void Graph::GetGraphName(QString &GraphName) { GraphName = m_GraphName; } QString Graph::GetGraphName() { return m_GraphName; } QColor Graph::GetTitleColor() { return m_TitleColor; } double Graph::GetX0() { return xo; } bool Graph::GetXMajGrid() { return m_bXMajGrid; } void Graph::GetXMajGrid(bool &bstate, QColor &clr, int &style, int &width) { bstate = m_bXMajGrid; clr = m_XMajClr; style = m_XMajStyle; width = m_XMajWidth; } bool Graph::GetXMinGrid() { return m_bXMinGrid; } void Graph::GetXMinGrid(bool &state, bool &bAuto, QColor &clr, int &style, int &width, double &unit) { state = m_bXMinGrid; bAuto = m_bXAutoMinGrid; clr = m_XMinClr; style = m_XMinStyle; width = m_XMinWidth; unit = m_XMinorUnit; } double Graph::GetXMin() { return xmin; } double Graph::GetXMax() { return xmax; } double Graph::GetXScale() { return m_scalex; } void Graph::GetXTitle(QString &str) { str = m_XTitle; } double Graph::GetXUnit() { return xunit; } int Graph::GetXVariable() { return m_X; } bool Graph::GetYMajGrid() { return m_bYMajGrid; } void Graph::GetYMajGrid(bool &state, QColor &clr, int &style, int &width) { state = m_bYMajGrid; clr = m_YMajClr; style = m_YMajStyle; width = m_YMajWidth; } void Graph::GetYTitle(QString &str) { str = m_YTitle; } bool Graph::GetYMinGrid() { return m_bYMinGrid; } void Graph::GetYMinGrid(bool &state, bool &bAuto, QColor &clr, int &style, int &width, double &unit) { state = m_bYMinGrid; bAuto = m_bYAutoMinGrid; clr = m_YMinClr; style = m_YMinStyle; width = m_YMinWidth; unit = m_YMinorUnit; } double Graph::GetY0() { return yo; } double Graph::GetYMin() { return ymin; } double Graph::GetYMax() { return ymax; } double Graph::GetYUnit() { return yunit; } double Graph::GetYScale() { return m_scaley; } int Graph::GetYVariable() { return m_Y; } bool Graph::Init() { //graph width and height m_w = m_rCltRect.width() -2*m_iMargin; m_h = m_rCltRect.height() -2*m_iMargin; SetXScale(); SetYScale(); if(m_bXAutoMinGrid) m_XMinorUnit = xunit/5.0; if(m_bYAutoMinGrid) m_YMinorUnit = yunit/5.0; return true; } bool Graph::IsInDrawRect(CVector const &pt) { if(m_rDrawRect.PtInRect(pt)) { return true; } else return false; } bool Graph::IsInDrawRect(QPoint const &pt) { if(m_rCltRect.contains(pt)) return true; else return false; } bool Graph::IsInDrawRect(int const &x, int const &y) { if(m_rCltRect.contains(x,y)) return true; else return false; } void Graph::ResetCurves() { Curve *pCurve; for(int i=0; iclear(); } } void Graph::ResetLimits() { ResetXLimits(); ResetYLimits(); } void Graph::ResetXLimits() { if(m_bAutoX) { xmin = 0.0; xmax = 0.1; xo = 0.0; } } void Graph::ResetYLimits() { if(m_bAutoY) { ymin = 0.000; ymax = 0.001; yo = 0.000; } } void Graph::Scale(double zoom) { if (zoom<0.01) zoom =0.01; m_bAutoX = false; m_bAutoY = false; double xm = (xmin + xmax)/2.0; xmin = xm+(xmin-xm)*zoom; xmax = xm+(xmax-xm)*zoom; double ym = (ymin + ymax)/2.0; ymin = ym+(ymin-ym)*zoom; ymax = ym+(ymax-ym)*zoom; } void Graph::Scalex(double zoom) { if (zoom<0.01) zoom =0.01; m_bAutoX = false; double xm = (xmin + xmax)/2.0; xmin = xm+(xmin-xm)*zoom; xmax = xm+(xmax-xm)*zoom; } void Graph::Scaley(double zoom) { if (zoom<0.01) zoom =0.01; m_bAutoY = false; double ym = (ymin + ymax)/2.0; ymin = ym+(ymin-ym)*zoom; ymax = ym+(ymax-ym)*zoom; } //___________________Start Sets______________________________________________________________ void Graph::SetAuto(bool bAuto) { m_bAutoX = bAuto; m_bAutoY = bAuto; ResetXLimits(); ResetYLimits(); } void Graph::SetAutoX(bool bAuto) { m_bAutoX = bAuto; ResetXLimits(); } void Graph::SetAutoY(bool bAuto) { m_bAutoY = bAuto; ResetYLimits(); } void Graph::SetAutoXMinUnit(bool bAuto) { m_bXAutoMinGrid = bAuto; if(bAuto) m_XMinorUnit = xunit/5.0; } void Graph::SetAutoXUnit() { // xunit = 100.0*m_scalex; xunit = (xmax-xmin)/3.0; if (xunit<1.0) { exp_x = (int)log10(xunit*1.00001)-1; exp_x = qMax(-4, exp_x); } else exp_x = (int)log10(xunit*1.00001); int main_x = (int)(xunit/pow(10.0, exp_x)*1.000001); if(main_x<2) xunit = pow(10.0,exp_x); else if (main_x<5) xunit = 2.0*pow(10.0,exp_x); else xunit = 5.0*pow(10.0,exp_x); } void Graph::SetAutoYMinUnit(bool bAuto) { m_bYAutoMinGrid = bAuto; if(bAuto) m_YMinorUnit = yunit/5.0; } void Graph::SetAutoYUnit() { // yunit = 100.0 * m_scaley; yunit = (ymax-ymin)/5.0; if (yunit<1.0) { exp_y = (int)log10(yunit*1.00001)-1; // exp_y = qMax(-4, exp_y); } else exp_y = (int)log10(yunit*1.00001); int main_y = (int)(yunit/pow(10.0, exp_y)); if(main_y<2) yunit = pow(10.0,exp_y); else if (main_y<5) yunit = 2.0*pow(10.0,exp_y); else yunit = 5.0*pow(10.0,exp_y); } void Graph::SetAxisData(int s, int w, QColor clr) { m_AxisStyle = s; m_AxisWidth = w; m_AxisColor = clr; } void Graph::SetAxisColor(QColor crColor) { m_AxisColor = crColor; } void Graph::SetAxisStyle(int nStyle) { m_AxisStyle = nStyle; } void Graph::SetAxisWidth(int Width) { m_AxisWidth = Width; } void Graph::SetBkColor(QColor cr) { m_BkColor = cr; } void Graph::SetBorderColor(QColor crBorder) { m_BorderColor = crBorder; } void Graph::SetBorder(bool bBorder) { m_bBorder = bBorder; } void Graph::SetBorderWidth(int w) { m_BorderWidth = w; } void Graph::SetBorderStyle(int s) { m_BorderStyle = s; } void Graph::SetDrawRect(CRectangle &Rect) { m_rDrawRect = Rect; } void Graph::SetDrawRect(QRect &Rect) { m_rCltRect = Rect; } void Graph::SetGraphName(QString GraphName) { m_GraphName = GraphName; } void Graph::SetDefaults() { m_BkColor = QColor(0,10,20); m_BorderColor = QColor(200,200,200); m_BorderStyle = 0; m_BorderWidth = 3; m_LogPixelsY = 96; m_AxisStyle = 0; m_AxisWidth = 1; m_bYInverted = false; QFont TmpFont; // TmpFont.CreatePointFont(85, "Comic Sans MS"); SetTitleLogFont(&TmpFont); SetLabelLogFont(&TmpFont); SetAxisColor(QColor(200,200,200)); SetTitleColor(QColor(255,255,255)); SetLabelColor(QColor(255,255,255)); m_bXMajGrid = true; m_bYMajGrid = true; m_bXMinGrid = false; m_bYMinGrid = false; m_XMajStyle = 1; m_YMajStyle = 1; m_XMajWidth = 1; m_YMajWidth = 1; m_XMajClr = QColor(90,90,90); m_YMajClr = QColor(90,90,90); m_XMinStyle = 1; m_YMinStyle = 1; m_XMinWidth = 1; m_YMinWidth = 1; m_XMinClr = QColor(50,50,50); m_YMinClr = QColor(50,50,50); m_XMinorUnit = 0.1; m_YMinorUnit = 0.1; } void Graph::SetLabelLogFont(QFont *plgft) { m_LabelFont = *plgft; } void Graph::SetLabelColor(QColor crColor) { m_LabelColor = crColor; } void Graph::SetInverted(bool bInverted) { m_bYInverted = bInverted; } void Graph::SetLogPixelsY(int n) { m_LogPixelsY = n; } void Graph::SetMargin(double m) { m_iMargin = (int)m; } void Graph::SetMargin(int m) { m_iMargin = m; } void Graph::SetTitleColor(QColor crColor) { m_TitleColor = crColor; } void Graph::SetTitleLogFont(QFont *plgft) { m_TitleFont = *plgft; } void Graph::SetType(int type) { m_Type = type; } void Graph::SetVariables(int const & X, int const & Y) { m_X = X; m_Y = Y; } void Graph::SetWindow(double x1, double x2, double y1, double y2) { m_bAutoX = false; m_bAutoY = false; xmin = x1; xmax = x2; ymin = y1; ymax = y2; } void Graph::SetX0(double f){ xo = f; } void Graph::SetXMajGrid(bool const &state, QColor const &clr, int const &style, int const &width) { m_bXMajGrid = state; m_XMajClr = clr; m_XMajStyle = style; m_XMajWidth = width; } void Graph::SetXMajGrid(bool const &bGrid) { m_bXMajGrid = bGrid; } void Graph::SetXMinGrid(bool const &bGrid) { m_bXMinGrid = bGrid; } void Graph::SetXMax(double f){ xmax = f; } void Graph::SetXMin(double f){ xmin = f; } void Graph::SetXMinGrid(bool state, bool bAuto, QColor clr, int style, int width, double unit) { m_bXMinGrid = state; m_bXAutoMinGrid = bAuto; m_XMinClr = clr; m_XMinStyle = style; m_XMinWidth = width; if(unit>0.0) m_XMinorUnit = unit; } void Graph::SetXMinorUnit(double f){ m_XMinorUnit = f; } bool Graph::SetXScale() { Curve *pCurve; int nc; if(m_bAutoX) { bool bCurve = false; if (m_oaCurves.size()) { //init only if we have a curve for (nc=0; nc < m_oaCurves.size(); nc++) { pCurve = (Curve*)m_oaCurves[nc]; if ((pCurve->IsVisible() ||pCurve->PointsVisible()) && pCurve->size()>1) { bCurve = true; break;//there is something to draw } } } if (bCurve) { Cxmin = 9999999.0; Cxmax = -9999999.0; for (nc=0; nc < m_oaCurves.size(); nc++) { pCurve = (Curve*)m_oaCurves[nc]; if ((pCurve->IsVisible() ||pCurve->PointsVisible()) && pCurve->size()>0) { Cxmin = qMin(Cxmin, pCurve->xMin()); Cxmax = qMax(Cxmax, pCurve->xMax()); } } if(Cxmax<=Cxmin) Cxmax = (Cxmin+1.0)*2.0; if(m_Type == 1) { xmin = qMin(xmin, Cxmin); xmax = qMax(xmax, Cxmax); } else { xmin = Cxmin; xmax = Cxmax; } if(Cxmin>=0.0) xmin = 0.0; if(Cxmax<=0.0) xmax = 0.0; } else { // until things are made clear for (nc=0; nc < m_oaCurves.size(); nc++) { pCurve = (Curve*)m_oaCurves[nc]; if ((pCurve->IsVisible() ||pCurve->PointsVisible()) && pCurve->size()>0) { xmin = qMin(xmin, pCurve->x[0]); xmax = qMax(xmax, pCurve->x[0]); } } } xo=0.0; if(qAbs((xmin-xmax)/xmin)<0.001) { if(qAbs(xmin)<0.00001) xmax = 1.0; else { xmax = 2.0 * xmin; if(xmax < xmin) { double tmp = xmax; xmax = xmin; xmin = tmp; } } } if(m_w<=0.0) return false; m_scalex = (xmax-xmin)/m_w; //try to set an automatic scale for X Axis SetAutoXUnit(); } else { //scales are set manually if(m_w<=0.0) return false; // m_scalex = (xmax-xmin)/m_w; if (xunit<1.0) { exp_x = (int)log10(xunit*1.00001)-1; exp_x = qMax(-4, exp_x); } else exp_x = (int)log10(xunit*1.00001); } m_scalex = (xmax-xmin)/m_w; //graph center position int Xg = (m_rCltRect.right() + m_rCltRect.left())/2; // curves center position int Xc = (int)((xmin+xmax)/2.0/m_scalex); // center graph in drawing rectangle m_ptoffset.rx() = (Xg-Xc); return true; } void Graph::SetXUnit(double f){ xunit = f; } void Graph::SetXTitle(QString str) { m_XTitle = str; } void Graph::SetXVariable(int const & X) { m_X = X; } void Graph::SetYMin(double f){ ymin = f; } void Graph::SetYMinorUnit(double f){ m_YMinorUnit = f; } void Graph::SetYMax(double f){ ymax = f; } void Graph::SetY0(double f){ yo = f; } void Graph::SetYTitle(QString str) { m_YTitle = str; } void Graph::SetYUnit(double f){ yunit = f; } bool Graph::SetYScale() { int nc; Curve *pCurve; if(m_bAutoY) { bool bCurve = false; if (m_oaCurves.size()) { //init only if we have a curve for (nc=0; nc < m_oaCurves.size(); nc++) { pCurve = (Curve*)m_oaCurves[nc]; if ((pCurve->IsVisible() ||pCurve->PointsVisible()) && pCurve->size()>0) { bCurve = true; break; } } } if(bCurve) { Cymin = 9999999.0; Cymax = -9999999.0; for (nc=0; nc < m_oaCurves.size(); nc++) { pCurve = (Curve*)m_oaCurves[nc]; if ((pCurve->IsVisible() ||pCurve->PointsVisible()) && pCurve->size()>0) { Cymin = qMin(Cymin, pCurve->yMin()); Cymax = qMax(Cymax, pCurve->yMax()); } } if(Cymax<=Cymin) { Cymax = (Cymin+1.0)*2.0; } if(m_Type == 1) { ymin = qMin(ymin, Cymin); ymax = qMax(ymax, Cymax); } else { ymin = Cymin; ymax = Cymax; } if(Cymin>=0.0) ymin = 0.0; if(Cymax<=0.0) ymax = 0.0; } else { // until things are made clear for (int nc=0; nc < m_oaCurves.size(); nc++) { pCurve = (Curve*)m_oaCurves[nc]; if ((pCurve->IsVisible() ||pCurve->PointsVisible()) && pCurve->size()>0) { ymin = qMin(ymin, pCurve->y[0]); ymax = qMax(ymax, pCurve->y[0]); } } } yo=0.0; if (qAbs((ymin-ymax)/ymin)<0.001) { if(qAbs(ymin)<0.00001) ymax = 1.0; else { ymax = 2.0 * ymin; if(ymax < ymin) { double tmp = ymax; ymax = ymin; ymin = tmp; } } } if(m_h<=0.0) return false; if (!m_bYInverted) { m_scaley = -(ymax-ymin)/m_h; } else { m_scaley = (ymax-ymin)/m_h; } //try to set an automatic scale for Y Axis SetAutoYUnit(); } else { //scales are set manually if(m_h<=0) return false; if (!m_bYInverted) { m_scaley = -(ymax-ymin)/m_h; } else { m_scaley = (ymax-ymin)/m_h; } if (yunit<1.0) { exp_y = (int)log10(yunit*1.00001)-1; exp_y = qMax(-4, exp_y); } else exp_y = (int)log10(yunit*1.00001); } //graph center position int Yg = (m_rCltRect.top() + m_rCltRect.bottom())/2; // curves center position int Yc = (int)((ymin+ymax)/2.0/m_scaley); // center graph in drawing rectangle m_ptoffset.ry() = (Yg-Yc); return true; } void Graph::SetYMajGrid(bool const &state, QColor const &clr, int const &style, int const &width) { m_bYMajGrid = state; m_YMajClr = clr; m_YMajStyle = style; m_YMajWidth = width; } void Graph::SetYMajGrid(bool const &bGrid) { m_bYMajGrid = bGrid; } void Graph::SetYMinGrid(bool state, bool bAuto, QColor clr, int style, int width, double unit) { m_bYMinGrid = state; m_bYAutoMinGrid = bAuto; m_YMinClr = clr; m_YMinStyle = style; m_YMinWidth = width; if(unit>0.0) m_YMinorUnit = unit; } void Graph::SetYMinGrid(bool const &bGrid) { m_bYMinGrid = bGrid; } void Graph::SetYVariable(int const & Y) { m_Y = Y; } int Graph::xToClient(double x) { return (int)(x/m_scalex + m_ptoffset.x()); } int Graph::yToClient(double y) { return (int)(y/m_scaley + m_ptoffset.y()); } Curve* Graph::GetClosestPoint(const double &x, const double &y, double &xSel, double &ySel, int &nSel) { static int i, n1; static double dist, dmax, x1, y1; dmax = 1.e40; Curve *pOldCurve, *pCurveSel; pCurveSel = NULL; for(i=0; iclosestPoint(x, y, x1, y1, dist, n1); if(distclosestPoint(x, y, x1, y1, dist, n); xc = xToClient(x1); yc = yToClient(y1); if((xClt-xc)*(xClt-xc) + (yClt-yc)*(yClt-yc) <16)//sqrt(16) pixels distance { nSel = n; return pOldCurve; } } nSel = -1; return NULL; } bool Graph::SelectPoint(QString const &CurveName, int sel) { QString str; Curve *pCurve = NULL; if(sel<0) { // pCurve->SetSelected(-1); return false; } for(int i=0; ititle(str); if(str == CurveName) { if(sel>pCurve->count()) { pCurve->SetSelected(-1); return false; } else { pCurve->SetSelected(sel); return true; } } } // pCurve->SetSelected(-1); return false; } void Graph::DeselectPoint() { Curve *pCurve; for(int i=0; iSetSelected(-1); } } xflr5-6.09-06/src/graph/Curve.cpp000644 001750 000144 00000013365 12247174404 017763 0ustar00techwinderusers000000 000000 /**************************************************************************** Curve Class Copyright (C) 2003-2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "Curve.h" #include "math.h" #include "Graph.h" /** * The public constructor */ Curve::Curve() { CurveColor = QColor(255,0,0,127); m_CurveName = ""; m_bIsVisible = true; m_bShowPoints = false; CurveWidth = 1; CurveStyle = Qt::SolidLine; m_iSelected = -1; } /** * Appends a point to the end of the data * @param xn: x-coordinate * @param yn: y-coordinate * @return the new number of points in the curve */ int Curve::AppendPoint(double xn, double yn) { x.append(xn); y.append(yn); return size(); } /** * Copies the data and settings from an existing curve * @param pCurve: a pointer to the input curve */ void Curve::Duplicate(Curve *pCurve) { if(!pCurve) return; CopyData(pCurve); CurveColor = pCurve->CurveColor; CurveStyle = pCurve->CurveStyle; CurveWidth = pCurve->CurveWidth; m_bIsVisible = pCurve->m_bIsVisible; m_bShowPoints = pCurve->m_bShowPoints; m_CurveName = pCurve->m_CurveName; } /** * Copies the data and settings from an existing curve * @param pCurve: a pointer to the input curve */ void Curve::CopyData(Curve *pCurve) { if(!pCurve) return; clear(); for (int i=0; isize() ;i++) { x.append(pCurve->x[i]); y.append(pCurve->y[i]); } } /** * Returns the point referenced by the input parameter as a CVector object * @param ref the reference of the requested pointed * @return a CVector instance of the point, or (0, 0, 0) if the reference is out of bounds */ CVector Curve::point(int ref) { CVector r; if(ref<0 || ref>=size()){ r.x = 0.0; r.y = 0.0; } else{ r.x = x[ref]; r.y = y[ref]; } return r; } /** * Returns the index of the curve's point closest to the input coordinates * @param xs x coordinate * @param ys y coordinate * @param &dist distance to the return point * @return the index of the closest point */ int Curve::closestPoint(double xs, double ys, double &dist ) { Graph *pGraph = (Graph*)m_pParentGraph; static int ref; static double d2; ref = -1; dist = 1.e10; if (size()<1) return -1; for(int i=0; iGetXScale()/pGraph->GetXScale() + (ys-y[i])*(ys-y[i])/pGraph->GetYScale()/pGraph->GetYScale(); if (d2GetXScale()/pGraph->GetXScale() + (ys-y[i])*(ys-y[i])/pGraph->GetYScale()/pGraph->GetYScale(); if (d2 #include "params.h" /** *@class TwoDWidget * @brief This class is used for 2d drawing in the central area of the application's MainFrame. * There is a unique instance of this class, attached to the QStackedWidget of the MainFrame. * Depending on the active application, this class calls the drawings methods in QAFoil, QXDirect, QXInverse or QMiarex. * All Qt events received by this widget are sent to the child applications for handling. */ class TwoDWidget : public QWidget { Q_OBJECT friend class MainFrame; friend class QXDirect; friend class QMiarex; public: TwoDWidget(QWidget *parent = 0); protected: void contextMenuEvent (QContextMenuEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void mouseDoubleClickEvent (QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void paintEvent(QPaintEvent *event); void resizeEvent (QResizeEvent *event); void wheelEvent (QWheelEvent *event); private: void *m_pAFoil; /**< A void pointer to the instance of the QAFoil object. */ void *m_pMainFrame; /**< A void pointer to the instance of the MainFrame object. */ void *m_pMiarex; /**< A void pointer to the instance of the QMiarex object. */ void *m_pXDirect; /**< A void pointer to the instance of the QXDirect object. */ void *m_pXInverse; /**< A void pointer to the instance of the QXInverse object. */ }; #endif xflr5-6.09-06/src/misc/000755 001750 000144 00000000000 12250003440 015776 5ustar00techwinderusers000000 000000 xflr5-6.09-06/src/misc/UnitsDlg.h000644 001750 000144 00000004140 12247174404 017716 0ustar00techwinderusers000000 000000 /**************************************************************************** UnitsDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef UNITSDLG_H #define UNITSDLG_H #include #include #include #include class UnitsDlg : public QDialog { Q_OBJECT friend class MainFrame; friend class QMiarex; friend class GL3dBodyDlg; friend class Body; public: UnitsDlg(QWidget *parent); private slots: void OnSelChanged(const QString &strong); private: QPushButton *OKButton, *CancelButton; QComboBox *m_pctrlMoment; QComboBox *m_pctrlSurface; QComboBox *m_pctrlWeight; QComboBox *m_pctrlSpeed; QComboBox *m_pctrlLength; QComboBox *m_pctrlForce; QLabel *m_pctrlForceFactor, *m_pctrlForceInvFactor; QLabel *m_pctrlLengthFactor, *m_pctrlLengthInvFactor; QLabel *m_pctrlSpeedFactor, *m_pctrlSpeedInvFactor; QLabel *m_pctrlSurfaceFactor, *m_pctrlSurfaceInvFactor; QLabel *m_pctrlWeightFactor, *m_pctrlWeightInvFactor; QLabel *m_pctrlMomentFactor, *m_pctrlMomentInvFactor; QLabel *m_pctrlQuestion; private: void InitDialog(); void SetupLayout(); bool m_bLengthOnly; int m_Length, m_Area, m_Weight, m_Speed, m_Force, m_Moment; double m_mtoUnit; double m_kgtoUnit; double m_mstoUnit; double m_NtoUnit; double m_NmtoUnit; double m_m2toUnit; QString m_Question; }; #endif // UNITSDLG_H xflr5-6.09-06/src/misc/ModDlg.h000644 001750 000144 00000002436 12247174404 017341 0ustar00techwinderusers000000 000000 /**************************************************************************** ModDlg class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef MODDLG_H #define MODDLG_H #include #include #include class ModDlg : public QDialog { Q_OBJECT friend class QMiarex; friend class ManageBodiesDlg; public: ModDlg(QWidget *pParent); private slots: void OnSaveAsNew(); private: void SetupLayout(); void InitDialog(); QLabel * m_pctrlQuestion; QString m_Question; }; #endif // MODDLG_H xflr5-6.09-06/src/misc/DisplaySettingsDlg.h000644 001750 000144 00000004276 12247174404 021754 0ustar00techwinderusers000000 000000 /**************************************************************************** DisplaySettingsDlg Class Copyright (C) 2008-2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef DISPLAYSETTINGSDLG_H #define DISPLAYSETTINGSDLG_H #include #include #include #include #include #include #include "ColorButton.h" #include "../graph/QGraph.h" class DisplaySettingsDlg : public QDialog { Q_OBJECT friend class MainFrame; public: DisplaySettingsDlg(QWidget *pParent); void InitDialog(); private slots: void OnStyleChanged(const QString &StyleName); void OnBackgroundColor(); void OnGraphSettings(); void OnTextColor(); void OnTextFont(); private: void reject(); void SetupLayout(); ColorButton *m_pctrlBackColor; QPushButton *m_pctrlTextClr; QPushButton *m_pctrlTextFont; QPushButton *m_pctrlGraphSettings; QPushButton *OKButton, *CancelButton; QCheckBox *m_pctrlReverseZoom, *m_pctrlAlphaChannel; QComboBox *m_pctrlStyles; QPushButton *OK, *Cancel; void *m_pMainFrame; QColor m_BackgroundColor; QColor m_TextColor; QFont m_TextFont; QGraph *m_pRefGraph; QGraph m_MemGraph; bool m_bIsGraphModified; bool m_bReverseZoom, m_bAlphaChannel; static bool s_bStyleSheets; static QString s_StyleName, s_StyleSheetName; QDir m_StyleSheetDir; }; #endif // DisplaySettingsDlg_H xflr5-6.09-06/src/misc/RenameDlg.cpp000644 001750 000144 00000013537 12247174404 020370 0ustar00techwinderusers000000 000000 /**************************************************************************** RenameDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "RenameDlg.h" #include RenameDlg::RenameDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Rename")); m_bEnableOverwrite = true; m_bExists = true; m_pstrArray = NULL; SetupLayout(); } void RenameDlg::SetupLayout() { QVBoxLayout *MainLayout = new QVBoxLayout; m_pctrlMessage = new QLabel("A Message here"); m_pctrlNote = new QLabel(tr("Enter the new name")); m_pctrlNote->setMinimumWidth(350); m_pctrlName = new QLineEdit(""); QLabel* NameListLabel = new QLabel(tr("Existing Names:")); m_pctrlNameList = new QListWidget; connect(m_pctrlNameList, SIGNAL(currentRowChanged(int)), this, SLOT(OnSelChangeList(int))); connect(m_pctrlNameList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(OnDoubleClickList(QListWidgetItem *))); QHBoxLayout *CommandButtons = new QHBoxLayout; OKButton = new QPushButton(tr("OK")); OKButton->setAutoDefault(false); CancelButton = new QPushButton(tr("Cancel")); CancelButton->setAutoDefault(false); OverwriteButton = new QPushButton(tr("Overwrite")); OverwriteButton->setAutoDefault(false); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); CommandButtons->addWidget(OverwriteButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(OverwriteButton, SIGNAL(clicked()), this, SLOT(OnOverwrite())); QLabel *LabelNote = new QLabel; LabelNote->setText(tr("Note : Overwrite will delete Opps and reset polars")); MainLayout->setStretchFactor(m_pctrlMessage, 1); MainLayout->setStretchFactor(m_pctrlName, 1); MainLayout->setStretchFactor(NameListLabel, 1); MainLayout->setStretchFactor(m_pctrlNameList, 5); MainLayout->setStretchFactor(CommandButtons, 1); MainLayout->setStretchFactor(LabelNote, 1); MainLayout->addWidget(m_pctrlMessage); MainLayout->addWidget(m_pctrlName); MainLayout->addStretch(1); MainLayout->addWidget(NameListLabel); MainLayout->addWidget(m_pctrlNameList); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addWidget(LabelNote); MainLayout->setStretchFactor(m_pctrlMessage, 1); MainLayout->setStretchFactor(m_pctrlName, 1); MainLayout->setStretchFactor(NameListLabel, 1); MainLayout->setStretchFactor(m_pctrlNameList, 5); MainLayout->setStretchFactor(CommandButtons, 1); MainLayout->setStretchFactor(LabelNote, 1); setLayout(MainLayout); } void RenameDlg::InitDialog() { m_pctrlNote->setText(m_Note); m_pctrlNameList->clear(); if(!m_bEnableOverwrite) OverwriteButton->setEnabled(false); if(m_strName.length()) { m_pctrlMessage->setText(m_strQuestion); } else { m_pctrlMessage->setText(tr("Enter a name")); } m_StartName = m_strName; m_pctrlName->setText(m_StartName); m_pctrlName->setFocus(); m_pctrlName->selectAll(); if(m_pstrArray) { for (int i=0; isize(); i++) { m_pctrlNameList->addItem(m_pstrArray->at(i)); } } else { m_pctrlNameList->setEnabled(false); OverwriteButton->setEnabled(false); } } void RenameDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OKButton->setFocus(); } else { OnOK(); } return; } case Qt::Key_Escape: { reject(); return; } default: event->ignore(); } } void RenameDlg::OnOverwrite() { m_bExists = true; m_strName = m_pctrlName->text(); done(10); } void RenameDlg::OnOK() { m_strName = m_pctrlName->text(); if (!m_strName.length()) { QMessageBox::warning(this, tr("Warning"), tr("Must enter a name")); m_pctrlName->setFocus(); return; } QString strong; //exists ? m_bExists = false; if(m_pstrArray) { for (int l=0; lsize(); l++) { strong = m_pstrArray->at(l); if(strong == m_strName) { QString str = tr("Do you wish to overwrite ")+m_strName + " ?"; if (QMessageBox::Yes == QMessageBox::question(window(), tr("Question"), str, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel)) { m_bExists = true; done(10); return; } else return; } } } QDialog::accept(); } void RenameDlg::OnSelChangeList(int item) { QListWidgetItem *pItem = m_pctrlNameList->currentItem(); if(pItem) { QString str = pItem->text(); m_pctrlName->setText(str); m_pctrlName->selectAll(); } } void RenameDlg::OnDoubleClickList(QListWidgetItem * pItem) { // QListWidgetItem *pItem = m_pctrlNameList->currentItem(); if(pItem) { QString str = pItem->text(); m_pctrlName->setText(str); OnOK(); } } xflr5-6.09-06/src/misc/FloatEditDelegate.h000644 001750 000144 00000003410 12247174404 021472 0ustar00techwinderusers000000 000000 /**************************************************************************** DoubleEditDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef DoubleEditDELEGATE_H #define DoubleEditDELEGATE_H #include #include "DoubleEdit.h" class FloatEditDelegate : public QItemDelegate { Q_OBJECT public: FloatEditDelegate(QObject *parent = 0); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void SetPrecision(int*PrecisionTable); private: int *m_Precision; ///table of float precisions for each column }; #endif // QDoubleEditDELEGATE_H xflr5-6.09-06/src/misc/IntEdit.cpp000644 001750 000144 00000004142 12247261645 020066 0ustar00techwinderusers000000 000000 /**************************************************************************** IntEdit Class Copyright (C) 2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "IntEdit.h" IntEdit::IntEdit(QWidget *pParent) { setParent(pParent); m_Value = 0.0; m_pDV = new QIntValidator(this); setValidator(m_pDV); setAlignment(Qt::AlignRight); } IntEdit::IntEdit(int val, QWidget *pParent) { if(pParent) setParent(pParent); m_Value = val; m_pDV = new QIntValidator(this); setValidator(m_pDV); setAlignment(Qt::AlignRight); } void IntEdit::focusOutEvent (QFocusEvent *event) { ReadValue(); FormatValue(); emit(editingFinished()); QLineEdit::focusOutEvent(event); } int IntEdit::ReadValue() { bool bOK; int f = locale().toInt(text().trimmed(), &bOK); if(bOK) m_Value = f; return m_Value; } void IntEdit::SetValue(int val) { m_Value = val; FormatValue(); } void IntEdit::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Return: { ReadValue(); FormatValue(); QLineEdit::keyPressEvent(event); break; } case Qt::Key_Escape: { FormatValue(); QLineEdit::keyPressEvent(event); break; } default: { QLineEdit::keyPressEvent(event); ReadValue(); break; } } } void IntEdit::FormatValue() { setText(QString("%L1").arg(m_Value)); } void IntEdit::SetValueNoFormat(int val) { m_Value = val; } xflr5-6.09-06/src/misc/ObjectPropsDlg.h000644 001750 000144 00000002707 12247174404 021055 0ustar00techwinderusers000000 000000 /**************************************************************************** ObjectPropsDlg Class Copyright (C) 2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef ObjectPropsDlg_H #define ObjectPropsDlg_H #include #include #include "../objects/Polar.h" #include "../objects/WPolar.h" class ObjectPropsDlg : public QDialog { Q_OBJECT friend class MainFrame; friend class QXDirect; friend class QMiarex; public: ObjectPropsDlg(QWidget *pParent); void InitDialog(); private: void SetupLayout(); QTextEdit *m_pctrlDescription; Polar *m_pPolar; WPolar *m_pWPolar; WingOpp *m_pWOpp; OpPoint *m_pOpp; void *m_pXDirect; void *m_pMiarex; }; #endif // ObjectPropsDlg_H xflr5-6.09-06/src/misc/LineBtn.h000644 001750 000144 00000003050 12247407671 017524 0ustar00techwinderusers000000 000000 /**************************************************************************** LineBtn Class Copyright (C) 2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef CharWidget_H #define CharWidget_H #include class LineBtn : public QAbstractButton { Q_OBJECT public: LineBtn(QWidget *parent = 0); void SetStyle(int const &style, int const &width, QColor const & color); void SetColor(QColor const & color); void SetStyle(int const &style); void SetWidth(int const &width); QColor &GetColor(); int & GetStyle(); int & GetWidth(); signals: void clickedLB(); public: void mouseReleaseEvent(QMouseEvent *event); void paintEvent(QPaintEvent *event); QSize sizeHint() const; private: QColor m_Color; int m_Style, m_Width; }; #endif xflr5-6.09-06/src/misc/AboutQ5.h000644 001750 000144 00000002335 12247174404 017451 0ustar00techwinderusers000000 000000 /**************************************************************************** AboutQ5 Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef ABOUTQ5_H #define ABOUTQ5_H #include #include class AboutQ5 : public QDialog { Q_OBJECT public: explicit AboutQ5(QWidget *parent); private: void SetupLayout(); void *m_pMainFrame; }; #endif // AboutQ5_H xflr5-6.09-06/src/misc/PolarFilterDlg.cpp000644 001750 000144 00000007740 12247174404 021403 0ustar00techwinderusers000000 000000 /**************************************************************************** PolarFilterDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include "PolarFilterDlg.h" PolarFilterDlg::PolarFilterDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Polar Filter")); m_bType1 = m_bType2 = m_bType3 = m_bType4 = m_bType5 = m_bType6 = m_bType7 = true; m_bMiarex = false; SetupLayout(); } void PolarFilterDlg::SetupLayout() { QVBoxLayout *MainLayout = new QVBoxLayout; QLabel *Label = new QLabel(tr("Show polar types")); m_pctrlType1 = new QCheckBox(tr("Type 1")); m_pctrlType2 = new QCheckBox(tr("Type 2")); m_pctrlType3 = new QCheckBox(tr("Type 3")); m_pctrlType4 = new QCheckBox(tr("Type 4")); m_pctrlType5 = new QCheckBox(tr("Type 5")); m_pctrlType6 = new QCheckBox(tr("Type 6")); m_pctrlType7 = new QCheckBox(tr("Type 7")); QHBoxLayout *CommandButtons = new QHBoxLayout; OKButton = new QPushButton(tr("OK")); OKButton->setAutoDefault(false); QPushButton *CancelButton = new QPushButton(tr("Cancel")); CancelButton->setAutoDefault(false); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); MainLayout->addWidget(Label); MainLayout->addWidget(m_pctrlType1); MainLayout->addWidget(m_pctrlType2); MainLayout->addWidget(m_pctrlType3); MainLayout->addWidget(m_pctrlType4); MainLayout->addWidget(m_pctrlType5); MainLayout->addWidget(m_pctrlType6); MainLayout->addWidget(m_pctrlType7); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); setLayout(MainLayout); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()),this, SLOT(reject())); } void PolarFilterDlg::InitDialog() { m_pctrlType1->setChecked(m_bType1); m_pctrlType2->setChecked(m_bType2); m_pctrlType3->setChecked(m_bType3); m_pctrlType4->setChecked(m_bType4); m_pctrlType5->setChecked(m_bType5); m_pctrlType6->setChecked(m_bType6); m_pctrlType7->setChecked(m_bType7); if(m_bMiarex) { m_pctrlType3->setEnabled(false); m_pctrlType3->setChecked(false); } else { m_pctrlType5->setChecked(false); m_pctrlType6->setChecked(false); m_pctrlType7->setChecked(false); m_pctrlType5->setEnabled(false); m_pctrlType6->setEnabled(false); m_pctrlType7->setEnabled(false); } } void PolarFilterDlg::OnOK() { m_bType1 = m_pctrlType1->isChecked(); m_bType2 = m_pctrlType2->isChecked(); m_bType3 = m_pctrlType3->isChecked(); m_bType4 = m_pctrlType4->isChecked(); m_bType5 = m_pctrlType5->isChecked(); m_bType6 = m_pctrlType6->isChecked(); m_bType7 = m_pctrlType7->isChecked(); QDialog::accept(); } void PolarFilterDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus()) { OKButton->setFocus(); return; } else { accept(); return; } break; } case Qt::Key_Escape: { reject(); return; } } } xflr5-6.09-06/src/misc/UnitsDlg.cpp000644 001750 000144 00000022442 12247174404 020256 0ustar00techwinderusers000000 000000 /**************************************************************************** UnitsDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../globals.h" #include "UnitsDlg.h" #include #include UnitsDlg::UnitsDlg(QWidget *parent): QDialog(parent) { m_Length = 0; m_Area = 1; m_Weight = 1; m_Speed = 0; m_Force = 0; m_bLengthOnly = false; m_Question = tr("Select units for this project :"); setWindowTitle(tr("Units Dialog")); SetupLayout(); } void UnitsDlg::SetupLayout() { QGridLayout *UnitsLayout = new QGridLayout; QLabel *lab1 = new QLabel(tr("Length")); QLabel *lab2 = new QLabel(tr("Area")); QLabel *lab3 = new QLabel(tr("Speed")); QLabel *lab4 = new QLabel(tr("Mass")); QLabel *lab5 = new QLabel(tr("Force")); QLabel *lab6 = new QLabel(tr("Moment")); UnitsLayout->addWidget(lab1, 1,1); UnitsLayout->addWidget(lab2, 2,1); UnitsLayout->addWidget(lab3, 3,1); UnitsLayout->addWidget(lab4, 4,1); UnitsLayout->addWidget(lab5, 5,1); UnitsLayout->addWidget(lab6, 6,1); m_pctrlQuestion = new QLabel(tr("Define the project units")); m_pctrlLengthFactor = new QLabel(" "); m_pctrlSurfaceFactor = new QLabel(" "); m_pctrlWeightFactor = new QLabel(" "); m_pctrlSpeedFactor = new QLabel(" "); m_pctrlForceFactor = new QLabel(" "); m_pctrlMomentFactor = new QLabel(" "); m_pctrlLengthFactor->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlSurfaceFactor->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlWeightFactor->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlSpeedFactor->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlForceFactor->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlMomentFactor->setAlignment(Qt::AlignRight | Qt::AlignCenter); UnitsLayout->addWidget(m_pctrlLengthFactor, 1,2); UnitsLayout->addWidget(m_pctrlSurfaceFactor, 2,2); UnitsLayout->addWidget(m_pctrlSpeedFactor, 3,2); UnitsLayout->addWidget(m_pctrlWeightFactor, 4,2); UnitsLayout->addWidget(m_pctrlForceFactor, 5,2); UnitsLayout->addWidget(m_pctrlMomentFactor, 6,2); m_pctrlLength = new QComboBox; m_pctrlSurface = new QComboBox; m_pctrlSpeed = new QComboBox; m_pctrlWeight = new QComboBox; m_pctrlForce = new QComboBox; m_pctrlMoment = new QComboBox; UnitsLayout->addWidget(m_pctrlLength, 1,3); UnitsLayout->addWidget(m_pctrlSurface, 2,3); UnitsLayout->addWidget(m_pctrlSpeed, 3,3); UnitsLayout->addWidget(m_pctrlWeight, 4,3); UnitsLayout->addWidget(m_pctrlForce, 5,3); UnitsLayout->addWidget(m_pctrlMoment, 6,3); m_pctrlLengthInvFactor = new QLabel(" "); m_pctrlSurfaceInvFactor = new QLabel(" "); m_pctrlWeightInvFactor = new QLabel(" "); m_pctrlSpeedInvFactor = new QLabel(" "); m_pctrlForceInvFactor = new QLabel(" "); m_pctrlMomentInvFactor = new QLabel(" "); m_pctrlLengthInvFactor->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlSurfaceInvFactor->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlWeightInvFactor->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlSpeedInvFactor->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlForceInvFactor->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlMomentInvFactor->setAlignment(Qt::AlignRight | Qt::AlignCenter); UnitsLayout->addWidget(m_pctrlLengthInvFactor, 1,4); UnitsLayout->addWidget(m_pctrlSurfaceInvFactor, 2,4); UnitsLayout->addWidget(m_pctrlSpeedInvFactor, 3,4); UnitsLayout->addWidget(m_pctrlWeightInvFactor, 4,4); UnitsLayout->addWidget(m_pctrlForceInvFactor, 5,4); UnitsLayout->addWidget(m_pctrlMomentInvFactor, 6,4); UnitsLayout->setColumnStretch(4,2); UnitsLayout->setColumnMinimumWidth(4,220); QHBoxLayout *CommandButtons = new QHBoxLayout; OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addWidget(m_pctrlQuestion); MainLayout->addLayout(UnitsLayout); MainLayout->addStretch(1); MainLayout->addSpacing(20); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); setLayout(MainLayout); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(m_pctrlLength, SIGNAL(activated(const QString &)),this, SLOT(OnSelChanged(const QString &))); connect(m_pctrlSurface, SIGNAL(activated(const QString &)),this, SLOT(OnSelChanged(const QString &))); connect(m_pctrlSpeed, SIGNAL(activated(const QString &)),this, SLOT(OnSelChanged(const QString &))); connect(m_pctrlWeight, SIGNAL(activated(const QString &)),this, SLOT(OnSelChanged(const QString &))); connect(m_pctrlForce, SIGNAL(activated(const QString &)),this, SLOT(OnSelChanged(const QString &))); connect(m_pctrlMoment, SIGNAL(activated(const QString &)),this, SLOT(OnSelChanged(const QString &))); } void UnitsDlg::InitDialog() { QStringList list; list <<"mm" << "cm"<<"dm"<<"m"<<"in"<<"ft"; m_pctrlLength->clear(); m_pctrlLength->addItems(list); //5 m_pctrlSurface->clear(); m_pctrlSurface->addItem(QString::fromUtf8("mm²")); //0 m_pctrlSurface->addItem(QString::fromUtf8("cm²")); //1 m_pctrlSurface->addItem(QString::fromUtf8("dm²")); //2 m_pctrlSurface->addItem(QString::fromUtf8("m²")); //3 m_pctrlSurface->addItem(QString::fromUtf8("in²")); //4 m_pctrlSurface->addItem(QString::fromUtf8("ft²")); //5 m_pctrlSpeed->clear(); m_pctrlSpeed->addItem("m/s"); //0 m_pctrlSpeed->addItem("km/h"); //1 m_pctrlSpeed->addItem("ft/s"); //2 m_pctrlSpeed->addItem("kt (int.)"); //3 m_pctrlSpeed->addItem("mph"); //4 m_pctrlWeight->clear(); m_pctrlWeight->addItem("g"); //0 m_pctrlWeight->addItem("kg"); //1 m_pctrlWeight->addItem("oz"); //2 m_pctrlWeight->addItem("lb"); //3 m_pctrlForce->clear(); m_pctrlForce->addItem("N"); //0 m_pctrlForce->addItem("lbf"); //1 m_pctrlMoment->clear(); m_pctrlMoment->addItem("N.m"); //0 m_pctrlMoment->addItem("lbf.in"); //1 m_pctrlMoment->addItem("lbf.ft"); //2 m_pctrlLength->setCurrentIndex(m_Length); m_pctrlWeight->setCurrentIndex(m_Weight); m_pctrlSurface->setCurrentIndex(m_Area); m_pctrlSpeed->setCurrentIndex(m_Speed); m_pctrlForce->setCurrentIndex(m_Force); m_pctrlMoment->setCurrentIndex(m_Moment); m_pctrlLength->setFocus(); OnSelChanged(" "); if(m_bLengthOnly) { m_pctrlSpeed->setEnabled(false); m_pctrlSurface->setEnabled(false); m_pctrlWeight->setEnabled(false); m_pctrlForce->setEnabled(false); m_pctrlMoment->setEnabled(false); } m_pctrlQuestion->setText(m_Question); } void UnitsDlg::OnSelChanged(const QString &strong) { m_Length = m_pctrlLength->currentIndex(); m_Area = m_pctrlSurface->currentIndex(); m_Weight = m_pctrlWeight->currentIndex(); m_Speed = m_pctrlSpeed->currentIndex(); m_Force = m_pctrlForce->currentIndex(); m_Moment = m_pctrlMoment->currentIndex(); SetUnits(m_Length, m_Area, m_Speed, m_Weight, m_Force, m_Moment, m_mtoUnit, m_m2toUnit, m_mstoUnit, m_kgtoUnit, m_NtoUnit, m_NmtoUnit); QString str, strange; GetLengthUnit(str,m_Length); strange= QString(" 1 m = %1").arg(m_mtoUnit,15,'f',5); m_pctrlLengthFactor->setText(strange); strange= "1 "+str+" = " +QString("%1 m").arg(1./m_mtoUnit,15,'f',5); m_pctrlLengthInvFactor->setText(strange); GetAreaUnit(str,m_Area); strange= QString(QString::fromUtf8(" 1 m² = %1")).arg(m_m2toUnit,15,'f',5); m_pctrlSurfaceFactor->setText(strange); strange= "1 "+str+" = " +QString("%1 m").arg(1./m_m2toUnit,15,'f',5); strange += QString::fromUtf8("²"); m_pctrlSurfaceInvFactor->setText(strange); GetWeightUnit(str,m_Weight); strange= QString(" 1 kg = %1").arg(m_kgtoUnit,15,'f',5); m_pctrlWeightFactor->setText(strange); strange= "1 "+str+" = " +QString("%1 kg").arg(1./m_kgtoUnit,15,'f',5); m_pctrlWeightInvFactor->setText(strange); GetSpeedUnit(str,m_Speed); strange= QString(" 1 m/s = %1").arg(m_mstoUnit,15,'f',5); m_pctrlSpeedFactor->setText(strange); strange= "1 "+str+" = " +QString("%1 m/s").arg(1./m_mstoUnit,15,'f',5); m_pctrlSpeedInvFactor->setText(strange); GetForceUnit(str,m_Force); strange= QString(" 1 N = %1").arg(m_NtoUnit,15,'f',5); m_pctrlForceFactor->setText(strange); strange= "1 "+str+" = " +QString("%1 N").arg(1./m_NtoUnit,15,'f',5); m_pctrlForceInvFactor->setText(strange); GetMomentUnit(str,m_Moment); strange= QString(" 1 N.m = %1").arg(m_NmtoUnit,15,'f',5); m_pctrlMomentFactor->setText(strange); strange= "1 "+str+" = " +QString("%1 N.m").arg(1./m_NmtoUnit,15,'f',5); m_pctrlMomentInvFactor->setText(strange); } xflr5-6.09-06/src/misc/AboutQ5.cpp000644 001750 000144 00000011026 12247174407 020004 0ustar00techwinderusers000000 000000 /**************************************************************************** AboutQ5 Class Copyright (C) 2008-2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "AboutQ5.h" #include "../mainframe.h" #include #include AboutQ5::AboutQ5(QWidget *parent) : QDialog(parent) { setWindowTitle(tr("About XFLR5")); m_pMainFrame = parent; SetupLayout(); } void AboutQ5::SetupLayout() { QGridLayout *LogoLayout = new QGridLayout; { QLabel *LabIconQ5 = new QLabel; LabIconQ5->setObjectName("iconXFLR5"); LabIconQ5->setPixmap(QPixmap(QString::fromUtf8(":/images/xflr5_64.png"))); QLabel *lab1 = new QLabel(MainFrame::versionName()); lab1->setAlignment(Qt::AlignVCenter| Qt::AlignLeft); QLabel *XFLR5Link = new QLabel; XFLR5Link->setText("http://www.xflr5.com"); XFLR5Link->setOpenExternalLinks(true); XFLR5Link->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse); XFLR5Link->setAlignment(Qt::AlignVCenter| Qt::AlignLeft); LogoLayout->setColumnStretch(1,1); LogoLayout->setColumnStretch(2,2); LogoLayout->addWidget(LabIconQ5,1,1,2,1); LogoLayout->addWidget(lab1,1,2); LogoLayout->addWidget(XFLR5Link,2,2); } QLabel *lab2 = new QLabel(tr("Copyright (C) M. Drela and H. Youngren 2000 - XFoil v6.94")); QLabel *lab3 = new QLabel(tr("Copyright (C) Matthieu Scherrer 2004 - Miarex v1.00")); QLabel *lab4 = new QLabel(tr("Copyright (C) Andre Deperrois 2003-2013")); QLabel *lab5 = new QLabel(tr("This program is distributed in the hope that it will be useful,")); QLabel *lab6 = new QLabel(tr("but WITHOUT ANY WARRANTY; without even the implied warranty of")); QLabel *lab7 = new QLabel(tr("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.")); QLabel *lab8 = new QLabel(tr("This program has been developed exclusively for the analysis of model aircraft")); QLabel *lab9 = new QLabel(tr("Any other usage is strongly disapproved")); QLabel *lab10 = new QLabel(tr("Program distributed under the terms of the GNU General Public License")); QLabel *lab11 = new QLabel(tr("German translation by Martin Willner")); QLabel *lab12 = new QLabel(tr("Japanese translation by IKUSU, Koichi Akabe, Misatus, dynamicsoar, hide253")); QLabel *lab13 = new QLabel(tr("icchy_07, ina111, ohayo_cycling, ohisa_64, ozawa64.")); QLabel *lab14 = new QLabel(tr("French translation by Jean-Luc Coulon")); QPushButton *OKButton = new QPushButton(tr("OK")); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); QHBoxLayout *OKLayout = new QHBoxLayout; { OKLayout->addStretch(1); OKLayout->addWidget(OKButton); OKLayout->addStretch(1); } QVBoxLayout *MainLayout = new QVBoxLayout; { MainLayout->addLayout(LogoLayout); MainLayout->addStretch(1); MainLayout->addWidget(lab2); MainLayout->addWidget(lab3); MainLayout->addWidget(lab4); MainLayout->addStretch(1); MainLayout->addWidget(lab11); MainLayout->addWidget(lab12); MainLayout->addWidget(lab13); MainLayout->addWidget(lab14); MainLayout->addSpacing(20); MainLayout->addStretch(1); MainLayout->addWidget(lab5); MainLayout->addWidget(lab6); MainLayout->addWidget(lab7); MainLayout->addStretch(1); MainLayout->addWidget(lab8); MainLayout->addWidget(lab9); MainLayout->addStretch(1); MainLayout->addWidget(lab10); MainLayout->addStretch(1); MainLayout->addLayout(OKLayout); } setLayout(MainLayout); setMinimumHeight(400); } xflr5-6.09-06/src/misc/NewNameDlg.h000644 001750 000144 00000002625 12247174404 020154 0ustar00techwinderusers000000 000000 /**************************************************************************** NewNameDlg Classes Copyright (C) 2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef NEWNAMEDLG_H #define NEWNAMEDLG_H #include #include #include #include class NewNameDlg : public QDialog { friend class StabViewDlg; Q_OBJECT public: NewNameDlg(QWidget *pParent=NULL); void InitDialog(); void keyPressEvent(QKeyEvent *event); private: void SetupLayout(); private slots: void OnOK(); private: QPushButton *OKButton; QLineEdit *m_pctrlName; QString m_OldName; QString m_NewName; }; #endif // NEWNAMEDLG_H xflr5-6.09-06/src/misc/ColorButton.h000644 001750 000144 00000002442 12247422232 020435 0ustar00techwinderusers000000 000000 /**************************************************************************** ColorButton Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef COLORBUTTON_H #define COLORBUTTON_H #include class ColorButton : public QAbstractButton { public: ColorButton(QWidget *pParent = NULL); void paintEvent ( QPaintEvent * event ); QSize sizeHint() const; void SetColor(QColor const & color); QColor &GetColor(); private: QColor m_Color; }; #endif // COLORBUTTON_H xflr5-6.09-06/src/misc/LineBtn.cpp000644 001750 000144 00000006111 12247421772 020056 0ustar00techwinderusers000000 000000 /**************************************************************************** LineBtn Class Copyright (C) 2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include "../mainframe.h" #include "LineBtn.h" #include "../globals.h" LineBtn::LineBtn(QWidget *parent) : QAbstractButton(parent) { QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::MinimumExpanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Minimum); setSizePolicy(szPolicyExpanding); m_Color = Qt::darkGray; m_Style = 0; m_Width = 1; } void LineBtn::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { emit clickedLB(); } else QWidget::mouseReleaseEvent(event); } QSize LineBtn::sizeHint() const { QFontMetrics fm(MainFrame::s_TextFont); int w = 13 * fm.averageCharWidth(); int h = fm.height(); return QSize(w, h); } void LineBtn::SetColor(QColor const & color) { m_Color = color; update(); } void LineBtn::SetStyle(int const & style) { m_Style = style; update(); } void LineBtn::SetWidth(int const & width) { m_Width = width; update(); } void LineBtn::SetStyle(int const &style, int const &width, QColor const & color) { m_Style = style; m_Width = width; m_Color = color; update(); } QColor &LineBtn::GetColor() { return m_Color; } int &LineBtn::GetStyle() { return m_Style; } int &LineBtn::GetWidth() { return m_Width; } void LineBtn::paintEvent(QPaintEvent *event) { QRect r = rect(); QStyleOption opt; opt.init(this); QPainter painter(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); painter.save(); painter.setBrush(Qt::DiagCrossPattern); painter.setBackgroundMode(Qt::TransparentMode); QPen LinePen(m_Color); LinePen.setStyle(::GetStyle(m_Style)); LinePen.setWidth(m_Width); painter.setPen(LinePen); painter.drawLine(r.left()+5, r.height()/2, r.width()-10, r.height()/2); /* QColor ContourColor = Qt::gray; if(isEnabled()) { if(isDown()) { ContourColor = Qt::red; } else { ContourColor = Qt::gray; } } else { ContourColor = Qt::lightGray; } QPen ContourPen(ContourColor); painter.setPen(ContourPen); r.adjust(0,2,-1,-3); painter.drawRoundRect(r,5,40);*/ painter.restore(); } xflr5-6.09-06/src/misc/LineCbBox.cpp000644 001750 000144 00000004674 12247421667 020347 0ustar00techwinderusers000000 000000 /**************************************************************************** LineCbBox Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../globals.h" #include "../mainframe.h" #include "LineCbBox.h" #include #include #include LineCbBox::LineCbBox(QWidget *pParent) :QComboBox(pParent) { setParent(pParent); m_Style = 0; m_Width = 1; m_Color = QColor(255,100,50); QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::MinimumExpanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Minimum); setSizePolicy(szPolicyExpanding); } QSize LineCbBox::sizeHint() const { QFontMetrics fm(MainFrame::s_TextFont); int w = 13 * fm.averageCharWidth(); int h = fm.height(); return QSize(w, h); } void LineCbBox::SetLine(int const &style, int const &width, QColor const &color) { m_Style = style; m_Width = width; m_Color = color; } void LineCbBox::paintEvent (QPaintEvent *event) { QStyleOption opt; opt.init(this); QPainter painter(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); painter.save(); QColor ContourColor = Qt::gray; if(isEnabled()) ContourColor = Qt::gray; else ContourColor = Qt::lightGray; QRect r = event->rect(); // QRect g = rect(); painter.setBrush(Qt::NoBrush); painter.setBackgroundMode(Qt::TransparentMode); QPen LinePen(m_Color); LinePen.setStyle(GetStyle(m_Style)); LinePen.setWidth(m_Width); painter.setPen(LinePen); painter.drawLine(r.left()+5, r.height()/2, r.width()-10, r.height()/2); // QPen ContourPen(ContourColor); // painter.setPen(ContourPen); // r.adjust(0,2,-1,-3); // painter.drawRoundRect(r,5,40); painter.restore(); } xflr5-6.09-06/src/misc/GLLightDlg.h000644 001750 000144 00000005370 12247174404 020114 0ustar00techwinderusers000000 000000 /**************************************************************************** GLLightDlg class Copyright (C) 2009 Andre Deperrois xflr5@yahoo.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef GLLIGHTDLG_H #define GLLIGHTDLG_H #include #include #include #include #include class GLLightDlg : public QDialog { Q_OBJECT friend class QMiarex; friend class ThreeDWidget; public: GLLightDlg(QWidget *pParent=NULL); void Apply(); void ReadParams(void); void SetDefaults(double size); void SetParams(void); static bool LoadSettings(QSettings *pSettings); static bool SaveSettings(QSettings *pSettings); static bool IsLightOn() {return s_bLight;} static void SetLightOn(bool bLight) {s_bLight = bLight;} private: void SetupLayout(); void showEvent(QShowEvent *event); void SetEnabled(); private slots: void OnSlider(int pos); void OnChanged(); void OnDefaults(); void OnLight(); private: QSlider *m_pctrlRed; QSlider *m_pctrlGreen; QSlider *m_pctrlBlue; QSlider *m_pctrlAmbient; QSlider *m_pctrlDiffuse; QSlider *m_pctrlSpecular; QSlider *m_pctrlMatAmbient; QSlider *m_pctrlMatDiffuse; QSlider *m_pctrlMatSpecular; QSlider *m_pctrlMatShininess; QSlider *m_pctrlMatEmission; QSlider *m_pctrlXLight; QSlider *m_pctrlYLight; QSlider *m_pctrlZLight; QCheckBox *m_pctrlColorMaterial; QCheckBox *m_pctrlDepthTest; QCheckBox *m_pctrlCullFaces; QCheckBox *m_pctrlShade; QCheckBox *m_pctrlSmooth; QCheckBox *m_pctrlLocalView; QCheckBox *m_pctrlLight; QPushButton *m_pctrlDefaults, *m_pctrlClose; private: void *m_pGL3dBodyDlg; void *m_pGL3dWingDlg; void *m_p3DWidget; static float s_Ambient, s_Diffuse, s_Specular; static float s_MatAmbient, s_MatDiffuse, s_MatSpecular, s_MatEmission; static float s_Red, s_Green, s_Blue; static float s_XLight, s_YLight, s_ZLight; static int s_iMatShininess; static bool s_bCullFaces, s_bShade, s_bSmooth, s_bLocalView, s_bDepthTest; static bool s_bColorMaterial; static bool s_bLight; double m_Size; }; #endif // GLLIGHTDLG_H xflr5-6.09-06/src/misc/LinePickerDlg.h000644 001750 000144 00000003563 12247174404 020651 0ustar00techwinderusers000000 000000 /**************************************************************************** LinePicker Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef LINEPICKERDLG_H #define LINEPICKERDLG_H #include #include #include "LineBtn.h" #include "LineCbBox.h" #include "LineDelegate.h" class LinePickerDlg : public QDialog { Q_OBJECT public: LinePickerDlg(QWidget *pParent); void InitDialog(); void InitDialog(int style, int width, QColor color); void keyPressEvent(QKeyEvent *event); int &GetWidth(); int &GetStyle(); QColor &GetColor(); void SetColor(QColor color); void SetWidth(int width); void SetStyle(int style); void FillBoxes(); void SetupLayout(); protected: LineBtn *m_pctrlColor; LineCbBox *m_pctrlWidth, *m_pctrlStyle; QPushButton *OKButton, *CancelButton; private: int m_Style; int m_Width; QColor m_Color; void* m_pParent; LineDelegate *m_pStyleDelegate, *m_pWidthDelegate; private slots: void OnWidth(int val); void OnStyle(int val); void OnColor(); }; #endif // LINEPICKERDLG_H xflr5-6.09-06/src/misc/GLLightDlg.cpp000644 001750 000144 00000043501 12247174404 020445 0ustar00techwinderusers000000 000000 /**************************************************************************** GLLightDlg class Copyright (C) 2009 Andre Deperrois xflr5@yahoo.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "GLLightDlg.h" #include "../threedwidget.h" #include #include #include #include #include float GLLightDlg::s_Ambient, GLLightDlg::s_Diffuse, GLLightDlg::s_Specular; float GLLightDlg::s_MatAmbient, GLLightDlg::s_MatDiffuse, GLLightDlg::s_MatSpecular, GLLightDlg::s_MatEmission; float GLLightDlg::s_Red, GLLightDlg::s_Green, GLLightDlg::s_Blue; float GLLightDlg::s_XLight, GLLightDlg::s_YLight, GLLightDlg::s_ZLight; int GLLightDlg::s_iMatShininess; bool GLLightDlg::s_bCullFaces, GLLightDlg::s_bShade, GLLightDlg::s_bSmooth, GLLightDlg::s_bLocalView, GLLightDlg::s_bDepthTest; bool GLLightDlg::s_bColorMaterial; bool GLLightDlg::s_bLight; GLLightDlg::GLLightDlg(QWidget *pParent) : QDialog(pParent) { m_pGL3dBodyDlg = m_pGL3dWingDlg = NULL; m_Size = 5.0; SetDefaults(m_Size); setWindowTitle(tr("OpenGL Light Options")); setModal(false); setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); SetupLayout(); connect(m_pctrlClose, SIGNAL(clicked()),this, SLOT(accept())); connect(m_pctrlDefaults, SIGNAL(clicked()), this, SLOT(OnDefaults())); connect(m_pctrlRed, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlGreen, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlBlue, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlAmbient, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlDiffuse, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlSpecular, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlMatAmbient, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlMatDiffuse, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlMatSpecular, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlMatShininess, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlMatEmission, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlXLight, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlYLight, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlZLight, SIGNAL(sliderMoved(int)), this, SLOT(OnSlider(int))); connect(m_pctrlColorMaterial, SIGNAL(clicked()), this, SLOT(OnChanged())); connect(m_pctrlDepthTest, SIGNAL(clicked()), this, SLOT(OnChanged())); connect(m_pctrlCullFaces, SIGNAL(clicked()), this, SLOT(OnChanged())); connect(m_pctrlShade, SIGNAL(clicked()), this, SLOT(OnChanged())); connect(m_pctrlSmooth, SIGNAL(clicked()), this, SLOT(OnChanged())); connect(m_pctrlLocalView, SIGNAL(clicked()), this, SLOT(OnChanged())); connect(m_pctrlLight, SIGNAL(clicked()), this, SLOT(OnLight())); } void GLLightDlg::SetupLayout() { m_pctrlDiffuse = new QSlider(Qt::Horizontal); m_pctrlAmbient = new QSlider(Qt::Horizontal); m_pctrlSpecular = new QSlider(Qt::Horizontal); m_pctrlRed = new QSlider(Qt::Horizontal); m_pctrlGreen = new QSlider(Qt::Horizontal); m_pctrlBlue = new QSlider(Qt::Horizontal); m_pctrlXLight = new QSlider(Qt::Horizontal); m_pctrlYLight = new QSlider(Qt::Horizontal); m_pctrlZLight = new QSlider(Qt::Horizontal); m_pctrlMatDiffuse = new QSlider(Qt::Horizontal); m_pctrlMatAmbient = new QSlider(Qt::Horizontal); m_pctrlMatSpecular = new QSlider(Qt::Horizontal); m_pctrlMatEmission = new QSlider(Qt::Horizontal); m_pctrlMatShininess = new QSlider(Qt::Horizontal); m_pctrlDiffuse->setTickPosition(QSlider::TicksBelow); m_pctrlAmbient->setTickPosition(QSlider::TicksBelow); m_pctrlSpecular->setTickPosition(QSlider::TicksBelow); m_pctrlRed->setTickPosition(QSlider::TicksBelow); m_pctrlGreen->setTickPosition(QSlider::TicksBelow); m_pctrlBlue->setTickPosition(QSlider::TicksBelow); m_pctrlXLight->setTickPosition(QSlider::TicksBelow); m_pctrlYLight->setTickPosition(QSlider::TicksBelow); m_pctrlZLight->setTickPosition(QSlider::TicksBelow); m_pctrlMatDiffuse->setTickPosition(QSlider::TicksBelow); m_pctrlMatAmbient->setTickPosition(QSlider::TicksBelow); m_pctrlMatSpecular->setTickPosition(QSlider::TicksBelow); m_pctrlMatEmission->setTickPosition(QSlider::TicksBelow); m_pctrlMatShininess->setTickPosition(QSlider::TicksBelow); m_pctrlRed->setMinimum(0); m_pctrlRed->setMaximum(100); m_pctrlRed->setTickInterval(10); m_pctrlGreen->setMinimum(0); m_pctrlGreen->setMaximum(100); m_pctrlGreen->setTickInterval(10); m_pctrlBlue->setMinimum(0); m_pctrlBlue->setMaximum(100); m_pctrlBlue->setTickInterval(10); m_pctrlAmbient->setMinimum(0); m_pctrlAmbient->setMaximum(100); m_pctrlAmbient->setTickInterval(10); m_pctrlDiffuse->setMinimum(0); m_pctrlDiffuse->setMaximum(100); m_pctrlDiffuse->setTickInterval(10); m_pctrlSpecular->setMinimum(0); m_pctrlSpecular->setMaximum(100); m_pctrlSpecular->setTickInterval(10); m_pctrlMatAmbient->setMinimum(-100); m_pctrlMatAmbient->setMaximum(100); m_pctrlMatAmbient->setTickInterval(20); m_pctrlMatDiffuse->setMinimum(-100); m_pctrlMatDiffuse->setMaximum(100); m_pctrlMatDiffuse->setTickInterval(20); m_pctrlMatSpecular->setMinimum(-100); m_pctrlMatSpecular->setMaximum(100); m_pctrlMatSpecular->setTickInterval(20); m_pctrlMatEmission->setMinimum(-100); m_pctrlMatEmission->setMaximum(100); m_pctrlMatEmission->setTickInterval(20); m_pctrlMatShininess->setMinimum(0); m_pctrlMatShininess->setMaximum(128); m_pctrlMatShininess->setTickInterval(16); m_pctrlXLight->setMinimum(0); m_pctrlXLight->setMaximum(100); m_pctrlXLight->setTickInterval(10); m_pctrlYLight->setMinimum(0); m_pctrlYLight->setMaximum(100); m_pctrlYLight->setTickInterval(10); m_pctrlZLight->setMinimum(0); m_pctrlZLight->setMaximum(100); m_pctrlZLight->setTickInterval(10); QGroupBox *LightIntensityBox = new QGroupBox(tr("Light Intensity")); QGridLayout *LightIntensity = new QGridLayout; { QLabel *lab1 = new QLabel(tr("Diffuse")); QLabel *lab2 = new QLabel(tr("Ambient")); QLabel *lab3 = new QLabel(tr("Specular")); LightIntensity->addWidget(lab1,1,1); LightIntensity->addWidget(lab2,2,1); LightIntensity->addWidget(lab3,3,1); LightIntensity->addWidget(m_pctrlDiffuse,1,2); LightIntensity->addWidget(m_pctrlAmbient,2,2); LightIntensity->addWidget(m_pctrlSpecular,3,2); LightIntensityBox->setLayout(LightIntensity); } QGroupBox *LightColorBox = new QGroupBox(tr("Light Color")); { QGridLayout *LightColor = new QGridLayout; QLabel *lab11 = new QLabel(tr("Red")); QLabel *lab12 = new QLabel(tr("Green")); QLabel *lab13 = new QLabel(tr("Blue")); LightColor->addWidget(lab11,1,1); LightColor->addWidget(lab12,2,1); LightColor->addWidget(lab13,3,1); LightColor->addWidget(m_pctrlRed,1,2); LightColor->addWidget(m_pctrlGreen,2,2); LightColor->addWidget(m_pctrlBlue,3,2); LightColorBox->setLayout(LightColor); } QGroupBox *LightPositionBox = new QGroupBox(tr("Light Position")); { QGridLayout *LightPosition = new QGridLayout; QLabel *lab21 = new QLabel(tr("x")); QLabel *lab22 = new QLabel(tr("y")); QLabel *lab23 = new QLabel(tr("z")); LightPosition->addWidget(lab21,1,1); LightPosition->addWidget(lab22,2,1); LightPosition->addWidget(lab23,3,1); LightPosition->addWidget(m_pctrlXLight,1,2); LightPosition->addWidget(m_pctrlYLight,2,2); LightPosition->addWidget(m_pctrlZLight,3,2); LightPositionBox->setLayout(LightPosition); } QGroupBox *MaterialDataBox = new QGroupBox(tr("Material")); { QGridLayout *MaterialData = new QGridLayout; QLabel *lab31 = new QLabel(tr("Diffuse")); QLabel *lab32 = new QLabel(tr("Ambient")); QLabel *lab33 = new QLabel(tr("Specular")); QLabel *lab34 = new QLabel(tr("Emissions")); QLabel *lab35 = new QLabel(tr("Shininess")); MaterialData->addWidget(lab31,1,1); MaterialData->addWidget(lab32,2,1); MaterialData->addWidget(lab33,3,1); MaterialData->addWidget(lab34,4,1); MaterialData->addWidget(lab35,5,1); MaterialData->addWidget(m_pctrlMatDiffuse,1,2); MaterialData->addWidget(m_pctrlMatAmbient,2,2); MaterialData->addWidget(m_pctrlMatSpecular,3,2); MaterialData->addWidget(m_pctrlMatEmission,4,2); MaterialData->addWidget(m_pctrlMatShininess,5,2); MaterialDataBox->setLayout(MaterialData); } QGroupBox *CheckBoxes = new QGroupBox(tr("Options")); { QVBoxLayout *CheckLayout = new QVBoxLayout; m_pctrlColorMaterial = new QCheckBox(tr("Color Material")); m_pctrlCullFaces = new QCheckBox(tr("Cull Faces")); m_pctrlSmooth = new QCheckBox(tr("Smooth Quads")); m_pctrlDepthTest = new QCheckBox(tr("Depth Test")); m_pctrlShade = new QCheckBox(tr("Smooth Shading")); m_pctrlLocalView = new QCheckBox(tr("Local View")); CheckLayout->addWidget(m_pctrlColorMaterial); CheckLayout->addWidget(m_pctrlCullFaces); CheckLayout->addWidget(m_pctrlSmooth); CheckLayout->addWidget(m_pctrlDepthTest); CheckLayout->addWidget(m_pctrlShade); CheckLayout->addWidget(m_pctrlLocalView); CheckBoxes->setLayout(CheckLayout); } QHBoxLayout *CommandButtons = new QHBoxLayout; { m_pctrlClose = new QPushButton(tr("Close")); m_pctrlDefaults = new QPushButton(tr("Reset Defaults")); CommandButtons->addStretch(1); CommandButtons->addWidget(m_pctrlDefaults); CommandButtons->addStretch(1); CommandButtons->addWidget(m_pctrlClose); CommandButtons->addStretch(1); } QVBoxLayout *LeftSide = new QVBoxLayout; { LeftSide->addStretch(1); LeftSide->addWidget(LightIntensityBox); LeftSide->addStretch(1); LeftSide->addWidget(LightColorBox); LeftSide->addStretch(1); LeftSide->addWidget(LightPositionBox); LeftSide->addStretch(1); } QVBoxLayout *RightSide = new QVBoxLayout; { RightSide->addStretch(1); RightSide->addWidget(MaterialDataBox); RightSide->addStretch(1); RightSide->addWidget(CheckBoxes); RightSide->addStretch(1); } QHBoxLayout *TopLayout = new QHBoxLayout; { TopLayout->addLayout(LeftSide); TopLayout->addLayout(RightSide); } QVBoxLayout *MainLayout = new QVBoxLayout; { m_pctrlLight = new QCheckBox(tr("Light")); MainLayout->addWidget(m_pctrlLight);; MainLayout->addLayout(TopLayout); MainLayout->addLayout(CommandButtons); } setLayout(MainLayout); } void GLLightDlg::Apply() { ReadParams(); ThreeDWidget *p3dWidget = (ThreeDWidget*)m_p3DWidget; p3dWidget->updateGL(); } void GLLightDlg::OnSlider(int pos) { Apply(); } void GLLightDlg::OnChanged() { Apply(); } void GLLightDlg::OnDefaults() { ThreeDWidget *p3dWidget = (ThreeDWidget*)m_p3DWidget; SetDefaults(m_Size); SetParams(); SetEnabled(); p3dWidget->updateGL(); } void GLLightDlg::ReadParams(void) { s_bLight = m_pctrlLight->isChecked(); s_Red = (float)m_pctrlRed->value() /100.0f; s_Green = (float)m_pctrlGreen->value() /100.0f; s_Blue = (float)m_pctrlBlue->value() /100.0f; s_MatAmbient = (float)m_pctrlMatAmbient->value() /100.0f; s_MatSpecular = (float)m_pctrlMatSpecular->value() /100.0f; s_MatDiffuse = (float)m_pctrlMatDiffuse->value() /100.0f; s_MatEmission = (float)m_pctrlMatEmission->value() /100.0f; s_iMatShininess = m_pctrlMatShininess->value(); s_bCullFaces = m_pctrlCullFaces->isChecked(); s_bColorMaterial = m_pctrlColorMaterial->isChecked(); s_bSmooth = m_pctrlSmooth->isChecked(); s_bShade = m_pctrlShade->isChecked(); s_bLocalView = m_pctrlLocalView->isChecked(); s_bDepthTest = m_pctrlDepthTest->isChecked(); float factor = 10.0f; s_XLight = ((float)m_pctrlXLight->value()-50.0f)/factor; s_YLight = ((float)m_pctrlYLight->value()-50.0f)/factor; s_ZLight = ((float)m_pctrlZLight->value())/factor; s_Ambient = (float)m_pctrlAmbient->value() / 100.0f; s_Diffuse = (float)m_pctrlDiffuse->value() / 100.0f; s_Specular = (float)m_pctrlSpecular->value() / 100.0f; } void GLLightDlg::SetParams(void) { m_pctrlLight->setChecked(s_bLight); m_pctrlAmbient->setValue( (int)(s_Ambient *100.0)); m_pctrlDiffuse->setValue( (int)(s_Diffuse *100.0)); m_pctrlSpecular->setValue( (int)(s_Specular *100.0)); float factor = 10.0f; m_pctrlXLight->setValue((int)((s_XLight+5.0)*factor)); m_pctrlYLight->setValue((int)((s_YLight+5.0)*factor)); m_pctrlZLight->setValue((int)((s_ZLight)*factor)); m_pctrlRed->setValue( (int)(s_Red *100.0)); m_pctrlGreen->setValue((int)(s_Green*100.0)); m_pctrlBlue->setValue( (int)(s_Blue *100.0)); m_pctrlMatAmbient->setValue( (int)(s_MatAmbient *100.0)); m_pctrlMatDiffuse->setValue( (int)(s_MatDiffuse *100.0)); m_pctrlMatSpecular->setValue( (int)(s_MatSpecular*100.0)); m_pctrlMatEmission->setValue( (int)(s_MatEmission*100.0)); m_pctrlMatShininess->setValue(s_iMatShininess); m_pctrlCullFaces->setChecked(s_bCullFaces); m_pctrlSmooth->setChecked(s_bSmooth); m_pctrlShade->setChecked(s_bShade); m_pctrlLocalView->setChecked(s_bLocalView); m_pctrlDepthTest->setChecked(s_bDepthTest); m_pctrlColorMaterial->setChecked(s_bColorMaterial); } bool GLLightDlg::LoadSettings(QSettings *pSettings) { pSettings->beginGroup("GLLight"); { // we're reading/loading s_Diffuse = pSettings->value("Diffuse",0.26).toDouble(); s_Ambient = pSettings->value("Ambient",0.18).toDouble(); s_Specular = pSettings->value("Specular",0.05).toDouble(); s_MatAmbient = pSettings->value("MatAmbient",-0.51).toDouble(); s_MatDiffuse = pSettings->value("MatDiffuse",-0.43).toDouble(); s_MatSpecular = pSettings->value("MatSpecular",-0.08).toDouble(); s_MatEmission = pSettings->value("MatEmission",-0.04).toDouble(); s_iMatShininess = pSettings->value("MatShininess",0).toDouble(); s_XLight = pSettings->value("XLight", 0.56).toDouble(); s_YLight = pSettings->value("YLight", 0.02).toDouble(); s_ZLight = pSettings->value("ZLight", 0.68).toDouble(); s_Red = pSettings->value("RedLight",1.0).toDouble(); s_Green = pSettings->value("GreenLight",1.0).toDouble(); s_Blue = pSettings->value("BlueLight",1.0).toDouble(); s_bCullFaces = pSettings->value("CullFaces",false).toBool(); s_bSmooth = pSettings->value("Smooth",true).toBool(); s_bShade = pSettings->value("Shade",true).toBool(); s_bLocalView = pSettings->value("LocalView",true).toBool(); s_bDepthTest = pSettings->value("DepthTest",true).toBool(); s_bColorMaterial = pSettings->value("ColorMaterial",true).toBool(); s_bLight = pSettings->value("bLight", true).toBool(); } pSettings->endGroup(); return true; } void GLLightDlg::SetDefaults(double size) { s_Red = 1.0f; s_Green = 1.0f; s_Blue = 1.0f; s_Diffuse = 0.83f; s_Ambient = 0.18f; s_Specular = 0.05f; s_MatAmbient = -0.51f; s_MatDiffuse = -0.43f; s_MatSpecular = -0.08f; s_MatEmission = -0.06f; s_iMatShininess = 0; s_XLight = 0.56f * m_Size;//.2 s_YLight = 0.02f * m_Size;//1.2 s_ZLight = 5.0f * m_Size;//20 s_bLight = true; s_bCullFaces = false; s_bShade = true; s_bSmooth = true; s_bLocalView = true; s_bDepthTest = true; s_bColorMaterial = true; } bool GLLightDlg::SaveSettings(QSettings *pSettings) { pSettings->beginGroup("GLLight"); { pSettings->setValue("Ambient",s_Ambient); pSettings->setValue("Diffuse",s_Diffuse); pSettings->setValue("Specular",s_Specular); pSettings->setValue("MatAmbient",s_MatAmbient); pSettings->setValue("MatDiffuse",s_MatDiffuse); pSettings->setValue("MatSpecular",s_MatSpecular ); pSettings->setValue("MatEmission",s_MatEmission); pSettings->setValue("MatShininess",s_iMatShininess); pSettings->setValue("XLight",s_XLight); pSettings->setValue("YLight",s_YLight); pSettings->setValue("ZLight",s_ZLight); pSettings->setValue("RedLight",s_Red); pSettings->setValue("GreenLight",s_Green); pSettings->setValue("BlueLight",s_Blue); pSettings->setValue("CullFaces",s_bCullFaces); pSettings->setValue("Smooth",s_bSmooth); pSettings->setValue("Shade",s_bShade); pSettings->setValue("LocalView",s_bLocalView); pSettings->setValue("DepthTest",s_bDepthTest); pSettings->setValue("ColorMaterial",s_bColorMaterial); pSettings->setValue("bLight", s_bLight); } pSettings->endGroup(); return true; } void GLLightDlg::showEvent(QShowEvent *event) { SetParams(); SetEnabled(); Apply(); } void GLLightDlg::OnLight() { s_bLight = m_pctrlLight->isChecked(); SetEnabled(); Apply(); } void GLLightDlg::SetEnabled() { m_pctrlRed->setEnabled(s_bLight); m_pctrlGreen->setEnabled(s_bLight); m_pctrlBlue->setEnabled(s_bLight); m_pctrlAmbient->setEnabled(s_bLight); m_pctrlDiffuse->setEnabled(s_bLight); m_pctrlSpecular->setEnabled(s_bLight); m_pctrlMatAmbient->setEnabled(s_bLight); m_pctrlMatSpecular->setEnabled(s_bLight); m_pctrlMatDiffuse->setEnabled(s_bLight); m_pctrlMatEmission->setEnabled(s_bLight); m_pctrlMatShininess->setEnabled(s_bLight); m_pctrlCullFaces->setEnabled(s_bLight); m_pctrlColorMaterial->setEnabled(s_bLight); m_pctrlSmooth->setEnabled(s_bLight); m_pctrlShade->setEnabled(s_bLight); m_pctrlLocalView->setEnabled(s_bLight); m_pctrlDepthTest->setEnabled(s_bLight); m_pctrlXLight->setEnabled(s_bLight); m_pctrlYLight->setEnabled(s_bLight); m_pctrlZLight->setEnabled(s_bLight); } xflr5-6.09-06/src/misc/DoubleEdit.h000644 001750 000144 00000003567 12247174404 020221 0ustar00techwinderusers000000 000000 /**************************************************************************** DoubleEdit Class Copyright (C) 2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef DOUBLEEDIT_H #define DOUBLEEDIT_H #include #include #include class DoubleEdit : public QLineEdit { public: DoubleEdit(QWidget *pParent=NULL); DoubleEdit(double val, int decimals=2); ~DoubleEdit() {delete m_pDV;} void focusOutEvent ( QFocusEvent * event ); void keyPressEvent(QKeyEvent *event); double Value(){return m_Value;} void SetValue(double val); void SetValueNoFormat(double val); void FormatValue(); double ReadValue(); void SetMin(double min) {m_pDV->setBottom(min);} void SetMax(double max) {m_pDV->setTop(max);} void SetPrecision(int decimals) {m_pDV->setDecimals(decimals);} void setNotation(QDoubleValidator::Notation notation) {m_pDV->setNotation(notation);} int precision(){return m_pDV->decimals();} public: QDoubleValidator *m_pDV; double m_Value;//we need to store a full precision value, irrespective of the display }; #endif // DOUBLEEDIT_H xflr5-6.09-06/src/misc/RenameDlg.h000644 001750 000144 00000003766 12247174404 020040 0ustar00techwinderusers000000 000000 /**************************************************************************** RenameDlg Classes Copyright (C) 2003-2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef RENAMEDLG_H #define RENAMEDLG_H #include #include #include #include #include #include #include #include class RenameDlg : public QDialog { Q_OBJECT friend class MainFrame; friend class QXDirect; friend class QAFoil; friend class QMiarex; friend class StabViewDlg; private: void InitDialog(); private slots: void OnOverwrite(); void OnOK(); void OnSelChangeList(int iItem); void OnDoubleClickList(QListWidgetItem * pItem); public: RenameDlg(QWidget *pParent=NULL); void keyPressEvent(QKeyEvent *event); void SetupLayout(); QLabel *m_pctrlMessage; QLineEdit *m_pctrlName; QListWidget *m_pctrlNameList; QPushButton *OverwriteButton; QPushButton *OKButton; QPushButton *CancelButton; QLabel *m_pctrlNote; QStringList *m_pstrArray; QString m_StartName; QString m_strName; QString m_strQuestion; QString m_Note; bool m_bEnableOverwrite; bool m_bExists; }; #endif // RENAMEDLG_H xflr5-6.09-06/src/misc/IntEdit.h000644 001750 000144 00000003130 12247261610 017517 0ustar00techwinderusers000000 000000 /**************************************************************************** IntEdit Class Copyright (C) 2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef INTEDIT_H #define INTEDIT_H #include #include #include class IntEdit : public QLineEdit { public: IntEdit(QWidget *pParent=NULL); IntEdit(int val, QWidget *pParent=NULL); ~IntEdit() {delete m_pDV;} void focusOutEvent ( QFocusEvent * event ); void keyPressEvent(QKeyEvent *event); int Value(){return m_Value;} void SetValue(int val); void SetValueNoFormat(int val); void FormatValue(); int ReadValue(); void SetMin(int min) {m_pDV->setBottom(min);} void SetMax(int max) {m_pDV->setTop(max);} public: QIntValidator *m_pDV; int m_Value;//we need to store a full precision value, irrespective of the display }; #endif // IntEdit_H xflr5-6.09-06/src/misc/SaveOptionsDlg.cpp000644 001750 000144 00000004660 12247174404 021430 0ustar00techwinderusers000000 000000 /**************************************************************************** SaveOptionsDlg Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "SaveOptionsDlg.h" #include #include #include #include SaveOptionsDlg::SaveOptionsDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Save Options")); m_bOpps = false; m_bWOpps = true; SetupLayout(); } void SaveOptionsDlg::SetupLayout() { QLabel *label = new QLabel(tr("Save:")); m_pctrlOpps = new QCheckBox(tr("Foil Operating Points")); m_pctrlWOpps = new QCheckBox(tr("Wing and Plane Operating Points")); QHBoxLayout *CommandButtons = new QHBoxLayout; QPushButton *OKButton = new QPushButton(tr("OK")); OKButton->setAutoDefault(false); QPushButton *CancelButton = new QPushButton(tr("Cancel")); CancelButton->setAutoDefault(false); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addWidget(label); MainLayout->addWidget(m_pctrlOpps); MainLayout->addWidget(m_pctrlWOpps); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); setLayout(MainLayout); } void SaveOptionsDlg::InitDialog(bool bOpps, bool bWOpps) { m_bOpps = bOpps; m_bWOpps = bWOpps; m_pctrlOpps->setChecked(m_bOpps); m_pctrlWOpps->setChecked(m_bWOpps); } void SaveOptionsDlg::OnOK() { m_bOpps = m_pctrlOpps->isChecked(); m_bWOpps = m_pctrlWOpps->isChecked(); accept(); } xflr5-6.09-06/src/misc/PolarFilterDlg.h000644 001750 000144 00000003207 12247174404 021042 0ustar00techwinderusers000000 000000 /**************************************************************************** PolarFilterDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef POLARFILTERDLG_H #define POLARFILTERDLG_H #include #include #include #include class PolarFilterDlg : public QDialog { Q_OBJECT friend class QMiarex; friend class QXDirect; public: PolarFilterDlg(QWidget *pParent=NULL); void InitDialog(); private slots: void OnOK(); private: void keyPressEvent(QKeyEvent *event); void SetupLayout(); QPushButton *OKButton; QCheckBox *m_pctrlType1, *m_pctrlType2, *m_pctrlType3, *m_pctrlType4, *m_pctrlType5, *m_pctrlType6, *m_pctrlType7; bool m_bType1, m_bType2, m_bType3, m_bType4, m_bType5, m_bType6, m_bType7; bool m_bMiarex; }; #endif // POLARFILTERDLG_H xflr5-6.09-06/src/misc/TranslatorDlg.h000644 001750 000144 00000002652 12247174404 020753 0ustar00techwinderusers000000 000000 /**************************************************************************** TranslatorDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef TRANSLATORDLG_H #define TRANSLATORDLG_H #include #include #include #include class TranslatorDlg : public QDialog { Q_OBJECT friend class MainFrame; public: TranslatorDlg(QWidget *pParent); private slots: void OnOK(); private: void SetupLayout(); void InitDialog(); QStringList findQmFiles(); QString languageName(const QString &qmFile); QListWidget *m_pctrlLanguageList; QMap qmFileForLanguage; }; #endif // TRANSLATORDLG_H xflr5-6.09-06/src/misc/FloatEditDelegate.cpp000644 001750 000144 00000006522 12247174404 022034 0ustar00techwinderusers000000 000000 /**************************************************************************** FloatEditDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "FloatEditDelegate.h" FloatEditDelegate::FloatEditDelegate(QObject *parent) : QItemDelegate(parent) { } QWidget *FloatEditDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex & index ) const { if(m_Precision[index.column()]>=0) { //we have a number DoubleEdit *editor = new DoubleEdit(parent); editor->SetPrecision(m_Precision[index.column()]); double value = index.model()->data(index, Qt::EditRole).toDouble(); editor->SetValue(value); return editor; } else { //we have a string QLineEdit *editor = new QLineEdit(parent); editor->setAlignment(Qt::AlignLeft); return editor; } } void FloatEditDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if(m_Precision[index.column()]>=0) { double value = index.model()->data(index, Qt::EditRole).toDouble(); DoubleEdit *pDE = static_cast(editor); pDE->SetValueNoFormat(value); } else { QLineEdit *pLine = static_cast(editor); pLine->setText(index.model()->data(index, Qt::EditRole).toString()); } } void FloatEditDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { if(m_Precision[index.column()]>=0) { DoubleEdit *pDE = static_cast(editor); double value = pDE->Value(); model->setData(index, value, Qt::EditRole); } else { QLineEdit *pLine = static_cast(editor); model->setData(index, pLine->text(), Qt::EditRole); } } void FloatEditDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { editor->setGeometry(option.rect); } void FloatEditDelegate::SetPrecision(int *PrecisionTable) { m_Precision = PrecisionTable; } void FloatEditDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QString strong; QStyleOptionViewItem myOption = option; if(m_Precision[index.column()]>=0) { myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; strong = QString("%1").arg(index.model()->data(index, Qt::DisplayRole).toDouble(),0,'f', m_Precision[index.column()]); } else { myOption.displayAlignment = Qt::AlignLeft | Qt::AlignVCenter; strong = index.model()->data(index, Qt::DisplayRole).toString(); } drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } xflr5-6.09-06/src/misc/TranslatorDlg.cpp000644 001750 000144 00000010303 12250563015 021270 0ustar00techwinderusers000000 000000 /**************************************************************************** TranslatorDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "TranslatorDlg.h" #include "../mainframe.h" #include #include #include #include #include #include #include #include #include TranslatorDlg::TranslatorDlg(QWidget *pParent): QDialog(pParent) { setWindowTitle(tr("Language settings")); QString LanguageName = tr("English");// will be translated in the ts & qm files and this will be used to fill the QListWidget SetupLayout(); } void TranslatorDlg::OnOK() { //read user language selection and exit QListWidgetItem *pItem = m_pctrlLanguageList->currentItem(); if(pItem) { if(pItem->text()=="English") MainFrame::s_LanguageFilePath = ""; else MainFrame::s_LanguageFilePath = qmFileForLanguage[pItem->text()]; } else { MainFrame::s_LanguageFilePath = ""; } QMessageBox::warning(this, tr("Warning"), tr("The change will take effect at the next session")); accept(); } void TranslatorDlg::SetupLayout() { QLabel *lab = new QLabel(tr("Select the application's default language:")); m_pctrlLanguageList = new QListWidget; m_pctrlLanguageList->setMinimumHeight(300); connect(m_pctrlLanguageList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(OnOK())); QHBoxLayout *CommandButtons = new QHBoxLayout; { QPushButton *OKButton = new QPushButton(tr("OK")); QPushButton *CancelButton = new QPushButton(tr("Cancel")); OKButton->setAutoDefault(true); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()),this, SLOT(reject())); } QVBoxLayout *MainLayout = new QVBoxLayout; { MainLayout->addWidget(lab); MainLayout->addStretch(1); MainLayout->addWidget(m_pctrlLanguageList); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); } setLayout(MainLayout); } void TranslatorDlg::InitDialog() { QStringList qmFiles = findQmFiles(); qmFiles.sort(); qmFileForLanguage.insert("English", "English"); m_pctrlLanguageList->clear(); m_pctrlLanguageList->addItem("English (default)"); for (int i=0; iaddItem(languageName(qmFiles[i])); } m_pctrlLanguageList->setCurrentRow(0); for (int i=0; isetCurrentRow(i+1); break; } } } QStringList TranslatorDlg::findQmFiles() { if(!MainFrame::s_TranslationDir.exists()) { QMessageBox::warning(this, tr("Warning"), tr("The directory ")+MainFrame::s_TranslationDir.path()+tr(" does not exist")); } QStringList fileNames = MainFrame::s_TranslationDir.entryList(QStringList("*.qm"), QDir::Files, QDir::Name); QMutableStringListIterator i(fileNames); while (i.hasNext()) { i.next(); i.setValue(MainFrame::s_TranslationDir.filePath(i.value())); } return fileNames; } QString TranslatorDlg::languageName(const QString &qmFile) { QTranslator translator; translator.load(qmFile); return translator.translate("TranslatorDlg", "English"); } xflr5-6.09-06/src/misc/NewNameDlg.cpp000644 001750 000144 00000004511 12247174404 020503 0ustar00techwinderusers000000 000000 /**************************************************************************** NewNameDlg Classes Copyright (C) 2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "NewNameDlg.h" #include #include NewNameDlg::NewNameDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle("Curve Name Dialog"); SetupLayout(); } void NewNameDlg::InitDialog() { m_pctrlName->setText(m_OldName); m_pctrlName->selectAll(); } void NewNameDlg::SetupLayout() { QVBoxLayout *MainLayout = new QVBoxLayout; m_pctrlName = new QLineEdit(this); QHBoxLayout *CommandButtons = new QHBoxLayout; OKButton = new QPushButton(tr("OK")); OKButton->setAutoDefault(false); QPushButton *CancelButton = new QPushButton(tr("Cancel")); CancelButton->setAutoDefault(false); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); MainLayout->addStretch(1); MainLayout->addWidget(m_pctrlName); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); setLayout(MainLayout); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void NewNameDlg::OnOK() { m_NewName = m_pctrlName->text(); accept(); } void NewNameDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus()) OKButton->setFocus(); else OnOK(); break; } case Qt::Key_Escape: { reject(); break; } default: event->ignore(); } } xflr5-6.09-06/src/misc/ColorButton.cpp000644 001750 000144 00000004502 12247423470 020774 0ustar00techwinderusers000000 000000 /**************************************************************************** ColorButton Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../mainframe.h" #include "ColorButton.h" #include #include ColorButton::ColorButton(QWidget *pParent) : QAbstractButton(pParent) { m_Color = Qt::darkGray; QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::Minimum); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Minimum); setSizePolicy(szPolicyExpanding); } QSize ColorButton::sizeHint() const { QFontMetrics fm(MainFrame::s_TextFont); int w = 5 * fm.averageCharWidth(); int h = fm.height()*3/2; return QSize(w, h); } void ColorButton::SetColor(QColor const & color) { m_Color = color; update(); } QColor &ColorButton::GetColor() { return m_Color; } void ColorButton::paintEvent ( QPaintEvent * event ) { QColor paintcolor; if(isEnabled()) paintcolor = m_Color; else { if(isDown()) paintcolor = m_Color.lighter(150); else paintcolor = Qt::lightGray; } QStyleOption opt; opt.init(this); QPainter painter(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); painter.setBackgroundMode(Qt::TransparentMode); QRect r = rect(); QPen blackPen(Qt::black, 1, Qt::SolidLine); QBrush colorbrush(paintcolor); painter.setBrush(colorbrush); // r.adjust(3,3,-3,-3); painter.setPen(blackPen); painter.drawRoundedRect(r, 5, 25, Qt::RelativeSize); } xflr5-6.09-06/src/misc/DoubleEdit.cpp000644 001750 000144 00000005151 12247406023 020536 0ustar00techwinderusers000000 000000 /**************************************************************************** DoubleEdit Class Copyright (C) 2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "DoubleEdit.h" DoubleEdit::DoubleEdit(QWidget *pParent) { setParent(pParent); m_Value = 0.0; m_pDV = new QDoubleValidator(this); // m_pDV->setNotation(QDoubleValidator::StandardNotation); m_pDV->setRange(-1.e10, 1.e10); m_pDV->setDecimals(2); setValidator(m_pDV); setAlignment(Qt::AlignRight); setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)); } DoubleEdit::DoubleEdit(double val, int decimals) { m_Value = val; m_pDV = new QDoubleValidator(this); // m_pDV->setNotation(QDoubleValidator::StandardNotation); m_pDV->setRange(-1.e10, 1.e10); m_pDV->setDecimals(decimals); setValidator(m_pDV); setAlignment(Qt::AlignRight); setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)); } void DoubleEdit::focusOutEvent (QFocusEvent *event) { ReadValue(); FormatValue(); emit(editingFinished()); QLineEdit::focusOutEvent(event); } double DoubleEdit::ReadValue() { bool bOK; double f = locale().toDouble(text().trimmed(), &bOK); if(bOK) m_Value = f; return m_Value; // DoubleEdit orig // if(bOK) return f; // else return m_Value; } void DoubleEdit::SetValue(double val) { m_Value = val; FormatValue(); } void DoubleEdit::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Return: { ReadValue(); FormatValue(); QLineEdit::keyPressEvent(event); break; } case Qt::Key_Escape: { FormatValue(); QLineEdit::keyPressEvent(event); break; } default: { QLineEdit::keyPressEvent(event); ReadValue(); break; } } } void DoubleEdit::FormatValue() { setText(QString("%L1").arg(m_Value,0,'f', m_pDV->decimals())); } void DoubleEdit::SetValueNoFormat(double val) { m_Value = val; } xflr5-6.09-06/src/misc/ObjectPropsDlg.cpp000644 001750 000144 00000005546 12247174404 021414 0ustar00techwinderusers000000 000000 /**************************************************************************** ObjectPropsDlg Class Copyright (C) 2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "ObjectPropsDlg.h" #include #include #include #include #include "../globals.h" ObjectPropsDlg::ObjectPropsDlg(QWidget *pParent) : QDialog(pParent) { m_pMiarex = NULL; m_pXDirect = NULL; m_pPolar = NULL; m_pWPolar = NULL; m_pWOpp = NULL; m_pOpp = NULL; SetupLayout(); } void ObjectPropsDlg::SetupLayout() { setMinimumHeight(400); setMinimumWidth(700); m_pctrlDescription = new QTextEdit; m_pctrlDescription->setFontFamily("Courier"); m_pctrlDescription->setReadOnly(true); m_pctrlDescription->setLineWrapMode(QTextEdit::NoWrap); m_pctrlDescription->setWordWrapMode(QTextOption::NoWrap); // QVBoxLayout *PropertiesLayout = new QVBoxLayout; // PropertiesLayout->addWidget(lab); // PropertiesLayout->addWidget(m_pctrlDescription); QPushButton *OKButton = new QPushButton(tr("OK")); QHBoxLayout *CommandButtons = new QHBoxLayout; CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); QVBoxLayout * MainLayout = new QVBoxLayout(this); MainLayout->addWidget(m_pctrlDescription); // MainLayout->addStretch(1); MainLayout->addSpacing(20); MainLayout->addLayout(CommandButtons); // MainLayout->addStretch(1); setLayout(MainLayout); } void ObjectPropsDlg::InitDialog() { QString strange; if(m_pXDirect) { if(m_pPolar) { m_pPolar->GetPolarProperties(strange, true); setWindowTitle(tr("Polar Properties")); } else if(m_pOpp) { m_pOpp->GetOppProperties(strange, true); setWindowTitle(tr("Operating Point Properties")); } } else if(m_pMiarex) { if(m_pWPolar) { m_pWPolar->GetPolarProperties(strange, true); setWindowTitle(tr("Polar Properties")); } else if(m_pWOpp) { m_pWOpp->GetWingOppProperties(strange); setWindowTitle(tr("Operating Point Properties")); } } m_pctrlDescription->setText(strange); } xflr5-6.09-06/src/misc/ProgressDlg.cpp000644 001750 000144 00000004344 12247174404 020761 0ustar00techwinderusers000000 000000 /**************************************************************************** ProgressDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include "ProgressDlg.h" ProgressDlg::ProgressDlg(QWidget *pParent) : QDialog(pParent) { m_Min = 0; m_Max = 100; m_bCancel = false; SetupLayout(); } void ProgressDlg::SetValue(int value) { // value = qMax(value, m_Min); // value = qMin(value, m_Max); m_pctrlProgress->setValue(value); } void ProgressDlg::InitDialog(int min, int max) { m_Min = min; m_Max = max; m_pctrlProgress->setMinimum(m_Min); m_pctrlProgress->setMaximum(m_Max); m_pctrlProgress->setValue(0); } void ProgressDlg::SetupLayout() { setWindowTitle(tr("Progress")); m_pctrlProgress = new QProgressBar; m_pctrlProgress->setOrientation(Qt::Horizontal); m_pctrlProgress->setMinimum(0); m_pctrlProgress->setMaximum(100); m_pctrlProgress->setValue(0); QHBoxLayout *CancelLayout = new QHBoxLayout; CancelButton = new QPushButton(tr("Cancel")); CancelButton->setDefault(true); connect(CancelButton, SIGNAL(clicked()), this, SLOT(OnCancel())); CancelLayout->addStretch(1); CancelLayout->addWidget(CancelButton); CancelLayout->addStretch(1); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(m_pctrlProgress); mainLayout->addStretch(1); mainLayout->addLayout(CancelLayout); setLayout(mainLayout); } void ProgressDlg::OnCancel() { m_bCancel = true; reject(); } bool ProgressDlg::IsCanceled() { return m_bCancel; } xflr5-6.09-06/src/misc/LineDelegate.cpp000644 001750 000144 00000005075 12247174404 021052 0ustar00techwinderusers000000 000000 /**************************************************************************** LineDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "LineDelegate.h" #include "../globals.h" LineDelegate::LineDelegate(QObject *parent) : QAbstractItemDelegate(parent) { //initialize with something, just in case for (int i=0; i<5; i++) { m_LineWidth[i] = i+1; m_LineStyle[i] = i; } m_LineColor = QColor(0,255,0); m_Size.setHeight(15); m_Size.setWidth(50); } void LineDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (option.state & QStyle::State_Selected) painter->fillRect(option.rect, option.palette.highlight()); painter->save(); QPen LinePen(m_LineColor); LinePen.setStyle(GetStyle(m_LineStyle[index.row()])); LinePen.setWidth(m_LineWidth[index.row()]); painter->setPen(LinePen); // if (option.state & QStyle::State_Selected) painter->setBrush(option.palette.highlightedText()); // else painter->setBrush(QBrush(Qt::black)); painter->drawLine(option.rect.x()+3, option.rect.y() + option.rect.height()/2, option.rect.width()-6, option.rect.y() + option.rect.height()/2); painter->restore(); } QSize LineDelegate::sizeHint(const QStyleOptionViewItem & /* option */, const QModelIndex & /* index */) const { return m_Size; } void LineDelegate::SetLineColor(QColor color) { m_LineColor = color; } void LineDelegate::SetLineStyle(int *style) { for (int i=0; i<5; i++) m_LineStyle[i] = style[i]; } void LineDelegate::SetLineWidth(int *width) { for (int i=0; i<5; i++) m_LineWidth[i] = width[i]; } void LineDelegate::SetSize(QSize size) { m_Size = size; } xflr5-6.09-06/src/misc/W3dPrefsDlg.cpp000644 001750 000144 00000053615 12247174404 020617 0ustar00techwinderusers000000 000000 /**************************************************************************** W3dPrefsDlg Class Copyright (C) 2009-2013 Andre Deperrois XFLR5@yahoo.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include #include "../params.h" #include "W3dPrefsDlg.h" #include "../misc/LinePickerDlg.h" bool W3dPrefsDlg::s_bWakePanels = false; double W3dPrefsDlg::s_MassRadius = .01; QColor W3dPrefsDlg::s_MassColor = QColor(130, 170, 130); int W3dPrefsDlg::s_VLMStyle = 0; int W3dPrefsDlg::s_VLMWidth = 1; QColor W3dPrefsDlg::s_VLMColor = QColor(180,180,180); int W3dPrefsDlg::s_3DAxisStyle = 3; int W3dPrefsDlg::s_3DAxisWidth = 1; QColor W3dPrefsDlg::s_3DAxisColor = QColor(150,150,150); int W3dPrefsDlg::s_OutlineStyle = 0; int W3dPrefsDlg::s_OutlineWidth = 1; QColor W3dPrefsDlg::s_OutlineColor = QColor(255,255,255); int W3dPrefsDlg::s_XCPStyle = 0; int W3dPrefsDlg::s_XCPWidth = 1; QColor W3dPrefsDlg::s_XCPColor = QColor(50, 150, 50); int W3dPrefsDlg::s_MomentStyle = 0; int W3dPrefsDlg::s_MomentWidth = 1; QColor W3dPrefsDlg::s_MomentColor = QColor(200, 100, 100); int W3dPrefsDlg::s_IDragStyle = 0; int W3dPrefsDlg::s_IDragWidth = 1; QColor W3dPrefsDlg::s_IDragColor = QColor(255,200,0); int W3dPrefsDlg::s_DownwashStyle = 0; int W3dPrefsDlg::s_DownwashWidth = 1; QColor W3dPrefsDlg::s_DownwashColor = QColor(255, 100, 100); int W3dPrefsDlg::s_WakeStyle = 0; int W3dPrefsDlg::s_WakeWidth = 1; QColor W3dPrefsDlg::s_WakeColor = QColor(0, 150, 200); int W3dPrefsDlg::s_CpStyle = 0; int W3dPrefsDlg::s_CpWidth = 1; QColor W3dPrefsDlg::s_CpColor = QColor(255,0,0); int W3dPrefsDlg::s_StreamLinesStyle = 0; int W3dPrefsDlg::s_StreamLinesWidth = 1; QColor W3dPrefsDlg::s_StreamLinesColor = QColor(200, 150, 255); int W3dPrefsDlg::s_VDragStyle = 0; int W3dPrefsDlg::s_VDragWidth = 1; QColor W3dPrefsDlg::s_VDragColor = QColor(200,100,220); int W3dPrefsDlg::s_TopStyle = 0; int W3dPrefsDlg::s_TopWidth = 1; QColor W3dPrefsDlg::s_TopColor = QColor(150, 240, 50); int W3dPrefsDlg::s_BotStyle = 1; int W3dPrefsDlg::s_BotWidth = 1; QColor W3dPrefsDlg::s_BotColor = QColor(150, 240, 50); W3dPrefsDlg::W3dPrefsDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("3D Styles")); // s_pSail7 = NULL; SetupLayout(); connect(m_pctrlAxis, SIGNAL(clickedLB()), SLOT(On3DAxis())); connect(m_pctrlOutline, SIGNAL(clickedLB()), SLOT(OnOutline())); connect(m_pctrlVLMMesh, SIGNAL(clickedLB()), SLOT(OnVLMMesh())); connect(m_pctrlTopTrans, SIGNAL(clickedLB()), SLOT(OnTopTrans())); connect(m_pctrlBotTrans, SIGNAL(clickedLB()), SLOT(OnBotTrans())); connect(m_pctrlLift, SIGNAL(clickedLB()), SLOT(OnXCP())); connect(m_pctrlMoments, SIGNAL(clickedLB()), SLOT(OnMoments())); connect(m_pctrlInducedDrag, SIGNAL(clickedLB()), SLOT(OnIDrag())); connect(m_pctrlViscousDrag, SIGNAL(clickedLB()), SLOT(OnVDrag())); connect(m_pctrlDownwash, SIGNAL(clickedLB()), SLOT(OnDownwash())); connect(m_pctrlStreamLines, SIGNAL(clickedLB()), SLOT(OnStreamLines())); connect(m_pctrlWakePanels, SIGNAL(clickedLB()), SLOT(OnWakePanels())); connect(m_pctrlShowWake, SIGNAL(clicked()), SLOT(OnShowWake())); connect(m_pctrlMassColor, SIGNAL(clicked()), SLOT(OnMasses())); } void W3dPrefsDlg::InitDialog() { m_pctrlAxis->SetStyle(s_3DAxisStyle,s_3DAxisWidth, s_3DAxisColor); m_pctrlOutline->SetStyle(s_OutlineStyle, s_OutlineWidth, s_OutlineColor); m_pctrlVLMMesh->SetStyle(s_VLMStyle, s_VLMWidth, s_VLMColor); m_pctrlLift->SetStyle(s_XCPStyle, s_XCPWidth, s_XCPColor); m_pctrlMoments->SetStyle(s_MomentStyle, s_MomentWidth, s_MomentColor); m_pctrlInducedDrag->SetStyle(s_IDragStyle, s_IDragWidth, s_IDragColor); m_pctrlViscousDrag->SetStyle(s_VDragStyle, s_VDragWidth, s_VDragColor); m_pctrlDownwash->SetStyle(s_DownwashStyle, s_DownwashWidth, s_DownwashColor); m_pctrlWakePanels->SetStyle(s_WakeStyle, s_WakeWidth, s_WakeColor); m_pctrlStreamLines->SetStyle(s_StreamLinesStyle, s_StreamLinesWidth, s_StreamLinesColor); m_pctrlTopTrans->SetStyle(s_TopStyle, s_TopWidth, s_TopColor); m_pctrlBotTrans->SetStyle(s_BotStyle, s_BotWidth, s_BotColor); m_pctrlShowWake->setChecked(s_bWakePanels); m_pctrlMassColor->SetColor(s_MassColor); } void W3dPrefsDlg::SetupLayout() { QLabel *lab1 = new QLabel(tr("Axis")); QLabel *lab2 = new QLabel(tr("Outline")); QLabel *lab3 = new QLabel(tr("VLM Mesh")); QLabel *lab4 = new QLabel(tr("Top transition")); QLabel *lab5 = new QLabel(tr("Bottom transition")); QLabel *lab6 = new QLabel(tr("Lift")); QLabel *lab7 = new QLabel(tr("Moments")); QLabel *lab8 = new QLabel(tr("Induced Drag")); QLabel *lab9 = new QLabel(tr("Viscous Drag")); QLabel *lab10 = new QLabel(tr("Downwash")); QLabel *lab11 = new QLabel(tr("WakePanels")); QLabel *lab12 = new QLabel(tr("Streamlines")); QLabel *lab13 = new QLabel(tr("Masses")); lab1->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab2->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab3->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab4->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab5->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab6->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab7->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab8->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab9->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab10->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab11->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab12->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab13->setAlignment(Qt::AlignVCenter|Qt::AlignRight); m_pctrlAxis = new LineBtn(this); m_pctrlOutline = new LineBtn(this); m_pctrlVLMMesh = new LineBtn(this); m_pctrlTopTrans = new LineBtn(this); m_pctrlBotTrans = new LineBtn(this); m_pctrlLift = new LineBtn(this); m_pctrlMoments = new LineBtn(this); m_pctrlInducedDrag = new LineBtn(this); m_pctrlViscousDrag = new LineBtn(this); m_pctrlDownwash = new LineBtn(this); m_pctrlWakePanels = new LineBtn(this); m_pctrlStreamLines = new LineBtn(this); m_pctrlMassColor = new ColorButton; m_pctrlShowWake = new QCheckBox(tr("Show Wake Panels")); QGridLayout *PrefsLayout = new QGridLayout; { PrefsLayout->setColumnStretch(1,1); PrefsLayout->setColumnStretch(2,2); PrefsLayout->setColumnStretch(3,1); PrefsLayout->setColumnStretch(4,2); PrefsLayout->addWidget(lab1,1,1); PrefsLayout->addWidget(lab2,2,1); PrefsLayout->addWidget(lab3,3,1); PrefsLayout->addWidget(lab4,4,1); PrefsLayout->addWidget(lab5,5,1); PrefsLayout->addWidget(lab6,6,1); PrefsLayout->addWidget(lab7,1,3); PrefsLayout->addWidget(lab8,2,3); PrefsLayout->addWidget(lab9,3,3); PrefsLayout->addWidget(lab10,4,3); PrefsLayout->addWidget(lab11,5,3); PrefsLayout->addWidget(lab12,6,3); PrefsLayout->addWidget(lab13,7,3); PrefsLayout->addWidget(m_pctrlAxis,1,2); PrefsLayout->addWidget(m_pctrlOutline,2,2); PrefsLayout->addWidget(m_pctrlVLMMesh,3,2); PrefsLayout->addWidget(m_pctrlTopTrans,4,2); PrefsLayout->addWidget(m_pctrlBotTrans,5,2); PrefsLayout->addWidget(m_pctrlLift,6,2); PrefsLayout->addWidget(m_pctrlShowWake,7,1,1,2); PrefsLayout->addWidget(m_pctrlMoments,1,4); PrefsLayout->addWidget(m_pctrlInducedDrag,2,4); PrefsLayout->addWidget(m_pctrlViscousDrag,3,4); PrefsLayout->addWidget(m_pctrlDownwash,4,4); PrefsLayout->addWidget(m_pctrlWakePanels,5,4); PrefsLayout->addWidget(m_pctrlStreamLines,6,4); PrefsLayout->addWidget(m_pctrlMassColor,7,4); } QHBoxLayout *CommandButtons = new QHBoxLayout; { QPushButton *OKButton = new QPushButton(tr("Close")); QPushButton *ResetButton = new QPushButton(tr("Reset Defaults")); CommandButtons->addStretch(1); CommandButtons->addWidget(ResetButton); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); connect(ResetButton, SIGNAL(clicked()),this, SLOT(OnResetDefaults())); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); } QVBoxLayout *MainLayout = new QVBoxLayout; { MainLayout->addStretch(1); MainLayout->addLayout(PrefsLayout); MainLayout->addStretch(1); MainLayout->addSpacing(20); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); } setLayout(MainLayout); } void W3dPrefsDlg::OnOutline() { LinePickerDlg LPdlg(this); LPdlg.SetColor(s_OutlineColor); LPdlg.SetStyle(s_OutlineStyle); LPdlg.SetWidth(s_OutlineWidth); LPdlg.InitDialog(); if (QDialog::Accepted == LPdlg.exec()) { s_OutlineColor = LPdlg.GetColor(); s_OutlineStyle = LPdlg.GetStyle(); s_OutlineWidth = LPdlg.GetWidth(); m_pctrlOutline->SetStyle(s_OutlineStyle, s_OutlineWidth, s_OutlineColor); } } void W3dPrefsDlg::On3DAxis() { LinePickerDlg LPdlg(this); LPdlg.SetColor(s_3DAxisColor); LPdlg.SetStyle(s_3DAxisStyle); LPdlg.SetWidth(s_3DAxisWidth); LPdlg.InitDialog(); if (QDialog::Accepted == LPdlg.exec()) { s_3DAxisColor = LPdlg.GetColor(); s_3DAxisStyle = LPdlg.GetStyle(); s_3DAxisWidth = LPdlg.GetWidth(); m_pctrlAxis->SetStyle(s_3DAxisStyle, s_3DAxisWidth, s_3DAxisColor); } } void W3dPrefsDlg::OnTopTrans() { LinePickerDlg LPdlg(this); LPdlg.SetColor(s_TopColor); LPdlg.SetStyle(s_TopStyle); LPdlg.SetWidth(s_TopWidth); LPdlg.InitDialog(); if (QDialog::Accepted == LPdlg.exec()) { s_TopColor = LPdlg.GetColor(); s_TopStyle = LPdlg.GetStyle(); s_TopWidth = LPdlg.GetWidth(); m_pctrlTopTrans->SetStyle(s_TopStyle, s_TopWidth, s_TopColor); } } void W3dPrefsDlg::OnBotTrans() { LinePickerDlg LPdlg(this); LPdlg.SetColor(s_BotColor); LPdlg.SetStyle(s_BotStyle); LPdlg.SetWidth(s_BotWidth); LPdlg.InitDialog(); if (QDialog::Accepted == LPdlg.exec()) { s_BotColor = LPdlg.GetColor(); s_BotStyle = LPdlg.GetStyle(); s_BotWidth = LPdlg.GetWidth(); m_pctrlBotTrans->SetStyle(s_BotStyle, s_BotWidth, s_BotColor); } } void W3dPrefsDlg::OnIDrag() { LinePickerDlg LPdlg(this); LPdlg.SetColor(s_IDragColor); LPdlg.SetStyle(s_IDragStyle); LPdlg.SetWidth(s_IDragWidth); LPdlg.InitDialog(); if (QDialog::Accepted == LPdlg.exec()) { s_IDragColor = LPdlg.GetColor(); s_IDragStyle = LPdlg.GetStyle(); s_IDragWidth = LPdlg.GetWidth(); m_pctrlInducedDrag->SetStyle(s_IDragStyle, s_IDragWidth, s_IDragColor); } } void W3dPrefsDlg::OnVDrag() { LinePickerDlg LPdlg(this); LPdlg.SetColor(s_VDragColor); LPdlg.SetStyle(s_VDragStyle); LPdlg.SetWidth(s_VDragWidth); LPdlg.InitDialog(); if (QDialog::Accepted == LPdlg.exec()) { s_VDragColor = LPdlg.GetColor(); s_VDragStyle = LPdlg.GetStyle(); s_VDragWidth = LPdlg.GetWidth(); m_pctrlViscousDrag->SetStyle(s_VDragStyle, s_VDragWidth, s_VDragColor); } } void W3dPrefsDlg::OnXCP() { LinePickerDlg LPdlg(this); LPdlg.SetColor(s_XCPColor); LPdlg.SetStyle(s_XCPStyle); LPdlg.SetWidth(s_XCPWidth); LPdlg.InitDialog(); if (QDialog::Accepted == LPdlg.exec()) { s_XCPColor = LPdlg.GetColor(); s_XCPStyle = LPdlg.GetStyle(); s_XCPWidth = LPdlg.GetWidth(); m_pctrlLift->SetStyle(s_XCPStyle, s_XCPWidth, s_XCPColor); } } void W3dPrefsDlg::OnMoments() { LinePickerDlg LPdlg(this); LPdlg.SetColor(s_MomentColor); LPdlg.SetStyle(s_MomentStyle); LPdlg.SetWidth(s_MomentWidth); LPdlg.InitDialog(); if (QDialog::Accepted == LPdlg.exec()) { s_MomentColor = LPdlg.GetColor(); s_MomentStyle = LPdlg.GetStyle(); s_MomentWidth = LPdlg.GetWidth(); m_pctrlMoments->SetStyle(s_MomentStyle, s_MomentWidth, s_MomentColor); } } void W3dPrefsDlg::OnDownwash() { LinePickerDlg LPdlg(this); LPdlg.SetColor(s_DownwashColor); LPdlg.SetStyle(s_DownwashStyle); LPdlg.SetWidth(s_DownwashWidth); LPdlg.InitDialog(); if (QDialog::Accepted == LPdlg.exec()) { s_DownwashColor = LPdlg.GetColor(); s_DownwashStyle = LPdlg.GetStyle(); s_DownwashWidth = LPdlg.GetWidth(); m_pctrlDownwash->SetStyle(s_DownwashStyle, s_DownwashWidth,s_DownwashColor); } } void W3dPrefsDlg::OnStreamLines() { LinePickerDlg LPdlg(this); LPdlg.SetColor(s_StreamLinesColor); LPdlg.SetStyle(s_StreamLinesStyle); LPdlg.SetWidth(s_StreamLinesWidth); LPdlg.InitDialog(); if (QDialog::Accepted == LPdlg.exec()) { s_StreamLinesColor = LPdlg.GetColor(); s_StreamLinesStyle = LPdlg.GetStyle(); s_StreamLinesWidth = LPdlg.GetWidth(); m_pctrlStreamLines->SetStyle(s_StreamLinesStyle, s_StreamLinesWidth, s_StreamLinesColor); } } void W3dPrefsDlg::OnWakePanels() { LinePickerDlg LPdlg(this); LPdlg.SetColor(s_WakeColor); LPdlg.SetStyle(s_WakeStyle); LPdlg.SetWidth(s_WakeWidth); LPdlg.InitDialog(); if (QDialog::Accepted == LPdlg.exec()) { s_WakeColor = LPdlg.GetColor(); s_WakeStyle = LPdlg.GetStyle(); s_WakeWidth = LPdlg.GetWidth(); m_pctrlWakePanels->SetStyle(s_WakeStyle, s_WakeWidth, s_WakeColor); } } void W3dPrefsDlg::OnVLMMesh() { LinePickerDlg LPdlg(this); LPdlg.SetColor(s_VLMColor); LPdlg.SetStyle(s_VLMStyle); LPdlg.SetWidth(s_VLMWidth); LPdlg.InitDialog(); if (QDialog::Accepted == LPdlg.exec()) { s_VLMColor = LPdlg.GetColor(); s_VLMStyle = LPdlg.GetStyle(); s_VLMWidth = LPdlg.GetWidth(); m_pctrlVLMMesh->SetStyle(s_VLMStyle, s_VLMWidth, s_VLMColor); } repaint(); } void W3dPrefsDlg::OnMasses() { QColorDialog::ColorDialogOptions dialogOptions = QColorDialog::ShowAlphaChannel; #ifdef Q_WS_MAC #if QT_VERSION >= 0x040700 dialogOptions |= QColorDialog::DontUseNativeDialog; #endif #endif QColor Color = QColorDialog::getColor(s_MassColor, this, "Select the color", dialogOptions); if(Color.isValid()) s_MassColor = Color; m_pctrlMassColor->SetColor(s_MassColor); update(); } void W3dPrefsDlg::OnShowWake() { s_bWakePanels = m_pctrlShowWake->isChecked(); } void W3dPrefsDlg::SaveSettings(QSettings *pSettings) { pSettings->beginGroup("3DPrefs"); { pSettings->setValue("3DAxisStyle", s_3DAxisStyle ); pSettings->setValue("3DAXisWidth", s_3DAxisWidth ); pSettings->setValue("3DAxisColorRed", s_3DAxisColor.red()); pSettings->setValue("3DAxisColorGreen", s_3DAxisColor.green()); pSettings->setValue("3DAxisColorBlue", s_3DAxisColor.blue()); pSettings->setValue("VLMStyle", s_VLMStyle ); pSettings->setValue("VLMWidth", s_VLMWidth ); pSettings->setValue("VLMColorRed", s_VLMColor.red()); pSettings->setValue("VLMColorGreen", s_VLMColor.green()); pSettings->setValue("VLMColorBlue", s_VLMColor.blue()); pSettings->setValue("OutlineStyle", s_OutlineStyle ); pSettings->setValue("OutlineWidth", s_OutlineWidth ); pSettings->setValue("OutlineColorRed", s_OutlineColor.red()); pSettings->setValue("OutlineColorGreen", s_OutlineColor.green()); pSettings->setValue("OutlineColorBlue", s_OutlineColor.blue()); pSettings->setValue("XCPStyle", s_XCPStyle ); pSettings->setValue("XCPWidth", s_XCPWidth ); pSettings->setValue("XCPColorRed", s_XCPColor.red()); pSettings->setValue("XCPColorGreen", s_XCPColor.green() ); pSettings->setValue("XCPColorBlue", s_XCPColor.blue() ); pSettings->setValue("MomentStyle", s_MomentStyle ); pSettings->setValue("MomentWidth", s_MomentWidth ); pSettings->setValue("MomentColorRed", s_MomentColor.red() ); pSettings->setValue("MomentColorGreen", s_MomentColor.green() ); pSettings->setValue("MomentColorBlue", s_MomentColor.blue() ); pSettings->setValue("IDragStyle", s_IDragStyle ); pSettings->setValue("IDragWidth", s_IDragWidth ); pSettings->setValue("IDragColorRed", s_IDragColor.red() ); pSettings->setValue("IDragColorGreen", s_IDragColor.green() ); pSettings->setValue("IDragColorBlue", s_IDragColor.blue() ); pSettings->setValue("DownwashStyle", s_DownwashStyle ); pSettings->setValue("DownwashWidth", s_DownwashWidth ); pSettings->setValue("DownwashColorRed", s_DownwashColor.red() ); pSettings->setValue("DownwashColorGreen", s_DownwashColor.green() ); pSettings->setValue("DownwashColorBlue", s_DownwashColor.blue() ); pSettings->setValue("WakeStyle", s_WakeStyle ); pSettings->setValue("WakeWidth", s_WakeWidth ); pSettings->setValue("WakeColorRed", s_WakeColor.red() ); pSettings->setValue("WakeColorGreen", s_WakeColor.green() ); pSettings->setValue("WakeColorBlue", s_WakeColor.blue()); pSettings->setValue("CpStyle", s_CpStyle ); pSettings->setValue("CpWidth", s_CpWidth ); pSettings->setValue("CpColorRed", s_CpColor.red() ); pSettings->setValue("CpColorGreen", s_CpColor.green() ); pSettings->setValue("CpColorBlue", s_CpColor.blue() ); pSettings->setValue("StreamLinesStyle", s_StreamLinesStyle); pSettings->setValue("StreamLinesWidth", s_StreamLinesWidth); pSettings->setValue("StreamLinesColor", s_StreamLinesColor); } pSettings->endGroup(); } void W3dPrefsDlg::LoadSettings(QSettings *pSettings) { int r,g,b; pSettings->beginGroup("3DPrefs"); { s_3DAxisStyle = pSettings->value("3DAxisStyle", 3).toInt(); s_3DAxisWidth = pSettings->value("3DAXisWidth",1).toInt(); r = pSettings->value("3DAxisColorRed",255).toInt(); g = pSettings->value("3DAxisColorGreen",255).toInt(); b = pSettings->value("3DAxisColorBlue",255).toInt(); s_3DAxisColor = QColor(r,g,b); s_VLMStyle = pSettings->value("VLMStyle", 0).toInt(); s_VLMWidth = pSettings->value("VLMWidth",1).toInt(); r = pSettings->value("VLMColorRed",220).toInt(); g = pSettings->value("VLMColorGreen",220).toInt(); b = pSettings->value("VLMColorBlue",220).toInt(); s_VLMColor = QColor(r,g,b); s_OutlineStyle = pSettings->value("OutlineStyle",0).toInt(); s_OutlineWidth = pSettings->value("OutlineWidth",1).toInt(); r = pSettings->value("OutlineColorRed",255).toInt(); g = pSettings->value("OutlineColorGreen",255).toInt(); b = pSettings->value("OutlineColorBlue",255).toInt(); s_OutlineColor = QColor(r,g,b); s_XCPStyle = pSettings->value("XCPStyle",0).toInt(); s_XCPWidth = pSettings->value("XCPWidth",2).toInt(); r = pSettings->value("XCPColorRed",0).toInt(); g = pSettings->value("XCPColorGreen",200).toInt(); b = pSettings->value("XCPColorBlue",50).toInt(); s_XCPColor = QColor(r,g,b); s_MomentStyle = pSettings->value("MomentStyle",0).toInt(); s_MomentWidth = pSettings->value("MomentWidth",3).toInt(); r = pSettings->value("MomentColorRed",0).toInt(); g = pSettings->value("MomentColorGreen",100).toInt(); b = pSettings->value("MomentColorBlue",200).toInt(); s_MomentColor = QColor(r,g,b); s_IDragStyle = pSettings->value("IDragStyle",0).toInt(); s_IDragWidth = pSettings->value("IDragWidth",1).toInt(); r = pSettings->value("IDragColorRed",160).toInt(); g = pSettings->value("IDragColorGreen",170).toInt(); b = pSettings->value("IDragColorBlue",20).toInt(); s_IDragColor = QColor(r,g,b); s_DownwashStyle = pSettings->value("DownwashStyle",0).toInt(); s_DownwashWidth = pSettings->value("DownwashWidth",1).toInt(); r = pSettings->value("DownwashColorRed",200).toInt(); g = pSettings->value("DownwashColorGreen",50).toInt(); b = pSettings->value("DownwashColorBlue",50).toInt(); s_DownwashColor = QColor(r,g,b); s_WakeStyle = pSettings->value("WakeStyle",2).toInt(); s_WakeWidth = pSettings->value("WakeWidth",1).toInt(); r = pSettings->value("WakeColorRed",50).toInt(); g = pSettings->value("WakeColorGreen",120).toInt(); b = pSettings->value("WakeColorBlue",190).toInt(); s_WakeColor = QColor(r,g,b); s_CpStyle = pSettings->value("CpStyle",0).toInt(); s_CpWidth = pSettings->value("CpWidth",1).toInt(); r = pSettings->value("CpColorRed",0).toInt(); g = pSettings->value("CpColorGreen",78).toInt(); b = pSettings->value("CpColorBlue",231).toInt(); s_CpColor = QColor(r,g,b); s_StreamLinesStyle = pSettings->value("StreamLinesStyle", 0).toInt(); s_StreamLinesWidth = pSettings->value("StreamLinesWidth", 1).toInt(); s_StreamLinesColor = pSettings->value("StreamLinesColor", QColor(150, 140, 255)).value(); } pSettings->endGroup(); } void W3dPrefsDlg::OnResetDefaults() { s_bWakePanels = false; s_MassColor = QColor(130, 170, 130); s_VLMStyle = 0; s_VLMWidth = 1; s_VLMColor = QColor(180,180,180); s_3DAxisStyle = 3; s_3DAxisWidth = 1; s_3DAxisColor = QColor(150,150,150); s_OutlineStyle = 0; s_OutlineWidth = 1; s_OutlineColor = QColor(255,255,255); s_XCPStyle = 0; s_XCPWidth = 1; s_XCPColor = QColor(50, 150, 50); s_MomentStyle = 0; s_MomentWidth = 1; s_MomentColor = QColor(200, 100, 100); s_IDragStyle = 0; s_IDragWidth = 1; s_IDragColor = QColor(255,200,0); s_DownwashStyle = 0; s_DownwashWidth = 1; s_DownwashColor = QColor(255, 100, 100); s_WakeStyle = 0; s_WakeWidth = 1; s_WakeColor = QColor(0, 150, 200); s_CpStyle = 0; s_CpWidth = 1; s_CpColor = QColor(255,0,0); s_StreamLinesStyle = 0; s_StreamLinesWidth = 1; s_StreamLinesColor = QColor(200, 150, 255); s_VDragStyle = 0; s_VDragWidth = 1; s_VDragColor = QColor(200,100,220); s_TopStyle = 0; s_TopWidth = 1; s_TopColor = QColor(150, 240, 50); s_BotStyle = 1; s_BotWidth = 1; s_BotColor = QColor(150, 240, 50); InitDialog(); } xflr5-6.09-06/src/misc/LinePickerDlg.cpp000644 001750 000144 00000015372 12247174404 021205 0ustar00techwinderusers000000 000000 /**************************************************************************** LinePicker Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include #include "LinePickerDlg.h" #include "../globals.h" #include "../mainframe.h" LinePickerDlg::LinePickerDlg(QWidget *pParent): QDialog(pParent) { setWindowTitle(tr("Line Picker")); m_pParent = pParent; m_Style = 0; m_Width = 1; m_Color = QColor(0,255,0); SetupLayout(); m_pStyleDelegate = new LineDelegate(this);//will intercept painting operations m_pWidthDelegate = new LineDelegate(this);//will intercept painting operations m_pctrlStyle->setItemDelegate(m_pStyleDelegate); m_pctrlWidth->setItemDelegate(m_pWidthDelegate); connect(m_pctrlColor, SIGNAL(clickedLB()), this, SLOT(OnColor())); connect(m_pctrlStyle, SIGNAL(activated(int)), this, SLOT(OnStyle(int))); connect(m_pctrlWidth, SIGNAL(activated(int)), this, SLOT(OnWidth(int))); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void LinePickerDlg::FillBoxes() { m_pctrlStyle->SetLine(m_Style, m_Width, m_Color); m_pctrlWidth->SetLine(m_Style, m_Width, m_Color); m_pctrlColor->SetStyle(m_Style); m_pctrlColor->SetWidth(m_Width); m_pctrlColor->SetColor(m_Color); m_pStyleDelegate->SetLineColor(m_Color); m_pWidthDelegate->SetLineColor(m_Color); m_pctrlStyle->setCurrentIndex(m_Style); m_pctrlWidth->setCurrentIndex(m_Width-1); int LineWidth[5]; for (int i=0; i<5;i++) LineWidth[i] = m_Width; m_pStyleDelegate->SetLineWidth(LineWidth); // the same selected width for all styles int LineStyle[5]; for (int i=0; i<5;i++) LineStyle[i] = m_Style; m_pWidthDelegate->SetLineStyle(LineStyle); //the same selected style for all widths } void LinePickerDlg::InitDialog(int style, int width, QColor color) { m_Color = color; m_Width = width; m_Style = style; QString str; for (int i=0; i<5; i++) { str = QString("%1").arg(i); m_pctrlWidth->addItem(str); } m_pctrlStyle->addItem("solid");//string doesn't matter m_pctrlStyle->addItem("dash"); m_pctrlStyle->addItem("dot"); m_pctrlStyle->addItem("dashdot"); m_pctrlStyle->addItem("dashdotdot"); FillBoxes(); } void LinePickerDlg::InitDialog() { QString str; for (int i=0; i<5; i++) { str = QString("%1").arg(i); m_pctrlWidth->addItem(str); } m_pctrlStyle->addItem("solid");//string doesn't matter m_pctrlStyle->addItem("dash"); m_pctrlStyle->addItem("dot"); m_pctrlStyle->addItem("dashdot"); m_pctrlStyle->addItem("dashdotdot"); FillBoxes(); } void LinePickerDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus()) { OKButton->setFocus(); return; } else { accept(); return; } break; } case Qt::Key_Escape: { reject(); return; } } } void LinePickerDlg::OnWidth(int val) { m_Width = val+1; FillBoxes(); repaint(); OKButton->setFocus(); } void LinePickerDlg::OnStyle(int val) { m_Style = val; FillBoxes(); repaint(); OKButton->setFocus(); } void LinePickerDlg::OnColor() { QColorDialog::ColorDialogOptions dialogOptions = QColorDialog::ShowAlphaChannel; #ifdef Q_WS_MAC #if QT_VERSION >= 0x040700 dialogOptions |= QColorDialog::DontUseNativeDialog; #endif #endif QColor Color = QColorDialog::getColor(m_Color, this, "Color Selection", dialogOptions); if(Color.isValid()) m_Color = Color; FillBoxes(); repaint(); OKButton->setFocus(); } int & LinePickerDlg::GetWidth() { return m_Width; } int & LinePickerDlg::GetStyle() { return m_Style; } QColor & LinePickerDlg::GetColor() { return m_Color; } void LinePickerDlg::SetColor(QColor color) { m_Color = color; FillBoxes(); repaint(); } void LinePickerDlg::SetStyle(int style) { m_Style = style; FillBoxes(); repaint(); } void LinePickerDlg::SetupLayout() { QGridLayout *StyleLayout = new QGridLayout; { QLabel *lab1 = new QLabel(tr("Style")); QLabel *lab2 = new QLabel(tr("Width")); QLabel *lab3 = new QLabel(tr("Color")); lab1->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab2->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab3->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab1->setMinimumWidth(60); lab2->setMinimumWidth(60); lab3->setMinimumWidth(60); m_pctrlColor = new LineBtn; m_pctrlStyle = new LineCbBox; m_pctrlWidth = new LineCbBox; QFontMetrics fm(MainFrame::s_TextFont); m_pctrlStyle->setMinimumWidth(17*fm.averageCharWidth()); m_pctrlWidth->setMinimumWidth(17*fm.averageCharWidth()); m_pctrlColor->setMinimumWidth(17*fm.averageCharWidth()); m_pctrlColor->setMinimumHeight(m_pctrlStyle->minimumSizeHint().height()); StyleLayout->addWidget(lab1,1,1); StyleLayout->addWidget(lab2,2,1); StyleLayout->addWidget(lab3,3,1); StyleLayout->addWidget(m_pctrlStyle,1,2); StyleLayout->addWidget(m_pctrlWidth,2,2); StyleLayout->addWidget(m_pctrlColor,3,2); } QHBoxLayout *CommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); } QVBoxLayout *MainLayout = new QVBoxLayout; { MainLayout->addStretch(1); MainLayout->addLayout(StyleLayout); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); } setMinimumHeight(170); setLayout(MainLayout); } void LinePickerDlg::SetWidth(int width) { m_Width = width; FillBoxes(); repaint(); } xflr5-6.09-06/src/misc/ProgressDlg.h000644 001750 000144 00000002635 12247174404 020427 0ustar00techwinderusers000000 000000 /**************************************************************************** ProgressDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef PROGRESSDLG_H #define PROGRESSDLG_H #include #include #include class ProgressDlg : public QDialog { Q_OBJECT friend class QMiarex; public: ProgressDlg(QWidget *pParent); void InitDialog(int min=0, int max=100); void SetValue(int value); bool IsCanceled(); private slots: void OnCancel(); private: void SetupLayout(); private : QPushButton *CancelButton; QProgressBar* m_pctrlProgress; int m_Min, m_Max; bool m_bCancel; }; #endif // PROGRESSDLG_H xflr5-6.09-06/src/misc/ModDlg.cpp000644 001750 000144 00000004167 12247174404 017677 0ustar00techwinderusers000000 000000 /**************************************************************************** ModDlg class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "ModDlg.h" #include #include ModDlg::ModDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Modification")); m_Question = ""; SetupLayout(); } void ModDlg::InitDialog() { m_pctrlQuestion->setText(m_Question); } void ModDlg::SetupLayout() { m_pctrlQuestion = new QLabel("Question here"); QHBoxLayout *CommandButtons = new QHBoxLayout; QPushButton *OKButton = new QPushButton(tr("OK")); QPushButton *CancelButton = new QPushButton(tr("Cancel")); QPushButton *SaveNewButton = new QPushButton(tr("Save as new")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); CommandButtons->addWidget(SaveNewButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(SaveNewButton, SIGNAL(clicked()), this, SLOT(OnSaveAsNew())); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addWidget(m_pctrlQuestion); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); setLayout(MainLayout); } void ModDlg::OnSaveAsNew() { done(20); } xflr5-6.09-06/src/misc/DisplaySettingsDlg.cpp000644 001750 000144 00000027364 12247174404 022312 0ustar00techwinderusers000000 000000 /**************************************************************************** DisplaySettingsDlg Class Copyright (C) 2008-2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "DisplaySettingsDlg.h" #include "../mainframe.h" #include "../miarex/Miarex.h" #include "../xdirect/XDirect.h" #include "../xinverse/XInverse.h" #include "../graph/GraphDlg.h" #include #include #include #include #include #include bool DisplaySettingsDlg::s_bStyleSheets = true; QString DisplaySettingsDlg::s_StyleName; QString DisplaySettingsDlg::s_StyleSheetName; DisplaySettingsDlg::DisplaySettingsDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("General Display Settings")); m_pMainFrame = pParent; m_bIsGraphModified = false; m_bReverseZoom = false; m_bAlphaChannel = true; #ifdef Q_WS_MAC m_StyleSheetDir.setPath(qApp->applicationDirPath()); #endif #ifdef Q_WS_WIN m_StyleSheetDir.setPath(qApp->applicationDirPath()); #endif #ifdef Q_OS_LINUX m_StyleSheetDir.setPath("/usr/share/xflr5"); #endif SetupLayout(); connect(m_pctrlStyles, SIGNAL(activated(const QString &)),this, SLOT(OnStyleChanged(const QString &))); connect(m_pctrlBackColor, SIGNAL(clicked()),this, SLOT(OnBackgroundColor())); connect(m_pctrlGraphSettings, SIGNAL(clicked()),this, SLOT(OnGraphSettings())); connect(m_pctrlTextClr, SIGNAL(clicked()),this, SLOT(OnTextColor())); connect(m_pctrlTextFont, SIGNAL(clicked()),this, SLOT(OnTextFont())); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void DisplaySettingsDlg::SetupLayout() { QVBoxLayout *MainLayout = new QVBoxLayout; m_pctrlStyles = new QComboBox; QRegExp regExp("Q(.*)Style"); QString defaultStyle = QApplication::style()->metaObject()->className(); if (defaultStyle == QLatin1String("QMacStyle")) defaultStyle = QLatin1String("Macintosh (Aqua)"); else if (defaultStyle == QLatin1String("OxygenStyle")) defaultStyle = QLatin1String("Oxygen"); else if (regExp.exactMatch(defaultStyle)) defaultStyle = regExp.cap(1); m_pctrlStyles->addItems(QStyleFactory::keys()); m_pctrlStyles->setCurrentIndex(m_pctrlStyles->findText(defaultStyle)); // add custom style sheets QString fileName = "*.qss"; QStringList filesList = MainFrame::s_StylesheetDir.entryList(QStringList(fileName), QDir::Files | QDir::NoSymLinks); for(int is=0; isaddItem(styleSheetName); } // m_pctrlStyleSheets = new QCheckBox(tr("Use Stylesheets")); QGroupBox *GraphBox = new QGroupBox(tr("Graph Settings")); { QHBoxLayout *GraphLayout = new QHBoxLayout; { m_pctrlGraphSettings = new QPushButton(tr("All Graph Settings")); m_pctrlGraphSettings->setMinimumWidth(120); GraphLayout->addWidget(m_pctrlGraphSettings); } GraphBox->setLayout(GraphLayout); } QGroupBox *BackBox = new QGroupBox(tr("Background Color")); { QHBoxLayout *BackLayout = new QHBoxLayout; { m_pctrlBackColor = new ColorButton; m_pctrlBackColor->setMinimumWidth(120); BackLayout->addWidget(m_pctrlBackColor); } BackBox->setLayout(BackLayout); } QGroupBox *FontBox = new QGroupBox(tr("Font")); { QHBoxLayout *FontLayout = new QHBoxLayout; { m_pctrlTextFont = new QPushButton; m_pctrlTextClr = new QPushButton(tr("Text Color")); m_pctrlTextFont->setMinimumWidth(120); m_pctrlTextClr->setMinimumWidth(120); FontLayout->addWidget(m_pctrlTextFont); FontLayout->addWidget(m_pctrlTextClr); } FontBox->setLayout(FontLayout); } m_pctrlReverseZoom = new QCheckBox(tr("Reverse zoom direction using mouse wheel")); m_pctrlAlphaChannel = new QCheckBox(tr("Enable 3D transparency")); QHBoxLayout *CommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); OKButton->setAutoDefault(false); CancelButton = new QPushButton(tr("Cancel")); CancelButton->setAutoDefault(false); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); } MainLayout->addStretch(1); MainLayout->addWidget(m_pctrlStyles); // MainLayout->addWidget(m_pctrlStyleSheets); MainLayout->addStretch(1); MainLayout->addWidget(BackBox); MainLayout->addStretch(1); MainLayout->addWidget(FontBox); MainLayout->addStretch(1); MainLayout->addWidget(GraphBox); MainLayout->addStretch(1); MainLayout->addWidget(m_pctrlReverseZoom); MainLayout->addStretch(1); MainLayout->addWidget(m_pctrlAlphaChannel); MainLayout->addSpacing(20); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); setLayout(MainLayout); } void DisplaySettingsDlg::InitDialog() { // m_pctrlStyleSheets->setChecked(m_bStyleSheets); m_MemGraph.CopySettings(m_pRefGraph); m_pctrlBackColor->SetColor(m_BackgroundColor); QString FontName = m_TextFont.family() + QString(" %1").arg(m_TextFont.pointSize()); m_pctrlTextFont->setText(FontName); if(m_pctrlStyles->findText(s_StyleName)>=0) m_pctrlStyles->setCurrentIndex(m_pctrlStyles->findText(s_StyleName)); else if(m_pctrlStyles->findText(s_StyleSheetName)>=0) m_pctrlStyles->setCurrentIndex(m_pctrlStyles->findText(s_StyleSheetName)); m_pctrlReverseZoom->setChecked(m_bReverseZoom); m_pctrlAlphaChannel->setChecked(m_bAlphaChannel); QPalette palette = m_pctrlTextClr->palette(); QColor listColor = palette.color(QPalette::Button); if(listColor.isValid()) { palette.setColor(QPalette::Button, m_BackgroundColor); palette.setColor(QPalette::ButtonText, m_TextColor); m_pctrlTextClr->setPalette(palette); m_pctrlTextClr->setFont(m_TextFont); } } void DisplaySettingsDlg::OnStyleChanged(const QString &StyleName) { //test for style sheet QString fileName = "*.qss"; QStringList filesList = MainFrame::s_StylesheetDir.entryList(QStringList(fileName), QDir::Files | QDir::NoSymLinks); for(int is=0; issetStyleSheet(styleSheet()); qApp->setStyle(StyleName); s_StyleName = StyleName; } void DisplaySettingsDlg::OnBackgroundColor() { QColor Color = QColorDialog::getColor(m_BackgroundColor); if(Color.isValid()) m_BackgroundColor = Color; m_pctrlBackColor->SetColor(m_BackgroundColor); QPalette palette = m_pctrlTextClr->palette(); QColor listColor = palette.color(QPalette::Button); if(listColor.isValid()) { // palette.setColor(QPalette::Background, m_BackgroundColor); palette.setColor(QPalette::Button, m_BackgroundColor); palette.setColor(QPalette::ButtonText, m_TextColor); m_pctrlTextClr->setPalette(palette); } } void DisplaySettingsDlg::reject() { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; QXDirect *pXDirect = (QXDirect*)pMainFrame->m_pXDirect; QMiarex *pMiarex = (QMiarex*)pMainFrame->m_pMiarex; QXInverse *pXInverse = (QXInverse*)pMainFrame->m_pXInverse; pXDirect->m_pCpGraph->CopySettings(&m_MemGraph); pXDirect->m_pCpGraph->SetInverted(true); for(int ig=0; igm_PlrGraph[ig].CopySettings(&m_MemGraph); for(int ig=0; ig<4; ig++) { pMiarex->m_WingGraph[ig].CopySettings(&m_MemGraph); pMiarex->m_TimeGraph[ig].CopySettings(&m_MemGraph); pMiarex->m_WPlrGraph[ig].CopySettings(&m_MemGraph); } pXInverse->m_QGraph.CopySettings(&m_MemGraph); pXInverse->m_QGraph.SetInverted(true); QDialog::reject(); } void DisplaySettingsDlg::OnGraphSettings() { if(!m_pRefGraph) return; MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; QXDirect *pXDirect = (QXDirect*)pMainFrame->m_pXDirect; QMiarex *pMiarex = (QMiarex*)pMainFrame->m_pMiarex; QXInverse *pXInverse = (QXInverse*)pMainFrame->m_pXInverse; GraphDlg dlg(this); dlg.m_GraphArray[0] = pXDirect->m_pCpGraph; for(int ig=0; igm_PlrGraph+ig; dlg.m_GraphArray[6] = pMiarex->m_WingGraph; dlg.m_GraphArray[7] = pMiarex->m_WingGraph+1; dlg.m_GraphArray[8] = pMiarex->m_WingGraph+2; dlg.m_GraphArray[9] = pMiarex->m_WingGraph+3; dlg.m_GraphArray[10] = pMiarex->m_WPlrGraph; dlg.m_GraphArray[11] = pMiarex->m_WPlrGraph+1; dlg.m_GraphArray[12] = pMiarex->m_WPlrGraph+2; dlg.m_GraphArray[13] = pMiarex->m_WPlrGraph+3; dlg.m_GraphArray[14] = pMiarex->m_TimeGraph; dlg.m_GraphArray[15] = pMiarex->m_TimeGraph+1; dlg.m_GraphArray[16] = pMiarex->m_TimeGraph+2; dlg.m_GraphArray[17] = pMiarex->m_TimeGraph+3; dlg.m_GraphArray[18] = &pMiarex->m_LongRLGraph; dlg.m_GraphArray[19] = &pMiarex->m_LatRLGraph; dlg.m_GraphArray[20] = &pXInverse->m_QGraph; dlg.m_NGraph = 21; QGraph graph; graph.CopySettings(m_pRefGraph); dlg.m_pMemGraph = m_pRefGraph; dlg.m_pGraph = &graph; dlg.SetParams(); if(dlg.exec() == QDialog::Accepted) { m_pRefGraph->CopySettings(dlg.m_pGraph); m_bIsGraphModified = true; pXDirect->m_pCpGraph->SetInverted(true); pXInverse->m_QGraph.SetInverted(true); } } void DisplaySettingsDlg::OnTextColor() { QColor Color = QColorDialog::getColor(m_TextColor); if(Color.isValid()) m_TextColor = Color; QPalette palette = m_pctrlTextClr->palette(); QColor listColor = palette.color(QPalette::Button); if(listColor.isValid()) { // palette.setColor(QPalette::Background, m_BackgroundColor); palette.setColor(QPalette::Button, m_BackgroundColor); palette.setColor(QPalette::ButtonText, m_TextColor); m_pctrlTextClr->setPalette(palette); // m_pctrlTextClr->setAutoFillBackground(true); } } void DisplaySettingsDlg::OnTextFont() { bool ok; QFont TextFont; TextFont.setStyleHint(QFont::TypeWriter, QFont::OpenGLCompatible); #ifdef Q_WS_MAC //20090604 Mac OS Native font dialog does not work well under QT 4.5.1 //QFont font = QFontDialog::getFont(&ok, m_TextFont, this); //20110324 Works again under QT 4.6, though it loses focus is mouse is moved outside of it (QT bug?) //QFont font = QFontDialog::getFont(&ok, m_TextFont, this, "",QFontDialog::DontUseNativeDialog); TextFont = QFontDialog::getFont(&ok, m_TextFont, this); #else TextFont = QFontDialog::getFont(&ok, m_TextFont, this); #endif if (ok) { m_TextFont = TextFont; m_pctrlTextFont->setText(m_TextFont.family()); m_pctrlTextFont->setFont(m_TextFont); m_pctrlTextClr->setFont(m_TextFont); } } xflr5-6.09-06/src/misc/LineDelegate.h000644 001750 000144 00000003660 12247174404 020515 0ustar00techwinderusers000000 000000 /**************************************************************************** LineDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef LINEDELEGATE_H #define LINEDELEGATE_H #include #include #include #include #include #include class LineDelegate : public QAbstractItemDelegate { Q_OBJECT public: LineDelegate (QObject *parent = NULL); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index ) const; void SetLineColor(QColor color); void SetLineStyle(int *style); void SetLineWidth(int *width); public slots: void SetSize(QSize size);//what's the use ? private: void * m_pCbBox; //pointer to the parent QLineComboBox QSize m_Size; int m_LineStyle[5]; // values depend on whether we have a line or width CbBox.... int m_LineWidth[5]; // values depend on whether we have a line or width CbBox.... QColor m_LineColor; // the same for all CbBox items }; #endif //LINEDELEGATE_H xflr5-6.09-06/src/misc/W3dPrefsDlg.h000644 001750 000144 00000005773 12247174404 020266 0ustar00techwinderusers000000 000000 /**************************************************************************** W3dPrefsDlg Class Copyright (C) 2009-2013 Andre Deperrois XFLR5@yahoo.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef W3DPREFSDLG_H #define W3DPREFSDLG_H #include #include #include #include "../misc/LineBtn.h" #include "../misc/ColorButton.h" class W3dPrefsDlg : public QDialog { Q_OBJECT friend class QMiarex; friend class MainFrame; friend class GL3dBodyDlg; public: W3dPrefsDlg(QWidget *pParent); void InitDialog(); private slots: void On3DAxis(); void OnOutline(); void OnTopTrans(); void OnBotTrans(); void OnXCP(); void OnMoments(); void OnIDrag(); void OnVDrag(); void OnDownwash(); void OnWakePanels(); void OnStreamLines(); void OnVLMMesh(); void OnShowWake(); void OnMasses(); void OnResetDefaults(); private: void SetupLayout(); static void SaveSettings(QSettings *pSettings); static void LoadSettings(QSettings *pSettings); LineBtn *m_pctrlAxis, *m_pctrlOutline, *m_pctrlVLMMesh, *m_pctrlTopTrans, *m_pctrlBotTrans; LineBtn *m_pctrlLift, *m_pctrlMoments, *m_pctrlInducedDrag, *m_pctrlViscousDrag, *m_pctrlDownwash; LineBtn *m_pctrlStreamLines, *m_pctrlWakePanels; ColorButton *m_pctrlMassColor; QCheckBox *m_pctrlShowWake; public: static double s_MassRadius; static QColor s_MassColor; static int s_3DAxisStyle, s_3DAxisWidth; static QColor s_3DAxisColor; static int s_VLMStyle, s_VLMWidth; static QColor s_VLMColor; static int s_OutlineStyle, s_OutlineWidth; static QColor s_OutlineColor; static int s_XCPStyle, s_XCPWidth; static QColor s_XCPColor; static int s_MomentStyle, s_MomentWidth; static QColor s_MomentColor; static int s_IDragStyle, s_IDragWidth; static QColor s_IDragColor; static int s_VDragStyle, s_VDragWidth; static QColor s_VDragColor; static int s_TopStyle, s_TopWidth; static QColor s_TopColor; static int s_BotStyle, s_BotWidth; static QColor s_BotColor; static int s_DownwashStyle, s_DownwashWidth; static QColor s_DownwashColor; static int s_StreamLinesStyle, s_StreamLinesWidth; static QColor s_StreamLinesColor; static int s_WakeStyle, s_WakeWidth; static QColor s_WakeColor; static int s_CpStyle, s_CpWidth; static QColor s_CpColor; static bool s_bWakePanels; }; #endif // W3DPREFSDLG_H xflr5-6.09-06/src/misc/LineCbBox.h000644 001750 000144 00000002401 12247412477 017775 0ustar00techwinderusers000000 000000 /**************************************************************************** LineCbBox Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef LINECBBOX_H #define LINECBBOX_H #include class LineCbBox : public QComboBox { public: LineCbBox(QWidget *pParent=NULL); QSize sizeHint() const; void paintEvent (QPaintEvent *event); void SetLine(int const &style, int const &width, QColor const &color); private: int m_Style, m_Width; QColor m_Color; }; #endif // LINECBBOX_H xflr5-6.09-06/src/misc/SaveOptionsDlg.h000644 001750 000144 00000002532 12247174404 021071 0ustar00techwinderusers000000 000000 /**************************************************************************** SaveOptionsDlg Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef SAVEOPTIONSDLG_H #define SAVEOPTIONSDLG_H #include #include class SaveOptionsDlg : public QDialog { Q_OBJECT friend class MainFrame; public: SaveOptionsDlg(QWidget *pParent); void InitDialog(bool bOpps=false, bool bWOpps = true); private slots: void OnOK(); private: void SetupLayout(); void ReadParams(); bool m_bOpps, m_bWOpps; QCheckBox *m_pctrlOpps, *m_pctrlWOpps; }; #endif // SAVEOPTIONSDLG_H xflr5-6.09-06/src/xinverse/000755 001750 000144 00000000000 12250003436 016713 5ustar00techwinderusers000000 000000 xflr5-6.09-06/src/xinverse/XInverse.h000644 001750 000144 00000021651 12247174410 020643 0ustar00techwinderusers000000 000000 /**************************************************************************** QXInverse Class Copyright (C) 2009-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** * @file * This implements the QXInverse class which provides the interface for inverse design of Foil objects */ #ifndef QXINVERSE_H #define QXINVERSE_H #include #include #include #include #include #include #include #include #include #include "../misc/DoubleEdit.h" #include "../graph/QGraph.h" #include "../objects/Foil.h" #include "../objects/Spline.h" /** * @brief This class implements the interface for the inverse Foil design. * *Note: this interface was written without a good understanding of the XFoil methodology, which is a potential source of errors. */ class QXInverse : public QWidget { Q_OBJECT friend class MainFrame; friend class TwoDWidget; friend class InverseOptionsDlg; friend class FoilSelectionDlg; friend class DisplaySettingsDlg; public: QXInverse(QWidget *parent = NULL); ~QXInverse(); void SetupLayout(); void InitDialog(); private slots: void OnCpxx(); void OnInverseApp(); void OnMarkSegment(); void OnInverseStyles(); void OnTangentSpline(); void OnShowSpline(); void OnNewSpline(); void OnApplySpline(); void OnSpecal(); void OnQReset(); void OnFilter(); void OnSmooth(); void OnSymm() ; void OnExecute(); void OnStoreFoil(); void OnExtractFoil(); void OnResetFoilScale(); void OnInsertCtrlPt(); void OnRemoveCtrlPt(); void OnQInitial(); void OnQSpec(); void OnQViscous(); void OnQPoints(); void OnQReflected(); void OnPertubate(); void OnGraphSettings(); void OnSpecInv() ; void OnZoomIn(); void OnZoomX(); void OnZoomY(); private: void UpdateView(); void wheelEvent(QWheelEvent *event); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event) ; void mouseReleaseEvent(QMouseEvent *event) ; void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void mouseDoubleClickEvent ( QMouseEvent * event ); void CheckActions(); void DrawGrid(QPainter &painter, double scale); void PaintView(QPainter &painter); void PaintGraph(QPainter &painter); void PaintFoil(QPainter &painter); void SetScale(QRect CltRect); void ResetQ(); void ResetScale(); void ResetMixedQ(); void ReleaseZoom(); void Smooth(int Pos1 = -1, int Pos2 = -1); void Clear(); void Connect(); void CreateMCurve(); void CreateQCurve(); void CancelMark(); void CancelSpline(); void CancelSmooth(); void SetFoil(); void SetTAngle(double a); void SetTGap(double tr, double ti); void ExecMDES(); void LoadSettings(QSettings *pSettings); void SaveSettings(QSettings *pSettings); bool ExecQDES(); bool SetParams(); bool InitXFoil(Foil * pFoil); double qincom(double qc, double qinf, double tklam); private: QTextEdit *m_pctrlOutput; QLabel *m_pctrlSpecif; QRadioButton *m_pctrlSpecAlpha, *m_pctrlSpecCl; QPushButton *m_pctrlExec, *m_pctrlFilter, *m_pctrlPert, *m_pctrlApplySpline, *m_pctrlNewSpline, *m_pctrlResetQSpec, *m_pctrlSmooth; QCheckBox *m_pctrlShowSpline, *m_pctrlTangentSpline, *m_pctrlSymm; DoubleEdit *m_pctrlSpec, *m_pctrlFilterParam, *m_pctrlTGapy, *m_pctrlTGapx, *m_pctrlTAngle; QLineEdit *m_pctrlMAlphaSpec, *m_pctrlMClSpec; QTextEdit *m_pctrlMOutput; DoubleEdit *m_pctrlIter; QPushButton *m_pctrlMark; QCheckBox *m_pctrlCpxx; QCheckBox *m_pctrlMShowSpline, *m_pctrlMTangentSpline; QPushButton *m_pctrlMExec, *m_pctrlMNewSpline, *m_pctrlMApplySpline, *m_pctrlMSmooth, *m_pctrlMResetQSpec; QWidget *m_pctrlMInvWidget,*m_pctrlFInvWidget; QStackedWidget *m_pctrlStackedInv; static void *s_pMainFrame; /**< a static pointer to the instance of the application's MainFrame object */ static void *s_p2DWidget; /**< a static pointer to the instance of the application's central widget used for 2D drawings */ void *m_pXFoil; /**< a void pointer to the unique instance of the XFoil object */ QList *m_poaFoil; /**< a pointer to the array of Foil objects */ Foil* m_pRefFoil; /**< a pointer to the reference foil geometry used for inverse design */ Foil* m_pModFoil; /**< a pointer to the resulting Foil modified by inverse design operations */ Spline m_Spline; /**< the spline oject to modify the velocity curve */ bool m_bXPressed; /**< true if the 'X' key is pressed */ bool m_bYPressed; /**< true if the 'Y' key is pressed */ bool m_bLoaded; /**< true if a Foil has been loaded from the database and copied to the reference Foil */ bool m_bTrans; /**< true if the Foil representation is in the process of being translated */ bool m_bTransGraph; /**< true if the curves in the graph are in the process of being translated */ bool m_bRefFoil; /**< true if the reference Foil should be displayed */ bool m_bModFoil; /**< true if the modified Foil should be displayed */ bool m_bGetPos; /**< true if the program is waiting for the user to click on a point curve */ bool m_bMark; /**< true if the user is in the process of marking a curve segment for modifiction */ bool m_bMarked; /**< true if a curve segment has been marked for modifiction */ bool m_bSpline; /**< true if the user is in the process of selecting points segments for the spline */ bool m_bSplined; /**< true if the velocity curve has been modified by application of the spline */ bool m_bSmooth; /**< true if the user is in the process of smoothing the curve */ bool m_bZoomPlus; /**< true if the user is in the process of zooming in by drawing a rectangle */ bool m_bZoomXOnly; /**< true if only the x-axis should be scaled */ bool m_bZoomYOnly; /**< true if only the y-axis should be scaled */ bool m_bFullInverse; /**< true if the full inverse method is selected, false if mixed-inverse */ bool m_bReflected; /**< true if the reflected curve should be displayed */ bool m_bShowPoints; /**< true if the curve points are visible in the graph */ bool m_bTangentSpline; /**< true if the spline should be tangent to the velocity curve at its end points */ int m_Mk1; /** the index of the first marked point on the graph */ int m_Mk2; /** the index of the second marked point on the graph */ double m_fRefScale; /**< the default scale for the display of the Foil, for the current window size */ double m_fScale; /**< the current scale for the Foil display */ int m_ReflectedStyle; /**< the index of the reflected curve's style */ int m_ReflectedWidth; /**< the reflected curve's width */ QColor m_ReflectedClr; /**< the reflected curve's color */ QGraph m_QGraph; /**< the velocity QGraph object */ QGraph *m_pCurGraph; /**< = &m_QGraph if the mouse hivers over the graph, false otherwise */ Curve* m_pQCurve; /**< a pointer to the inviscid velocity reference Curve */ Curve* m_pQVCurve; /**< a pointer to the viscous velocity reference Curve */ Curve* m_pMCurve; /**< a pointer to the modified specification curve */ Curve* m_pReflectedCurve; /**< a pointer to the reflected curve */ QRect m_rCltRect; /**< the view's client area, in pixels */ QRect m_rGraphRect; /**< the graph's client are, in pixels */ QRect m_ZoomRect; /**< the rectangle drawn by the user to define the area to zoom in */ QPoint m_PointDown; /**< the screen point where the left mouse button was last pressed */ QPoint m_ptPopUp; /**< the screen point where the right mouse button was last pressed */ QPoint m_ptOffset; /**< the offset position for the display of the Foil */ // temporary allocations int m_tmpPos, m_Pos1, m_Pos2, m_nPos, m_SplineLeftPos, m_SplineRightPos; double xd, yd; double xu, yu; QPoint tanpt; QPoint P0, P1, P2; }; #endif // QXINVERSE_H xflr5-6.09-06/src/xinverse/PertDlg.h000644 001750 000144 00000004023 12247174406 020440 0ustar00techwinderusers000000 000000 /**************************************************************************** PertDlg class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef PERTDLG_H #define PERTDLG_H #include #include #include #include #include #include "../misc/FloatEditDelegate.h" #include "../objects/Foil.h" #include "../misc/DoubleEdit.h" #include "../params.h" class PertDlg : public QDialog { Q_OBJECT public: PertDlg(QWidget *pParent); friend class MainFrame; friend class QXInverse; private slots: void OnCellChanged(QWidget *pWidget); void OnRestore(); void OnApply(); void OnOK(); private: void SetupLayout(); void InitDialog(); void FillCnModel() ; void ReadData(); private: QPushButton *OKButton, *CancelButton, *ApplyButton, *RestoreButton; QTableView *m_pctrlCnTable; QStandardItemModel *m_pCnModel; FloatEditDelegate *m_pFloatDelegate; // DoubleEdit *m_pctrlCnr; // DoubleEdit *m_pctrlCni; // QListBox *m_pctrlCnList; protected: void keyPressEvent(QKeyEvent *event); private: void * m_pXInverse; int m_nc; double m_cnr[IMX+1]; double m_cni[IMX+1]; double m_backr[IMX+1]; double m_backi[IMX+1]; }; #endif xflr5-6.09-06/src/xinverse/InverseOptionsDlg.h000644 001750 000144 00000002663 12247174406 022525 0ustar00techwinderusers000000 000000 /**************************************************************************** InverseOptionsDlg Classes Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef INVERSEOPTIONSDLG_H #define INVERSEOPTIONSDLG_H #include "../misc/LineBtn.h" #include class InverseOptionsDlg:public QDialog { Q_OBJECT friend class QXInverse; public: InverseOptionsDlg(QWidget *pParent); private slots: void OnRefStyle(); void OnModStyle(); void OnSplineStyle(); void OnReflectedStyle(); private: void SetupLayout(); void InitDialog(); LineBtn *m_pctrlRefFoil, *m_pctrlModFoil, *m_pctrlSpline, *m_pctrlReflected; void * m_pXInverse; }; #endif // INVERSEOPTIONSDLG_H xflr5-6.09-06/src/xinverse/InverseOptionsDlg.cpp000644 001750 000144 00000013336 12247174406 023057 0ustar00techwinderusers000000 000000 /**************************************************************************** InverseOptionsDlg Classes Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "XInverse.h" #include "InverseOptionsDlg.h" #include "../misc/LinePickerDlg.h" InverseOptionsDlg::InverseOptionsDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("XInverse Style")); m_pXInverse = NULL; SetupLayout(); } void InverseOptionsDlg::SetupLayout() { m_pctrlRefFoil = new LineBtn(this); m_pctrlModFoil = new LineBtn(this); m_pctrlSpline = new LineBtn(this); m_pctrlReflected = new LineBtn(this); QLabel * lab1 = new QLabel(tr("Reference Foil")); QLabel * lab2 = new QLabel(tr("Modified Foil")); QLabel * lab3 = new QLabel(tr("Spline")); QLabel * lab4 = new QLabel(tr("Reflected Curve")); lab1->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab2->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab3->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab4->setAlignment(Qt::AlignRight | Qt::AlignVCenter); QGridLayout *StyleLayout = new QGridLayout; StyleLayout->addWidget(lab1,1,1); StyleLayout->addWidget(lab2,2,1); StyleLayout->addWidget(lab3,3,1); StyleLayout->addWidget(lab4,4,1); StyleLayout->addWidget(m_pctrlRefFoil,1,2); StyleLayout->addWidget(m_pctrlModFoil,2,2); StyleLayout->addWidget(m_pctrlSpline,3,2); StyleLayout->addWidget(m_pctrlReflected,4,2); QHBoxLayout *CommandButtons = new QHBoxLayout; QPushButton *OKButton = new QPushButton(tr("OK")); QPushButton *CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addLayout(StyleLayout); MainLayout->addLayout(CommandButtons); setLayout(MainLayout); connect(m_pctrlRefFoil, SIGNAL(clickedLB()),this, SLOT(OnRefStyle())); connect(m_pctrlModFoil, SIGNAL(clickedLB()),this, SLOT(OnModStyle())); connect(m_pctrlSpline, SIGNAL(clickedLB()),this, SLOT(OnSplineStyle())); connect(m_pctrlReflected, SIGNAL(clickedLB()),this, SLOT(OnReflectedStyle())); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void InverseOptionsDlg::InitDialog() { QXInverse *pXInverse = (QXInverse*)m_pXInverse; m_pctrlRefFoil->SetStyle(pXInverse->m_pRefFoil->m_nFoilStyle, pXInverse->m_pRefFoil->m_nFoilWidth, pXInverse->m_pRefFoil->m_FoilColor); m_pctrlModFoil->SetStyle(pXInverse->m_pModFoil->m_nFoilStyle, pXInverse->m_pModFoil->m_nFoilWidth, pXInverse->m_pModFoil->m_FoilColor); m_pctrlSpline->SetStyle(pXInverse->m_Spline.style(), pXInverse->m_Spline.width(), pXInverse->m_Spline.color()); m_pctrlReflected->SetStyle(pXInverse->m_ReflectedStyle, pXInverse->m_ReflectedWidth, pXInverse->m_ReflectedClr); } void InverseOptionsDlg::OnRefStyle() { QXInverse *pXInverse = (QXInverse*)m_pXInverse; LinePickerDlg dlg(this); dlg.InitDialog(pXInverse->m_pRefFoil->m_nFoilStyle, pXInverse->m_pRefFoil->m_nFoilWidth, pXInverse->m_pRefFoil->m_FoilColor); if(QDialog::Accepted==dlg.exec()) { m_pctrlRefFoil->SetStyle(dlg.GetStyle(),dlg.GetWidth(),dlg.GetColor()); pXInverse->m_pRefFoil->m_nFoilStyle = dlg.GetStyle(); pXInverse->m_pRefFoil->m_nFoilWidth = dlg.GetWidth(); pXInverse->m_pRefFoil->m_FoilColor = dlg.GetColor(); } } void InverseOptionsDlg::OnModStyle() { QXInverse *pXInverse = (QXInverse*)m_pXInverse; LinePickerDlg dlg(this); dlg.InitDialog(pXInverse->m_pModFoil->m_nFoilStyle, pXInverse->m_pModFoil->m_nFoilWidth, pXInverse->m_pModFoil->m_FoilColor); if(QDialog::Accepted==dlg.exec()) { m_pctrlModFoil->SetStyle(dlg.GetStyle(),dlg.GetWidth(),dlg.GetColor()); pXInverse->m_pModFoil->m_nFoilStyle = dlg.GetStyle(); pXInverse->m_pModFoil->m_nFoilWidth = dlg.GetWidth(); pXInverse->m_pModFoil->m_FoilColor = dlg.GetColor(); } } void InverseOptionsDlg::OnSplineStyle() { QXInverse *pXInverse = (QXInverse*)m_pXInverse; LinePickerDlg dlg(this); dlg.InitDialog(pXInverse->m_Spline.style(), pXInverse->m_Spline.width(), pXInverse->m_Spline.color()); if(QDialog::Accepted==dlg.exec()) { m_pctrlModFoil->SetStyle(dlg.GetStyle(),dlg.GetWidth(),dlg.GetColor()); pXInverse->m_Spline.SetStyle(dlg.GetStyle()); pXInverse->m_Spline.SetWidth(dlg.GetWidth()); pXInverse->m_Spline.SetColor(dlg.GetColor()); } } void InverseOptionsDlg::OnReflectedStyle() { QXInverse *pXInverse = (QXInverse*)m_pXInverse; LinePickerDlg dlg(this); dlg.InitDialog(pXInverse->m_ReflectedStyle, pXInverse->m_ReflectedWidth, pXInverse->m_ReflectedClr); if(QDialog::Accepted==dlg.exec()) { m_pctrlModFoil->SetStyle(dlg.GetStyle(),dlg.GetWidth(),dlg.GetColor()); pXInverse->m_ReflectedStyle = dlg.GetStyle(); pXInverse->m_ReflectedWidth = dlg.GetWidth(); pXInverse->m_ReflectedClr = dlg.GetColor(); } } xflr5-6.09-06/src/xinverse/FoilSelectionDlg.h000644 001750 000144 00000003031 12247174406 022263 0ustar00techwinderusers000000 000000 /**************************************************************************** FoilSelectionDlg Classes Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef FOILSELECTIONDLG_H #define FOILSELECTIONDLG_H #include #include #include #include class FoilSelectionDlg : public QDialog { Q_OBJECT friend class QXInverse; friend class BatchDlg; friend class BatchThreadDlg; public: FoilSelectionDlg(QWidget *pParent); private slots: void OnOK(); void OnSelChangeList(QListWidgetItem *); void OnDoubleClickList(QListWidgetItem *pItem); private: void SetupLayout(); void InitDialog(); QListWidget *m_pctrlNameList; QString m_FoilName; QStringList m_FoilList; QList *m_poaFoil; }; #endif // FOILSELECTIONDLG_H xflr5-6.09-06/src/xinverse/XInverse.cpp000644 001750 000144 00000211434 12247174406 021203 0ustar00techwinderusers000000 000000 /**************************************************************************** XInverse Class Copyright (C) 2009-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include #include "XInverse.h" #include "FoilSelectionDlg.h" #include "PertDlg.h" #include "../globals.h" #include "../mainframe.h" #include "../objects/Foil.h" #include "InverseOptionsDlg.h" #include "../graph/GraphDlg.h" #include "../xdirect/XFoil.h" void *QXInverse::s_pMainFrame; void *QXInverse::s_p2DWidget; /** The public contructor */ QXInverse::QXInverse(QWidget *parent) : QWidget(parent) { // m_pGraphDlg = new GraphDlg(pMainFrame); // m_pXInverseStyleDlg = new InverseOptionsDlg(pMainFrame); // m_pPertDlg = new PertDlg(pMainFrame); m_bFullInverse = false; m_pXFoil = NULL; m_pCurGraph = NULL; m_bTransGraph = false; m_bLoaded = false; // m_bSaved = true; m_bZoomPlus = false; m_bZoomXOnly = false; m_bZoomYOnly = false; m_bShowPoints = false; m_bTangentSpline = false; m_bReflected = false; m_bMarked = false; m_bTrans = false; m_bSpline = false; m_bSplined = true; m_bRefFoil = true; m_bModFoil = false; m_bGetPos = false; m_bMark = false; m_bMarked = false; m_bSmooth = false; m_bXPressed = m_bYPressed = false; m_pRefFoil = new Foil(); m_pModFoil = new Foil(); m_pRefFoil->m_FoilColor = QColor(255,0,0); m_pRefFoil->m_nFoilStyle = 0; m_pRefFoil->m_nFoilWidth = 0; m_pModFoil->m_FoilColor = QColor(0,0,255); m_pModFoil->m_nFoilStyle = 0; m_pModFoil->m_nFoilWidth = 1; m_Spline.InsertPoint(0.0, 0.0); m_Spline.InsertPoint(0.25, 0.0); m_Spline.InsertPoint(0.5, 0.0); m_Spline.InsertPoint(0.75, 0.0); m_Spline.InsertPoint(1.0, 0.0); m_Spline.SplineKnots(); m_Spline.SplineCurve(); m_Spline.SetStyle(0); m_Spline.SetWidth(1); m_Spline.SetColor(QColor(170,120, 0)); m_ReflectedStyle = 1; m_ReflectedWidth = 1; m_ReflectedClr = QColor(170,120, 0); m_nPos = 0; m_tmpPos = -1; m_Pos1 = -1; m_Pos2 = -1; m_SplineLeftPos = -1; m_SplineRightPos = -1; m_QGraph.SetType(2); m_QGraph.SetDefaults(); m_QGraph.SetXTitle(tr("x/c")); m_QGraph.SetYTitle(tr("Q/Vinf")); m_QGraph.SetXMin(0.0); m_QGraph.SetXMax(1.0); m_QGraph.SetYMin(-0.1); m_QGraph.SetYMax(0.1); m_QGraph.SetGraphName(tr("Q Graph")); m_pQCurve = m_QGraph.AddCurve(); m_pMCurve = m_QGraph.AddCurve(); m_pQVCurve = m_QGraph.AddCurve(); m_pReflectedCurve = m_QGraph.AddCurve(); m_pReflectedCurve->SetVisible(m_bReflected); SetupLayout(); if(m_bFullInverse) { m_pctrlStackedInv->setCurrentIndex(0); } else { m_pctrlStackedInv->setCurrentIndex(1); } } /** * The public destructor */ QXInverse::~QXInverse() { // delete m_pPertDlg; // delete m_pGraphDlg; // delete m_pXInverseStyleDlg; } /** * Cancels the existing modification limits on the velocity curve */ void QXInverse::CancelMark() { m_pctrlMark->setChecked(false); m_bGetPos = false; m_bMark = false; } /** * Cancels the existing smoothing limits on the velocity curve */ void QXInverse::CancelSmooth() { m_bSmooth = false; m_bGetPos = false; m_pctrlSmooth->setChecked(false); } /** * Cancels the spline definition process */ void QXInverse::CancelSpline() { m_pctrlOutput->setPlainText(" "); // m_bSpline = false; m_bSplined = false; // m_ctrlShowSpline.SetCheck(0); m_pctrlNewSpline->setChecked(false); m_bSmooth = false; m_bGetPos = false; m_nPos = 0; m_tmpPos = -1; m_Pos1 = -1; m_Pos2 = -1; } /** * Initializes the widgets and actions with the current data */ void QXInverse::CheckActions() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->InvQInitial->setChecked(m_pQCurve->IsVisible()); pMainFrame->InvQSpec->setChecked(m_pMCurve->IsVisible()); pMainFrame->InvQViscous->setChecked(m_pQVCurve->IsVisible()); pMainFrame->InvQPoints->setChecked(m_bShowPoints); pMainFrame->InvQReflected->setChecked(m_bReflected); if(m_bFullInverse) { m_pctrlShowSpline->setChecked(m_bSpline); m_pctrlTangentSpline->setChecked(m_bTangentSpline); } else { XFoil *pXFoil = (XFoil*)m_pXFoil; m_pctrlMShowSpline->setChecked(m_bSpline); m_pctrlMTangentSpline->setChecked(m_bTangentSpline); m_pctrlCpxx->setChecked(pXFoil->lcpxx); } } /** * Clears the data associated to the loaded Foil */ void QXInverse::Clear() { m_pRefFoil->n = 0; m_pRefFoil->m_FoilName = ""; m_pModFoil->m_FoilName = ""; m_bLoaded = false; m_pReflectedCurve->clear(); m_pMCurve->clear(); m_pQCurve->clear(); m_pQVCurve->clear(); } /** * Performs the connections between SIGNALS and SLOTS */ void QXInverse::Connect() { connect(m_pctrlSpecAlpha, SIGNAL(clicked()), this, SLOT(OnSpecal())); connect(m_pctrlSpecCl, SIGNAL(clicked()), this, SLOT(OnSpecal())); connect(m_pctrlSpec, SIGNAL(editingFinished()), this, SLOT(OnSpecInv())); connect(m_pctrlShowSpline, SIGNAL(clicked()), this, SLOT(OnShowSpline())); connect(m_pctrlNewSpline, SIGNAL(clicked()), this, SLOT(OnNewSpline())); connect(m_pctrlApplySpline, SIGNAL(clicked()), this, SLOT(OnApplySpline())); connect(m_pctrlTangentSpline, SIGNAL(clicked()), this, SLOT(OnTangentSpline())); connect(m_pctrlResetQSpec, SIGNAL(clicked()), this, SLOT(OnQReset())); connect(m_pctrlSmooth, SIGNAL(clicked()), this, SLOT(OnSmooth())); connect(m_pctrlPert, SIGNAL(clicked()), this, SLOT(OnPertubate())); connect(m_pctrlFilter, SIGNAL(clicked()), this, SLOT(OnFilter())); connect(m_pctrlSymm, SIGNAL(clicked()), this, SLOT(OnSymm())); connect(m_pctrlExec, SIGNAL(clicked()), this, SLOT(OnExecute())); connect(m_pctrlMNewSpline, SIGNAL(clicked()), this, SLOT(OnNewSpline())); connect(m_pctrlMark, SIGNAL(clicked()), this, SLOT(OnMarkSegment())); connect(m_pctrlMApplySpline, SIGNAL(clicked()), this, SLOT(OnApplySpline())); connect(m_pctrlMTangentSpline, SIGNAL(clicked()), this, SLOT(OnTangentSpline())); connect(m_pctrlMShowSpline, SIGNAL(clicked()), this, SLOT(OnShowSpline())); connect(m_pctrlMResetQSpec, SIGNAL(clicked()), this, SLOT(OnQReset())); connect(m_pctrlCpxx, SIGNAL(clicked()), this, SLOT(OnCpxx())); connect(m_pctrlMExec, SIGNAL(clicked()), this, SLOT(OnExecute())); } /** * Creates the velocity curve */ void QXInverse::CreateQCurve() { XFoil *pXFoil = (XFoil*)m_pXFoil; double x,y; m_pQCurve->clear(); int points; if(m_bFullInverse) points = 257; else points = pXFoil->n; for (int i=1; i<=points; i++) { x = 1.0 - pXFoil->sspec[i]; y = pXFoil->qcomp(pXFoil->qspec[1][i])/pXFoil->qinf; m_pQCurve->AppendPoint(x,y); } } /** * Creates the modified velocity specification curve */ void QXInverse::CreateMCurve() { XFoil *pXFoil = (XFoil*)m_pXFoil; int i, points; double x,y; m_pMCurve->clear(); m_pReflectedCurve->clear(); if(m_bFullInverse) points = 257; else points = pXFoil->n; for (i=1; i<=points; i++) { x = 1.0 - pXFoil->sspec[i]; y = pXFoil->qcomp(pXFoil->qspec[1][i])/pXFoil->qinf; m_pMCurve->AppendPoint(x,y); m_pReflectedCurve->AppendPoint(pXFoil->sspec[i],-y); } } /** * Draws the grid underneath the Foil display * @param painter the instance of the QPainter object on which to draw * @param scale the scaling factor for drawing */ void QXInverse::DrawGrid(QPainter &painter, double scale) { painter.save(); double scalex; int TickSize; TickSize = 5; scalex= scale; QPen TextPen(MainFrame::s_TextColor); painter.setPen(TextPen); //neutral line first // QPen LinePen(MainFrame::m_TextColor); // painter.setPen(LinePen); painter.drawLine(0, m_ptOffset.y(), m_rCltRect.right(), m_ptOffset.y()); double xo = 0.0; double xmin = 0.0; double xmax = 1.0; // double ymin = -0.2; // double ymax = 0.2; double XGridUnit = 0.1; double XHalfGridUnit = 0.05; double XMinGridUnit = 0.01; double xt = xo-int((xo-xmin)*1.0001/XGridUnit)*XGridUnit;//one tick at the origin double xht = xo-int((xo-xmin)*1.0001/XHalfGridUnit)*XHalfGridUnit;//one tick at the origin double xmt = xo-int((xo-xmin)*1.0001/XMinGridUnit)*XMinGridUnit;//one tick at the origin QString strLabel; while(xt<=xmax*1.001) { //Draw ticks painter.drawLine(int(xt*scalex) + m_ptOffset.x(), m_ptOffset.y(), int(xt*scalex) + m_ptOffset.x(), m_ptOffset.y()+TickSize); strLabel = QString("%1").arg(xt,0,'f',1); painter.drawText(int(xt*scalex)+m_ptOffset.x()-5, m_ptOffset.y()+(int)(TickSize*5), strLabel); xt += XGridUnit ; } while(xht<=xmax*1.001) { //Draw ticks painter.drawLine(int(xht*scalex) + m_ptOffset.x(), m_ptOffset.y(), int(xht*scalex) + m_ptOffset.x(), m_ptOffset.y()+TickSize*2); xht += XHalfGridUnit ; } while(xmt<=xmax*1.001) { //Draw ticks painter.drawLine(int(xmt*scalex) + m_ptOffset.x(), m_ptOffset.y(), int(xmt*scalex) + m_ptOffset.x(), m_ptOffset.y()+TickSize); xmt += XMinGridUnit ; } painter.restore(); } /** * Executes a full inverse design analysis * Updates the geometry of the modified Foil */ void QXInverse::ExecMDES() { //----- put modified info back into global arrays XFoil *pXFoil = (XFoil*)m_pXFoil; int i, isp; double qscom; for (i=1; i<= pXFoil->nsp; i++) { isp = pXFoil->nsp - i + 1; qscom = pXFoil->qinf*m_pMCurve->y[i-1]; pXFoil->qspec[1][i] = qincom(qscom, pXFoil->qinf, pXFoil->tklam); } pXFoil->ExecMDES(); for(i=1; i<=pXFoil->nsp; i++) { m_pModFoil->x[i-1] = pXFoil->xb[i]; m_pModFoil->y[i-1] = pXFoil->yb[i]; } for(i=1; i<=pXFoil->nsp; i++) { m_pModFoil->xb[i-1] = pXFoil->xb[i]; m_pModFoil->yb[i-1] = pXFoil->yb[i]; } m_pModFoil->n = pXFoil->nsp; m_pModFoil->nb = pXFoil->nsp; m_pModFoil->InitFoil(); m_pModFoil->m_bSaved = false; m_bModFoil = true; } /** * Executes a mixed inverse design analysis * Updates the geometry of the modified Foil *@return true unless the modifications points were not marked */ bool QXInverse::ExecQDES() { XFoil *pXFoil = (XFoil*)m_pXFoil; int i; if(!m_bMarked) { // || !pXFoil->liqset m_pctrlMOutput->setPlainText(tr("Must mark off target segment first")); return false; } //----- put modified info back into global arrays int isp; double qscom; for (i=1; i<= pXFoil->nsp; i++) { isp = pXFoil->nsp - i + 1; qscom = pXFoil->qinf*m_pMCurve->y[i-1]; pXFoil->qspec[1][i] = qincom(qscom, pXFoil->qinf, pXFoil->tklam); } bool bRes = pXFoil->ExecQDES(); QString str; QString strong = ""; strong = " dNMax dGMax\n"; for(int l=1; l<=pXFoil->QMax; l++) { str = QString("%1e %2\n").arg(pXFoil->dnTrace[l],7,'e',3).arg(pXFoil->dgTrace[l],7,'e',3); strong += str; } if(bRes) { strong += tr("Converged"); m_pctrlMOutput->setPlainText(strong); } else { strong += tr("Unconverged"); m_pctrlMOutput->setPlainText(strong); } for (i=1; i<=pXFoil->n; i++) { m_pModFoil->x[i-1] = pXFoil->x[i]; m_pModFoil->y[i-1] = pXFoil->y[i]; } for (i=1; i<=pXFoil->nb; i++) { m_pModFoil->xb[i-1] = pXFoil->x[i]; m_pModFoil->yb[i-1] = pXFoil->y[i]; } m_pModFoil->n = pXFoil->n; m_pModFoil->nb = pXFoil->nb; m_pModFoil->InitFoil(); m_bModFoil = true; return true; } /** * Initializes XFoil with the data from the input Foil object * @param pFoil a pointer to the Foil object with which to initialize the XFoil object * @true if the initialization has been sucessful */ bool QXInverse::InitXFoil(Foil * pFoil) { //loads pFoil in XFoil, calculates normal vectors, and sets results in current foil if(!pFoil) return false; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; XFoil *pXFoil = (XFoil*)m_pXFoil; m_pModFoil->m_FoilName = pFoil->m_FoilName + tr(" Modified"); pXFoil->m_FoilName = m_pRefFoil->m_FoilName ; pXFoil->Initialize(); for(int i =0; in; i++) { pXFoil->xb[i+1] = pFoil->x[i]; pXFoil->yb[i+1] = pFoil->y[i]; } pXFoil->nb = pFoil->n; pXFoil->lflap = false; pXFoil->lbflap = false; pXFoil->ddef = 0.0; pXFoil->xbf = 1.0; pXFoil->ybf = 0.0; pXFoil->lqspec = false; pXFoil->lscini = false; if(pXFoil->Preprocess()) { pXFoil->CheckAngles(); for (int k=0; kn;k++) { pFoil->nx[k] = pXFoil->nx[k+1]; pFoil->ny[k] = pXFoil->ny[k+1]; } pFoil->n = pXFoil->n; return true; } else { QMessageBox::warning(pMainFrame,tr("Warning"),tr("Unrecognized foil format")); return false; } } /** * Overrides the QWidget's keyPressEvent method. * Dispatches the key press event * @param event the QKeyEvent */ void QXInverse::keyPressEvent(QKeyEvent *event) { bool bCtrl; if(event->modifiers() & Qt::ControlModifier) bCtrl = true; switch (event->key()) { case Qt::Key_X: m_bXPressed = true; break; case Qt::Key_Y: m_bYPressed = true; break; case Qt::Key_Escape: { if(m_bZoomPlus) { ReleaseZoom(); } else if(m_bGetPos) { m_bGetPos = false; m_bSpline = false; m_bSmooth = false; if(m_bFullInverse) { CancelSpline(); CancelSmooth(); } else { CancelSpline(); CancelSmooth(); } UpdateView(); } break; } case Qt::Key_Return: { if (m_bSmooth) { Smooth(-1); m_bGetPos = false; } else { if(m_bFullInverse) { m_pctrlExec->setFocus(); } else { m_pctrlExec->setFocus(); } return; } break; } case Qt::Key_Z: { return;//User is zooming with 'Z' key instead of mouse midle button } case Qt::Key_G: { OnGraphSettings(); return; } case Qt::Key_R: { if(m_pCurGraph) { m_QGraph.SetAuto(true); UpdateView(); } else OnResetFoilScale(); break; } default: QWidget::keyPressEvent(event); } } /** * Overrides the QWidget's keyReleaseEvent method. * Dispatches the key release event * @param event the QKeyEvent */ void QXInverse::keyReleaseEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Escape: { if(m_bZoomPlus) ReleaseZoom(); if(m_bZoomXOnly) { m_bZoomXOnly = false; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->InverseZoomX->setChecked(false); } if(m_bZoomYOnly) { m_bZoomYOnly = false; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->InverseZoomY->setChecked(false); } break; } case Qt::Key_X: if(!event->isAutoRepeat()) m_bXPressed = false; break; case Qt::Key_Y: if(!event->isAutoRepeat()) m_bYPressed = false; break; default: QWidget::keyReleaseEvent(event); } } /** * Loads the user's default settings from the application QSettings object * @param pSettings a pointer to the QSettings object */ void QXInverse::LoadSettings(QSettings *pSettings) { pSettings->beginGroup("XInverse"); { m_bFullInverse = pSettings->value("FullInverse").toBool(); m_Spline.SetColor(pSettings->value("SplineColor").value()); m_Spline.SetStyle(pSettings->value("SplineStyle").toInt()); m_Spline.SetWidth(pSettings->value("SplineWdth").toInt()); m_pRefFoil->m_FoilColor = pSettings->value("BaseFoilColor").value(); m_pRefFoil->m_nFoilStyle = pSettings->value("BaseFoilStyle").toInt(); m_pRefFoil->m_nFoilWidth = pSettings->value("BaseFoilWidth").toInt(); m_pModFoil->m_FoilColor = pSettings->value("ModFoilColor").value(); m_pModFoil->m_nFoilStyle = pSettings->value("ModFoilStyle").toInt(); m_pModFoil->m_nFoilWidth = pSettings->value("ModFoilWidth").toInt(); } pSettings->endGroup(); m_QGraph.LoadSettings(pSettings); } /** * Overrides the QWidget's mouseDoubleClickEvent method. * Dispatches the event * @param event the QMouseEvent */ void QXInverse::mouseDoubleClickEvent (QMouseEvent *event) { if (!m_QGraph.IsInDrawRect(event->pos())) return; OnGraphSettings(); } /** * Overrides the QWidget's mouseMoveEvent method. * Dispatches the event * @param event the QMouseEvent */ void QXInverse::mouseMoveEvent(QMouseEvent *event) { // if(!hasFocus()) setFocus(); static double x1,y1, xmin, xmax, ymin, ymax, xpt, ypt, scale, ux, uy, unorm, vx, vy, vnorm, scal; static double xx0,xx1,xx2,yy0,yy1,yy2, dist; static int a, n, ipt; static QPoint point; point = event->pos(); if(m_bGetPos) { m_tmpPos = m_pMCurve->closestPoint(m_QGraph.ClientTox(point.x()), m_QGraph.ClientToy(point.y()), dist); UpdateView(); } else if(m_bZoomPlus && (event->buttons() & Qt::LeftButton)) { m_ZoomRect.setRight(point.x()); m_ZoomRect.setBottom(point.y()); UpdateView(); } else if(m_rCltRect.contains(point) && (event->buttons() & Qt::LeftButton) && m_bTrans) { if(m_bTransGraph) { // we're dragging the graph x1 = m_QGraph.ClientTox(m_PointDown.x()) ; y1 = m_QGraph.ClientToy(m_PointDown.y()) ; xu = m_QGraph.ClientTox(point.x()); yu = m_QGraph.ClientToy(point.y()); xmin = m_QGraph.GetXMin() - xu+x1; xmax = m_QGraph.GetXMax() - xu+x1; ymin = m_QGraph.GetYMin() - yu+y1; ymax = m_QGraph.GetYMax() - yu+y1; m_QGraph.SetWindow(xmin, xmax, ymin, ymax); } else { //we're dragging the foil m_ptOffset.rx() += point.x() - m_PointDown.x(); m_ptOffset.ry() += point.y() - m_PointDown.y(); } UpdateView(); m_PointDown = point; } else if ((event->buttons() & Qt::LeftButton) && !m_bZoomPlus && m_bSpline && m_Spline.m_iSelect>=0) { // user is dragging the point x1 = m_QGraph.ClientTox(point.x()) ; y1 = m_QGraph.ClientToy(point.y()) ; if(m_rGraphRect.contains(point)) { n = m_Spline.m_iSelect; if(n==0) { // user is dragging end point // find closest graph point ipt = m_pMCurve->closestPoint(m_QGraph.ClientTox(point.x()), m_QGraph.ClientToy(point.y()), dist); m_SplineLeftPos = ipt; xpt = m_pMCurve->x[ipt]; ypt = m_pMCurve->y[ipt]; // check for inversion if(xpt> m_Spline.m_CtrlPoint.last().x) { m_Spline.m_CtrlPoint[n].x = m_Spline.m_CtrlPoint.last().x; m_Spline.m_CtrlPoint[n].y = m_Spline.m_CtrlPoint.last().y; m_Spline.m_CtrlPoint.last().x = xpt; m_Spline.m_CtrlPoint.last().y = ypt; } else { m_Spline.m_CtrlPoint[n].x = xpt; m_Spline.m_CtrlPoint[n].y = ypt; } m_bSplined = false; m_Spline.SplineCurve(); } else if(n == m_Spline.m_CtrlPoint.size()-1) { // user is dragging end point // find closest graph point ipt = m_pMCurve->closestPoint(m_QGraph.ClientTox(point.x()), m_QGraph.ClientToy(point.y()), dist); m_SplineRightPos = ipt; xpt = m_pMCurve->x[ipt]; ypt = m_pMCurve->y[ipt]; // check for inversion if(xpt< m_Spline.m_CtrlPoint[0].x) { m_Spline.m_CtrlPoint[n].x = m_Spline.m_CtrlPoint[0].x; m_Spline.m_CtrlPoint[n].y = m_Spline.m_CtrlPoint[0].y; m_Spline.m_CtrlPoint[0].x = xpt; m_Spline.m_CtrlPoint[0].y = ypt; } else { m_Spline.m_CtrlPoint[n].x = xpt; m_Spline.m_CtrlPoint[n].y = ypt; } m_Spline.SplineCurve(); m_bSplined = false; } else if (n==1 && m_bTangentSpline) { // Second point must remain on tangent to curve // difficulty is that we are working in non-normal coordinates tanpt = point; P0 = QPoint(m_QGraph.xToClient(m_pMCurve->x[m_SplineLeftPos-1]), m_QGraph.yToClient(m_pMCurve->y[m_SplineLeftPos-1])); P1 = QPoint(m_QGraph.xToClient(m_pMCurve->x[m_SplineLeftPos]), m_QGraph.yToClient(m_pMCurve->y[m_SplineLeftPos])); P2 = QPoint(m_QGraph.xToClient(m_pMCurve->x[m_SplineLeftPos+1]), m_QGraph.yToClient(m_pMCurve->y[m_SplineLeftPos+1])); //v is the tangent to the curve in screen coordinates vx = (double)((P0.x()-P1.x())*(P0.x()-P2.x())*(P1.x()-P2.x())*(P2.x()-P0.x())); vy = (double)( P0.y() *(P1.x()-P2.x()) * (P1.x()-P2.x()) * (P2.x()-P0.x()) - P1.y() *(2.0*P1.x()-P0.x()-P2.x()) * (P0.x()-P2.x()) * (P2.x()-P0.x()) - P2.y() *(P1.x()-P0.x()) * (P0.x()-P1.x()) * (P0.x()-P2.x())); vnorm = sqrt(vx*vx+vy*vy); vx/=vnorm; vy/=vnorm; scal = (double)(point.x()-P1.x())*vx + (double)(point.y()-P1.y())*vy; tanpt.rx() = P1.x() + (int)(vx * scal); tanpt.ry() = P1.y() + (int)(vy * scal); x1 = m_QGraph.ClientTox(tanpt.x()) ; y1 = m_QGraph.ClientToy(tanpt.y()) ; xx0 = m_pMCurve->x[m_SplineLeftPos-1]; xx1 = m_pMCurve->x[m_SplineLeftPos]; xx2 = m_pMCurve->x[m_SplineLeftPos+1]; yy0 = m_pMCurve->y[m_SplineLeftPos-1]; yy1 = m_pMCurve->y[m_SplineLeftPos]; yy2 = m_pMCurve->y[m_SplineLeftPos+1]; ux = (xx0-xx1)*(xx0-xx2)*(xx1-xx2)*(xx2-xx0); uy = yy0 *(xx1-xx2) * (xx1-xx2) * (xx2-xx0) - yy1 *(2.0*xx1-xx0-xx2) * (xx0-xx2) * (xx2-xx0) - yy2 *(xx1-xx0) * (xx0-xx1) * (xx0-xx2); // unorm = sqrt(ux*ux*scx*scx+uy*uy*scy*scy)/scx/scy; unorm = sqrt(ux*ux+uy*uy); ux /= unorm; uy /= unorm; vx = x1-m_Spline.m_CtrlPoint[n-1].x; vy = y1-m_Spline.m_CtrlPoint[n-1].y; scal = (ux*vx + uy*vy); m_Spline.m_CtrlPoint[n].x = m_Spline.m_CtrlPoint[0].x + scal * ux ; m_Spline.m_CtrlPoint[n].y = m_Spline.m_CtrlPoint[0].y + scal * uy ; m_Spline.SplineCurve(); m_bSplined = false; } else if (n==m_Spline.m_CtrlPoint.size()-2 && m_bTangentSpline) { //penultimate point must remain on tangent to curve // difficulty is that we are working in non-normal coordinates tanpt = QPoint(point.x(), point.y()); P0 = QPoint(m_QGraph.xToClient(m_pMCurve->x[m_SplineRightPos-1]), m_QGraph.yToClient(m_pMCurve->y[m_SplineRightPos-1])); P1 = QPoint(m_QGraph.xToClient(m_pMCurve->x[m_SplineRightPos]), m_QGraph.yToClient(m_pMCurve->y[m_SplineRightPos])); P2 = QPoint(m_QGraph.xToClient(m_pMCurve->x[m_SplineRightPos+1]), m_QGraph.yToClient(m_pMCurve->y[m_SplineRightPos+1])); //v is the tangent to the curve in screen coordinates vx = (double)((P0.x()-P1.x())*(P0.x()-P2.x())*(P1.x()-P2.x())*(P2.x()-P0.x())); vy = (double)( P0.y() *(P1.x()-P2.x()) * (P1.x()-P2.x()) * (P2.x()-P0.x()) - P1.y() *(2.0*P1.x()-P0.x()-P2.x()) * (P0.x()-P2.x()) * (P2.x()-P0.x()) - P2.y() *(P1.x()-P0.x()) * (P0.x()-P1.x()) * (P0.x()-P2.x())); vnorm = sqrt(vx*vx+vy*vy); vx/=vnorm; vy/=vnorm; scal = (double)(point.x()-P1.x())*vx + (double)(point.y()-P1.y())*vy; tanpt.rx() = P1.x() + (int)(vx * scal); tanpt.ry() = P1.y() + (int)(vy * scal); x1 = m_QGraph.ClientTox(tanpt.x()) ; y1 = m_QGraph.ClientToy(tanpt.y()) ; xx0 = m_pMCurve->x[m_SplineRightPos-1]; xx1 = m_pMCurve->x[m_SplineRightPos]; xx2 = m_pMCurve->x[m_SplineRightPos+1]; yy0 = m_pMCurve->y[m_SplineRightPos-1]; yy1 = m_pMCurve->y[m_SplineRightPos]; yy2 = m_pMCurve->y[m_SplineRightPos+1]; ux = (xx0-xx1)*(xx0-xx2)*(xx1-xx2)*(xx2-xx0); uy = yy0 *(xx1-xx2) * (xx1-xx2) * (xx2-xx0) - yy1 *(2.0*xx1-xx0-xx2) * (xx0-xx2) * (xx2-xx0) - yy2 *(xx1-xx0) * (xx0-xx1) * (xx0-xx2); unorm = sqrt(ux*ux+uy*uy); ux /= unorm; uy /= unorm; vx = x1-m_Spline.m_CtrlPoint[n+1].x; vy = y1-m_Spline.m_CtrlPoint[n+1].y; scal = (ux*vx + uy*vy); m_Spline.m_CtrlPoint[n].x = m_Spline.m_CtrlPoint[n+1].x + scal * ux; m_Spline.m_CtrlPoint[n].y = m_Spline.m_CtrlPoint[n+1].y + scal * uy; m_Spline.SplineCurve(); m_bSplined = false; } else if (n>0 && nbuttons() & Qt::MidButton) /*|| (shZ & 0x8000)*/) { ReleaseZoom(); QPoint pttmp(point.x(), point.y()); if(m_QGraph.IsInDrawRect(pttmp)) { //zoom graph m_QGraph.SetAuto(false); if(point.y()-m_PointDown.y()<0) m_QGraph.Scale(1.02); else m_QGraph.Scale(1.0/1.02); } else { scale = m_fScale; if(point.y()-m_PointDown.y()>0) m_fScale *= 1.02; else m_fScale /= 1.02; a = (int)((m_rCltRect.right()+m_rCltRect.left())/2); m_ptOffset.rx() = a + (int)((m_ptOffset.x()-a)*m_fScale/scale); } UpdateView(); m_PointDown = point; } else { // highlight if mouse passe over a point if(m_bSpline) { x1 = m_QGraph.ClientTox(point.x()); y1 = m_QGraph.ClientToy(point.y()); n = m_Spline.IsControlPoint(x1,y1, m_QGraph.GetXScale(), m_QGraph.GetYScale()); if (n>=0 && nstatusBar()->showMessage(QString("X = %1, Y = %2").arg(m_QGraph.ClientTox(event->x())).arg(m_QGraph.ClientToy(event->y()))); m_pCurGraph = &m_QGraph; } else m_pCurGraph = NULL; } /** * Overrides the QWidget's mousePressEvent method. * Dispatches the event * @param event the QMouseEvent */ void QXInverse::mousePressEvent(QMouseEvent *event) { TwoDWidget *p2DWidget = (TwoDWidget*)s_p2DWidget; bool bCtrl, bShift; bCtrl = bShift = false; if(event->modifiers() & Qt::ControlModifier) bCtrl = true; if(event->modifiers() & Qt::ShiftModifier) bShift = true; int CtrlPt; QPoint pttmp; QPoint point = event->pos(); if((event->buttons() & Qt::LeftButton)) { if(!m_bGetPos) { m_PointDown.rx() = point.x(); m_PointDown.ry() = point.y(); pttmp = QPoint(point.x(), point.y()); if(m_QGraph.IsInDrawRect(pttmp)) { m_bTransGraph = true; p2DWidget->setCursor(Qt::ClosedHandCursor); xd = m_QGraph.ClientTox(point.x()); yd = m_QGraph.ClientToy(point.y()); if(m_bSpline) { CtrlPt = m_Spline.IsControlPoint(xd, yd, m_QGraph.GetXScale(), m_QGraph.GetYScale()); if(CtrlPt<0) m_Spline.m_iSelect = -1; else { m_Spline.m_iSelect = CtrlPt; // return; } if (bCtrl) { if(CtrlPt>=0) { if (m_Spline.m_iSelect>=0) { if(!m_Spline.RemovePoint(m_Spline.m_iSelect)) { QMessageBox::warning(p2DWidget,tr("Warning"), tr("The minimum number of control points has been reached for this spline degree")); return; } m_Spline.SplineKnots(); m_Spline.SplineCurve(); } } } else if (bShift) { m_Spline.InsertPoint(xd,yd); m_Spline.SplineKnots(); m_Spline.SplineCurve(); } if(CtrlPt>=0) return; } } else m_bTransGraph = false; if(m_bZoomPlus && m_QGraph.IsInDrawRect(point)) { m_ZoomRect.setLeft(point.x()); m_ZoomRect.setTop(point.y()); m_ZoomRect.setRight(point.x()); m_ZoomRect.setBottom(point.y()); return; } else if(m_bZoomPlus && !m_QGraph.IsInDrawRect(point)) { ReleaseZoom(); } else { p2DWidget->setCursor(Qt::ClosedHandCursor); m_bTrans = true; m_bZoomPlus = false; } } } else if((event->buttons() & Qt::RightButton)) { m_ptPopUp = event->pos(); } } /** * Overrides the QWidget's mouseReleaseEvent method. * Dispatches the event * @param event the QMouseEvent */ void QXInverse::mouseReleaseEvent(QMouseEvent *event) { XFoil *pXFoil = (XFoil*)m_pXFoil; TwoDWidget *p2DWidget = (TwoDWidget*)s_p2DWidget; m_bTrans = false; static int tmp, width, height; static double x1,x2,w,h,xw,yh,xm,ym, dist; static double xmin, ymin, xmax, ymax; static double ratio,x, y, ux, uy, xpt, ypt, norm; QPoint point = event->pos(); if(m_bZoomPlus && m_rCltRect.contains(point)) { QRect ZRect = m_ZoomRect.normalized(); if (!ZRect.isEmpty() ) { xu = m_QGraph.ClientTox(point.x()); yu = m_QGraph.ClientToy(point.y()); width = abs(m_PointDown.x()-point.x()); height = abs(m_PointDown.y()-point.y()); //preserve ratio w = qAbs(xu-xd); h = qAbs(yu-yd); xw = m_QGraph.GetXMax() - m_QGraph.GetXMin(); yh = m_QGraph.GetYMax() - m_QGraph.GetYMin(); xm = (xu+xd)/2.0; ym = (yu+yd)/2.0; if(width>=height) { xmin = xm - w/2.0; xmax = xm + w/2.0; ratio = w/xw; ymin = ym - ratio*yh/2.0; ymax = ym + ratio*yh/2.0; } else { ymin = ym - h/2.0; ymax = ym + h/2.0; ratio = h/yh; xmin = xm - ratio * xw/2.0; xmax = xm + ratio * xw/2.0; } if (m_QGraph.IsInDrawRect(ZRect.left(), ZRect.top()) && m_QGraph.IsInDrawRect(ZRect.right(), ZRect.bottom())) { m_QGraph.SetWindow(xmin, xmax, ymin, ymax); } m_ZoomRect.setRight(m_ZoomRect.left()-1); m_ZoomRect.setTop(m_ZoomRect.bottom()+1); } else { ReleaseZoom(); } } else if(m_bZoomPlus && !m_rCltRect.contains(point)) { ReleaseZoom(); } else if(m_bGetPos && m_rCltRect.contains(point)) { if(m_nPos == 0) { m_Pos1 = m_pMCurve->closestPoint(m_QGraph.ClientTox(point.x()), m_QGraph.ClientToy(point.y()), dist); } if(m_nPos == 1) { m_Pos2 = m_pMCurve->closestPoint(m_QGraph.ClientTox(point.x()), m_QGraph.ClientToy(point.y()), dist); } m_nPos++; if(m_nPos == 2) { if(m_bSmooth) { m_pctrlOutput->setPlainText(" "); Smooth(m_Pos1, m_Pos2); } else if(m_bSpline) { x1 = m_pMCurve->x[m_Pos1]; x2 = m_pMCurve->x[m_Pos2]; if(qAbs(x2-x1)<0.00001) return; if(x2x[m_Pos1], m_pMCurve->y[m_Pos1]); m_Spline.InsertPoint(m_pMCurve->x[m_Pos2], m_pMCurve->y[m_Pos2]); x = (3.0*m_pMCurve->x[m_Pos1] + m_pMCurve->x[m_Pos2])/4.0; y = (3.0*m_pMCurve->y[m_Pos1] + m_pMCurve->y[m_Pos2])/4.0; m_Spline.InsertPoint(x,y); x = (m_pMCurve->x[m_Pos1] + m_pMCurve->x[m_Pos2])/2.0; y = (m_pMCurve->y[m_Pos1] + m_pMCurve->y[m_Pos2])/2.0; m_Spline.InsertPoint(x,y); x = (m_pMCurve->x[m_Pos1] + 3.0*m_pMCurve->x[m_Pos2])/4.0; y = (m_pMCurve->y[m_Pos1] + 3.0*m_pMCurve->y[m_Pos2])/4.0; m_Spline.InsertPoint(x,y); if (m_bTangentSpline) { //Second point must remain on tangent to curve ux = m_pMCurve->x[m_Pos1+1] - m_pMCurve->x[m_Pos1]; uy = m_pMCurve->y[m_Pos1+1] - m_pMCurve->y[m_Pos1]; norm = sqrt(ux*ux+uy*uy); ux /= norm; uy /= norm; xpt = m_Spline.m_CtrlPoint[1].x - m_Spline.m_CtrlPoint[0].x; ypt = m_Spline.m_CtrlPoint[1].y - m_Spline.m_CtrlPoint[0].y; m_Spline.m_CtrlPoint[1].x = m_Spline.m_CtrlPoint[0].x + (ux*xpt + uy*ypt) * ux; m_Spline.m_CtrlPoint[1].y = m_Spline.m_CtrlPoint[0].y + (ux*xpt + uy*ypt) * uy; //penultimate point must remain on tangent to curve ux = m_pMCurve->x[m_Pos2] - m_pMCurve->x[m_Pos2-1]; uy = m_pMCurve->y[m_Pos2] - m_pMCurve->y[m_Pos2-1]; norm = sqrt(ux*ux+uy*uy); ux /= norm; uy /= norm; xpt = m_Spline.m_CtrlPoint[m_Spline.m_CtrlPoint.size()-2].x - m_Spline.m_CtrlPoint[m_Spline.m_CtrlPoint.size()-1].x; ypt = m_Spline.m_CtrlPoint[m_Spline.m_CtrlPoint.size()-2].y - m_Spline.m_CtrlPoint[m_Spline.m_CtrlPoint.size()-1].y; m_Spline.m_CtrlPoint[m_Spline.m_CtrlPoint.size()-2].x = m_Spline.m_CtrlPoint[m_Spline.m_CtrlPoint.size()-1].x + (ux*xpt + uy*ypt) * ux; m_Spline.m_CtrlPoint[m_Spline.m_CtrlPoint.size()-2].y = m_Spline.m_CtrlPoint[m_Spline.m_CtrlPoint.size()-1].y + (ux*xpt + uy*ypt) * uy; } m_Spline.SplineKnots(); m_Spline.SplineCurve(); if(m_bFullInverse) { m_pctrlNewSpline->setChecked(0); m_pctrlOutput->setPlainText( tr("Drag points to modify splines, Apply, and Execute to generate the new geometry")); } else { m_pctrlMNewSpline->setChecked(0); m_pctrlMOutput->setPlainText( tr("Drag points to modify splines, Apply, and Execute to generate the new geometry")); } } else if(m_bMark) { m_pctrlOutput->setPlainText(" "); if (m_Pos1 == m_Pos2) return; m_Mk1 = m_Pos1; m_Mk2 = m_Pos2; pXFoil->iq1 = min(m_Pos1, m_Pos2)+1; pXFoil->iq2 = max(m_Pos1, m_Pos2)+1; if(pXFoil->iq1<=1) pXFoil->iq1 = 2; if(pXFoil->iq2>=pXFoil->n) pXFoil->iq2 = pXFoil->n-1; pXFoil->liqset = true; m_bMarked = true; m_bMark = false; m_pctrlMark->setChecked(false); } m_bGetPos = false; } } p2DWidget->setCursor(Qt::CrossCursor); UpdateView(); } /** * The user has requested to apply the spline to the velocity curve */ void QXInverse::OnApplySpline() { if(!m_bSplined) { XFoil *pXFoil = (XFoil*)m_pXFoil; int i, isp; double qscom, xx; for (i=1; isize()-1; i++) { xx = m_pMCurve->x[i]; if (xx > m_Spline.m_CtrlPoint.first().x && xx < m_Spline.m_CtrlPoint.last().x ) { //interpolate spline at xx m_pMCurve->y[i] = m_Spline.GetY(xx); } } for (i=1; isize()-1; i++) { m_pReflectedCurve->y[i] = -m_pMCurve->y[i]; } m_bSplined = true; for (i=1; i<= pXFoil->nsp; i++) { isp = pXFoil->nsp - i + 1; qscom = pXFoil->qinf*m_pMCurve->y[i-1]; pXFoil->qspec[1][i] = qincom(qscom,pXFoil->qinf,pXFoil->tklam); } pXFoil->lqspec = false; UpdateView(); } if(m_bZoomPlus) ReleaseZoom(); // m_bSpline = false; m_nPos = 0; m_tmpPos = -1; m_Pos1 = -1; m_Pos2 = -1; UpdateView(); // m_ctrlShowSpline.Invalidate(); } /** * Not sure - refer to XFoil documentation */ void QXInverse::OnCpxx() { XFoil *pXFoil = (XFoil*)m_pXFoil; CancelSpline(); CancelSmooth(); CancelMark(); if (m_bZoomPlus) ReleaseZoom(); pXFoil->lcpxx = m_pctrlCpxx->isChecked(); } /** * The user has requested the execution of the modification */ void QXInverse::OnExecute() { if (m_bZoomPlus) ReleaseZoom(); XFoil *pXFoil = (XFoil*)m_pXFoil; CancelSpline(); CancelSmooth(); CancelMark(); if(m_bFullInverse) { SetTAngle(m_pctrlTAngle->Value()); SetTGap(m_pctrlTGapx->Value(),m_pctrlTGapy->Value()); m_pctrlOutput->setPlainText(" "); ExecMDES(); } else { pXFoil->niterq = m_pctrlIter->Value(); m_pctrlMOutput->setPlainText(" "); ExecQDES(); } UpdateView(); } /** * Extracts a Foil from the database for display and modification */ void QXInverse::OnExtractFoil() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; FoilSelectionDlg dlg(this); dlg.m_poaFoil = m_poaFoil; dlg.InitDialog(); if(m_bLoaded) { dlg.m_FoilName = m_pRefFoil->m_FoilName; } if(QDialog::Accepted == dlg.exec()) { m_bMark = false; m_bMarked = false; m_bSpline = false; m_bSplined = true; Foil *pFoil; pFoil = MainFrame::foil(dlg.m_FoilName); pMainFrame->SetCurrentFoil(pFoil); m_pRefFoil->CopyFoil(pFoil); m_pModFoil->m_FoilName = m_pRefFoil->m_FoilName + tr(" Modified"); InitXFoil(m_pRefFoil); SetFoil(); UpdateView(); } } /** * Applies a Hanning type filter to the veolocty curve */ void QXInverse::OnFilter() { XFoil *pXFoil = (XFoil*)m_pXFoil; CancelSpline(); if (m_bZoomPlus) ReleaseZoom(); double filt = m_pctrlFilterParam->Value(); pXFoil->Filter(filt); CreateMCurve(); UpdateView(); } /** *The user has requested an edition of the graph settings */ void QXInverse::OnGraphSettings() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; GraphDlg *m_pGraphDlg = new GraphDlg(pMainFrame); m_pGraphDlg->m_iGraphType = 31; m_pGraphDlg->m_XSel = 0; m_pGraphDlg->m_YSel = 0; m_pGraphDlg->m_pGraph = &m_QGraph; QGraph graph; graph.CopySettings(&m_QGraph); m_pGraphDlg->m_pMemGraph = &m_QGraph; m_pGraphDlg->m_pGraph = &m_QGraph; m_pGraphDlg->SetParams(); if(m_pGraphDlg->exec() == QDialog::Accepted) { } else { m_QGraph.CopySettings(&graph); } UpdateView(); } /** * The user has requested the insertion of a new control point in the Spline object at the mouse position */ void QXInverse::OnInsertCtrlPt() { double xd = m_QGraph.ClientTox(m_ptPopUp.x()); double yd = m_QGraph.ClientToy(m_ptPopUp.y()); if(xd < m_Spline.m_CtrlPoint.first().x) return; if(xd > m_Spline.m_CtrlPoint.last().x) return; m_Spline.InsertPoint(xd,yd); m_Spline.SplineKnots(); m_Spline.SplineCurve(); UpdateView(); } /** * The user has toggled between full-inverse and mixed-inverse applications */ void QXInverse::OnInverseApp() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; m_bFullInverse = pMainFrame->m_pctrlFullInverse->isChecked(); if(m_bFullInverse) { m_pctrlStackedInv->setCurrentIndex(0); } else { m_pctrlStackedInv->setCurrentIndex(1); } SetFoil(); UpdateView(); } /** * The user has requested a modification of the styles of the curves */ void QXInverse::OnInverseStyles() { InverseOptionsDlg *m_pXInverseStyleDlg = new InverseOptionsDlg((MainFrame*)s_pMainFrame); m_pXInverseStyleDlg->m_pXInverse = this; m_pXInverseStyleDlg->InitDialog(); m_pXInverseStyleDlg->exec(); } /** * The user has requested to mark a segment for modification on the curve */ void QXInverse::OnMarkSegment() { CancelSpline(); CancelSmooth(); if (m_bZoomPlus) ReleaseZoom(); if(m_pctrlMark->isChecked()) m_pctrlMOutput->setPlainText(tr("Mark target segment for modification")); m_tmpPos = -1; m_bMark = true; m_bMarked = false; m_bSpline = false; m_bGetPos = true; m_nPos = 0; m_pctrlMNewSpline->setChecked(false); m_pctrlMShowSpline->setChecked(false); UpdateView(); } /** * The user has requested the creation of a new spline to define the modification of the velocity curve */ void QXInverse::OnNewSpline() { ReleaseZoom(); if((m_bFullInverse && m_pctrlNewSpline->isChecked()) || (!m_bFullInverse && m_pctrlMNewSpline->isChecked())) { CancelSmooth(); CancelMark(); m_pctrlOutput->setPlainText(tr("Mark spline endpoints")); m_bSpline = true; m_bSplined = false; if(m_bFullInverse) m_pctrlShowSpline->setChecked(true); else m_pctrlMShowSpline->setChecked(true); m_bSmooth = false; m_bGetPos = true; m_nPos = 0; m_tmpPos = -1; m_Pos1 = -1; m_Pos2 = -1; } else { CancelSpline(); } UpdateView(); } /** * @todo check The user has requested the launch of the interface to define the perturbation to the curve */ void QXInverse::OnPertubate() { XFoil *pXFoil = (XFoil*)m_pXFoil; int m; pXFoil->pert_init(1); PertDlg PerturbDlg((MainFrame*)s_pMainFrame); for (m=0; m<=qMin(32, pXFoil->nc); m++) { PerturbDlg.m_cnr[m] = (double)real(pXFoil->cn[m]); PerturbDlg.m_cni[m] = (double)imag(pXFoil->cn[m]); } PerturbDlg.m_nc = qMin(32, pXFoil->nc); PerturbDlg.InitDialog(); if(PerturbDlg.exec() == QDialog::Accepted) { for (m=0; m<=qMin(32, pXFoil->nc); m++) { pXFoil->cn[m] = complex(PerturbDlg.m_cnr[m], PerturbDlg.m_cni[m]); } pXFoil->pert_process(1); CreateMCurve(); m_pMCurve->SetVisible(true); UpdateView(); } } /** Toggles the visibility of the reference curve */ void QXInverse::OnQInitial() { m_pQCurve->SetVisible(!m_pQCurve->IsVisible()); CheckActions(); UpdateView(); } /** Toggles the visibility of the specification curve */ void QXInverse::OnQSpec() { m_pMCurve->SetVisible(!m_pMCurve->IsVisible()); CheckActions(); UpdateView(); } /** Toggles the visibility of the viscous curve */ void QXInverse::OnQViscous() { XFoil *pXFoil = (XFoil*)m_pXFoil; if(pXFoil->lvisc) { m_pQVCurve->SetVisible(!m_pQVCurve->IsVisible()); UpdateView(); } CheckActions(); } /** Toggles the visibility of the curve's points */ void QXInverse::OnQPoints() { m_bShowPoints = !m_bShowPoints; m_pQCurve->ShowPoints(m_bShowPoints); m_pMCurve->ShowPoints(m_bShowPoints); CheckActions(); UpdateView(); } /** Toggles the visibility of the reflected curve */ void QXInverse::OnQReflected() { m_bReflected = !m_bReflected; m_pReflectedCurve->SetVisible(m_bReflected); CheckActions(); UpdateView(); } /** Resets the specification curve */ void QXInverse::OnQReset() { CancelSpline(); CancelSmooth(); CancelMark(); ReleaseZoom(); if(m_bFullInverse) ResetQ(); else ResetMixedQ(); UpdateView(); } /** * The user has requested to remove the selected control point from the spline */ void QXInverse::OnRemoveCtrlPt() { if (m_Spline.m_iHighlight>=0) { if(!m_Spline.RemovePoint(m_Spline.m_iHighlight)) { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QMessageBox::warning(pMainFrame,tr("Warning"), tr("The minimum number of control points has been reached for this spline degree")); return; } } m_Spline.SplineCurve(); UpdateView(); } /** The user has requested a reset of the Foil scale */ void QXInverse::OnResetFoilScale() { ReleaseZoom(); ResetScale(); UpdateView(); } /** * The user has toggled between aoa and lift coefficient as the input parameter */ void QXInverse::OnSpecal() { XFoil *pXFoil = (XFoil*)m_pXFoil; if(m_pctrlSpecAlpha->isChecked()) { m_pctrlSpecif->setText(tr("Alpha = ")); m_pctrlSpec->SetPrecision(2); m_pctrlSpec->SetValue(pXFoil->alqsp[1]*180.0/PI); } else { m_pctrlSpecif->setText(tr("Cl = ")); m_pctrlSpec->SetPrecision(3); m_pctrlSpec->SetValue(pXFoil->clqsp[1]); } } /** * The user has modified the value of the aoa or lift coefficient */ void QXInverse::OnSpecInv() { if (m_bZoomPlus) ReleaseZoom(); XFoil *pXFoil = (XFoil*)m_pXFoil; if(m_pctrlSpecAlpha->isChecked()) { pXFoil->alqsp[1] = m_pctrlSpec->Value()*PI/180.0; pXFoil->iacqsp = 1; pXFoil->qspcir(); } else if(m_pctrlSpecCl->isChecked()) { pXFoil->clqsp[1] = m_pctrlSpec->Value(); pXFoil->iacqsp = 2; pXFoil->qspcir(); } CreateQCurve(); CreateMCurve(); UpdateView(); } /** The user has toggled the spline display */ void QXInverse::OnShowSpline() { if(m_bFullInverse) m_bSpline = m_pctrlShowSpline->isChecked(); else m_bSpline = m_pctrlMShowSpline->isChecked(); m_bSplined = !m_bSpline; UpdateView(); } /** The user has requested a smoothing operation on the curve */ void QXInverse::OnSmooth() { CancelSpline(); if(m_pctrlSmooth->isChecked()) { m_pctrlOutput->setPlainText(tr("Mark target segment for smoothing, or type 'Return' to smooth the entire distribution")); m_bSpline = false; m_bSmooth = true; UpdateView(); m_bGetPos = true; m_nPos = 0; } else CancelSmooth(); } /** * The user has requested the storage of the modified Foil in the database */ void QXInverse::OnStoreFoil() { if(!m_bLoaded) return; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; Foil* pFoil = new Foil(); pFoil->CopyFoil(m_pModFoil); pFoil->m_nFoilStyle = 0; pFoil->m_nFoilWidth = 1; memcpy(pFoil->xb, m_pModFoil->x, sizeof(m_pModFoil->x)); memcpy(pFoil->yb, m_pModFoil->y, sizeof(m_pModFoil->y)); pFoil->nb = m_pModFoil->n; pFoil->m_FoilName = m_pRefFoil->m_FoilName; pMainFrame->SetModFoil(pFoil); } /** The user has toggled the symetric requirement for the foil*/ void QXInverse::OnSymm() { CancelSpline(); if (m_bZoomPlus) ReleaseZoom(); XFoil *pXFoil = (XFoil*)m_pXFoil; pXFoil->lqsym = m_pctrlSymm->isChecked(); pXFoil->lqspec = false; } /** The user has requested to zoom in on a part of the display */ void QXInverse::OnZoomIn() { if(!m_bZoomPlus) { if(m_fScale/m_fRefScale <32.0) { m_bZoomPlus = true; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->InverseZoomIn->setChecked(true); } else { ReleaseZoom(); } } else { ReleaseZoom(); } } /** The user has requested to zoom the x-axis only */ void QXInverse::OnZoomX() { ReleaseZoom(); m_bZoomYOnly = false; m_bZoomXOnly = !m_bZoomXOnly; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->InverseZoomX->setChecked(m_bZoomXOnly); pMainFrame->InverseZoomY->setChecked(m_bZoomYOnly); } /** The user has requested to zoom the y-axis only */ void QXInverse::OnZoomY() { ReleaseZoom(); m_bZoomXOnly = false; m_bZoomYOnly = !m_bZoomYOnly; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->InverseZoomX->setChecked(m_bZoomXOnly); pMainFrame->InverseZoomY->setChecked(m_bZoomYOnly); } /** The user has toggled the requirement for a spline tangent to the specification curve */ void QXInverse::OnTangentSpline() { if(m_bFullInverse) m_bTangentSpline = m_pctrlTangentSpline->isChecked(); else m_bTangentSpline = m_pctrlMTangentSpline->isChecked(); m_pctrlTangentSpline->setChecked(m_bTangentSpline); m_pctrlMTangentSpline->setChecked(m_bTangentSpline); } /** * Draws the graph * @param painter a reference to the QPainter object with which to draw */ void QXInverse::PaintGraph(QPainter &painter) { painter.save(); // draw the graph if(m_rGraphRect.width()>200 && m_rGraphRect.height()>150) { m_QGraph.DrawGraph(painter); QPoint Place((int)(m_rGraphRect.right()-300), m_rGraphRect.top()+12); m_QGraph.DrawLegend(painter, Place, MainFrame::s_TextFont, MainFrame::s_TextColor); } // draw the zoom rectangle, if relevant QRect ZRect = m_ZoomRect.normalized(); if(m_bZoomPlus && !ZRect.isEmpty()) { QPen ZoomPen(QColor(100,100,100)); ZoomPen.setStyle(Qt::DashLine); painter.setPen(ZoomPen); painter.drawRect(ZRect); } //Draw spline, if any if(m_bSpline && !m_bGetPos) { QPoint pt = m_QGraph.GetOffset(); m_Spline.DrawSpline(painter, 1.0/m_QGraph.GetXScale(), -1.0/m_QGraph.GetYScale(), pt); m_Spline.DrawCtrlPoints(painter, 1.0/m_QGraph.GetXScale(), -1.0/m_QGraph.GetYScale(), pt); } // Highlight selected points, if any if(m_bGetPos) { QPoint pt; //QRect r; m_QGraph.Highlight(painter, m_pMCurve,m_tmpPos); if(m_nPos>=1) m_QGraph.Highlight(painter, m_pMCurve, m_Pos1); if(m_nPos>=2) m_QGraph.Highlight(painter, m_pMCurve, m_Pos2); } // Show marked segment if mixed-inverse design if(m_bMarked) { QPoint ptl, ptr; ptl.rx() = m_QGraph.xToClient(m_pMCurve->x[m_Mk1]); ptr.rx() = m_QGraph.xToClient(m_pMCurve->x[m_Mk2]); ptl.ry() = m_QGraph.yToClient(m_pMCurve->y[m_Mk1]); ptr.ry() = m_QGraph.yToClient(m_pMCurve->y[m_Mk2]); QPen MarkPen(QColor(175,30,30)); MarkPen.setStyle(Qt::SolidLine); MarkPen.setWidth(2); painter.setPen(MarkPen); if(m_rGraphRect.contains(ptl)) { painter.drawLine(ptl.x(), ptl.y()-20, ptl.x(), ptl.y()+20); } if(m_rGraphRect.contains(ptr)) { painter.drawLine(ptr.x(), ptr.y()-20, ptr.x(), ptr.y()+20); } } painter.restore(); } /** * Draws the Foil * @param painter a reference to the QPainter object with which to draw */ void QXInverse::PaintFoil(QPainter &painter) { painter.save(); QString str,str1,str2; // draw the scale/grid if(m_bModFoil || m_bRefFoil) { DrawGrid(painter, m_fScale); } //draw the reference and modified foils XFoil *pXFoil = (XFoil*)m_pXFoil; double alpha = pXFoil->alqsp[1]*180./PI; QPen TextPen(MainFrame::s_TextColor); if(m_bRefFoil && m_bLoaded) { QPen FoilPen(m_pRefFoil->m_FoilColor); FoilPen.setStyle(GetStyle(m_pRefFoil->m_nFoilStyle)); FoilPen.setWidth(m_pRefFoil->m_nFoilWidth); painter.setPen(FoilPen); m_pRefFoil->DrawFoil(painter, -alpha, m_fScale, m_fScale, m_ptOffset); painter.drawLine(20, m_rGraphRect.bottom()+20, 40, m_rGraphRect.bottom()+20); painter.setPen(TextPen); painter.drawText(50, m_rGraphRect.bottom()+25, m_pRefFoil->m_FoilName); } if(m_bModFoil && m_bLoaded) { QPen ModPen(m_pModFoil->m_FoilColor); ModPen.setStyle(GetStyle(m_pModFoil->m_nFoilStyle)); ModPen.setWidth(m_pModFoil->m_nFoilWidth); painter.setPen(ModPen); m_pModFoil->DrawFoil(painter, -alpha, m_fScale, m_fScale, m_ptOffset); painter.drawLine(20, m_rGraphRect.bottom()+35, 40, m_rGraphRect.bottom()+35); painter.setPen(TextPen); painter.drawText(50, m_rGraphRect.bottom()+40, m_pModFoil->m_FoilName); } if (m_pRefFoil->m_bPoints) { QPen CtrlPen(m_pRefFoil->m_FoilColor); CtrlPen.setStyle(GetStyle(m_pRefFoil->m_nFoilStyle)); CtrlPen.setWidth(m_pRefFoil->m_nFoilWidth); painter.setPen(CtrlPen); m_pRefFoil->DrawPoints(painter, 1.0, 1.0, m_ptOffset); } painter.setFont(MainFrame::s_TextFont); QFontMetrics fm(MainFrame::s_TextFont); int dD = fm.height(); int Back = 4; int LeftPos = m_rCltRect.left()+10; int ZPos = m_rCltRect.bottom() - 10 - Back*dD; int D = 0; str = tr(" Base"); if(m_bModFoil && m_bLoaded) str +=tr(" Mod."); painter.drawText(LeftPos,ZPos+D, str); D += dD; str1 = QString(tr("Thickness = %1%")).arg(m_pRefFoil->m_fThickness*100.0, 6, 'f', 2); if(m_bModFoil && m_bLoaded) str2 = QString(" %1%").arg(m_pModFoil->m_fThickness*100.0, 6, 'f', 2); else str2 = ""; painter.drawText(LeftPos,ZPos+D, str1+str2); D += dD; str1 = QString(tr("Max.Thick.pos. = %1%")).arg(m_pRefFoil->m_fXThickness*100.0, 6, 'f', 2); if(m_bModFoil && m_bLoaded) str2 = QString(" %1%").arg(m_pModFoil->m_fXThickness*100.0, 6, 'f', 2); else str2 = ""; painter.drawText(LeftPos,ZPos+D, str1+str2); D += dD; str1 = QString(tr("Max. Camber = %1%")).arg( m_pRefFoil->m_fCamber*100.0, 6, 'f', 2); if(m_bModFoil && m_bLoaded) str2 = QString(" %1%").arg(m_pModFoil->m_fCamber*100.0, 6, 'f', 2); else str2 = ""; painter.drawText(LeftPos,ZPos+D, str1+str2); D += dD; str1 = QString(tr("Max.Thick.pos. = %1%")).arg(m_pRefFoil->m_fXCamber*100.0, 6, 'f', 2); if(m_bModFoil && m_bLoaded) str2 = QString(" %1%").arg(m_pModFoil->m_fXCamber*100.0, 6, 'f', 2); else str2 = ""; painter.drawText(LeftPos,ZPos+D, str1+str2); D += dD; painter.restore(); } /** Paints the view * @param painter a reference to the QPainter object with which to draw */ void QXInverse::PaintView(QPainter &painter) { painter.save(); painter.fillRect(m_rCltRect, MainFrame::s_BackgroundColor); PaintGraph(painter); PaintFoil(painter); painter.restore(); } /** * ------------------------------------- * XFoil source code: sets incompressible speed from karman-tsien compressible speed *------------------------------------- */ double QXInverse::qincom(double qc, double qinf, double tklam) { //------------------------------------- // sets incompressible speed from // karman-tsien compressible speed //------------------------------------- if(tklam<1.0e-4 || qAbs(qc)<1.0e-4) { //----- for nearly incompressible case or very small speed, use asymptotic // expansion of singular quadratic formula to avoid numerical problems return( qc/(1.0 - tklam)); } else { //----- use quadratic formula for typical case double tmp = 0.5*(1.0 - tklam)*qinf/(qc*tklam); return (qinf*tmp*((double)sqrt(1.0 + 1.0/(tklam*tmp*tmp)) - 1.0)); } } /** * Ends the zoom-in process */ void QXInverse::ReleaseZoom() { m_bZoomPlus = false; m_ZoomRect.setRight(m_ZoomRect.left()-1); m_ZoomRect.setTop(m_ZoomRect.bottom()+1); MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->InverseZoomIn->setChecked(false); } /** * Resets the mixed inverse specification curve */ void QXInverse::ResetMixedQ() { m_pMCurve->clear(); for (int i=0; i<=m_pQCurve->size(); i++) { m_pMCurve->AppendPoint(m_pQCurve->x[i], m_pQCurve->y[i]); } // m_pXFoil->gamqsp(1); // CreateMCurve(); } /** * Resets the reference velocity curve */ void QXInverse::ResetQ() { XFoil *pXFoil = (XFoil*)m_pXFoil; pXFoil->cncalc(pXFoil->qgamm,false); pXFoil->qspcir(); CreateMCurve(); UpdateView(); } /** * Resets the Foil scale */ void QXInverse::ResetScale() { int h4 = m_rCltRect.height()/4; m_ptOffset.rx() = m_rGraphRect.left() +(int)(1.0*m_QGraph.GetMargin()); m_fRefScale = m_rGraphRect.width()-2.0*m_QGraph.GetMargin(); m_ptOffset.ry() = m_rCltRect.bottom()-h4/2; m_fScale = m_fRefScale; } /** * Saves the user settings * @param pSettings a pointer to the QSetting object. */ void QXInverse::SaveSettings(QSettings *pSettings) { pSettings->beginGroup("XInverse"); { pSettings->setValue("FullInverse", m_bFullInverse); pSettings->setValue("SplineColor", m_Spline.color()); pSettings->setValue("SplineStyle", m_Spline.style()); pSettings->setValue("SplineWdth", m_Spline.width()); pSettings->setValue("BaseFoilColor", m_pRefFoil->m_FoilColor); pSettings->setValue("BaseFoilStyle", m_pRefFoil->m_nFoilStyle); pSettings->setValue("BaseFoilWidth", m_pRefFoil->m_nFoilWidth); pSettings->setValue("ModFoilColor", m_pModFoil->m_FoilColor); pSettings->setValue("ModFoilStyle", m_pModFoil->m_nFoilStyle); pSettings->setValue("ModFoilWidth", m_pModFoil->m_nFoilWidth); } pSettings->endGroup(); m_QGraph.SaveSettings(pSettings); } /** * Initializes the interface with the selected foil */ void QXInverse::SetFoil() { int i; XFoil *pXFoil = (XFoil*)m_pXFoil; QString strong; for(i=1; i<=pXFoil->n; i++) { m_pModFoil->x[i-1] = pXFoil->x[i]; m_pModFoil->y[i-1] = pXFoil->y[i]; } m_pModFoil->n = pXFoil->n; if(m_bFullInverse) { pXFoil->InitMDES(); CreateQCurve(); CreateMCurve(); m_pctrlSpec->SetValue(pXFoil->alqsp[1]*180.0/PI); m_pctrlTAngle->SetValue(pXFoil->agte*180.0);//agte expressed in PI units:!?!? m_pctrlTGapx->SetValue(real(pXFoil->dzte)); m_pctrlTGapy->SetValue(imag(pXFoil->dzte)); } else { // Mixed Inverse pXFoil->InitQDES(); CreateQCurve(); CreateMCurve(); strong = QString(tr("Alpha = %1")).arg(pXFoil->algam/pXFoil->dtor,0,'f',3); m_pctrlMAlphaSpec->setText(strong); strong = QString(tr("Cl = %1")).arg(pXFoil->clgam,0,'f',3); m_pctrlMClSpec->setText(strong); m_pctrlIter->SetValue(pXFoil->niterq); } if(pXFoil->lvisc) { //a previous xfoil calculation is still active, so add the associated viscous curve double x,y; double dsp, dqv, sp1, sp2, qv1, qv2; m_pQVCurve->clear(); for(i=2; i<= pXFoil->n; i++) { dsp = pXFoil->s[i] - pXFoil->s[i-1]; dqv = pXFoil->qcomp(pXFoil->qvis[i]) - pXFoil->qcomp(pXFoil->qvis[i-1]); sp1 = (pXFoil->s[i-1] + 0.25*dsp)/pXFoil->s[pXFoil->n]; sp2 = (pXFoil->s[i] - 0.25*dsp)/pXFoil->s[pXFoil->n]; qv1 = pXFoil->qcomp(pXFoil->qvis[i-1]) + 0.25*dqv; qv2 = pXFoil->qcomp(pXFoil->qvis[i] ) - 0.25*dqv; x = 1.0 - sp1; y = qv1/pXFoil->qinf; m_pQVCurve->AppendPoint(x,y); x = 1.0 - sp2; y = qv2/pXFoil->qinf; m_pQVCurve->AppendPoint(x,y); } m_pQVCurve->SetVisible(true); } else { m_pQVCurve->SetVisible(false); } m_bLoaded = true; } /** * Initializes the widgets with the active data * @return */ bool QXInverse::SetParams() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; XFoil *pXFoil = (XFoil*)m_pXFoil; Foil*pFoil; if(m_bFullInverse) { pMainFrame->m_pctrlFullInverse->setChecked(true); pMainFrame->m_pctrlMixedInverse->setChecked(false); m_pctrlStackedInv->setCurrentIndex(0); } else { pMainFrame->m_pctrlFullInverse->setChecked(false); pMainFrame->m_pctrlMixedInverse->setChecked(true); m_pctrlStackedInv->setCurrentIndex(1); } m_pQCurve->SetColor(m_pRefFoil->m_FoilColor); m_pQCurve->SetStyle(m_pRefFoil->m_nFoilStyle); m_pQCurve->SetWidth(m_pRefFoil->m_nFoilWidth); m_pMCurve->SetColor(m_pModFoil->m_FoilColor); m_pMCurve->SetStyle(m_pModFoil->m_nFoilStyle); m_pMCurve->SetWidth(m_pModFoil->m_nFoilWidth); m_pQCurve->SetTitle(tr("Q - Reference")); m_pMCurve->SetTitle(tr("Q - Specification")); m_pQVCurve->SetTitle(tr("Q - Viscous")); m_pQVCurve->SetColor(QColor(50,170,0)); m_pQVCurve->SetStyle(0); m_pReflectedCurve->SetColor(m_ReflectedClr); m_pReflectedCurve->SetStyle(m_ReflectedStyle); m_pReflectedCurve->SetWidth(m_ReflectedWidth); m_pReflectedCurve->SetTitle(tr("Reflected")); m_bTrans = false; m_bSpline = false; m_bSplined = true; m_bRefFoil = true; m_bModFoil = false; m_bGetPos = false; m_bMark = false; m_bMarked = false; m_bSmooth = false; m_QGraph.SetDrawRect(m_rGraphRect); m_QGraph.Init(); m_pQCurve->SetVisible(true); m_pctrlSpecAlpha->setChecked(true); OnSpecal(); //is a foil set as current in the mainframe ? if (MainFrame::s_pCurFoil && pXFoil->m_FoilName==MainFrame::s_pCurFoil->m_FoilName && pXFoil->lqspec) { m_pRefFoil->CopyFoil(MainFrame::s_pCurFoil); m_pRefFoil->m_FoilColor = m_pQCurve->color(); // m_pXFoil->m_FoilName = m_pRefFoil->m_FoilName ; // InitXFoil(m_pRefFoil); } else if(!pXFoil->m_FoilName.length()) { // XFoil is not initialized //is there anything in the database ? if(m_poaFoil->size()) { pFoil = (Foil*)m_poaFoil->at(0); m_pRefFoil->CopyFoil(pFoil); m_pRefFoil->m_FoilColor = m_pQCurve->color(); pXFoil->m_FoilName = m_pRefFoil->m_FoilName ; InitXFoil(m_pRefFoil); } else { //nothing to initialize if(m_bFullInverse) { m_pctrlSpec->SetValue(0.0); m_pctrlTAngle->SetValue(0.0); m_pctrlTGapx->SetValue(0.0); m_pctrlTGapy->SetValue(0.0); } else { m_pctrlIter->SetValue(pXFoil->niterq); } Clear(); CheckActions(); return false; } } //XFOIL has already been initialized so retrieve the foil for (int i=1; i<=pXFoil->n; i++) { m_pRefFoil->x[i-1] = pXFoil->x[i]; m_pRefFoil->y[i-1] = pXFoil->y[i]; m_pRefFoil->xb[i-1] = pXFoil->x[i]; m_pRefFoil->yb[i-1] = pXFoil->y[i]; } m_pRefFoil->n = pXFoil->n; m_pRefFoil->nb = pXFoil->n; m_pRefFoil->m_FoilName = pXFoil->m_FoilName; m_pRefFoil->InitFoil(); m_pModFoil->m_FoilName = pXFoil->m_FoilName + tr(" Modified"); SetFoil(); CheckActions(); return true; } /** * Sets the scale for the Foil and QGraph display * @param CltRect the client area */ void QXInverse::SetScale(QRect CltRect) { m_rCltRect = CltRect; int h = CltRect.height(); int h4 = (int)(h/3.0); int w = CltRect.width(); int w20 = (int)(w/20); m_rGraphRect = QRect(w20, 10, + m_rCltRect.width()-2*w20, m_rCltRect.height()-h4); m_QGraph.SetMargin(50); m_QGraph.SetDrawRect(m_rGraphRect); ResetScale(); } /** * Sets the angle at the trailing edge * @param a the angle in degrees */ void QXInverse::SetTAngle(double a) { XFoil *pXFoil = (XFoil*)m_pXFoil; pXFoil->agte = a/180.0; } /** * Sets the trailing edge gap. */ void QXInverse::SetTGap(double tr, double ti) { XFoil *pXFoil = (XFoil*)m_pXFoil; pXFoil->dzte = complex(tr,ti); } /** * Sets up the interface */ void QXInverse::SetupLayout() { // QDesktopWidget desktop; // QRect r = desktop.geometry(); // setMinimumHeight(r.height()/3); // move(r.width()/3, r.height()/6); QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::Expanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Expanding); QSizePolicy szPolicyMinimum; szPolicyMinimum.setHorizontalPolicy(QSizePolicy::Minimum); szPolicyMinimum.setVerticalPolicy(QSizePolicy::Minimum); QSizePolicy szPolicyMaximum; szPolicyMaximum.setHorizontalPolicy(QSizePolicy::Maximum); szPolicyMaximum.setVerticalPolicy(QSizePolicy::Maximum); setSizePolicy(szPolicyMaximum); QGridLayout *SpecLayout = new QGridLayout; m_pctrlSpecAlpha = new QRadioButton(tr("Alpha")); m_pctrlSpecCl = new QRadioButton(tr("Cl")); m_pctrlSpecif = new QLabel(tr("Alpha = ")); m_pctrlSpecif->setAlignment(Qt::AlignVCenter | Qt::AlignRight); m_pctrlSpec = new DoubleEdit(1.23); SpecLayout->addWidget(m_pctrlSpecAlpha,1,1); SpecLayout->addWidget(m_pctrlSpecCl,1,2); SpecLayout->addWidget(m_pctrlSpecif,2,1); SpecLayout->addWidget(m_pctrlSpec,2,2); QGroupBox *SpecBox = new QGroupBox(tr("Specification")); SpecBox->setLayout(SpecLayout); QGridLayout *ModLayout = new QGridLayout; m_pctrlShowSpline = new QCheckBox(tr("ShowSpline")); m_pctrlTangentSpline = new QCheckBox(tr("Tangent Spline")); m_pctrlNewSpline = new QPushButton(tr("New Spline")); m_pctrlApplySpline = new QPushButton(tr("Apply Spline")); m_pctrlResetQSpec = new QPushButton(tr("Reset QSpec")); m_pctrlPert = new QPushButton(tr("Pert")); m_pctrlNewSpline->setCheckable(true); ModLayout->addWidget(m_pctrlShowSpline,1,1); ModLayout->addWidget(m_pctrlTangentSpline,1,2); ModLayout->addWidget(m_pctrlNewSpline,2,1); ModLayout->addWidget(m_pctrlApplySpline,2,2); ModLayout->addWidget(m_pctrlResetQSpec,3,1); ModLayout->addWidget(m_pctrlPert,3,2); QGroupBox *ModBox = new QGroupBox(tr("Modification")); ModBox->setLayout(ModLayout); QGridLayout *SmoothLayout = new QGridLayout; m_pctrlSmooth = new QPushButton(tr("Smooth QSpec")); m_pctrlFilter = new QPushButton(tr("Hannig Filter")); QLabel *lab0 = new QLabel(tr("Filter parameter")); lab0->setAlignment(Qt::AlignVCenter | Qt::AlignRight); m_pctrlFilterParam = new DoubleEdit(2.34); SmoothLayout->addWidget(m_pctrlSmooth,1,1); SmoothLayout->addWidget(m_pctrlFilter,1,2); SmoothLayout->addWidget(lab0,2,1); SmoothLayout->addWidget(m_pctrlFilterParam,2,2); QGroupBox *SmoothBox = new QGroupBox(tr("Smoothing")); SmoothBox->setLayout(SmoothLayout); QGridLayout *TELayout = new QGridLayout; QLabel *lab1 = new QLabel(tr("T.E. Angle")); QLabel *lab2 = new QLabel(tr("T.E. Gap dx/c")); QLabel *lab3 = new QLabel(tr("T.E. Gap dy/c")); lab1->setAlignment(Qt::AlignVCenter | Qt::AlignRight); lab2->setAlignment(Qt::AlignVCenter | Qt::AlignRight); lab3->setAlignment(Qt::AlignVCenter | Qt::AlignRight); m_pctrlTAngle = new DoubleEdit(3.681); m_pctrlTGapx = new DoubleEdit(0.001); m_pctrlTGapy = new DoubleEdit(0.002); m_pctrlTAngle->SetPrecision(3); m_pctrlTGapx->SetPrecision(3); m_pctrlTGapy->SetPrecision(3); TELayout->addWidget(lab1,1,1); TELayout->addWidget(lab2,2,1); TELayout->addWidget(lab3,3,1); TELayout->addWidget(m_pctrlTAngle,1,2); TELayout->addWidget(m_pctrlTGapx,2,2); TELayout->addWidget(m_pctrlTGapy,3,2); m_pctrlSymm = new QCheckBox(tr("Symmetric foil")); QVBoxLayout *ConstraintsLayout = new QVBoxLayout; ConstraintsLayout->addLayout(TELayout); ConstraintsLayout->addWidget(m_pctrlSymm); QGroupBox *ConstraintsBox = new QGroupBox(tr("Constraints")); ConstraintsBox->setLayout(ConstraintsLayout); m_pctrlExec = new QPushButton(tr("Execute")); m_pctrlOutput = new QTextEdit(" "); m_pctrlOutput->setEnabled(false); QVBoxLayout *FInvLayout = new QVBoxLayout; FInvLayout->addWidget(SpecBox); FInvLayout->addWidget(ModBox); FInvLayout->addWidget(SmoothBox); FInvLayout->addWidget(ConstraintsBox); FInvLayout->addWidget(m_pctrlExec); FInvLayout->addWidget(m_pctrlOutput); FInvLayout->addStretch(1); m_pctrlFInvWidget = new QWidget(this); m_pctrlFInvWidget->setLayout(FInvLayout); //specific MInv Controls m_pctrlMAlphaSpec = new QLineEdit(tr("Alpha = ")); m_pctrlMClSpec = new QLineEdit(tr("Cl =")); m_pctrlMAlphaSpec->setEnabled(false); m_pctrlMClSpec->setEnabled(false); QHBoxLayout *MSpecLayout = new QHBoxLayout; MSpecLayout->addWidget(m_pctrlMAlphaSpec); MSpecLayout->addWidget(m_pctrlMClSpec); m_pctrlIter = new DoubleEdit(11); m_pctrlMark = new QPushButton(tr("Mark for modification")); m_pctrlCpxx = new QCheckBox(tr("End Point Constraint")); m_pctrlMExec = new QPushButton(tr("Execute")); m_pctrlMOutput = new QTextEdit(tr(" ")); m_pctrlMShowSpline = new QCheckBox(tr("ShowSpline")); m_pctrlMTangentSpline = new QCheckBox(tr("Tangent Spline")); m_pctrlMNewSpline = new QPushButton(tr("New Spline")); m_pctrlMApplySpline = new QPushButton(tr("Apply Spline")); m_pctrlMSmooth = new QPushButton(tr("Smooth")); m_pctrlMResetQSpec = new QPushButton(tr("Reset QSpec")); m_pctrlMNewSpline->setCheckable(true); m_pctrlMark->setCheckable(true); m_pctrlMOutput->setEnabled(false); QGridLayout *MSplineslayout = new QGridLayout; MSplineslayout->addWidget(m_pctrlMShowSpline,1,1); MSplineslayout->addWidget(m_pctrlMTangentSpline,1,2); MSplineslayout->addWidget(m_pctrlMNewSpline,2,1); MSplineslayout->addWidget(m_pctrlMApplySpline,2,2); MSplineslayout->addWidget(m_pctrlMark,3,1,1,2); MSplineslayout->addWidget(m_pctrlMSmooth,4,1); MSplineslayout->addWidget(m_pctrlMResetQSpec,4,2); QGroupBox *MSplinesBox = new QGroupBox(tr("Modification")); MSplinesBox->setLayout(MSplineslayout); QVBoxLayout *FoilLayout = new QVBoxLayout; FoilLayout->addWidget(m_pctrlCpxx); FoilLayout->addWidget(m_pctrlMExec); QHBoxLayout *MaxIter = new QHBoxLayout; QLabel *lab10 = new QLabel(tr("Max Iterations")); MaxIter->addWidget(lab10); MaxIter->addWidget(m_pctrlIter); FoilLayout->addLayout(MaxIter); QGroupBox *FoilBox = new QGroupBox(tr("Foil")); FoilBox->setLayout(FoilLayout); QVBoxLayout *MInvLayout = new QVBoxLayout; MInvLayout->addLayout(MSpecLayout); MInvLayout->addWidget(MSplinesBox); MInvLayout->addWidget(FoilBox); MInvLayout->addWidget(m_pctrlMOutput); MInvLayout->addStretch(1); m_pctrlMInvWidget = new QWidget(this); m_pctrlMInvWidget->setLayout(MInvLayout); m_pctrlStackedInv = new QStackedWidget; m_pctrlStackedInv->addWidget(m_pctrlFInvWidget); m_pctrlStackedInv->addWidget(m_pctrlMInvWidget); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addWidget(m_pctrlStackedInv); MainLayout->addStretch(1); setLayout(MainLayout); Connect(); } /** * Performs a smoothing operation of the specification cuve between two end points * @param Pos1 the first end point * @param Pos2 the seconf end point */ void QXInverse::Smooth(int Pos1, int Pos2) { XFoil *pXFoil = (XFoil*)m_pXFoil; if(Pos1 ==-1) { //smooth it all Pos1 = 1; Pos2 = pXFoil->nsp; } m_bGetPos = false; if (abs(Pos2-Pos1)<=2) return; if (Pos1>Pos2) { int tmp = Pos2; Pos2 = Pos1; Pos1 = tmp; } if(m_bFullInverse) { pXFoil->smooq(Pos1,Pos2,1); pXFoil->cncalc(pXFoil->qspec[1], false); pXFoil->qspcir(); pXFoil->lqspec = true; } else { // added v1.17, i.e. different sequence as for Full Inverse pXFoil->smooq(Pos1,Pos2,1); pXFoil->splqsp(1); pXFoil->clcalc(pXFoil->xcmref,pXFoil->ycmref); // pXFoil->lqspec = true; ?? should we } CreateMCurve(); m_bSmooth = false; CancelSmooth(); UpdateView(); } /** * Refreshes the display */ void QXInverse::UpdateView() { TwoDWidget *p2DWidget = (TwoDWidget*)s_p2DWidget; if(s_p2DWidget) { p2DWidget->update(); } } /** * Overrides the QWidget's wheelEvent method. * Dispatches the event * @param event the QMouseEvent */ void QXInverse::wheelEvent(QWheelEvent *event) { ReleaseZoom(); static double ZoomFactor; if(event->delta()>0) { if(!MainFrame::s_bReverseZoom) ZoomFactor = 1./1.06; else ZoomFactor = 1.06; } else { if(!MainFrame::s_bReverseZoom) ZoomFactor = 1.06; else ZoomFactor = 1./1.06; } QPoint pttmp(event->pos()); if(m_QGraph.IsInDrawRect(pttmp)) { if (m_bXPressed || m_bZoomXOnly) { //zoom x scale m_QGraph.SetAutoX(false); m_QGraph.Scalex(1.0/ZoomFactor); } else if(m_bYPressed || m_bZoomYOnly) { //zoom y scale m_QGraph.SetAutoY(false); m_QGraph.Scaley(1.0/ZoomFactor); } else { //zoom both m_QGraph.SetAuto(false); m_QGraph.Scale(1.0/ZoomFactor); } m_QGraph.SetAutoXUnit(); m_QGraph.SetAutoYUnit(); } else { double scale = m_fScale; if(event->delta()<0) m_fScale *= 1.06; else m_fScale /= 1.06; int a = (int)((m_rCltRect.right() + m_rCltRect.left())/2); m_ptOffset.rx() = a + (int)((m_ptOffset.x()-a)*m_fScale/scale); } UpdateView(); } xflr5-6.09-06/src/xinverse/FoilSelectionDlg.cpp000644 001750 000144 00000007130 12247174406 022622 0ustar00techwinderusers000000 000000 /**************************************************************************** FoilSelectionDlg Classes Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include "../objects/Foil.h" #include "FoilSelectionDlg.h" FoilSelectionDlg::FoilSelectionDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Foil Selection")); m_poaFoil = NULL; m_FoilName = ""; m_FoilList.clear(); SetupLayout(); } void FoilSelectionDlg::SetupLayout() { QVBoxLayout *MainLayout = new QVBoxLayout; { m_pctrlNameList = new QListWidget; m_pctrlNameList->setMinimumHeight(300); m_pctrlNameList->setSelectionMode(QAbstractItemView::MultiSelection); QHBoxLayout *CommandButtons = new QHBoxLayout; { QPushButton *OKButton = new QPushButton(tr("OK")); OKButton->setAutoDefault(false); QPushButton *CancelButton = new QPushButton(tr("Cancel")); CancelButton->setAutoDefault(false); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } MainLayout->addStretch(1); MainLayout->addWidget(m_pctrlNameList); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); } connect(m_pctrlNameList, SIGNAL(itemClicked(QListWidgetItem *)), this, SLOT(OnSelChangeList(QListWidgetItem *))); connect(m_pctrlNameList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(OnDoubleClickList(QListWidgetItem *))); setLayout(MainLayout); } void FoilSelectionDlg::OnOK() { QListWidgetItem *pItem = m_pctrlNameList->currentItem(); m_FoilName = pItem->text(); m_FoilList.clear(); for(int i=0; icount();i++) { pItem = m_pctrlNameList->item(i); if(pItem->isSelected()) { m_FoilList.append(pItem->text()); } } accept(); } void FoilSelectionDlg::OnSelChangeList(QListWidgetItem *pItem) { m_FoilName = pItem->text(); } void FoilSelectionDlg::OnDoubleClickList(QListWidgetItem *pItem) { OnOK(); } void FoilSelectionDlg::InitDialog() { if(!m_poaFoil) return; Foil *pFoil; for (int i=0; isize(); i++) { pFoil = (Foil*)m_poaFoil->at(i); m_pctrlNameList->addItem(pFoil->m_FoilName); m_pctrlNameList->setItemSelected(m_pctrlNameList->item(i), false); for(int j=0; jm_FoilName) { m_pctrlNameList->setItemSelected(m_pctrlNameList->item(i), true); break; } } // if(pFoil->m_FoilName==m_FoilName) m_pctrlNameList->setItemSelected(m_pctrlNameList->item(i), true); // else m_pctrlNameList->setItemSelected(m_pctrlNameList->item(i), false); } } xflr5-6.09-06/src/xinverse/PertDlg.cpp000644 001750 000144 00000012635 12247176330 021001 0ustar00techwinderusers000000 000000 /**************************************************************************** PertDlg class Copyright (C) 2004-2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include "PertDlg.h" PertDlg::PertDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Pertubation Dialog")); m_pXInverse = pParent; memset(m_cnr, 0, sizeof(m_cnr)); memset(m_cni, 0, sizeof(m_cni)); memset(m_backr, 0, sizeof(m_backr)); memset(m_backi, 0, sizeof(m_backi)); SetupLayout(); connect(RestoreButton, SIGNAL(clicked()),this, SLOT(OnRestore())); connect(ApplyButton, SIGNAL(clicked()),this, SLOT(OnApply())); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void PertDlg::SetupLayout() { QVBoxLayout *CommandButtons = new QVBoxLayout; RestoreButton = new QPushButton(tr("Restore")); ApplyButton = new QPushButton(tr("Apply")); OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(RestoreButton); CommandButtons->addWidget(ApplyButton); CommandButtons->addStretch(2); CommandButtons->addWidget(OKButton); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); m_pctrlCnTable = new QTableView(this); m_pctrlCnTable->setWindowTitle(tr("Cn List")); m_pctrlCnTable->setMinimumHeight(500); m_pctrlCnTable->setMinimumWidth(350); m_pCnModel = new QStandardItemModel; m_pCnModel->setColumnCount(3); QHBoxLayout * MainLayout = new QHBoxLayout(this); MainLayout->addWidget(m_pctrlCnTable); MainLayout->addLayout(CommandButtons); setLayout(MainLayout); } void PertDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Escape: { reject(); return; } case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OKButton->setFocus(); } else if(CancelButton->hasFocus()) { reject(); return; } else { accept(); return; } break; } default: break; } } void PertDlg::OnApply() { ReadData(); OKButton->setFocus(); } void PertDlg::OnOK() { ReadData(); accept(); } void PertDlg::ReadData() { int pos; bool bOK; QString strong; QStandardItem *pItem; for (pos=0; posrowCount(); pos++) { pItem = m_pCnModel->item(pos,1); strong =pItem->text(); m_cnr[pos]=strong.toDouble(&bOK); pItem = m_pCnModel->item(pos,2); strong =pItem->text(); m_cni[pos]=strong.toDouble(&bOK); } } void PertDlg::InitDialog() { memcpy(m_backr, m_cnr, sizeof(m_cnr)); memcpy(m_backi, m_cni, sizeof(m_cni)); m_pCnModel = new QStandardItemModel; m_pCnModel->setRowCount(10);//temporary m_pCnModel->setColumnCount(3); m_pCnModel->setHeaderData(0, Qt::Horizontal, QObject::tr("i")); m_pCnModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Cn")); m_pCnModel->setHeaderData(2, Qt::Horizontal, QObject::tr("Ci")); m_pctrlCnTable->setModel(m_pCnModel); m_pctrlCnTable->setColumnWidth(0,30); m_pctrlCnTable->setColumnWidth(1,100); m_pctrlCnTable->setColumnWidth(2,100); m_pFloatDelegate = new FloatEditDelegate; m_pctrlCnTable->setItemDelegate(m_pFloatDelegate); int *precision = new int[3]; precision[0] = 0;//no digits for Re Number precision[1] = 5; precision[2] = 5; m_pFloatDelegate->SetPrecision(precision); connect(m_pFloatDelegate, SIGNAL(closeEditor(QWidget *)), this, SLOT(OnCellChanged(QWidget *))); FillCnModel(); m_pctrlCnTable->setFocus(); } void PertDlg::OnCellChanged(QWidget *pWidget) { QModelIndex index = m_pctrlCnTable->currentIndex(); int pos = index.row(); if(pos<0) return; bool bOK; QString strong; QStandardItem *pItem; pItem = m_pCnModel->item(pos,1); strong =pItem->text(); m_cnr[pos]=strong.toDouble(&bOK); pItem = m_pCnModel->item(pos,2); strong =pItem->text(); m_cni[pos]=strong.toDouble(&bOK); FillCnModel(); } void PertDlg::FillCnModel() { m_pCnModel->setRowCount(m_nc); for (int i=0; iindex(i, 0, QModelIndex()); m_pCnModel->setData(Xindex, i); QModelIndex Yindex =m_pCnModel->index(i, 1, QModelIndex()); m_pCnModel->setData(Yindex, m_cnr[i]); QModelIndex Zindex =m_pCnModel->index(i, 2, QModelIndex()); m_pCnModel->setData(Zindex, m_cni[i]); } } void PertDlg::OnRestore() { for (int i=0; i #include "params.h" #include "objects/CRectangle.h" #include "objects/ArcBall.h" #include "misc/GLLightDlg.h" /** @enum This enumeration lists the different 3D views used in the program, i.e. the view in Miarex, in Body edition and in Wing edition.*/ typedef enum {GLMIAREXVIEW,GLBODYVIEW, GLWINGVIEW} enumGLView; #define GLLISTSPHERE 531 /** *@class ThreeDWidget * This class is used for 3d OpenGl-based drawing in the central area of the application's MainFrame. * There are three instances of this class, one attached to the QStackedWidget of the MainFrame, one for Wing edition, and one for Body edition. * Depending on the active application, this class calls the drawings methods in QMiarex, in the GLBodyDlg or in GLWingDlg. * All Qt events received by this widget are sent to the child windows for handling. */ class ThreeDWidget : public QGLWidget { Q_OBJECT friend class QMiarex; friend class GL3dBodyDlg; friend class GL3dWingDlg; friend class MainFrame; friend class ArcBall; public: ThreeDWidget(QWidget *parent = 0); void CreateArcballList(ArcBall &ArcBall, double GLScale); void ClientToGL(QPoint const &point, CVector &real); void GLDrawAxes(double length, QColor AxisColor, int AxisStyle, int AxisWidth); void GLCreateUnitSphere(); void GLRenderSphere(double radius); void GLSetupLight(double Offset_y, double LightFactor); void GLToClient(CVector const &real, QPoint &point); void GLToClient(double const &x, double const &y, QPoint &point); void NormalVector(GLdouble p1[3], GLdouble p2[3], GLdouble p3[3], GLdouble n[3]); private: void contextMenuEvent (QContextMenuEvent * event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseDoubleClickEvent (QMouseEvent *event); void paintGL();//virtual override void resizeGL(int width, int height); void wheelEvent (QWheelEvent *event ); private: static void *s_pMiarex; /**< A void pointer to the instance of the QMiarex widget.*/ static void *s_pMainFrame; /**< A void pointer to the instance of the MainFrame widget.*/ void *m_pParent; /**< A void pointer to the parent widget. */ QRect m_rCltRect; /**< The client window rectangle */ CRectangle m_GLViewRect; /**< The OpenGl viewport.*/ enumGLView m_iView; /**< The identification of the type of the calling parent widget*/ }; #endif xflr5-6.09-06/src/params.h000644 001750 000144 00000011767 12247174406 016534 0ustar00techwinderusers000000 000000 /** *@file * * This files defines the values of the main constant parameters used throughout the program. * * A modification of this file triggers the compilation of the whole project. * */ #ifndef PARAMS_H #define PARAMS_H //General #define XFLR5 #define PI 3.14159265358979 #define MAXRECENTFILES 8 /**< Defines the maximum number of file names in the recent file list */ #define SETTINGSFORMAT 53627 /**< A random number which defines the format of the settings file */ #define PRECISION 0.00000000001 /**< Values are assumed 0 if less than this value. This is to avoid comparing the equality of two floating point numbers */ #define MAXCOLORS 30 /**< The number of the different colors used, mainly for the graph curves */ #define PLANFORMAREA 1 /** The reference area and span for aero coefficients is the planform area. @todo replace by an enumeration */ #define PROJECTEDAREA 2 /** The reference area and span for aero coefficients is the area projected on the xy plane. */ //3D analysis parameters #define MAXWINGS 4 /**< Wing, wing2, elevator, fin, in that order.*/ #define MAXBODIES 1 /**< One only in XFLR5 */ #define MAXSPANSECTIONS 30 /**< The max number of sections on a half wing */ #define MAXSPANSTATIONS 250 /**< The max number of stations for LLT. For a VLM analysis, this is the max number of panels in the spanwise direction. */ #define MAXCHORDPANELS 100 /**< The max number of panels in the chordwise direction for a VLM analysis. */ #define MAXCONTROLS 40 /**< The max number of controls */ #define MAXBODYFRAMES 60 /**< The max number of frames that can be used to define a body. */ #define MAXSIDELINES 40 /**< The max number of sidelines that can be used to define a body? */ #define MAXPOLARPOINTS 1000 /**< The max number of points on a polar. @todo check usage now that the storage has been transferred to QList type arrays. Needs to be consistent with the max number of points on a graph curve. */ //XFoil Direct Parameters - refer to XFoil documentation #define IQX 302 /**< 300 = number of surface panel nodes + 6 */ #define IQX2 151 /**< IQX/2 */ #define IWX 50 /**< number of wake panel nodes */ #define IPX 6 /**< 6 number of qspec[s] distributions */ #define ISX 3 /**< number of airfoil sides */ #define IBX 604 /**< 600 number of buffer airfoil nodes = 2*IQX */ #define IZX 350 /**< 350 = number of panel nodes [airfoil + wake] */ #define IVX 302 /**< 300 = number of nodes along bl on one side of airfoil and wake. */ //XFoil INVERSE parameters - refer to XFoil documentation #define ICX 257 /**< number of circle-plane points for complex mapping ( 2^n + 1 ) */ #define IMX 64 /**< number of complex mapping coefficients Cn */ #define IMX4 16 /**< = IMX/4 */ //MIAREX //3D OpenGl list references #define VLMSTREAMLINES 1220 #define SURFACESPEEDS 1221 #define LIFTFORCE 1222 #define VLMMOMENTS 1223 #define VLMWINGLIFT 1232 #define VLMWINGDRAG 1236 #define VLMWINGWASH 1241 #define VLMWINGTOPTRANS 1245 #define VLMWINGBOTTRANS 1249 #define WINGSURFACES 1300 #define WINGOUTLINE 1304 #define MESHPANELS 1372 #define MESHBACK 1373 #define WINGLEGEND 1376 #define WOPPLEGEND 1377 #define WOPPCPLEGENDCLR 1378 #define WOPPCPLEGENDTXT 1379 #define WINGWAKEPANELS 1383 #define VLMCTRLPTS 1385 #define VLMVORTICES 1386 #define PANELCP 1390 #define PANELFORCEARROWS 1391 #define PANELFORCELEGENDTXT 1392 #define ARCBALL 1414 #define ARCPOINT 1415 #define MODELEGEND 1416 #define BODYGEOMBASE 4321 #define BODYMESHBASE 5322 #define BODYCPBASE 6173 #define BODYFORCELISTBASE 6245 #define MAXGRAPHS 4 /**< The max number of graphs available for display in QXDirect and in QMiarex. */ /** @enum The different types of analysis methods for 3D calculations of wings and planes. */ typedef enum{LLTMETHOD, VLMMETHOD, PANELMETHOD} enumAnalysisMethod; /** @enum The different types of polar available for 2D and 3D calculations. */ typedef enum{FIXEDSPEEDPOLAR, FIXEDLIFTPOLAR, RUBBERCHORDPOLAR, FIXEDAOAPOLAR, STABILITYPOLAR} enumPolarType; /** @enum The different applications available to the user */ typedef enum {NOAPP, XFOILANALYSIS, DIRECTDESIGN, INVERSEDESIGN, MIAREX} enumApp; /**< @enum The different image formats usable to export screen captures*/ typedef enum {PNG, JPEG, BMP} enumImageFormat; /** @enum The different formats usable to export data to text format files*/ typedef enum {TXT, CSV} enumTextFileType; /** @enum The different number of graphs in the polar view */ typedef enum {ONEPOLARGRAPH, TWOPOLARGRAPHS, ALLPOLARGRAPHS} enumPolarGraphView; #define QUESTION (BB || !BB) /**< Shakespeare */ #endif // PARAMS_H xflr5-6.09-06/src/XFLR5Application.h000644 001750 000144 00000002623 12247174407 020265 0ustar00techwinderusers000000 000000 /**************************************************************************** XFLR5Application Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com Francesco Meschia francesco.meschia@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef XFLR5APPLICATION_H #define XFLR5APPLICATION_H #include #include "mainframe.h" class XFLR5Application : public QApplication { Q_OBJECT private: //MainFrame *mainFrame; protected: bool event(QEvent *); public: XFLR5Application(int&, char**); // void setQFLR5MainWindow(MainFrame *); }; #endif // XFLR5APPLICATION_H xflr5-6.09-06/src/design/000755 001750 000144 00000000000 12250003441 016315 5ustar00techwinderusers000000 000000 xflr5-6.09-06/src/design/FoilTableDelegate.h000644 001750 000144 00000004153 12247174406 022005 0ustar00techwinderusers000000 000000 /**************************************************************************** FoilTableDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef FOILTABLEDELEGATE_H #define FOILTABLEDELEGATE_H #include #include #include #include "../misc/DoubleEdit.h" class FoilTableDelegate : public QItemDelegate { Q_OBJECT friend class QAFoil; friend class ManageFoilsDlg; public: FoilTableDelegate(QObject *parent = 0); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawCheck(QPainter *painter, const QStyleOptionViewItem &option, const QRect &, Qt::CheckState state) const; bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index); private: QStandardItemModel *m_pFoilModel; int *m_Precision; ///table of float precisions for each column static void *s_pAFoil; }; #endif // FOILTABLEDELEGATE_H xflr5-6.09-06/src/design/AFoilTableDlg.h000644 001750 000144 00000003535 12247174406 021105 0ustar00techwinderusers000000 000000 /**************************************************************************** AFoilGridDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef AFOILTABLEDLG_H #define AFOILTABLEDLG_H #include #include #include class AFoilTableDlg : public QDialog { Q_OBJECT friend class QAFoil; public: AFoilTableDlg(QWidget *pParent); void InitDialog(); private slots: void OnOK(); private: void SetupLayout(); void keyPressEvent(QKeyEvent *event); QPushButton *OKButton, *CancelButton; QCheckBox *m_pctrlFoilName; QCheckBox *m_pctrlThickness; QCheckBox *m_pctrlThicknessAt; QCheckBox *m_pctrlCamber; QCheckBox *m_pctrlCamberAt; QCheckBox *m_pctrlPoints; QCheckBox *m_pctrlTEFlapAngle; QCheckBox *m_pctrlTEXHinge; QCheckBox *m_pctrlTEYHinge; QCheckBox *m_pctrlLEFlapAngle; QCheckBox *m_pctrlLEXHinge; QCheckBox *m_pctrlLEYHinge; bool m_bFoilName, m_bPoints; bool m_bThickness, m_bThicknessAt, m_bCamber, m_bCamberAt; bool m_bTEFlapAngle, m_bTEXHinge, m_bTEYHinge, m_bLEFlapAngle, m_bLEXHinge, m_bLEYHinge; }; #endif // AFOILTableDLG_H xflr5-6.09-06/src/design/LECircleDlg.cpp000644 001750 000144 00000005524 12247174407 021121 0ustar00techwinderusers000000 000000 /**************************************************************************** LECircleDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include "LECircleDlg.h" #include "AFoil.h" LECircleDlg::LECircleDlg(QWidget *pParent): QDialog(pParent) { setWindowTitle(tr("L.E. Circle")); SetupLayout(); } void LECircleDlg::SetupLayout() { QHBoxLayout *LERadius = new QHBoxLayout; m_pctrlRadius = new DoubleEdit(0.0,3); QLabel *lab0 = new QLabel(tr("r=")); QLabel *lab1 = new QLabel(tr("% Chord")); lab0->setAlignment(Qt::AlignRight | Qt::AlignVCenter); LERadius->addStretch(1); LERadius->addWidget(lab0); LERadius->addWidget(m_pctrlRadius); LERadius->addWidget(lab1); m_pctrlShow = new QCheckBox(tr("Show")); QHBoxLayout *CommandButtons = new QHBoxLayout; OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addWidget(m_pctrlShow); MainLayout->addStretch(1); MainLayout->addLayout(LERadius); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); setLayout(MainLayout); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void LECircleDlg::InitDialog() { m_pctrlRadius->SetValue(m_Radius); m_pctrlShow->setChecked(m_bShowRadius); } void LECircleDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Escape: { reject(); return; } case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OKButton->setFocus(); } else { OnOK(); } break; } default: event->ignore(); break; } } void LECircleDlg::OnOK() { m_Radius = m_pctrlRadius->Value(); m_bShowRadius = m_pctrlShow->isChecked(); accept(); } xflr5-6.09-06/src/design/AFoil.h000644 001750 000144 00000022366 12247175150 017506 0ustar00techwinderusers000000 000000 /**************************************************************************** QAFoil Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file * * This file implements the QAFoil class used as the interface for direct Foil design. * */ #ifndef QAFOIL_H #define QAFOIL_H #include #include #include #include #include #include #include #include #include "../params.h" #include "FoilTableDelegate.h" #include "../objects/Foil.h" #include "../objects/SplineFoil.h" /** * @brief the QAFoil class used as the interface for direct Foil design */ class QAFoil : public QWidget { Q_OBJECT friend class MainFrame; friend class FoilTableDelegate; friend class TwoDWidget; friend class AFoilGridDlg; friend class AFoilTableDlg; friend class FlapDlg; friend class NacaFoilDlg; friend class InterpolateFoilsDlg; friend class SplineCtrlsDlg; friend class TwoDPanelDlg; friend class FoilGeomDlg; friend class TEGapDlg; friend class LEDlg; friend class LECircleDlg; friend class FoilCoordDlg; friend class CAddDlg; public: QAFoil(QWidget *parent = NULL); ~QAFoil(); void SetupLayout(); void InitDialog(); private slots: void OnAFoilLECircle(); void OnExportSplinesToFile(); void OnRenameFoil(); void OnGrid(); void OnFoilStyle(); void OnDelete(); void OnDuplicate(); void OnExportCurFoil(); void OnFoilClicked(const QModelIndex& index); void OnShowAllFoils(); void OnHideAllFoils(); void OnHideCurrentFoil(); void OnShowCurrentFoil(); void OnShowLegend(); void OnStoreSplines(); void OnZoomIn(); void OnZoomLess(); void OnZoomYOnly(); void OnResetXScale(); void OnResetYScale(); void OnResetScales(); void OnUndo(); void OnRedo(); void OnSplineControls(); void OnNewSplines(); void OnAFoilSetFlap(); void OnAFoilDerotateFoil(); void OnAFoilNormalizeFoil(); void OnAFoilCadd(); void OnAFoilPanels(); void OnAFoilFoilCoordinates(); void OnAFoilFoilGeom(); void OnAFoilSetTEGap(); void OnAFoilSetLERadius(); void OnAFoilInterpolateFoils(); void OnAFoilNacaFoils(); void OnFoilTableCtxMenu(const QPoint & position); void OnAFoilTableColumns(); void OnColumnWidths(); void OnLoadBackImage(); void OnClearBackImage(); void OnInsertCtrlPt(); void OnRemoveCtrlPt(); private: void CheckButtons(); void ClearStack(int pos=0); void DrawScale(QPainter &painter, double scalex); void DrawXGrid(QPainter &painter, double scalex, double scaley, QPoint Offset, QRect dRect); void DrawYGrid(QPainter &painter, double scalex, double scaley, QPoint Offset, QRect dRect); void DrawXMinGrid(QPainter &painter, double scalex, double scaley, QPoint Offset, QRect dRect); void DrawYMinGrid(QPainter &painter, double scalex, double scaley, QPoint Offset, QRect dRect); void FillFoilTable(); void FillTableRow(int row); void ShowFoil(Foil* pFoil, bool bShow=true); void SetParams(); void SelectFoil(Foil* pFoil = NULL); void PaintGrids(QPainter &painter); void PaintSplines(QPainter &painter); void PaintFoils(QPainter &painter); void PaintLegend(QPainter &painter); void PaintView(QPainter &painter); void SetScale(); void SetScale(QRect CltRect); void ReleaseZoom(); void FoilVisibleClicked(const QModelIndex& index); void LoadSettings(QSettings *pSettings); void SaveSettings(QSettings *pSettings); void TakePicture(); void SetPicture(); void UpdateView(); void wheelEvent(QWheelEvent *event); void mouseDoubleClickEvent (QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event) ; void mouseReleaseEvent(QMouseEvent *event) ; void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void resizeEvent(QResizeEvent *event); CVector MousetoReal(QPoint &point); private: QTableView *m_pctrlFoilTable; QStandardItemModel *m_pFoilModel; FoilTableDelegate *m_pFoilDelegate; static void *s_pMainFrame; /**< a static pointer to the instance of the application's MainFrame object */ static void *s_p2DWidget; /**< a static pointer to the instance of the application's central widget used for 2D drawings */ bool m_bScale; /**< true if the scale should be displayed */ bool m_bZoomPlus; /**< true if the user is in the process of zooming in by drawing a rectangle */ bool m_bZoomYOnly; /**< true if only the y-axis should be scaled */ bool m_bNeutralLine; /**< true if the neutral line should be displayed */ bool m_bTrans; /**< true if the view is being dragged by the user */ bool m_bLECircle; /**< true if the leading edge circle should be displayed */ bool m_bStored; /**< true if the current Picture has been stored on the Undo stack */ bool m_bShowLegend; /**< true is the legend should be shown */ bool m_bXDown; /**< true if the 'X' key is pressed */ bool m_bYDown; /**< true if the 'Y' key is pressed */ bool m_bZDown; /**< true if the 'Z' key is pressed */ bool m_bXGrid; /**< true if the X main grid (vertical lines) should be displayed */ bool m_bYGrid; /**< true if the Y main grid (horizontal lines) should be displayed */ bool m_bXMinGrid; /**< true if the X minor grid (vertical lines) should be displayed */ bool m_bYMinGrid; /**< true if the Y minor grid (horizontal lines) should be displayed */ int m_XGridStyle; /**< the style of the main X-grid */ int m_YGridStyle; /**< the style of the main Y-grid */ int m_XGridWidth; /**< the width of the main X-grid */ int m_YGridWidth; /**< the width of the main Y-grid */ int m_XMinStyle; /**< the style of the minor X-grid */ int m_YMinStyle; /**< the style of the minor Y-grid */ int m_XMinWidth; /**< the width of the minor X-grid */ int m_YMinWidth; /**< the width of the minor Y-grid */ int m_NeutralStyle; /**< the style of the neutral line y=0 */ int m_NeutralWidth; /**< the width of the neutral line y=0 */ double m_XGridUnit; /**< the unit of the main X-grid */ double m_YGridUnit; /**< the unit of the main Y-grid */ double m_XMinUnit; /**< the unit of the minor X-grid */ double m_YMinUnit; /**< the unit of the minor Y-grid */ QColor m_XGridColor; /**< the color of the main X-grid */ QColor m_YGridColor; /**< the color of the main Y-grid */ QColor m_XMinColor; /**< the color of the minor X-grid */ QColor m_YMinColor; /**< the color of the minor Y-grid */ QColor m_NeutralColor; double m_LERad; /**< the radius of the leading edge circle to draw */ double m_fScale; /**< the current scale of the display */ double m_fScaleY; /**< the ratio between the y and x scales */ double m_fRefScale; /**< the reference scale of the display */ QList *m_poaFoil; /**< a pointer to the array of Foil objects */ void *m_pXFoil; /**< a void pointer to the XFoil object */ SplineFoil *m_pSF; /**< a pointer to the SplineFoil object */ QPoint m_ptOffset; /**< the foil's leading edge position in screen coordinates */ QPoint m_ViewportTrans; /**< the translation of the viewport */ QPoint m_PointDown; /**< the screen point where the last left-click occured */ QRect m_rCltRect; /**< the screen client rectangle */ QRect m_ZoomRect; /**< the user-defined rectangle for zooming in */ CVector m_MousePos; /**< the mouse position */ Foil *m_pBufferFoil; /**< a pointer to the active buffer foil */ QCursor m_hcMove; /**< the cursor to display when moving the viewport */ QCursor m_hcCross; /**< the cursor to display in the client area, when not dragging or zooming */ int m_StackPos; /**< the current position on the Undo stack */ QList m_UndoStack; /**< the stack of incremental modifications to the SplineFoil; we can't use the QStack though, because we need to access any point in the case of multiple undo operations */ bool m_bIsImageLoaded; /**< true if a backgruond image is loaded */ QPixmap m_BackImage; /**< the QPixmap object with the background image */ }; #endif // QAFOIL_H xflr5-6.09-06/src/design/SplineCtrlsDlg.cpp000644 001750 000144 00000030446 12247174407 021742 0ustar00techwinderusers000000 000000 /**************************************************************************** SplineCtrlsDlg Copyright (C) 2009-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "AFoil.h" #include "SplineCtrlsDlg.h" #include #include #include #include #include void *SplineCtrlsDlg::s_pAFoil = NULL; SplineCtrlsDlg::SplineCtrlsDlg(QWidget *pParent): QDialog(pParent) { setWindowTitle(tr("Spline Parameters")); m_pSF = NULL; SetupLayout(); } void SplineCtrlsDlg::InitDialog() { int i; QString str; m_pctrlDegExtrados->clear(); m_pctrlDegIntrados->clear(); for (i=2; i<6; i++) { str = QString("%1").arg(i); m_pctrlDegExtrados->addItem(str); m_pctrlDegIntrados->addItem(str); } m_pctrlDegExtrados->setEnabled(true); m_pctrlDegIntrados->setEnabled(true); m_pctrlDegExtrados->setCurrentIndex(m_pSF->m_Extrados.m_iDegree-2); m_pctrlDegIntrados->setCurrentIndex(m_pSF->m_Intrados.m_iDegree-2); m_pctrlOutExtrados->SetValue(m_pSF->m_Extrados.m_iRes); m_pctrlOutIntrados->SetValue(m_pSF->m_Intrados.m_iRes); //upper point list m_pUpperListModel = new QStandardItemModel; m_pUpperListModel->setRowCount(10);//temporary m_pUpperListModel->setColumnCount(3); m_pUpperListModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Point")); m_pUpperListModel->setHeaderData(1, Qt::Horizontal, QObject::tr("x")); m_pUpperListModel->setHeaderData(2, Qt::Horizontal, QObject::tr("y")); m_pctrlUpperList->setModel(m_pUpperListModel); QHeaderView *HorizontalHeader = m_pctrlUpperList->horizontalHeader(); HorizontalHeader->setStretchLastSection(true); m_pUpperFloatDelegate = new FloatEditDelegate; m_pctrlUpperList->setItemDelegate(m_pUpperFloatDelegate); //Lower point list m_pLowerListModel = new QStandardItemModel; m_pLowerListModel->setRowCount(10);//temporary m_pLowerListModel->setColumnCount(3); m_pLowerListModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Point")); m_pLowerListModel->setHeaderData(1, Qt::Horizontal, QObject::tr("x")); m_pLowerListModel->setHeaderData(2, Qt::Horizontal, QObject::tr("y")); m_pctrlLowerList->setModel(m_pLowerListModel); HorizontalHeader = m_pctrlLowerList->horizontalHeader(); HorizontalHeader->setStretchLastSection(true); m_pLowerFloatDelegate = new FloatEditDelegate; m_pctrlLowerList->setItemDelegate(m_pLowerFloatDelegate); int *precision = new int[3]; precision[0] = 0; precision[1] = 5; precision[2] = 5; m_pUpperFloatDelegate->SetPrecision(precision); m_pLowerFloatDelegate->SetPrecision(precision); connect(m_pUpperFloatDelegate, SIGNAL(closeEditor(QWidget *)), this, SLOT(OnUpdate())); connect(m_pLowerFloatDelegate, SIGNAL(closeEditor(QWidget *)), this, SLOT(OnUpdate())); m_pctrlPtWeight->setValue(m_pSF->m_Extrados.m_PtWeight); FillPointLists(); SetControls(); } void SplineCtrlsDlg::showEvent(QShowEvent *event) { int w = m_pctrlUpperList->width(); m_pctrlUpperList->setColumnWidth(0,(int)(w/3)-20); m_pctrlUpperList->setColumnWidth(1,(int)(w/3)-20); m_pctrlUpperList->setColumnWidth(2,(int)(w/3)-20); w = m_pctrlLowerList->width(); m_pctrlLowerList->setColumnWidth(0,(int)(w/3)-20); m_pctrlLowerList->setColumnWidth(1,(int)(w/3)-20); m_pctrlLowerList->setColumnWidth(2,(int)(w/3)-20); } void SplineCtrlsDlg::SetupLayout() { QGroupBox *UpperSideBox = new QGroupBox(tr("Upper side")); { QVBoxLayout *UpperSideLayout = new QVBoxLayout; { QGridLayout *UpperLayout = new QGridLayout; { QLabel *labupper1 = new QLabel(tr("Spline degree")); QLabel *labupper2 = new QLabel(tr("Output")); m_pctrlDegExtrados = new QComboBox; m_pctrlOutExtrados = new DoubleEdit; m_pctrlOutExtrados->SetPrecision(0); UpperLayout->addWidget(labupper1, 1,1); UpperLayout->addWidget(labupper2, 2,1); UpperLayout->addWidget(m_pctrlDegExtrados, 1,2); UpperLayout->addWidget(m_pctrlOutExtrados, 2,2); } m_pctrlUpperList = new QTableView; m_pctrlUpperList->setWindowTitle(QObject::tr("Upper side points")); m_pctrlUpperList->setMinimumHeight(200); m_pctrlUpperList->setMinimumWidth(250); m_pctrlUpperList->setSelectionBehavior(QAbstractItemView::SelectRows); UpperSideLayout->addLayout(UpperLayout); UpperSideLayout->addStretch(1); UpperSideLayout->addWidget(m_pctrlUpperList); } UpperSideBox->setLayout(UpperSideLayout); } QGroupBox *LowerSideBox = new QGroupBox(tr("Lower side")); { QVBoxLayout *LowerSideLayout = new QVBoxLayout; { QGridLayout *LowerLayout = new QGridLayout; { QLabel *lablower1 = new QLabel(tr("Spline degree")); QLabel *lablower2 = new QLabel(tr("Output")); m_pctrlDegIntrados = new QComboBox; m_pctrlOutIntrados = new DoubleEdit; m_pctrlOutIntrados->SetPrecision(0); LowerLayout->addWidget(lablower1, 1,1); LowerLayout->addWidget(lablower2, 2,1); LowerLayout->addWidget(m_pctrlDegIntrados, 1,2); LowerLayout->addWidget(m_pctrlOutIntrados, 2,2); } m_pctrlLowerList = new QTableView; m_pctrlLowerList->setWindowTitle(QObject::tr("Lower side points")); m_pctrlLowerList->setMinimumHeight(200); m_pctrlLowerList->setMinimumWidth(250); m_pctrlLowerList->setSelectionBehavior(QAbstractItemView::SelectRows); LowerSideLayout->addLayout(LowerLayout); LowerSideLayout->addStretch(1); LowerSideLayout->addWidget(m_pctrlLowerList); } LowerSideBox->setLayout(LowerSideLayout); } QHBoxLayout *SideLayout = new QHBoxLayout; { SideLayout->addWidget(UpperSideBox); SideLayout->addWidget(LowerSideBox); } m_pctrlSymetric = new QCheckBox(tr("Symetric foil")); QHBoxLayout *WeightLayout = new QHBoxLayout; { QLabel *labWeight = new QLabel(tr("Point Weight =")); m_pctrlPtWeight = new QSlider(Qt::Horizontal); m_pctrlPtWeight->setMinimum(1); m_pctrlPtWeight->setMaximum(11); m_pctrlPtWeight->setSliderPosition(1); m_pctrlPtWeight->setTickInterval(1); m_pctrlPtWeight->setTickPosition(QSlider::TicksBelow); // m_pctrlPtWeight->setSizePolicy(szPolicyMinimum); WeightLayout->addWidget(labWeight); WeightLayout->addWidget(m_pctrlPtWeight); } QHBoxLayout *CommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); } QVBoxLayout *MainLayout = new QVBoxLayout; { MainLayout->addLayout(SideLayout); MainLayout->addStretch(1); MainLayout->addWidget(m_pctrlSymetric); // MainLayout->addLayout(WeightLayout); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); setLayout(MainLayout); } connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(m_pctrlSymetric, SIGNAL(clicked()), this, SLOT(OnUpdate())); connect(m_pctrlDegExtrados, SIGNAL(activated(int)), this, SLOT(OnUpdate())); connect(m_pctrlDegIntrados, SIGNAL(activated(int)), this, SLOT(OnUpdate())); connect(m_pctrlOutExtrados, SIGNAL(editingFinished()), this, SLOT(OnUpdate())); connect(m_pctrlOutIntrados, SIGNAL(editingFinished()), this, SLOT(OnUpdate())); connect(m_pctrlPtWeight, SIGNAL(sliderMoved(int)), this, SLOT(OnUpdate())); connect(m_pctrlPtWeight, SIGNAL(sliderReleased()), this, SLOT(OnUpdate())); } void SplineCtrlsDlg::FillPointLists() { m_pUpperListModel->setRowCount(m_pSF->m_Extrados.m_CtrlPoint.size()); for (int i=0; im_Extrados.m_CtrlPoint.size(); i++) { QModelIndex index = m_pUpperListModel->index(i, 0, QModelIndex()); m_pUpperListModel->setData(index, i+1); QModelIndex Xindex =m_pUpperListModel->index(i, 1, QModelIndex()); m_pUpperListModel->setData(Xindex, m_pSF->m_Extrados.m_CtrlPoint[i].x); QModelIndex Zindex =m_pUpperListModel->index(i, 2, QModelIndex()); m_pUpperListModel->setData(Zindex, m_pSF->m_Extrados.m_CtrlPoint[i].y); } m_pLowerListModel->setRowCount(m_pSF->m_Intrados.m_CtrlPoint.size()); for (int i=0; im_Intrados.m_CtrlPoint.size(); i++) { QModelIndex index = m_pLowerListModel->index(i, 0, QModelIndex()); m_pLowerListModel->setData(index, i+1); QModelIndex Xindex =m_pLowerListModel->index(i, 1, QModelIndex()); m_pLowerListModel->setData(Xindex, m_pSF->m_Intrados.m_CtrlPoint[i].x); QModelIndex Zindex =m_pLowerListModel->index(i, 2, QModelIndex()); m_pLowerListModel->setData(Zindex, m_pSF->m_Intrados.m_CtrlPoint[i].y); } } void SplineCtrlsDlg::ReadData() { for(int i=0; im_Extrados.m_CtrlPoint.size(); i++) { QModelIndex index = m_pUpperListModel->index(i, 1, QModelIndex()); m_pSF->m_Extrados.m_CtrlPoint[i].x = index.data().toDouble(); index = m_pUpperListModel->index(i, 2, QModelIndex()); m_pSF->m_Extrados.m_CtrlPoint[i].y = index.data().toDouble(); } for (int i=0; im_Intrados.m_CtrlPoint.size(); i++) { QModelIndex index = m_pLowerListModel->index(i, 1, QModelIndex()); m_pSF->m_Intrados.m_CtrlPoint[i].x = index.data().toDouble(); index = m_pLowerListModel->index(i, 2, QModelIndex()); m_pSF->m_Intrados.m_CtrlPoint[i].y = index.data().toDouble(); } int ideg = m_pctrlDegExtrados->currentIndex()+2; if(idegm_Extrados.m_CtrlPoint.size()) { // there are enough control points for this degree m_pSF->m_Extrados.m_iDegree = ideg; } else { // too few control points, adjust the degree QMessageBox::warning(this,tr("Warning"), tr("The spline degree must be less than the number of control points")); m_pSF->m_Extrados.m_iDegree = qMax(2,m_pSF->m_Extrados.m_CtrlPoint.size()-1); m_pctrlDegExtrados->setCurrentIndex(m_pSF->m_Extrados.m_iDegree-2); } ideg = m_pctrlDegIntrados->currentIndex()+2; if(idegm_Intrados.m_CtrlPoint.size()) { // there are enough control points for this degree m_pSF->m_Intrados.m_iDegree = ideg; } else { // too few control points, adjust the degree QMessageBox::warning(this,tr("Warning"), tr("The spline degree must be less than the number of control points")); m_pSF->m_Intrados.m_iDegree = qMax(2,m_pSF->m_Intrados.m_CtrlPoint.size()-1); m_pctrlDegIntrados->setCurrentIndex(m_pSF->m_Intrados.m_iDegree-2); } m_pSF->m_Extrados.m_iRes = m_pctrlOutExtrados->Value(); m_pSF->m_Intrados.m_iRes = m_pctrlOutExtrados->Value(); m_pSF->m_bSymetric = m_pctrlSymetric->isChecked(); if(m_pSF->m_bSymetric) { m_pSF->m_Intrados.CopySymetric(&m_pSF->m_Extrados); } double w = (double)m_pctrlPtWeight->value(); m_pSF->m_Extrados.m_PtWeight = exp(w); m_pSF->m_Extrados.m_PtWeight = exp(w); } void SplineCtrlsDlg::SetControls() { m_pctrlSymetric->setChecked(m_pSF->m_bSymetric); if(m_pSF->m_bSymetric) { m_pctrlDegIntrados->setCurrentIndex(m_pSF->m_Intrados.m_iDegree-2); m_pctrlOutIntrados->SetValue(m_pSF->m_Intrados.m_iRes); FillPointLists(); } m_pctrlLowerList->setEnabled(!m_pSF->m_bSymetric); m_pctrlDegIntrados->setEnabled(!m_pSF->m_bSymetric); m_pctrlOutIntrados->setEnabled(!m_pSF->m_bSymetric); } void SplineCtrlsDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Escape: { reject(); return; } case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OKButton->setFocus(); } else { OnOK(); } break; } default: event->ignore(); break; } } void SplineCtrlsDlg::OnOK() { ReadData(); accept(); } void SplineCtrlsDlg::OnUpdate() { ReadData(); SetControls(); UpdateSplines(); } void SplineCtrlsDlg::UpdateSplines() { m_pSF->m_Extrados.SplineKnots(); m_pSF->m_Extrados.SplineCurve(); m_pSF->m_Intrados.SplineKnots(); m_pSF->m_Intrados.SplineCurve(); m_pSF->UpdateSplineFoil(); QAFoil *pAFoil = (QAFoil*)s_pAFoil; pAFoil->UpdateView(); } xflr5-6.09-06/src/design/AFoilTableDlg.cpp000644 001750 000144 00000011436 12247174406 021437 0ustar00techwinderusers000000 000000 /**************************************************************************** AFoilTableDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "AFoil.h" #include "AFoilTableDlg.h" #include #include #include #include "../misc/LinePickerDlg.h" AFoilTableDlg::AFoilTableDlg(QWidget *pParent): QDialog(pParent) { setWindowTitle(tr("Foil Table Columns")); SetupLayout(); m_bFoilName = m_bPoints = true; m_bThickness = m_bThicknessAt = m_bCamber = m_bCamberAt = true; m_bTEFlapAngle = m_bTEXHinge = m_bTEYHinge = m_bLEFlapAngle = m_bLEXHinge = m_bLEYHinge = true; } void AFoilTableDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Escape: { done(0); break; } case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OKButton->setFocus(); // m_bApplied = true; } else { QDialog::accept(); } break; } default: event->ignore(); } } void AFoilTableDlg::InitDialog() { m_pctrlFoilName->setChecked(m_bFoilName); m_pctrlThickness->setChecked(m_bThickness); m_pctrlThicknessAt->setChecked(m_bThicknessAt); m_pctrlCamber->setChecked(m_bCamber); m_pctrlCamberAt->setChecked(m_bCamberAt); m_pctrlPoints->setChecked(m_bPoints); m_pctrlTEFlapAngle->setChecked(m_bTEFlapAngle); m_pctrlTEXHinge->setChecked(m_bTEXHinge); m_pctrlTEYHinge->setChecked(m_bTEYHinge); m_pctrlLEFlapAngle->setChecked(m_bLEFlapAngle); m_pctrlLEXHinge->setChecked(m_bLEXHinge); m_pctrlLEYHinge->setChecked(m_bLEYHinge); } void AFoilTableDlg::SetupLayout() { QVBoxLayout *ColumnsLayout = new QVBoxLayout; m_pctrlFoilName = new QCheckBox(tr("Foil Name")); m_pctrlThickness = new QCheckBox(tr("Thickness")); m_pctrlThicknessAt = new QCheckBox(tr("Thickness max. position")); m_pctrlCamber = new QCheckBox(tr("Camber")); m_pctrlCamberAt = new QCheckBox(tr("Camber max. position")); m_pctrlPoints = new QCheckBox(tr("Number of points")); m_pctrlTEFlapAngle = new QCheckBox(tr("Trailing edge flap angle")); m_pctrlTEXHinge = new QCheckBox(tr("Trailing edge hinge x-position")); m_pctrlTEYHinge = new QCheckBox(tr("Trailing edge hinge y-position")); m_pctrlLEFlapAngle = new QCheckBox(tr("Leading edge flap angle")); m_pctrlLEXHinge = new QCheckBox(tr("Leading edge hinge x-position")); m_pctrlLEYHinge = new QCheckBox(tr("Leading edge hinge y-position")); ColumnsLayout->addWidget(m_pctrlFoilName); ColumnsLayout->addWidget(m_pctrlThickness); ColumnsLayout->addWidget(m_pctrlThicknessAt); ColumnsLayout->addWidget(m_pctrlCamber); ColumnsLayout->addWidget(m_pctrlCamberAt); ColumnsLayout->addWidget(m_pctrlPoints); ColumnsLayout->addWidget(m_pctrlTEFlapAngle); ColumnsLayout->addWidget(m_pctrlTEXHinge); ColumnsLayout->addWidget(m_pctrlTEYHinge); ColumnsLayout->addWidget(m_pctrlLEFlapAngle); ColumnsLayout->addWidget(m_pctrlLEXHinge); ColumnsLayout->addWidget(m_pctrlLEYHinge); QHBoxLayout *CommandButtons = new QHBoxLayout; OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addWidget(OKButton); CommandButtons->addWidget(CancelButton); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addLayout(ColumnsLayout); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); setLayout(MainLayout); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void AFoilTableDlg::OnOK() { m_bFoilName = m_pctrlFoilName->isChecked(); m_bThickness = m_pctrlThickness->isChecked(); m_bThicknessAt = m_pctrlThicknessAt->isChecked(); m_bCamber = m_pctrlCamber->isChecked(); m_bCamberAt = m_pctrlCamberAt->isChecked(); m_bPoints = m_pctrlPoints->isChecked(); m_bTEFlapAngle = m_pctrlTEFlapAngle->isChecked(); m_bTEXHinge = m_pctrlTEXHinge->isChecked(); m_bTEYHinge = m_pctrlTEYHinge->isChecked(); m_bLEFlapAngle = m_pctrlLEFlapAngle->isChecked(); m_bLEXHinge = m_pctrlLEXHinge->isChecked(); m_bLEYHinge = m_pctrlLEYHinge->isChecked(); accept(); } xflr5-6.09-06/src/design/AFoil.cpp000644 001750 000144 00000244463 12247175622 020051 0ustar00techwinderusers000000 000000 /**************************************************************************** AFoil Class Copyright (C) 2009-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include #include #include #include #include "../globals.h" #include "../mainframe.h" #include "../misc/LinePickerDlg.h" #include "../xdirect/XFoil.h" #include "AFoil.h" #include "AFoilGridDlg.h" #include "AFoilTableDlg.h" #include "SplineCtrlsDlg.h" #include "LECircleDlg.h" #include "../xdirect/NacaFoilDlg.h" #include "../xdirect/CAddDlg.h" #include "../xdirect/TwoDPanelDlg.h" #include "../xdirect/TEGapDlg.h" #include "../xdirect/LEDlg.h" #include "../xdirect/FlapDlg.h" #include "../xdirect/FoilCoordDlg.h" #include "../xdirect/FoilGeomDlg.h" #include "../xdirect/InterpolateFoilsDlg.h" void *QAFoil::s_pMainFrame = NULL; void *QAFoil::s_p2DWidget = NULL; /** * The public constructor * @param parent a pointer to the MainFrame window */ QAFoil::QAFoil(QWidget *parent) : QWidget(parent) { m_hcCross = QCursor(Qt::CrossCursor); m_hcMove = QCursor(Qt::ClosedHandCursor); m_StackPos = 0; m_MousePos.x = 0.0; m_MousePos.y = 0.0; m_poaFoil = NULL; m_pctrlFoilTable = NULL; m_pSF = new SplineFoil(); m_pSF->m_bModified = false; m_pSF->InitSplineFoil(); ClearStack(); TakePicture(); m_bZoomPlus = false; m_bZoomYOnly = false; m_bTrans = false; m_bNeutralLine = true; m_bScale = true; m_bLECircle = false; m_bShowLegend = true; m_bStored = false; m_bXDown = m_bYDown = m_bZDown = false; m_bIsImageLoaded = false; m_LERad = 1.0; m_bXGrid = false; m_XGridUnit = 0.05; m_XGridStyle = 1; m_XGridWidth = 1; m_XGridColor = QColor(150,150,150); m_bYGrid = false; m_YGridUnit = 0.05; m_YGridStyle = 1; m_YGridWidth = 1; m_YGridColor = QColor(150,150,150); m_bXMinGrid = false; m_XMinUnit = 0.01; m_XMinStyle = 2; m_XMinWidth = 1; m_XMinColor = QColor(70,70,70); m_bYMinGrid = false; m_YMinUnit = 0.01; m_YMinStyle = 2; m_YMinWidth = 1; m_YMinColor = QColor(70,70,70); m_NeutralStyle = 3; m_NeutralWidth = 1; m_NeutralColor = QColor(70,70,70); m_fScale = 1.0; m_fRefScale = 1.0; m_fScaleY = 1.0; m_ptOffset.rx() = 0; m_ptOffset.ry() = 0; m_ViewportTrans = QPoint(0,0); m_pBufferFoil = new Foil(); m_StackPos = 0; SetupLayout(); FoilTableDelegate::s_pAFoil = this; SplineCtrlsDlg::s_pAFoil = this; } /** * The public destructor */ QAFoil::~QAFoil() { ClearStack(-1); delete m_pSF; } /** * Initializes the state of the button widgets and of the QAction objects. */ void QAFoil::CheckButtons() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->AFoilDelete->setEnabled(MainFrame::s_pCurFoil); pMainFrame->AFoilRename->setEnabled(MainFrame::s_pCurFoil); pMainFrame->AFoilExport->setEnabled(MainFrame::s_pCurFoil); pMainFrame->ShowCurrentFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->HideCurrentFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->AFoilDerotateFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->AFoilEditCoordsFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->AFoilInterpolateFoils->setEnabled(MainFrame::s_pCurFoil); pMainFrame->AFoilNormalizeFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->AFoilRefineGlobalFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->AFoilRefineLocalFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->AFoilScaleFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->AFoilSetFlap->setEnabled(MainFrame::s_pCurFoil); pMainFrame->AFoilSetLERadius->setEnabled(MainFrame::s_pCurFoil); pMainFrame->AFoilSetTEGap->setEnabled(MainFrame::s_pCurFoil); pMainFrame->m_pShowLegend->setChecked(m_bShowLegend); pMainFrame->AFoilSplineMenu->setEnabled(!MainFrame::s_pCurFoil); pMainFrame->InsertSplinePt->setEnabled(!MainFrame::s_pCurFoil); pMainFrame->RemoveSplinePt->setEnabled(!MainFrame::s_pCurFoil); pMainFrame->UndoAFoilAct->setEnabled(m_StackPos>0); pMainFrame->RedoAFoilAct->setEnabled(m_StackPos=xmin) { painter.drawLine(int(xt*scalex) + Offset.x(), YMin, int(xt*scalex) + Offset.x(), YMax); } } xt += xDelta; k++; } painter.restore(); } /** * Draws the Y minor grid. * @param painter a reference to the QPainter object with which to draw * @param scalex the scale factor in the x-direction * @param scaley the scale factor in the y-direction * @param Offset the Foil leading edge offset in the client area * @param dRect the drawing rectangle */ void QAFoil::DrawYMinGrid(QPainter &painter, double scalex, double scaley, QPoint Offset, QRect dRect) { painter.save(); QPen GridPen(m_YMinColor); GridPen.setWidth(m_YMinWidth); GridPen.setStyle(GetStyle(m_YMinStyle)); painter.setPen(GridPen); double yo = 0.0; double xmin = 0.0; double xmax = 1.0; double ymin = -0.2; double ymax = 0.2; int XMin = qMax(int(xmin*scalex)+ Offset.x(), dRect.left()); int XMax = qMin(int(xmax*scalex)+ Offset.x(), dRect.right()); // double yDelta = m_YGridUnit/(m_YMinFreq+1); double yDelta = m_YMinUnit; int MinFreq = (int)(m_YGridUnit/m_YMinUnit); int k=0; double yt = yo-int((yo-ymin)*1.0001/m_YGridUnit)*m_YGridUnit;//one tick at the origin while(yt<=ymax*1.001) { if(k%(MinFreq)!=0) { // do not overwrite main grid if (yt>=ymin) { painter.drawLine(XMin, (int)(yt*scaley) + Offset.y(), XMax, (int)(yt*scaley) + Offset.y()); } } yt += yDelta; k++; } painter.restore(); } /** * Fills the table with the data from the Foil objects. */ void QAFoil::FillFoilTable() { int i; m_pFoilModel->setRowCount(m_poaFoil->size()+1); QString name; QModelIndex ind; double Thickness, xThickness, Camber, xCamber; Thickness = xThickness = Camber = xCamber = 0; int points = 0; if(m_pSF) { name = tr("Spline foil"); Thickness = m_pSF->m_fThickness; xThickness = m_pSF->m_fxThickMax; Camber = m_pSF->m_fCamber; xCamber = m_pSF->m_fxCambMax; points = m_pSF->m_OutPoints; } ind = m_pFoilModel->index(0, 0, QModelIndex()); m_pFoilModel->setData(ind,name); ind = m_pFoilModel->index(0, 1, QModelIndex()); m_pFoilModel->setData(ind, Thickness); ind = m_pFoilModel->index(0, 2, QModelIndex()); m_pFoilModel->setData(ind, xThickness); ind = m_pFoilModel->index(0, 3, QModelIndex()); m_pFoilModel->setData(ind, Camber); ind = m_pFoilModel->index(0, 4, QModelIndex()); m_pFoilModel->setData(ind,xCamber); ind = m_pFoilModel->index(0, 5, QModelIndex()); m_pFoilModel->setData(ind, points); ind = m_pFoilModel->index(0,12, QModelIndex()); if(m_pSF->m_bVisible) m_pFoilModel->setData(ind, Qt::Checked, Qt::CheckStateRole); else m_pFoilModel->setData(ind, Qt::Unchecked, Qt::CheckStateRole); QStandardItem *pItem = m_pFoilModel->item(0,12); pItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsUserCheckable); ind = m_pFoilModel->index(0,13, QModelIndex()); if(m_pSF->m_bOutPoints) m_pFoilModel->setData(ind, Qt::Checked, Qt::CheckStateRole); else m_pFoilModel->setData(ind, Qt::Unchecked, Qt::CheckStateRole); pItem = m_pFoilModel->item(0,13); pItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsUserCheckable); ind = m_pFoilModel->index(0,14, QModelIndex()); if(m_pSF->m_bCenterLine) m_pFoilModel->setData(ind, Qt::Checked, Qt::CheckStateRole); else m_pFoilModel->setData(ind, Qt::Unchecked, Qt::CheckStateRole); pItem = m_pFoilModel->item(0,14); pItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsUserCheckable); for(i=0; isize(); i++) { FillTableRow(i+1); } } /** * Fills the data from a Foil object in the specified table row. * @param row the index of the row to be filled */ void QAFoil::FillTableRow(int row) { QModelIndex ind; QStandardItem *pItem; Foil *pFoil = (Foil*)m_poaFoil->at(row-1); ind = m_pFoilModel->index(row, 0, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_FoilName); ind = m_pFoilModel->index(row, 1, QModelIndex()); m_pFoilModel->setData(ind, pFoil->m_fThickness); ind = m_pFoilModel->index(row, 2, QModelIndex()); m_pFoilModel->setData(ind, pFoil->m_fXThickness); ind = m_pFoilModel->index(row, 3, QModelIndex()); m_pFoilModel->setData(ind, pFoil->m_fCamber); ind = m_pFoilModel->index(row, 4, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_fXCamber); ind = m_pFoilModel->index(row, 5, QModelIndex()); m_pFoilModel->setData(ind,pFoil->n); if(pFoil && pFoil->m_bTEFlap) { ind = m_pFoilModel->index(row, 6, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_TEFlapAngle); ind = m_pFoilModel->index(row, 7, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_TEXHinge/100.0); ind = m_pFoilModel->index(row, 8, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_TEYHinge/100.0); } if(pFoil && pFoil->m_bLEFlap) { ind = m_pFoilModel->index(row, 9, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_LEFlapAngle); ind = m_pFoilModel->index(row, 10, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_LEXHinge/100.0); ind = m_pFoilModel->index(row, 11, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_LEYHinge/100.0); } ind = m_pFoilModel->index(row, 12, QModelIndex()); if(pFoil->m_bVisible) m_pFoilModel->setData(ind, Qt::Checked, Qt::CheckStateRole); else m_pFoilModel->setData(ind, Qt::Unchecked, Qt::CheckStateRole); pItem = m_pFoilModel->item(row,12); if(pItem) pItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsUserCheckable); ind = m_pFoilModel->index(row, 13, QModelIndex()); if(pFoil->m_bPoints) m_pFoilModel->setData(ind, Qt::Checked, Qt::CheckStateRole); else m_pFoilModel->setData(ind, Qt::Unchecked, Qt::CheckStateRole); pItem = m_pFoilModel->item(row,13); if(pItem) pItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsUserCheckable); ind = m_pFoilModel->index(row, 14, QModelIndex()); if(pFoil->m_bCenterLine) m_pFoilModel->setData(ind, Qt::Checked, Qt::CheckStateRole); else m_pFoilModel->setData(ind, Qt::Unchecked, Qt::CheckStateRole); pItem = m_pFoilModel->item(row,14); if(pItem) pItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsUserCheckable); } /** * Overrides the QWidget's keyPressEvent method. * Dispatches the key press event * @param event the QKeyEvent */ void QAFoil::keyPressEvent(QKeyEvent *event) { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; bool bShift = false; bool bCtrl = false; if(event->modifiers() & Qt::ShiftModifier) bShift =true; if(event->modifiers() & Qt::ControlModifier) bCtrl =true; switch (event->key()) { case Qt::Key_Escape: { if(m_bZoomPlus) { ReleaseZoom(); } else if(m_bZoomYOnly) { pMainFrame->zoomYAct->setChecked(false); m_bZoomYOnly = false; } break; } case Qt::Key_F2: { OnRenameFoil(); break; } case Qt::Key_F3: { if(MainFrame::s_pCurFoil) { if(bShift) OnAFoilCadd(); else OnAFoilPanels(); } break; } case Qt::Key_F4: { OnStoreSplines(); break; } case Qt::Key_F9: { OnAFoilFoilGeom(); break; } case Qt::Key_F10: { OnAFoilSetFlap(); break; } case Qt::Key_F11: { OnAFoilInterpolateFoils(); break; } case Qt::Key_R: OnResetScales(); break; case Qt::Key_X: m_bXDown = true; break; case Qt::Key_Y: m_bYDown = true; break; case Qt::Key_Z: m_bZDown = true; break; case Qt::Key_I: if (event->modifiers().testFlag(Qt::ControlModifier) & event->modifiers().testFlag(Qt::ShiftModifier)) { if(!m_bIsImageLoaded) { OnLoadBackImage(); } else { OnClearBackImage(); } } break; default: QWidget::keyPressEvent(event); } } /** * Overrides the QWidget's keyReleaseEvent method. * Dispatches the key press event * @param event the QKeyEvent */ void QAFoil::keyReleaseEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_X: { if(!event->isAutoRepeat()) m_bXDown = false; break; } case Qt::Key_Y: if(!event->isAutoRepeat()) m_bYDown = false; break; case Qt::Key_Z: if(!event->isAutoRepeat()) m_bZDown = false; break; default: QWidget::keyReleaseEvent(event); } } /** * Converts screen coordinate to viewport coordinates * @param point the screen coordinates * @return the viewport coordinates */ CVector QAFoil::MousetoReal(QPoint &point) { CVector Real; Real.x = (point.x() - m_ptOffset.x())/m_fScale; Real.y = -(point.y() - m_ptOffset.y())/m_fScale/m_fScaleY; Real.z = 0.0; return Real; } /** * Loads the user's default settings from the application QSettings object. * @param pSettings a pointer to the QSettings object */ void QAFoil::LoadSettings(QSettings *pSettings) { int r,g,b; int style, width; QColor color; pSettings->beginGroup("DirectDesign"); { m_bXGrid = pSettings->value("XMajGrid").toBool(); m_bYGrid = pSettings->value("YMajGrid").toBool(); m_bXMinGrid = pSettings->value("XMinGrid").toBool(); m_bYMinGrid = pSettings->value("YMinGrid").toBool(); m_XGridStyle = pSettings->value("XMajStyle").toInt(); m_YGridStyle = pSettings->value("YMajStyle").toInt(); m_XGridWidth = pSettings->value("XMajWidth").toInt(); m_YGridWidth = pSettings->value("YMajWidth").toInt(); m_XMinStyle = pSettings->value("XMinStyle").toInt(); m_YMinStyle = pSettings->value("YMinStyle").toInt(); m_XMinWidth = pSettings->value("XMinWidth").toInt(); m_YMinWidth = pSettings->value("YMinWidth").toInt(); m_XGridUnit = pSettings->value("XMajUnit").toDouble(); m_YGridUnit = pSettings->value("YMajUnit").toDouble(); m_XMinUnit = pSettings->value("XMinUnit").toDouble(); m_YMinUnit = pSettings->value("YMinUnit").toDouble(); r = pSettings->value("XMajColorRed",34).toInt(); g = pSettings->value("XMajColorGreen",177).toInt(); b = pSettings->value("XMajColorBlue",234).toInt(); m_XGridColor = QColor(r,g,b); r = pSettings->value("YMajColorRed").toInt(); g = pSettings->value("YMajColorGreen").toInt(); b = pSettings->value("YMajColorBlue").toInt(); m_YGridColor = QColor(r,g,b); r = pSettings->value("XMinColorRed").toInt(); g = pSettings->value("XMinColorGreen").toInt(); b = pSettings->value("XMinColorBlue").toInt(); m_XMinColor = QColor(r,g,b); r = pSettings->value("YMinColorRed").toInt(); g = pSettings->value("YMinColorGreen").toInt(); b = pSettings->value("YMinColorBlue").toInt(); m_YMinColor = QColor(r,g,b); m_NeutralStyle = pSettings->value("NeutralStyle").toInt(); m_NeutralWidth = pSettings->value("NeutralWidth").toInt(); r = pSettings->value("NeutralColorRed").toInt(); g = pSettings->value("NeutralColorGreen").toInt(); b = pSettings->value("NeutralColorBlue").toInt(); m_NeutralColor = QColor(r,g,b); m_bNeutralLine = pSettings->value("NeutralLine").toBool(); style = pSettings->value("SFStyle", 0).toInt(); width = pSettings->value("SFWidth",1).toInt(); r = pSettings->value("SFColorRed",216).toInt(); g = pSettings->value("SFColorGreen",183).toInt(); b = pSettings->value("SFColorBlue",83).toInt(); color = QColor(r,g,b); m_pSF->SetCurveParams(style, width, color); m_pSF->m_bVisible = pSettings->value("SFVisible").toBool(); m_pSF->m_bOutPoints = pSettings->value("SFOutPoints").toBool(); m_pSF->m_bCenterLine = pSettings->value("SFCenterLine").toBool(); m_pSF->m_Intrados.m_iRes = pSettings->value("LowerRes",79).toInt(); m_pSF->m_Extrados.m_iRes = pSettings->value("UpperRes",79).toInt(); m_pSF->m_Extrados.SplineCurve(); m_pSF->m_Intrados.SplineCurve(); m_bLECircle = pSettings->value("LECircle").toBool(); m_bScale = pSettings->value("Scale").toBool(); m_bShowLegend = pSettings->value("Legend").toBool(); QString str; for(int i=0; i<16; i++) { str = QString("Column_%1").arg(i); m_pctrlFoilTable->setColumnWidth(i, pSettings->value(str,40).toInt()); if(pSettings->value(str+"_hidden", false).toBool()) m_pctrlFoilTable->hideColumn(i); } } pSettings->endGroup(); } /** * Overrides the QWidget's mouseDoubleClickEvent method. * Dispatches the key press event * @param event the QMouseEvent */ void QAFoil::mouseDoubleClickEvent (QMouseEvent * event) { if(!hasFocus()) setFocus(); QPoint point = event->pos(); QPoint center; //translate center.rx() = (int)(m_rCltRect.width()/2); center.ry() = (int)(m_rCltRect.height()/2); m_ptOffset.rx() += -point.x() + center.x(); m_ptOffset.ry() += -point.y() + center.y(); m_ViewportTrans.rx() += -point.x() + center.x(); m_ViewportTrans.ry() += -point.y() + center.y(); UpdateView(); return; } /** * Overrides the QWidget's mouseMoveEvent method. * Dispatches the key press event * @param event the QMouseEvent */ void QAFoil::mouseMoveEvent(QMouseEvent *event) { if(!hasFocus()) setFocus(); QPoint point = event->pos(); m_MousePos = MousetoReal(point); CVector Real = m_MousePos; bool bCtrl = false; if(event->modifiers() & Qt::ControlModifier) bCtrl =true; if(m_bZoomPlus && (event->buttons() & Qt::LeftButton)) { // we're zooming in using the rectangle method m_ZoomRect.setBottomRight(point); UpdateView(); return; } else if(m_rCltRect.contains(point) && (event->buttons() & Qt::LeftButton) && m_bTrans) { //translate m_ptOffset.rx() += point.x() - m_PointDown.x(); m_ptOffset.ry() += point.y() - m_PointDown.y(); m_ViewportTrans.rx() += point.x() - m_PointDown.x(); m_ViewportTrans.ry() += point.y() - m_PointDown.y(); m_PointDown.rx() = point.x(); m_PointDown.ry() = point.y(); m_MousePos = Real; UpdateView(); return; } if (event->buttons() & Qt::LeftButton && !m_bZoomPlus) { // user is dragging the point if(m_rCltRect.contains(point)) { int n = m_pSF->m_Extrados.m_iSelect; if (n>=0 && nm_Extrados.m_CtrlPoint.size()) { // if(n==1) m_MousePos.x = 0.0;// we can't move point 1 for vertical slope m_pSF->m_Extrados.m_CtrlPoint[n].x = m_MousePos.x; m_pSF->m_Extrados.m_CtrlPoint[n].y = m_MousePos.y; m_pSF->m_Extrados.SplineCurve(); m_pSF->UpdateSplineFoil(); if(m_pSF->m_bSymetric) { m_pSF->m_Intrados.m_CtrlPoint[n].x = m_MousePos.x; m_pSF->m_Intrados.m_CtrlPoint[n].y = -m_MousePos.y; m_pSF->m_Intrados.SplineCurve(); m_pSF->UpdateSplineFoil(); } m_pSF->m_bModified = true; MainFrame::SetSaveState(false); } else { int n = m_pSF->m_Intrados.m_iSelect; if (n>=0 && nm_Intrados.m_CtrlPoint.size()) { m_pSF->m_Intrados.m_CtrlPoint[n].x = m_MousePos.x; m_pSF->m_Intrados.m_CtrlPoint[n].y = m_MousePos.y; m_pSF->m_Intrados.SplineCurve(); m_pSF->UpdateSplineFoil(); if(m_pSF->m_bSymetric) { m_pSF->m_Extrados.m_CtrlPoint[n].x = m_MousePos.x; m_pSF->m_Extrados.m_CtrlPoint[n].y = -m_MousePos.y; m_pSF->m_Extrados.SplineCurve(); m_pSF->UpdateSplineFoil(); } m_pSF->m_bModified = true; MainFrame::SetSaveState(false); } } FillFoilTable(); } } else if ((event->buttons() & Qt::MidButton)) { // user is zooming with mouse button down rather than with wheel if(m_rCltRect.contains(point)) { double scale = m_fScale; if(!m_bZoomYOnly) { if (m_bXDown) { if(point.y()-m_PointDown.y()>0) { m_fScale *= 1.02; m_fScaleY /= 1.02; } else { m_fScale /= 1.02; m_fScaleY *= 1.02; } } else if (m_bYDown) { if(point.y()-m_PointDown.y()>0) m_fScaleY *= 1.02; else m_fScaleY /= 1.02; } else { if(point.y()-m_PointDown.y()>0) m_fScale *= 1.02; else m_fScale /= 1.02; } } else { if(point.y()-m_PointDown.y()>0) m_fScaleY *= 1.02; else m_fScaleY /= 1.02; } m_PointDown = point; int a = (int)((m_rCltRect.right()+m_rCltRect.left())/2); m_ptOffset.rx() = a + (int)((m_ptOffset.x()-a)*m_fScale/scale); } } else if(!m_bZoomPlus) { //not zooming, check if mouse passes over control point and highlight if(m_pSF->m_bVisible) { int n = m_pSF->m_Extrados.IsControlPoint(Real, m_fScale/m_fRefScale); if (n>0 && nm_Extrados.m_CtrlPoint.size()) { m_pSF->m_Extrados.m_iHighlight = n; } else { if(m_pSF->m_Extrados.m_iHighlight>=0) { m_pSF->m_Extrados.m_iHighlight = -10; } } n = m_pSF->m_Intrados.IsControlPoint(Real, m_fScale/m_fRefScale); if (n>0 && nm_Intrados.m_CtrlPoint.size()) { m_pSF->m_Intrados.m_iHighlight = n; } else { if(m_pSF->m_Intrados.m_iHighlight>=0) { m_pSF->m_Intrados.m_iHighlight = -10; } } UpdateView(); } } UpdateView(); } /** * Overrides the QWidget's mousePressEvent method. * Dispatches the key press event * @param event the QMouseEvent */ void QAFoil::mousePressEvent(QMouseEvent *event) { QPoint point = event->pos(); TwoDWidget *p2DWidget = (TwoDWidget*)s_p2DWidget; CVector Real = MousetoReal(point); // get a reference for mouse movements m_PointDown.rx() = point.x(); m_PointDown.ry() = point.y(); if(m_bZoomPlus && m_rCltRect.contains(point)) { m_ZoomRect.setTopLeft(point); m_ZoomRect.setBottomRight(point); } else if(!m_bZoomPlus && (event->buttons() & Qt::LeftButton)) { if (event->modifiers() & Qt::ShiftModifier) { //shift --> inserts a point OnInsertCtrlPt(); } else if (event->modifiers() & Qt::ControlModifier) { //Ctrl --> removes the point OnRemoveCtrlPt(); } else { //Selects the point m_pSF->m_Extrados.m_iSelect = m_pSF->m_Extrados.IsControlPoint(Real, m_fScale/m_fRefScale); if(m_pSF->m_Extrados.m_iSelect<0) m_pSF->m_Intrados.m_iSelect = m_pSF->m_Intrados.IsControlPoint(Real, m_fScale/m_fRefScale); if(m_pSF->m_Extrados.m_iSelect ==-10 && m_pSF->m_Intrados.m_iSelect ==-10) { p2DWidget->setCursor(m_hcMove); m_bTrans = true; } } } UpdateView(); } /** * Overrides the QWidget's mouseReleaseEvent method. * Dispatches the key press event * @param event the QMouseEvent */ void QAFoil::mouseReleaseEvent(QMouseEvent *event) { QPoint point = event->pos(); TwoDWidget *p2DWidget = (TwoDWidget*)s_p2DWidget; if(m_bZoomPlus && m_rCltRect.contains(point)) { m_ZoomRect.setBottomRight(point); QRect ZRect = m_ZoomRect.normalized(); if(!ZRect.isEmpty()) { m_ZoomRect = ZRect; double ZoomFactor = qMin((double)m_rCltRect.width() / (double)m_ZoomRect.width() , (double)m_rCltRect.height() / (double)m_ZoomRect.height()); double newScale = qMin(ZoomFactor*m_fScale, 32.0*m_fRefScale); ZoomFactor = qMin(ZoomFactor, newScale/m_fScale); m_fScale = ZoomFactor*m_fScale; int a = (int)((m_rCltRect.right() + m_rCltRect.left())/2); int b = (int)((m_rCltRect.top() + m_rCltRect.bottom())/2); int aZoom = (int)((m_ZoomRect.right() + m_ZoomRect.left())/2); int bZoom = (int)((m_ZoomRect.top() + m_ZoomRect.bottom())/2); //translate view m_ptOffset.rx() += (a - aZoom); m_ptOffset.ry() += (b - bZoom); //scale view m_ptOffset.rx() = (int)(ZoomFactor * (m_ptOffset.x()-a)+a); m_ptOffset.ry() = (int)(ZoomFactor * (m_ptOffset.y()-b)+b); // m_ZoomRect.setBottomRight(m_ZoomRect.topLeft()); m_ZoomRect.setRight(m_ZoomRect.left()-1); } else { m_ZoomRect.setBottomRight(m_ZoomRect.topLeft()); ReleaseZoom(); } } else if(m_bZoomPlus && !m_rCltRect.contains(point)) { ReleaseZoom(); } else if(m_bTrans) { // nothing to do } else { //we're releasing a point drag if(event->button()==Qt::LeftButton) { TakePicture(); m_pSF->CompMidLine(); } } p2DWidget->setCursor(m_hcCross); m_bTrans = false; UpdateView(); } /** * The user has requested that the foil be derotated. */ void QAFoil::OnAFoilDerotateFoil() { if(!MainFrame::s_pCurFoil) return; m_pBufferFoil->CopyFoil(MainFrame::s_pCurFoil); m_pBufferFoil->m_bVisible = true; m_pBufferFoil->m_FoilName = MainFrame::s_pCurFoil->m_FoilName; m_pBufferFoil->m_FoilColor = QColor(160,160,160); m_pBufferFoil->m_nFoilStyle = 1; m_pBufferFoil->m_nFoilWidth = 1; UpdateView(); double angle = m_pBufferFoil->DeRotate(); QString str = QString(tr("Foil has been de-rotated by %1 degrees")).arg(angle,6,'f',3); MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->statusBar()->showMessage(str); //then duplicate the buffer foil and add it Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(m_pBufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; Foil * pFoil = pMainFrame->SetModFoil(pNewFoil); FillFoilTable(); SelectFoil(pFoil); m_pBufferFoil->m_bVisible = false; UpdateView(); } /** * The user has requested that the Foil be normalized to unit length. */ void QAFoil::OnAFoilNormalizeFoil() { if(!MainFrame::s_pCurFoil) return; double length = MainFrame::s_pCurFoil->NormalizeGeometry(); MainFrame::s_pCurFoil->InitFoil(); QString str = QString(tr("Foil has been normalized from %1 to 1.000")).arg(length,7,'f',3); MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->statusBar()->showMessage(str); UpdateView(); } /** * The user has requested a local refinement of the panels of the current Foil. */ void QAFoil::OnAFoilCadd() { if(!MainFrame::s_pCurFoil) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; m_pBufferFoil->CopyFoil(MainFrame::s_pCurFoil); m_pBufferFoil->m_FoilName = MainFrame::s_pCurFoil->m_FoilName; m_pBufferFoil->m_FoilColor = QColor(160,160,160); m_pBufferFoil->m_nFoilStyle = 1; m_pBufferFoil->m_nFoilWidth = 1; m_pBufferFoil->m_bPoints = true; m_pBufferFoil->m_bVisible = true; UpdateView(); CAddDlg caDlg(pMainFrame); caDlg.m_pBufferFoil = m_pBufferFoil; caDlg.m_pMemFoil = MainFrame::s_pCurFoil; caDlg.m_pXDirect = NULL; caDlg.m_pAFoil = this; caDlg.InitDialog(); if(QDialog::Accepted == caDlg.exec()) { //then duplicate the buffer foil and add it Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(m_pBufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; Foil * pFoil = pMainFrame->SetModFoil(pNewFoil); FillFoilTable(); SelectFoil(pFoil); } else { FillFoilTable(); SelectFoil(MainFrame::s_pCurFoil); ((XFoil*)m_pXFoil)->m_FoilName =""; } m_pBufferFoil->m_bVisible = false; UpdateView(); } /** * The user has requested the display of a circle at the L.E. position. */ void QAFoil::OnAFoilLECircle() { LECircleDlg LECircleDlg(this); LECircleDlg.m_Radius = m_LERad; LECircleDlg.m_bShowRadius = m_bLECircle; LECircleDlg.m_pAFoil = this; LECircleDlg.InitDialog(); if(LECircleDlg.exec()==QDialog::Accepted) { m_LERad = LECircleDlg.m_Radius; m_bLECircle = LECircleDlg.m_bShowRadius; } UpdateView(); } /** * The user has requested the launch of the interface to refine globally the Foil. */ void QAFoil::OnAFoilPanels() { if(!MainFrame::s_pCurFoil) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; m_pBufferFoil->CopyFoil(MainFrame::s_pCurFoil); m_pBufferFoil->m_FoilName = MainFrame::s_pCurFoil->m_FoilName; m_pBufferFoil->m_FoilColor = QColor(160,160,160); m_pBufferFoil->m_nFoilStyle = 1; m_pBufferFoil->m_nFoilWidth = 1; m_pBufferFoil->m_bPoints = true; m_pBufferFoil->m_bVisible = true; UpdateView(); TwoDPanelDlg tdpDlg(pMainFrame); tdpDlg.m_pBufferFoil = m_pBufferFoil; tdpDlg.m_pMemFoil = MainFrame::s_pCurFoil; tdpDlg.m_pXDirect = NULL; tdpDlg.m_pAFoil = this; tdpDlg.InitDialog(); if(QDialog::Accepted == tdpDlg.exec()) { //then duplicate the buffer foil and add it Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(m_pBufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; Foil * pFoil = pMainFrame->SetModFoil(pNewFoil); FillFoilTable(); SelectFoil(pFoil); } else { FillFoilTable(); SelectFoil(MainFrame::s_pCurFoil); // m_pXFoil->m_FoilName =""; } m_pBufferFoil->m_bVisible = false; UpdateView(); } /** * The user has requested the launch of the interface to edit the Foil coordinates manually. */ void QAFoil::OnAFoilFoilCoordinates() { if(!MainFrame::s_pCurFoil) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; m_pBufferFoil->CopyFoil(MainFrame::s_pCurFoil); m_pBufferFoil->m_bPoints = true; m_pBufferFoil->m_bVisible = true; m_pBufferFoil->m_FoilName = MainFrame::s_pCurFoil->m_FoilName; m_pBufferFoil->m_FoilColor = QColor(160,160,160); m_pBufferFoil->m_nFoilStyle = 1; m_pBufferFoil->m_nFoilWidth = 1; UpdateView(); FoilCoordDlg fcDlg(pMainFrame); fcDlg.m_pMemFoil = MainFrame::s_pCurFoil; fcDlg.m_pBufferFoil = m_pBufferFoil; fcDlg.m_pXDirect = NULL; fcDlg.m_pAFoil = this; fcDlg.InitDialog(); if(QDialog::Accepted == fcDlg.exec()) { //then duplicate the buffer foil and add it Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(m_pBufferFoil); pNewFoil->m_bPoints = false; pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_iHighLight = -1; Foil * pFoil = pMainFrame->SetModFoil(pNewFoil); FillFoilTable(); SelectFoil(pFoil); } else { FillFoilTable(); SelectFoil(MainFrame::s_pCurFoil); ((XFoil*)m_pXFoil)->m_FoilName =""; } m_pBufferFoil->m_bVisible = false; UpdateView(); } /** * The user has requested to perform an edition of the current foil's thickness and camber properties. */ void QAFoil::OnAFoilFoilGeom() { if(!MainFrame::s_pCurFoil) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; m_pBufferFoil->CopyFoil(MainFrame::s_pCurFoil); m_pBufferFoil->m_bPoints = true; m_pBufferFoil->m_bVisible = true; m_pBufferFoil->m_FoilName = MainFrame::s_pCurFoil->m_FoilName; m_pBufferFoil->m_FoilColor = QColor(160,160,160); m_pBufferFoil->m_nFoilStyle = 1; m_pBufferFoil->m_nFoilWidth = 1; UpdateView(); FoilGeomDlg fgeDlg(pMainFrame); fgeDlg.m_pMemFoil = MainFrame::s_pCurFoil; fgeDlg.m_pBufferFoil = m_pBufferFoil; fgeDlg.m_pAFoil = this; fgeDlg.m_pXDirect = NULL; fgeDlg.InitDialog(); if(QDialog::Accepted == fgeDlg.exec()) { //then duplicate the buffer foil and add it Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(m_pBufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; Foil * pFoil = pMainFrame->SetModFoil(pNewFoil); FillFoilTable(); SelectFoil(pFoil); } else { FillFoilTable(); SelectFoil(MainFrame::s_pCurFoil); // m_pXFoil->m_FoilName =""; } m_pBufferFoil->m_bVisible = false; UpdateView(); } /** * The user has requested the launch of the interface to modify the gap at the Foil's trailing edge. */ void QAFoil::OnAFoilSetTEGap() { if(!MainFrame::s_pCurFoil) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; m_pBufferFoil->CopyFoil(MainFrame::s_pCurFoil); m_pBufferFoil->m_bPoints = false; m_pBufferFoil->m_bVisible = true; m_pBufferFoil->m_FoilName = MainFrame::s_pCurFoil->m_FoilName; m_pBufferFoil->m_FoilColor = QColor(160,160,160); m_pBufferFoil->m_nFoilStyle = 1; m_pBufferFoil->m_nFoilWidth = 1; UpdateView(); TEGapDlg teDlg(pMainFrame); teDlg.m_pBufferFoil = m_pBufferFoil; teDlg.m_pMemFoil = MainFrame::s_pCurFoil; teDlg.m_pXDirect = NULL; teDlg.m_pAFoil = this; teDlg.InitDialog(); if(QDialog::Accepted == teDlg.exec()) { //then duplicate the buffer foil and add it Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(m_pBufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; Foil * pFoil = pMainFrame->SetModFoil(pNewFoil); FillFoilTable(); SelectFoil(pFoil); } else { FillFoilTable(); SelectFoil(MainFrame::s_pCurFoil); // m_pXFoil->m_FoilName =""; //to un-initialize XFoil in case user switches to XInverse //Thanks Jean-Marc ! } m_pBufferFoil->m_bVisible = false; UpdateView(); } /** * The user has requested the launch of the interface to modify the radius of the Foil's leading edge. */ void QAFoil::OnAFoilSetLERadius() { if(!MainFrame::s_pCurFoil) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; m_pBufferFoil->CopyFoil(MainFrame::s_pCurFoil); m_pBufferFoil->m_bVisible = true; m_pBufferFoil->m_bPoints = false; m_pBufferFoil->m_FoilName = MainFrame::s_pCurFoil->m_FoilName; m_pBufferFoil->m_FoilColor = QColor(160,160,160); m_pBufferFoil->m_nFoilStyle = 1; m_pBufferFoil->m_nFoilWidth = 1; UpdateView(); LEDlg leDlg(pMainFrame); leDlg.m_pBufferFoil = m_pBufferFoil; leDlg.m_pMemFoil = MainFrame::s_pCurFoil; leDlg.m_pXDirect = NULL; leDlg.m_pAFoil = this; leDlg.InitDialog(); if(QDialog::Accepted == leDlg.exec()) { //then duplicate the buffer foil and add it Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(m_pBufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; Foil * pFoil = pMainFrame->SetModFoil(pNewFoil); FillFoilTable(); SelectFoil(pFoil); } else { FillFoilTable(); SelectFoil(MainFrame::s_pCurFoil); // m_pXFoil->m_FoilName =""; } m_pBufferFoil->m_bVisible = false; UpdateView(); } /** * The user has requested the launch of the interface to create a foil from the interpolation of two existing Foil objects. */ void QAFoil::OnAFoilInterpolateFoils() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(m_poaFoil->size()<2) { QMessageBox::warning(pMainFrame,tr("Warning"), tr("At least two foils are required")); return; } if(!MainFrame::s_pCurFoil) SelectFoil(); if(!MainFrame::s_pCurFoil) return; m_pBufferFoil->CopyFoil(MainFrame::s_pCurFoil); m_pBufferFoil->m_FoilName = MainFrame::s_pCurFoil->m_FoilName; m_pBufferFoil->m_FoilColor = QColor(160,160,160); m_pBufferFoil->m_nFoilStyle = 1; m_pBufferFoil->m_nFoilWidth = 1; m_pBufferFoil->m_bPoints = false; m_pBufferFoil->m_bVisible = true; UpdateView(); InterpolateFoilsDlg ifDlg(pMainFrame); ifDlg.m_poaFoil = m_poaFoil; ifDlg.m_pBufferFoil = m_pBufferFoil; ifDlg.m_pXDirect = NULL; ifDlg.m_pAFoil = this; ifDlg.InitDialog(); if(QDialog::Accepted == ifDlg.exec()) { //then duplicate the buffer foil and add it Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(m_pBufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; pNewFoil->m_FoilName = ifDlg.m_NewFoilName; Foil * pFoil = pMainFrame->SetModFoil(pNewFoil); FillFoilTable(); SelectFoil(pFoil); } else { FillFoilTable(); SelectFoil(MainFrame::s_pCurFoil); } m_pBufferFoil->m_bVisible = false; UpdateView(); } /** * The user has requested the launch of the interface used to create a NACA type Foil. */ void QAFoil::OnAFoilNacaFoils() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; m_pBufferFoil->SetNaca009(); m_pBufferFoil->m_bPoints = true; m_pBufferFoil->m_bVisible = true; m_pBufferFoil->m_FoilName = "Naca xxxx"; m_pBufferFoil->m_FoilColor = QColor(160,160,160); m_pBufferFoil->m_nFoilStyle = 1; m_pBufferFoil->m_nFoilWidth = 1; UpdateView(); NacaFoilDlg nacaDlg(pMainFrame); nacaDlg.m_pBufferFoil = m_pBufferFoil; nacaDlg.m_pXDirect = NULL; nacaDlg.m_pAFoil = this; if(QDialog::Accepted == nacaDlg.exec()) { //then duplicate the buffer foil and add it QString str; if(nacaDlg.s_Digits>0 && log10((double)nacaDlg.s_Digits)<4) str = QString("%1").arg(nacaDlg.s_Digits,4,10,QChar('0')); else str = QString("%1").arg(nacaDlg.s_Digits); str = "NACA "+ str; Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(m_pBufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; pNewFoil->m_FoilName = str; Foil * pFoil = pMainFrame->SetModFoil(pNewFoil); FillFoilTable(); SelectFoil(pFoil); } else { FillFoilTable();; if(MainFrame::s_pCurFoil) SelectFoil(MainFrame::s_pCurFoil); ((XFoil*)m_pXFoil)->m_FoilName =""; } m_pBufferFoil->m_bVisible = false; UpdateView(); } /** * The user has requested the launch of the interface to define a L.E. or T.E. flap. */ void QAFoil::OnAFoilSetFlap() { if(!MainFrame::s_pCurFoil) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; m_pBufferFoil->CopyFoil(MainFrame::s_pCurFoil); m_pBufferFoil->m_bVisible = true; m_pBufferFoil->m_FoilName = MainFrame::s_pCurFoil->m_FoilName; m_pBufferFoil->m_FoilColor = QColor(160,160,160); m_pBufferFoil->m_nFoilStyle = 1; m_pBufferFoil->m_nFoilWidth = 1; UpdateView(); FlapDlg flDlg(pMainFrame); flDlg.m_pAFoil = this; flDlg.m_pXDirect = NULL; flDlg.m_pXFoil = m_pXFoil; flDlg.m_pMemFoil = MainFrame::s_pCurFoil; flDlg.m_pBufferFoil = m_pBufferFoil; flDlg.InitDialog(); if(QDialog::Accepted == flDlg.exec()) { //then duplicate the buffer foil and add it Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(m_pBufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; Foil * pFoil = pMainFrame->SetModFoil(pNewFoil); FillFoilTable(); SelectFoil(pFoil); } else { FillFoilTable(); SelectFoil(MainFrame::s_pCurFoil); ((XFoil*)m_pXFoil)->m_FoilName =""; } m_pBufferFoil->m_bVisible = false; UpdateView(); } /** * The user has requested the deletion of the current Foil. */ void QAFoil::OnDelete() { if(!MainFrame::s_pCurFoil) return; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; Foil *pNextFoil = pMainFrame->DeleteFoil(MainFrame::s_pCurFoil); FillFoilTable(); SelectFoil(pNextFoil); UpdateView(); } /** * The user has requested the duplication of the current Foil. */ void QAFoil::OnDuplicate() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(!MainFrame::s_pCurFoil) return; Foil *pNewFoil = new Foil; pNewFoil->CopyFoil(MainFrame::s_pCurFoil); pNewFoil->InitFoil(); if(pMainFrame->SetModFoil(pNewFoil)) { FillFoilTable(); SelectFoil(pNewFoil); } else { FillFoilTable(); SelectFoil(NULL); } } /** * The user has requested the export of the current Foil to a text file. */ void QAFoil::OnExportCurFoil() { if(!MainFrame::s_pCurFoil) return; QString FileName; FileName = MainFrame::s_pCurFoil->m_FoilName; FileName.replace("/", " "); FileName = QFileDialog::getSaveFileName(this, tr("Export Foil"), MainFrame::s_LastDirName+"/"+FileName+".dat", tr("Foil File (*.dat)")); if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&XFile); MainFrame::s_pCurFoil->ExportFoil(out); XFile.close(); } /** * The user has requested the export of the current SplineFoil to a text file. */ void QAFoil::OnExportSplinesToFile() { QString FoilName = tr("Spline Foil"); QString FileName, strong; QString strOut; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; // deselect points so as not to interfere with other mouse commands m_pSF->m_Intrados.m_iSelect = -10; m_pSF->m_Extrados.m_iSelect = -10; //check that the number of output points is consistent with the array's size if(m_pSF->m_Extrados.m_iRes>IQX2) { strong = QString(tr("Too many output points on upper surface\n Max =%1")).arg(IQX2); QMessageBox::warning(pMainFrame, tr("Warning"), strong, QMessageBox::Ok); return; } if(m_pSF->m_Intrados.m_iRes>IQX2) { strong = QString(tr("Too many output points on lower surface\n Max =%1")).arg(IQX2); QMessageBox::warning(pMainFrame, tr("Warning"), strong, QMessageBox::Ok); return; } FileName.replace("/", " "); FileName = QFileDialog::getSaveFileName(this, tr("Export Splines"), MainFrame::s_LastDirName, tr("Text File (*.dat)")); if(!FileName.length()) return; int pos; pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&XFile); strOut = FoilName + "\n"; out << strOut; m_pSF->ExportToFile(out); XFile.close(); } /** * The visibility of a foil in the table has been toggled. * @param index a QModelIndex object clicked in the table */ void QAFoil::FoilVisibleClicked(const QModelIndex& index) { if(index.row()>=m_poaFoil->size()+1) return; QStandardItem *pItem = m_pFoilModel->item(index.row(),0); if(index.row()>0) { Foil *pFoil= MainFrame::foil(pItem->text()); MainFrame::s_pCurFoil = pFoil; if(index.column()==12) { pFoil->m_bVisible = !pFoil->m_bVisible; } else if(index.column()==13) { pFoil->m_bPoints = !pFoil->m_bPoints; } else if(index.column()==14) { pFoil->m_bCenterLine = !pFoil->m_bCenterLine; } MainFrame::SetSaveState(false); } else if(index.row()==0) { MainFrame::s_pCurFoil = NULL; if(index.column()==12) { m_pSF->m_bVisible = !m_pSF->m_bVisible; } else if(index.column()==13) { m_pSF->m_bOutPoints = !m_pSF->m_bOutPoints; } else if(index.column()==14) { m_pSF->m_bCenterLine = !m_pSF->m_bCenterLine; } } UpdateView(); } /** * A row has been clicked in the table of Foil objects. * @param index a QModelIndex object clicked in the table */ void QAFoil::OnFoilClicked(const QModelIndex& index) { if(index.row()>=m_poaFoil->size()+1) return; QStandardItem *pItem = m_pFoilModel->item(index.row(),0); if(index.row()>0) { Foil *pFoil= MainFrame::foil(pItem->text()); MainFrame::s_pCurFoil = pFoil; } else if(index.row()==0) { MainFrame::s_pCurFoil = NULL; } if(index.column()==15) OnFoilStyle(); CheckButtons(); } /** * The user has requested an edition of the style of the active Foil. */ void QAFoil::OnFoilStyle() { if(!MainFrame::s_pCurFoil) { LinePickerDlg dlg(this); dlg.InitDialog(m_pSF->m_FoilStyle, m_pSF->m_FoilWidth, m_pSF->m_FoilColor); if(QDialog::Accepted==dlg.exec()) { m_pSF->SetCurveParams(dlg.GetStyle(), dlg.GetWidth(), dlg.GetColor()); UpdateView(); } } else { LinePickerDlg dlg(this); dlg.InitDialog(MainFrame::s_pCurFoil->m_nFoilStyle, MainFrame::s_pCurFoil->m_nFoilWidth, MainFrame::s_pCurFoil->m_FoilColor); if(QDialog::Accepted==dlg.exec()) { MainFrame::SetSaveState(false); MainFrame::s_pCurFoil->m_nFoilStyle = dlg.GetStyle(); MainFrame::s_pCurFoil->m_nFoilWidth = dlg.GetWidth(); MainFrame::s_pCurFoil->m_FoilColor = dlg.GetColor(); UpdateView(); } } } /** * The user has requested the launch the interface for the edition of the grid parameters. */ void QAFoil::OnGrid() { AFoilGridDlg dlg(this); dlg.m_bScale = m_bScale; dlg.m_bNeutralLine = m_bNeutralLine; dlg.m_NeutralStyle = m_NeutralStyle; dlg.m_NeutralWidth = m_NeutralWidth; dlg.m_NeutralColor = m_NeutralColor; dlg.m_bXGrid = m_bXGrid; dlg.m_bXMinGrid = m_bXMinGrid; dlg.m_XStyle = m_XGridStyle; dlg.m_XWidth = m_XGridWidth; dlg.m_XColor = m_XGridColor; dlg.m_XUnit = m_XGridUnit; dlg.m_XMinStyle = m_XMinStyle; dlg.m_XMinWidth = m_XMinWidth; dlg.m_XMinColor = m_XMinColor; dlg.m_XMinUnit = m_XMinUnit; dlg.m_bYGrid = m_bYGrid; dlg.m_bYMinGrid = m_bYMinGrid; dlg.m_YStyle = m_YGridStyle; dlg.m_YWidth = m_YGridWidth; dlg.m_YColor = m_YGridColor; dlg.m_YUnit = m_YGridUnit; dlg.m_YMinStyle = m_YMinStyle; dlg.m_YMinWidth = m_YMinWidth; dlg.m_YMinColor = m_YMinColor; dlg.m_YMinUnit = m_YMinUnit; dlg.InitDialog(); if(dlg.exec() == QDialog::Accepted) { m_bScale = dlg.m_bScale; m_bNeutralLine = dlg.m_bNeutralLine; m_NeutralStyle = dlg.m_NeutralStyle; m_NeutralWidth = dlg.m_NeutralWidth; m_NeutralColor = dlg.m_NeutralColor; m_bXGrid = dlg.m_bXGrid; m_bXMinGrid = dlg.m_bXMinGrid; m_XGridStyle = dlg.m_XStyle; m_XGridWidth = dlg.m_XWidth; m_XGridColor = dlg.m_XColor; m_XGridUnit = dlg.m_XUnit; m_XMinStyle = dlg.m_XMinStyle; m_XMinWidth = dlg.m_XMinWidth; m_XMinColor = dlg.m_XMinColor; m_XMinUnit = dlg.m_XMinUnit; m_bYGrid = dlg.m_bYGrid; m_bYMinGrid = dlg.m_bYMinGrid; m_YGridStyle = dlg.m_YStyle; m_YGridWidth = dlg.m_YWidth; m_YGridColor = dlg.m_YColor; m_YGridUnit = dlg.m_YUnit; m_YMinStyle = dlg.m_YMinStyle; m_YMinWidth = dlg.m_YMinWidth; m_YMinColor = dlg.m_YMinColor; m_YMinUnit = dlg.m_YMinUnit; } UpdateView(); } /** * The user has requested that the visibility of all Foil objects be turned off. */ void QAFoil::OnHideAllFoils() { MainFrame::SetSaveState(false); Foil*pFoil; for (int k=0; ksize(); k++) { pFoil = (Foil*)m_poaFoil->at(k); pFoil->m_bVisible = false; } FillFoilTable(); UpdateView(); } /** * The user has requested that the visibility of the active Foil object be turned off. */ void QAFoil::OnHideCurrentFoil() { if(!MainFrame::s_pCurFoil) return; ShowFoil(MainFrame::s_pCurFoil, false); UpdateView(); } /** * The user has requested to restore the default settings for the splines. */ void QAFoil::OnNewSplines() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(m_pSF->m_bModified) { if (QMessageBox::Yes != QMessageBox::question(pMainFrame, tr("Question"), tr("Discard changes to Splines ?"), QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel)) { return; } } m_pSF->InitSplineFoil(); m_StackPos = 0; ClearStack(0); TakePicture(); MainFrame::SetSaveState(false); UpdateView(); } /** * The user has requested to rename the Foil object */ void QAFoil::OnRenameFoil() { if(!MainFrame::s_pCurFoil) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->OnRenameCurFoil(); FillFoilTable(); } /** * The user has requested that the visibility of all Foil objects be turned on. */ void QAFoil::OnShowAllFoils() { MainFrame::SetSaveState(false); Foil*pFoil; for (int k=0; ksize(); k++) { pFoil = (Foil*)m_poaFoil->at(k); pFoil->m_bVisible = true; } FillFoilTable(); UpdateView(); } /** * The user has requested that the visibility of the active Foil object be turned on. */ void QAFoil::OnShowCurrentFoil() { if(!MainFrame::s_pCurFoil) return; ShowFoil(MainFrame::s_pCurFoil, true); UpdateView(); } /** * The user has toggled the visibility of the legend */ void QAFoil::OnShowLegend() { m_bShowLegend = !m_bShowLegend; UpdateView(); CheckButtons(); } /** * The user has requested to convert the SplineFoil object to a Foil, and to store it in the database. */ void QAFoil::OnStoreSplines() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(m_pSF->m_Extrados.m_iRes>IQX2) { QString strong = QString(tr("Too many output points on upper surface\n Max =%1")).arg(IQX2); QMessageBox::warning(pMainFrame, tr("Warning"), strong, QMessageBox::Ok); return; } if(m_pSF->m_Intrados.m_iRes>IQX2) { QString strong = QString(tr("Too many output points on lower surface\n Max =%1")).arg(IQX2); QMessageBox::warning(pMainFrame, tr("Warning"), strong, QMessageBox::Ok); return; } Foil *pNewFoil = new Foil(); m_pSF->ExportToBuffer(pNewFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; pNewFoil->m_FoilName = ""; if(pMainFrame->SetModFoil(pNewFoil)) { MainFrame::s_pCurFoil = NULL; FillFoilTable(); SelectFoil(pNewFoil); } else { FillFoilTable(); SelectFoil(); } UpdateView(); } /** * The user has requested to reset the x-scale to its default value. */ void QAFoil::OnResetXScale() { SetScale(); ReleaseZoom(); UpdateView(); } /** * The user has requested to reset the y-scale to its default value. */ void QAFoil::OnResetYScale() { m_fScaleY = 1.0; UpdateView(); } /** * The user has requested to reset the scales to their default value. */ void QAFoil::OnResetScales() { m_fScaleY = 1.0; SetScale(); ReleaseZoom(); UpdateView(); } /** * The user has requested the launch of the interface to edit SplineFoil data. */ void QAFoil::OnSplineControls() { SplineCtrlsDlg dlg(this); dlg.m_pSF = m_pSF; dlg.InitDialog(); SplineFoil memSF; memSF.Copy(m_pSF); if(dlg.exec() == QDialog::Accepted) { TakePicture(); } else m_pSF->Copy(&memSF); } /** * The user has requested to zoom in on the display by drawing a rectangle on the screen. */ void QAFoil::OnZoomIn() { if(!m_bZoomPlus) { if(m_fScale/m_fRefScale <32.0) { m_bZoomPlus = true; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->zoomInAct->setChecked(true); } else { ReleaseZoom(); } } else { ReleaseZoom(); } } /** * The user has requested to scale the y-axis only. */ void QAFoil::OnZoomYOnly() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; TwoDWidget *p2Dwidget = (TwoDWidget*)s_p2DWidget; m_bZoomYOnly = !m_bZoomYOnly; pMainFrame->zoomYAct->setChecked(m_bZoomYOnly); p2Dwidget->setFocus(); } /** * The user has requested to zoom out. */ void QAFoil::OnZoomLess() { // can't do two things at the same time can we ? ReleaseZoom(); double ZoomFactor = 0.8; double newScale = qMax(ZoomFactor*m_fScale, m_fRefScale); ZoomFactor = qMax(ZoomFactor, newScale/m_fScale); m_fScale = ZoomFactor*m_fScale; int a = (int)((m_rCltRect.right()+m_rCltRect.left())/2); int b = (int)((m_rCltRect.top()+m_rCltRect.bottom())/2); //scale m_ptOffset.rx() = (int)(ZoomFactor*(m_ptOffset.x()-a)+a); m_ptOffset.ry() = (int)(ZoomFactor*(m_ptOffset.y()-b)+b); UpdateView(); } /** * Draws the grids. * @param painter a reference to the QPainter object with which to draw. */ void QAFoil::PaintGrids(QPainter &painter) { painter.save(); if(m_bZoomPlus&& !m_ZoomRect.isEmpty()) { QRect ZRect = m_ZoomRect.normalized(); QPen ZoomPen(QColor(100,100,100)); ZoomPen.setStyle(Qt::DashLine); painter.setPen(ZoomPen); painter.drawRect(ZRect); } if(m_bLECircle) { int rx = (int)(m_LERad/100.0 * m_fScale); int ry = (int)(m_LERad/100.0 * m_fScale * m_fScaleY); QRect rc(m_ptOffset.x(), m_ptOffset.y() - ry, 2*rx, 2*ry); QPen CirclePen(QColor(128,128,128)); CirclePen.setStyle(Qt::DashLine); painter.setPen(CirclePen); painter.drawEllipse(rc); } if (m_bNeutralLine) { QPen NPen(m_NeutralColor); NPen.setStyle(GetStyle(m_NeutralStyle)); NPen.setWidth(m_NeutralWidth); painter.setPen(NPen); painter.drawLine(m_rCltRect.right(),m_ptOffset.y(), m_rCltRect.left(),m_ptOffset.y()); } //draw grids if(m_bXGrid) DrawXGrid(painter, m_fScale, m_fScale*m_fScaleY, m_ptOffset, m_rCltRect); if(m_bYGrid) DrawYGrid(painter, m_fScale, m_fScale*m_fScaleY, m_ptOffset, m_rCltRect); if(m_bXMinGrid) DrawXMinGrid(painter, m_fScale, m_fScale*m_fScaleY, m_ptOffset, m_rCltRect); if(m_bYMinGrid) DrawYMinGrid(painter, m_fScale, m_fScale*m_fScaleY, m_ptOffset, m_rCltRect); if(m_bScale) DrawScale(painter, m_fScale); painter.restore(); } /** * Draws the legend. * @param painter a reference to the QPainter object with which to draw. */ void QAFoil::PaintLegend(QPainter &painter) { painter.save(); painter.setFont(MainFrame::s_TextFont); if(m_bShowLegend) { Foil* pRefFoil; QString strong; QPoint Place(m_rCltRect.right()-250, 10); int LegendSize, ypos, x1, n, k, delta; LegendSize = 20; ypos = 15; delta = 5; painter.setBackgroundMode(Qt::TransparentMode); QPen TextPen(MainFrame::s_TextColor); painter.setPen(TextPen); QPen LegendPen; k=0; if(m_pSF->m_bVisible) { LegendPen.setColor(m_pSF->m_FoilColor); LegendPen.setStyle(GetStyle(m_pSF->m_FoilStyle)); LegendPen.setWidth(m_pSF->m_FoilWidth); painter.setPen(LegendPen); painter.drawLine(Place.x(), Place.y() + ypos*k, Place.x() + (int)(LegendSize), Place.y() + ypos*k); if(m_pSF->m_bOutPoints ) { // x1 = Place.x + (int)(0.5*LegendSize); // pDC->Rectangle(x1-2, Place.y + ypos*k-2, x1+2, Place.y + ypos*k+2); x1 = Place.x() + (int)(0.5*LegendSize); painter.drawRect(x1-2, Place.y() + ypos*k-2, 4,4); } painter.setPen(TextPen); painter.drawText(Place.x() + (int)(1.5*LegendSize), Place.y() + ypos*k+delta, m_pSF->m_strFoilName); } k++; for (n=0; n < m_poaFoil->size(); n++) { pRefFoil = (Foil*)m_poaFoil->at(n); if(pRefFoil && pRefFoil->m_bVisible) { strong = pRefFoil->m_FoilName; if(strong.length()) { LegendPen.setColor(pRefFoil->m_FoilColor); LegendPen.setStyle(GetStyle(pRefFoil->m_nFoilStyle)); LegendPen.setWidth(pRefFoil->m_nFoilWidth); painter.setPen(LegendPen); painter.drawLine(Place.x(), Place.y() + ypos*k, Place.x() + (int)(LegendSize), Place.y() + ypos*k); if(pRefFoil->m_bPoints) { x1 = Place.x() + (int)(0.5*LegendSize); painter.drawRect(x1-2, Place.y() + ypos*k-2, 4,4); } painter.setPen(TextPen); painter.drawText(Place.x() + (int)(1.5*LegendSize), Place.y() + ypos*k+delta, pRefFoil->m_FoilName); k++; } } } } painter.restore(); } /** * Draws the view. * @param painter a reference to the QPainter object with which to draw. */ void QAFoil::PaintView(QPainter &painter) { painter.save(); double xscale = m_fScale /m_fRefScale; double yscale = m_fScale*m_fScaleY/m_fRefScale; //zoom from the center of the viewport QPoint VCenter = QPoint((int)((m_rCltRect.right() + m_rCltRect.left() )/2), (int)((m_rCltRect.top() + m_rCltRect.bottom())/2)); painter.fillRect(m_rCltRect, MainFrame::s_BackgroundColor); //draw the background image in the viewport if(m_bIsImageLoaded && !m_BackImage.isNull()) { int w = (int)((double)m_BackImage.width()* xscale); int h = (int)((double)m_BackImage.height()* yscale); //the coordinates of the top left corner are measured from the center of the viewport double xtop = VCenter.x() + m_ViewportTrans.x() - (int)((double)m_BackImage.width() /2.*xscale); double ytop = VCenter.y() + m_ViewportTrans.y() - (int)((double)m_BackImage.height() /2.*yscale); painter.drawPixmap(xtop, ytop, w,h, m_BackImage); } // m_ptOffset.rx() = VCenter.x() + m_ViewportTrans.x() - (int)(0.5 *m_fScale); // m_ptOffset.ry() = VCenter.y() + m_ViewportTrans.y() ; painter.setFont(MainFrame::s_TextFont); QPen TextPen(MainFrame::s_TextColor); painter.setPen(TextPen); PaintGrids(painter); PaintSplines(painter); PaintFoils(painter); PaintLegend(painter); QString str; str = QString(tr("X-Scale = %1")).arg(m_fScale/m_fRefScale,4,'f',1); painter.drawText(5,10, str); str = QString(tr("Y-Scale = %1")).arg(m_fScaleY*m_fScale/m_fRefScale,4,'f',1); painter.drawText(5,22, str); str = QString(tr("x = %1")).arg(m_MousePos.x,7,'f',4); painter.drawText(5,34, str); str = QString(tr("y = %1")).arg(m_MousePos.y,7,'f',4); painter.drawText(5,46, str); painter.restore(); } /** * Draws the SplineFoil object. * @param painter a reference to the QPainter object with which to draw. */ void QAFoil::PaintSplines(QPainter &painter) { painter.save(); QPen CtrlPen; QBrush FillBrush(MainFrame::s_BackgroundColor); painter.setBrush(FillBrush); if(m_pSF->m_bVisible) { m_pSF->DrawFoil(painter, m_fScale,m_fScale*m_fScaleY, m_ptOffset); CtrlPen.setStyle(Qt::SolidLine); CtrlPen.setColor(m_pSF->m_FoilColor); painter.setPen(CtrlPen); m_pSF->DrawCtrlPoints(painter, m_fScale,m_fScale*m_fScaleY, m_ptOffset); if (m_pSF->m_bCenterLine) { m_pSF->DrawMidLine(painter, m_fScale,m_fScale*m_fScaleY, m_ptOffset); } if (m_pSF->m_bOutPoints) { m_pSF->DrawOutPoints(painter, m_fScale,m_fScale*m_fScaleY, m_ptOffset); } } painter.restore(); } /** * Draws the visible Foil objects. * @param painter a reference to the QPainter object with which to draw. */ void QAFoil::PaintFoils(QPainter &painter) { painter.save(); int k; Foil *pFoil; QPen FoilPen, CenterPen, CtrlPen; QBrush FillBrush(MainFrame::s_BackgroundColor); painter.setBrush(FillBrush); for (k=0; k< m_poaFoil->size(); k++) { pFoil = (Foil*)m_poaFoil->at(k); if (pFoil->m_bVisible) { FoilPen.setStyle(GetStyle(pFoil->m_nFoilStyle)); FoilPen.setWidth(pFoil->m_nFoilWidth); FoilPen.setColor(pFoil->m_FoilColor); painter.setPen(FoilPen); pFoil->DrawFoil(painter, 0.0, m_fScale, m_fScale*m_fScaleY,m_ptOffset); if (pFoil->m_bCenterLine) { CenterPen.setColor(pFoil->m_FoilColor); CenterPen.setStyle(Qt::DashLine); painter.setPen(CenterPen); pFoil->DrawMidLine(painter, m_fScale, m_fScale*m_fScaleY, m_ptOffset); } if (pFoil->m_bPoints) { CtrlPen.setColor(pFoil->m_FoilColor); painter.setPen(CtrlPen); pFoil->DrawPoints(painter, m_fScale,m_fScale*m_fScaleY, m_ptOffset); } } } if (m_pBufferFoil->m_bVisible) { m_pBufferFoil->DrawFoil(painter, 0.0, m_fScale, m_fScale*m_fScaleY,m_ptOffset); if (m_pBufferFoil->m_bCenterLine) { CenterPen.setColor(m_pBufferFoil->m_FoilColor); CenterPen.setStyle(Qt::DashLine); painter.setPen(CenterPen); m_pBufferFoil->DrawMidLine(painter, m_fScale, m_fScale*m_fScaleY, m_ptOffset); } if (m_pBufferFoil->m_bPoints) { CtrlPen.setColor(m_pBufferFoil->m_FoilColor); painter.setPen(CtrlPen); m_pBufferFoil->DrawPoints(painter, m_fScale,m_fScale*m_fScaleY, m_ptOffset); } } painter.restore(); } /** * Ends the zoom-in action. */ void QAFoil::ReleaseZoom() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->zoomInAct->setChecked(false); TwoDWidget *p2DWidget = (TwoDWidget*)s_p2DWidget; m_bZoomPlus = false; m_ZoomRect.setRight(m_ZoomRect.left()-1); m_ZoomRect.setTop(m_ZoomRect.bottom()+1); p2DWidget->setCursor(m_hcCross); } /** * Saves the user-defined settings. * @param pSettings a pointer to the QSetting object. */ void QAFoil::SaveSettings(QSettings *pSettings) { pSettings->beginGroup("DirectDesign"); { pSettings->setValue("XMajGrid", m_bXGrid); pSettings->setValue("YMajGrid", m_bYGrid); pSettings->setValue("XMinGrid", m_bXMinGrid); pSettings->setValue("YMinGrid", m_bYMinGrid); pSettings->setValue("XMajStyle", m_XGridStyle); pSettings->setValue("YMajStyle", m_YGridStyle); pSettings->setValue("XMajWidth", m_XGridWidth); pSettings->setValue("YMajWidth", m_YGridWidth); pSettings->setValue("XMinStyle", m_XMinStyle); pSettings->setValue("YMinStyle", m_YMinStyle); pSettings->setValue("XMinWidth", m_XMinWidth); pSettings->setValue("YMinWidth", m_YMinWidth); pSettings->setValue("XMajUnit", m_YGridUnit); pSettings->setValue("YMajUnit", m_YGridUnit); pSettings->setValue("XMinUnit", m_XMinUnit); pSettings->setValue("YMinUnit", m_YMinUnit); pSettings->setValue("XMajColorRed",m_XGridColor.red()); pSettings->setValue("XMajColorGreen",m_XGridColor.green()); pSettings->setValue("XMajColorBlue",m_XGridColor.blue()); pSettings->setValue("YMajColorRed", m_YGridColor.red()); pSettings->setValue("YMajColorGreen", m_YGridColor.green()); pSettings->setValue("YMajColorBlue", m_YGridColor.blue()); pSettings->setValue("XMinColorRed", m_XMinColor.red()); pSettings->setValue("XMinColorGreen", m_XMinColor.green()); pSettings->setValue("XMinColorBlue", m_XMinColor.blue()); pSettings->setValue("YMinColorRed", m_YMinColor.red()); pSettings->setValue("YMinColorGreen", m_YMinColor.green()); pSettings->setValue("YMinColorBlue", m_YMinColor.blue()); pSettings->setValue("NeutralLine", m_bNeutralLine); pSettings->setValue("NeutralStyle", m_NeutralStyle); pSettings->setValue("NeutralWidth", m_NeutralWidth); pSettings->setValue("NeutralColorRed", m_NeutralColor.red()); pSettings->setValue("NeutralColorGreen", m_NeutralColor.green()); pSettings->setValue("NeutralColorBlue", m_NeutralColor.blue()); pSettings->setValue("SFStyle", m_pSF->m_FoilStyle); pSettings->setValue("SFWidth", m_pSF->m_FoilWidth); pSettings->setValue("SFColorRed", m_pSF->m_FoilColor.red()); pSettings->setValue("SFColorGreen", m_pSF->m_FoilColor.green()); pSettings->setValue("SFColorBlue", m_pSF->m_FoilColor.blue()); pSettings->setValue("SFVisible", m_pSF->m_bVisible); pSettings->setValue("SFOutPoints", m_pSF->m_bOutPoints); pSettings->setValue("SFCenterLine", m_pSF->m_bCenterLine); pSettings->setValue("LowerRes", m_pSF->m_Intrados.m_iRes); pSettings->setValue("UpperRes", m_pSF->m_Extrados.m_iRes); pSettings->setValue("LECircle", m_bLECircle); pSettings->setValue("Scale", m_bScale); pSettings->setValue("Legend", m_bShowLegend ); QString str; for(int i=0; i<16; i++) { str = QString("Column_%1").arg(i); pSettings->setValue(str,m_pctrlFoilTable->columnWidth(i)); } for(int i=0; i<16; i++) { str = QString("Column_%1").arg(i); pSettings->setValue(str+"_hidden", m_pctrlFoilTable->isColumnHidden(i)); } } pSettings->endGroup(); } /** * Sets the default scale for the Foil display. */ void QAFoil::SetScale() { //scale is set by user zooming m_fRefScale = (double)m_rCltRect.width()-150.0; m_fScale = m_fRefScale; m_ptOffset.rx() = 75; m_ptOffset.ry() = (int)(m_rCltRect.height()/2); m_ViewportTrans = QPoint(0,0); } /** * Overloaded function. * Sets the default scale for the Foil display based on a specified client rectangle. */ void QAFoil::SetScale(QRect CltRect) { m_rCltRect = CltRect; SetScale(); } /** * The user has requested the context menu associated to the Foil table. * @param position the right-click positon */ void QAFoil::OnFoilTableCtxMenu(const QPoint & position) { // m_CurrentColumn = m_pctrlFoilTable->columnAt(position.x()); MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->AFoilTableCtxMenu->exec(cursor().pos()); } /** * Sets up the GUI. */ void QAFoil::SetupLayout() { QDesktopWidget desktop; QRect r = desktop.geometry(); // setMinimumHeight(r.height()/3); move(r.width()/3, r.height()/6); m_pctrlFoilTable = new QTableView(this); // m_pctrlFoilTable->setMinimumWidth(800); m_pctrlFoilTable->setSelectionMode(QAbstractItemView::SingleSelection); m_pctrlFoilTable->setSelectionBehavior(QAbstractItemView::SelectRows); m_pctrlFoilTable->setContextMenuPolicy(Qt::CustomContextMenu); QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::MinimumExpanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Expanding); m_pctrlFoilTable->setSizePolicy(szPolicyExpanding); QHBoxLayout *MainLayout = new QHBoxLayout; MainLayout->addWidget(m_pctrlFoilTable); setLayout(MainLayout); // connect(m_pctrlFoilTable, SIGNAL(clicked(const QModelIndex &)), this, SLOT(OnFoilClicked(const QModelIndex&))); connect(m_pctrlFoilTable, SIGNAL(pressed(const QModelIndex &)), this, SLOT(OnFoilClicked(const QModelIndex&))); connect(m_pctrlFoilTable, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(OnFoilTableCtxMenu(const QPoint &))); m_pFoilModel = new QStandardItemModel; m_pFoilModel->setRowCount(10);//temporary m_pFoilModel->setColumnCount(16); m_pFoilModel->setHeaderData(0, Qt::Horizontal, tr("Name")); m_pFoilModel->setHeaderData(1, Qt::Horizontal, tr("Thickness (%)")); m_pFoilModel->setHeaderData(2, Qt::Horizontal, tr("at (%)")); m_pFoilModel->setHeaderData(3, Qt::Horizontal, tr("Camber (%)")); m_pFoilModel->setHeaderData(4, Qt::Horizontal, tr("at (%)")); m_pFoilModel->setHeaderData(5, Qt::Horizontal, tr("Points")); m_pFoilModel->setHeaderData(6, Qt::Horizontal, tr("TE Flap (")+QString::fromUtf8("°")+")"); m_pFoilModel->setHeaderData(7, Qt::Horizontal, tr("TE XHinge")); m_pFoilModel->setHeaderData(8, Qt::Horizontal, tr("TE YHinge")); m_pFoilModel->setHeaderData(9, Qt::Horizontal, tr("LE Flap (")+QString::fromUtf8("°")+")"); m_pFoilModel->setHeaderData(10, Qt::Horizontal, tr("LE XHinge")); m_pFoilModel->setHeaderData(11, Qt::Horizontal, tr("LE YHinge")); m_pFoilModel->setHeaderData(12, Qt::Horizontal, tr("Show")); m_pFoilModel->setHeaderData(13, Qt::Horizontal, tr("Points")); m_pFoilModel->setHeaderData(14, Qt::Horizontal, tr("Centerline")); m_pFoilModel->setHeaderData(15, Qt::Horizontal, tr("Style")); m_pctrlFoilTable->setModel(m_pFoilModel); m_pctrlFoilTable->setWindowTitle(tr("Foils")); m_pctrlFoilTable->horizontalHeader()->setStretchLastSection(true); m_pFoilDelegate = new FoilTableDelegate; m_pctrlFoilTable->setItemDelegate(m_pFoilDelegate); m_pFoilDelegate->m_pFoilModel = m_pFoilModel; /* int unitwidth = (int)(750.0/16.0); m_pctrlFoilTable->setColumnWidth(0, 3*unitwidth); for(int i=1; i<16; i++) m_pctrlFoilTable->setColumnWidth(i, unitwidth);*/ m_pctrlFoilTable->setColumnHidden(9, true); m_pctrlFoilTable->setColumnHidden(10, true); m_pctrlFoilTable->setColumnHidden(11, true); int *precision = new int[16]; precision[0] = 2; precision[1] = 2; precision[2] = 2; precision[3] = 2; precision[4] = 2; precision[5] = 0; precision[6] = 2; precision[7] = 2; precision[8] = 2; precision[9] = 2; precision[10] = 2; precision[11] = 2; precision[12] = 2; precision[13] = 2; precision[14] = 2; precision[15] = 2; m_pFoilDelegate->m_Precision = precision; // connect(m_pFoilDelegate, SIGNAL(closeEditor(QWidget *)), this, SLOT(OnCellChanged(QWidget *))); } /** * Selects the specified foil in the table of Foil objects. This will highlight the corresponding row. * @param pFoil */ void QAFoil::SelectFoil(Foil* pFoil) { int i; if(pFoil) { QModelIndex ind; QString FoilName; for(i=0; i< m_pFoilModel->rowCount(); i++) { ind = m_pFoilModel->index(i, 0, QModelIndex()); FoilName = ind.model()->data(ind, Qt::EditRole).toString(); if(FoilName == pFoil->m_FoilName) { m_pctrlFoilTable->selectRow(i); break; } } } else { m_pctrlFoilTable->selectRow(0); } MainFrame::s_pCurFoil = pFoil; } /** * Initializes the Foil table, the QWidget and the QAction objects from the data. * Selects the current foil in the table */ void QAFoil::SetParams() { FillFoilTable(); SelectFoil(MainFrame::s_pCurFoil); CheckButtons(); } /** * Turns on or off the display of the current Foil object. * @param pFoil a pointer to the Foil object to show * @param bShow the new visibility status of the Foil */ void QAFoil::ShowFoil(Foil* pFoil, bool bShow) { if(!pFoil) return; MainFrame::s_pCurFoil->m_bVisible = bShow; MainFrame::SetSaveState(false); } /** * Copies the current SplineFoil object to a new SplineFoil object and pushes it on the stack. */ void QAFoil::TakePicture() { //clear the downstream part of the stack which becomes obsolete ClearStack(m_StackPos); // append a copy of the current object m_UndoStack.append(SplineFoil(m_pSF)); // the new current position is the top of the stack m_StackPos = m_UndoStack.size()-1; m_bStored = true; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(s_pMainFrame && pMainFrame->UndoAFoilAct && pMainFrame->RedoAFoilAct) { pMainFrame->UndoAFoilAct->setEnabled(m_StackPos>0); pMainFrame->RedoAFoilAct->setEnabled(m_StackPosCopy(&SF); m_pSF->m_Intrados.SplineKnots(); m_pSF->m_Intrados.SplineCurve(); m_pSF->m_Extrados.SplineKnots(); m_pSF->m_Extrados.SplineCurve(); m_pSF->UpdateSplineFoil(); UpdateView(); } /** * The user has requested to Undo the last modification to the SplineFoil object. */ void QAFoil::OnUndo() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(m_StackPos>0) { m_StackPos--; SetPicture(); pMainFrame->UndoAFoilAct->setEnabled(m_StackPos>0); pMainFrame->RedoAFoilAct->setEnabled(m_StackPosUndoAFoilAct->setEnabled(m_StackPos>0); pMainFrame->RedoAFoilAct->setEnabled(m_StackPospos; il--) { m_UndoStack.removeAt(il); // remove from the stack } m_StackPos = m_UndoStack.size()-1; } /** * Refreshes the view. */ void QAFoil::UpdateView() { TwoDWidget *p2DWidget = (TwoDWidget*)s_p2DWidget; if(s_p2DWidget) { p2DWidget->update(); } } /** * Overrides the QWidget's wheelEvent method. * Dispatches the event * @param event the QWheelEvent */ void QAFoil::wheelEvent(QWheelEvent *event) { if(! m_rCltRect.contains(event->pos())) return; m_ZoomRect.setBottomRight(m_ZoomRect.topLeft()); ReleaseZoom(); static double ZoomFactor, scale; if(event->delta()>0) { if(!MainFrame::s_bReverseZoom) ZoomFactor = 1./1.06; else ZoomFactor = 1.06; } else { if(!MainFrame::s_bReverseZoom) ZoomFactor = 1.06; else ZoomFactor = 1./1.06; } scale = m_fScale; if(!m_bZoomYOnly) { if (m_bXDown) { m_fScale *= ZoomFactor; m_fScaleY *= 1./ZoomFactor; } else if (m_bYDown) m_fScaleY *= ZoomFactor; else m_fScale *= ZoomFactor; } else m_fScaleY *= ZoomFactor; int a = (int)((m_rCltRect.right() + m_rCltRect.left())/2); m_ptOffset.rx() = a + (int)((m_ptOffset.x()-a)*m_fScale/scale); m_ViewportTrans.rx() = (int)((m_ViewportTrans.x())*m_fScale /scale); m_ViewportTrans.ry() = (int)((m_ViewportTrans.y())*m_fScale /scale); UpdateView(); } /** * The width of the columns in the Foil table has been changed. */ void QAFoil::OnColumnWidths() { int unitwidth = (int)((double)m_pctrlFoilTable->width()/16.0); m_pctrlFoilTable->setColumnWidth(0, 3*unitwidth); for(int i=1; i<16; i++) m_pctrlFoilTable->setColumnWidth(i, unitwidth); m_pctrlFoilTable->setColumnHidden(9, true); m_pctrlFoilTable->setColumnHidden(10, true); m_pctrlFoilTable->setColumnHidden(11, true); } /** * The user has requested the lanuch of the interface to show or hide the columns of the Foil table. */ void QAFoil::OnAFoilTableColumns() { AFoilTableDlg dlg((MainFrame*)s_pMainFrame); dlg.m_bFoilName = !m_pctrlFoilTable->isColumnHidden(0); dlg.m_bThickness = !m_pctrlFoilTable->isColumnHidden(1); dlg.m_bThicknessAt = !m_pctrlFoilTable->isColumnHidden(2); dlg.m_bCamber = !m_pctrlFoilTable->isColumnHidden(3); dlg.m_bCamberAt = !m_pctrlFoilTable->isColumnHidden(4); dlg.m_bPoints = !m_pctrlFoilTable->isColumnHidden(5); dlg.m_bTEFlapAngle = !m_pctrlFoilTable->isColumnHidden(6); dlg.m_bTEXHinge = !m_pctrlFoilTable->isColumnHidden(7); dlg.m_bTEYHinge = !m_pctrlFoilTable->isColumnHidden(8); dlg.m_bLEFlapAngle = !m_pctrlFoilTable->isColumnHidden(9); dlg.m_bLEXHinge = !m_pctrlFoilTable->isColumnHidden(10); dlg.m_bLEYHinge = !m_pctrlFoilTable->isColumnHidden(11); dlg.InitDialog(); if(dlg.exec()==QDialog::Accepted) { m_pctrlFoilTable->setColumnHidden(0, !dlg.m_bFoilName); m_pctrlFoilTable->setColumnHidden(1, !dlg.m_bThickness); m_pctrlFoilTable->setColumnHidden(2, !dlg.m_bThicknessAt); m_pctrlFoilTable->setColumnHidden(3, !dlg.m_bCamber); m_pctrlFoilTable->setColumnHidden(4, !dlg.m_bCamberAt); m_pctrlFoilTable->setColumnHidden(5, !dlg.m_bPoints); m_pctrlFoilTable->setColumnHidden(6, !dlg.m_bTEFlapAngle); m_pctrlFoilTable->setColumnHidden(7, !dlg.m_bTEXHinge); m_pctrlFoilTable->setColumnHidden(8, !dlg.m_bTEYHinge); m_pctrlFoilTable->setColumnHidden(9, !dlg.m_bLEFlapAngle); m_pctrlFoilTable->setColumnHidden(10, !dlg.m_bLEXHinge); m_pctrlFoilTable->setColumnHidden(11, !dlg.m_bLEYHinge); } } /** * The user has requested to load a background image in the view. */ void QAFoil::OnLoadBackImage() { QString PathName; PathName = QFileDialog::getOpenFileName(this, tr("Open Image File"), MainFrame::s_LastDirName, "Image files (*.png *.jpg *.bmp)"); m_bIsImageLoaded = m_BackImage.load(PathName); UpdateView(); } /** * The user has requested to clear the background image. */ void QAFoil::OnClearBackImage() { m_bIsImageLoaded = false; UpdateView(); } /** * The client area has been resized. Update the column widths. * @param event the QResizeEvent. */ void QAFoil::resizeEvent(QResizeEvent *event) { int ncol = m_pctrlFoilTable->horizontalHeader()->count() - m_pctrlFoilTable->horizontalHeader()->hiddenSectionCount(); //add 1 to get double width for the name ncol++; //get column width and spare 10% for horizontal header int unitwidth = (int)((double)(m_pctrlFoilTable->width())/(double)ncol/1.1); m_pctrlFoilTable->setColumnWidth(0, 2*unitwidth); for(int i=1; i<16; i++) m_pctrlFoilTable->setColumnWidth(i, unitwidth); } /** * The user has requested the insertion of a control point in the SplineFoil at the location of the mouse */ void QAFoil::OnInsertCtrlPt() { if(MainFrame::s_pCurFoil) return; // Action can be performed only if the spline foil is selected CVector Real = MousetoReal(m_PointDown); if(Real.y>=0) { m_pSF->m_Extrados.InsertPoint(Real.x,Real.y); m_pSF->m_Extrados.SplineKnots(); m_pSF->m_Extrados.SplineCurve(); m_pSF->UpdateSplineFoil(); } else { m_pSF->m_Intrados.InsertPoint(Real.x,Real.y); m_pSF->m_Intrados.SplineKnots(); m_pSF->m_Intrados.SplineCurve(); m_pSF->UpdateSplineFoil(); } // TakePicture(); } /** * The user has requested the deletion of a control point in the SplineFoil at the location of the mouse. */ void QAFoil::OnRemoveCtrlPt() { //Removes a point in the spline if(MainFrame::s_pCurFoil) return; // Action can be performed only if the spline foil is selected MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; CVector Real = MousetoReal(m_PointDown); int n = m_pSF->m_Extrados.IsControlPoint(Real, m_fScale/m_fRefScale); if (n>=0) { if(!m_pSF->m_Extrados.RemovePoint(n)) { QMessageBox::warning(pMainFrame,tr("Warning"), tr("The minimum number of control points has been reached for this spline degree")); return; } m_pSF->m_Extrados.SplineKnots(); m_pSF->m_Extrados.SplineCurve(); m_pSF->UpdateSplineFoil(); } else { int n=m_pSF->m_Intrados.IsControlPoint(Real, m_fScale/m_fRefScale); if (n>=0) { if(!m_pSF->m_Intrados.RemovePoint(n)) { QMessageBox::warning(pMainFrame,tr("Warning"), tr("The minimum number of control points has been reached for this spline degree")); return; } m_pSF->m_Intrados.SplineKnots(); m_pSF->m_Intrados.SplineCurve(); m_pSF->UpdateSplineFoil(); } } // TakePicture(); } xflr5-6.09-06/src/design/SplineCtrlsDlg.h000644 001750 000144 00000004074 12247174406 021404 0ustar00techwinderusers000000 000000 /**************************************************************************** SplineCtrlsDlg Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef SPLINECTRLSDLG_H #define SPLINECTRLSDLG_H #include "../misc/DoubleEdit.h" #include "../objects/SplineFoil.h" #include "../misc/FloatEditDelegate.h" #include #include #include #include #include #include #include class SplineCtrlsDlg : public QDialog { Q_OBJECT friend class QAFoil; public: SplineCtrlsDlg(QWidget *pParent); void InitDialog(); private slots: void OnOK(); void OnUpdate(); private: void keyPressEvent(QKeyEvent *event); void showEvent(QShowEvent *event); void FillPointLists(); void ReadData(); void SetControls(); void SetupLayout(); void UpdateSplines(); DoubleEdit *m_pctrlOutExtrados; DoubleEdit *m_pctrlOutIntrados; QComboBox *m_pctrlDegExtrados; QComboBox *m_pctrlDegIntrados; QPushButton *OKButton, *CancelButton; QCheckBox *m_pctrlSymetric; QSlider *m_pctrlPtWeight; QTableView *m_pctrlUpperList, *m_pctrlLowerList; QStandardItemModel *m_pUpperListModel,*m_pLowerListModel; FloatEditDelegate *m_pUpperFloatDelegate, *m_pLowerFloatDelegate; protected: SplineFoil *m_pSF; static void *s_pAFoil; }; #endif // SPLINECTRLSDLG_H xflr5-6.09-06/src/design/AFoilGridDlg.cpp000644 001750 000144 00000024706 12247174406 021301 0ustar00techwinderusers000000 000000 /**************************************************************************** AFoilGridDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "AFoil.h" #include "AFoilGridDlg.h" #include #include #include #include "../misc/LinePickerDlg.h" AFoilGridDlg::AFoilGridDlg(QWidget *pParent): QDialog(pParent) { setWindowTitle(tr("Grid Options")); m_pAFoil = pParent; m_bScale = false; m_bXGrid = false; m_XUnit = 0.05; m_XStyle = 1; m_XWidth = 1; m_XColor = QColor(150,150,150); m_bYGrid = false; m_YUnit = 0.05; m_YStyle = 1; m_YWidth = 1; m_YColor = QColor(150,150,150); m_bXMinGrid = false; m_XMinUnit = 0.01; m_XMinStyle = 2; m_XMinWidth = 1; m_XMinColor = QColor(70,70,70); m_bYMinGrid = false; m_YMinUnit = 0.01; m_YMinStyle = 2; m_YMinWidth = 1; m_YMinColor = QColor(70,70,70); m_NeutralStyle = 3; m_NeutralWidth = 1; m_NeutralColor = QColor(70,70,70); SetupLayout(); connect(ApplyButton, SIGNAL(clicked()),this, SLOT(OnApply())); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(m_pctrlScale, SIGNAL(clicked()), this, SLOT(OnScale())); connect(m_pctrlNeutralShow, SIGNAL(clicked(bool)), this, SLOT(OnNeutralShow(bool))); connect(m_pctrlXMajShow, SIGNAL(clicked(bool)), this, SLOT(OnXMajShow(bool))); connect(m_pctrlYMajShow, SIGNAL(clicked(bool)), this, SLOT(OnYMajShow(bool))); connect(m_pctrlXMinShow, SIGNAL(clicked(bool)), this, SLOT(OnXMinShow(bool))); connect(m_pctrlYMinShow, SIGNAL(clicked(bool)), this, SLOT(OnYMinShow(bool))); connect(m_pctrlNeutralStyle, SIGNAL(clickedLB()), this, SLOT(OnNeutralStyle())); connect(m_pctrlXMajStyle, SIGNAL(clickedLB()), this, SLOT(OnXMajStyle())); connect(m_pctrlYMajStyle, SIGNAL(clickedLB()), this, SLOT(OnYMajStyle())); connect(m_pctrlXMinStyle, SIGNAL(clickedLB()), this, SLOT(OnXMinStyle())); connect(m_pctrlYMinStyle, SIGNAL(clickedLB()), this, SLOT(OnYMinStyle())); } void AFoilGridDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Escape: { done(0); break; } case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OnApply(); OKButton->setFocus(); // m_bApplied = true; } else { QDialog::accept(); } break; } default: event->ignore(); } } void AFoilGridDlg::InitDialog() { m_pctrlNeutralStyle->SetStyle(m_NeutralStyle, m_NeutralWidth, m_NeutralColor); m_pctrlXMajStyle->SetStyle(m_XStyle, m_XWidth, m_XColor); m_pctrlXMinStyle->SetStyle(m_XMinStyle, m_XMinWidth, m_XMinColor); m_pctrlYMajStyle->SetStyle(m_YStyle, m_YWidth, m_YColor); m_pctrlYMinStyle->SetStyle(m_YMinStyle, m_YMinWidth, m_YMinColor); m_pctrlNeutralStyle->setEnabled(m_bNeutralLine); m_pctrlXMajStyle->setEnabled(m_bXGrid); m_pctrlYMajStyle->setEnabled(m_bYGrid); m_pctrlXMinStyle->setEnabled(m_bXMinGrid); m_pctrlYMinStyle->setEnabled(m_bYMinGrid); m_pctrlXUnit->setEnabled(m_bXGrid); m_pctrlYUnit->setEnabled(m_bYGrid); m_pctrlXMinUnit->setEnabled(m_bXMinGrid); m_pctrlYMinUnit->setEnabled(m_bYMinGrid); m_pctrlScale->setChecked(m_bScale); m_pctrlNeutralShow->setChecked(m_bNeutralLine); m_pctrlXMajShow->setChecked(m_bXGrid); m_pctrlYMajShow->setChecked(m_bYGrid); m_pctrlXMinShow->setChecked(m_bXMinGrid); m_pctrlYMinShow->setChecked(m_bYMinGrid); m_pctrlXUnit->SetValue(m_XUnit); m_pctrlYUnit->SetValue(m_YUnit); m_pctrlXMinUnit->SetValue(m_XMinUnit); m_pctrlYMinUnit->SetValue(m_YMinUnit); } void AFoilGridDlg::SetupLayout() { QGridLayout *GridData = new QGridLayout; { m_pctrlNeutralShow = new QCheckBox(tr("Neutral Line")); m_pctrlScale = new QCheckBox(tr("X-Scale")); m_pctrlXMajShow = new QCheckBox(tr("X Major Grid")); m_pctrlYMajShow = new QCheckBox(tr("Y Major Grid")); m_pctrlXMinShow = new QCheckBox(tr("X Minor Grid")); m_pctrlYMinShow = new QCheckBox(tr("Y Minor Grid")); m_pctrlNeutralStyle = new LineBtn(this); m_pctrlXMajStyle = new LineBtn(this); m_pctrlYMajStyle = new LineBtn(this); m_pctrlXMinStyle = new LineBtn(this); m_pctrlYMinStyle = new LineBtn(this); m_pctrlXUnit = new DoubleEdit; m_pctrlYUnit = new DoubleEdit; m_pctrlXMinUnit = new DoubleEdit; m_pctrlYMinUnit = new DoubleEdit; m_pctrlXUnit->SetPrecision(3); m_pctrlYUnit->SetPrecision(3); m_pctrlXMinUnit->SetPrecision(3); m_pctrlYMinUnit->SetPrecision(3); GridData->addWidget(m_pctrlNeutralShow,1,1); GridData->addWidget(m_pctrlXMajShow,2,1); GridData->addWidget(m_pctrlYMajShow,3,1); GridData->addWidget(m_pctrlXMinShow,4,1); GridData->addWidget(m_pctrlYMinShow,5,1); GridData->addWidget(m_pctrlNeutralStyle,1,2); GridData->addWidget(m_pctrlXMajStyle,2,2); GridData->addWidget(m_pctrlYMajStyle,3,2); GridData->addWidget(m_pctrlXMinStyle,4,2); GridData->addWidget(m_pctrlYMinStyle,5,2); GridData->addWidget(m_pctrlScale,1,3); GridData->addWidget(m_pctrlXUnit,2,3); GridData->addWidget(m_pctrlYUnit,3,3); GridData->addWidget(m_pctrlXMinUnit,4,3); GridData->addWidget(m_pctrlYMinUnit,5,3); } QHBoxLayout *CommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("Accept")); CancelButton = new QPushButton(tr("Cancel")); ApplyButton = new QPushButton(tr("Apply")); CommandButtons->addStretch(1); CommandButtons->addWidget(ApplyButton); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); } QVBoxLayout *mainLayout = new QVBoxLayout; { mainLayout->addLayout(GridData); mainLayout->addLayout(CommandButtons); } setLayout(mainLayout); } void AFoilGridDlg::OnNeutralStyle() { LinePickerDlg dlg(this); dlg.InitDialog(m_NeutralStyle,m_NeutralWidth,m_NeutralColor); if(QDialog::Accepted==dlg.exec()) { m_NeutralStyle = dlg.GetStyle(); m_NeutralWidth = dlg.GetWidth(); m_NeutralColor = dlg.GetColor(); m_pctrlNeutralStyle->SetStyle(dlg.GetStyle()); m_pctrlNeutralStyle->SetWidth(dlg.GetWidth()); m_pctrlNeutralStyle->SetColor(dlg.GetColor()); } } void AFoilGridDlg::OnXMajStyle() { LinePickerDlg dlg(this); dlg.InitDialog(m_XStyle,m_XWidth,m_XColor); if(QDialog::Accepted==dlg.exec()) { m_XStyle = dlg.GetStyle(); m_XWidth = dlg.GetWidth(); m_XColor = dlg.GetColor(); m_pctrlXMajStyle->SetStyle(dlg.GetStyle()); m_pctrlXMajStyle->SetWidth(dlg.GetWidth()); m_pctrlXMajStyle->SetColor(dlg.GetColor()); } } void AFoilGridDlg::OnXMinStyle() { LinePickerDlg dlg(this); dlg.InitDialog(m_XMinStyle,m_XMinWidth,m_XMinColor); if(QDialog::Accepted==dlg.exec()) { m_XMinStyle = dlg.GetStyle(); m_XMinWidth = dlg.GetWidth(); m_XMinColor = dlg.GetColor(); m_pctrlXMinStyle->SetStyle(dlg.GetStyle()); m_pctrlXMinStyle->SetWidth(dlg.GetWidth()); m_pctrlXMinStyle->SetColor(dlg.GetColor()); } } void AFoilGridDlg::OnYMajStyle() { LinePickerDlg dlg(this); dlg.InitDialog(m_YStyle,m_YWidth,m_YColor); if(QDialog::Accepted==dlg.exec()) { m_YStyle = dlg.GetStyle(); m_YWidth = dlg.GetWidth(); m_YColor = dlg.GetColor(); m_pctrlYMajStyle->SetStyle(dlg.GetStyle()); m_pctrlYMajStyle->SetWidth(dlg.GetWidth()); m_pctrlYMajStyle->SetColor(dlg.GetColor()); } } void AFoilGridDlg::OnYMinStyle() { LinePickerDlg dlg(this); dlg.InitDialog(m_YMinStyle,m_YMinWidth,m_YMinColor); if(QDialog::Accepted==dlg.exec()) { m_YMinStyle = dlg.GetStyle(); m_YMinWidth = dlg.GetWidth(); m_YMinColor = dlg.GetColor(); m_pctrlYMinStyle->SetStyle(dlg.GetStyle()); m_pctrlYMinStyle->SetWidth(dlg.GetWidth()); m_pctrlYMinStyle->SetColor(dlg.GetColor()); } } void AFoilGridDlg::OnNeutralShow(bool bShow) { m_bNeutralLine = bShow; m_pctrlNeutralStyle->setEnabled(m_bNeutralLine); } void AFoilGridDlg::OnScale() { m_bScale = m_pctrlScale->isChecked(); } void AFoilGridDlg::OnXMajShow(bool bShow) { m_bXGrid = bShow; m_pctrlXMajStyle->setEnabled(m_bXGrid); m_pctrlXUnit->setEnabled(m_bXGrid); } void AFoilGridDlg::OnYMajShow(bool bShow) { m_bYGrid = bShow; m_pctrlYMajStyle->setEnabled(m_bYGrid); m_pctrlYUnit->setEnabled(m_bYGrid); } void AFoilGridDlg::OnXMinShow(bool bShow) { m_bXMinGrid = bShow; m_pctrlXMinStyle->setEnabled(m_bXMinGrid); m_pctrlXMinUnit->setEnabled(m_bXMinGrid); } void AFoilGridDlg::OnYMinShow(bool bShow) { m_bYMinGrid = bShow; m_pctrlYMinStyle->setEnabled(m_bYMinGrid); m_pctrlYMinUnit->setEnabled(m_bYMinGrid); } void AFoilGridDlg::OnOK() { m_XUnit = m_pctrlXUnit->Value(); m_YUnit = m_pctrlYUnit->Value(); m_XMinUnit = m_pctrlXMinUnit->Value(); m_YMinUnit = m_pctrlYMinUnit->Value(); accept(); } void AFoilGridDlg::OnApply() { if(!m_pAFoil) return; QAFoil *pAFoil = (QAFoil*)m_pAFoil; m_XUnit = m_pctrlXUnit->Value(); m_YUnit = m_pctrlYUnit->Value(); m_XMinUnit = m_pctrlXMinUnit->Value(); m_YMinUnit = m_pctrlYMinUnit->Value(); pAFoil->m_bScale = m_bScale; pAFoil->m_bNeutralLine = m_bNeutralLine; pAFoil->m_NeutralStyle = m_NeutralStyle; pAFoil->m_NeutralWidth = m_NeutralWidth; pAFoil->m_NeutralColor = m_NeutralColor; pAFoil->m_bXGrid = m_bXGrid; pAFoil->m_bXMinGrid = m_bXMinGrid; pAFoil->m_XGridStyle = m_XStyle; pAFoil->m_XGridWidth = m_XWidth; pAFoil->m_XGridColor = m_XColor; pAFoil->m_XGridUnit = m_XUnit; pAFoil->m_XMinStyle = m_XMinStyle; pAFoil->m_XMinWidth = m_XMinWidth; pAFoil->m_XMinColor = m_XMinColor; pAFoil->m_XMinUnit = m_XMinUnit; pAFoil->m_bYGrid = m_bYGrid; pAFoil->m_bYMinGrid = m_bYMinGrid; pAFoil->m_YGridStyle = m_YStyle; pAFoil->m_YGridWidth = m_YWidth; pAFoil->m_YGridColor = m_YColor; pAFoil->m_YGridUnit = m_YUnit; pAFoil->m_YMinStyle = m_YMinStyle; pAFoil->m_YMinWidth = m_YMinWidth; pAFoil->m_YMinColor = m_YMinColor; pAFoil->m_YMinUnit = m_YMinUnit; pAFoil->UpdateView(); } xflr5-6.09-06/src/design/FoilTableDelegate.cpp000644 001750 000144 00000021200 12247174407 022331 0ustar00techwinderusers000000 000000 /**************************************************************************** FoilTableDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include "FoilTableDelegate.h" #include "AFoil.h" #include "../globals.h" void *FoilTableDelegate::s_pAFoil; FoilTableDelegate::FoilTableDelegate(QObject *parent) : QItemDelegate(parent) { } QWidget *FoilTableDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex & index ) const { return NULL;//No edition possible - display only if(index.column()==0) { QLineEdit *editor = new QLineEdit(parent); editor->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); return editor; } else { DoubleEdit *editor = new DoubleEdit(parent); editor->setAlignment(Qt::AlignRight | Qt::AlignVCenter); editor->SetPrecision(m_Precision[index.column()]); return editor; } return NULL; } void FoilTableDelegate::drawCheck(QPainter *painter, const QStyleOptionViewItem &option, const QRect &, Qt::CheckState state) const { const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; /* QRect checkRect = QStyle::alignedRect(option.direction, Qt::AlignCenter, check(option, option.rect, Qt::Checked).size(), QRect(option.rect.x() + textMargin, option.rect.y(), option.rect.width() - (textMargin * 2), option.rect.height()));*/ QRect checkRect = QStyle::alignedRect(option.direction, Qt::AlignCenter, option.rect.size(), QRect(option.rect.x() + textMargin, option.rect.y(), option.rect.width() - (2 * textMargin), option.rect.height())); QItemDelegate::drawCheck(painter, option, checkRect, state); } bool FoilTableDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { if(index.column()<12) return false; // make sure that the item is checkable Qt::ItemFlags flags = model->flags(index); if (!(flags & Qt::ItemIsUserCheckable) || !(flags & Qt::ItemIsEnabled)) return false; // make sure that we have a check state QVariant value = index.data(Qt::CheckStateRole); if (!value.isValid()) return false; // make sure that we have the right event type if (event->type() == QEvent::MouseButtonRelease) { const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; /* QRect checkRect = QStyle::alignedRect(option.direction, Qt::AlignCenter, check(option, option.rect, Qt::Checked).size(), QRect(option.rect.x() + textMargin, option.rect.y(), option.rect.width() - (2 * textMargin), option.rect.height()));*/ QRect checkRect = QStyle::alignedRect(option.direction, Qt::AlignCenter, option.rect.size(), QRect(option.rect.x() + textMargin, option.rect.y(), option.rect.width() - (2 * textMargin), option.rect.height())); /* QRect QStyle::alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment, const QSize & size, const QRect & rectangle) [static] Returns a new rectangle of the specified size that is aligned to the given rectangle according to the specified alignment and direction.*/ if (!checkRect.contains(static_cast(event)->pos())) return false; } else if (event->type() == QEvent::KeyPress) { if ( static_cast(event)->key() != Qt::Key_Space && static_cast(event)->key() != Qt::Key_Select) return false; } else { return false; } Qt::CheckState state = (static_cast(value.toInt()) == Qt::Checked ? Qt::Unchecked : Qt::Checked); QAFoil *pAFoil = (QAFoil*)s_pAFoil; bool bSuccess = model->setData(index, state, Qt::CheckStateRole); if(bSuccess) pAFoil->FoilVisibleClicked(index); return bSuccess; } void FoilTableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QString strong; QStyleOptionViewItem myOption = option; QAFoil *pAFoil = (QAFoil*)s_pAFoil; int NFoils = pAFoil->m_poaFoil->size(); if(index.row()> NFoils) { strong=" "; drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } else if(index.column()==0) { myOption.displayAlignment = Qt::AlignLeft | Qt::AlignVCenter; strong = index.model()->data(index, Qt::DisplayRole).toString(); drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } else if(index.column()==5) { myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; strong = QString("%1").arg(index.model()->data(index, Qt::DisplayRole).toInt()); drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } else if(index.column()==6 || index.column()==9) { myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; strong = QString("%1").arg(index.model()->data(index, Qt::DisplayRole).toDouble(), 0,'f',m_Precision[index.column()]); drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } else if(index.column()==12 || index.column()==13 || index.column()==14) { QVariant value = index.data(Qt::CheckStateRole); // Qt::CheckState state = (static_cast(value.toInt()) == Qt::Checked ? Qt::Unchecked : Qt::Checked); Qt::CheckState state; if(value.toInt()==0) state = Qt::Unchecked; else state = Qt::Checked; drawCheck(painter,myOption, myOption.rect, state); drawFocus(painter, myOption, myOption.rect); } else if(index.column()==15) { QColor color; int style, width; //get a link to the foil to get its style if(index.row()==0) { color = pAFoil->m_pSF->m_FoilColor; style = pAFoil->m_pSF->m_FoilStyle; width = pAFoil->m_pSF->m_FoilWidth; } else { Foil *pFoil = (Foil*)pAFoil->m_poaFoil->at(index.row()-1); color = pFoil->m_FoilColor; style = pFoil->m_nFoilStyle; width = pFoil->m_nFoilWidth; } QRect r = option.rect; r = pAFoil->m_pctrlFoilTable->visualRect(index);; QColor ContourColor = Qt::gray; painter->setBrush(Qt::NoBrush); painter->setBackgroundMode(Qt::TransparentMode); QPen LinePen(color); LinePen.setStyle(::GetStyle(style)); LinePen.setWidth(width); painter->setPen(LinePen); painter->drawLine(r.left()+5, r.top()+r.height()/2, r.right()-5, r.top()+r.height()/2); QPen ContourPen(ContourColor); painter->setPen(ContourPen); r.adjust(0,2,-1,-3); painter->drawRoundRect(r,5,40); drawFocus(painter, myOption, myOption.rect); } else { myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; strong = QString("%1").arg(index.model()->data(index, Qt::DisplayRole).toDouble()*100.0, 0,'f', m_Precision[index.column()]); drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } } void FoilTableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if(index.column()==0) { QString strong = index.model()->data(index, Qt::EditRole).toString(); QLineEdit *lineEdit = (QLineEdit*)editor; lineEdit->setText(strong); } else { double value = index.model()->data(index, Qt::EditRole).toDouble(); DoubleEdit *pDE = static_cast(editor); pDE->SetValue(value); } } void FoilTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { if(index.column()==0) { QString strong; QLineEdit *pLineEdit = static_cast(editor); strong = pLineEdit->text(); model->setData(index, strong, Qt::EditRole); } else { DoubleEdit *pDE = static_cast(editor); double value = pDE->Value()/100.0; model->setData(index, value, Qt::EditRole); } } void FoilTableDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { editor->setGeometry(option.rect); } xflr5-6.09-06/src/design/AFoilGridDlg.h000644 001750 000144 00000004557 12247174407 020751 0ustar00techwinderusers000000 000000 /**************************************************************************** AFoilGridDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef AFOILGRIDDLG_H #define AFOILGRIDDLG_H #include #include #include #include "../misc/LineBtn.h" #include "../misc/DoubleEdit.h" class AFoilGridDlg : public QDialog { Q_OBJECT friend class QAFoil; public: AFoilGridDlg(QWidget *pParent); void InitDialog(); private slots: void OnApply(); void OnOK(); void OnScale(); void OnNeutralStyle(); void OnXMajStyle(); void OnXMinStyle(); void OnYMajStyle(); void OnYMinStyle(); void OnNeutralShow(bool bShow); void OnXMajShow(bool bShow); void OnYMajShow(bool bShow); void OnXMinShow(bool bShow); void OnYMinShow(bool bShow); private: void SetupLayout(); void keyPressEvent(QKeyEvent *event); void *m_pAFoil; QCheckBox *m_pctrlNeutralShow, *m_pctrlScale, *m_pctrlXMajShow, *m_pctrlYMajShow, *m_pctrlXMinShow, *m_pctrlYMinShow; LineBtn *m_pctrlNeutralStyle, *m_pctrlXMajStyle, *m_pctrlYMajStyle, *m_pctrlXMinStyle, *m_pctrlYMinStyle; DoubleEdit *m_pctrlXUnit, *m_pctrlYUnit,*m_pctrlXMinUnit, *m_pctrlYMinUnit; QPushButton *ApplyButton, *OKButton, *CancelButton; bool m_bNeutralLine, m_bScale; bool m_bXGrid,m_bYGrid; bool m_bXMinGrid, m_bYMinGrid; int m_XStyle, m_YStyle; int m_XWidth, m_YWidth; int m_XMinStyle, m_YMinStyle; int m_XMinWidth, m_YMinWidth; int m_NeutralStyle, m_NeutralWidth; double m_XUnit, m_YUnit; double m_XMinUnit, m_YMinUnit; QColor m_XColor,m_YColor; QColor m_XMinColor,m_YMinColor; QColor m_NeutralColor; }; #endif // AFOILGRIDDLG_H xflr5-6.09-06/src/design/LECircleDlg.h000644 001750 000144 00000002723 12247174406 020563 0ustar00techwinderusers000000 000000 /**************************************************************************** LECircleDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef LECIRCLEDLG_H #define LECIRCLEDLG_H #include #include #include #include "../misc/DoubleEdit.h" class LECircleDlg : public QDialog { Q_OBJECT friend class QAFoil; public: LECircleDlg(QWidget *pParent); void SetupLayout(); void InitDialog(); private slots: void OnOK(); private: void keyPressEvent(QKeyEvent *event); private: QCheckBox *m_pctrlShow; DoubleEdit *m_pctrlRadius; QPushButton *OKButton, *CancelButton; double m_Radius; bool m_bShowRadius; void* m_pAFoil; }; #endif // LECIRCLEDLG_H xflr5-6.09-06/src/main.cpp000644 001750 000144 00000003004 12247174406 016511 0ustar00techwinderusers000000 000000 /**************************************************************************** QFLR5 Application Copyright (C) 2008-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "XFLR5Application.h" #include "mainframe.h" #include #include /** *The app's point of entry ! */ int main(int argc, char *argv[]) { #if QT_VERSION >= 0x040600 // QGL::setPreferredPaintEngine (QPaintEngine::OpenGL); #endif #ifdef Q_OS_MACX if ( QSysInfo::MacintoshVersion > QSysInfo::MV_10_8 ) { // fix Mac OS X 10.9 (mavericks) font issue // https://bugreports.qt-project.org/browse/QTBUG-32789 QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); } #endif XFLR5Application app(argc, argv); return app.exec(); } xflr5-6.09-06/src/xdirect/000755 001750 000144 00000000000 12250003437 016513 5ustar00techwinderusers000000 000000 xflr5-6.09-06/src/xdirect/XFoilAnalysisDlg.cpp000644 001750 000144 00000031403 12247174410 022402 0ustar00techwinderusers000000 000000 /**************************************************************************** XFoilAnalysisDlg Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include "XFoilAnalysisDlg.h" #include "XDirect.h" #include "../mainframe.h" void *XFoilAnalysisDlg::s_pMainFrame; void *XFoilAnalysisDlg::s_pXDirect; QPoint XFoilAnalysisDlg::s_Position; XFoilAnalysisDlg::XFoilAnalysisDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("XFoil Analysis")); SetupLayout(); m_RmsGraph.SetXTitle(tr("Iter")); m_RmsGraph.SetYTitle("");//Change from bl newton system solution m_RmsGraph.SetAuto(true); m_RmsGraph.SetXMajGrid(true, QColor(120,120,120),2,1); m_RmsGraph.SetYMajGrid(true, QColor(120,120,120),2,1); m_RmsGraph.SetXMin(0.0); m_RmsGraph.SetXMax(50); m_RmsGraph.SetYMin(0.0); m_RmsGraph.SetYMax(1.0); m_RmsGraph.SetType(1); m_RmsGraph.SetXTitle("abs"); m_RmsGraph.SetYTitle("rms"); m_RmsGraph.SetMargin(.1); m_bSkip = false; m_bExit = false; m_bFinished = false; m_bAutoInitBL = true; m_pXFile = NULL; m_Iterations = 0; m_IterLim = 20; m_bType4 = false; m_bSequence = false; m_bAlpha = true; m_LegendPlace.rx() = 0; m_LegendPlace.ry() = 0; m_AlphaMin = 0.0; m_AlphaMax = 1.0; m_DeltaAlpha = 0.5; m_ClMin = 0.0; m_ClMax = 1.0; m_DeltaCl = 0.1; m_ReMin = 10000.0; m_ReMax = 100000.0; m_DeltaRe = 10000.0; m_pXFoil = NULL; m_pXFile = NULL; } void XFoilAnalysisDlg::SetupLayout() { m_pctrlTextOutput = new QTextEdit; m_pctrlTextOutput->setReadOnly(true); m_pctrlTextOutput->setLineWrapMode(QTextEdit::NoWrap); m_pctrlTextOutput->setWordWrapMode(QTextOption::NoWrap); m_pGraphWidget = new GraphWidget; m_pGraphWidget->setMinimumHeight(350); m_pGraphWidget->setMinimumWidth(600); m_pGraphWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); m_pGraphWidget->m_pGraph = &m_RmsGraph; QHBoxLayout *buttonsLayout = new QHBoxLayout; { m_pctrlSkip = new QPushButton(tr("Skip")); m_pctrlCancel = new QPushButton(tr("Cancel")); connect(m_pctrlSkip, SIGNAL(clicked()), this, SLOT(OnSkipPoint())); connect(m_pctrlCancel, SIGNAL(clicked()), this, SLOT(OnCancelAnalysis())); buttonsLayout->addStretch(1); buttonsLayout->addWidget(m_pctrlSkip); buttonsLayout->addStretch(1); buttonsLayout->addWidget(m_pctrlCancel); buttonsLayout->addStretch(1); } QVBoxLayout *mainLayout = new QVBoxLayout; { mainLayout->addWidget(m_pctrlTextOutput); mainLayout->addWidget(m_pGraphWidget); mainLayout->addLayout(buttonsLayout); setLayout(mainLayout); } } void XFoilAnalysisDlg::reject() { XFoil::s_bCancel = true; m_bSkip = true; m_bExit = true; m_pXFile->close(); QDialog::reject(); } void XFoilAnalysisDlg::accept() { XFoil::s_bCancel = true; m_bSkip = true; m_bExit = true; m_pXFile->close(); QDialog::accept(); } void XFoilAnalysisDlg::AddOpPoint() { QXDirect *pXDirect = (QXDirect*)s_pXDirect; pXDirect->AddOpPoint(NULL, pXDirect->m_bStoreOpp); if(pXDirect->m_bPolarView) { pXDirect->CreatePolarCurves(); pXDirect->UpdateView(); } m_RmsGraph.ResetYLimits(); } bool XFoilAnalysisDlg::AlphaLoop() { QString str; double alfa; int ia, total; if(m_AlphaMax< m_AlphaMin) m_DeltaAlpha = -qAbs(m_DeltaAlpha); if(m_ClMax< m_ClMin) m_DeltaCl = -qAbs(m_DeltaCl); if ( m_bAlpha && qAbs(m_DeltaAlpha)<1.e-3) total = 0; else if (!m_bAlpha && qAbs(m_DeltaCl)<1.e-4) total = 0; else { if(m_bAlpha) total=int((m_AlphaMax-m_AlphaMin)*1.0001/m_DeltaAlpha);//*1.0001 to make sure upper limit is included else total=int((m_ClMax-m_ClMin)*1.0001/m_DeltaCl);//*1.0001 to make sure upper limit is included } total = abs(total); if(!m_bSequence) total = 0; QString strange; for (ia=0; ia<=total; ia++) { if(!m_bExit) { if(m_bAlpha) { alfa = m_AlphaMin+ia*m_DeltaAlpha; m_pXFoil->alfa = alfa*PI/180.0; m_pXFoil->lalfa = true; m_pXFoil->qinf = 1.0; str = QString("\n\n"+tr("Alpha = %1")+"\n").arg(alfa,5,'f',2); WriteString(str); strange = QString(tr("Alfa = %1 ........ ")).arg(m_pXFoil->alfa*180.0/PI,7,'f',2); UpdateOutput(strange); // here we go ! if (!m_pXFoil->specal()) { str = tr("Invalid Analysis Settings\nCpCalc: local speed too large\n Compressibility corrections invalid "); WriteString(str); m_bExit = true; return false; } } else { m_pXFoil->lalfa = false; m_pXFoil->alfa = 0.0; m_pXFoil->qinf = 1.0; m_pXFoil->clspec = m_ClMin+ia*m_DeltaCl; str = QString("\n\n"+tr("Cl = %1")+"\n").arg(m_pXFoil->clspec, 10,'f',3); WriteString(str); strange = QString(tr("Cl = %1 ........ ")).arg(m_pXFoil->clspec,7,'f',2); UpdateOutput(strange); if(!m_pXFoil->speccl()) { str = tr("Invalid Analysis Settings\nCpCalc: local speed too large\n Compressibility corrections invalid "); WriteString(str); m_bExit = true; return false; } } if ((double)abs(m_pXFoil->alfa-m_pXFoil->awake) > 0.00001) m_pXFoil->lwake = false; if ((double)abs(m_pXFoil->alfa-m_pXFoil->avisc) > 0.00001) m_pXFoil->lvconv = false; if ((double)abs(m_pXFoil->minf-m_pXFoil->mvisc) > 0.00001) m_pXFoil->lvconv = false; m_pXFoil->lwake = false; m_pXFoil->lvconv = false; m_bSkip = false; while(!Iterate()){} qApp->processEvents(); ResetCurves(); m_Iterations = 0; AddOpPoint();// only if converged ??? } else { break; } } return true; } void XFoilAnalysisDlg::InitDialog() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QString FileName = QDir::tempPath() + "/XFLR5.log"; m_pXFile = new QFile(FileName); if (!m_pXFile->open(QIODevice::WriteOnly | QIODevice::Text)) m_pXFile = NULL; m_pXFoil->pXFile = m_pXFile; SetFileHeader(); m_Iterations = 0; QString str; m_RmsGraph.AddCurve(); m_RmsGraph.AddCurve(); str = "rms"; m_RmsGraph.GetCurve(0)->SetTitle(str); str = "max"; m_RmsGraph.GetCurve(1)->SetTitle(str); m_RmsGraph.GetCurve(1)->SetStyle(0); m_RmsGraph.SetAutoX(true); m_RmsGraph.SetXMin(0.0); m_RmsGraph.SetXMax((double)m_IterLim); m_RmsGraph.SetX0(0.0); m_RmsGraph.SetXUnit((int)(m_IterLim/10.0)); m_RmsGraph.SetAutoY(true); m_RmsGraph.SetY0(0.0); m_RmsGraph.SetYMin(0.0); m_RmsGraph.SetYMax(1.0); m_RmsGraph.SetMargin(40); if(pMainFrame) m_RmsGraph.CopySettings(&pMainFrame->m_RefGraph, false); m_pctrlTextOutput->clear(); } bool XFoilAnalysisDlg::Iterate() { QString str, strange; Curve *pCurve0 = m_RmsGraph.GetCurve(0); Curve *pCurve1 = m_RmsGraph.GetCurve(1); str= tr(" Initializing viscous analysis ...\n"); WriteString(str); if(!m_pXFoil->viscal()) { m_pXFoil->lvconv = false;//point is unconverged str = tr("CpCalc: local speed too large\n Compressibility corrections invalid")+"\n"; WriteString(str); m_bExit = true; return true;// to exit loop } str= tr(" Solving BL system ...\n"); WriteString(str); while(m_Iterationslvconv && !m_bSkip) { qApp->processEvents(); str= QString(tr(" Iteration %1 ...\n")).arg(m_Iterations); WriteString(str); if(m_pXFoil->ViscousIter()) { if(pCurve0) pCurve0->AppendPoint((double)m_Iterations, m_pXFoil->rmsbl); if(pCurve1) pCurve1->AppendPoint((double)m_Iterations, m_pXFoil->rmxbl); m_Iterations++; } else { m_Iterations = m_IterLim; } UpdateView(); } if(m_bSkip) { m_pXFoil->lblini = false; m_pXFoil->lipan = false; return true; } if(!m_pXFoil->ViscalEnd()) { m_pXFoil->lvconv = false;//point is unconverged str = tr("CpCalc: local speed too large\n Compressibility corrections invalid")+"\n"; WriteString(str); m_bExit = true; m_pXFoil->lblini = false; m_pXFoil->lipan = false; return true;// to exit loop } if(m_Iterations>=m_IterLim && !m_pXFoil->lvconv) { strange = QString(tr("unconverged after %1 iterations\n")).arg(m_Iterations); UpdateOutput(strange); str = tr("--------- Unconverged -----------\n"); WriteString(str); UpdateView(); m_pXFoil->fcpmin();// Is it of any use ? if(m_bAutoInitBL) { m_pXFoil->lblini = false; m_pXFoil->lipan = false; } return true; } if(!m_pXFoil->lvconv) { m_pXFoil->fcpmin();// Is it of any use ? return false; } else { //converged at last strange = QString(tr("converged after %1 iterations\n")).arg(m_Iterations); UpdateOutput(strange); m_pXFoil->fcpmin(); return true; } } void XFoilAnalysisDlg::OnCancelAnalysis() { m_bSkip = true; m_bExit = true; XFoil::s_bCancel= true; if(m_bFinished) reject(); } void XFoilAnalysisDlg::OnSkipPoint() { m_bSkip = true; } bool XFoilAnalysisDlg::ReLoop() { QString str; int ia; double Re; if(m_ReMax< m_ReMin) m_DeltaRe = -qAbs(m_DeltaRe); int total=int((m_ReMax*1.0001-m_ReMin)/m_DeltaRe);//*1.0001 to make sure upper limit is included total = abs(total); if(!m_bSequence) total = 0; QString strange; for (ia=0; ia<=total; ia++) { if(!m_bExit) { Re = m_ReMin+ia*m_DeltaRe; strange =QString("Re = %1 ........ ").arg(Re,0,'f',0); UpdateOutput(strange); m_pXFoil->reinf1 = Re; m_pXFoil->lalfa = true; m_pXFoil->qinf = 1.0; str = QString("\n\nRe = %1\n").arg(Re,8,'f',0); WriteString(str); // here we go ! if (!m_pXFoil->specal()) { QString str; str = tr("Invalid Analysis Settings\nCpCalc: local speed too large\n Compressibility corrections invalid "); WriteString(str); m_bExit = true; return false; } if (qAbs(m_pXFoil->alfa-m_pXFoil->awake) > 0.00001) m_pXFoil->lwake = false; if (qAbs(m_pXFoil->alfa-m_pXFoil->avisc) > 0.00001) m_pXFoil->lvconv = false; if (qAbs(m_pXFoil->minf-m_pXFoil->mvisc) > 0.00001) m_pXFoil->lvconv = false; m_pXFoil->lwake = false; m_pXFoil->lvconv = false; m_bSkip = false; while(!Iterate()){} qApp->processEvents(); ResetCurves(); m_Iterations = 0; AddOpPoint();// only if converged ??? } else { break; } } return true; } void XFoilAnalysisDlg::ResetCurves() { Curve*pCurve; pCurve = m_RmsGraph.GetCurve(0); if(pCurve) pCurve->clear(); pCurve = m_RmsGraph.GetCurve(1); if(pCurve) pCurve->clear(); } void XFoilAnalysisDlg::SetAlpha(double AlphaMin, double AlphaMax, double DeltaAlpha) { m_AlphaMin = AlphaMin; m_AlphaMax = AlphaMax; m_DeltaAlpha = DeltaAlpha; } void XFoilAnalysisDlg::SetCl(double ClMin, double ClMax, double DeltaCl) { m_ClMin = ClMin; m_ClMax = ClMax; m_DeltaCl = DeltaCl; } void XFoilAnalysisDlg::SetRe(double ReMin, double ReMax, double DeltaRe) { m_ReMin = ReMin; m_ReMax = ReMax; m_DeltaRe = DeltaRe; } void XFoilAnalysisDlg::SetFileHeader() { QXDirect *pXDirect = (QXDirect*)s_pXDirect; QTextStream out(m_pXFile); out << "\n"; out << MainFrame::versionName(); out << "\n"; out << m_FoilName; out << "\n"; if(pXDirect && pXDirect->m_pCurPolar) { // out << pXDirect->m_pCurPolar->m_PlrName; // out << "\n"; } QDateTime dt = QDateTime::currentDateTime(); QString str = dt.toString("dd.MM.yyyy hh:mm:ss"); out << str; out << "\n___________________________________\n\n"; // m_pXFile->close(); } void XFoilAnalysisDlg::StartAnalysis() { m_pctrlCancel->setText(tr("Cancel")); m_pctrlSkip->setEnabled(true); m_bSkip = false; m_bExit = false; m_bFinished = false; XFoil::s_bCancel = false; //all set to launch the analysis if (!m_bType4) { AlphaLoop() ; } else { ReLoop(); } m_bFinished = true; m_pctrlCancel->setText(tr("Close")); m_pctrlSkip->setEnabled(false); } void XFoilAnalysisDlg::UpdateView() { m_pGraphWidget->update(); repaint(); } void XFoilAnalysisDlg::UpdateOutput(QString &strong) { m_pctrlTextOutput->insertPlainText(strong); m_pctrlTextOutput->ensureCursorVisible(); } void XFoilAnalysisDlg::WriteString(QString &strong) { if(!m_pXFile) return; if(!m_pXFile->isOpen()) return; QTextStream ds(m_pXFile); ds << strong; } void XFoilAnalysisDlg::showEvent(QShowEvent *event) { move(s_Position); } void XFoilAnalysisDlg::hideEvent(QHideEvent *event) { s_Position = pos(); } xflr5-6.09-06/src/xdirect/FoilCoordDlg.cpp000644 001750 000144 00000022447 12247174405 021551 0ustar00techwinderusers000000 000000 /**************************************************************************** FoilCoordDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include "FoilCoordDlg.h" #include "XDirect.h" #include "../design/AFoil.h" FoilCoordDlg::FoilCoordDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Foil Coordinates")); m_pAFoil = NULL; m_pXDirect = NULL; m_pBufferFoil = NULL; m_pMemFoil = NULL; SetupLayout(); m_bApplied = true; m_bModified = false; } void FoilCoordDlg::FillList() { m_pCoordModel->setRowCount(m_pBufferFoil->n); m_pCoordModel->setColumnCount(2); for (int i=0; in; i++) { QModelIndex Xindex = m_pCoordModel->index(i, 0, QModelIndex()); m_pCoordModel->setData(Xindex, m_pBufferFoil->x[i]); QModelIndex Yindex =m_pCoordModel->index(i, 1, QModelIndex()); m_pCoordModel->setData(Yindex, m_pBufferFoil->y[i]); } } void FoilCoordDlg::InitDialog() { if(!m_pMemFoil || !m_pBufferFoil) return; int w = m_pctrlCoordView->width(); m_pctrlCoordView->setColumnWidth(0,(int)(w/2)); m_pctrlCoordView->setColumnWidth(1,(int)(w/2)); QHeaderView *HorizontalHeader = m_pctrlCoordView->horizontalHeader(); HorizontalHeader->setStretchLastSection(true); m_pCoordModel = new QStandardItemModel; m_pCoordModel->setRowCount(10);//temporary m_pCoordModel->setColumnCount(2); m_pCoordModel->setHeaderData(0, Qt::Horizontal, QObject::tr("X")); m_pCoordModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Y")); m_pctrlCoordView->setModel(m_pCoordModel); m_pFloatDelegate = new FloatEditDelegate; m_pctrlCoordView->setItemDelegate(m_pFloatDelegate); int *precision = new int[2]; precision[0] = 5;//five digits for x and y coordinates precision[1] = 5; m_pFloatDelegate->SetPrecision(precision); //void QAbstractItemDelegate::closeEditor ( QWidget * editor, QAbstractItemDelegate::EndEditHint hint = NoHint ) connect(m_pFloatDelegate, SIGNAL(closeEditor(QWidget *)), this, SLOT(OnCellChanged(QWidget *))); QItemSelectionModel *selectionModel = new QItemSelectionModel(m_pCoordModel); m_pctrlCoordView->setSelectionModel(selectionModel); connect(selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnItemClicked(QModelIndex))); //void QAbstractItemView::activated ( const QModelIndex & index ) [signal] //void itemChanged ( QStandardItem * item ) connect(m_pctrlApply, SIGNAL(clicked()),this, SLOT(OnApply())); connect(m_pctrlDeletePoint, SIGNAL(clicked()),this, SLOT(OnDeletePoint())); connect(m_pctrlInsertPoint, SIGNAL(clicked()),this, SLOT(OnInsertPoint())); connect(m_pctrlRestore, SIGNAL(clicked()),this, SLOT(OnRestore())); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); FillList(); } void FoilCoordDlg::resizeEvent(QResizeEvent *event) { int w2 = (int)((double)m_pctrlCoordView->width()*.7/2); m_pctrlCoordView->setColumnWidth(0,w2); m_pctrlCoordView->setColumnWidth(1,w2); } void FoilCoordDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OKButton->setFocus(); } else { QDialog::accept(); } break; } default: event->ignore(); } } void FoilCoordDlg::OnApply() { if(m_bApplied) return; QXDirect *pXDirect = (QXDirect*)m_pXDirect; QAFoil *pAFoil = (QAFoil*)m_pAFoil; m_bApplied = true; m_bModified = true; if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } void FoilCoordDlg::OnDeletePoint() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; QAFoil *pAFoil = (QAFoil*)m_pAFoil; int i, sel; QModelIndex index = m_pctrlCoordView->currentIndex(); sel = index.row(); if(sel<0) return; for (i=sel;inb-1; i++) { m_pBufferFoil->xb[i] = m_pBufferFoil->xb[i+1]; m_pBufferFoil->yb[i] = m_pBufferFoil->yb[i+1]; } for (i=sel;in-1; i++) { m_pBufferFoil->x[i] = m_pBufferFoil->x[i+1]; m_pBufferFoil->y[i] = m_pBufferFoil->y[i+1]; } m_pBufferFoil->nb--; m_pBufferFoil->n--; FillList(); SetSelection(sel); m_bModified = true; if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } void FoilCoordDlg::OnInsertPoint() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; QAFoil *pAFoil = (QAFoil*)m_pAFoil; int i, sel; sel = m_pctrlCoordView->currentIndex().row(); if(sel<=0) return; for (i=m_pBufferFoil->nb; i>sel; i--) { m_pBufferFoil->xb[i] = m_pBufferFoil->xb[i-1]; m_pBufferFoil->yb[i] = m_pBufferFoil->yb[i-1]; } m_pBufferFoil->xb[sel] = (m_pBufferFoil->xb[sel-1] + m_pBufferFoil->xb[sel+1])/2.0; m_pBufferFoil->yb[sel] = (m_pBufferFoil->yb[sel-1] + m_pBufferFoil->yb[sel+1])/2.0 ; for (i=m_pBufferFoil->n; i>sel; i--) { m_pBufferFoil->x[i] = m_pBufferFoil->x[i-1]; m_pBufferFoil->y[i] = m_pBufferFoil->y[i-1]; } m_pBufferFoil->x[sel] = (m_pBufferFoil->x[sel-1] + m_pBufferFoil->x[sel+1])/2.; m_pBufferFoil->y[sel] = (m_pBufferFoil->y[sel-1] + m_pBufferFoil->y[sel+1])/2.; m_pBufferFoil->nb++; m_pBufferFoil->n++; FillList(); SetSelection(sel); m_bModified = true; if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } void FoilCoordDlg::OnCellChanged(QWidget *DoubleEdit) { double X,Y; int sel = m_pctrlCoordView->currentIndex().row(); QModelIndex Xindex = m_pCoordModel->index(sel, 0); X = Xindex.data().toDouble(); m_pBufferFoil->x[sel] = X; m_pBufferFoil->xb[sel] = X; QModelIndex Yindex = m_pCoordModel->index(sel, 1); Y = Yindex.data().toDouble(); m_pBufferFoil->y[sel] = Y; m_pBufferFoil->yb[sel] = Y; m_bApplied = false; OnApply(); } void FoilCoordDlg::OnItemClicked(QModelIndex index) { int sel = m_pctrlCoordView->currentIndex().row(); QXDirect *pXDirect = (QXDirect*)m_pXDirect; QAFoil *pAFoil = (QAFoil*)m_pAFoil; if(m_pBufferFoil) m_pBufferFoil->m_iHighLight = sel; if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } void FoilCoordDlg::OnRestore() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; QAFoil *pAFoil = (QAFoil*)m_pAFoil; int i; for (i=0;inb; i++) { m_pBufferFoil->xb[i] = m_pMemFoil->xb[i]; m_pBufferFoil->yb[i] = m_pMemFoil->yb[i]; } m_pBufferFoil->nb = m_pMemFoil->n; for (i=0;in; i++) { m_pBufferFoil->x[i] = m_pMemFoil->x[i]; m_pBufferFoil->y[i] = m_pMemFoil->y[i]; } m_pBufferFoil->n = m_pMemFoil->n; FillList(); m_bApplied = true; m_bModified = false; SetSelection(0); if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } void FoilCoordDlg::ReadSectionData(int sel, double &X, double &Y) { QModelIndex XIndex =m_pCoordModel->index(sel, 0, QModelIndex()); X = XIndex.data().toDouble(); QModelIndex YIndex =m_pCoordModel->index(sel, 0, QModelIndex()); Y = YIndex.data().toDouble(); } void FoilCoordDlg::SetSelection(int sel) { if(sel>=0) { m_pctrlCoordView->selectRow(sel); } } void FoilCoordDlg::SetupLayout() { QVBoxLayout *CommandButtons = new QVBoxLayout; m_pctrlInsertPoint = new QPushButton(tr("Insert Point")); m_pctrlDeletePoint = new QPushButton(tr("Delete Point")); m_pctrlRestore = new QPushButton(tr("Restore")); m_pctrlApply = new QPushButton(tr("Apply")); OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(m_pctrlInsertPoint); CommandButtons->addWidget(m_pctrlDeletePoint); CommandButtons->addWidget(m_pctrlRestore); CommandButtons->addWidget(m_pctrlApply); CommandButtons->addStretch(2); CommandButtons->addWidget(OKButton); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); m_pctrlCoordView = new QTableView(this); m_pctrlCoordView->setMinimumHeight(500); m_pctrlCoordView->setMinimumWidth(150); QHBoxLayout * MainLayout = new QHBoxLayout(this); MainLayout->addWidget(m_pctrlCoordView); MainLayout->addLayout(CommandButtons); setLayout(MainLayout); } void FoilCoordDlg::showEvent(QShowEvent *event) { //setWindowModality(Qt::NonModal); setModal(true); // Qt::WindowFlags flags = windowFlags(); // flags = Qt::Dialog | Qt::WindowStaysOnTopHint; // setWindowFlags(flags); } xflr5-6.09-06/src/xdirect/XDirectStyleDlg.h000644 001750 000144 00000003303 12247174405 021707 0ustar00techwinderusers000000 000000 /**************************************************************************** QXDirectStyleDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef XDIRECTSTYLEDLG_H #define XDIRECTSTYLEDLG_H #include #include "../misc/LineBtn.h" class XDirectStyleDlg : public QDialog { Q_OBJECT friend class QXDirect; public: XDirectStyleDlg(QWidget *pParent=NULL); void InitDialog(); private slots: void OnRestoreDefaults(); void OnNeutralStyle(); void OnBLStyle(); void OnPressureStyle(); private: void keyPressEvent(QKeyEvent *event); void SetupLayout(); void *m_pXDirect; LineBtn *m_pctrlBL, *m_pctrlPressure, *m_pctrlNeutral; QPushButton *OKButton; QColor m_crFoilColor, m_crBLColor, m_crPressureColor, m_crNeutralColor; //foil display parameters int m_iFoilStyle, m_iFoilWidth; int m_iBLStyle, m_iBLWidth; int m_iPressureStyle, m_iPressureWidth; int m_iNeutralStyle, m_iNeutralWidth; }; #endif // XDIRECTSTYLEDLG_H xflr5-6.09-06/src/xdirect/XFoilTask.cpp000644 001750 000144 00000014633 12247174405 021104 0ustar00techwinderusers000000 000000 /**************************************************************************** XFoilTask Class Copyright (C) 2011 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "BatchThreadDlg.h" #include "XFoilTask.h" #include #include #include #include bool XFoilTask::s_bAutoInitBL = false; bool XFoilTask::s_bCancel = true; void *XFoilTask::s_pBatchThreadDlg; /** * The public constructor */ XFoilTask::XFoilTask() { m_Id = -1; m_pFoil = NULL; m_pPolar = NULL; m_bIsFinished = true; setAutoDelete(false); } /** * Implements the run method of the QRunnable virtual base method * * Asssumes that XFoil has been initialized with foil and polar */ void XFoilTask::run() { QObject *pBatch = (QObject*)s_pBatchThreadDlg; if(s_bCancel || !m_pPolar || !m_pFoil) { m_bIsFinished = true; return; } if(m_pPolar->m_PolarType!=FIXEDAOAPOLAR) AlphaSequence(); else { m_bIsFinished = true; return; } QTimerEvent *event = new QTimerEvent(m_Id); QApplication::postEvent(pBatch, event); //will be truly finished whent this message has been received by the parent batch analysis } /** * Initializes the XFoil calculation * @param pFoil a pointer to the instance of the Foil object for which the calculation is run * @param pPolar a pointer to the instance of the Polar object for which the calculation is run * @return true if the initialization of the Foil in XFoil has been sucessful, false otherwise */ bool XFoilTask::Init(Foil *pFoil, Polar *pPolar) { m_bIsFinished = false; XFoilInstance.lvisc=true; m_pFoil = pFoil; m_pPolar = pPolar; if(!XFoilInstance.InitXFoilGeometry(m_pFoil)) return false; // if(!XFoilInstance.InitXFoilAnalysis(m_pPolar)) return false; return true; } /** * Performs a sequence of Xfoil calculations for a range of aoa. * @return true if the calculation was successful */ bool XFoilTask::AlphaSequence() { BatchThreadDlg *pBatch = (BatchThreadDlg*)s_pBatchThreadDlg; QString str; QString strong = ""; double alphadeg; int ia, series, total, MaxSeries; double SpMin, SpMax, SpInc; MaxSeries = 1; if(pBatch->m_bAlpha) { SpMin = pBatch->m_AlphaMin; SpMax = pBatch->m_AlphaMax; SpInc = qAbs(pBatch->m_AlphaInc); if (pBatch->m_bFromZero && SpMin*SpMax<0) { MaxSeries = 2; SpMin = 0.0; SpMax = SpMax; } } else { SpMin = pBatch->m_ClMin; SpMax = pBatch->m_ClMax; SpInc = qAbs(pBatch->m_ClInc); } if(SpMin > SpMax) SpInc = -qAbs(SpInc); for (series=0; seriesprocessEvents(); if(s_bCancel) break; total = (int)qAbs((SpMax*1.0001-SpMin)/SpInc);//*1.0001 to make sure upper limit is included XFoilInstance.InitXFoilAnalysis(m_pPolar); XFoilInstance.lvisc = true; if(pBatch->m_bInitBL) { XFoilInstance.lblini = false; XFoilInstance.lipan = false; } for (ia=0; ia<=total; ia++) { if(s_bCancel) break; if(pBatch->m_bAlpha) { alphadeg = SpMin+ia*SpInc; XFoilInstance.alfa = alphadeg * PI/180.0; XFoilInstance.lalfa = true; XFoilInstance.qinf = 1.0; // str = QString("Alpha = %1").arg(alphadeg,9,'f',3); // strong+=str; // UpdateOutput(str); // here we go ! if (!XFoilInstance.specal()) { str = QObject::tr("Invalid Analysis Settings\nCpCalc: local speed too large\n Compressibility corrections invalid "); // UpdateOutput(str); return false; } } else { XFoilInstance.lalfa = false; XFoilInstance.alfa = 0.0; XFoilInstance.qinf = 1.0; XFoilInstance.clspec = SpMin+ia*SpInc; str = QString(QObject::tr("Cl = %1")).arg(XFoilInstance.clspec,9,'f',3); strong+=str; // UpdateOutput(str); if(!XFoilInstance.speccl()) { // str = QObject::tr("Invalid Analysis Settings\nCpCalc: local speed too large\n Compressibility corrections invalid "); // UpdateOutput(str); return false; } } XFoilInstance.lwake = false; XFoilInstance.lvconv = false; m_Iterations = 0; while(!Iterate()){} if(XFoilInstance.lvconv) { str = QString(QObject::tr(" ...converged after %1 iterations\n")).arg(m_Iterations); strong+= str; // UpdateOutput(str); m_pPolar->AddData(&XFoilInstance); } else { str = QString(QObject::tr(" ...unconverged after %1 iterations\n")).arg(m_Iterations); strong+= str; // UpdateOutput(str); } }// end Alpha or Cl loop SpMin = 0.0; SpMax = pBatch->m_AlphaMin; SpInc = -SpInc; } // strong+="\n"; return true; } /** * Manages the viscous iterations of the XFoil calculation. * @return true if the analysis has been successful. */ bool XFoilTask::Iterate() { BatchThreadDlg *pBatch = (BatchThreadDlg*)s_pBatchThreadDlg; QString str; if(!XFoilInstance.viscal()) { XFoilInstance.lvconv = false; // str =QObject::tr("CpCalc: local speed too large\n Compressibility corrections invalid"); return false; } while(m_Iterationsm_IterLim && !XFoilInstance.lvconv && !s_bCancel) { if(XFoilInstance.ViscousIter()) m_Iterations++; else m_Iterations = pBatch->m_IterLim; } if(s_bCancel) return true;// to exit loop if(!XFoilInstance.ViscalEnd()) { XFoilInstance.lvconv = false;//point is unconverged XFoilInstance.lblini = false; XFoilInstance.lipan = false; return true;// to exit loop } if(m_Iterations>=pBatch->m_IterLim && !XFoilInstance.lvconv) { if(s_bAutoInitBL) { XFoilInstance.lblini = false; XFoilInstance.lipan = false; } XFoilInstance.fcpmin();// Is it of any use ? return true; } if(!XFoilInstance.lvconv) { XFoilInstance.fcpmin();// Is it of any use ? return false; } else { //converged at last XFoilInstance.fcpmin();// Is it of any use ? return true; } return false; } xflr5-6.09-06/src/xdirect/LEDlg.cpp000644 001750 000144 00000013105 12247174405 020160 0ustar00techwinderusers000000 000000 /**************************************************************************** LEDlg Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "LEDlg.h" #include "XFoil.h" #include "XDirect.h" #include "../design/AFoil.h" #include #include void *LEDlg::s_pXFoil; LEDlg::LEDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Leading Edge")); m_LErfac = 1.0; m_Blend = 0.1; m_pAFoil = NULL; m_pXDirect = NULL; m_bModified = false; m_bApplied = true; SetupLayout(); connect(m_pctrlLE, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlBlend, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(ApplyButton, SIGNAL(clicked()),this, SLOT(OnApply())); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void LEDlg::SetupLayout() { QHBoxLayout *LEValue = new QHBoxLayout; QLabel *lab1 = new QLabel(tr("Approximate new/old ratio for L.E. radius")); lab1->setMinimumWidth(200); lab1->setAlignment(Qt::AlignRight); QLabel *lab2 = new QLabel(tr("ratio")); lab2->setMinimumWidth(80); m_pctrlLE = new DoubleEdit; LEValue->addWidget(lab1); LEValue->addWidget(m_pctrlLE); LEValue->addWidget(lab2); QHBoxLayout *BlendValue = new QHBoxLayout; QLabel *lab3 = new QLabel(tr("Blending Distance from L.E.")); lab3->setMinimumWidth(200); lab3->setAlignment(Qt::AlignRight); QLabel *lab4 = new QLabel(tr("% chord")); lab4->setMinimumWidth(80); m_pctrlBlend = new DoubleEdit; BlendValue->addWidget(lab3); BlendValue->addWidget(m_pctrlBlend); BlendValue->addWidget(lab4); QHBoxLayout *CommandButtons = new QHBoxLayout; OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); ApplyButton = new QPushButton(tr("Apply")); CommandButtons->addStretch(1); CommandButtons->addWidget(ApplyButton); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addStretch(1); MainLayout->addLayout(LEValue); MainLayout->addStretch(1); MainLayout->addLayout(BlendValue); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); setLayout(MainLayout); } void LEDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Escape: { done(0); return; } case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OnApply(); OKButton->setFocus(); m_bApplied = true; } else { QDialog::accept(); } break; } default: event->ignore(); break; } } void LEDlg::InitDialog() { m_pctrlLE->SetMin( 0.0); m_pctrlLE->SetMax(100.0); m_pctrlBlend->SetMin( 0.001); m_pctrlBlend->SetMax(100.0); m_pctrlLE->SetValue(m_LErfac); m_pctrlBlend->SetValue(m_Blend*100.0); } void LEDlg::OnChanged() { m_bApplied = false; } void LEDlg::OnApply() { if(m_bApplied) return; //reset everything and retry QAFoil *pAFoil = (QAFoil*)m_pAFoil; QXDirect *pXDirect = (QXDirect*)m_pXDirect; XFoil *pXFoil = (XFoil*)s_pXFoil; int i, j; for (i=0; i< m_pMemFoil->nb; i++) { pXFoil->xb[i+1] = m_pMemFoil->xb[i] ; pXFoil->yb[i+1] = m_pMemFoil->yb[i]; } pXFoil->nb = m_pMemFoil->nb; pXFoil->lflap = false; pXFoil->lbflap = false; if(pXFoil->Preprocess()) { pXFoil->CheckAngles(); /* for (int k=0; kn;k++) { m_pMemFoil->nx[k] = pXFoil->nx[k+1]; m_pMemFoil->ny[k] = pXFoil->ny[k+1]; } m_pMemFoil->n = pXFoil->n;*/ } else { QMessageBox::information(window(), tr("Warning"), tr("Unrecognized foil format")); return; } m_LErfac = m_pctrlLE->Value(); m_Blend = m_pctrlBlend->Value()/100.0; pXFoil->lerad(m_LErfac,m_Blend); if(pXFoil->n>IQX) { QMessageBox::information(window(), tr("Warning"), tr("Panel number cannot exceed 300")); //reset everything and retry for (i=0; i< m_pMemFoil->nb; i++) { pXFoil->x[i+1] = m_pMemFoil->xb[i] ; pXFoil->y[i+1] = m_pMemFoil->yb[i]; } pXFoil->n = m_pMemFoil->nb; } else { for (j=0; j< pXFoil->n; j++) { m_pBufferFoil->xb[j] = pXFoil->xb[j+1]; m_pBufferFoil->yb[j] = pXFoil->yb[j+1]; } m_pBufferFoil->nb = pXFoil->nb; // pXFoil->SetFoilFlap(m_pBufferFoil); m_pBufferFoil->InitFoil(); m_pBufferFoil->SetFlap(); } m_bApplied = true; m_bModified = true; if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } void LEDlg::OnOK() { if(!m_bApplied) OnApply(); if(!m_bModified) done(0); else done(1); } xflr5-6.09-06/src/xdirect/EditPlrDlg.cpp000644 001750 000144 00000017212 12247174405 021226 0ustar00techwinderusers000000 000000 /**************************************************************************** EditPlrDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "EditPlrDlg.h" #include #include #include #include #include "../xdirect/XDirect.h" QPoint EditPlrDlg::s_WindowPos; QSize EditPlrDlg::s_WindowSize; bool EditPlrDlg::s_bWindowMaximized; EditPlrDlg::EditPlrDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Polar Points Edition")); m_pXDirect = NULL; m_pPolar = NULL; m_pctrlPointTable = NULL; m_pPointModel = NULL; m_pFloatDelegate = NULL; SetupLayout(); } void EditPlrDlg::InitDialog() { m_pPointModel = new QStandardItemModel; m_pPointModel->setRowCount(10);//temporary m_pPointModel->setColumnCount(14); m_pPointModel->setHeaderData(0, Qt::Horizontal, "Alpha"); m_pPointModel->setHeaderData(1, Qt::Horizontal, "Cl"); m_pPointModel->setHeaderData(2, Qt::Horizontal, "Cd"); m_pPointModel->setHeaderData(3, Qt::Horizontal, "Cm"); m_pPointModel->setHeaderData(4, Qt::Horizontal, "XTr_top"); m_pPointModel->setHeaderData(5, Qt::Horizontal, "XTr_bot"); m_pPointModel->setHeaderData(6, Qt::Horizontal, "Cl/Cd"); m_pPointModel->setHeaderData(7, Qt::Horizontal, "Cl^3/2/Cd"); m_pPointModel->setHeaderData(8, Qt::Horizontal, "sqrt(Cl)"); m_pPointModel->setHeaderData(9, Qt::Horizontal, "XCp"); m_pPointModel->setHeaderData(10, Qt::Horizontal, "HMom"); m_pPointModel->setHeaderData(11, Qt::Horizontal, "Cdp"); m_pPointModel->setHeaderData(12, Qt::Horizontal, "Cpmn"); m_pPointModel->setHeaderData(13, Qt::Horizontal, "Re"); m_pctrlPointTable->setModel(m_pPointModel); QHeaderView *HorizontalHeader = m_pctrlPointTable->horizontalHeader(); HorizontalHeader->setStretchLastSection(true); m_pFloatDelegate = new FloatEditDelegate; m_pctrlPointTable->setItemDelegate(m_pFloatDelegate); int *precision = new int[14]; precision[0] = 3; precision[1] = 3; precision[2] = 3; precision[3] = 3; precision[4] = 3; precision[5] = 3; precision[6] = 3; precision[7] = 3; precision[8] = 3; precision[9] = 3; precision[10] = 3; precision[11] = 3; precision[12] = 3; precision[13] = 0; m_pFloatDelegate->SetPrecision(precision); FillTable(); } void EditPlrDlg::FillTable() { m_pPointModel->setColumnCount(14); m_pPointModel->setRowCount(m_pPolar->m_Alpha.size()); QModelIndex index; for (int i=0; im_Alpha.size(); i++) { index = m_pPointModel->index(i, 0, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_Alpha.at(i)); index = m_pPointModel->index(i, 1, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_Cl.at(i)); index = m_pPointModel->index(i, 2, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_Cd.at(i)); index = m_pPointModel->index(i, 3, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_Cm.at(i)); index = m_pPointModel->index(i, 4, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_XTr1.at(i)); index = m_pPointModel->index(i, 5, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_XTr2.at(i)); index = m_pPointModel->index(i, 6, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_ClCd.at(i)); index = m_pPointModel->index(i, 7, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_Cl32Cd.at(i)); index = m_pPointModel->index(i, 8, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_RtCl.at(i)); index = m_pPointModel->index(i, 9, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_XCp.at(i)); index = m_pPointModel->index(i, 10, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_HMom.at(i)); index = m_pPointModel->index(i, 11, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_Cdp.at(i)); index = m_pPointModel->index(i, 12, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_Cpmn.at(i)); index = m_pPointModel->index(i, 13, QModelIndex()); m_pPointModel->setData(index, m_pPolar->m_Re.at(i)); } m_pctrlPointTable->resizeRowsToContents(); // m_pctrlPointTable->resizeColumnsToContents(); } void EditPlrDlg::closeEvent(QCloseEvent*event) { s_WindowPos = pos(); s_WindowSize = size(); s_bWindowMaximized = isMaximized(); } void EditPlrDlg::resizeEvent(QResizeEvent*event) { if(!m_pPointModel || !m_pctrlPointTable) return; int n = m_pPointModel->columnCount(); int w = m_pctrlPointTable->width(); int w14 = (int)((double)(w-25)/(double)n); for(int i=0; icolumnCount(); i++) m_pctrlPointTable->setColumnWidth(i,w14); } void EditPlrDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OKButton->setFocus(); } else { QDialog::accept(); } break; } case Qt::Key_Escape: { QDialog::reject(); return; } default: event->ignore(); } } void EditPlrDlg::OnDeletePoint() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; QModelIndex index = m_pctrlPointTable->currentIndex(); if(pXDirect) { m_pPolar->Remove(index.row()); FillTable(); pXDirect->CreatePolarCurves(); pXDirect->UpdateView(); } if(index.row()>=m_pPointModel->rowCount()-1) { index = m_pPointModel->index(m_pPointModel->rowCount()-1,0); } if(m_pPointModel->rowCount()) m_pctrlPointTable->setCurrentIndex(index); } void EditPlrDlg::OnDeleteAllPoints() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; if(pXDirect) { m_pPolar->ResetPolar(); FillTable(); pXDirect->CreatePolarCurves(); pXDirect->UpdateView(); } } void EditPlrDlg::SetupLayout() { QVBoxLayout *CommandButtonsLayout = new QVBoxLayout; { m_pctrlDeleteAllPoints = new QPushButton(tr("Delete All Points")); m_pctrlDeletePoint = new QPushButton(tr("Delete Point")); OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(m_pctrlDeleteAllPoints); CommandButtonsLayout->addWidget(m_pctrlDeletePoint); CommandButtonsLayout->addStretch(2); CommandButtonsLayout->addWidget(OKButton); CommandButtonsLayout->addWidget(CancelButton); CommandButtonsLayout->addStretch(1); } m_pctrlPointTable = new QTableView(this); m_pctrlPointTable->setMinimumHeight(500); m_pctrlPointTable->setMinimumWidth(500); m_pctrlPointTable->setSelectionBehavior(QAbstractItemView::SelectRows); m_pctrlPointTable->setEditTriggers(QAbstractItemView::NoEditTriggers); QHBoxLayout * MainLayout = new QHBoxLayout(this); { MainLayout->addWidget(m_pctrlPointTable); MainLayout->addLayout(CommandButtonsLayout); } setLayout(MainLayout); connect(m_pctrlDeletePoint, SIGNAL(clicked()),this, SLOT(OnDeletePoint())); connect(m_pctrlDeleteAllPoints, SIGNAL(clicked()),this, SLOT(OnDeleteAllPoints())); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } xflr5-6.09-06/src/xdirect/FlapDlg.cpp000644 001750 000144 00000016746 12247174405 020560 0ustar00techwinderusers000000 000000 /**************************************************************************** FlapDlg class Copyright (C) 2004-2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include "FlapDlg.h" #include "XDirect.h" #include "../design/AFoil.h" FlapDlg::FlapDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Flap Dlg")); m_pAFoil = NULL; m_pXDirect = NULL; m_pMemFoil = NULL; m_pBufferFoil = NULL; m_bTEFlap = false; m_TEFlapAngle = 0.0; m_TEXHinge = 80.0;//% m_TEYHinge = 50.0;//% m_bLEFlap = false; m_LEFlapAngle = 0.0; m_LEXHinge = 20.0;//% m_LEYHinge = 50.0;//% m_pXFoil = NULL; m_bModified = false; m_bApplied = true; SetupLayout(); connect(ApplyButton, SIGNAL(clicked()),this, SLOT(OnApply())); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(m_pctrlLEFlapCheck, SIGNAL(stateChanged(int)), this, SLOT(OnLEFlapCheck(int))); connect(m_pctrlTEFlapCheck, SIGNAL(stateChanged(int)), this, SLOT(OnTEFlapCheck(int))); connect(m_pctrlLEXHinge, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlLEYHinge, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlTEXHinge, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlTEYHinge, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlLEFlapAngle, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlTEFlapAngle, SIGNAL(editingFinished()), this, SLOT(OnChanged())); } void FlapDlg::SetupLayout() { QGridLayout *pFlapDataLayout = new QGridLayout; { m_pctrlLEFlapCheck = new QCheckBox(tr("L.E. Flap")); m_pctrlTEFlapCheck = new QCheckBox(tr("T.E. Flap")); m_pctrlLEXHinge = new DoubleEdit; m_pctrlLEYHinge = new DoubleEdit; m_pctrlTEXHinge = new DoubleEdit; m_pctrlTEYHinge = new DoubleEdit; m_pctrlTEFlapAngle = new DoubleEdit; m_pctrlLEFlapAngle = new DoubleEdit; QLabel *lab1 = new QLabel(tr("Flap Angle")); QLabel *lab2 = new QLabel(QString::fromUtf8("° (")+tr("+ is down") +")"); QLabel *lab3 = new QLabel(tr("Hinge X Position")); QLabel *lab4 = new QLabel(tr("% Chord")); QLabel *lab5 = new QLabel(tr("Hinge Y Position")); QLabel *lab6 = new QLabel(tr("% Thickness")); pFlapDataLayout->addWidget(m_pctrlLEFlapCheck, 1, 2); pFlapDataLayout->addWidget(m_pctrlTEFlapCheck, 1, 3); pFlapDataLayout->addWidget(lab1, 2, 1); pFlapDataLayout->addWidget(m_pctrlLEFlapAngle, 2, 2); pFlapDataLayout->addWidget(m_pctrlTEFlapAngle, 2, 3); pFlapDataLayout->addWidget(lab2, 2, 4); pFlapDataLayout->addWidget(lab3, 3, 1); pFlapDataLayout->addWidget(m_pctrlLEXHinge, 3, 2); pFlapDataLayout->addWidget(m_pctrlTEXHinge, 3, 3); pFlapDataLayout->addWidget(lab4, 3, 4); pFlapDataLayout->addWidget(lab5, 4, 1); pFlapDataLayout->addWidget(m_pctrlLEYHinge, 4, 2); pFlapDataLayout->addWidget(m_pctrlTEYHinge, 4, 3); pFlapDataLayout->addWidget(lab6, 4, 4); } QHBoxLayout *pCommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); ApplyButton = new QPushButton(tr("Apply")); } pCommandButtons->addStretch(1); pCommandButtons->addWidget(ApplyButton); pCommandButtons->addStretch(1); pCommandButtons->addWidget(OKButton); pCommandButtons->addStretch(1); pCommandButtons->addWidget(CancelButton); pCommandButtons->addStretch(1); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addLayout(pFlapDataLayout); MainLayout->addLayout(pCommandButtons); setLayout(MainLayout); } void FlapDlg::InitDialog() { m_pctrlTEFlapCheck->setChecked(m_pMemFoil->m_bTEFlap); EnableTEFlap(m_pMemFoil->m_bTEFlap); m_pctrlTEFlapAngle->SetValue(m_pMemFoil->m_TEFlapAngle); m_pctrlTEXHinge->SetValue(m_pMemFoil->m_TEXHinge); m_pctrlTEYHinge->SetValue(m_pMemFoil->m_TEYHinge); m_pctrlLEFlapCheck->setChecked(m_pMemFoil->m_bLEFlap); EnableLEFlap(m_pMemFoil->m_bLEFlap); m_pctrlLEFlapAngle->SetValue(m_pMemFoil->m_LEFlapAngle); m_pctrlLEXHinge->SetValue(m_pMemFoil->m_LEXHinge); m_pctrlLEYHinge->SetValue(m_pMemFoil->m_LEYHinge); } void FlapDlg::ReadParams() { m_bLEFlap = m_pctrlLEFlapCheck->isChecked(); m_LEFlapAngle = m_pctrlLEFlapAngle->Value(); m_LEXHinge = m_pctrlLEXHinge->Value(); m_LEYHinge = m_pctrlLEYHinge->Value(); m_bTEFlap = m_pctrlTEFlapCheck->isChecked(); m_TEFlapAngle = m_pctrlTEFlapAngle->Value(); m_TEXHinge = m_pctrlTEXHinge->Value(); m_TEYHinge = m_pctrlTEYHinge->Value(); if(m_LEXHinge>=m_TEXHinge && m_bLEFlap && m_bTEFlap) { QMessageBox::information(window(), tr("Warning"), tr("The trailing edge hinge must be downstream of the leading edge hinge")); m_pctrlLEXHinge->setFocus(); m_pctrlLEXHinge->selectAll(); } } void FlapDlg::OnApply() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; QAFoil *pAFoil = (QAFoil*)m_pAFoil; if(m_bApplied) return; //reset everything and retry ReadParams(); m_pBufferFoil->SetTEFlapData(m_bTEFlap, m_TEXHinge, m_TEYHinge, m_TEFlapAngle); m_pBufferFoil->SetLEFlapData(m_bLEFlap, m_LEXHinge, m_LEYHinge, m_LEFlapAngle); m_pBufferFoil->SetFlap(); m_bApplied = true; m_bModified = true; if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } void FlapDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Escape: { done(0); return; } case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OnApply(); OKButton->setFocus(); m_bApplied = true; } else { QDialog::accept(); } break; } default: event->ignore(); break; } } void FlapDlg::EnableLEFlap(bool bEnable) { m_pctrlLEFlapAngle->setEnabled(bEnable); m_pctrlLEXHinge->setEnabled(bEnable); m_pctrlLEYHinge->setEnabled(bEnable); } void FlapDlg::EnableTEFlap(bool bEnable) { m_pctrlTEFlapAngle->setEnabled(bEnable); m_pctrlTEXHinge->setEnabled(bEnable); m_pctrlTEYHinge->setEnabled(bEnable); } void FlapDlg::OnTEFlapCheck(int state) { if(m_pctrlTEFlapCheck->isChecked()) { EnableTEFlap(true); m_pctrlTEFlapAngle->setFocus(); } else EnableTEFlap(false); m_bApplied = false; OnApply(); } void FlapDlg::OnLEFlapCheck(int state) { if(m_pctrlLEFlapCheck->isChecked()) { EnableLEFlap(true); m_pctrlLEFlapAngle->setFocus(); } else EnableLEFlap(false); m_bApplied = false; OnApply(); } void FlapDlg::OnChanged() { m_bApplied = false; } void FlapDlg::OnOK() { if(!m_bApplied) { OnApply(); accept(); } else done(1); } xflr5-6.09-06/src/xdirect/ManageFoilsDlg.h000644 001750 000144 00000004006 12247174405 021512 0ustar00techwinderusers000000 000000 /**************************************************************************** ManageFoilsDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef MANAGEFOILSDLG_H #define MANAGEFOILSDLG_H #include #include #include #include #include "../design/FoilTableDelegate.h" #include "../objects/Foil.h" class ManageFoilsDlg : public QDialog { Q_OBJECT friend class QXDirect; friend class MainFrame; public: ManageFoilsDlg(QWidget *pParent=NULL); void InitDialog(QString FoilName); private slots: void OnDelete(); void OnRename(); void OnExport(); void OnFoilClicked(const QModelIndex& index); void OnDoubleClickTable(const QModelIndex &index); private: void resizeEvent(QResizeEvent *event); void keyPressEvent(QKeyEvent *event); void FillFoilTable(); void FillTableRow(int row); void SetupLayout(); private: QPushButton *CloseButton; QPushButton *m_pctrlRename, *m_pctrlDelete, *m_pctrlSelect, *m_pctrlExport; QTableView *m_pctrlFoilTable; QStandardItemModel *m_pFoilModel; FoilTableDelegate *m_pFoilDelegate; int m_iSelection; Foil *m_pFoil; void *m_pMainFrame, *m_pXDirect; }; #endif // MANAGEFOILSDLG_H xflr5-6.09-06/src/xdirect/FoilPolarDlg.h000644 001750 000144 00000005141 12247174410 021211 0ustar00techwinderusers000000 000000 /**************************************************************************** FoilPolarDlg Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef FOILPOLARDLG_H #define FOILPOLARDLG_H #include #include #include #include #include "../misc/DoubleEdit.h" #include "../objects/Polar.h" class FoilPolarDlg : public QDialog { friend class QOperWidget; Q_OBJECT public: FoilPolarDlg(QWidget *pParent=NULL); void ReadParams(); void keyPressEvent(QKeyEvent *event); void InitDialog(); void SetPlrName(); void SetupLayout(); void SetDensity(); QRadioButton *m_pctrlAuto1; QRadioButton *m_pctrlAuto2; QLabel *m_pctrlReLabel; QLabel *m_pctrlMachLabel; QLineEdit *m_pctrlAnalysisName; QRadioButton *m_rbtype1; QRadioButton *m_rbtype2; QRadioButton *m_rbtype3; QRadioButton *m_rbtype4; DoubleEdit *m_pctrlReynolds; DoubleEdit *m_pctrlMach; DoubleEdit *m_pctrlChord, *m_pctrlMass, *m_pctrlSpan; QLabel *m_pctrlLengthUnit1, *m_pctrlLengthUnit2, *m_pctrlMassUnit; QRadioButton *m_pctrlUnit1, *m_pctrlUnit2; QLabel *m_pctrlRho, *m_pctrlNu, *m_pctrlViscosityUnit, *m_pctrlDensityUnit; DoubleEdit *m_pctrlDensity, *m_pctrlViscosity; QPushButton *OKButton; QPushButton *CancelButton; DoubleEdit *m_pctrlNCrit; DoubleEdit *m_pctrlTopTrans; DoubleEdit *m_pctrlBotTrans; bool m_bAutoName; enumPolarType m_PolarType; int m_MaTypDef, m_ReTypDef; int m_UnitType; double m_Reynolds; double m_Viscosity, m_Density; double m_Chord, m_Span, m_Mass; double m_Mach; double m_ReDef; double m_ASpec; double m_XTopTr, m_XBotTr; double m_NCrit; QString m_FoilName; QString m_PlrName; public slots: void OnAutoName(); void OnOK(); void OnPolarType(); void OnNameChanged(); void EditingFinished(); void OnUnit(); void OnEditingFinished(); }; #endif // FOILPOLARDLG_H xflr5-6.09-06/src/xdirect/XFoil.cpp000644 001750 000144 00001227134 12247174410 020260 0ustar00techwinderusers000000 000000 /**************************************************************************** XFoil Class Copyright (C) 2000 Mark Drela Copyright (C) 2003 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include "XDirect.h" #include "XFoil.h" #include #include #include bool XFoil::s_bCancel = false; XFoil::XFoil() { //------ primary dimensioning limit parameters //------ derived dimensioning limit parameters // nax=800;//number of points in stored polar // npx=8;//number of polars and reference polars // nfx=128;// number of points in one reference polar // ncom = 73; // imx number of complex mapping coefficients cn m_bTrace = false; m_bFullReport = false; sccon = 5.6 ; gacon = 6.70; gbcon = 0.75; gbc0 = 0.60; gbc1 = 0.40; gccon = 18.0; dlcon = 0.9; ctcon = 0.01485111754659538130244; //(ctcon = 0.5/(gacon**2 * gbcon)) angtol = 40.0; // fortran seems to initializes variables to 0 mvisc = 0.0; //initialize transition parameters until user changes them acrit = 9.0; xstrip[1] = 1.0; xstrip[2] = 1.0; //intialize analysis parameter until user changes them //---- default paneling parameters npan = 140; cvpar = 1.0; cterat = 0.15; ctrrat = 0.2; //---- default paneling refinement zone x/c endpoints xsref1 = 1.0; xsref2 = 1.0; xpref1 = 1.0; xpref2 = 1.0; //---- initialize freestream mach number to zero matyp = 1; minf1 = 0.0; //---- drop tolerance for bl system solver vaccel = 0.01; //---- default viscous parameters retyp = 1; reinf1 = 0.0; Initialize(); } XFoil::~XFoil() { } bool XFoil::abcopy() { int i; if(nb<=1) { QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QXDirect::tr("Warning")); msgBox.setText(QXDirect::tr("abcopy: buffer airfoil not available")); msgBox.exec(); return false; } else if(nb>IQX-2) { QString str1, str2; str1 = QString("Maximum number of panel nodes : %1\n").arg(IQX-2); str2 = QString("Number of buffer airfoil points: %1\n").arg(nb); str2+="Current airfoil cannot be set\n"; str2+="Try executing PANE at top level instead"; str1+=str2; QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QXDirect::tr("Warning")); msgBox.setText(str1); msgBox.exec(); return false; } if(n!=nb) lblini = false; n = nb; for (i=1; i<= n; i++){ x[i] = xb[i]; y[i] = yb[i]; } lgsame = true; if(lbflap) { xof = xbf; yof = ybf; lflap = true; } //---- strip out doubled points i = 1; while (iqAbs(s2)) { apx1 = atan2(s1,c1); apx2 = apx1 + 0.5*PI; } else{ apx2 = atan2(s2,c2); apx1 = apx2 - 0.5*PI; } if(apx1<-0.5*PI) apx1 = apx1 + PI; if(apx1>+0.5*PI) apx1 = apx1 - PI; if(apx2<-0.5*PI) apx2 = apx2 + PI; if(apx2>+0.5*PI) apx2 = apx2 - PI; } } return true; } double XFoil::aint(double number){ if(number>=0) return (double)( int(number)); else return (double)(-int(-number)); } bool XFoil::apcalc() { double sx, sy; int i, ip; //---- set angles of airfoil panels for (i=1; i<= n-1; i++) { sx = x[i+1] - x[i]; sy = y[i+1] - y[i]; if(sx==0.0 && sy==0.0) apanel[i] = atan2(-ny[i], -nx[i]); else apanel[i] = atan2(sx, -sy ); } //---- te panel i = n; ip = 1; if(sharp) apanel[i] = PI; else { sx = x[ip] - x[i]; sy = y[ip] - y[i]; apanel[i] = atan2( -sx , sy ) + PI; } return true; } double XFoil::atanc(double y, double x, double thold) { //------------------------------------------------------------- // atan2 function with branch cut checking. // // increments position angle of point x,y from some previous // value thold due to a change in position, ensuring that the // position change does not cross the atan2 branch cut // (which is in the -x direction). for example: // // atanc( -1.0 , -1.0 , 0.75*PI ) returns 1.25*PI , whereas // atan2( -1.0 , -1.0 ) returns -.75*PI . // // typically, atanc is used to fill an array of angles: // // theta(1) = atan2( y(1) , x(1) ) // do i=2, n // theta[i] = atanc( y[i] , x[i] , theta(i-1) ) // end do // // this will prevent the angle array theta(i) from jumping by // +/- 2 pi when the path x(i),y(i) crosses the negative x axis. // // input: // x,y point position coordinates // thold position angle of nearby point // // output: // atanc position angle of x,y //-------------------------------------------------------------- double tpi, thnew, dthet, dtcorr ; tpi = 6.2831853071795864769; //---- set new position angle, ignoring branch cut in atan2 function for now thnew = atan2( y , x ); dthet = thnew - thold; //---- angle change cannot exceed +/- pi, so get rid of any multiples of 2 pi dtcorr = dthet - tpi*int( (dthet + sign(PI,dthet))/tpi ); //---- set correct new angle return thold + dtcorr; } bool XFoil::axset(double hk1, double t1, double rt1, double a1, double hk2, double t2, double rt2, double a2, double acrit, double &ax, double &ax_hk1, double &ax_t1, double &ax_rt1, double &ax_a1, double &ax_hk2, double &ax_t2, double &ax_rt2, double &ax_a2) { //---------------------------------------------------------- // returns average amplification ax over interval 1..2 //---------------------------------------------------------- // //========================== //---- 2nd-order double ax1, ax2, ax1_hk1, ax1_t1, ax1_rt1; double ax2_hk2, ax2_t2, ax2_rt2, axsq; double axa, axa_ax1, axa_ax2; double exn, exn_a1, exn_a2, dax, dax_a1, dax_a2, dax_t1, dax_t2; double f_arg;//ex arg dampl(hk1, t1, rt1, ax1, ax1_hk1, ax1_t1, ax1_rt1); dampl(hk2, t2, rt2, ax2, ax2_hk2, ax2_t2, ax2_rt2); //---- rms-average version (seems a little better on coarse grids) axsq = 0.5*(ax1*ax1 + ax2*ax2); if(axsq <= 0.0) { axa = 0.0; axa_ax1 = 0.0; axa_ax2 = 0.0; } else { axa = sqrt(axsq); axa_ax1 = 0.5*ax1/axa; axa_ax2 = 0.5*ax2/axa; } //----- small additional term to ensure dn/dx > 0 near n = ncrit f_arg = qMin(20.0*(acrit-0.5*(a1+a2)) , 20.0); if(f_arg<=0.0) { exn = 1.0; exn_a1 = 0.0; exn_a2 = 0.0; } else { exn = exp(-f_arg); exn_a1 = 20.0*0.5*exn; exn_a2 = 20.0*0.5*exn; } dax = exn * 0.002/(t1+t2); dax_a1 = exn_a1 * 0.002/(t1+t2); dax_a2 = exn_a2 * 0.002/(t1+t2); dax_t1 = -dax/(t1+t2); dax_t2 = -dax/(t1+t2); //========================== ax = axa + dax; ax_hk1 = axa_ax1*ax1_hk1; ax_t1 = axa_ax1*ax1_t1 + dax_t1; ax_rt1 = axa_ax1*ax1_rt1; ax_a1 = dax_a1; ax_hk2 = axa_ax2*ax2_hk2; ax_t2 = axa_ax2*ax2_t2 + dax_t2; ax_rt2 = axa_ax2*ax2_rt2; ax_a2 = dax_a2; return true; } bool XFoil::bldif(int ityp) { //----------------------------------------------------------- // sets up the newton system coefficients and residuals // // ityp = 0 : similarity station // ityp = 1 : laminar interval // ityp = 2 : turbulent interval // ityp = 3 : wake interval // // this routine knows nothing about a transition interval, // which is taken care of by trdif. //----------------------------------------------------------- int k,l; double hupwt,hdcon, hl, hd_hk1,hd_hk2, hlsq, ehh; double upw, upw_hl, upw_hd, upw_hk1, upw_hk2, upw_u1, upw_t1, upw_d1; double upw_u2, upw_t2, upw_d2, upw_ms; double dxi, slog, scc, scc_usa, scc_us1, scc_us2; double ax, ax_t1, ax_rt1, ax_a1, ax_hk2, ax_t2, ax_rt2, ax_a2; double rezc, z_ax, hr, hr_hka, hr_rta; double hl_hk1, hl_hk2, ax_hk1, sa, cqa, cfa, hka, usa, rta, dea, da, ald; double gcc, hkc, hkc_hka, hkc_rta, rezt, rezh; double btmp, hwa, ha, ma, xa, ta, xlog, ulog, tlog, hlog, ddlog; double z_cfx, z_ha, z_hwa, z_ma, z_xl, z_tl, z_cfm, z_t1, z_t2; double z_dix, z_hca, z_hl, z_hs1, z_hs2, z_di1, z_di2; double z_cfa, z_hka, z_da, z_sl, z_ul, z_dxi, z_usa, z_cqa, z_sa, z_dea; double z_upw, z_de1, z_de2, z_us1, z_us2, z_d1, z_d2, z_u1, z_u2, z_x1, z_x2; double z_s1, z_s2, z_cq1, z_cq2, z_cf1, z_cf2, z_hk1, z_hk2; double cfx, cfx_xa, cfx_ta, cfx_x1, cfx_x2, cfx_t1, cfx_t2, cfx_cf1, cfx_cf2, cfx_cfm; double xot1, xot2, hca, hsa, dix, dix_upw, cfx_upw; double uq, uq_hka, uq_rta, uq_cfa, uq_da, uq_upw, uq_t1, uq_t2; double uq_d1, uq_d2, uq_u1, uq_u2, uq_ms, uq_re; double f_arg;// ex arg if(ityp==0) { //----- similarity logarithmic differences (prescribed) xlog = 1.0; ulog = bule; tlog = 0.5*(1.0 - bule); hlog = 0.0; ddlog = 0.0; } else { //----- usual logarithmic differences xlog = log(x2/x1); ulog = log(u2/u1); tlog = log(t2/t1); hlog = log(hs2/hs1); ddlog = 1.0; } for (k=1; k<=4;k++) { vsrez[k] = 0.0; vsm[k] = 0.0; vsr[k] = 0.0; vsx[k] = 0.0; for (l=1;l<=5;l++) { vs1[k][l] = 0.0; vs2[k][l] = 0.0; } } //---- set triggering constant for local upwinding hupwt = 1.0; hdcon = 5.0*hupwt/hk2/hk2; hd_hk1 = 0.0; hd_hk2 = -hdcon*2.0/hk2; //---- use less upwinding in the wake if(ityp==3) { hdcon = hupwt/hk2/hk2; hd_hk1 = 0.0; hd_hk2 = -hdcon*2.0/hk2; } // //---- local upwinding is based on local change in log(hk-1) //- (mainly kicks in at transition) f_arg = qAbs((hk2-1.0)/(hk1-1.0)); hl = log(f_arg); hl_hk1 = -1.0/(hk1-1.0); hl_hk2 = 1.0/(hk2-1.0); hlsq = qMin(hl*hl, 15.0); ehh = exp(-hlsq*hdcon); upw = 1.0 - 0.5*ehh; upw_hl = ehh * hl *hdcon; upw_hd = 0.5*ehh * hlsq; upw_hk1 = upw_hl*hl_hk1 + upw_hd*hd_hk1; upw_hk2 = upw_hl*hl_hk2 + upw_hd*hd_hk2; upw_u1 = upw_hk1*hk1_u1; upw_t1 = upw_hk1*hk1_t1; upw_d1 = upw_hk1*hk1_d1; upw_u2 = upw_hk2*hk2_u2; upw_t2 = upw_hk2*hk2_t2; upw_d2 = upw_hk2*hk2_d2; upw_ms = upw_hk1*hk1_ms + upw_hk2*hk2_ms; if(ityp==0) { //***** le point --> set zero amplification factor vs2[1][1] = 1.0; vsr[1] = 0.0; vsrez[1] = -ampl2; } else { if(ityp==1) { //***** laminar part --> set amplification equation //----- set average amplification ax over interval x1..x2 axset(hk1, t1, rt1, ampl1, hk2, t2, rt2, ampl2, amcrit, ax, ax_hk1, ax_t1, ax_rt1, ax_a1, ax_hk2, ax_t2, ax_rt2, ax_a2 ); rezc = ampl2 - ampl1 - ax*(x2-x1); z_ax = -(x2-x1); vs1[1][1] = z_ax* ax_a1 - 1.0; vs1[1][2] = z_ax*(ax_hk1*hk1_t1 + ax_t1 + ax_rt1*rt1_t1); vs1[1][3] = z_ax*(ax_hk1*hk1_d1 ); vs1[1][4] = z_ax*(ax_hk1*hk1_u1 + ax_rt1*rt1_u1); vs1[1][5] = ax; vs2[1][1] = z_ax* ax_a2 + 1.0; vs2[1][2] = z_ax*(ax_hk2*hk2_t2 + ax_t2 + ax_rt2*rt2_t2); vs2[1][3] = z_ax*(ax_hk2*hk2_d2 ) ; vs2[1][4] = z_ax*(ax_hk2*hk2_u2 + ax_rt2*rt2_u2); vs2[1][5] = -ax; vsm[1] = z_ax*(ax_hk1*hk1_ms + ax_rt1*rt1_ms + ax_hk2*hk2_ms + ax_rt2*rt2_ms); vsr[1] = z_ax*( ax_rt1*rt1_re + ax_rt2*rt2_re); vsx[1] = 0.0; vsrez[1] = -rezc; } else { //***** turbulent part --> set shear lag equation sa = (1.0-upw)*s1 + upw*s2; cqa = (1.0-upw)*cq1 + upw*cq2; cfa = (1.0-upw)*cf1 + upw*cf2; hka = (1.0-upw)*hk1 + upw*hk2; usa = 0.5*(us1 + us2); rta = 0.5*(rt1 + rt2); dea = 0.5*(de1 + de2); da = 0.5*(d1 + d2 ); if(ityp==3) ald = dlcon;//------ increased dissipation length in wake (decrease its reciprocal) else ald = 1.0; //----- set and linearize equilibrium 1/ue due/dx ... new 12 oct 94 if(ityp==2) { gcc = gccon; hkc = hka - 1.0 - gcc/rta; hkc_hka = 1.0; hkc_rta = gcc/rta/rta; if(hkc < 0.01) { hkc = 0.01; hkc_hka = 0.0; hkc_rta = 0.0; } } else { gcc = 0.0; hkc = hka - 1.0; hkc_hka = 1.0; hkc_rta = 0.0; } hr = hkc / (gacon*ald*hka); hr_hka = hkc_hka / (gacon*ald*hka) - hr / hka; hr_rta = hkc_rta / (gacon*ald*hka); uq = (0.5*cfa - hr*hr) / (gbcon*da); uq_hka = -2.0*hr*hr_hka / (gbcon*da); uq_rta = -2.0*hr*hr_rta / (gbcon*da); uq_cfa = 0.5 / (gbcon*da); uq_da = -uq/da; uq_upw = uq_cfa*(cf2-cf1) + uq_hka*(hk2-hk1); uq_t1 = (1.0-upw)*(uq_cfa*cf1_t1 + uq_hka*hk1_t1) + uq_upw*upw_t1; uq_d1 = (1.0-upw)*(uq_cfa*cf1_d1 + uq_hka*hk1_d1) + uq_upw*upw_d1; uq_u1 = (1.0-upw)*(uq_cfa*cf1_u1 + uq_hka*hk1_u1) + uq_upw*upw_u1; uq_t2 = upw *(uq_cfa*cf2_t2 + uq_hka*hk2_t2) + uq_upw*upw_t2; uq_d2 = upw *(uq_cfa*cf2_d2 + uq_hka*hk2_d2) + uq_upw*upw_d2; uq_u2 = upw *(uq_cfa*cf2_u2 + uq_hka*hk2_u2) + uq_upw*upw_u2; uq_ms = (1.0-upw)*(uq_cfa*cf1_ms + uq_hka*hk1_ms) + uq_upw*upw_ms + upw *(uq_cfa*cf2_ms + uq_hka*hk2_ms); uq_re = (1.0-upw)* uq_cfa*cf1_re + upw * uq_cfa*cf2_re; uq_t1 = uq_t1 + 0.5*uq_rta*rt1_t1; uq_d1 = uq_d1 + 0.5*uq_da; uq_u1 = uq_u1 + 0.5*uq_rta*rt1_u1; uq_t2 = uq_t2 + 0.5*uq_rta*rt2_t2; uq_d2 = uq_d2 + 0.5*uq_da; uq_u2 = uq_u2 + 0.5*uq_rta*rt2_u2; uq_ms = uq_ms + 0.5*uq_rta*rt1_ms + 0.5*uq_rta*rt2_ms; uq_re = uq_re + 0.5*uq_rta*rt1_re + 0.5*uq_rta*rt2_re; scc = sccon*1.333/(1.0+usa); scc_usa = -scc/(1.0+usa); scc_us1 = scc_usa*0.5; scc_us2 = scc_usa*0.5; slog = log(s2/s1); dxi = x2 - x1; rezc = scc*(cqa - sa*ald)*dxi- dea*2.0* slog + dea*2.0*(uq*dxi - ulog); z_cfa = dea*2.0*uq_cfa*dxi; z_hka = dea*2.0*uq_hka*dxi; z_da = dea*2.0*uq_da *dxi; z_sl = -dea*2.0; z_ul = -dea*2.0; z_dxi = scc *(cqa - sa*ald) + dea*2.0*uq; z_usa = scc_usa*(cqa - sa*ald)*dxi; z_cqa = scc*dxi; z_sa = -scc*dxi*ald; z_dea = 2.0*(uq*dxi - ulog - slog); z_upw = z_cqa*(cq2-cq1) + z_sa *(s2 -s1 )+ z_cfa*(cf2-cf1) + z_hka*(hk2-hk1); z_de1 = 0.5*z_dea; z_de2 = 0.5*z_dea; z_us1 = 0.5*z_usa; z_us2 = 0.5*z_usa; z_d1 = 0.5*z_da; z_d2 = 0.5*z_da; z_u1 = - z_ul/u1; z_u2 = z_ul/u2; z_x1 = -z_dxi; z_x2 = z_dxi; z_s1 = (1.0-upw)*z_sa - z_sl/s1; z_s2 = upw *z_sa + z_sl/s2; z_cq1 = (1.0-upw)*z_cqa; z_cq2 = upw *z_cqa; z_cf1 = (1.0-upw)*z_cfa; z_cf2 = upw *z_cfa; z_hk1 = (1.0-upw)*z_hka; z_hk2 = upw *z_hka; vs1[1][1] = z_s1; vs1[1][2] = z_upw*upw_t1 + z_de1*de1_t1 + z_us1*us1_t1; vs1[1][3] = z_d1 + z_upw*upw_d1 + z_de1*de1_d1 + z_us1*us1_d1; vs1[1][4] = z_u1 + z_upw*upw_u1 + z_de1*de1_u1 + z_us1*us1_u1; vs1[1][5] = z_x1; vs2[1][1] = z_s2; vs2[1][2] = z_upw*upw_t2 + z_de2*de2_t2 + z_us2*us2_t2; vs2[1][3] = z_d2 + z_upw*upw_d2 + z_de2*de2_d2 + z_us2*us2_d2; vs2[1][4] = z_u2 + z_upw*upw_u2 + z_de2*de2_u2 + z_us2*us2_u2; vs2[1][5] = z_x2; vsm[1] = z_upw*upw_ms + z_de1*de1_ms + z_us1*us1_ms+ z_de2*de2_ms + z_us2*us2_ms; vs1[1][2] = vs1[1][2] + z_cq1*cq1_t1 + z_cf1*cf1_t1 + z_hk1*hk1_t1; vs1[1][3] = vs1[1][3] + z_cq1*cq1_d1 + z_cf1*cf1_d1 + z_hk1*hk1_d1; vs1[1][4] = vs1[1][4] + z_cq1*cq1_u1 + z_cf1*cf1_u1 + z_hk1*hk1_u1; vs2[1][2] = vs2[1][2] + z_cq2*cq2_t2 + z_cf2*cf2_t2 + z_hk2*hk2_t2; vs2[1][3] = vs2[1][3] + z_cq2*cq2_d2 + z_cf2*cf2_d2 + z_hk2*hk2_d2; vs2[1][4] = vs2[1][4] + z_cq2*cq2_u2 + z_cf2*cf2_u2 + z_hk2*hk2_u2; vsm[1] = vsm[1] + z_cq1*cq1_ms + z_cf1*cf1_ms + z_hk1*hk1_ms + z_cq2*cq2_ms + z_cf2*cf2_ms + z_hk2*hk2_ms; vsr[1] = z_cq1*cq1_re + z_cf1*cf1_re + z_cq2*cq2_re + z_cf2*cf2_re; vsx[1] = 0.0; vsrez[1] = -rezc; } }//endif //**** set up momentum equation ha = 0.5*(h1 + h2); ma = 0.5*(m1 + m2); xa = 0.5*(x1 + x2); ta = 0.5*(t1 + t2); hwa = 0.5*(dw1/t1 + dw2/t2); //---- set cf term, using central value cfm for better accuracy in drag cfx = 0.50*cfm*xa/ta + 0.25*(cf1*x1/t1 + cf2*x2/t2); cfx_xa = 0.50*cfm /ta; cfx_ta = -.50*cfm*xa/ta/ta; cfx_x1 = 0.25*cf1 /t1 + cfx_xa*0.5; cfx_x2 = 0.25*cf2 /t2 + cfx_xa*0.5; cfx_t1 = -.25*cf1*x1/t1/t1 + cfx_ta*0.5; cfx_t2 = -.25*cf2*x2/t2/t2 + cfx_ta*0.5; cfx_cf1 = 0.25* x1/t1; cfx_cf2 = 0.25* x2/t2; cfx_cfm = 0.50* xa/ta; btmp = ha + 2.0 - ma + hwa; rezt = tlog + btmp*ulog - xlog*0.5*cfx; z_cfx = -xlog*0.5; z_ha = ulog; z_hwa = ulog; z_ma = -ulog; z_xl =-ddlog * 0.5*cfx; z_ul = ddlog * btmp; z_tl = ddlog; z_cfm = z_cfx*cfx_cfm; z_cf1 = z_cfx*cfx_cf1; z_cf2 = z_cfx*cfx_cf2; z_t1 = -z_tl/t1 + z_cfx*cfx_t1 + z_hwa*0.5*(-dw1/t1/t1); z_t2 = z_tl/t2 + z_cfx*cfx_t2 + z_hwa*0.5*(-dw2/t2/t2); z_x1 = -z_xl/x1 + z_cfx*cfx_x1; z_x2 = z_xl/x2 + z_cfx*cfx_x2; z_u1 = -z_ul/u1; z_u2 = z_ul/u2; vs1[2][2] = 0.5*z_ha*h1_t1 + z_cfm*cfm_t1 + z_cf1*cf1_t1 + z_t1; vs1[2][3] = 0.5*z_ha*h1_d1 + z_cfm*cfm_d1 + z_cf1*cf1_d1; vs1[2][4] = 0.5*z_ma*m1_u1 + z_cfm*cfm_u1 + z_cf1*cf1_u1 + z_u1; vs1[2][5] = z_x1; vs2[2][2] = 0.5*z_ha*h2_t2 + z_cfm*cfm_t2 + z_cf2*cf2_t2 + z_t2; vs2[2][3] = 0.5*z_ha*h2_d2 + z_cfm*cfm_d2 + z_cf2*cf2_d2; vs2[2][4] = 0.5*z_ma*m2_u2 + z_cfm*cfm_u2 + z_cf2*cf2_u2 + z_u2; vs2[2][5] = z_x2; vsm[2] = 0.5*z_ma*m1_ms + z_cfm*cfm_ms + z_cf1*cf1_ms + 0.5*z_ma*m2_ms + z_cf2*cf2_ms; vsr[2] = z_cfm*cfm_re + z_cf1*cf1_re + z_cf2*cf2_re; vsx[2] = 0.0; vsrez[2] = -rezt; //**** set up shape parameter equation xot1 = x1/t1; xot2 = x2/t2; ha = 0.5*(h1 + h2 ); hsa = 0.5*(hs1 + hs2); hca = 0.5*(hc1 + hc2); hwa = 0.5*(dw1/t1 + dw2/t2); dix = (1.0-upw)*di1*xot1 + upw*di2*xot2; cfx = (1.0-upw)*cf1*xot1 + upw*cf2*xot2; dix_upw = di2*xot2 - di1*xot1; cfx_upw = cf2*xot2 - cf1*xot1; btmp = 2.0*hca/hsa + 1.0 - ha - hwa; rezh = hlog + btmp*ulog + xlog*(0.5*cfx-dix); z_cfx = xlog*0.5; z_dix = -xlog; z_hca = 2.0*ulog/hsa; z_ha = -ulog; z_hwa = -ulog; z_xl = ddlog * (0.5*cfx-dix); z_ul = ddlog * btmp; z_hl = ddlog; z_upw = z_cfx*cfx_upw + z_dix*dix_upw; z_hs1 = -hca*ulog/hsa/hsa - z_hl/hs1; z_hs2 = -hca*ulog/hsa/hsa + z_hl/hs2; z_cf1 = (1.0-upw)*z_cfx*xot1; z_cf2 = upw *z_cfx*xot2; z_di1 = (1.0-upw)*z_dix*xot1; z_di2 = upw *z_dix*xot2; z_t1 = (1.0-upw)*(z_cfx*cf1 + z_dix*di1)*(-xot1/t1); z_t2 = upw *(z_cfx*cf2 + z_dix*di2)*(-xot2/t2); z_x1 = (1.0-upw)*(z_cfx*cf1 + z_dix*di1)/ t1 - z_xl/x1; z_x2 = upw *(z_cfx*cf2 + z_dix*di2)/ t2 + z_xl/x2; z_u1 = - z_ul/u1; z_u2 = z_ul/u2; z_t1 = z_t1 + z_hwa*0.5*(-dw1/t1/t1); z_t2 = z_t2 + z_hwa*0.5*(-dw2/t2/t2); vs1[3][1] = z_di1*di1_s1; vs1[3][2] = z_hs1*hs1_t1 + z_cf1*cf1_t1 + z_di1*di1_t1 + z_t1; vs1[3][3] = z_hs1*hs1_d1 + z_cf1*cf1_d1 + z_di1*di1_d1; vs1[3][4] = z_hs1*hs1_u1 + z_cf1*cf1_u1 + z_di1*di1_u1 + z_u1; vs1[3][5] = z_x1; vs2[3][1] = z_di2*di2_s2; vs2[3][2] = z_hs2*hs2_t2 + z_cf2*cf2_t2 + z_di2*di2_t2 + z_t2; vs2[3][3] = z_hs2*hs2_d2 + z_cf2*cf2_d2 + z_di2*di2_d2; vs2[3][4] = z_hs2*hs2_u2 + z_cf2*cf2_u2 + z_di2*di2_u2 + z_u2; vs2[3][5] = z_x2; vsm[3] = z_hs1*hs1_ms + z_cf1*cf1_ms + z_di1*di1_ms + z_hs2*hs2_ms + z_cf2*cf2_ms + z_di2*di2_ms; vsr[3] = z_hs1*hs1_re + z_cf1*cf1_re + z_di1*di1_re + z_hs2*hs2_re + z_cf2*cf2_re + z_di2*di2_re; vs1[3][2] = vs1[3][2] + 0.5*(z_hca*hc1_t1+z_ha*h1_t1) + z_upw*upw_t1; vs1[3][3] = vs1[3][3] + 0.5*(z_hca*hc1_d1+z_ha*h1_d1) + z_upw*upw_d1; vs1[3][4] = vs1[3][4] + 0.5*(z_hca*hc1_u1 ) + z_upw*upw_u1; vs2[3][2] = vs2[3][2] + 0.5*(z_hca*hc2_t2+z_ha*h2_t2) + z_upw*upw_t2; vs2[3][3] = vs2[3][3] + 0.5*(z_hca*hc2_d2+z_ha*h2_d2) + z_upw*upw_d2; vs2[3][4] = vs2[3][4] + 0.5*(z_hca*hc2_u2 ) + z_upw*upw_u2; vsm[3] = vsm[3] + 0.5*(z_hca*hc1_ms ) + z_upw*upw_ms + 0.5*(z_hca*hc2_ms ); vsx[3] = 0.0; vsrez[3] = -rezh; return true; } bool XFoil::blkin() { //---------------------------------------------------------- // calculates turbulence-independent secondary "2" // variables from the primary "2" variables. //---------------------------------------------------------- double tr2, herat, he_u2, he_ms, v2_he, hk2_h2, hk2_m2; //---- set edge mach number ** 2 m2 = u2*u2*hstinv / (gm1bl*(1.0 - 0.5*u2*u2*hstinv)); tr2 = 1.0 + 0.5*gm1bl*m2; m2_u2 = 2.0*m2*tr2/u2; m2_ms = u2*u2*tr2 / (gm1bl*(1.0 - 0.5*u2*u2*hstinv))* hstinv_ms; //---- set edge density (isentropic relation) r2 = rstbl *pow(tr2,(-1.0/gm1bl)); r2_u2 = -r2/tr2 * 0.5*m2_u2; r2_ms = -r2/tr2 * 0.5*m2_ms+ rstbl_ms*pow(tr2,(-1.0/gm1bl)); //---- set shape parameter h2 = d2/t2; h2_d2 = 1.0/t2; h2_t2 = -h2/t2; //---- set edge static/stagnation enthalpy herat = 1.0 - 0.5*u2*u2*hstinv; he_u2 = - u2*hstinv; he_ms = - 0.5*u2*u2*hstinv_ms; //---- set molecular viscosity v2 = sqrt(herat*herat*herat) * (1.0+hvrat)/(herat+hvrat)/reybl; v2_he = v2*(1.5/herat - 1.0/(herat+hvrat)); v2_u2 = v2_he*he_u2; v2_ms = -v2/reybl * reybl_ms + v2_he*he_ms; v2_re = -v2/reybl * reybl_re; //---- set kinematic shape parameter hkin(h2, m2, hk2, hk2_h2, hk2_m2 ); hk2_u2 = hk2_m2*m2_u2; hk2_t2 = hk2_h2*h2_t2; hk2_d2 = hk2_h2*h2_d2; hk2_ms = hk2_m2*m2_ms; //---- set momentum thickness reynolds number rt2 = r2*u2*t2/v2; rt2_u2 = rt2*(1.0/u2 + r2_u2/r2 - v2_u2/v2); rt2_t2 = rt2/t2; rt2_ms = rt2*( r2_ms/r2 - v2_ms/v2); rt2_re = rt2*( - v2_re/v2); return true; } bool XFoil::blmid(int ityp) { //---------------------------------------------------- // calculates midpoint skin friction cfm // // ityp = 1 : laminar // ityp = 2 : turbulent // ityp = 3 : turbulent wake //---------------------------------------------------- // double hka, rta, ma, cfm_rta, cfm_ma; double cfml, cfml_hka, cfml_rta, cfml_ma, cfm_hka; //---- set similarity variables if not defined if(simi) { hk1 = hk2; hk1_t1 = hk2_t2; hk1_d1 = hk2_d2; hk1_u1 = hk2_u2; hk1_ms = hk2_ms; rt1 = rt2; rt1_t1 = rt2_t2; rt1_u1 = rt2_u2; rt1_ms = rt2_ms; rt1_re = rt2_re; m1 = m2; m1_u1 = m2_u2; m1_ms = m2_ms; } //---- define stuff for midpoint cf hka = 0.5*(hk1 + hk2); rta = 0.5*(rt1 + rt2); ma = 0.5*(m1 + m2 ); //---- midpoint skin friction coefficient (zero in wake) if(ityp==3) { cfm = 0.0; cfm_hka = 0.0; cfm_rta = 0.0; cfm_ma = 0.0; cfm_ms = 0.0; } else { if(ityp==1) cfl( hka, rta, cfm, cfm_hka, cfm_rta, cfm_ma ); else { cft( hka, rta, ma, cfm, cfm_hka, cfm_rta, cfm_ma ); cfl( hka, rta, cfml, cfml_hka, cfml_rta, cfml_ma); if(cfml>cfm) { //ccc write(*,*) 'cft cfl rt hk:', cfm, cfml, rta, hka, 0.5*(x1+x2) cfm = cfml; cfm_hka = cfml_hka; cfm_rta = cfml_rta; cfm_ma = cfml_ma; } } } cfm_u1 = 0.5*(cfm_hka*hk1_u1 + cfm_ma*m1_u1 + cfm_rta*rt1_u1); cfm_t1 = 0.5*(cfm_hka*hk1_t1 + cfm_rta*rt1_t1); cfm_d1 = 0.5*(cfm_hka*hk1_d1 ); cfm_u2 = 0.5*(cfm_hka*hk2_u2 + cfm_ma*m2_u2 + cfm_rta*rt2_u2); cfm_t2 = 0.5*(cfm_hka*hk2_t2 + cfm_rta*rt2_t2); cfm_d2 = 0.5*(cfm_hka*hk2_d2 ); cfm_ms = 0.5*(cfm_hka*hk1_ms + cfm_ma*m1_ms + cfm_rta*rt1_ms + cfm_hka*hk2_ms + cfm_ma*m2_ms + cfm_rta*rt2_ms); cfm_re = 0.5*( cfm_rta*rt1_re + cfm_rta*rt2_re); return true; } bool XFoil::blprv(double xsi, double ami, double cti, double thi, double dsi, double dswaki, double uei){ //---------------------------------------------------------- // set bl primary "2" variables from parameter list //---------------------------------------------------------- x2 = xsi; ampl2 = ami; s2 = cti; t2 = thi; d2 = dsi - dswaki; dw2 = dswaki; u2 = uei*(1.0-tkbl) / (1.0 - tkbl*(uei/qinfbl)*(uei/qinfbl)); u2_uei = (1.0 + tkbl*(2.0*u2*uei/qinfbl/qinfbl - 1.0)) / (1.0 - tkbl*(uei/qinfbl)*(uei/qinfbl)); u2_ms = (u2*(uei/qinfbl)*(uei/qinfbl) - uei)*tkbl_ms / (1.0 - tkbl*(uei/qinfbl)*(uei/qinfbl)); return true; } bool XFoil::blsolve() { //----------------------------------------------------------------- // custom solver for coupled viscous-inviscid newton system: // // a | | . | | . | d r s // b a | . | | . | d r s // | b a . | | . | d r s // . . . . | | . | d = r - dre s // | | | b a | . | d r s // | z | | b a . | d r s // . . . . . . . | d r s // | | | | | | b a d r s // // a, b, z 3x3 blocks containing linearized bl equation coefficients // | 3x1 vectors containing mass defect influence // coefficients on ue // d 3x1 unknown vectors (newton deltas for ctau][ theta][ m) // r 3x1 residual vectors // s 3x1 re influence vectors //----------------------------------------------------------------- // int iv, kv, ivp, k, l, ivte1, ivz; double pivot, vtmp, vtmp1, vtmp2, vtmp3; ivte1 = isys[iblte[1]][1]; // for (iv=1; iv<= nsys; iv++) { // ivp = iv + 1; // //====== invert va[iv] block // //------ normalize first row pivot = 1.0 / va[1][1][iv]; va[1][2][iv] *= pivot; for (l=iv;l<= nsys;l++) vm[1][l][iv] *= pivot; vdel[1][1][iv] *= pivot; vdel[1][2][iv] *= pivot; // //------ eliminate lower first column in va block for (k=2; k<= 3; k++) { vtmp = va[k][1][iv]; va[k][2][iv] -= vtmp*va[1][2][iv]; for (int l=iv; l<=nsys; l++) vm[k][l][iv] -= vtmp*vm[1][l][iv]; vdel[k][1][iv] -= vtmp*vdel[1][1][iv]; vdel[k][2][iv] -= vtmp*vdel[1][2][iv]; } // //------ normalize second row pivot = 1.0 / va[2][2][iv]; for (l=iv; l<= nsys; l++) vm[2][l][iv] *=pivot; vdel[2][1][iv] *= pivot; vdel[2][2][iv] *= pivot; // //------ eliminate lower second column in va block k = 3; vtmp = va[k][2][iv]; for (l=iv; l<=nsys; l++) vm[k][l][iv] -= vtmp*vm[2][l][iv]; vdel[k][1][iv] -= vtmp*vdel[2][1][iv]; vdel[k][2][iv] -= vtmp*vdel[2][2][iv]; //------ normalize third row pivot = 1.0/vm[3][iv][iv]; for (l=ivp; l<=nsys; l++) vm[3][l][iv] *= pivot; vdel[3][1][iv] *= pivot; vdel[3][2][iv] *= pivot; // // //------ eliminate upper third column in va block vtmp1 = vm[1][iv][iv]; vtmp2 = vm[2][iv][iv]; for(l=ivp;l<= nsys;l++) { vm[1][l][iv] -= vtmp1*vm[3][l][iv]; vm[2][l][iv] -= vtmp2*vm[3][l][iv]; } vdel[1][1][iv] -= vtmp1*vdel[3][1][iv]; vdel[2][1][iv] -= vtmp2*vdel[3][1][iv]; vdel[1][2][iv] -= vtmp1*vdel[3][2][iv]; vdel[2][2][iv] -= vtmp2*vdel[3][2][iv]; // //------ eliminate upper second column in va block vtmp = va[1][2][iv]; for (l=ivp; l<=nsys;l++) vm[1][l][iv] -= vtmp*vm[2][l][iv]; vdel[1][1][iv] -= vtmp*vdel[2][1][iv]; vdel[1][2][iv] -= vtmp*vdel[2][2][iv]; // // if(iv!=nsys) { // //====== eliminate vb(iv+1) block][ rows 1 -> 3 for (k=1; k<= 3;k++) { vtmp1 = vb[k][ 1][ivp]; vtmp2 = vb[k][ 2][ivp]; vtmp3 = vm[k][iv][ivp]; for(l=ivp; l<= nsys;l++) vm[k][l][ivp] -= (vtmp1*vm[1][l][iv]+ vtmp2*vm[2][l][iv]+vtmp3*vm[3][l][iv]); vdel[k][1][ivp] -= (vtmp1*vdel[1][1][iv]+vtmp2*vdel[2][1][iv]+ vtmp3*vdel[3][1][iv]); vdel[k][2][ivp] -= (vtmp1*vdel[1][2][iv]+vtmp2*vdel[2][2][iv]+ vtmp3*vdel[3][2][iv]); } // if(iv==ivte1) { //------- eliminate vz block ivz = isys[iblte[2]+1][2]; // for(k=1;k<=3;k++) { vtmp1 = vz[k][1]; vtmp2 = vz[k][2]; for (l=ivp;l<= nsys;l++) { vm[k][l][ivz] -=(vtmp1*vm[1][l][iv]+ vtmp2*vm[2][l][iv]); } vdel[k][1][ivz] -= (vtmp1*vdel[1][1][iv]+ vtmp2*vdel[2][1][iv]); vdel[k][2][ivz] -= (vtmp1*vdel[1][2][iv]+ vtmp2*vdel[2][2][iv]); } } // if(ivp!=nsys) { // //====== eliminate lower vm column for(kv=iv+2; kv<= nsys;kv++) { vtmp1 = vm[1][iv][kv]; vtmp2 = vm[2][iv][kv]; vtmp3 = vm[3][iv][kv]; // if(qAbs(vtmp1)>vaccel) { for(l=ivp;l<= nsys;l++) vm[1][l][kv] -= vtmp1*vm[3][l][iv]; vdel[1][1][kv] -= vtmp1*vdel[3][1][iv]; vdel[1][2][kv] -= vtmp1*vdel[3][2][iv]; } // if(qAbs(vtmp2)>vaccel) { for (l=ivp;l<=nsys;l++) vm[2][l][kv] -= vtmp2*vm[3][l][iv]; vdel[2][1][kv] -= vtmp2*vdel[3][1][iv]; vdel[2][2][kv] -= vtmp2*vdel[3][2][iv]; } // if(qAbs(vtmp3)>vaccel) { for(l=ivp;l<=nsys;l++) vm[3][l][kv] -= vtmp3*vm[3][l][iv]; vdel[3][1][kv] -= vtmp3*vdel[3][1][iv]; vdel[3][2][kv] -= vtmp3*vdel[3][2][iv]; } // } } } }//1000 // for (iv=nsys; iv>=2;iv--) { //------ eliminate upper vm columns vtmp = vdel[3][1][iv]; for (kv=iv-1; kv>=1;kv--) { vdel[1][1][kv] -= vm[1][iv][kv]*vtmp; vdel[2][1][kv] -= vm[2][iv][kv]*vtmp; vdel[3][1][kv] -= vm[3][iv][kv]*vtmp; } vtmp = vdel[3][2][iv]; for (kv=iv-1; kv>=1;kv--) { vdel[1][2][kv] -= vm[1][iv][kv]*vtmp; vdel[2][2][kv] -= vm[2][iv][kv]*vtmp; vdel[3][2][kv] -= vm[3][iv][kv]*vtmp; } // } return true; } bool XFoil::blsys() { //------------------------------------------------------------------ // // sets up the bl newton system governing the current interval: // // | ||da1| | ||da2| | | // | vs1 ||dt1| + | vs2 ||dt2| = |vsrez| // | ||dd1| | ||dd2| | | // |du1| |du2| // |dx1| |dx2| // // 3x5 5x1 3x5 5x1 3x1 // // the system as shown corresponds to a laminar station // if tran, then ds2 replaces da2 // if turb, then ds1, ds2 replace da1, da2 // //------------------------------------------------------------------ // double res_u1, res_u2, res_ms; int k, l; //---- calculate secondary bl variables and their sensitivities if(wake) { blvar(3); blmid(3); } else { if(turb || tran) { blvar(2); blmid(2); } else { blvar(1); blmid(1); } } //---- for the similarity station, "1" and "2" variables are the same if(simi) { // for(int icom=1;icom<= ncom;icom++) com1[icom] = com2[icom]; stepbl(); } //---- set up appropriate finite difference system for current interval if(tran) trdif(); else if(simi) bldif(0); else if(!turb) bldif(1); else if(wake) bldif(3); else if(turb) bldif(2); if(simi) { //----- at similarity station, "1" variables are really "2" variables for (k=1; k<= 4;k++) { for(l=1; l<= 5; l++){ vs2[k][l] = vs1[k][l] + vs2[k][l]; vs1[k][l] = 0.0; } } } //---- change system over into incompressible uei and mach for(k=1;k<= 4;k++) { //------ residual derivatives wrt compressible uec res_u1 = vs1[k][4]; res_u2 = vs2[k][4]; res_ms = vsm[k]; //------ combine with derivatives of compressible u1,u2 = uec(uei m) vs1[k][4] = res_u1*u1_uei; vs2[k][4] = res_u2*u2_uei; vsm[k] = res_u1*u1_ms + res_u2*u2_ms + res_ms; } return true; } bool XFoil::blvar(int ityp) { //---------------------------------------------------- // calculates all secondary "2" variables from // the primary "2" variables x2, u2, t2, d2, s2. // also calculates the sensitivities of the // secondary variables wrt the primary variables. // // ityp = 1 : laminar // ityp = 2 : turbulent // ityp = 3 : turbulent wake //---------------------------------------------------- double hs2_hk2, hs2_rt2, hs2_m2; double hc2_hk2, hc2_m2, us2_hs2, us2_hk2, us2_h2; double gcc, hkc, hkc_hk2, hkc_rt2, hkb, usb; double cq2_hs2, cq2_us2, cq2_hk2; double cq2_rt2, cq2_h2, cf2_hk2, cf2_rt2, cf2_m2; double cf2l, cf2l_hk2, cf2l_rt2, cf2l_m2; double di2_hk2, di2_rt2, cf2t, cf2t_hk2; double cf2t_rt2, cf2t_m2, cf2t_u2, cf2t_t2; double cf2t_d2, cf2t_ms, cf2t_re, di2_hs2; double di2_us2, di2_cf2t, hmin, hm_rt2; double grt, fl, fl_hk2, fl_rt2, tfl; double dfac, df_fl, df_hk2, df_rt2, dd, dd_hs2; double dd_us2, dd_s2, dd_rt2, di2l, di2l_hk2, di2l_rt2, de2_hk2, hdmax; // double gbcon, gccon, ctcon, hkc2;//were are they initialized ? if(ityp==3) hk2 = qMax(hk2,1.00005); if(ityp!=3) hk2 = qMax(hk2,1.05000); //---- density thickness shape parameter ( h** ) hct( hk2, m2, hc2, hc2_hk2, hc2_m2 ); hc2_u2 = hc2_hk2*hk2_u2 + hc2_m2*m2_u2; hc2_t2 = hc2_hk2*hk2_t2; hc2_d2 = hc2_hk2*hk2_d2; hc2_ms = hc2_hk2*hk2_ms + hc2_m2*m2_ms; //---- set ke thickness shape parameter from h - h* correlations if(ityp==1) hsl(hk2, hs2, hs2_hk2, hs2_rt2, hs2_m2 ); else hst(hk2, rt2, m2, hs2, hs2_hk2, hs2_rt2, hs2_m2 ); hs2_u2 = hs2_hk2*hk2_u2 + hs2_rt2*rt2_u2 + hs2_m2*m2_u2; hs2_t2 = hs2_hk2*hk2_t2 + hs2_rt2*rt2_t2; hs2_d2 = hs2_hk2*hk2_d2; hs2_ms = hs2_hk2*hk2_ms + hs2_rt2*rt2_ms + hs2_m2*m2_ms; hs2_re = hs2_rt2*rt2_re; //---- normalized slip velocity us us2 = 0.5*hs2*( 1.0 - (hk2-1.0)/(gbcon*h2) ); us2_hs2 = 0.5 * ( 1.0 - (hk2-1.0)/(gbcon*h2) ); us2_hk2 = 0.5*hs2*( - 1.0 /(gbcon*h2) ); us2_h2 = 0.5*hs2* (hk2-1.0)/(gbcon*h2*h2); us2_u2 = us2_hs2*hs2_u2 + us2_hk2*hk2_u2; us2_t2 = us2_hs2*hs2_t2 + us2_hk2*hk2_t2 + us2_h2*h2_t2; us2_d2 = us2_hs2*hs2_d2 + us2_hk2*hk2_d2 + us2_h2*h2_d2; us2_ms = us2_hs2*hs2_ms + us2_hk2*hk2_ms; us2_re = us2_hs2*hs2_re; if(ityp<=2 && us2>0.95) { // write(*,*) 'blvar: us clamped:', us2 us2 = 0.98; us2_u2 = 0.0; us2_t2 = 0.0; us2_d2 = 0.0; us2_ms = 0.0; us2_re = 0.0; } if(ityp==3 && us2>0.99995) { // write(*,*) 'blvar: wake us clamped:', us2 us2 = 0.99995; us2_u2 = 0.0; us2_t2 = 0.0; us2_d2 = 0.0; us2_ms = 0.0; us2_re = 0.0; } //---- equilibrium wake layer shear coefficient (ctau)eq ** 1/2 // ... new 12 oct 94 gcc = 0.0; hkc = hk2 - 1.0; hkc_hk2 = 1.0; hkc_rt2 = 0.0; if(ityp==2) { gcc = gccon; hkc = hk2 - 1.0 - gcc/rt2; hkc_hk2 = 1.0; hkc_rt2 = gcc/rt2/rt2; if(hkc < 0.01) { hkc = 0.01; hkc_hk2 = 0.0; hkc_rt2 = 0.0; } } hkb = hk2 - 1.0; usb = 1.0 - us2; cq2 = sqrt( ctcon*hs2*hkb*hkc*hkc / (usb*h2*hk2*hk2) ); cq2_hs2 = ctcon *hkb*hkc*hkc / (usb*h2*hk2*hk2) * 0.5/cq2; cq2_us2 = ctcon*hs2*hkb*hkc*hkc / (usb*h2*hk2*hk2) / usb * 0.5/cq2; cq2_hk2 = ctcon*hs2 *hkc*hkc / (usb*h2*hk2*hk2) * 0.5/cq2 - ctcon*hs2*hkb*hkc*hkc / (usb*h2*hk2*hk2*hk2) * 2.0 * 0.5/cq2 + ctcon*hs2*hkb*hkc / (usb*h2*hk2*hk2) * 2.0 * 0.5/cq2 *hkc_hk2; cq2_rt2 = ctcon*hs2*hkb*hkc / (usb*h2*hk2*hk2) * 2.0 * 0.5/cq2 *hkc_rt2; cq2_h2 =-ctcon*hs2*hkb*hkc*hkc / (usb*h2*hk2*hk2) / h2 * 0.5/cq2; cq2_u2 = cq2_hs2*hs2_u2 + cq2_us2*us2_u2 + cq2_hk2*hk2_u2; cq2_t2 = cq2_hs2*hs2_t2 + cq2_us2*us2_t2 + cq2_hk2*hk2_t2; cq2_d2 = cq2_hs2*hs2_d2 + cq2_us2*us2_d2 + cq2_hk2*hk2_d2; cq2_ms = cq2_hs2*hs2_ms + cq2_us2*us2_ms + cq2_hk2*hk2_ms; cq2_re = cq2_hs2*hs2_re + cq2_us2*us2_re; cq2_u2 = cq2_u2 + cq2_rt2*rt2_u2; cq2_t2 = cq2_t2 + cq2_h2*h2_t2 + cq2_rt2*rt2_t2; cq2_d2 = cq2_d2 + cq2_h2*h2_d2; cq2_ms = cq2_ms + cq2_rt2*rt2_ms; cq2_re = cq2_re + cq2_rt2*rt2_re; //---- set skin friction coefficient if(ityp==3) { //----- wake cf2 = 0.0; cf2_hk2 = 0.0; cf2_rt2 = 0.0; cf2_m2 = 0.0; } else { if(ityp==1) //----- laminar cfl(hk2, rt2, cf2, cf2_hk2, cf2_rt2, cf2_m2); else { //----- turbulent cft(hk2, rt2, m2, cf2, cf2_hk2, cf2_rt2, cf2_m2); cfl(hk2, rt2, cf2l, cf2l_hk2, cf2l_rt2, cf2l_m2); if(cf2l>cf2) { //------- laminar cf is greater than turbulent cf -- use laminar //- (this will only occur for unreasonably small rtheta) cf2 = cf2l; cf2_hk2 = cf2l_hk2; cf2_rt2 = cf2l_rt2; cf2_m2 = cf2l_m2; } } } cf2_u2 = cf2_hk2*hk2_u2 + cf2_rt2*rt2_u2 + cf2_m2*m2_u2; cf2_t2 = cf2_hk2*hk2_t2 + cf2_rt2*rt2_t2; cf2_d2 = cf2_hk2*hk2_d2; cf2_ms = cf2_hk2*hk2_ms + cf2_rt2*rt2_ms + cf2_m2*m2_ms; cf2_re = cf2_rt2*rt2_re; //---- dissipation function 2 cd / h* if(ityp==1) { //----- laminar dil( hk2, rt2, di2, di2_hk2, di2_rt2 ); di2_u2 = di2_hk2*hk2_u2 + di2_rt2*rt2_u2; di2_t2 = di2_hk2*hk2_t2 + di2_rt2*rt2_t2; di2_d2 = di2_hk2*hk2_d2; di2_s2 = 0.0; di2_ms = di2_hk2*hk2_ms + di2_rt2*rt2_ms; di2_re = di2_rt2*rt2_re; } else { if(ityp==2) { //----- turbulent wall contribution cft(hk2, rt2, m2, cf2t, cf2t_hk2, cf2t_rt2, cf2t_m2); cf2t_u2 = cf2t_hk2*hk2_u2 + cf2t_rt2*rt2_u2 + cf2t_m2*m2_u2; cf2t_t2 = cf2t_hk2*hk2_t2 + cf2t_rt2*rt2_t2; cf2t_d2 = cf2t_hk2*hk2_d2; cf2t_ms = cf2t_hk2*hk2_ms + cf2t_rt2*rt2_ms + cf2t_m2*m2_ms; cf2t_re = cf2t_rt2*rt2_re; di2 = ( 0.5*cf2t*us2 ) * 2.0/hs2; di2_hs2 = -( 0.5*cf2t*us2 ) * 2.0/hs2/hs2; di2_us2 = ( 0.5*cf2t ) * 2.0/hs2; di2_cf2t = ( 0.5 *us2 ) * 2.0/hs2; di2_s2 = 0.0; di2_u2 = di2_hs2*hs2_u2 + di2_us2*us2_u2 + di2_cf2t*cf2t_u2; di2_t2 = di2_hs2*hs2_t2 + di2_us2*us2_t2 + di2_cf2t*cf2t_t2; di2_d2 = di2_hs2*hs2_d2 + di2_us2*us2_d2 + di2_cf2t*cf2t_d2; di2_ms = di2_hs2*hs2_ms + di2_us2*us2_ms + di2_cf2t*cf2t_ms; di2_re = di2_hs2*hs2_re + di2_us2*us2_re + di2_cf2t*cf2t_re; //----- set minimum hk for wake layer to still exist grt = log(rt2); hmin = 1.0 + 2.1/grt; hm_rt2 = -(2.1/grt/grt) / rt2; //----- set factor dfac for correcting wall dissipation for very low hk fl = (hk2-1.0)/(hmin-1.0); fl_hk2 = 1.0/(hmin-1.0); fl_rt2 = ( -fl/(hmin-1.0) ) * hm_rt2; tfl = tanh(fl); dfac = 0.5 + 0.5* tfl; df_fl = 0.5*(1.0 - tfl*tfl); df_hk2 = df_fl*fl_hk2; df_rt2 = df_fl*fl_rt2; di2_s2 = di2_s2*dfac; di2_u2 = di2_u2*dfac + di2*(df_hk2*hk2_u2 + df_rt2*rt2_u2); di2_t2 = di2_t2*dfac + di2*(df_hk2*hk2_t2 + df_rt2*rt2_t2); di2_d2 = di2_d2*dfac + di2*(df_hk2*hk2_d2 ); di2_ms = di2_ms*dfac + di2*(df_hk2*hk2_ms + df_rt2*rt2_ms); di2_re = di2_re*dfac + di2*( df_rt2*rt2_re); di2 = di2 *dfac; } else { //----- zero wall contribution for wake di2 = 0.0; di2_s2 = 0.0; di2_u2 = 0.0; di2_t2 = 0.0; di2_d2 = 0.0; di2_ms = 0.0; di2_re = 0.0; } } //---- add on turbulent outer layer contribution if(ityp!=1) { dd = s2*s2 * (0.995-us2) * 2.0/hs2; dd_hs2 = -s2*s2 * (0.995-us2) * 2.0/hs2/hs2; dd_us2 = -s2*s2 * 2.0/hs2; dd_s2 = s2*2.0* (0.995-us2) * 2.0/hs2; di2 = di2 + dd; di2_s2 = dd_s2; di2_u2 = di2_u2 + dd_hs2*hs2_u2 + dd_us2*us2_u2; di2_t2 = di2_t2 + dd_hs2*hs2_t2 + dd_us2*us2_t2; di2_d2 = di2_d2 + dd_hs2*hs2_d2 + dd_us2*us2_d2; di2_ms = di2_ms + dd_hs2*hs2_ms + dd_us2*us2_ms; di2_re = di2_re + dd_hs2*hs2_re + dd_us2*us2_re; //----- add laminar stress contribution to outer layer cd dd = 0.15*(0.995-us2)*(0.995-us2) / rt2 * 2.0/hs2; dd_us2 = -0.15*(0.995-us2)*2.0 / rt2 * 2.0/hs2; dd_hs2 = -dd/hs2; dd_rt2 = -dd/rt2; di2 = di2 + dd; di2_u2 = di2_u2 + dd_hs2*hs2_u2 + dd_us2*us2_u2 + dd_rt2*rt2_u2; di2_t2 = di2_t2 + dd_hs2*hs2_t2 + dd_us2*us2_t2 + dd_rt2*rt2_t2; di2_d2 = di2_d2 + dd_hs2*hs2_d2 + dd_us2*us2_d2; di2_ms = di2_ms + dd_hs2*hs2_ms + dd_us2*us2_ms + dd_rt2*rt2_ms; di2_re = di2_re + dd_hs2*hs2_re + dd_us2*us2_re + dd_rt2*rt2_re; } if(ityp==2) { dil( hk2, rt2, di2l, di2l_hk2, di2l_rt2 ); if(di2l>di2) { //------- laminar cd is greater than turbulent cd -- use laminar //- (this will only occur for unreasonably small rtheta) di2 = di2l; di2_s2 = 0.0; di2_u2 = di2l_hk2*hk2_u2 + di2l_rt2*rt2_u2; di2_t2 = di2l_hk2*hk2_t2 + di2l_rt2*rt2_t2; di2_d2 = di2l_hk2*hk2_d2; di2_ms = di2l_hk2*hk2_ms + di2l_rt2*rt2_ms; di2_re = di2l_rt2*rt2_re; } } if(ityp==3) { //------ laminar wake cd dilw( hk2, rt2, di2l, di2l_hk2, di2l_rt2 ); if(di2l > di2) { //------- laminar wake cd is greater than turbulent cd -- use laminar //- (this will only occur for unreasonably small rtheta) di2 = di2l; di2_s2 = 0.0; di2_u2 = di2l_hk2*hk2_u2 + di2l_rt2*rt2_u2; di2_t2 = di2l_hk2*hk2_t2 + di2l_rt2*rt2_t2; di2_d2 = di2l_hk2*hk2_d2; di2_ms = di2l_hk2*hk2_ms + di2l_rt2*rt2_ms; di2_re = di2l_rt2*rt2_re; } } if(ityp==3) { //----- double dissipation for the wake (two wake halves) di2 = di2 *2.0; di2_s2 = di2_s2*2.0; di2_u2 = di2_u2*2.0; di2_t2 = di2_t2*2.0; di2_d2 = di2_d2*2.0; di2_ms = di2_ms*2.0; di2_re = di2_re*2.0; } //---- bl thickness (delta) from simplified green's correlation de2 = (3.15 + 1.72/(hk2-1.0) )*t2 + d2; de2_hk2 = ( - 1.72/(hk2-1.0)/(hk2-1.0))*t2; de2_u2 = de2_hk2*hk2_u2; de2_t2 = de2_hk2*hk2_t2 + (3.15 + 1.72/(hk2-1.0)); de2_d2 = de2_hk2*hk2_d2 + 1.0; de2_ms = de2_hk2*hk2_ms; hdmax = 12.0; if(de2 > hdmax*t2) { de2 = hdmax*t2; de2_u2 = 0.0; de2_t2 = hdmax; de2_d2 = 0.0; de2_ms = 0.0; } return true; } bool XFoil::cang(double x[], double y[], int n, int &imax, double &amax) { //------------------------------------------------------------------- double dx1, dx2, dy1, dy2, crossp, angl; amax = 0.0; imax = 1; //---- go over each point, calculating corner angle for (int i=2; i<= n-1; i++){ dx1 = x[i] - x[i-1]; dy1 = y[i] - y[i-1]; dx2 = x[i] - x[i+1]; dy2 = y[i] - y[i+1]; //------ allow for doubled points if(dx1==0.0 && dy1==0.0) { dx1 = x[i] - x[i-2]; dy1 = y[i] - y[i-2]; } if(dx2==0.0 && dy2==0.0) { dx2 = x[i] - x[i+2]; dy2 = y[i] - y[i+2]; } crossp = (dx2*dy1 - dy2*dx1) / sqrt((dx1*dx1 + dy1*dy1) * (dx2*dx2 + dy2*dy2)); angl = asin(crossp)*(180.0/PI); if(qAbs(angl) > qAbs(amax)) { amax = angl; imax = i; } } return true; } bool XFoil::cdcalc() { double thwake, urat, uewake, shwake, dx; int i,im,is,ibl; double sa, ca; sa = sin(alfa); ca = cos(alfa); if(lvisc && lblini) { //---- set variables at the end of the wake thwake = thet[nbl[2]][2]; urat = uedg[nbl[2]][2]/qinf; uewake = uedg[nbl[2]][2] * (1.0-tklam) / (1.0 - tklam*urat*urat); shwake = dstr[nbl[2]][2]/thet[nbl[2]][2]; //---- extrapolate wake to downstream infinity using squire-young relation // (reduces errors of the wake not being long enough) cd = 2.0*thwake * pow((uewake/qinf),(0.5*(5.0+shwake))); } else { cd = 0.0; } //--- calculate friction drag coefficient cdf = 0.0; for (is=1; is<=2;is++) { for(ibl=3;ibl<= iblte[is]; ibl++) { i = ipan[ibl][is]; im = ipan[ibl-1][is]; dx = (x[i] - x[im])*ca + (y[i] - y[im])*sa; cdf = cdf + 0.5*(tau[ibl][is]+tau[ibl-1][is])*dx * 2.0/qinf/qinf; } } return true; } bool XFoil::cfl(double hk, double rt, double &cf, double &cf_hk, double &cf_rt, double &cf_msq) { //---- laminar skin friction function ( cf ) ( from falkner-skan ) double tmp; if(hk<5.5) { tmp = (5.5-hk)*(5.5-hk)*(5.5-hk) / (hk+1.0); cf = ( 0.0727*tmp - 0.07 )/rt; cf_hk = ( -.0727*tmp*3.0/(5.5-hk) - 0.0727*tmp/(hk+1.0))/rt; } else { tmp = 1.0 - 1.0/(hk-4.5); cf = ( 0.015*tmp*tmp - 0.07 ) / rt; cf_hk = ( 0.015*tmp*2.0/(hk-4.5)/(hk-4.5) ) / rt; } cf_rt = -cf/rt; cf_msq = 0.0; return true; } bool XFoil::cft(double hk, double rt, double msq, double &cf, double &cf_hk, double &cf_rt, double &cf_msq) { double gam, gm1, f_arg, fc, grt, gex, thk, cfo; gam =1.4; //---- turbulent skin friction function ( cf ) (coles) gm1 = gam - 1.0; fc = sqrt(1.0 + 0.5*gm1*msq); grt = log(rt/fc); grt = qMax(grt,3.0); gex = -1.74 - 0.31*hk; f_arg = -1.33*hk; f_arg = qMax(-20.0, f_arg ); thk = tanh(4.0 - hk/0.875); cfo = 0.3*exp(f_arg) * pow((grt/2.3026),gex); cf = ( cfo + 0.00011*(thk-1.0) ) / fc; cf_hk = (-1.33*cfo - 0.31*log(grt/2.3026)*cfo - 0.00011*(1.0-thk*thk) / 0.875 ) / fc; cf_rt = gex*cfo/(fc*grt) / rt; cf_msq = gex*cfo/(fc*grt) * (-0.25*gm1/fc/fc) - 0.25*gm1*(cf)/fc/fc; return true; } bool XFoil::clcalc(double xref, double yref) { // modified arcds : all other variables are member variables (ex fortran common) //----------------------------------------------------------- // integrates surface pressures to get cl and cm. // integrates skin friction to get cdf. // calculates dcl/dalpha for prescribed-cl routines. //----------------------------------------------------------- //arcds addition : calculate XCp position //---- moment-reference coordinates ////ccc xref = 0.25 ////ccc yref = 0. double beta, beta_msq, bfac, bfac_msq, cginc; double cpi_gam, cpc_cpi; double dx, dy, dg, ax, ay, ag, dx_alf, ag_alf, ag_msq; double cpg1, cpg1_msq, cpg1_alf, cpg2, cpg2_msq, cpg2_alf; double sa, ca; sa = sin(alfa); ca = cos(alfa); xcp = 0.0; beta = sqrt(1.0 - minf*minf); beta_msq = -0.5/beta; bfac = 0.5*minf*minf / (1.0 + beta); bfac_msq = 0.5/ (1.0 + beta)- bfac/ (1.0 + beta) * beta_msq; cl = 0.0; cm = 0.0; cdp = 0.0; cl_alf = 0.0; cl_msq = 0.0; int i = 1; cginc = 1.0 - (gam[i]/qinf)*(gam[i]/qinf); cpg1 = cginc/(beta + bfac*cginc); cpg1_msq = -cpg1/(beta + bfac*cginc)*(beta_msq + bfac_msq*cginc); cpi_gam = -2.0*gam[i]/qinf/qinf; cpc_cpi = (1.0 - bfac*cpg1)/ (beta + bfac*cginc); cpg1_alf = cpc_cpi*cpi_gam*gam_a[i]; for (i=1; i<= n;i++) { int ip = i+1; if(i==n) ip = 1; cginc = 1.0 - (gam[ip]/qinf)*(gam[ip]/qinf); cpg2 = cginc/(beta + bfac*cginc); cpg2_msq = -cpg2/(beta + bfac*cginc)*(beta_msq + bfac_msq*cginc); cpi_gam = -2.0*gam[ip]/qinf/qinf; cpc_cpi = (1.0 - bfac*cpg2)/ (beta + bfac*cginc); cpg2_alf = cpc_cpi*cpi_gam*gam_a[ip]; dx = (x[ip] - x[i])*ca + (y[ip] - y[i])*sa; dy = (y[ip] - y[i])*ca - (x[ip] - x[i])*sa; dg = cpg2 - cpg1; ax = (0.5*(x[ip]+x[i])-xref)*ca + (0.5*(y[ip]+y[i])-yref)*sa; ay = (0.5*(y[ip]+y[i])-yref)*ca - (0.5*(x[ip]+x[i])-xref)*sa; ag = 0.5*(cpg2 + cpg1); dx_alf = -(x[ip] - x[i])*sa + (y[ip] - y[i])*ca; ag_alf = 0.5*(cpg2_alf + cpg1_alf); ag_msq = 0.5*(cpg2_msq + cpg1_msq); cl = cl + dx* ag; cdp = cdp - dy* ag; cm = cm - dx*(ag*ax + dg*dx/12.0) - dy*(ag*ay + dg*dy/12.0); xcp += dx*ag*(x[ip]+x[i])/2.0; cl_alf = cl_alf + dx*ag_alf + ag*dx_alf; cl_msq = cl_msq + dx*ag_msq; cpg1 = cpg2; cpg1_alf = cpg2_alf; cpg1_msq = cpg2_msq; } if(qAbs(cl)>0.0) xcp/= cl; else xcp = 0.0; return true; } bool XFoil::comset() { //---- set karman-tsien parameter tklam double beta, beta_msq; beta = sqrt(1.0 - minf*minf); beta_msq = -0.5/beta; tklam = minf*minf / (1.0 + beta)/ (1.0 + beta); tkl_msq = 1.0 / (1.0 + beta)/ (1.0 + beta) - 2.0*tklam/ (1.0 + beta) * beta_msq; //---- set sonic pressure coefficient and speed if(minf==0.0) { cpstar = -999.0; qstar = 999.0; } else{ cpstar = 2.0 / (gamma*minf*minf) * (pow(((1.0 + 0.5*gamm1*minf*minf)/(1.0 + 0.5*gamm1)),(gamma/gamm1)) - 1.0 ); qstar = qinf/minf * sqrt( (1.0 + 0.5*gamm1*minf*minf) /(1.0 + 0.5*gamm1 ) ); } return true; } bool XFoil::cpcalc(int n, double q[], double qinf, double minf, double cp[]) { //--------------------------------------------- // sets compressible cp from speed. //--------------------------------------------- int i; bool denneg; double cpinc, den, beta, bfac; beta = sqrt(1.0 - minf*minf); bfac = 0.5*minf*minf / (1.0 + beta); denneg = false; for (i=1; i<= n; i++) { cpinc = 1.0 - (q[i]/qinf)*(q[i]/qinf); den = beta + bfac*cpinc; cp[i] = cpinc / den; if(den <= 0.0) denneg = true; } if(denneg) { QString str(QObject::tr("CpCalc: local speed too larger\n Compressibility corrections invalid")+"\n"); QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QXDirect::tr("Warning")); msgBox.setText(str); msgBox.exec(); WriteString(str, true); return false; } return true; } void XFoil::WriteString(QString str, bool bFullReport) { if(!bFullReport && !m_bFullReport) return; if(!pXFile) return; if(!pXFile->isOpen()) return; QTextStream ds(pXFile); ds << str; } double XFoil::curv(double ss, double x[], double xs[], double y[], double ys[], double s[], int n){ //----------------------------------------------- // calculates curvature of splined 2-d curve | // at s = ss | // | // s arc length array of curve | // x, y coordinate arrays of curve | // xs,ys derivative arrays | // (calculated earlier by spline) | //----------------------------------------------- int ilow, i, imid; double crv,ds, t, cx1, cx2, xd, xdd, cy1, cy2, yd, ydd, sd; ilow = 1; i = n; stop10: if(i-ilow<=1) goto stop11; imid = (i+ilow)/2; if(ss < s[imid]) i = imid; else ilow = imid; goto stop10; stop11: ds = s[i] - s[i-1]; t = (ss - s[i-1]) / ds; cx1 = ds*xs[i-1] - x[i] + x[i-1]; cx2 = ds*xs[i] - x[i] + x[i-1]; xd = x[i] - x[i-1] + (1.0-4.0*t+3.0*t*t)*cx1 + t*(3.0*t-2.0)*cx2; xdd = (6.0*t-4.0)*cx1 + (6.0*t-2.0)*cx2; cy1 = ds*ys[i-1] - y[i] + y[i-1]; cy2 = ds*ys[i] - y[i] + y[i-1]; yd = y[i] - y[i-1] + (1.0-4.0*t+3.0*t*t)*cy1 + t*(3.0*t-2.0)*cy2; ydd = (6.0*t-4.0)*cy1 + (6.0*t-2.0)*cy2; sd = sqrt(xd*xd + yd*yd); sd = qMax(sd,0.001*ds); crv = (xd*ydd - yd*xdd) / sd/ sd/ sd; return crv; } double XFoil::d2val(double ss, double x[], double xs[], double s[], int n){ //-------------------------------------------------- // calculates d2x/ds2(ss) | // xs array must have been calculated by spline | //-------------------------------------------------- int i, imid, ilow; double ds, t, cx1, cx2, dtwoval; ilow = 1; i = n; stop10: if(i-ilow<=1) goto stop11; imid = (i+ilow)/2; if(ss < s[imid]) i = imid; else ilow = imid; goto stop10; stop11: ds = s[i] - s[i-1]; t = (ss - s[i-1]) / ds; cx1 = ds*xs[i-1] - x[i] + x[i-1]; cx2 = ds*xs[i] - x[i] + x[i-1]; dtwoval = (6.0*t-4.0)*cx1 + (6.0*t-2.0)*cx2; dtwoval = dtwoval/ds/ds; return dtwoval; } bool XFoil::dampl(double hk, double th, double rt, double &ax, double &ax_hk, double &ax_th, double &ax_rt) { //============================================================== // amplification rate routine for envelope e^n method. // reference: // drela, m., giles, m., // "viscous/inviscid analysis of transonic and // low reynolds number airfoils", // aiaa journal, oct. 1987. // // new version. march 1991 (latest bug fix july 93) // - m(h) correlation made more accurate up to h=20 // - for h > 5, non-similar profiles are used // instead of falkner-skan profiles. these // non-similar profiles have smaller reverse // velocities, are more representative of typical // separation bubble profiles. //-------------------------------------------------------------- // // input : hk kinematic shape parameter // th momentum thickness // rt momentum-thickness reynolds number // // output: ax envelope spatial amplification rate // ax_(.) sensitivity of ax to parameter (.) // // // usage: the log of the envelope amplitude n(x) is // calculated by integrating ax (= dn/dx) with // respect to the streamwise distance x. // x // / // n(x) = | ax(h(x),th(x),rth(x)) dx // / // 0 // the integration can be started from the leading // edge since ax will be returned as zero when rt // is below the critical rtheta. transition occurs // when n(x) reaches ncrit (ncrit= 9 is "standard"). //============================================================== // implicit real (a-h,m,o-z) double dgr = 0.08; double hmi, hmi_hk,aa, aa_hk, bb, bb_hk, grcrit, grc_hk, gr, gr_rt; double rnorm, rn_hk, rn_rt, rfac, rfac_hk, rfac_rt; double rfac_rn, arg_hk,ex, f_arg, ex_hk; double af, af_hmi, af_hk, dadr, dadr_hk; hmi = 1.0/(hk - 1.0); hmi_hk = -hmi*hmi; //---- log10(critical rth) - h correlation for falkner-skan profiles aa = 2.492*pow(hmi,0.43); aa_hk = (aa/hmi)*0.43 * hmi_hk; bb = tanh(14.0*hmi - 9.24); bb_hk = (1.0 - bb*bb) * 14.0 * hmi_hk; grcrit = aa + 0.7*(bb + 1.0); grc_hk = aa_hk + 0.7* bb_hk; gr = log10(rt); gr_rt = 1.0 / (2.3025851*rt); if(gr < grcrit-dgr) { //----- no amplification for rtheta < rcrit ax = 0.0; ax_hk = 0.0; ax_th = 0.0; ax_rt = 0.0; } else { //----- set steep cubic ramp used to turn on ax smoothly as rtheta //- exceeds rcrit (previously, this was done discontinuously). //- the ramp goes between -dgr < log10(rtheta/rcrit) < dgr rnorm = (gr - (grcrit-dgr)) / (2.0*dgr); rn_hk = - grc_hk / (2.0*dgr); rn_rt = gr_rt / (2.0*dgr); if(rnorm >= 1.0) { rfac = 1.0; rfac_hk = 0.0; rfac_rt = 0.0; } else{ rfac = 3.0*rnorm*rnorm - 2.0*rnorm*rnorm*rnorm; rfac_rn = 6.0*rnorm - 6.0*rnorm*rnorm; rfac_hk = rfac_rn*rn_hk; rfac_rt = rfac_rn*rn_rt; } //----- amplification envelope slope correlation for falkner-skan f_arg = 3.87*hmi - 2.52; arg_hk = 3.87*hmi_hk; ex = exp(-f_arg*f_arg); ex_hk = ex * (-2.0*f_arg*arg_hk); dadr = 0.028*(hk-1.0) - 0.0345*ex; dadr_hk = 0.028 - 0.0345*ex_hk; //----- new m(h) correlation 1 march 91 af = -0.05 + 2.7*hmi - 5.5*hmi*hmi + 3.0*hmi*hmi*hmi; af_hmi = 2.7 - 11.0*hmi + 9.0*hmi*hmi; af_hk = af_hmi*hmi_hk; ax = (af *dadr/th ) * rfac; ax_hk = (af_hk*dadr/th + af*dadr_hk/th) * rfac + (af *dadr/th ) * rfac_hk; ax_th = -(ax)/th; ax_rt = (af *dadr/th ) * rfac_rt; } return true; } double XFoil::deval(double ss, double x[], double xs[], double s[], int n) { //-------------------------------------------------- // calculates dx/ds(ss) | // xs array must have been calculated by spline | //-------------------------------------------------- int ilow, i, imid; double ds, t, cx1, cx2, deval; ilow = 1; // i = nc; i = n; ///arcds modified while(i-ilow>1) { imid = (i+ilow)/2; if(ss < s[imid]) i = imid; else ilow = imid; } ds = s[i] - s[i-1]; t = (ss - s[i-1]) / ds; cx1 = ds*xs[i-1] - x[i] + x[i-1]; cx2 = ds*xs[i] - x[i] + x[i-1]; deval = x[i] - x[i-1] + (1.0-4.0*t+3.0*t*t)*cx1 + t*(3.0*t-2.0)*cx2; deval = deval/ds; return deval; } bool XFoil::dil(double hk, double rt, double &di, double &di_hk, double &di_rt) { //---- laminar dissipation function ( 2 cd/h* ) (from falkner-skan) if(hk<4.0) { di = ( 0.00205 * pow((4.0-hk),5.5) + 0.207 ) / rt; di_hk = ( -.00205*5.5*pow((4.0-hk),4.5) ) / rt; } else { double hkb = hk - 4.0; double den = 1.0 + 0.02*hkb*hkb; di = ( -.0016 * hkb*hkb /den + 0.207 ) / rt; di_hk = ( -.0016*2.0*hkb*(1.0/den - 0.02*hkb*hkb/den/den) ) / rt; } di_rt = -(di)/rt; return true; } bool XFoil::dilw(double hk, double rt, double &di, double &di_hk, double &di_rt) { // double msq = 0.0; double hs, hs_hk, hs_rt, hs_msq; hsl(hk, hs, hs_hk, hs_rt, hs_msq); //---- laminar wake dissipation function ( 2 cd/h* ) double rcd = 1.10 * (1.0 - 1.0/hk)* (1.0 - 1.0/hk) / hk; double rcd_hk = -1.10 * (1.0 - 1.0/hk)*2.0/hk/hk/hk- rcd/hk; di = 2.0*rcd /(hs*rt); di_hk = 2.0*rcd_hk/(hs*rt) - ((di)/hs)*hs_hk; di_rt = -(di)/rt - ((di)/hs)*hs_rt; return true; } bool XFoil::dslim(double &dstr, double thet, double msq, double hklim) { double h, hk, hk_h, hk_m, dh; h = (dstr)/thet; hkin(h, msq, hk, hk_h, hk_m); dh = qMax(0.0 , hklim-hk ) / hk_h; dstr = (dstr) + dh*thet; return true; } bool XFoil::fcpmin() { //------------------------------------------------ // finds minimum cp on dist for cavitation work //------------------------------------------------ int i; xcpmni = x[1]; xcpmnv = x[1]; cpmni = cpi[1]; cpmnv = cpv[1]; for (i = 2; i<= n + nw; i++) { if(cpi[i] < cpmni) { xcpmni = x[i]; cpmni = cpi[i]; } if(cpv[i] < cpmnv) { xcpmnv = x[i]; cpmnv = cpv[i]; } } if (lvisc) cpmn = cpmnv; else { cpmn = cpmni; cpmnv = cpmni; xcpmnv = xcpmni; } return true; } bool XFoil::gamqv() { int i; for (i=1; i<= n; i++) { gam[i] = qvis[i]; gam_a[i] = qinv_a[i]; } return true; } bool XFoil::Gauss(int nn, double z[][6], double r[5]){ /******************************************************* * * * solves general nxn system in nn unknowns * * with arbitrary number (nrhs) of righthand sides. * * assumes system is invertible... * * ...if it isn't, a divide by zero will result. * * * * z is the coefficient matrix... * * ...destroyed during solution process. * * r is the righthand side(s)... * * ...replaced by the solution vector(s). * * * * mark drela 1984 * *******************************************************/ // arcds : only one rhs is enough ! nrhs = 1 // dimension z(nsiz,nsiz), r(nsiz,nrhs) int loc; int np, nnpp, nt, nx, k; double temp, ztmp, pivot; for (np=1; np<=nn-1; np++){ nnpp = np+1; //------ find max pivot index nx nx = np; for (nt =nnpp; nt<=nn; nt++){ if (qAbs(z[nt][np])>qAbs(z[nx][np])) nx = nt; } pivot = 1.0/z[nx][np]; //------ switch pivots z[nx][np] = z[np][np]; //------ switch rows & normalize pivot row for (loc = nnpp; loc<=nn; loc++){ temp = z[nx][loc]*pivot; z[nx][loc] = z[np][loc]; z[np][loc] = temp; } temp = r[nx]*pivot; r[nx] = r[np]; r[np] = temp; //------ forward eliminate everything for (k = nnpp; k<=nn; k++){ ztmp = z[k][np]; for (loc=nnpp; loc<=nn;loc++) z[k][loc] = z[k][loc] - ztmp*z[np][loc]; r[k] = r[k] - ztmp*r[np]; } } //---- solve for last row r[nn] = r[nn]/z[nn][nn]; //---- back substitute everything for (np=nn-1; np>= 1; np--){ nnpp = np+1; for(k=nnpp; k<= nn;k++) r[np] = r[np] - z[np][k]*r[k]; } return true; } bool XFoil::Gauss(int nn, double z[IQX][IQX], double r[IQX]){ /******************************************************* * * * solves general nxn system in nn unknowns * * with arbitrary number (nrhs) of righthand sides. * * assumes system is invertible... * * ...if it isn't, a divide by zero will result. * * * * z is the coefficient matrix... * * ...destroyed during solution process. * * r is the righthand side(s)... * * ...replaced by the solution vector(s). * * * * mark drela 1984 * *******************************************************/ // arcds : only one rhs is enough ! nrhs = 1 // dimension z(nsiz,nsiz), r(nsiz,nrhs) int loc; int np, nnpp, nt, nx, k; double temp, ztmp, pivot; for (np=1; np<=nn-1; np++) { nnpp = np+1; //------ find max pivot index nx nx = np; for (nt =nnpp; nt<=nn; nt++) { if (qAbs(z[nt][np])>qAbs(z[nx][np])) nx = nt; } pivot = 1.0/z[nx][np]; //------ switch pivots z[nx][np] = z[np][np]; //------ switch rows & normalize pivot row for (loc = nnpp; loc<=nn; loc++){ temp = z[nx][loc]*pivot; z[nx][loc] = z[np][loc]; z[np][loc] = temp; } temp = r[nx]*pivot; r[nx] = r[np]; r[np] = temp; //------ forward eliminate everything for (k = nnpp; k<=nn; k++){ ztmp = z[k][np]; for (loc=nnpp; loc<=nn;loc++) z[k][loc] = z[k][loc] - ztmp*z[np][loc]; r[k] = r[k] - ztmp*r[np]; } } //---- solve for last row r[nn] = r[nn]/z[nn][nn]; //---- back substitute everything for (np=nn-1; np>= 1; np--){ nnpp = np+1; for(k=nnpp; k<= nn;k++) r[np] = r[np] - z[np][k]*r[k]; } return true; } bool XFoil::geopar(double x[], double xp[], double y[], double yp[], double s[], int n, double t[], double &sle, double &chord, double &area, double &radle, double &angte, double &ei11a, double &ei22a, double &apx1a, double &apx2a, double &ei11t, double &ei22t, double &apx1t, double &apx2t) { int i; double chsq, curvle, ang1, ang2, xcena, ycena, slen, xcent, ycent; double thick, xthick, cambr, xcambr; double xcam[IQX], ycam[IQX], xthk[IQX], ythk[IQX], ycamp[IQX], ythkp[IQX]; int ncam, nthk; //------------------------------------------------------ // sets geometric parameters for airfoil shape //------------------------------------------------------ lefind(sle,x,xp,y,yp,s,n); xle = seval(sle,x,xp,s,n); yle = seval(sle,y,yp,s,n); xte = 0.5*(x[1]+x[n]); yte = 0.5*(y[1]+y[n]); chsq = (xte-xle)*(xte-xle) + (yte-yle)*(yte-yle); chord = sqrt(chsq); curvle = curv(sle,x,xp,y,yp,s,n); radle = 0.0; if(qAbs(curvle) > 0.001*(s[n]-s[1])) radle = 1.0 / curvle; ang1 = atan2( -yp[1] , -xp[1] ); ang2 = atanc( yp[n] , xp[n] , ang1 ); angte = ang2 - ang1; for (i=1; i<= n; i++) t[i] = 1.0; aecalc(n,x,y,t, 1, area,xcena,ycena,ei11a,ei22a,apx1a,apx2a); aecalc(n,x,y,t, 2, slen,xcent,ycent,ei11t,ei22t,apx1t,apx2t); //--- old, approximate thickness,camber routine (on discrete points only) // tccalc(x,xp,y,yp,s,n, &thick, &xthick, &cambr, &xcambr ); //--- more accurate thickness and camber estimates getcam(xcam,ycam,ncam,xthk,ythk,nthk,x,xp,y,yp,s,n ); getmax(xcam,ycam,ycamp,ncam,xcambr,cambr); getmax(xthk,ythk,ythkp,nthk,xthick,thick); thick = 2.0*thick; thickb = thick; cambrb = cambr; // write(*,1000) thick,xthick,cambr,xcambr // 1000 format( ' max thickness = ',f12.6,' at x = ',f7.3,/' max camber = ',f12.6,' at x = ',f7.3) return true; } void XFoil::getcam(double xcm[],double ycm[], int &ncm,double xtk[],double ytk[],int &ntk, double x[],double xp[],double y[],double yp[],double s[],int n ){ //------------------------------------------------------ // finds camber and thickness // distribution for input airfoil //------------------------------------------------------ double sl, xl, yl, sopp, xopp,yopp, tol; int i; xlfind(sl,x,xp,y,yp,s,n); xl = seval(sl,x,xp,s,n); yl = seval(sl,y,yp,s,n); //---- go over each point, finding opposite points, getting camber and thickness for (i=1; i<= n; i++) { //------ coordinates of point on the opposite side with the same x value sopps(sopp, s[i], x,xp,y,yp,s,n,sl); xopp = seval(sopp,x,xp,s,n); yopp = seval(sopp,y,yp,s,n); //------ get camber and thickness xcm[i] = 0.5*(x[i]+xopp); ycm[i] = 0.5*(y[i]+yopp); xtk[i] = 0.5*(x[i]+xopp); ytk[i] = 0.5*(y[i]-yopp); ytk[i] = qAbs(ytk[i]); // if (xopp.gt.0.9) then // write(*,*) 'cm i,x,y ',i,xcm(i),ycm(i) // write(*,*) 'tk i,x,y ',i,xtk(i),ytk(i) // endif } //---- tolerance for nominally identical points tol = 0.001 * (s[n]-s[1]); //---- sort the camber points ncm = n+1; xcm[n+1] = xl; ycm[n+1] = yl; sortol(tol,ncm,xcm,ycm); //--- reorigin camber from le so camberlines start at y=0 4/24/01 hhy // policy now to generate camber independent of y-offsets yof = ycm[1]; for (i=1; i<= ncm; i++) { ycm[i] -= yof; } //---- sort the thickness points ntk = n+1; xtk[n+1] = xl; ytk[n+1] = 0.0; sortol(tol,ntk,xtk,ytk); } void XFoil::getmax(double x[],double y[], double yp[], int n,double &xmax, double &ymax) { // real x(*), y(*), yp(*) //------------------------------------------------ // calculates camber or thickness highpoint // and x position //------------------------------------------------ double xlen, xtol; double xmax0, ymax0, ddx, res, resp, dx; int i, iter; ddx = 0.0; xlen = x[n] - x[1]; xtol = xlen * 0.00001; segspl(y,yp,x,n); //---- get approx max point and rough interval size ymax0 = y[1]; xmax0 = x[1]; for (i = 2; i<= n; i++) { if (qAbs(y[i])>qAbs(ymax0)) { ymax0 = y[i]; xmax0 = 0.5*(x[i-1] + x[i]); ddx = 0.5*qAbs(x[i+1] - x[i-1]); } } xmax = xmax0; //---- do a newton loop to refine estimate bool bConv =false; for (iter=1; iter<= 10; iter++) { ymax = seval(xmax,y,yp,x,n); res = deval(xmax,y,yp,x,n); resp = d2val(xmax,y,yp,x,n); if (qAbs(xlen*resp) < 1.0e-6) { bConv = true; break;//go to 20 } dx = -res/resp; dx = sign( min(0.5*ddx,qAbs(dx)), dx); xmax += dx; if(qAbs(dx) < xtol) { bConv = true; break;//go to 20 } } // write(*,*) 'getmax: newton iteration for max camber/thickness failed.' if(!bConv) { ymax = ymax0; xmax = xmax0; } } void XFoil::xlfind(double &sle, double x[], double xp[], double y[], double yp[], double s[], int n) { // dimension x(*),xp(*),y(*),yp(*),s(*) //------------------------------------------------------ // locates leftmost (minimum x) point location sle // // the defining condition is // // x' = 0 at s = sle // // i.e. the surface tangent is vertical //------------------------------------------------------ double dslen, dseps, dx, dxds, dxdd, dsle, res, ress; int i, iter; dslen = s[n] - s[1]; //---- convergence tolerance dseps = (s[n]-s[1]) * 0.00001; //---- get first guess for sle for (i=3; i<= n-2; i++) { dx = x[i+1] - x[i]; if(dx > 0.0) break; } sle = s[i]; //---- check for sharp le case if(qAbs(s[i] - s[i-1])<1.e-06) {// changed arcds //ccc write(*,*) 'sharp le found at ',i,sle return; } //---- newton iteration to get exact sle value for (iter=1 ;iter<= 50; iter++) { dxds = deval(sle,x,xp,s,n); dxdd = d2val(sle,x,xp,s,n); //------ drive dxds to zero res = dxds; ress = dxdd; //------ newton delta for sle dsle = -res/ress; dsle = max( dsle , -0.01*qAbs(dslen) ); dsle = min( dsle , 0.01*qAbs(dslen) ); sle += dsle; if(qAbs(dsle) < dseps) return; } // write(*,*) 'xlfind: left point not found. continuing...' sle = s[i]; } void XFoil::sortol(double tol,int &kk,double s[],double w[]) { // dimension s(kk), w(kk) bool done; int np, kks, ipass, k, kt; double temp, dsq; //---- sort arrays for (ipass=1; ipass<= 1234; ipass++) { done = true; for (int n=1; n<= kk-1; n++) { np = n+1; if(s[np]= 999.0) { // askr("enter flap hinge relative y/t location",yrel); // yrel = 0.5;//arcs added // } // flap y location in pyf is relative; yrel = yf; // so convert to absolute value yf = topy*yrel + boty*(1.0-yrel); return true; } bool XFoil::ggcalc() { //-------------------------------------------------------------- // calculates two surface vorticity (gamma) distributions // for alpha = 0, 90 degrees. these are superimposed // in specal or speccl for specified alpha or cl. //-------------------------------------------------------------- int i,j, iu; double psi, psi_n, psiinf, res, res1, res2, ag1, ag2; double abis, cbis, sbis, ds1, ds2, dsmin; double xbis, ybis, qbis, bwt; double bbb[IQX]; cosa = cos(alfa); sina = sin(alfa); //---- distance of internal control point ahead of sharp te //- (fraction of smaller panel length adjacent to te) bwt = 0.1; //TRACE("calculating unit vorticity distributions ...\n"); QString str(QObject::tr(" Calculating unit vorticity distributions ...\n")); WriteString(str); for(i=1; i<= n; i++) { gam[i] = 0.0; gamu[i][1] = 0.0; gamu[i][2] = 0.0; } psio = 0.0; //---- set up matrix system for psi = psio on airfoil surface. //- the unknowns are (dgamma)i and dpsio. for (i=1;i<= n;i++) { //------ calculate psi and dpsi/dgamma array for current node psilin(i,x[i],y[i],nx[i],ny[i],psi,psi_n,false,true); psiinf = qinf*(cosa*y[i] - sina*x[i]); //------ res1 = psi( 0) - psio //------ res2 = psi(90) - psio res1 = qinf*y[i]; res2 = -qinf*x[i]; //------ dres/dgamma for (j=1; j<= n; j++) { aij[i][j] = dzdg[j]; } for (j=1; j<= n; j++) { bij[i][j] = -dzdm[j]; } //------ dres/dpsio aij[i][n+1] = -1.0; gamu[i][1] = -res1; gamu[i][2] = -res2; } //---- set kutta condition //- res = gam(1) + gam[n] res = 0.0; for (j=1;j<= n+1;j++) aij[n+1][j] = 0.0; aij[n+1][1] = 1.0; aij[n+1][n] = 1.0; gamu[n+1][1] = -res; gamu[n+1][2] = -res; //---- set up kutta condition (no direct source influence) for (j=1;j<= n;j++) bij[n+1][j] = 0.0; if(sharp) { //----- set zero internal velocity in te corner //----- set te bisector angle ag1 = atan2(-yp[1],-xp[1] ); ag2 = atanc( yp[n], xp[n],ag1); abis = 0.5*(ag1+ag2); cbis = cos(abis); sbis = sin(abis); //----- minimum panel length adjacent to te ds1 = sqrt((x[1]-x[2] )*(x[1]-x[2] ) + (y[1]-y[2] )*(y[1]-y[2] )); ds2 = sqrt((x[n]-x[n-1])*(x[n]-x[n-1]) + (y[n]-y[n-1])*(y[n]-y[n-1])); dsmin = qMin( ds1 , ds2 ); //----- control point on bisector just ahead of te point xbis = xte - bwt*dsmin*cbis; ybis = yte - bwt*dsmin*sbis; //----- set velocity component along bisector line psilin(0,xbis,ybis,-sbis,cbis,psi,qbis,false,true); res = qbis; //----- dres/dgamma for (j=1; j<= n; j++) aij[n][j] = dqdg[j]; //----- -dres/dmass for (j=1; j<= n; j++) { bij[n][j] = -dqdm[j]; } //----- dres/dpsio aij[n][n+1] = 0.0; //----- -dres/duinf gamu[n][1] = -cbis; //----- -dres/dvinf gamu[n][2] = -sbis; } //---- lu-factor coefficient matrix aij ludcmp(n+1,aij,aijpiv); lqaij = true; //---- solve system for the two vorticity distributions for (iu=0; iu=1; i--){ sum = b[i]; if(i1.0) { QString str, strong; str = QObject::tr("Warning: High does not work well on rotated foils\n"); strong = QString(QObject::tr("Current chordline angle: %1\nproceeding anyway...")).arg(arot,5,'f',2); QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QObject::tr("Warning")); msgBox.setText(str+strong); msgBox.exec(); } //---- find leftmost point location xlfind(sbl,xb,xbp,yb,ybp,sb,nb); xbl = seval(sbl,xb,xbp,sb,nb); ybl = seval(sbl,yb,ybp,sb,nb); //---- find the current buffer airfoil camber and thickness getcam(xcm,ycm,ncm,xtk,ytk,ntk, xb,xbp,yb,ybp,sb,nb ); //---- find the max thickness and camber getmax(xcm,ycm,ycmp,ncm,cxmax,cymax); getmax(xtk,ytk,ytkp,ntk,txmax,tymax); //---- make a picture and get some input specs for mods // write(*,1010) 2.0*tymax,txmax, cymax,cxmax // 1010 format(/' max thickness = ',f8.4,' at x = ',f7.3, // & /' max camber = ',f8.4,' at x = ',f7.3/) /* if (ninput .ge. 2) then thpnt = rinput(1) chpnt = rinput(2) elseif(ninput .ge. 1) then thpnt = rinput(1) if(lgsym) then write(*,*) 'symmetry enforced: maintaining zero camber.' else chpnt = 0.0 call askr('enter new camber highpoint x: ^',chpnt) endif else thpnt = 0.0 call askr('enter new thickness highpoint x: ^',thpnt) if(lgsym) then write(*,*) 'symmetry enforced: maintaining zero camber.' else chpnt = 0.0 call askr('enter new camber highpoint x: ^',chpnt) endif endif if (thpnt<=0.0) thpnt = txmax; if (chpnt<=0.0) chpnt = cxmax;*/ // //--- a simple cubic mapping function is used to map x/c to move highpoints // // the assumption is that a smooth function (cubic, given by the old and // new highpoint locations) maps the range 0-1 for x/c // into the range 0-1 for altered x/c distribution for the same y/c // thickness or camber (ie. slide the points smoothly along the x axis) // //--- shift thickness highpoint if (thpnt > 0.0) { xfn[1] = xtk[1]; xfn[2] = txmax; xfn[3] = xtk[ntk]; yfn[1] = xtk[1]; yfn[2] = thpnt; yfn[3] = xtk[ntk]; splina(yfn,yfnp,xfn,3); for (int i = 1; i<= ntk; i++) xtk[i] = seval(xtk[i],yfn,yfnp,xfn,3); } //--- shift camber highpoint if (chpnt > 0.0) { xfn[1] = xcm[1]; xfn[2] = cxmax; xfn[3] = xcm[ncm]; yfn[1] = xcm[1]; yfn[2] = chpnt; yfn[3] = xcm[ncm]; splina(yfn,yfnp,xfn,3); for (int i = 1;i <= ncm; i++) xcm[i] = seval(xcm[i],yfn,yfnp,xfn,3); } //---- make new airfoil from thickness and camber // new airfoil points are spaced to match the original //--- hhy 4/24/01 got rid of splining vs x,y vs s (buggy), now spline y(x) segspl(ytk,ytkp,xtk,ntk); segspl(ycm,ycmp,xcm,ncm); //---- for each orig. airfoil point setup new yb from camber and thickness for (int i=1; i<= nb;i++){ //------ spline camber and thickness at original xb points ycc = seval(xb[i],ycm,ycmp,xcm,ncm); ytt = seval(xb[i],ytk,ytkp,xtk,ntk); //------ set new y coordinate from new camber & thickness if (sb[i] <= sbl) yb[i] = ycc + ytt; else yb[i] = ycc - ytt; //---- add y-offset for original leftmost (le) point to camber yb[i] = yb[i] + ybl; } scalc(xb,yb,sb,nb); segspl(xb,xbp,sb,nb); segspl(yb,ybp,sb,nb); geopar(xb,xbp,yb,ybp,sb,nb,w1,sble,chordb,areab, radble,angbte,ei11ba,ei22ba,apx1ba,apx2ba, ei11bt,ei22bt,apx1bt,apx2bt); } bool XFoil::hkin(double h, double msq, double &hk, double &hk_h, double &hk_msq){ //---- calculate kinematic shape parameter (assuming air) // (from Whitfield ) hk = (h - 0.29*msq) /(1.0 + 0.113*msq); hk_h = 1.0 /(1.0 + 0.113*msq); hk_msq = (-.29 - 0.113*(hk))/(1.0 + 0.113*msq); return true; } bool XFoil::hsl(double hk, double &hs, double &hs_hk, double &hs_rt, double &hs_msq) { //---- laminar hs correlation double tmp; if(hk<4.35) { tmp = hk - 4.35; hs = 0.0111*tmp*tmp/(hk+1.0) - 0.0278*tmp*tmp*tmp/(hk+1.0) + 1.528 - 0.0002*(tmp*hk)*(tmp*hk); hs_hk = 0.0111*(2.0*tmp - tmp*tmp/(hk+1.0))/(hk+1.0) - 0.0278*(3.0*tmp*tmp - tmp*tmp*tmp/(hk+1.0))/(hk+1.0) - 0.0002*2.0*tmp*hk * (tmp + hk); } else { hs = 0.015* (hk-4.35)*(hk-4.35)/hk + 1.528; hs_hk = 0.015*2.0*(hk-4.35) /hk - 0.015* (hk-4.35)* (hk-4.35)/hk/hk; } hs_rt = 0.0; hs_msq = 0.0; return true; } bool XFoil::hst(double hk, double rt, double msq, double &hs, double &hs_hk, double &hs_rt, double &hs_msq) { double hsmin, dhsinf, rtz, rtz_rt, ho, ho_rt, hr, hr_hk, hr_rt, fm; double grt, hdif, rtmp, htmp, htmp_hk, htmp_rt; //---- turbulent hs correlation hsmin = 1.5; dhsinf = 0.015; //---- ### 12/4/94 //---- limited rtheta dependence for rtheta < 200 if(rt>400.0) { ho = 3.0 + 400.0/rt; ho_rt = - 400.0/rt/rt; } else { ho = 4.0; ho_rt = 0.0; } if(rt>200.0) { rtz = rt; rtz_rt = 1.0; } else { rtz = 200.0; rtz_rt = 0.0; } if(hk panel location pointer array ipan //----------------------------------------------------------- int iblmax,is, ibl, i, iw; //-- top surface first is = 1; ibl = 1; for(i=ist; i>= 1;i--) { ibl = ibl+1; ipan[ibl][is] = i; vti[ibl][is] = 1.0; } iblte[is] = ibl; nbl[is] = ibl; //-- bottom surface next is = 2; ibl = 1; for(i=ist+1; i<=n; i++) { ibl = ibl+1; ipan[ibl][is] = i; vti[ibl][is] = -1.0; } //-- wake iblte[is] = ibl; for(iw=1; iw<=nw; iw++) { i = n+iw; ibl = iblte[is]+iw; ipan[ibl][is] = i; vti[ibl][is] = -1.0; } nbl[is] = iblte[is] + nw; //-- upper wake pointers (for plotting only) for(iw=1; iw<=nw; iw++){ ipan[iblte[1]+iw][1] = ipan[iblte[2]+iw][2]; vti[iblte[1]+iw][1] = 1.0; } iblmax = qMax(iblte[1],iblte[2]) + nw; if(iblmax>IVX) { QString str(QObject::tr("iblpan : *** bl array overflow")); WriteString(str, true); str = QString(QObject::tr("Increase IVX to at least %1\n")).arg(iblmax); WriteString(str, true); return false; } lipan = true; return true; } bool XFoil::iblsys() { //--------------------------------------------- // sets the bl newton system line number // corresponding to each bl station. //--------------------------------------------- int iv, is, ibl; iv = 0; for (is=1; is<=2;is++) { for (ibl=2; ibl<= nbl[is]; ibl++) { iv = iv+1; isys[ibl][is] = iv; } } nsys = iv; if(nsys>2*IVX) { QString str(QObject::tr("*** iblsys: bl system array overflow. ***")); WriteString(str, true); return false; } return true; } bool XFoil::Initialize() { pXFile = NULL; //--------------------------------------------------- // variable initialization/default routine. //--------------------------------------------------- int l; hopi = 0.50/PI; qopi = 0.25/PI; dtor = PI/180.0; n=0;// arcds : so that current airfoil is not initialized memset(aijpiv, 0, sizeof(aijpiv)); memset(apanel, 0, sizeof(apanel)); memset(blsav, 0, sizeof(blsav)); memset(aij, 0, sizeof(aij)); memset(bij, 0, sizeof(bij)); memset(cij, 0, sizeof(cij)); memset(cpi, 0, sizeof(cpi)); memset(cpv, 0, sizeof(cpv)); memset(ctau, 0, sizeof(ctau)); memset(ctq, 0, sizeof(ctq)); memset(dij, 0, sizeof(dij)); memset(dis, 0, sizeof(dis)); memset(dq, 0, sizeof(dq)); memset(dqdg, 0, sizeof(dqdg)); memset(dqdm, 0, sizeof(dqdm)); memset(delt, 0, sizeof(delt)); memset(dstr, 0, sizeof(dstr)); memset(dzdg, 0, sizeof(dzdg)); memset(dzdm, 0, sizeof(dzdm)); memset(dzdn, 0, sizeof(dzdn)); memset(guxd, 0, sizeof(guxd)); memset(guxq, 0, sizeof(guxq)); memset(iblte, 0, sizeof(iblte)); memset(ipan, 0, sizeof(ipan)); memset(isys, 0, sizeof(isys)); memset(itran, 0, sizeof(itran)); memset(mass, 0, sizeof(mass)); memset(nbl, 0, sizeof(nbl)); memset(nx, 0, sizeof(nx)); memset(ny, 0, sizeof(ny)); memset(gamu, 0, sizeof(gamu)); memset(gam, 0, sizeof(gam)); memset(gam_a, 0, sizeof(gam_a)); memset(q, 0, sizeof(q)); memset(qf0, 0, sizeof(qf0)); memset(qf1, 0, sizeof(qf1)); memset(qf2, 0, sizeof(qf2)); memset(qf3, 0, sizeof(qf3)); memset(qinv, 0, sizeof(qinv)); memset(qinvu, 0, sizeof(qinvu)); memset(qinv_a, 0, sizeof(qinv_a)); memset(qvis, 0, sizeof(qvis)); memset(s, 0, sizeof(x)); memset(sb, 0, sizeof(xb)); memset(sig, 0, sizeof(sig)); memset(snew, 0, sizeof(snew)); memset(sig, 0, sizeof(sig)); memset(tau, 0, sizeof(tau)); memset(thet, 0, sizeof(thet)); memset(uedg, 0, sizeof(uedg)); memset(uinv, 0, sizeof(uinv)); memset(uslp, 0, sizeof(uslp)); memset(vti, 0, sizeof(vti)); memset(x, 0, sizeof(x)); memset(xb, 0, sizeof(xb)); memset(xbp, 0, sizeof(xbp)); memset(xp, 0, sizeof(xp)); memset(xssi, 0, sizeof(xssi)); memset(y, 0, sizeof(y)); memset(yb, 0, sizeof(yb)); memset(ybp, 0, sizeof(ybp)); memset(yp, 0, sizeof(yp)); memset(wgap, 0, sizeof(wgap)); memset(va, 0, sizeof(va)); memset(vb, 0, sizeof(vb)); memset(vdel, 0, sizeof(vdel)); memset(vm, 0, sizeof(vm)); memset(vs1, 0, sizeof(vs1)); memset(vs2, 0, sizeof(vs2)); memset(vsrez, 0, sizeof(vsrez)); memset(vsr, 0, sizeof(vsr)); memset(vsm, 0, sizeof(vsm)); memset(vsx, 0, sizeof(vsx)); memset(vz, 0, sizeof(vz)); memset(w1, 0, sizeof(w1)); memset(w2, 0, sizeof(w2)); memset(w3, 0, sizeof(w3)); memset(w4, 0, sizeof(w4)); memset(w5, 0, sizeof(w5)); memset(w6, 0, sizeof(w6)); memset(w7, 0, sizeof(w7)); memset(w8, 0, sizeof(w8)); //mdes memset(wc, 0, sizeof(wc)); memset(sc, 0, sizeof(sc)); memset(scold, 0, sizeof(scold)); memset(xcold, 0, sizeof(xcold)); memset(ycold, 0, sizeof(ycold)); memset(sspec, 0, sizeof(sspec)); memset(xspoc, 0, sizeof(xspoc)); memset(yspoc, 0, sizeof(yspoc)); memset(qgamm, 0, sizeof(qgamm)); memset(qspec, 0, sizeof(qspec)); memset(qspecp, 0, sizeof(qspecp)); memset(alqsp, 0, sizeof(alqsp)); memset(clqsp, 0, sizeof(clqsp)); memset(cmqsp, 0, sizeof(cmqsp)); agte = 0.0; ag0 = 0.0; qim0 = 0.0; qimold = 0.0; ssple = 0.0; dwc = 0.0; algam = 0.0; clgam = 0.0; cmgam = 0.0; niterq = 6; //---- default cp/cv (air) gamma = 1.4; gamm1 = gamma - 1.0; //---- set unity freestream speed qinf = 1.0; psio = 0.0; cl = 0.0; cm = 0.0; cd = 0.0; sigte = 0.0; gamte = 0.0; // sigte_a = 0.0; // gamte_a = 0.0; nsp = 0; nqsp = 0; awake = 0.0; avisc = 0.0; // kimage = 1; yimage = -10.0; limage = false; liqset = false; // ??? lgamu = false; lqinu = false;//??? lvisc = false; lwake = false; // lpacc = false; lblini = false; lipan = false; lqaij = false; ladij = false; lwdij = false; lcpxx = false; // lqvdes = false; lqspec = false; // lqrefl = false; lvconv = false; // lcpref = false; // lforef = false; // lpfile = false; // lpfilx = false; // lppsho = false; leiw = false; lscini = false; // lclip = false; // lvlab = true; // lcminp = false; // lhmomp = false; // lcurs = true; // lland = true; lgsame = false; // lgparm = true; // lplcam = false; sharp = false; lalfa = false; lbflap = false; lflap = false; trforc = false; simi = false; tran = false; turb = false; wake = false; trfree = false; tforce[0] =false; tforce[1] =false; tforce[2] =false; thickb = 0.0; cambrb = 0.0; //---- input airfoil will not be normalized // lnorm = false; //---- airfoil will not be forced symmetric lqsym = false; // lgsym = false; //---- endpoint slopes will be matched lqslop = true; // lgslop = true; // lcslop = true; //---- buffer and current airfoil flap hinge coordinates xbf = 0.0; ybf = 0.0; xof = 0.0; yof = 0.0; // ncpref = 0; // n //---- circle plane array size (largest 2 + 1 that will fit array size) double ann = log(double((2*IQX)-1))/log(2.0); int nn = int( ann + 0.00001 ); int tmp = 1; for (l=0; l ICX) { tmp = 1; for (l=0; lm_FoilName; for (i =0; in; i++) { xb[i+1] = pFoil->x[i]; yb[i+1] = pFoil->y[i]; } nb = pFoil->n; lflap = false; lbflap = false; ddef = 0.0; xbf = 1.0; ybf = 0.0; lscini = false; lqspec = false; lvisc = false; if(Preprocess()) { CheckAngles(); for (k=0; knx[k] = nx[k+1]; pFoil->ny[k] = ny[k+1]; } pFoil->n = n; return true; } else { QString str = QObject::tr("Unrecognized foil format")+" "+pFoil->m_FoilName; WriteString(str); return false; } } bool XFoil::InitXFoilAnalysis(Polar *pPolar) { //Sets Analysis parameters in XFoil if(!pPolar) return false; lblini = false; lipan = false; reinf1 = pPolar->m_Reynolds; if (pPolar->m_PolarType==FIXEDAOAPOLAR) alfa = pPolar->m_ASpec*PI/180.0; minf1 = pPolar->m_Mach; retyp = pPolar->m_ReType; matyp = pPolar->m_MaType; lalfa = true; qinf = 1.0; acrit = pPolar->m_ACrit; xstrip[1] = pPolar->m_XTop; xstrip[2] = pPolar->m_XBot; if (pPolar->m_Mach > 0.000001) { if(!SetMach()) { QString str = QObject::tr("... Invalid Analysis Settings\nCpCalc: local speed too large\n Compressibility corrections invalid "); WriteString(str); return false; } } return true; } bool XFoil::inside(double x[], double y[], int n, double xf, double yf) { // logical function inside(x,y,n, xf,yf) // dimension x(n),y(n) //------------------------------------- // returns true if point xf,yf // is inside contour x(i),y(i). //------------------------------------- int i, ip; double xb1, xb2, yb1,yb2, angle; //---- integ, ybrate subtended angle around airfoil perimeter, yb angle = 0.0; for(i=1; i<= n;i++) { ip = i+1; if(i==n) ip = 1; xb1 = x[i] - xf; yb1 = y[i] - yf; xb2 = x[ip] - xf; yb2 = y[ip] - yf; angle = angle + (xb1*yb2 - yb1*xb2) / sqrt((xb1*xb1 + yb1*yb1)*(xb2*xb2 + yb2*yb2)); } //---- angle = 0 if xf,yf is outside, angle = +/- 2 pi if xf,yf is inside return (qAbs(angle) > 1.0); } bool XFoil::lefind(double &sle, double x[], double xp[], double y[], double yp[], double s[], int n) { //------------------------------------------------------ // locates leading edge spline-parameter value sle // // the defining condition is // // (x-xte,y-yte) . (x',y') = 0 at s = sle // // i.e. the surface tangent is normal to the chord // line connecting x(sle),y(sle) and the te point. //------------------------------------------------------ int i, iter; double dseps, dxte, dyte, dx, dy, dotp, dxds, dyds, dxdd, dydd; double res, ress, dsle; double xchord, ychord; //---- convergence tolerance dseps = (s[n]-s[1]) * 0.00001; //---- set trailing edge point coordinates xte = 0.5*(x[1] + x[n]); yte = 0.5*(y[1] + y[n]); //---- get first guess for sle for (i=3; i<= n-2; i++) { dxte = x[i] - xte; dyte = y[i] - yte; dx = x[i+1] - x[i]; dy = y[i+1] - y[i]; dotp = dxte*dx + dyte*dy; if(dotp < 0.0) break; } sle = s[i]; //---- check for sharp le case if(s[i] == s[i-1]) return false; //---- newton iteration to get exact sle value for (iter=1; iter<= 50; iter++) { xle = seval(sle,x,xp,s,n); yle = seval(sle,y,yp,s,n); dxds = deval(sle,x,xp,s,n); dyds = deval(sle,y,yp,s,n); dxdd = d2val(sle,x,xp,s,n); dydd = d2val(sle,y,yp,s,n); xchord = xle - xte; ychord = yle - yte; //------ drive dot product between chord line and le tangent to zero res = xchord*dxds + ychord*dyds; ress = dxds *dxds + dyds *dyds + xchord*dxdd + ychord*dydd; //------ newton delta for sle dsle = -res/ress; dsle = qMax( dsle , -0.02*qAbs(xchord+ychord) ); dsle = qMin( dsle , 0.02*qAbs(xchord+ychord) ); sle = sle + dsle; if(qAbs(dsle) < dseps) return true; } sle = s[i]; return true; } bool XFoil::ludcmp(int n, double a[IQX][IQX], int indx[IQX]) { // ******************************************************* // * * // * factors a full nxn matrix into an lu form. * // * subr. baksub can back-substitute it with some rhs.* // * assumes matrix is non-singular... * // * ...if it isn"t, a divide by zero will result. * // * * // * a is the matrix... * // * ...replaced with its lu factors. * // * * // * mark drela 1988 * // ******************************************************* // // bool bimaxok = false; int imax =0;//added arcds int nvx=IQX; int i, j, k; double vv[IQX]; double dum, sum, aamax; if(n>nvx) { QString str("Stop ludcmp: array overflow. Increase nvx"); WriteString(str, true); return false; } for (i=1; i<=n; i++){ aamax = 0.0; for (j=1; j<=n; j++) aamax = qMax(qAbs(a[i][j]), aamax); vv[i] = 1.0/aamax; } for(j=1;j<= n;j++){ for(i=1; i<=j-1; i++){ sum = a[i][j]; for (k=1;k<= i-1;k++) sum = sum - a[i][k]*a[k][j]; a[i][j] = sum; } aamax = 0.0; for (i=j; i<=n;i++){ sum = a[i][j]; for (k=1;k<= j-1;k++) sum = sum - a[i][k]*a[k][j]; a[i][j] = sum ; dum = (vv[i]*qAbs(sum)); if(dum>=aamax){ imax = i; aamax = dum; bimaxok = true; } } // ASSERT(bimaxok);// to check imax has been initialized if(j!=imax) { for (k=1; k<= n; k++){ dum = a[imax][k]; a[imax][k] = a[j][k]; a[j][k] = dum; } vv[imax] = vv[j]; } indx[j] = imax; if(j!=n) { dum = 1.0/a[j][j]; for(i=j+1; i<= n;i++) a[i][j] = a[i][j]*dum; } } return true; } bool XFoil::mhinge() { //---------------------------------------------------- // calculates the hinge moment of the flap about // (xof,yof) by integrating surface pressures. //---------------------------------------------------- int i; double tops,bots,botp,botx,boty,frac,topp,topx,topy; double xmid,ymid,pmid; double dx,dy; if(!lflap) { getxyf(x, xp, y, yp, s, n, tops, bots, xof, yof); lflap = true; } else { //------ find top and bottom y at hinge x location tops = xof; bots = s[n] - xof; sinvrt(tops,xof,x,xp,s,n); sinvrt(bots,xof,x,xp,s,n); } topx = seval(tops,x,xp,s,n); topy = seval(tops,y,yp,s,n); botx = seval(bots,x,xp,s,n); boty = seval(bots,y,yp,s,n); hmom = 0.0; hfx = 0.0; hfy = 0.0; //---- integrate pressures on top and bottom sides of flap for (i=2;i<= n;i++) { if(s[i-1]bots) { dx = x[i] - x[i-1]; dy = y[i] - y[i-1]; xmid = 0.5*(x[i]+x[i-1]) - xof; ymid = 0.5*(y[i]+y[i-1]) - yof; if(lvisc) pmid = 0.5*(cpv[i] + cpv[i-1]); else pmid = 0.5*(cpi[i] + cpi[i-1]); hmom = hmom + pmid*(xmid*dx + ymid*dy); hfx = hfx - pmid* dy; hfy = hfy + pmid* dx; } } //---- find s[i]..s[i-1] interval containing s=tops i=2; bool bexit = false; while (!bexit) { if(s[i]n) {} //we have a problem... } // for (i=2; i<= n;i++) { // if(s[i]>tops) goto stop31; // } //stop31 //---- add on top surface chunk tops..s[i-1], missed in the do 20 loop. dx = topx - x[i-1]; dy = topy - y[i-1]; xmid = 0.5*(topx+x[i-1]) - xof; ymid = 0.5*(topy+y[i-1]) - yof; if(s[i] != s[i-1]) frac = (tops-s[i-1])/(s[i]-s[i-1]); else frac = 0.0; if(lvisc) { topp = cpv[i]*frac + cpv[i-1]*(1.0-frac); pmid = 0.5*(topp+cpv[i-1]); } else{ topp = cpi[i]*frac + cpi[i-1]*(1.0-frac); pmid = 0.5*(topp+cpi[i-1]); } hmom = hmom + pmid*(xmid*dx + ymid*dy); hfx = hfx - pmid* dy; hfy = hfy + pmid* dx; //---- add on inside flap surface contribution from hinge to top surface dx = xof - topx; dy = yof - topy; xmid = 0.5*(topx+xof) - xof; ymid = 0.5*(topy+yof) - yof; hmom = hmom + pmid*(xmid*dx + ymid*dy); hfx = hfx - pmid* dy; hfy = hfy + pmid* dx; //---- find s[i]..s[i-1] interval containing s=bots for (i=n; i>= 2;i--){ if(s[i-1]iblte[is]; //------ initialize current station to existing variables xsi = xssi[ibl][is]; uei = uedg[ibl][is]; thi = thet[ibl][is]; dsi = dstr[ibl][is]; //------ fixed bug md 7 june 99 if(ibliblte[is]) dsi = qMax(dsi-dswaki,1.00005*thi) + dswaki; //------ newton iteration loop for current station for (itbl=1;itbl<= 25;itbl++){//100 //-------- assemble 10x3 linearized system for dctau, dth, dds, due, dxi // at the previous "1" station and the current "2" station // (the "1" station coefficients will be ignored) blprv(xsi,ami,cti,thi,dsi,dswaki,uei); blkin(); //-------- check for transition and set appropriate flags and things if((!simi) && (!turb)) { trchek(); ami = ampl2; if( tran) itran[is] = ibl; if(!tran) itran[is] = ibl+2; } if(ibl==iblte[is]+1) { tte = thet[iblte[1]][1] + thet[iblte[2]][2]; dte = dstr[iblte[1]][1] + dstr[iblte[2]][2] + ante; cte = ( ctau[iblte[1]][1]*thet[iblte[1]][1] + ctau[iblte[2]][2]*thet[iblte[2]][2] ) / tte; tesys(cte,tte,dte); } else{ blsys(); } //-------- set stuff at first iteration... if(itbl==1) { //--------- set "baseline" ue and hk for forming ue(hk) relation ueref = u2; hkref = hk2; //--------- if current point ibl was turbulent and is now laminar, then... if(ibl=itrold ) { //---------- extrapolate baseline hk uem = uedg[ibl-1][is]; dsm = dstr[ibl-1][is]; thm = thet[ibl-1][is]; msq = uem*uem*hstinv / (gm1bl*(1.0 - 0.5*uem*uem*hstinv)); hkin( dsm/thm, msq, hkref, dummy, dummy ); } //--------- if current point ibl was laminar, then... if(ibl=itran[is]) dmax = qMax(dmax,qAbs(vsrez[1]/(10.0*cti))); rlx = 1.0; if(dmax>0.3) rlx = 0.3/dmax; //-------- update as usual if(ibl=itran[is]) cti = cti + rlx*vsrez[1]; thi = thi + rlx*vsrez[2]; dsi = dsi + rlx*vsrez[3]; uei = uei + rlx*vsrez[4]; //-------- eliminate absurd transients if(ibl>=itran[is]) { cti = qMin(cti , 0.30); cti = qMax(cti , 0.0000001); } if(ibl<=iblte[is]) hklim = 1.02; else hklim = 1.00005; msq = uei*uei*hstinv / (gm1bl*(1.0 - 0.5*uei*uei*hstinv)); dsw = dsi - dswaki; dslim(dsw,thi,msq,hklim); dsi = dsw + dswaki; if(dmax<=deps) goto stop110; } str = QString(QObject::tr(" mrchdu: convergence failed at %1 , side %2, res =%3\n")).arg(ibl).arg(is).arg(dmax, 4, 'f', 3); WriteString(str, true); if (dmax<= 0.1) goto stop109; //------ the current unconverged solution might still be reasonable... if(dmax > 0.1) { //------- the current solution is garbage --> extrapolate values instead if(ibl>3) { if(ibl<=iblte[is]) { thi = thet[ibm][is] * sqrt(xssi[ibl][is]/xssi[ibm][is]); dsi = dstr[ibm][is] * sqrt(xssi[ibl][is]/xssi[ibm][is]); uei = uedg[ibm][is]; } else{ if(ibl==iblte[is]+1) { cti = cte; thi = tte; dsi = dte; uei = uedg[ibm][is]; } else{ thi = thet[ibm][is]; ratlen = (xssi[ibl][is]-xssi[ibm][is]) / (10.0*dstr[ibm][is]); dsi = (dstr[ibm][is] + thi*ratlen) / (1.0 + ratlen); uei = uedg[ibm][is]; } } if(ibl==itran[is]) cti = 0.05; if(ibl>itran[is]) cti = ctau[ibm][is]; } } stop109: blprv(xsi,ami,cti,thi,dsi,dswaki,uei); blkin(); //------- check for transition and set appropriate flags and things if((!simi) && (!turb)) { trchek(); ami = ampl2; if( tran) itran[is] = ibl; if(!tran) itran[is] = ibl+2; } //------- set all other extrapolated values for current station if(ibl=itran[is]) blvar(2); if(wake) blvar(3); if(ibl=itran[is]) blmid(2); if(wake) blmid(3); //------ pick up here after the newton iterations stop110: sens = sennew; //------ store primary variables if(iblprocessEvents(); if(s_bCancel) return false; }//1000 continue }// 2000 continue return true; } bool XFoil::mrchue() { //---------------------------------------------------- // marches the bls and wake in direct mode using // the uedg array. if separation is encountered, // a plausible value of hk extrapolated from // upstream is prescribed instead. continuous // checking of transition onset is performed. //---------------------------------------------------- QString str; bool direct; int is, ibl, ibm, iw, itbl; double msq, ratlen,dsw,hklim; double hlmax, htmax, xsi, uei, ucon, tsq, thi, ami, cti, dsi; double dswaki; double htest, hktest, dummy; double cst; double cte, dte, tte, dmax, hmax, htarg; cte = dte = tte = dmax = hmax = htarg = 0.0; //---- shape parameters for separation criteria hlmax = 3.8; htmax = 2.5; for (is=1;is<= 2;is++) {//2000 QString str = QString(QObject::tr(" Side %1 ...\n")).arg(is); WriteString(str); //---- set forced transition arc length position xifset(is); //---- initialize similarity station with thwaites' formula // ibl = 2; xsi = xssi[2][is]; uei = uedg[2][is]; // bule = log(uedg(ibl+1,is)/uei) / log(xssi(ibl+1,is)/xsi) // bule = qMax( -.08 , bule ) bule = 1.0; ucon = uei/pow(xsi,bule); tsq = 0.45/(ucon*(5.0*bule+1.0)*reybl) * pow(xsi,(1.0-bule)); thi = sqrt(tsq); dsi = 2.2*thi; ami = 0.0; //---- initialize ctau for first turbulent station cti = 0.03; tran = false; turb = false; itran[is] = iblte[is]; //---- march downstream for (ibl=2; ibl<=nbl[is];ibl++) {// 1000 ibm = ibl-1; iw = ibl - iblte[is]; simi = (ibl==2); wake = ibl>iblte[is]; //------ prescribed quantities xsi = xssi[ibl][is]; uei = uedg[ibl][is]; if(wake) { iw = ibl - iblte[is]; dswaki = wgap[iw]; } else dswaki = 0.0; direct = true; //------ newton iteration loop for current station for (itbl=1; itbl<= 25;itbl++){//100 //-------- assemble 10x3 linearized system for dctau, dth, dds, due, dxi // at the previous "1" station and the current "2" station // (the "1" station coefficients will be ignored) blprv(xsi,ami,cti,thi,dsi,dswaki,uei); blkin(); //-------- check for transition and set appropriate flags and things if((!simi) && (!turb)) { trchek(); ami = ampl2; //--------- fixed bug md 7 jun 99 if(tran) { itran[is] = ibl; if(cti<=0.0) { cti = 0.03; s2 = cti; } } else itran[is] = ibl+2; } if(ibl==iblte[is]+1) { tte = thet[iblte[1]][1] + thet[iblte[2]][2]; dte = dstr[iblte[1]][1] + dstr[iblte[2]][2] + ante; cte = ( ctau[iblte[1]][1]*thet[iblte[1]][1] + ctau[iblte[2]][2]*thet[iblte[2]][2] ) / tte; tesys(cte,tte,dte); } else blsys(); if(direct) { //--------- try direct mode (set due = 0 in currently empty 4th line) vs2[4][1] = 0.0; vs2[4][2] = 0.0; vs2[4][3] = 0.0; vs2[4][4] = 1.0; vsrez[4] = 0.0; //--------- solve newton system for current "2" station Gauss(4,vs2,vsrez); //--------- determine max changes and underrelax if necessary dmax = qMax( qAbs(vsrez[2]/thi), qAbs(vsrez[3]/dsi) ); if(ibl=itran[is]) dmax = qMax(dmax,qAbs(vsrez[1]/cti )); rlx = 1.0; if(dmax>0.3) rlx = 0.3/dmax; //--------- see if direct mode is not applicable if(ibl != iblte[is]+1) { //---------- calculate resulting kinematic shape parameter hk msq = uei*uei*hstinv / (gm1bl*(1.0 - 0.5*uei*uei*hstinv)); htest = (dsi + rlx*vsrez[3]) / (thi + rlx*vsrez[2]); hkin(htest, msq, hktest, dummy, dummy); //---------- decide whether to do direct or inverse problem based on hk if(ibl=itran[is]) hmax = htmax; direct = (hktest=itran[is]) cti = cti + rlx*vsrez[1]; thi = thi + rlx*vsrez[2]; dsi = dsi + rlx*vsrez[3]; } else { //---------- set prescribed hk for inverse calculation at the current station if(ibl=itran[is]) dmax = qMax( dmax , qAbs(vsrez[1]/cti)); rlx = 1.0; if(dmax>0.3) rlx = 0.3/dmax; //--------- update variables if(ibl>=itran[is]) cti = cti + rlx*vsrez[1]; thi = thi + rlx*vsrez[2]; dsi = dsi + rlx*vsrez[3]; uei = uei + rlx*vsrez[4]; } //-------- eliminate absurd transients if(ibl>=itran[is]) { cti = qMin(cti, 0.30); cti = qMax(cti, 0.0000001); } if(ibl<=iblte[is]) hklim = 1.02; else hklim = 1.00005; msq = uei*uei*hstinv / (gm1bl*(1.0 - 0.5*uei*uei*hstinv)); dsw = dsi - dswaki; dslim(dsw,thi,msq,hklim); dsi = dsw + dswaki; if(dmax<=0.00001) goto stop110; stop100: int nothing; nothing = 1; }//end itbl loop //TRACE(" mrchue: convergence failed at %d, side %d, res = %f\n", ibl, is, dmax); str = QString(QObject::tr(" mrchue: convergence failed at %1, side %2, res = %3\n")).arg( ibl).arg( is).arg( dmax,0,'f',3); WriteString(str, true); //------ the current unconverged solution might still be reasonable... if(dmax > 0.1) { //------- the current solution is garbage --> extrapolate values instead if(ibl>3) { if(ibl<=iblte[is]) { thi = thet[ibm][is] * sqrt(xssi[ibl][is]/xssi[ibm][is]); dsi = dstr[ibm][is] * sqrt(xssi[ibl][is]/xssi[ibm][is]); } else{ if(ibl==iblte[is]+1) { cti = cte; thi = tte; dsi = dte; } else{ thi = thet[ibm][is]; ratlen = (xssi[ibl][is]-xssi[ibm][is]) / (10.0*dstr[ibm][is]); dsi = (dstr[ibm][is] + thi*ratlen) / (1.0 + ratlen); } } if(ibl==itran[is]) cti = 0.05; if(ibl>itran[is]) cti = ctau[ibm][is]; uei = uedg[ibl][is]; if(ibl>2 && ibl=itran[is]) blvar(2); if(wake) blvar(3); if(ibl=itran[is]) blmid(2); if(wake) blmid(3); //------ pick up here after the newton iterations stop110: //------ store primary variables if(ibl=itran[is]) ctau[ibl][is] = cti; thet[ibl][is] = thi; dstr[ibl][is] = dsi; uedg[ibl][is] = uei; mass[ibl][is] = dsi*uei; tau[ibl][is] = 0.5*r2*u2*u2*cf2; dis[ibl][is] = r2*u2*u2*u2*di2*hs2*0.5; ctq[ibl][is] = cq2; delt[ibl][is] = de2; //------ set "1" variables to "2" variables for next streamwise station blprv(xsi,ami,cti,thi,dsi,dswaki,uei); blkin(); stepbl(); //------ turbulent intervals will follow transition interval or te if(tran || ibl==iblte[is]) { turb = true; //------- save transition location tforce[is] = trforc; xssitr[is] = xt; } tran = false; if(ibl==iblte[is]) { thi = thet[iblte[1]][1] + thet[iblte[2]][2]; dsi = dstr[iblte[1]][1] + dstr[iblte[2]][2] + ante; } }// 1000 continue : end ibl loop }// 2000 continue : end is loop return true; } bool XFoil::mrcl(double cls, double &m_cls, double &r_cls) { //------------------------------------------- // sets actual mach, reynolds numbers // from unit-cl values and specified cls // depending on matyp,retyp flags. //------------------------------------------- double rrat, cla; cla = qMax(cls, 0.000001); if(retyp<1 || retyp>3) { QString str(QObject::tr(" mrcl: illegal Re(cls) dependence trigger, Setting fixed Re ")); WriteString(str, true); retyp = 1; } if(matyp<1 || matyp>3) { QString str(QObject::tr(" mrcl: illegal Mach(cls) dependence trigger\n Setting fixed Mach")); WriteString(str, true); matyp = 1; } switch(matyp) { case 1: { minf = minf1; m_cls = 0.0; break; } case 2: { minf = minf1/sqrt(cla); m_cls = -0.5*minf/cla; break; } case 3: { minf = minf1; m_cls = 0.0; break; } } switch(retyp) { case 1: { reinf = reinf1; r_cls = 0.0; break; } case 2: { reinf = reinf1/sqrt(cla); r_cls = -0.5*reinf/cla; break; } case 3: { reinf = reinf1/cla; r_cls = -reinf /cla; break; } } if(minf >= 0.99) { //TRACE(" artificially limiting mach to 0.99\n"); QString str(QObject::tr("mrcl: Cl too low for chosen Mach(Cl) dependence\n")); WriteString(str, true); str = QObject::tr(" artificially limiting mach to 0.99"); WriteString(str, true); minf = 0.99; m_cls = 0.0; } rrat = 1.0; if(reinf1 > 0.0) rrat = reinf/reinf1; if(rrat > 100.0) { //TRACE(" artificially limiting re to %f\n",reinf1*100.0); QString str(QObject::tr("mrcl: cl too low for chosen Re(Cl) dependence\n")); WriteString(str, true); str = QString(QObject::tr(" artificially limiting Re to %1\n")).arg(reinf1*100.0,0,'f',0); WriteString(str, true); reinf = reinf1*100.0; r_cls = 0.0; } return true; } bool XFoil::ncalc(double x[], double y[], double s[], int n, double xn[], double yn[]) { double sx, sy, smod; int i; if(n<=1) return false; segspl(x,xn,s,n); segspl(y,yn,s,n); for (i=1; i<= n; i++) { sx = yn[i]; sy = -xn[i]; smod = sqrt(sx*sx + sy*sy); xn[i] = sx/smod; yn[i] = sy/smod; } //---- average normal vectors at corner points for (i=1;i<= n-1; i++){ if(s[i] == s[i+1]) { sx = 0.5*(xn[i] + xn[i+1]); sy = 0.5*(yn[i] + yn[i+1]); smod = sqrt(sx*sx + sy*sy); xn[i] = sx/smod; yn[i] = sy/smod; xn[i+1] = sx/smod; yn[i+1] = sy/smod; } } return true; } void XFoil::pangen() { // subroutine pangen(shopar) //--------------------------------------------------- // set paneling distribution from buffer airfoil // geometry, thus creating current airfoil. // // if refine=true, bunch points at x=xsref on // top side and at x=xpref on bottom side // by setting a fictitious local curvature of // ctrrat*(le curvature) there. //--------------------------------------------------- QString str; int ipfac, ible, nk, nn, nfrac1, nn2, ind, ncorn,j; double sbref, cvle, xble, xbte, yble, ybte, chbsq, cvsum, cvte; double frac, sbk, cvk, cvavg, cc, smool, smoosq, dsm, dsp, dso; double xoc, cvmax, rdste, rtf, dsavg, dsavg1, dsavg2; double cv1, cv2, cv3, cvs1, cvs2, cvs3, cavm, cavm_s1, cavm_s2; double cavp, cavp_s2, cavp_s3, fm, fp, rez; double dmax, ds, dds, dsrat, xbcorn, ybcorn, sbcorn; double dsmin, dsmax; double gap; int i,k, nn1; int nothing; nn1 = 0; if(nb<2) { QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QXDirect::tr("Warning")); msgBox.setText(QObject::tr("PanGen: buffer airfoil not available.")); msgBox.exec(); n = 0; return; } //---- number of temporary nodes for panel distribution calculation // exceeds the specified panel number by factor of ipfac. ipfac = 3; //---- number of airfoil panel points n = npan; //---- number of wake points // nw = npan/8 + 2 // if(nw>iwx) then // write(*,*) // & 'array size (iwx) too small. last wake point index reduced.' // nw = iwx // endif // //---- set arc length spline parameter scalc(xb,yb,sb,nb); //---- spline raw airfoil coordinates segspl(xb,xbp,sb,nb); segspl(yb,ybp,sb,nb); //---- normalizing length (~ chord) sbref = 0.5*(sb[nb]-sb[1]); //---- set up curvature array for(i = 1; i<= nb; i++) w5[i] = qAbs(curv(sb[i],xb,xbp,yb,ybp,sb,nb)) * sbref; //---- locate le point arc length value and the normalized curvature there lefind(sble,xb,xbp,yb,ybp,sb,nb); cvle = qAbs(curv(sble,xb,xbp,yb,ybp,sb,nb)) * sbref; //---- check for doubled point (sharp corner) at le ible = 0; for (i = 1; i<= nb-1; i++){ if(sble==sb[i] && sble==sb[i+1]) { ible = i; //TRACE("Sharp leading edge\n"); // QString str; // str.Format("Sharp leading edge\n"); // pXFile->WriteString(str); break; } } //stop21: //---- set le, te points xble = seval(sble,xb,xbp,sb,nb); yble = seval(sble,yb,ybp,sb,nb); xbte = 0.5*(xb[1]+xb[nb]); ybte = 0.5*(yb[1]+yb[nb]); chbsq = (xbte-xble)*(xbte-xble) + (ybte-yble)*(ybte-yble); //---- set average curvature over 2*nk+1 points within rcurv of le point nk = 3; cvsum = 0.0; for (k = -nk; k<=nk; k++){ frac = double(k)/double(nk); sbk = sble + frac*sbref/qMax(cvle,20.0); cvk = qAbs(curv(sbk,xb,xbp,yb,ybp,sb,nb)) * sbref; cvsum = cvsum + cvk; } cvavg = cvsum/double(2*nk+1); //---- dummy curvature for sharp le if(ible!=0) cvavg = 10.0; //---- set curvature attraction coefficient actually used cc = 6.0 * cvpar; //---- set artificial curvature at te to bunch panels there cvte = cvavg * cterat; w5[1] = cvte; w5[nb] = cvte; //**** smooth curvature array for smoother panel size distribution **** //---- set smoothing length = 1 / averaged le curvature, but // no more than 5% of chord and no less than 1/4 average panel spacing smool = qMax(1.0/qMax(cvavg,20.0), 0.25/double(npan/2)); smoosq = (smool*sbref) *(smool*sbref); //---- set up tri-diagonal system for smoothed curvatures w2[1] = 1.0; w3[1] = 0.0; for(i=2; i<= nb-1; i++) { dsm = sb[i] - sb[i-1]; dsp = sb[i+1] - sb[i]; dso = 0.5*(sb[i+1] - sb[i-1]); if(dsm==0.0 || dsp==0.0) { //------- leave curvature at corner point unchanged w1[i] = 0.0; w2[i] = 1.0; w3[i] = 0.0; } else{ w1[i] = smoosq * ( - 1.0/dsm) / dso; w2[i] = smoosq * ( 1.0/dsp + 1.0/dsm) / dso + 1.0; w3[i] = smoosq * (-1.0/dsp ) / dso; } } w1[nb] = 0.0; w2[nb] = 1.0; //---- fix curvature at le point by modifying equations adjacent to le for (i=2; i<= nb-1; i++) { if(sb[i]==sble || i==ible || i==ible+1) { //------- if node falls right on le point, fix curvature there w1[i] = 0.0; w2[i] = 1.0; w3[i] = 0.0; w5[i] = cvle; } else if(sb[i-1]sble) { //------- modify equation at node just before le point dsm = sb[i-1] - sb[i-2]; dsp = sble - sb[i-1]; dso = 0.5*(sble - sb[i-2]); w1[i-1] = smoosq * ( - 1.0/dsm) / dso; w2[i-1] = smoosq * (1.0/dsp + 1.0/dsm) / dso + 1.0; w3[i-1] = 0.0; w5[i-1] = w5[i-1] + smoosq*cvle/(dsp*dso); //------- modify equation at node just after le point dsm = sb[i] - sble; dsp = sb[i+1] - sb[i]; dso = 0.5*(sb[i+1] - sble); w1[i] = 0.0; w2[i] = smoosq * ( 1.0/dsp + 1.0/dsm) / dso + 1.0; w3[i] = smoosq * (-1.0/dsp ) / dso; w5[i] = w5[i] + smoosq*cvle/(dsm*dso); goto stop51; } } stop51: //---- set artificial curvature at bunching points and fix it there for (i=2; i<=nb-1; i++) { //------ chord-based x/c coordinate xoc = ((xb[i]-xble)*(xbte-xble) + (yb[i]-yble)*(ybte-yble) ) / chbsq; if(sb[i]xsref1 && xocxpref1 && xoc4.0) rlx = (4.0-1.0)*ds/dds; if(dsrat<0.2) rlx = (0.2-1.0)*ds/dds; dmax = qMax(qAbs(w4[i]),dmax); } //------ update node position for(i=2; i<=nn-1; i++){ snew[i] = snew[i] + rlx*w4[i]; } if(qAbs(dmax)<0.001) goto stop11; } //TRACE("Paneling convergence failed. Continuing anyway...\n"); str = QObject::tr("Paneling convergence failed. Continuing anyway...\n"); WriteString(str, true); stop11: //---- set new panel node coordinates for(i=1; i<= n; i++) { ind = ipfac*(i-1) + 1; s[i] = snew[ind]; x[i] = seval(snew[ind],xb,xbp,sb,nb); y[i] = seval(snew[ind],yb,ybp,sb,nb); } //---- go over buffer airfoil again, checking for corners (double points) ncorn = 0; for(int ib=1; ib<= nb-1; ib++) {//25 if(sb[ib] == sb[ib+1]) { //------- found one ! ncorn = ncorn+1; xbcorn = xb[ib]; ybcorn = yb[ib]; sbcorn = sb[ib]; //------- find current-airfoil panel which contains corner for(i=1; i<= n ; i++) {//252 //--------- keep stepping until first node past corner if(s[i] <= sbcorn) goto stop252; //---------- move remainder of panel nodes to make room for additional node for(j=n; j>=i; j--) { x[j+1] = x[j]; y[j+1] = y[j]; s[j+1] = s[j]; } n = n+1; if(n > IQX-1) { //TRACE("panel: too many panels. increase iqx in xfoil.inc"); QString str = QObject::tr("Panel: Too many panels. Increase IQX"); WriteString(str, true); return; } x[i] = xbcorn; y[i] = ybcorn; s[i] = sbcorn; //---------- shift nodes adjacent to corner to keep panel sizes comparable if(i-2 >= 1) { s[i-1] = 0.5*(s[i] + s[i-2]); x[i-1] = seval(s[i-1],xb,xbp,sb,nb); y[i-1] = seval(s[i-1],yb,ybp,sb,nb); } if(i+2 <= n) { s[i+1] = 0.5*(s[i] + s[i+2]); x[i+1] = seval(s[i+1],xb,xbp,sb,nb); y[i+1] = seval(s[i+1],yb,ybp,sb,nb); } //---------- go on to next input geometry point to check for corner goto stop25; stop252: nothing = 0;// C++ doesn't like gotos } } stop25: nothing = 0;// C++ doesn't like gotos } scalc(x,y,s,n); segspl(x,xp,s,n); segspl(y,yp,s,n); lefind(sle,x,xp,y,yp,s,n); xle = seval(sle,x,xp,s,n); yle = seval(sle,y,yp,s,n); xte = 0.5*(x[1]+x[n]); yte = 0.5*(y[1]+y[n]); chord = sqrt((xte-xle)*(xte-xle) + (yte-yle)*(yte-yle)); //---- calculate panel size ratios (user info) dsmin = 1000.0; dsmax = -1000.0; for(i=1; i<= n-1; i++) { ds = s[i+1]-s[i]; if(ds != 0.0) { dsmin = min(dsmin,ds); dsmax = max(dsmax,ds); } } dsmin = dsmin*(double)(n-1)/s[n]; dsmax = dsmax*(double)(n-1)/s[n]; //---- set various flags for new airfoil lgamu = false; lwake = false; lqaij = false; ladij = false; lwdij = false; lipan = false; lblini = false; lvconv = false; if(lbflap) { xof = xbf; yof = ybf; lflap = true; } //---- determine if te is blunt or sharp, calculate te geometry parameters tecalc(); //---- calculate normal vectors ncalc(x,y,s,n,nx,ny); //---- calculate panel angles for panel routines apcalc(); if(sharp) { // QString str; // str.Format("Sharp trailing edge\n"); // pXFile->WriteString(str); //TRACE("sharp trailing edge\n"); } else { gap = sqrt((x[1]-x[n])*(x[1]-x[n]) + (y[1]-y[n])*(y[1]-y[n])); //TRACE("Blunt trailing edge. Gap =%f", gap); // QString str; // str.Format("Blunt trailing edge. Gap =%f", gap); // pXFile->WriteString(str); } //TRACE("paneling parameters used...\n"); //TRACE(" Number of panel nodes %d\n", npan); //TRACE(" Panel bunching parameter %.3\n", cvpar); //TRACE(" te/le panel density ratio %.3\n", cterat); //TRACE(" refined-area/le panel density ratio %3\n",ctrrat); //TRACE(" top side refined area x/c limits %.3 %3\n",xsref1, xsref2); //TRACE(" bottom side refined area x/c limits %.3 %3\n",xpref1, xpref2); return; } bool XFoil::Preprocess() { double xble, yble, xbte, ybte; // double xinl, xout, ybot, ytop; //---- calculate airfoil area assuming counterclockwise ordering if(nb<=2) return false;//added arcds double area = 0.0; for (int i=1; i<= nb; i++) { int ip = i+1; if(i==nb) ip = 1; area = area + 0.5*(yb[i]+yb[ip])*(xb[i]-xb[ip]); } scalc(xb,yb,sb,nb); segspl(xb,xbp,sb,nb); // segspl(yb,ybp,sb,nb); geopar(xb,xbp,yb,ybp,sb,nb, w1,sble,chordb,areab,radble,angbte, ei11ba,ei22ba,apx1ba,apx2ba,ei11bt,ei22bt,apx1bt,apx2bt); xble = seval(sble,xb,xbp,sb,nb); yble = seval(sble,yb,ybp,sb,nb); xbte = 0.5*(xb[1] + xb[nb]); ybte = 0.5*(yb[1] + yb[nb]); //TRACE(" le_x = %f, le_y = %f, chord=%f\n te_x = %f, te_y = %f\n", xble,yble, chordb,xbte, ybte); //---- set reasonable mses domain parameters for non-mses coordinate file xble = seval(sble,xb,xbp,sb,nb); yble = seval(sble,yb,ybp,sb,nb); // What's the use ? /* xinl = xble - 2.0*chordb; xout = xble + 3.0*chordb; ybot = yble - 2.5*chordb; ytop = yble + 3.5*chordb; xinl = aint(20.0*qAbs(xinl/chordb)+0.5)/20.0 * sign(chordb,xinl); xout = aint(20.0*qAbs(xout/chordb)+0.5)/20.0 * sign(chordb,xout); ybot = aint(20.0*qAbs(ybot/chordb)+0.5)/20.0 * sign(chordb,ybot); ytop = aint(20.0*qAbs(ytop/chordb)+0.5)/20.0 * sign(chordb,ytop);*/ //---- wipe out old flap hinge location xbf = 0.0; ybf = 0.0; lbflap = false; // end "load" return abcopy(); } bool XFoil::psilin(int i, double xi, double yi, double nxi, double nyi, double &psi, double &psi_ni, bool geolin, bool siglin){ //----------------------------------------------------------------------- // calculates current streamfunction psi at panel node or wake node // i due to freestream and all bound vorticity gam on the airfoil. // sensitivities of psi with respect to alpha (z_alfa) and inverse // qspec dofs (z_qdof0,z_qdof1) which influence gam in inverse cases. // also calculates the sensitivity vector dpsi/dgam (dzdg). // // if siglin=true, then psi includes the effects of the viscous // source distribution sig and the sensitivity vector dpsi/dsig // (dzdm) is calculated. // // if geolin=true, then the geometric sensitivity vector dpsi/dn // is calculated, where n is the normal motion of the jth node. // // airfoil: 1 < i < n // wake: n+1 < i < n+nw //----------------------------------------------------------------------- int io,jo,jm,jq,jp; double dxinv,psum, qtanm, scs,sds, rx1,rx2,sx,sy,dsio,dso,dsm,dsim; double sgn, x0,g0,t0,rs0,rs1,rs2, xjo,xjp,yjo,yjp, nxo,nyo,nxp,nyp, ry1,ry2; double ssum, sdif, psni,pdni, psx0,psx1,psx2,pdx0,pdx1,pdx2,psyy,pdyy,psis,psig,psid; double psigx1,psigx2,psigyy,pgamx1,pgamx2,pgamyy,psigni,pgamni; double gsum,gdif,gsum1,gsum2,gdif1,gdif2,pdif,dsp,dsip; double sigte1,sigte2,gamte1,gamte2,pgam; double apan , yy, g1, g2, x1i, x2i, yyi, x1o, x1p, x2o,x2p,yyo,yyp; double seps; //---- distance tolerance for determining if two points are the same seps = (s[n]-s[1]) * 0.00001; apan = yy = g1 = g2 = x1i = x2i = yyi = x1o = x1p = x2o = x2p = yyo = yyp = 0.0; io = i; cosa = cos(alfa); sina = sin(alfa); jp = 0; for (jo=1;jo<= n;jo++) { dzdg[jo] = 0.0; dzdn[jo] = 0.0; dqdg[jo] = 0.0; } for (jo=1;jo<= n;jo++) { dzdm[jo] = 0.0; dqdm[jo] = 0.0; } z_qinf = 0.0; z_alfa = 0.0; z_qdof0 = 0.0; z_qdof1 = 0.0; z_qdof2 = 0.0; z_qdof3 = 0.0; psi = 0.0; psi_ni = 0.0; qtan1 = 0.0; qtan2 = 0.0; qtanm = 0.0; if(sharp) { scs = 1.0; sds = 0.0; } else { scs = ante/dste; sds = aste/dste; } for(jo=1;jo<= n;jo++) {//stop10 jp = jo+1; jm = jo-1; jq = jp+1; if(jo==1) jm = jo; else { if(jo==n-1) jq = jp; else { if(jo==n) { jp = 1; if((x[jo]-x[jp])*(x[jo]-x[jp]) + (y[jo]-y[jp])*(y[jo]-y[jp])< seps*seps) goto stop12; } } } dso = sqrt((x[jo]-x[jp])*(x[jo]-x[jp]) + (y[jo]-y[jp])*(y[jo]-y[jp])); //------ skip null panel if(dso == 0.0) goto stop10; //check - unsafe comparison dsio = 1.0 / dso; apan = apanel[jo]; rx1 = xi - x[jo]; ry1 = yi - y[jo]; rx2 = xi - x[jp]; ry2 = yi - y[jp]; sx = (x[jp] - x[jo]) * dsio; sy = (y[jp] - y[jo]) * dsio; x1 = sx*rx1 + sy*ry1; x2 = sx*rx2 + sy*ry2; yy = sx*ry1 - sy*rx1; rs1 = rx1*rx1 + ry1*ry1; rs2 = rx2*rx2 + ry2*ry2; //------ set reflection flag sgn to avoid branch problems with arctan if(io>=1 && io<=n) { //------- no problem on airfoil surface sgn = 1.0; } else { //------- make sure arctan falls between -/+ pi/2 sgn = sign(1.0,yy); } //------ set log(r^2) and arctan(x/y), correcting for reflection if any if(io!=jo && rs1>0.0) { g1 = log(rs1); t1 = atan2(sgn*x1,sgn*yy) + (0.5- 0.5*sgn)*PI; } else{ g1 = 0.0; t1 = 0.0; } if(io!=jp && rs2>0.0) { g2 = log(rs2); t2 = atan2(sgn*x2,sgn*yy) + (0.5- 0.5*sgn)*PI; } else { g2 = 0.0; t2 = 0.0; } x1i = sx*nxi + sy*nyi; x2i = sx*nxi + sy*nyi; yyi = sx*nyi - sy*nxi; if(geolin) { nxo = nx[jo]; nyo = ny[jo]; nxp = nx[jp]; nyp = ny[jp]; x1o =-((rx1-x1*sx)*nxo + (ry1-x1*sy)*nyo)*dsio-(sx*nxo+sy*nyo); x1p = ((rx1-x1*sx)*nxp + (ry1-x1*sy)*nyp)*dsio; x2o =-((rx2-x2*sx)*nxo + (ry2-x2*sy)*nyo)*dsio; x2p = ((rx2-x2*sx)*nxp + (ry2-x2*sy)*nyp)*dsio-(sx*nxp+sy*nyp); yyo = ((rx1+x1*sy)*nyo - (ry1-x1*sx)*nxo)*dsio-(sx*nyo-sy*nxo); yyp =-((rx1-x1*sy)*nyp - (ry1+x1*sx)*nxp)*dsio; } if (jo==n) goto stop11; if(siglin) { //------- set up midpoint quantities x0 = 0.5*(x1+x2); rs0 = x0*x0 + yy*yy; g0 = log(rs0); t0 = atan2(sgn*x0,sgn*yy) + (0.5- 0.5*sgn)*PI; //------- calculate source contribution to psi for 1-0 half-panel dxinv = 1.0/(x1-x0); psum = x0*(t0-apan) - x1*(t1-apan) + 0.5*yy*(g1-g0); pdif = ((x1+x0)*psum + rs1*(t1-apan) - rs0*(t0-apan)+ (x0-x1)*yy) * dxinv; psx1 = -(t1-apan); psx0 = t0-apan; psyy = 0.5*(g1-g0); pdx1 = ((x1+x0)*psx1 + psum + 2.0*x1*(t1-apan) - pdif) * dxinv; pdx0 = ((x1+x0)*psx0 + psum - 2.0*x0*(t0-apan) + pdif) * dxinv; pdyy = ((x1+x0)*psyy + 2.0*(x0-x1 + yy*(t1-t0)) ) * dxinv; dsm = sqrt((x[jp]-x[jm])*(x[jp]-x[jm]) + (y[jp]-y[jm])*(y[jp]-y[jm])); dsim = 1.0/dsm; ////ccc sig0 = (sig[jp] - sig[jo])*dsio ////ccc sig1 = (sig[jp] - sig[jm])*dsim ////ccc ssum = sig0 + sig1 ////ccc sdif = sig0 - sig1 ssum = (sig[jp] - sig[jo])*dsio + (sig[jp] - sig[jm])*dsim; sdif = (sig[jp] - sig[jo])*dsio - (sig[jp] - sig[jm])*dsim; psi = psi + qopi*(psum*ssum + pdif*sdif); //------- dpsi/dm dzdm[jm] = dzdm[jm] + qopi*(-psum*dsim + pdif*dsim); dzdm[jo] = dzdm[jo] + qopi*(-psum*dsio - pdif*dsio); dzdm[jp] = dzdm[jp] + qopi*( psum*(dsio+dsim) + pdif*(dsio-dsim)); //------- dpsi/dni psni = psx1*x1i + psx0*(x1i+x2i)*0.5 + psyy*yyi; pdni = pdx1*x1i + pdx0*(x1i+x2i)*0.5 + pdyy*yyi; psi_ni = psi_ni + qopi*(psni*ssum + pdni*sdif); qtanm = qtanm + qopi*(psni*ssum + pdni*sdif); dqdm[jm] = dqdm[jm] + qopi*(-psni*dsim + pdni*dsim); dqdm[jo] = dqdm[jo] + qopi*(-psni*dsio - pdni*dsio); dqdm[jp] = dqdm[jp] + qopi*( psni*(dsio+dsim)+ pdni*(dsio-dsim)); //------- calculate source contribution to psi for 0-2 half-panel dxinv = 1.0/(x0-x2); psum = x2*(t2-apan) - x0*(t0-apan) + 0.5*yy*(g0-g2); pdif = ((x0+x2)*psum + rs0*(t0-apan) - rs2*(t2-apan)+ (x2-x0)*yy) * dxinv; psx0 = -(t0-apan); psx2 = t2-apan; psyy = 0.5*(g0-g2); pdx0 = ((x0+x2)*psx0 + psum + 2.0*x0*(t0-apan) - pdif) * dxinv; pdx2 = ((x0+x2)*psx2 + psum - 2.0*x2*(t2-apan) + pdif) * dxinv; pdyy = ((x0+x2)*psyy + 2.0*(x2-x0 + yy*(t0-t2)) ) * dxinv; dsp = sqrt((x[jq]-x[jo])*(x[jq]-x[jo]) + (y[jq]-y[jo])*(y[jq]-y[jo])); dsip = 1.0/dsp; ////ccc sig2 = (sig[jq] - sig[jo])*dsip ////ccc sig0 = (sig[jp] - sig[jo])*dsio ////ccc ssum = sig2 + sig0 ////ccc sdif = sig2 - sig0 ssum = (sig[jq] - sig[jo])*dsip + (sig[jp] - sig[jo])*dsio; sdif = (sig[jq] - sig[jo])*dsip - (sig[jp] - sig[jo])*dsio; psi = psi + qopi*(psum*ssum + pdif*sdif); //------- dpsi/dm dzdm[jo] = dzdm[jo] + qopi*(-psum*(dsip+dsio)- pdif*(dsip-dsio)); dzdm[jp] = dzdm[jp] + qopi*( psum*dsio - pdif*dsio); dzdm[jq] = dzdm[jq] + qopi*( psum*dsip + pdif*dsip); //------- dpsi/dni psni = psx0*(x1i+x2i)*0.5 + psx2*x2i + psyy*yyi; pdni = pdx0*(x1i+x2i)*0.5 + pdx2*x2i + pdyy*yyi; psi_ni = psi_ni + qopi*(psni*ssum + pdni*sdif); qtanm = qtanm + qopi*(psni*ssum + pdni*sdif); dqdm[jo] = dqdm[jo] + qopi*(-psni*(dsip+dsio)- pdni*(dsip-dsio)); dqdm[jp] = dqdm[jp] + qopi*( psni*dsio - pdni*dsio); dqdm[jq] = dqdm[jq] + qopi*( psni*dsip + pdni*dsip); } //------ calculate vortex panel contribution to psi dxinv = 1.0/(x1-x2); psis = 0.5*x1*g1 - 0.5*x2*g2 + x2 - x1 + yy*(t1-t2); psid = ((x1+x2)*psis + 0.5*(rs2*g2-rs1*g1 + x1*x1-x2*x2))*dxinv; psx1 = 0.5*g1; psx2 = -.5*g2; psyy = t1-t2; pdx1 = ((x1+x2)*psx1 + psis - x1*g1 - psid)*dxinv; pdx2 = ((x1+x2)*psx2 + psis + x2*g2 + psid)*dxinv; pdyy = ((x1+x2)*psyy - yy*(g1-g2) )*dxinv; gsum1 = gamu[jp][1] + gamu[jo][1]; gsum2 = gamu[jp][2] + gamu[jo][2]; gdif1 = gamu[jp][1] - gamu[jo][1]; gdif2 = gamu[jp][2] - gamu[jo][2]; gsum = gam[jp] + gam[jo]; gdif = gam[jp] - gam[jo]; psi = psi + qopi*(psis*gsum + psid*gdif); //------ dpsi/dgam dzdg[jo] = dzdg[jo] + qopi*(psis-psid); dzdg[jp] = dzdg[jp] + qopi*(psis+psid); //------ dpsi/dni psni = psx1*x1i + psx2*x2i + psyy*yyi; pdni = pdx1*x1i + pdx2*x2i + pdyy*yyi; psi_ni = psi_ni + qopi*(gsum*psni + gdif*pdni); qtan1 = qtan1 + qopi*(gsum1*psni + gdif1*pdni); qtan2 = qtan2 + qopi*(gsum2*psni + gdif2*pdni); dqdg[jo] = dqdg[jo] + qopi*(psni - pdni); dqdg[jp] = dqdg[jp] + qopi*(psni + pdni); if(geolin) { //------- dpsi/dn dzdn[jo] = dzdn[jo]+ qopi*gsum*(psx1*x1o + psx2*x2o + psyy*yyo) + qopi*gdif*(pdx1*x1o + pdx2*x2o + pdyy*yyo); dzdn[jp] = dzdn[jp]+ qopi*gsum*(psx1*x1p + psx2*x2p + psyy*yyp) + qopi*gdif*(pdx1*x1p + pdx2*x2p + pdyy*yyp); //------- dpsi/dp z_qdof0 = z_qdof0 + qopi*((psis-psid)*qf0[jo] + (psis+psid)*qf0[jp]); z_qdof1 = z_qdof1 + qopi*((psis-psid)*qf1[jo] + (psis+psid)*qf1[jp]); z_qdof2 = z_qdof2 + qopi*((psis-psid)*qf2[jo] + (psis+psid)*qf2[jp]); z_qdof3 = z_qdof3 + qopi*((psis-psid)*qf3[jo] + (psis+psid)*qf3[jp]); } stop10: int nothing; nothing = 1; } stop11: psig = 0.5*yy*(g1-g2) + x2*(t2-apan) - x1*(t1-apan); pgam = 0.5*x1*g1 - 0.5*x2*g2 + x2 - x1 + yy*(t1-t2); psigx1 = -(t1-apan); psigx2 = t2-apan; psigyy = 0.5*(g1-g2); pgamx1 = 0.5*g1; pgamx2 = -.5*g2; pgamyy = t1-t2; psigni = psigx1*x1i + psigx2*x2i + psigyy*yyi; pgamni = pgamx1*x1i + pgamx2*x2i + pgamyy*yyi; //---- te panel source and vortex strengths sigte1 = 0.5*scs*(gamu[jp][1] - gamu[jo][1]); sigte2 = 0.5*scs*(gamu[jp][2] - gamu[jo][2]); gamte1 = -.5*sds*(gamu[jp][1] - gamu[jo][1]); gamte2 = -.5*sds*(gamu[jp][2] - gamu[jo][2]); sigte = 0.5*scs*(gam[jp] - gam[jo]); gamte = -.5*sds*(gam[jp] - gam[jo]); //---- te panel contribution to psi psi = psi + hopi*(psig*sigte + pgam*gamte); //---- dpsi/dgam dzdg[jo] = dzdg[jo] - hopi*psig*scs*0.5; dzdg[jp] = dzdg[jp] + hopi*psig*scs*0.5; dzdg[jo] = dzdg[jo] + hopi*pgam*sds*0.5; dzdg[jp] = dzdg[jp] - hopi*pgam*sds*0.5; //---- dpsi/dni psi_ni = psi_ni + hopi*(psigni*sigte + pgamni*gamte); qtan1 = qtan1 + hopi*(psigni*sigte1 + pgamni*gamte1); qtan2 = qtan2 + hopi*(psigni*sigte2 + pgamni*gamte2); dqdg[jo] = dqdg[jo] - hopi*(psigni*0.5*scs - pgamni*0.5*sds); dqdg[jp] = dqdg[jp] + hopi*(psigni*0.5*scs - pgamni*0.5*sds); if(geolin) { //----- dpsi/dn dzdn[jo] = dzdn[jo] + hopi*(psigx1*x1o + psigx2*x2o + psigyy*yyo)*sigte + hopi*(pgamx1*x1o + pgamx2*x2o + pgamyy*yyo)*gamte; dzdn[jp] = dzdn[jp] + hopi*(psigx1*x1p + psigx2*x2p + psigyy*yyp)*sigte + hopi*(pgamx1*x1p + pgamx2*x2p + pgamyy*yyp)*gamte; //----- dpsi/dp z_qdof0 = z_qdof0 + hopi*psig*0.5*(qf0[jp]-qf0[jo])*scs - hopi*pgam*0.5*(qf0[jp]-qf0[jo])*sds; z_qdof1 = z_qdof1 + hopi*psig*0.5*(qf1[jp]-qf1[jo])*scs - hopi*pgam*0.5*(qf1[jp]-qf1[jo])*sds; z_qdof2 = z_qdof2 + hopi*psig*0.5*(qf2[jp]-qf2[jo])*scs - hopi*pgam*0.5*(qf2[jp]-qf2[jo])*sds; z_qdof3 = z_qdof3 + hopi*psig*0.5*(qf3[jp]-qf3[jo])*scs - hopi*pgam*0.5*(qf3[jp]-qf3[jo])*sds; } stop12: //**** freestream terms psi = psi + qinf*(cosa*yi - sina*xi); //---- dpsi/dn psi_ni = psi_ni + qinf*(cosa*nyi - sina*nxi); qtan1 = qtan1 + qinf*nyi; qtan2 = qtan2 - qinf*nxi; //---- dpsi/dqinf z_qinf = z_qinf + (cosa*yi - sina*xi); //---- dpsi/dalfa z_alfa = z_alfa - qinf*(sina*yi + cosa*xi); if(!limage) return false; for(jo=1;jo<= n;jo++) {//stop20 jp = jo+1; jm = jo-1; jq = jp+1; if(jo==1) jm = jo; else { if(jo==n-1) jq = jp; else { if(jo==n) jp = 1; if((x[jo]-x[jp])*(x[jo]-x[jp]) + (y[jo]-y[jp])*(y[jo]-y[jp]) < seps*seps) goto stop22; } } dso = sqrt((x[jo]-x[jp])*(x[jo]-x[jp]) + (y[jo]-y[jp])*(y[jo]-y[jp])); //------ skip null panel if(dso == 0.0) goto stop20; // check - unsafe condition dsio = 1.0 / dso; ////ccc apan = apanel[jo] apan = PI - apanel[jo] + 2.0*alfa; xjo = x[jo] + 2.0*(yimage+y[jo])*sina; yjo = y[jo] - 2.0*(yimage+y[jo])*cosa; xjp = x[jp] + 2.0*(yimage+y[jp])*sina; yjp = y[jp] - 2.0*(yimage+y[jp])*cosa; rx1 = xi - xjo; ry1 = yi - yjo; rx2 = xi - xjp; ry2 = yi - yjp; sx = (xjp - xjo) * dsio; sy = (yjp - yjo) * dsio; x1 = sx*rx1 + sy*ry1; x2 = sx*rx2 + sy*ry2; yy = sx*ry1 - sy*rx1; rs1 = rx1*rx1 + ry1*ry1; rs2 = rx2*rx2 + ry2*ry2; //------ set reflection flag sgn to avoid branch problems with arctan if(io>=1 && io<=n) { //------- no problem on airfoil surface sgn = 1.0; } else { //------- make sure arctan falls between -/+ pi/2 sgn = sign(1.0,yy); } //------ set log(r^2) and arctan(x/y), correcting for reflection if any g1 = log(rs1); t1 = atan2(sgn*x1,sgn*yy) + (0.5 - 0.5*sgn)*PI; g2 = log(rs2); t2 = atan2(sgn*x2,sgn*yy) + (0.5 - 0.5*sgn)*PI; x1i = sx*nxi + sy*nyi; x2i = sx*nxi + sy*nyi; yyi = sx*nyi - sy*nxi; if(geolin) { nxo = nx[jo]; nyo = ny[jo]; nxp = nx[jp]; nyp = ny[jp]; x1o =-((rx1-x1*sx)*nxo + (ry1-x1*sy)*nyo)*dsio-(sx*nxo+sy*nyo); x1p = ((rx1-x1*sx)*nxp + (ry1-x1*sy)*nyp)*dsio; x2o =-((rx2-x2*sx)*nxo + (ry2-x2*sy)*nyo)*dsio; x2p = ((rx2-x2*sx)*nxp + (ry2-x2*sy)*nyp)*dsio-(sx*nxp+sy*nyp); yyo = ((rx1+x1*sy)*nyo - (ry1-x1*sx)*nxo)*dsio-(sx*nyo-sy*nxo); yyp =-((rx1-x1*sy)*nyp - (ry1+x1*sx)*nxp)*dsio; } if(jo==n) goto stop21; if(siglin) { //------- set up midpoint quantities x0 = 0.5*(x1+x2); rs0 = x0*x0 + yy*yy; g0 = log(rs0); t0 = atan2(sgn*x0,sgn*yy) + (0.5 - 0.5*sgn)*PI; //------- calculate source contribution to psi for 1-0 half-panel dxinv = 1.0/(x1-x0); psum = x0*(t0-apan) - x1*(t1-apan) + 0.5*yy*(g1-g0); pdif = ((x1+x0)*psum + rs1*(t1-apan) - rs0*(t0-apan) + (x0-x1)*yy) * dxinv; psx1 = -(t1-apan); psx0 = t0-apan; psyy = 0.5*(g1-g0); pdx1 = ((x1+x0)*psx1 + psum + 2.0*x1*(t1-apan) - pdif) * dxinv; pdx0 = ((x1+x0)*psx0 + psum - 2.0*x0*(t0-apan) + pdif) * dxinv; pdyy = ((x1+x0)*psyy + 2.0*(x0-x1 + yy*(t1-t0)) ) * dxinv; dsm = sqrt((x[jp]-x[jm])*(x[jp]-x[jm]) + (y[jp]-y[jm])*(y[jp]-y[jm])); dsim = 1.0/dsm; ////ccc sig0 = (sig[jp] - sig[jo])*dsio ////ccc sig1 = (sig[jp] - sig[jm])*dsim ////ccc ssum = sig0 + sig1 ////ccc sdif = sig0 - sig1 ssum = (sig[jp] - sig[jo])*dsio + (sig[jp] - sig[jm])*dsim; sdif = (sig[jp] - sig[jo])*dsio - (sig[jp] - sig[jm])*dsim; psi = psi + qopi*(psum*ssum + pdif*sdif); //------- dpsi/dm dzdm[jm] = dzdm[jm] + qopi*(-psum*dsim + pdif*dsim); dzdm[jo] = dzdm[jo] + qopi*(-psum*dsio - pdif*dsio); dzdm[jp] = dzdm[jp] + qopi*( psum*(dsio+dsim)+ pdif*(dsio-dsim)); //------- dpsi/dni psni = psx1*x1i + psx0*(x1i+x2i)*0.5+ psyy*yyi; pdni = pdx1*x1i + pdx0*(x1i+x2i)*0.5+ pdyy*yyi; psi_ni = psi_ni + qopi*(psni*ssum + pdni*sdif); qtanm = qtanm + qopi*(psni*ssum + pdni*sdif); dqdm[jm] = dqdm[jm] + qopi*(-psni*dsim + pdni*dsim); dqdm[jo] = dqdm[jo] + qopi*(-psni*dsio - pdni*dsio); dqdm[jp] = dqdm[jp] + qopi*( psni*(dsio+dsim)+ pdni*(dsio-dsim)); //------- calculate source contribution to psi for 0-2 half-panel dxinv = 1.0/(x0-x2); psum = x2*(t2-apan) - x0*(t0-apan) + 0.5*yy*(g0-g2); pdif = ((x0+x2)*psum + rs0*(t0-apan) - rs2*(t2-apan) + (x2-x0)*yy) * dxinv; psx0 = -(t0-apan); psx2 = t2-apan; psyy = 0.5*(g0-g2); pdx0 = ((x0+x2)*psx0 + psum + 2.0*x0*(t0-apan) - pdif) * dxinv; pdx2 = ((x0+x2)*psx2 + psum - 2.0*x2*(t2-apan) + pdif) * dxinv; pdyy = ((x0+x2)*psyy + 2.0*(x2-x0 + yy*(t0-t2)) ) * dxinv; dsp = sqrt((x[jq]-x[jo])*(x[jq]-x[jo]) + (y[jq]-y[jo])*(y[jq]-y[jo])); dsip = 1.0/dsp; ////ccc sig2 = (sig[jq] - sig[jo])*dsip ////ccc sig0 = (sig[jp] - sig[jo])*dsio ////ccc ssum = sig2 + sig0 ////ccc sdif = sig2 - sig0 ssum = (sig[jq] - sig[jo])*dsip + (sig[jp] - sig[jo])*dsio; sdif = (sig[jq] - sig[jo])*dsip - (sig[jp] - sig[jo])*dsio; psi = psi + qopi*(psum*ssum + pdif*sdif); //------- dpsi/dm dzdm[jo] = dzdm[jo] + qopi*(-psum*(dsip+dsio)- pdif*(dsip-dsio)); dzdm[jp] = dzdm[jp] + qopi*( psum*dsio - pdif*dsio); dzdm[jq] = dzdm[jq] + qopi*( psum*dsip + pdif*dsip); //------- dpsi/dni psni = psx0*(x1i+x2i)*0.5 + psx2*x2i + psyy*yyi; pdni = pdx0*(x1i+x2i)*0.5 + pdx2*x2i + pdyy*yyi; psi_ni = psi_ni + qopi*(psni*ssum + pdni*sdif); qtanm = qtanm + qopi*(psni*ssum + pdni*sdif); dqdm[jo] = dqdm[jo] + qopi*(-psni*(dsip+dsio)- pdni*(dsip-dsio)); dqdm[jp] = dqdm[jp] + qopi*( psni*dsio - pdni*dsio); dqdm[jq] = dqdm[jq] + qopi*( psni*dsip + pdni*dsip); } //------ calculate vortex panel contribution to psi dxinv = 1.0/(x1-x2); psis = 0.5*x1*g1 - 0.5*x2*g2 + x2 - x1 + yy*(t1-t2); psid = ((x1+x2)*psis + 0.5*(rs2*g2-rs1*g1 + x1*x1-x2*x2))*dxinv; psx1 = 0.5*g1; psx2 = -.5*g2; psyy = t1-t2; pdx1 = ((x1+x2)*psx1 + psis - x1*g1 - psid)*dxinv; pdx2 = ((x1+x2)*psx2 + psis + x2*g2 + psid)*dxinv; pdyy = ((x1+x2)*psyy - yy*(g1-g2) )*dxinv; gsum1 = gamu[jp][1] + gamu[jo][1]; gsum2 = gamu[jp][2] + gamu[jo][2]; gdif1 = gamu[jp][1] - gamu[jo][1]; gdif2 = gamu[jp][2] - gamu[jo][2]; gsum = gam[jp] + gam[jo]; gdif = gam[jp] - gam[jo]; psi = psi - qopi*(psis*gsum + psid*gdif); //------ dpsi/dgam dzdg[jo] = dzdg[jo] - qopi*(psis-psid); dzdg[jp] = dzdg[jp] - qopi*(psis+psid); //------ dpsi/dni psni = psx1*x1i + psx2*x2i + psyy*yyi; pdni = pdx1*x1i + pdx2*x2i + pdyy*yyi; psi_ni = psi_ni - qopi*(gsum*psni + gdif*pdni); qtan1 = qtan1 - qopi*(gsum1*psni + gdif1*pdni); qtan2 = qtan2 - qopi*(gsum2*psni + gdif2*pdni); dqdg[jo] = dqdg[jo] - qopi*(psni - pdni); dqdg[jp] = dqdg[jp] - qopi*(psni + pdni); if(geolin) { //------- dpsi/dn dzdn[jo] = dzdn[jo]- qopi*gsum*(psx1*x1o + psx2*x2o + psyy*yyo) - qopi*gdif*(pdx1*x1o + pdx2*x2o + pdyy*yyo); dzdn[jp] = dzdn[jp]- qopi*gsum*(psx1*x1p + psx2*x2p + psyy*yyp) - qopi*gdif*(pdx1*x1p + pdx2*x2p + pdyy*yyp); //------- dpsi/dp z_qdof0 = z_qdof0- qopi*((psis-psid)*qf0[jo] + (psis+psid)*qf0[jp]); z_qdof1 = z_qdof1- qopi*((psis-psid)*qf1[jo] + (psis+psid)*qf1[jp]); z_qdof2 = z_qdof2- qopi*((psis-psid)*qf2[jo] + (psis+psid)*qf2[jp]); z_qdof3 = z_qdof3- qopi*((psis-psid)*qf3[jo] + (psis+psid)*qf3[jp]); } stop20: int nothing; nothing = 1; } stop21: psig = 0.5*yy*(g1-g2) + x2*(t2-apan) - x1*(t1-apan); pgam = 0.5*x1*g1 - 0.5*x2*g2 + x2 - x1 + yy*(t1-t2); psigx1 = -(t1-apan); psigx2 = t2-apan; psigyy = 0.5*(g1-g2); pgamx1 = 0.5*g1; pgamx2 = -.5*g2; pgamyy = t1-t2; psigni = psigx1*x1i + psigx2*x2i + psigyy*yyi; pgamni = pgamx1*x1i + pgamx2*x2i + pgamyy*yyi; //---- te panel source and vortex strengths sigte1 = 0.5*scs*(gamu[jp][1] - gamu[jo][1]); sigte2 = 0.5*scs*(gamu[jp][2] - gamu[jo][2]); gamte1 = -.5*sds*(gamu[jp][1] - gamu[jo][1]); gamte2 = -.5*sds*(gamu[jp][2] - gamu[jo][2]); sigte = 0.5*scs*(gam[jp] - gam[jo]); gamte = -.5*sds*(gam[jp] - gam[jo]); //---- te panel contribution to psi psi = psi + hopi*(psig*sigte - pgam*gamte); //---- dpsi/dgam dzdg[jo] = dzdg[jo] - hopi*psig*scs*0.5; dzdg[jp] = dzdg[jp] + hopi*psig*scs*0.5; dzdg[jo] = dzdg[jo] - hopi*pgam*sds*0.5; dzdg[jp] = dzdg[jp] + hopi*pgam*sds*0.5; //---- dpsi/dni psi_ni = psi_ni + hopi*(psigni*sigte - pgamni*gamte); qtan1 = qtan1 + hopi*(psigni*sigte1 - pgamni*gamte1); qtan2 = qtan2 + hopi*(psigni*sigte2 - pgamni*gamte2); dqdg[jo] = dqdg[jo] - hopi*(psigni*0.5*scs + pgamni*0.5*sds); dqdg[jp] = dqdg[jp] + hopi*(psigni*0.5*scs + pgamni*0.5*sds); if(geolin) { //----- dpsi/dn dzdn[jo] = dzdn[jo] + hopi*(psigx1*x1o + psigx2*x2o + psigyy*yyo)*sigte - hopi*(pgamx1*x1o + pgamx2*x2o + pgamyy*yyo)*gamte; dzdn[jp] = dzdn[jp] + hopi*(psigx1*x1p + psigx2*x2p + psigyy*yyp)*sigte - hopi*(pgamx1*x1p + pgamx2*x2p + pgamyy*yyp)*gamte; //----- dpsi/dp z_qdof0 = z_qdof0 + hopi*psig*0.5*(qf0[jp]-qf0[jo])*scs + hopi*pgam*0.5*(qf0[jp]-qf0[jo])*sds; z_qdof1 = z_qdof1 + hopi*psig*0.5*(qf1[jp]-qf1[jo])*scs + hopi*pgam*0.5*(qf1[jp]-qf1[jo])*sds; z_qdof2 = z_qdof2 + hopi*psig*0.5*(qf2[jp]-qf2[jo])*scs + hopi*pgam*0.5*(qf2[jp]-qf2[jo])*sds; z_qdof3 = z_qdof3 + hopi*psig*0.5*(qf3[jp]-qf3[jo])*scs + hopi*pgam*0.5*(qf3[jp]-qf3[jo])*sds; } stop22: return true; } bool XFoil::pswlin(int i, double xi, double yi, double nxi, double nyi, double &psi, double &psi_ni){ //-------------------------------------------------------------------- // calculates current streamfunction psi and tangential velocity // qtan at panel node or wake node i due to freestream and wake // sources sig. also calculates sensitivity vectors dpsi/dsig // (dzdm) and dqtan/dsig (dqdm). // // airfoil: 1 < i < n // wake: n+1 < i < n+nw //-------------------------------------------------------------------- double g1,g2,t1,t2; double x1i, x2i, yyi, x0,rs0,g0,t0; double dso, dsio, apan, rx1, rx2, ry1, ry2; double sx, sy, x1, x2, yy, rs1, rs2, sgn; double dxinv, psum, pdif, psx1, psx0, psyy, pdx1, pdx0, pdyy; double dsm, dsim, ssum, sdif, psni, pdni, psx2, pdx2, dsp, dsip; //double nxi, nyi; int io,jo; io = i; cosa = cos(alfa); sina = sin(alfa); for(jo=n+1;jo<= n+nw;jo++) { dzdm[jo] = 0.0; dqdm[jo] = 0.0; } psi = 0.0; psi_ni = 0.0; for(jo=n+1;jo<= n+nw-1;jo++) { int jp = jo+1; int jm = jo-1; int jq = jp+1; if(jo==n+1) { jm = jo; } else { if(jo==n+nw-1) jq = jp; } dso = sqrt((x[jo]-x[jp])*(x[jo]-x[jp]) + (y[jo]-y[jp])* (y[jo]-y[jp])); dsio = 1.0 / dso; apan = apanel[jo]; rx1 = xi - x[jo]; ry1 = yi - y[jo]; rx2 = xi - x[jp]; ry2 = yi - y[jp]; sx = (x[jp] - x[jo]) * dsio; sy = (y[jp] - y[jo]) * dsio; x1 = sx*rx1 + sy*ry1; x2 = sx*rx2 + sy*ry2; yy = sx*ry1 - sy*rx1; rs1 = rx1*rx1 + ry1*ry1; rs2 = rx2*rx2 + ry2*ry2; sgn =1.0; if(io>=n+1 && io<=n+nw) { sgn = 1.0; } else { sgn = sign(1.0,yy); } if(io!=jo && rs1>0.0) { g1 = log(rs1); t1 = atan2(sgn*x1,sgn*yy) - (0.5- 0.5*sgn)*PI; } else { g1 = 0.0; t1 = 0.0; } if(io!=jp && rs2>0.0) { g2 = log(rs2); t2 = atan2(sgn*x2,sgn*yy) - (0.5- 0.5*sgn)*PI; } else { g2 = 0.0; t2 = 0.0; } x1i = sx*nxi + sy*nyi; x2i = sx*nxi + sy*nyi; yyi = sx*nyi - sy*nxi; //------- set up midpoint quantities x0 = 0.5*(x1+x2); rs0 = x0*x0 + yy*yy; g0 = log(rs0); t0 = atan2(sgn*x0,sgn*yy) - (0.5- 0.5*sgn)*PI; //------- calculate source contribution to psi for 1-0 half-panel dxinv = 1.0/(x1-x0); psum = x0*(t0-apan) - x1*(t1-apan) + 0.5*yy*(g1-g0); pdif = ((x1+x0)*psum + rs1*(t1-apan) - rs0*(t0-apan) + (x0-x1)*yy) * dxinv; psx1 = -(t1-apan); psx0 = t0-apan; psyy = 0.5*(g1-g0); pdx1 = ((x1+x0)*psx1 + psum + 2.0*x1*(t1-apan) - pdif) * dxinv; pdx0 = ((x1+x0)*psx0 + psum - 2.0*x0*(t0-apan) + pdif) * dxinv; pdyy = ((x1+x0)*psyy + 2.0*(x0-x1 + yy*(t1-t0)) ) * dxinv; dsm = sqrt((x[jp]-x[jm])*(x[jp]-x[jm]) + (y[jp]-y[jm])*(y[jp]-y[jm])); dsim = 1.0/dsm; ////ccc sig0 = (sig[jp] - sig[jo])*dsio ////ccc sig1 = (sig[jp] - sig[jm])*dsim ////ccc ssum = sig0 + sig1 ////ccc sdif = sig0 - sig1 ssum = (sig[jp] - sig[jo])*dsio + (sig[jp] - sig[jm])*dsim; sdif = (sig[jp] - sig[jo])*dsio - (sig[jp] - sig[jm])*dsim; psi = psi + qopi*(psum*ssum + pdif*sdif); //------- dpsi/dm dzdm[jm] = dzdm[jm] + qopi*(-psum*dsim + pdif*dsim); dzdm[jo] = dzdm[jo] + qopi*(-psum*dsio - pdif*dsio); dzdm[jp] = dzdm[jp] + qopi*( psum*(dsio+dsim) + pdif*(dsio-dsim)); //------- dpsi/dni psni = psx1*x1i + psx0*(x1i+x2i)*0.5+ psyy*yyi; pdni = pdx1*x1i + pdx0*(x1i+x2i)*0.5+ pdyy*yyi; psi_ni = psi_ni + qopi*(psni*ssum + pdni*sdif); dqdm[jm] = dqdm[jm] + qopi*(-psni*dsim + pdni*dsim); dqdm[jo] = dqdm[jo] + qopi*(-psni*dsio - pdni*dsio); dqdm[jp] = dqdm[jp] + qopi*( psni*(dsio+dsim)+ pdni*(dsio-dsim)); //------- calculate source contribution to psi for 0-2 half-panel dxinv = 1.0/(x0-x2); psum = x2*(t2-apan) - x0*(t0-apan) + 0.5*yy*(g0-g2); pdif = ((x0+x2)*psum + rs0*(t0-apan) - rs2*(t2-apan)+ (x2-x0)*yy) * dxinv; psx0 = -(t0-apan); psx2 = t2-apan; psyy = 0.5*(g0-g2); pdx0 = ((x0+x2)*psx0 + psum + 2.0*x0*(t0-apan) - pdif) * dxinv; pdx2 = ((x0+x2)*psx2 + psum - 2.0*x2*(t2-apan) + pdif) * dxinv; pdyy = ((x0+x2)*psyy + 2.0*(x2-x0 + yy*(t0-t2)) ) * dxinv; dsp = sqrt((x[jq]-x[jo])*(x[jq]-x[jo]) + (y[jq]-y[jo])*(y[jq]-y[jo])); dsip = 1.0/dsp; ////ccc sig2 = (sig[jq] - sig[jo])*dsip ////ccc sig0 = (sig[jp] - sig[jo])*dsio ////ccc ssum = sig2 + sig0 ////ccc sdif = sig2 - sig0 ssum = (sig[jq] - sig[jo])*dsip + (sig[jp] - sig[jo])*dsio; sdif = (sig[jq] - sig[jo])*dsip - (sig[jp] - sig[jo])*dsio; psi = psi + qopi*(psum*ssum + pdif*sdif); //------- dpsi/dm dzdm[jo] = dzdm[jo] + qopi*(-psum*(dsip+dsio)- pdif*(dsip-dsio)); dzdm[jp] = dzdm[jp] + qopi*( psum*dsio - pdif*dsio); dzdm[jq] = dzdm[jq] + qopi*( psum*dsip + pdif*dsip); //------- dpsi/dni psni = psx0*(x1i+x2i)*0.5+ psx2*x2i + psyy*yyi; pdni = pdx0*(x1i+x2i)*0.5+ pdx2*x2i + pdyy*yyi; psi_ni = psi_ni + qopi*(psni*ssum + pdni*sdif); dqdm[jo] = dqdm[jo] + qopi*(-psni*(dsip+dsio)- pdni*(dsip-dsio)); dqdm[jp] = dqdm[jp] + qopi*( psni*dsio - pdni*dsio); dqdm[jq] = dqdm[jq] + qopi*( psni*dsip + pdni*dsip); } return true; } bool XFoil::qdcalc() { //----------------------------------------------------- // calculates source panel influence coefficient // matrix for current airfoil and wake geometry. //----------------------------------------------------- int i, j, k, iu, iw; double psi, psi_n, sum; double bbb[IQX]; //TRACE("calculating source influence matrix ...\n"); QString str = QObject::tr(" Calculating source influence matrix ...\n"); WriteString(str); if(!ladij) { //----- calculate source influence matrix for airfoil surface if it doesn't exist for (j=1; j<= n;j++) { //------- multiply each dpsi/sig vector by inverse of factored dpsi/dgam matrix for (iu=0; iuiblte[is]); tran = (ibl==itran[is]); turb = (ibl>itran[is]); i = ipan[ibl][is]; //---- set primary variables for current station xsi = xssi[ibl][is]; if(ibl0.3) { QString str(QObject::tr("scheck: bad value for small panels (stol > 0.3)\n")); WriteString(str, true); return; } // 10 for (i = 2; i<= *n-2; i++) { im1 = i-1; ip1 = i+1; ip2 = i+2; dxm1 = x[i] - x[i-1]; dym1 = y[i] - y[i-1]; dsm1 = sqrt(dxm1*dxm1 + dym1*dym1); dxp1 = x[i+1] - x[i]; dyp1 = y[i+1] - y[i]; dsp1 = sqrt(dxp1*dxp1 + dyp1*dyp1); dxp2 = x[i+2] - x[i+1]; dyp2 = y[i+2] - y[i+1]; dsp2 = sqrt(dxp2*dxp2 + dyp2*dyp2); //------- don't mess with doubled points (slope breaks) if(dsp1>=0.00001) {//go to 20 if(dsp11) { imid = (int)((i+ilow)/2); if(ss < s[imid]) i = imid; else ilow = imid; } ds = s[i] - s[i-1]; t = (ss - s[i-1]) / ds; cx1 = ds*xs[i-1] - x[i] + x[i-1]; cx2 = ds*xs[i] - x[i] + x[i-1]; return t*x[i] + (1.0-t)*x[i-1] + (t-t*t)*((1.0-t)*cx1 - t*cx2); } double XFoil::sign(double a, double b){ // returns the absolute value of "a" x sign(b) if(b>=0.0) return qAbs(a); else return -qAbs(a); } bool XFoil::sinvrt(double &si, double xi, double x[], double xs[], double s[], int n) { //------------------------------------------------------- // calculates the "inverse" spline function s(x). | // since s(x) can be multi-valued or not defined, | // this is not a "black-box" routine. the ing | // program must pass via si a sufficiently good | // initial guess for s(xi). | // | // xi specified x value (input) | // si calculated s(xi) value (input,output) | // x,xs,s usual spline arrays (input) | // | //------------------------------------------------------- int iter; double sisav, res,resp,ds; sisav = si; for(iter=1;iter<= 10;iter++) { res = seval(si,x,xs,s,n) - xi; resp = deval(si,x,xs,s,n); ds = -res/resp; si = si + ds; if(qAbs(ds/(s[n]-s[1]))< 1.0e-5) return true; } QString str = QObject::tr("Sinvrt: spline inversion failed, input value returned\n"); WriteString(str, true); si = sisav; return false; } bool XFoil::specal() { //----------------------------------- // converges to specified alpha. //----------------------------------- double minf_clm, msq_clm, reinf_clm; double clm, dclm, clm1; int i, irlx, itcl; //---- calculate surface vorticity distributions for alpha = 0, 90 degrees if(!lgamu || !lqaij) ggcalc(); cosa = cos(alfa); sina = sin(alfa); //---- superimpose suitably weighted alpha = 0, 90 distributions for (i=1; i<= n; i++){ gam[i] = cosa*gamu[i][1] + sina*gamu[i][2]; gam_a[i] = -sina*gamu[i][1] + cosa*gamu[i][2]; } psio = cosa*gamu[n+1][1] + sina*gamu[n+1][2]; tecalc(); qiset(); //---- set initial guess for the newton variable clm clm = 1.0; //---- set corresponding m(clm), re(clm) mrcl(clm,minf_clm,reinf_clm); comset(); //---- set corresponding cl(m) clcalc(xcmref,ycmref); //---- iterate on clm bool bConv = false; for (itcl=1; itcl<= 20;itcl++){ msq_clm = 2.0*minf*minf_clm; dclm = (cl - clm)/(1.0 - cl_msq*msq_clm); clm1 = clm; rlx = 1.0; //------ under-relaxation loop to avoid driving m(cl) above 1 for (irlx=1; irlx<=12; irlx++){ clm = clm1 + rlx*dclm; //-------- set new freestream mach m(clm) mrcl(clm,minf_clm,reinf_clm); //-------- if mach is ok, go do next newton iteration if(matyp==1 || minf==0.0 || minf_clm!=0.0) break;// goto 91 rlx = 0.5*rlx; } //------ set new cl(m) comset(); clcalc(xcmref,ycmref); if(qAbs(dclm)<=1.0e-6) { bConv = true; break; } } if(!bConv) { QString str(QObject::tr("Specal: MInf convergence failed\n")); WriteString(str, true); return false; } //---- set final mach, cl, cp distributions, and hinge moment mrcl(cl,minf_cl,reinf_cl); comset(); clcalc(xcmref,ycmref); /* if (!cpcalc(n,qinv,qinf,minf,cpi)) return false;// no need to carry on if(lvisc) { if(!cpcalc(n+nw,qvis,qinf,minf,cpv)) return false;// no need to carry on if(!cpcalc(n+nw,qinv,qinf,minf,cpi)) return false;// no need to carry on } else if (!cpcalc(n,qinv,qinf,minf,cpi)) return false;// no need to carry on */ cpcalc(n,qinv,qinf,minf,cpi); if(lvisc) { cpcalc(n+nw,qvis,qinf,minf,cpv); cpcalc(n+nw,qinv,qinf,minf,cpi); } else cpcalc(n,qinv,qinf,minf,cpi); if(lflap) mhinge(); //Added arcds to get inviscid q after viscous calculation for (i=1; i<= n; i++){ qgamm[i] = gam[i]; } // end arcds addition return true; } bool XFoil::speccl(){ //----------------------------------------- // converges to specified inviscid cl. //----------------------------------------- double dalfa; int i, ital; //---- calculate surface vorticity distributions for alpha = 0, 90 degrees if(!lgamu || !lqaij) ggcalc(); //---- set freestream mach from specified cl -- mach will be held fixed mrcl(clspec,minf_cl,reinf_cl); comset(); //---- current alpha is the initial guess for newton variable alfa cosa = cos(alfa); sina = sin(alfa); for (i=1; i<=n; i++){ gam[i] = cosa*gamu[i][1] + sina*gamu[i][2]; gam_a[i] = -sina*gamu[i][1] + cosa*gamu[i][2]; } psio = cosa*gamu[n+1][1] + sina*gamu[n+1][2]; //---- get corresponding cl, cl_alpha, cl_mach clcalc(xcmref,ycmref); //---- newton loop for alpha to get specified inviscid cl bool bConv = false; for(ital=1;ital<= 20; ital++){ dalfa = (clspec - cl) / cl_alf; rlx = 1.0; alfa = alfa + rlx*dalfa; //------ set new surface speed distribution cosa = cos(alfa); sina = sin(alfa); for (i=1; i<= n; i++){ gam[i] = cosa*gamu[i][1] + sina*gamu[i][2]; gam_a[i] = -sina*gamu[i][1] + cosa*gamu[i][2]; } psio = cosa*gamu[n+1][1] + sina*gamu[n+1][2]; //------ set new cl(alpha) clcalc(xcmref,ycmref); if(qAbs(dalfa)<=1.0e-6){ bConv = true; break; } } if(!bConv) { QString str = QObject::tr("Speccl: cl convergence failed"); WriteString(str, true); return false; } //---- set final surface speed and cp distributions tecalc(); qiset(); /* if(lvisc) { if(!cpcalc(n+nw,qvis,qinf,minf,cpv)){ return false; } if(!cpcalc(n+nw,qinv,qinf,minf,cpi)){ return false; } } else{ if(!cpcalc(n,qinv,qinf,minf,cpi)){ return false; } } */ if(lvisc) { cpcalc(n+nw,qvis,qinf,minf,cpv); cpcalc(n+nw,qinv,qinf,minf,cpi); } else{ cpcalc(n,qinv,qinf,minf,cpi); } if(lflap) mhinge(); return true; } void XFoil::splina(double x[], double xs[], double s[], int n) { // dimension x(n),xs(n),s(n) bool lend; double ds, dx, xs1, xs2; xs1 = xs2 = 0.0; //------------------------------------------------------- // calculates spline coefficients for x(s). | // a simple averaging of adjacent segment slopes | // is used to achieve non-oscillatory curve | // end conditions are set by end segment slope | // to evaluate the spline at some value of s, | // use seval and/or deval. | // | // s independent variable array (input) | // x dependent variable array (input) | // xs dx/ds array (calculated) | // n number of points (input) | // | //------------------------------------------------------- lend = true; for (int i=1; i<= n-1; i++) { ds = s[i+1]-s[i]; if (qAbs(ds)<1.e-10) {//=0.0 xs[i] = xs1; lend = true; } else { dx = x[i+1]-x[i]; xs2 = dx / ds; if (lend) { xs[i] = xs2; lend = false; } else xs[i] = 0.5*(xs1 + xs2); } xs1 = xs2; } xs[n] = xs1; } bool XFoil::splind(double x[], double xs[], double s[], int n, double xs1, double xs2) { int nmax=600; double a[601],b[601],c[601]; //------------------------------------------------------- // calculates spline coefficients for x(s). | // specified 1st derivative and/or usual zero 2nd | // derivative end conditions are used. | // to evaluate the spline at some value of s, | // use seval and/or deval. | // | // s independent variable array (input) | // x dependent variable array (input) | // xs dx/ds array (calculated) | // n number of points (input) | // xs1,xs2 endpoint derivatives (input) | // if = 999.0, then usual zero second | // derivative end condition(s) are used | // if = -999.0, then zero third | // derivative end condition(s) are used | // | //------------------------------------------------------- double dsm, dsp; if(n>nmax) { QString str = QObject::tr("splind: array overflow, increase nmax"); WriteString(str, true); return false; } for(int i=2; i<= n-1;i++) { dsm = s[i] - s[i-1]; dsp = s[i+1] - s[i]; b[i] = dsp; a[i] = 2.0*(dsm+dsp); c[i] = dsm; xs[i] = 3.0*((x[i+1]-x[i])*dsm/dsp + (x[i]-x[i-1])*dsp/dsm); } if(xs1>=998.0) { //----- set zero second derivative end condition a[1] = 2.0; c[1] = 1.0; xs[1] = 3.0*(x[2]-x[1]) / (s[2]-s[1]); } else { if(xs1<=-998.0) { //----- set zero third derivative end condition a[1] = 1.0; c[1] = 1.0; xs[1] = 2.0*(x[2]-x[1]) / (s[2]-s[1]); } else{ //----- set specified first derivative end condition a[1] = 1.0; c[1] = 0.0; xs[1] = xs1; } } if(xs2>=998.0) { b[n] = 1.0; a[n] = 2.0; xs[n] = 3.0*(x[n]-x[n-1]) / (s[n]-s[n-1]); } else{ if(xs2<=-998.0) { b[n] = 1.0; a[n] = 1.0; xs[n] = 2.0*(x[n]-x[n-1]) / (s[n]-s[n-1]); } else{ a[n] = 1.0; b[n] = 0.0; xs[n] = xs2; } } if(n==2 && xs1<=-998.0 && xs2<=-998.0) { b[n] = 1.0; a[n] = 2.0; xs[n] = 3.0*(x[n]-x[n-1]) / (s[n]-s[n-1]); } //---- solve for derivative array xs trisol(a,b,c,xs,n); return true; } void XFoil::sss(double ss, double *s1, double *s2, double del, double xbf, double ybf, double x[], double xp[], double y[], double yp[], double s[], int n, int iside){ // dimension x(*),xp(*),y(*),yp(*),s(*) //---------------------------------------------------------------- // returns arc length points s1,s2 at flap surface break // locations. s1 is on fixed airfoil part, s2 is on flap. // the points are defined according to two cases: // // // if del > 0: surface will be eliminated in s1 < s < s2 // // returns the arc length values s1,s2 of the endpoints // of the airfoil surface segment which "disappears" as a // result of the flap deflection. the line segments between // these enpoints and the flap hinge point (xbf,ybf) have // an included angle of del. del is therefore the flap // deflection which will join up the points at s1,s2. // ss is an approximate arc length value near s1 and s2. // it is used as an initial guess for the newton loop // for s1 and s2. // // // if del = 0: surface will be created at s = s1 = s2 // // if del=0, then s1,s2 will cooincide, and will be located // on the airfoil surface where the segment joining the // point at s1,s2 and the hinge point is perpendicular to // the airfoil surface. this will be the point where the // airfoil surface must be broken to permit a gap to open // as a result of the flap deflection. //---------------------------------------------------------------- double rsq, x1p,y1p, x2p, y2p; double r1sq, r2sq, rrsq,rr,r1_s1,r2_s2,rr_s1,rr_s2,rs1, rs2; double a11,a12,a21,a22; double x1,x2, y1, y2;// also common variables...hmmm double x1pp, y1pp, x2pp, y2pp, xtot, ytot; double det, ds1,ds2, eps, stot, sind, ssgn, r1,r2; //---- convergence epsilon eps = 1.0e-5; stot = qAbs( s[n] - s[1] ); sind = sin(0.5*qAbs(del)); ssgn = 1.0; if(iside==1) ssgn = -1.0; //---- initial guesses for s1, s2 r1 = (seval(ss,x,xp,s,n)-xbf); r2 = (seval(ss,y,yp,s,n)-ybf); rsq = r1*r1 + r2*r2; *s1 = ss - (sind*sqrt(rsq) + eps*stot)*ssgn; *s2 = ss + (sind*sqrt(rsq) + eps*stot)*ssgn; //---- newton iteration loop for (int iter=1; iter<= 10; iter++) { x1 = seval(*s1,x,xp,s,n); x1p = deval(*s1,x,xp,s,n); y1 = seval(*s1,y,yp,s,n); y1p = deval(*s1,y,yp,s,n); x2 = seval(*s2,x,xp,s,n); x2p = deval(*s2,x,xp,s,n); y2 = seval(*s2,y,yp,s,n); y2p = deval(*s2,y,yp,s,n); r1sq = (x1-xbf)*(x1-xbf) + (y1-ybf)*(y1-ybf); r2sq = (x2-xbf)*(x2-xbf) + (y2-ybf)*(y2-ybf); r1 = sqrt(r1sq); r2 = sqrt(r2sq); rrsq = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2); rr = sqrt(rrsq); if(r1<=eps*stot || r2<=eps*stot) { *s1 = ss; *s2 = ss; return; } r1_s1 = (x1p*(x1-xbf) + y1p*(y1-ybf))/r1; r2_s2 = (x2p*(x2-xbf) + y2p*(y2-ybf))/r2; if(sind>0.01) { if(rr==0.0) return; rr_s1 = (x1p*(x1-x2) + y1p*(y1-y2))/rr; rr_s2 = -(x2p*(x1-x2) + y2p*(y1-y2))/rr; //------- residual 1: set included angle via dot product rs1 = ((xbf-x1)*(x2-x1) + (ybf-y1)*(y2-y1))/rr - sind*r1; a11 = ((xbf-x1)*( -x1p) + (ybf-y1)*( -y1p))/rr + (( -x1p)*(x2-x1) + ( -y1p)*(y2-y1))/rr - ((xbf-x1)*(x2-x1) + (ybf-y1)*(y2-y1))*rr_s1/rrsq - sind*r1_s1; a12 = ((xbf-x1)*(x2p ) + (ybf-y1)*(y2p ))/rr - ((xbf-x1)*(x2-x1) + (ybf-y1)*(y2-y1))*rr_s2/rrsq; //------- residual 2: set equal length segments rs2 = r1 - r2; a21 = r1_s1; a22 = - r2_s2; } else { //------- residual 1: set included angle via small angle approximation rs1 = (r1+r2)*sind + (s1 - s2)*ssgn; a11 = r1_s1 *sind + ssgn; a12 = r2_s2 *sind - ssgn; //------- residual 2: set vector sum of line segments beteen the //- endpoints and flap hinge to be perpendicular to airfoil surface. x1pp = d2val(*s1,x,xp,s,n); y1pp = d2val(*s1,y,yp,s,n); x2pp = d2val(*s2,x,xp,s,n); y2pp = d2val(*s2,y,yp,s,n); xtot = x1+x2 - 2.0*xbf; ytot = y1+y2 - 2.0*ybf; rs2 = xtot*(x1p+x2p) + ytot*(y1p+y2p); a21 = x1p*(x1p+x2p) + y1p*(y1p+y2p) + xtot*x1pp + ytot*y1pp; a22 = x2p*(x1p+x2p) + y2p*(y1p+y2p) + xtot*x2pp + ytot*y2pp; } det = a11*a22 - a12*a21; ds1 = -(rs1*a22 - a12*rs2) / det; ds2 = -(a11*rs2 - rs1*a21) / det; ds1 = min( ds1 , 0.01*stot ); ds1 = max( ds1 , -.01*stot ); ds2 = min( ds2 , 0.01*stot ); ds2 = max( ds2 , -.01*stot ); *s1 = *s1 + ds1; *s2 = *s2 + ds2; if(qAbs(ds1)+qAbs(ds2) < eps*stot ) break; // newton loop //go to 11 }//10 continue // write(*,*) 'sss: failed to converge subtending angle points' *s1 = ss; *s2 = ss; // 11 continue //---- make sure points are identical if included angle is zero. if(del<=0.00001) { *s1 = 0.5*(*s1+*s2); *s2 = *s1; } } bool XFoil::stepbl() { //arcds : can't think of a more elegant way to do this, and too lazy to search x1 = x2; u1 = u2; t1 = t2; d1 = d2; s1 = s2; ampl1 = ampl2; u1_uei = u2_uei; u1_ms = u2_ms; dw1 = dw2; h1 = h2; h1_t1 = h2_t2; h1_d1 = h2_d2; m1 = m2; m1_u1 = m2_u2; m1_ms = m2_ms; r1 = r2; r1_u1 = r2_u2; r1_ms = r2_ms; v1 = v2; v1_u1 = v2_u2; v1_ms = v2_ms; v1_re = v2_re; hk1 = hk2; hk1_u1 = hk2_u2; hk1_t1 = hk2_t2; hk1_d1 = hk2_d2; hk1_ms = hk2_ms; hs1 = hs2; hs1_u1 = hs2_u2; hs1_t1 = hs2_t2; hs1_d1 = hs2_d2; hs1_ms = hs2_ms; hs1_re = hs2_re; hc1 = hc2; hc1_u1 = hc2_u2; hc1_t1 = hc2_t2; hc1_d1 = hc2_d2; hc1_ms = hc2_ms; rt1 = rt2; rt1_u1 = rt2_u2; rt1_t1 = rt2_t2; rt1_ms = rt2_ms; rt1_re = rt2_re; cf1 = cf2; cf1_u1 = cf2_u2; cf1_t1 = cf2_t2; cf1_d1 = cf2_d2; cf1_ms = cf2_ms; cf1_re = cf2_re; di1 = di2; di1_u1 = di2_u2; di1_t1 = di2_t2; di1_d1 = di2_d2; di1_s1 = di2_s2; di1_ms = di2_ms; di1_re = di2_re; us1 = us2; us1_u1 = us2_u2; us1_t1 = us2_t2; us1_d1 = us2_d2; us1_ms = us2_ms; us1_re = us2_re; cq1 = cq2; cq1_u1 = cq2_u2; cq1_t1 = cq2_t2; cq1_d1 = cq2_d2; cq1_ms = cq2_ms; cq1_re = cq2_re; de1 = de2; de1_u1 = de2_u2; de1_t1 = de2_t2; de1_d1 = de2_d2; de1_ms = de2_ms; return true; } bool XFoil::stfind() { //----------------------------------------- // locates stagnation point arc length // location sst and panel index ist. //----------------------------------------- double dgam, ds; int i; bool bFound; bFound = false; for(i=1;i<= n-1;i++) { if(gam[i]>=0.0 && gam[i+1]<0.0) { bFound = true; break; } } if(!bFound) { QString str = QObject::tr("stfind: Stagnation point not found. Continuing ...\n"); WriteString(str, true); i = n/2; } //stop11: ist = i; dgam = gam[i+1] - gam[i]; ds = s[i+1] - s[i]; //---- evaluate so as to minimize roundoff for very small gam[i] or gam[i+1] if(gam[i] < -gam[i+1]) sst = s[i] - ds*(gam[i] /dgam); else sst = s[i+1] - ds*(gam[i+1]/dgam); //---- tweak stagnation point if it falls right on a node (very unlikely) if(sst <= s[i] ) sst = s[i] + 0.0000001; if(sst >= s[i+1]) sst = s[i+1] - 0.0000001; sst_go = (sst - s[i+1])/dgam; sst_gp = (s[i] - sst )/dgam; return true; } bool XFoil::stmove() { //-------------------------------------------------- // moves stagnation point location to new panel. //--------------------------------------------------- int ibl, idif, istold, is; double dudx; //-- locate new stagnation point arc length sst from gam distribution istold = ist; stfind(); if(istold==ist) { //--- recalculate new arc length array xicalc(); } else { // write(*,*) 'stmove: resetting stagnation point' //--- set new bl position -> panel position pointers iblpan(); //--- set new inviscid bl edge velocity uinv from qinv uicalc(); //--- recalculate new arc length array xicalc(); //--- set bl position -> system line pointers iblsys(); if(ist>istold) { //---- increase in number of points on top side (is=1) idif = ist-istold; itran[1] = itran[1] + idif; itran[2] = itran[2] - idif; //---- move top side bl variables downstream for (ibl=nbl[1];ibl>= idif+2;ibl--){ ctau[ibl][1] = ctau[ibl-idif][1]; thet[ibl][1] = thet[ibl-idif][1]; dstr[ibl][1] = dstr[ibl-idif][1]; uedg[ibl][1] = uedg[ibl-idif][1]; } //---- set bl variables between old and new stagnation point dudx = uedg[idif+2][1]/xssi[idif+2][1]; for (ibl=idif+1;ibl>= 2;ibl--) { ctau[ibl][1] = ctau[idif+2][1]; thet[ibl][1] = thet[idif+2][1]; dstr[ibl][1] = dstr[idif+2][1]; uedg[ibl][1] = dudx * xssi[ibl][1]; } //---- move bottom side bl variables upstream for (ibl=2; ibl<= nbl[2];ibl++){ ctau[ibl][2] = ctau[ibl+idif][2]; thet[ibl][2] = thet[ibl+idif][2]; dstr[ibl][2] = dstr[ibl+idif][2]; uedg[ibl][2] = uedg[ibl+idif][2]; } } else{ //---- increase in number of points on bottom side (is=2) idif = istold-ist; itran[1] = itran[1] - idif; itran[2] = itran[2] + idif; //---- move bottom side bl variables downstream for (ibl=nbl[2];ibl>= idif+2;ibl--){ ctau[ibl][2] = ctau[ibl-idif][2]; thet[ibl][2] = thet[ibl-idif][2]; dstr[ibl][2] = dstr[ibl-idif][2]; uedg[ibl][2] = uedg[ibl-idif][2]; } //---- set bl variables between old and new stagnation point dudx = uedg[idif+2][2]/xssi[idif+2][2]; for (ibl=idif+1;ibl>= 2;ibl--){ ctau[ibl][2] = ctau[idif+2][2]; thet[ibl][2] = thet[idif+2][2]; dstr[ibl][2] = dstr[idif+2][2]; uedg[ibl][2] = dudx * xssi[ibl][2]; } //---- move top side bl variables upstream for(ibl=2;ibl<= nbl[1];ibl++){ ctau[ibl][1] = ctau[ibl+idif][1]; thet[ibl][1] = thet[ibl+idif][1]; dstr[ibl][1] = dstr[ibl+idif][1]; uedg[ibl][1] = uedg[ibl+idif][1]; } } } //-- set new mass array since ue has been tweaked for (is=1;is<= 2;is++) { for(ibl=2; ibl<= nbl[is];ibl++) mass[ibl][is] = dstr[ibl][is]*uedg[ibl][is]; } return true; } bool XFoil::tecalc() { //------------------------------------------- // calculates total and projected te // areas and te panel strengths. //------------------------------------------- double scs, sds; //---- set te base vector and te bisector components double dxte = x[1] - x[n]; double dyte = y[1] - y[n]; double dxs = 0.5*(-xp[1] + xp[n]); double dys = 0.5*(-yp[1] + yp[n]); //---- normal and streamwise projected te gap areas ante = dxs*dyte - dys*dxte; aste = dxs*dxte + dys*dyte; //---- total te gap area dste = sqrt(dxte*dxte + dyte*dyte); sharp = dste < 0.0001*chord; if(sharp) { scs = 1.0; sds = 0.0; } else{ scs = ante/dste; sds = aste/dste; } //---- te panel source and vorticity strengths sigte = 0.5*(gam[1] - gam[n])*scs; gamte = -.5*(gam[1] - gam[n])*sds; // sigte_a = 0.5*(gam_a[1] - gam_a[n])*scs; // gamte_a = -.5*(gam_a[1] - gam_a[n])*sds; return true; } bool XFoil::tesys(double cte, double tte, double dte){ //-------------------------------------------------------- // sets up "dummy" bl system between airfoil te point // and first wake point infinitesimally behind te. //-------------------------------------------------------- for(int k=1;k<= 4;k++){ vsrez[k] = 0.0; vsm[k] = 0.0; vsr[k] = 0.0; vsx[k] = 0.0; for (int l=1; l<=5;l++){ vs1[k][l] = 0.0; vs2[k][l] = 0.0; } } blvar(3); vs1[1][1] = -1.0; vs2[1][1] = 1.0; vsrez[1] = cte - s2; vs1[2][2] = -1.0; vs2[2][2] = 1.0; vsrez[2] = tte - t2; vs1[3][3] = -1.0; vs2[3][3] = 1.0; vsrez[3] = dte - d2 - dw2; return true; } bool XFoil::trchek() { //---------------------------------------------------------------- // new second-order version: december 1994. // // checks if transition occurs in the current interval x1..x2. // if transition occurs, then set transition location xt, and // its sensitivities to "1" and "2" variables. if no transition, // set amplification ampl2. // // solves the implicit amplification equation for n2: // // n2 - n1 n'(xt,nt) + n'(x1,n1) // ------- = --------------------- // x2 - x1 2 // // in effect, a 2-point central difference is used between // x1..x2 (no transition), or x1..xt (transition). the switch // is done by defining xt,nt in the equation above depending // on whether n2 exceeds ncrit. // // if n2ncrit: nt=ncrit , xt=(ncrit-n1)/(n2-n1) (transition) // //---------------------------------------------------------------- QString str; int itam; double ax_hk1, ax_t1, ax_a1, ax_hk2, ax_t2, ax_rt2, ax_a2; double amplt, sfa, sfa_a1, sfa_a2, sfx; double sfx_x1, sfx_x2, sfx_xf; double tt, dt, ut, amsave; double ax, ax_rt1,res, res_a2; double da2, dxt, tt_t1, dt_d1, ut_u1; double tt_t2, dt_d2, ut_u2, tt_a1, dt_a1; double ut_a1, tt_x1, dt_x1, ut_x1, tt_x2, dt_x2, ut_x2, tt_xf, dt_xf, ut_xf; double ax_d1, ax_u1, ax_x1, ax_d2, ax_u2, ax_x2, ax_xf, ax_ms, ax_re; double z_ax, z_a1, z_t1, z_d1, z_u1, z_x1, z_a2, z_t2, z_d2, z_u2, z_x2, z_xf, z_ms, z_re; double ax_at, ax_rtt, ax_tt, ax_hkt, amplt_a2, wf1, wf1_a1, wf1_a2, wf1_xf, wf1_x1, wf1_x2; double wf2, wf2_a1, wf2_a2, wf2_xf, wf2_x1, wf2_x2, xt_a2, dt_a2, tt_a2; double ut_a2, hkt, hkt_tt, hkt_dt, hkt_ut, hkt_ms, rtt_tt, rtt_ut, rtt_ms, rtt, rtt_re; double daeps; daeps =0.00005; ax_at= ax_rtt= ax_tt= ax_hkt= amplt_a2= wf1= wf1_a1= wf1_a2= wf1_xf= wf1_x1= wf1_x2 = 0.0; wf2 = wf2_a1= wf2_a2= wf2_xf= wf2_x1= wf2_x2= xt_a2= dt_a2= tt_a2 = 0.0; ut_a2= hkt= hkt_tt= hkt_dt= hkt_ut= hkt_ms= rtt_tt= rtt_ut= rtt_ms= rtt= rtt_re = 0.0; //---- save variables and sensitivities at ibl ("2") for future restoration saveblData(2); //---- calculate average amplification rate ax over x1..x2 interval axset(hk1, t1, rt1, ampl1, hk2, t2, rt2, ampl2, amcrit, ax, ax_hk1, ax_t1, ax_rt1, ax_a1, ax_hk2, ax_t2, ax_rt2, ax_a2 ); //---- set initial guess for iterate n2 (ampl2) at x2 ampl2 = ampl1 + ax*(x2-x1); //---- solve implicit system for amplification ampl2 for(itam=1; itam<=30;itam++) { //---- define weighting factors wf1,wf2 for defining "t" quantities from 1,2 if(ampl2 <= amcrit) { //------ there is no transition yet, "t" is the same as "2" amplt = ampl2; amplt_a2 = 1.0; sfa = 1.0; sfa_a1 = 0.0; sfa_a2 = 0.0; } else { //------ there is transition in x1..x2, "t" is set from n1, n2 amplt = amcrit; amplt_a2 = 0.0; sfa = (amplt - ampl1)/(ampl2-ampl1); sfa_a1 = ( sfa - 1.0 )/(ampl2-ampl1); sfa_a2 = ( - sfa )/(ampl2-ampl1); } if(xiforc 0.05) rlx = 0.05*qAbs((x2-x1)/dxt); if(rlx*qAbs(da2) > 1.0) rlx = 1.0 *qAbs( 1.0 /da2); //---- check if converged if(qAbs(da2) < daeps) goto stop101; if((ampl2>amcrit && ampl2+rlx*da2amcrit) ) //------ limited newton step so ampl2 doesn't step across amcrit either way ampl2 = amcrit; else //------ regular newton step ampl2 = ampl2 + rlx*da2; } //TRACE("trchek2 - n2 convergence failed\n"); str = QObject::tr("trchek2 - n2 convergence failed\n"); WriteString(str, true); if(s_bCancel) return false; stop101: //---- test for free or forced transition trfree = (ampl2 >= amcrit); trforc = (xiforc>x1) && (xiforc<=x2); //---- set transition interval flag tran = (trforc || trfree); if(!tran) return false; //---- resolve if both forced and free transition if(trfree && trforc) { trforc = xiforc < xt; trfree = xiforc >= xt; } if(trforc) { //----- if forced transition, then xt is prescribed, //- no sense calculating the sensitivities, since we know them... xt = xiforc; xt_a1 = 0.0; xt_x1 = 0.0; xt_t1 = 0.0; xt_d1 = 0.0; xt_u1 = 0.0; xt_x2 = 0.0; xt_t2 = 0.0; xt_d2 = 0.0; xt_u2 = 0.0; xt_ms = 0.0; xt_re = 0.0; xt_xf = 1.0; return true; } //---- free transition ... set sensitivities of xt xt_x1 = wf1; tt_t1 = wf1; dt_d1 = wf1; ut_u1 = wf1; xt_x2 = wf2; tt_t2 = wf2; dt_d2 = wf2; ut_u2 = wf2; xt_a1 = x1*wf1_a1 + x2*wf2_a1; tt_a1 = t1*wf1_a1 + t2*wf2_a1; dt_a1 = d1*wf1_a1 + d2*wf2_a1; ut_a1 = u1*wf1_a1 + u2*wf2_a1; xt_x1 = x1*wf1_x1 + x2*wf2_x1 + xt_x1; tt_x1 = t1*wf1_x1 + t2*wf2_x1; dt_x1 = d1*wf1_x1 + d2*wf2_x1; ut_x1 = u1*wf1_x1 + u2*wf2_x1; xt_x2 = x1*wf1_x2 + x2*wf2_x2 + xt_x2; tt_x2 = t1*wf1_x2 + t2*wf2_x2; dt_x2 = d1*wf1_x2 + d2*wf2_x2; ut_x2 = u1*wf1_x2 + u2*wf2_x2; xt_xf = x1*wf1_xf + x2*wf2_xf; tt_xf = t1*wf1_xf + t2*wf2_xf; dt_xf = d1*wf1_xf + d2*wf2_xf; ut_xf = u1*wf1_xf + u2*wf2_xf; //---- at this point, ax = ax( hk1, t1, rt1, a1, hkt, tt, rtt, at ) //---- set sensitivities of ax( t1 d1 u1 a1 t2 d2 u2 a2 ms re ) ax_t1 = ax_hk1*hk1_t1 + ax_t1 + ax_rt1*rt1_t1 + (ax_hkt*hkt_tt + ax_tt + ax_rtt*rtt_tt)*tt_t1; ax_d1 = ax_hk1*hk1_d1 + (ax_hkt*hkt_dt )*dt_d1; ax_u1 = ax_hk1*hk1_u1 + ax_rt1*rt1_u1 + (ax_hkt*hkt_ut + ax_rtt*rtt_ut)*ut_u1; ax_a1 = ax_a1 + (ax_hkt*hkt_tt + ax_tt + ax_rtt*rtt_tt)*tt_a1//is tt_a1 initialized ? + (ax_hkt*hkt_dt )*dt_a1 + (ax_hkt*hkt_ut + ax_rtt*rtt_ut)*ut_a1; ax_x1 = (ax_hkt*hkt_tt + ax_tt + ax_rtt*rtt_tt)*tt_x1 + (ax_hkt*hkt_dt )*dt_x1 + (ax_hkt*hkt_ut + ax_rtt*rtt_ut)*ut_x1; ax_t2 = (ax_hkt*hkt_tt + ax_tt + ax_rtt*rtt_tt)*tt_t2; ax_d2 = (ax_hkt*hkt_dt )*dt_d2; ax_u2 = (ax_hkt*hkt_ut + ax_rtt*rtt_ut)*ut_u2; ax_a2 = ax_at *amplt_a2 + (ax_hkt*hkt_tt + ax_tt + ax_rtt*rtt_tt)*tt_a2//is tt_a2 initialized ? + (ax_hkt*hkt_dt )*dt_a2 + (ax_hkt*hkt_ut + ax_rtt*rtt_ut)*ut_a2; ax_x2 = (ax_hkt*hkt_tt + ax_tt + ax_rtt*rtt_tt)*tt_x2 + (ax_hkt*hkt_dt )*dt_x2 + (ax_hkt*hkt_ut + ax_rtt*rtt_ut)*ut_x2; ax_xf = (ax_hkt*hkt_tt + ax_tt + ax_rtt*rtt_tt)*tt_xf + (ax_hkt*hkt_dt )*dt_xf + (ax_hkt*hkt_ut + ax_rtt*rtt_ut)*ut_xf; ax_ms = ax_hkt*hkt_ms + ax_rtt*rtt_ms + ax_hk1*hk1_ms + ax_rt1*rt1_ms; ax_re = ax_rtt*rtt_re + ax_rt1*rt1_re; //---- set sensitivities of residual res //c res = ampl2 - ampl1 - ax*(x2-x1) z_ax = - (x2-x1); z_a1 = z_ax*ax_a1 - 1.0; z_t1 = z_ax*ax_t1; z_d1 = z_ax*ax_d1; z_u1 = z_ax*ax_u1; z_x1 = z_ax*ax_x1 + ax; z_a2 = z_ax*ax_a2 + 1.0; z_t2 = z_ax*ax_t2; z_d2 = z_ax*ax_d2; z_u2 = z_ax*ax_u2; z_x2 = z_ax*ax_x2 - ax; z_xf = z_ax*ax_xf; z_ms = z_ax*ax_ms; z_re = z_ax*ax_re; //---- set sensitivities of xt, with res being stationary for a2 constraint xt_a1 = xt_a1 - (xt_a2/z_a2)*z_a1; xt_t1 = - (xt_a2/z_a2)*z_t1; xt_d1 = - (xt_a2/z_a2)*z_d1; xt_u1 = - (xt_a2/z_a2)*z_u1; xt_x1 = xt_x1 - (xt_a2/z_a2)*z_x1; xt_t2 = - (xt_a2/z_a2)*z_t2; xt_d2 = - (xt_a2/z_a2)*z_d2; xt_u2 = - (xt_a2/z_a2)*z_u2; xt_x2 = xt_x2 - (xt_a2/z_a2)*z_x2; xt_ms = - (xt_a2/z_a2)*z_ms; xt_re = - (xt_a2/z_a2)*z_re; xt_xf = 0.0; return true ; } bool XFoil::trdif() { //----------------------------------------------- // sets up the newton system governing the // transition interval. equations governing // the laminar part x1 < xi < xt and // the turbulent part xt < xi < x2 // are simply summed. //----------------------------------------------- double bl1[5][6], bl2[5][6], blrez[5], blm[5], blr[5], blx[5], bt1[5][6], bt2[5][6], btrez[5], btm[5], btr[5], btx[5]; double wf2, wf2_xt, wf2_a1,wf2_x1, wf2_x2, wf2_t1, wf2_t2; double wf2_d1, wf2_d2, wf2_u1, wf2_u2, wf2_ms, wf2_re, wf2_xf; double wf1, wf1_a1, wf1_x1, wf1_x2, wf1_t1, wf1_t2, wf1_d1, wf1_d2; double wf1_u1, wf1_u2, wf1_ms, wf1_re, wf1_xf; double tt, tt_a1, tt_x1, tt_x2, tt_t1, tt_t2, tt_d1, tt_d2, tt_u1, tt_u2; double tt_ms, tt_re, tt_xf, dt, dt_a1, dt_x1, dt_x2, dt_t1, dt_t2; double dt_d1, dt_d2, dt_u1, dt_u2, dt_ms, dt_re, dt_xf; double ut, ut_a1, ut_x1, ut_x2, ut_t1, ut_t2, ut_d1, ut_d2, ut_u1, ut_u2; double ut_ms, ut_re, ut_xf; double st, st_tt, st_dt, st_ut, st_ms, st_re, st_a1, st_x1, st_x2, st_t1, st_t2; double st_d1, st_d2, st_u1, st_u2, st_xf; double ctr, ctr_hk2; int k; // double c1sav[74], c2sav[74]; //---- save variables and sensitivities for future restoration // for (int icom=1; icom<= ncom;icom++){ // c1sav[icom] = com1[icom]; // c2sav[icom] = com2[icom]; // } saveblData(1); saveblData(2); //---- weighting factors for linear interpolation to transition point wf2 = (xt-x1)/(x2-x1); wf2_xt = 1.0/(x2-x1); wf2_a1 = wf2_xt*xt_a1; wf2_x1 = wf2_xt*xt_x1 + (wf2-1.0)/(x2-x1); wf2_x2 = wf2_xt*xt_x2 - wf2 /(x2-x1); wf2_t1 = wf2_xt*xt_t1; wf2_t2 = wf2_xt*xt_t2; wf2_d1 = wf2_xt*xt_d1; wf2_d2 = wf2_xt*xt_d2; wf2_u1 = wf2_xt*xt_u1; wf2_u2 = wf2_xt*xt_u2; wf2_ms = wf2_xt*xt_ms; wf2_re = wf2_xt*xt_re; wf2_xf = wf2_xt*xt_xf; wf1 = 1.0 - wf2; wf1_a1 = -wf2_a1; wf1_x1 = -wf2_x1; wf1_x2 = -wf2_x2; wf1_t1 = -wf2_t1; wf1_t2 = -wf2_t2; wf1_d1 = -wf2_d1; wf1_d2 = -wf2_d2; wf1_u1 = -wf2_u1; wf1_u2 = -wf2_u2; wf1_ms = -wf2_ms; wf1_re = -wf2_re; wf1_xf = -wf2_xf; //**** first, do laminar part between x1 and xt //-----interpolate primary variables to transition point tt = t1*wf1 + t2*wf2; tt_a1 = t1*wf1_a1 + t2*wf2_a1; tt_x1 = t1*wf1_x1 + t2*wf2_x1; tt_x2 = t1*wf1_x2 + t2*wf2_x2; tt_t1 = t1*wf1_t1 + t2*wf2_t1 + wf1; tt_t2 = t1*wf1_t2 + t2*wf2_t2 + wf2; tt_d1 = t1*wf1_d1 + t2*wf2_d1; tt_d2 = t1*wf1_d2 + t2*wf2_d2; tt_u1 = t1*wf1_u1 + t2*wf2_u1; tt_u2 = t1*wf1_u2 + t2*wf2_u2; tt_ms = t1*wf1_ms + t2*wf2_ms; tt_re = t1*wf1_re + t2*wf2_re; tt_xf = t1*wf1_xf + t2*wf2_xf; dt = d1*wf1 + d2*wf2; dt_a1 = d1*wf1_a1 + d2*wf2_a1; dt_x1 = d1*wf1_x1 + d2*wf2_x1; dt_x2 = d1*wf1_x2 + d2*wf2_x2; dt_t1 = d1*wf1_t1 + d2*wf2_t1; dt_t2 = d1*wf1_t2 + d2*wf2_t2; dt_d1 = d1*wf1_d1 + d2*wf2_d1 + wf1; dt_d2 = d1*wf1_d2 + d2*wf2_d2 + wf2; dt_u1 = d1*wf1_u1 + d2*wf2_u1; dt_u2 = d1*wf1_u2 + d2*wf2_u2; dt_ms = d1*wf1_ms + d2*wf2_ms; dt_re = d1*wf1_re + d2*wf2_re; dt_xf = d1*wf1_xf + d2*wf2_xf; ut = u1*wf1 + u2*wf2; ut_a1 = u1*wf1_a1 + u2*wf2_a1; ut_x1 = u1*wf1_x1 + u2*wf2_x1; ut_x2 = u1*wf1_x2 + u2*wf2_x2; ut_t1 = u1*wf1_t1 + u2*wf2_t1; ut_t2 = u1*wf1_t2 + u2*wf2_t2; ut_d1 = u1*wf1_d1 + u2*wf2_d1; ut_d2 = u1*wf1_d2 + u2*wf2_d2; ut_u1 = u1*wf1_u1 + u2*wf2_u1 + wf1; ut_u2 = u1*wf1_u2 + u2*wf2_u2 + wf2; ut_ms = u1*wf1_ms + u2*wf2_ms; ut_re = u1*wf1_re + u2*wf2_re; ut_xf = u1*wf1_xf + u2*wf2_xf; //---- set primary "t" variables at xt (really placed into "2" variables) x2 = xt; t2 = tt; d2 = dt; u2 = ut; ampl2 = amcrit; s2 = 0.0; //---- calculate laminar secondary "t" variables blkin(); blvar(1); //---- calculate x1-xt midpoint cfm value blmid(1); //= at this point, all "2" variables are really "t" variables at xt //---- set up newton system for dam, dth, dds, due, dxi at x1 and xt bldif(1); //---- the current newton system is in terms of "1" and "t" variables, //- so calculate its equivalent in terms of "1" and "2" variables. //- in other words, convert residual sensitivities wrt "t" variables //- into sensitivities wrt "1" and "2" variables. the amplification //- equation is unnecessary here, so the k=1 row is left empty. for (k=2; k<= 3; k++) { blrez[k] = vsrez[k]; blm[k] = vsm[k]+ vs2[k][2]*tt_ms+ vs2[k][3]*dt_ms+ vs2[k][4]*ut_ms+ vs2[k][5]*xt_ms; blr[k] = vsr[k]+ vs2[k][2]*tt_re+ vs2[k][3]*dt_re+ vs2[k][4]*ut_re+ vs2[k][5]*xt_re; blx[k] = vsx[k]+ vs2[k][2]*tt_xf+ vs2[k][3]*dt_xf+ vs2[k][4]*ut_xf+ vs2[k][5]*xt_xf; bl1[k][1] = vs1[k][1]+ vs2[k][2]*tt_a1+ vs2[k][3]*dt_a1+ vs2[k][4]*ut_a1+ vs2[k][5]*xt_a1; bl1[k][2] = vs1[k][2]+ vs2[k][2]*tt_t1+ vs2[k][3]*dt_t1+ vs2[k][4]*ut_t1+ vs2[k][5]*xt_t1; bl1[k][3] = vs1[k][3]+ vs2[k][2]*tt_d1+ vs2[k][3]*dt_d1+ vs2[k][4]*ut_d1+ vs2[k][5]*xt_d1; bl1[k][4] = vs1[k][4]+ vs2[k][2]*tt_u1+ vs2[k][3]*dt_u1+ vs2[k][4]*ut_u1+ vs2[k][5]*xt_u1; bl1[k][5] = vs1[k][5]+ vs2[k][2]*tt_x1+ vs2[k][3]*dt_x1+ vs2[k][4]*ut_x1+ vs2[k][5]*xt_x1; bl2[k][1] = 0.0; bl2[k][2] = vs2[k][2]*tt_t2+ vs2[k][3]*dt_t2+ vs2[k][4]*ut_t2+ vs2[k][5]*xt_t2; bl2[k][3] = vs2[k][2]*tt_d2+ vs2[k][3]*dt_d2+ vs2[k][4]*ut_d2+ vs2[k][5]*xt_d2; bl2[k][4] = vs2[k][2]*tt_u2+ vs2[k][3]*dt_u2+ vs2[k][4]*ut_u2+ vs2[k][5]*xt_u2; bl2[k][5] = vs2[k][2]*tt_x2+ vs2[k][3]*dt_x2+ vs2[k][4]*ut_x2+ vs2[k][5]*xt_x2; } //**** second, set up turbulent part between xt and x2 **** //---- calculate equilibrium shear coefficient cqt at transition point blvar(2); //---- set initial shear coefficient value st at transition point //- ( note that cq2, cq2_t2, etc. are really "cqt", "cqt_tt", etc.) ctr = 1.8*exp(-3.3/(hk2-1.0)); ctr_hk2 = ctr * 3.3/(hk2-1.0)/(hk2-1.0); st = ctr*cq2; st_tt = ctr*cq2_t2 + cq2*ctr_hk2*hk2_t2; st_dt = ctr*cq2_d2 + cq2*ctr_hk2*hk2_d2; st_ut = ctr*cq2_u2 + cq2*ctr_hk2*hk2_u2; st_ms = ctr*cq2_ms + cq2*ctr_hk2*hk2_ms; st_re = ctr*cq2_re; //---- calculate st sensitivities wrt the actual "1" and "2" variables st_a1 = st_tt*tt_a1 + st_dt*dt_a1 + st_ut*ut_a1; st_x1 = st_tt*tt_x1 + st_dt*dt_x1 + st_ut*ut_x1; st_x2 = st_tt*tt_x2 + st_dt*dt_x2 + st_ut*ut_x2; st_t1 = st_tt*tt_t1 + st_dt*dt_t1 + st_ut*ut_t1; st_t2 = st_tt*tt_t2 + st_dt*dt_t2 + st_ut*ut_t2; st_d1 = st_tt*tt_d1 + st_dt*dt_d1 + st_ut*ut_d1; st_d2 = st_tt*tt_d2 + st_dt*dt_d2 + st_ut*ut_d2; st_u1 = st_tt*tt_u1 + st_dt*dt_u1 + st_ut*ut_u1; st_u2 = st_tt*tt_u2 + st_dt*dt_u2 + st_ut*ut_u2; st_ms = st_tt*tt_ms + st_dt*dt_ms + st_ut*ut_ms + st_ms; st_re = st_tt*tt_re + st_dt*dt_re + st_ut*ut_re + st_re; st_xf = st_tt*tt_xf + st_dt*dt_xf + st_ut*ut_xf; ampl2 = 0.0; s2 = st; //---- recalculate turbulent secondary "t" variables using proper cti blvar(2); //---- set "1" variables to "t" variables and reset "2" variables //- to their saved turbulent values // for (icom=1; icom<= ncom; icom++){ // com1[icom] = com2[icom]; // com2[icom] = c2sav[icom]; // } stepbl(); restoreblData(2); //---- calculate xt-x2 midpoint cfm value blmid(2); //---- set up newton system for dct, dth, dds, due, dxi at xt and x2 bldif(2); //---- convert sensitivities wrt "t" variables into sensitivities //- wrt "1" and "2" variables as done before for the laminar part for (k=1; k<= 3;k++) { btrez[k] = vsrez[k]; btm[k] = vsm[k] + vs1[k][1]*st_ms+ vs1[k][2]*tt_ms+ vs1[k][3]*dt_ms+ vs1[k][4]*ut_ms+ vs1[k][5]*xt_ms; btr[k] = vsr[k] + vs1[k][1]*st_re+ vs1[k][2]*tt_re+ vs1[k][3]*dt_re+ vs1[k][4]*ut_re+ vs1[k][5]*xt_re; btx[k] = vsx[k] + vs1[k][1]*st_xf+ vs1[k][2]*tt_xf+ vs1[k][3]*dt_xf+ vs1[k][4]*ut_xf+ vs1[k][5]*xt_xf; bt1[k][1] = vs1[k][1]*st_a1+ vs1[k][2]*tt_a1+ vs1[k][3]*dt_a1+ vs1[k][4]*ut_a1+ vs1[k][5]*xt_a1; bt1[k][2] = vs1[k][1]*st_t1+ vs1[k][2]*tt_t1+ vs1[k][3]*dt_t1+ vs1[k][4]*ut_t1+ vs1[k][5]*xt_t1; bt1[k][3] = vs1[k][1]*st_d1+ vs1[k][2]*tt_d1+ vs1[k][3]*dt_d1+ vs1[k][4]*ut_d1+ vs1[k][5]*xt_d1; bt1[k][4] = vs1[k][1]*st_u1+ vs1[k][2]*tt_u1+ vs1[k][3]*dt_u1+ vs1[k][4]*ut_u1+ vs1[k][5]*xt_u1; bt1[k][5] = vs1[k][1]*st_x1+ vs1[k][2]*tt_x1+ vs1[k][3]*dt_x1+ vs1[k][4]*ut_x1+ vs1[k][5]*xt_x1; bt2[k][1] = vs2[k][1]; bt2[k][2] = vs2[k][2]+ vs1[k][1]*st_t2+ vs1[k][2]*tt_t2+ vs1[k][3]*dt_t2+ vs1[k][4]*ut_t2+ vs1[k][5]*xt_t2; bt2[k][3] = vs2[k][3]+ vs1[k][1]*st_d2+ vs1[k][2]*tt_d2+ vs1[k][3]*dt_d2+ vs1[k][4]*ut_d2+ vs1[k][5]*xt_d2; bt2[k][4] = vs2[k][4]+ vs1[k][1]*st_u2+ vs1[k][2]*tt_u2+ vs1[k][3]*dt_u2+ vs1[k][4]*ut_u2+ vs1[k][5]*xt_u2; bt2[k][5] = vs2[k][5]+ vs1[k][1]*st_x2+ vs1[k][2]*tt_x2+ vs1[k][3]*dt_x2+ vs1[k][4]*ut_x2+ vs1[k][5]*xt_x2; } //---- add up laminar and turbulent parts to get final system //- in terms of honest-to-god "1" and "2" variables. vsrez[1] = btrez[1]; vsrez[2] = blrez[2] + btrez[2]; vsrez[3] = blrez[3] + btrez[3]; vsm[1] = btm[1]; vsm[2] = blm[2] + btm[2]; vsm[3] = blm[3] + btm[3]; vsr[1] = btr[1]; vsr[2] = blr[2] + btr[2]; vsr[3] = blr[3] + btr[3]; vsx[1] = btx[1]; vsx[2] = blx[2] + btx[2]; vsx[3] = blx[3] + btx[3]; for (int l=1; l<=5;l++) { vs1[1][l] = bt1[1][l]; vs2[1][l] = bt2[1][l]; vs1[2][l] = bl1[2][l] + bt1[2][l]; vs2[2][l] = bl2[2][l] + bt2[2][l]; vs1[3][l] = bl1[3][l] + bt1[3][l]; vs2[3][l] = bl2[3][l] + bt2[3][l]; } //---- to be sanitary, restore "1" quantities which got clobbered //- in all of the numerical gymnastics above. the "2" variables //- were already restored for the xt-x2 differencing part. // for (icom=1; icom<=ncom;icom++){ // com1[icom] = c1sav[icom]; // } restoreblData(1); return true; } bool XFoil::trisol(double a[], double b[], double c[], double d[], int kk){ //----------------------------------------- // solves kk long, tri-diagonal system | // | // a c d | // b a c d | // b a . . | // . . c . | // b a d | // | // the righthand side d is replaced by | // the solution. a, c are destroyed. | //----------------------------------------- int k; for (k=2; k<= kk;k++){ int km = k-1; c[km] = c[km] / a[km]; d[km] = d[km] / a[km]; a[k] = a[k] - b[k]*c[km]; d[k] = d[k] - b[k]*d[km]; } d[kk] = d[kk]/a[kk]; for(k=kk-1;k>= 1;k--){ d[k] = d[k] - c[k]*d[k+1]; } return true; } bool XFoil::ueset() { //--------------------------------------------------------- // sets ue from inviscid ue plus all source influence //--------------------------------------------------------- int i, is,ibl, j, js, jbl; double dui, ue_m; for (is=1; is<= 2;is++) { for(ibl=2; ibl<= nbl[is]; ibl++) { i = ipan[ibl][is]; dui = 0.0; for (js=1; js<= 2; js++) { for(jbl=2; jbl<= nbl[js]; jbl++) { j = ipan[jbl][js]; ue_m = -vti[ibl][is]*vti[jbl][js]*dij[i][j]; dui = dui + ue_m*mass[jbl][js]; } } uedg[ibl][is] = uinv[ibl][is] + dui; } } return true; } bool XFoil::uicalc() { //-------------------------------------------------------------- // sets inviscid ue from panel inviscid tangential velocity //-------------------------------------------------------------- int i,ibl,is; for (is=1; is<=2;is++) { uinv [1][is] = 0.0; uinv_a[1][is] = 0.0; for (ibl=2;ibl<= nbl[is];ibl++) { i = ipan[ibl][is]; uinv[ibl][is] = vti[ibl][is]*qinv [i]; uinv_a[ibl][is] = vti[ibl][is]*qinv_a[i]; } } return true; } bool XFoil::update() { //------------------------------------------------------------------ // adds on newton deltas to boundary layer variables. // checks for excessive changes and underrelaxes if necessary. // calculates max and rms changes. // also calculates the change in the global variable "ac". // if lalfa=true , "ac" is cl // if lalfa=false, "ac" is alpha //------------------------------------------------------------------ int i, ip, is, iv, iw, j, js, jv, ibl, jbl, kbl; double unew[IVX][3], u_ac[IVX][3]; double qnew[IQX],q_ac[IQX]; double dalmax, dalmin, dclmax, dclmin ,dx, dx_a, ag, ag_ms, ag_ac; double dac, dhi, dlo, dctau, dthet, dmass, duedg, ddstr; double dn1, dn2, dn3, dn4, rdn1,rdn2,rdn3,rdn4; double dswaki, hklim, msq, dsw; double dui, dui_ac, ue_m, uinv_ac,sa,ca, beta, beta_msq, bfac, bfac_msq; double clnew, cl_a, cl_ms, cl_ac, cginc; double cpg1,cpg1_ms, cpi_q, cpc_cpi, cpg1_ac,cpg2, cpg2_ms, cpg2_ac; QString vmxbl; //---- max allowable alpha changes per iteration dalmax = 0.5*dtor; dalmin = -0.5*dtor; //---- max allowable cl change per iteration dclmax = 0.5; dclmin = -0.5; if(matyp!=1) dclmin = qMax(-0.5, -0.9*cl) ; hstinv = gamm1*(minf/qinf)*(minf/qinf) / (1.0 + 0.5*gamm1*minf*minf); //--- calculate new ue distribution assuming no under-relaxation //--- also set the sensitivity of ue wrt to alpha or re for (is=1; is<= 2; is++) { for(ibl=2;ibl<= nbl[is];ibl++) { i = ipan[ibl][is]; dui = 0.0; dui_ac = 0.0; for (js=1; js<=2; js++) { for (jbl=2; jbl<=nbl[js];jbl++) { j = ipan[jbl][js]; jv = isys[jbl][js]; ue_m = -vti[ibl][is]*vti[jbl][js]*dij[i][j]; dui = dui + ue_m*(mass[jbl][js]+vdel[3][1][jv]); dui_ac = dui_ac + ue_m*( -vdel[3][2][jv]); } } //------- uinv depends on "ac" only if "ac" is alpha if(lalfa) uinv_ac = 0.0; else uinv_ac = uinv_a[ibl][is]; unew[ibl][is] = uinv[ibl][is] + dui; u_ac[ibl][is] = uinv_ac + dui_ac; } } //--- set new qtan from new ue with appropriate sign change for (is=1; is<= 2; is++) { for(ibl=2; ibl<= iblte[is]; ibl++) { i = ipan[ibl][is]; qnew[i] = vti[ibl][is]*unew[ibl][is]; q_ac[i] = vti[ibl][is]*u_ac[ibl][is]; } } //--- calculate new cl from this new qtan sa = sin(alfa); ca = cos(alfa); beta = sqrt(1.0 - minf*minf); beta_msq = -0.5/beta; bfac = 0.5*minf*minf / (1.0 + beta); bfac_msq = 0.5 / (1.0 + beta) - bfac / (1.0 + beta) * beta_msq; clnew = 0.0; cl_a = 0.0; cl_ms = 0.0; cl_ac = 0.0; i = 1; cginc = 1.0 - (qnew[i]/qinf)*(qnew[i]/qinf); cpg1 = cginc / (beta + bfac*cginc); cpg1_ms = -cpg1/(beta + bfac*cginc)*(beta_msq + bfac_msq*cginc); cpi_q = -2.0*qnew[i]/qinf/qinf; cpc_cpi = (1.0 - bfac*cpg1)/ (beta + bfac*cginc); cpg1_ac = cpc_cpi*cpi_q*q_ac[i]; for (i=1; i<= n;i++) { ip = i+1; if(i==n) ip = 1; cginc = 1.0 - (qnew[ip]/qinf)*(qnew[ip]/qinf); cpg2 = cginc / (beta + bfac*cginc); cpg2_ms = -cpg2/(beta + bfac*cginc)*(beta_msq + bfac_msq*cginc); cpi_q = -2.0*qnew[ip]/qinf/qinf; cpc_cpi = (1.0 - bfac*cpg2)/ (beta + bfac*cginc); cpg2_ac = cpc_cpi*cpi_q*q_ac[ip]; dx = (x[ip] - x[i])*ca + (y[ip] - y[i])*sa; dx_a = -(x[ip] - x[i])*sa + (y[ip] - y[i])*ca; ag = 0.5*(cpg2 + cpg1 ); ag_ms = 0.5*(cpg2_ms + cpg1_ms); ag_ac = 0.5*(cpg2_ac + cpg1_ac); clnew = clnew + dx *ag; cl_a = cl_a + dx_a*ag; cl_ms = cl_ms + dx *ag_ms; cl_ac = cl_ac + dx *ag_ac; cpg1 = cpg2; cpg1_ms = cpg2_ms; cpg1_ac = cpg2_ac; } //--- initialize under-relaxation factor rlx = 1.0; if(lalfa) { //===== alpha is prescribed: ac is cl //---- set change in re to account for cl changing, since re = re(cl) dac = (clnew - cl) / (1.0 - cl_ac - cl_ms*2.0*minf*minf_cl); //---- set under-relaxation factor if re change is too large if(rlx*dac > dclmax) rlx = dclmax/dac; if(rlx*dac < dclmin) rlx = dclmin/dac; } else { //===== cl is prescribed: ac is alpha //---- set change in alpha to drive cl to prescribed value dac = (clnew - clspec) / (0.0 - cl_ac - cl_a); //---- set under-relaxation factor if alpha change is too large if(rlx*dac > dalmax) rlx = dalmax/dac; if(rlx*dac < dalmin) rlx = dalmin/dac; } rmsbl = 0.0; rmxbl = 0.0; dhi = 1.5; dlo = -.5; //--- calculate changes in bl variables and under-relaxation if needed for(is=1;is<= 2;is++) { for(ibl=2; ibl<= nbl[is];ibl++) { iv = isys[ibl][is]; //------- set changes without underrelaxation dctau = vdel[1][1][iv] - dac*vdel[1][2][iv]; dthet = vdel[2][1][iv] - dac*vdel[2][2][iv]; dmass = vdel[3][1][iv] - dac*vdel[3][2][iv]; duedg = unew[ibl][is] + dac*u_ac[ibl][is] - uedg[ibl][is]; ddstr = (dmass - dstr[ibl][is]*duedg)/uedg[ibl][is]; //------- normalize changes if(ibl qAbs(rmxbl)) { rmxbl = dn1; if(ibl=itran[is]) vmxbl = "c"; imxbl = ibl; ismxbl = is; } if(rdn1 > dhi) rlx = dhi/dn1; if(rdn1 < dlo) rlx = dlo/dn1; //------- see if theta needs underrelaxation rdn2 = rlx*dn2; if(qAbs(dn2) > qAbs(rmxbl)) { rmxbl = dn2; vmxbl = "t"; imxbl = ibl; ismxbl = is; } if(rdn2 > dhi) rlx = dhi/dn2; if(rdn2 < dlo) rlx = dlo/dn2; //------- see if dstar needs underrelaxation rdn3 = rlx*dn3; if(qAbs(dn3) > qAbs(rmxbl)) { rmxbl = dn3; vmxbl = "d"; imxbl = ibl; ismxbl = is; } if(rdn3 > dhi) rlx = dhi/dn3; if(rdn3 < dlo) rlx = dlo/dn3; //------- see if ue needs underrelaxation rdn4 = rlx*dn4; if(qAbs(dn4) > qAbs(rmxbl)) { rmxbl = duedg; vmxbl = "u"; imxbl = ibl; ismxbl = is; } if(rdn4 > dhi) rlx = dhi/dn4; if(rdn4 < dlo) rlx = dlo/dn4; } } //--- set true rms change rmsbl = sqrt( rmsbl / (4.0*double( nbl[1]+nbl[2] )) ); if(lalfa) { //---- set underrelaxed change in reynolds number from change in lift cl = cl + rlx*dac; } else { //---- set underrelaxed change in alpha alfa = alfa + rlx*dac; adeg = alfa/dtor; } //--- update bl variables with underrelaxed changes for(is=1;is<= 2;is++) { for(ibl=2;ibl<= nbl[is];ibl++) { iv = isys[ibl][is]; dctau = vdel[1][1][iv] - dac*vdel[1][2][iv]; dthet = vdel[2][1][iv] - dac*vdel[2][2][iv]; dmass = vdel[3][1][iv] - dac*vdel[3][2][iv]; duedg = unew[ibl][is] + dac*u_ac[ibl][is] - uedg[ibl][is]; ddstr = (dmass - dstr[ibl][is]*duedg)/uedg[ibl][is]; ctau[ibl][is] = ctau[ibl][is] + rlx*dctau; thet[ibl][is] = thet[ibl][is] + rlx*dthet; dstr[ibl][is] = dstr[ibl][is] + rlx*ddstr; uedg[ibl][is] = uedg[ibl][is] + rlx*duedg; if(ibl>iblte[is]) { iw = ibl - iblte[is]; dswaki = wgap[iw]; } else dswaki = 0.0; //------- eliminate absurd transients if(ibl>=itran[is]) ctau[ibl][is] = qMin(ctau[ibl][is], 0.25); if(ibl<=iblte[is]) hklim = 1.02; else hklim = 1.00005; msq = uedg[ibl][is]*uedg[ibl][is]*hstinv / (gamm1*(1.0 - 0.5*uedg[ibl][is]*uedg[ibl][is]*hstinv)); dsw = dstr[ibl][is] - dswaki; dslim(dsw,thet[ibl][is],msq,hklim); dstr[ibl][is] = dsw + dswaki; //------- set new mass defect (nonlinear update) mass[ibl][is] = dstr[ibl][is] * uedg[ibl][is]; } } //--- equate upper wake arrays to lower wake arrays for(kbl=1;kbl<= nbl[2]-iblte[2];kbl++) { ctau[iblte[1]+kbl][1] = ctau[iblte[2]+kbl][2]; thet[iblte[1]+kbl][1] = thet[iblte[2]+kbl][2]; dstr[iblte[1]+kbl][1] = dstr[iblte[2]+kbl][2]; uedg[iblte[1]+kbl][1] = uedg[iblte[2]+kbl][2]; tau[iblte[1]+kbl][1] = tau[iblte[2]+kbl][2]; dis[iblte[1]+kbl][1] = dis[iblte[2]+kbl][2]; ctq[iblte[1]+kbl][1] = ctq[iblte[2]+kbl][2]; } // equivalence (va(1,1,1), unew(1,1)) , (vb(1,1,1), qnew(1) ) // equivalence (va(1,1,IVX), u_ac(1,1)) , (vb(1,1,ivx), q_ac(1) ) for (int kk = 1; kk<250; kk++) { vb[kk][1][1] = qnew[kk]; vb[kk][1][IVX] = q_ac[kk]; } for (is=1; is<= 2; is++){ for(ibl=2;ibl<= nbl[is];ibl++){ va[ibl][is][1] = unew[ibl][is]; va[ibl][is][IVX] = u_ac[ibl][is]; } } return true; } bool XFoil::viscal() { ////-------------------------------------- // converges viscous operating point ////-------------------------------------- int ibl; //---- calculate wake trajectory from current inviscid solution if necessary if(!lwake) xyWake(); // ---- set velocities on wake from airfoil vorticity for alpha=0, 90 qwcalc(); // ---- set velocities on airfoil and wake for initial alpha qiset(); if(!lipan) { if(lblini) gamqv(); // ----- locate stagnation point arc length position and panel index stfind(); // ----- set bl position -> panel position pointers iblpan(); // ----- calculate surface arc length array for current stagnation point location xicalc(); // ----- set bl position -> system line pointers iblsys(); } // ---- set inviscid bl edge velocity uinv from qinv uicalc(); if(!lblini) { // ----- set initial ue from inviscid ue for (ibl=1; ibl<= nbl[1];ibl++){ uedg[ibl][1] = uinv[ibl][1]; } for (ibl=1; ibl<= nbl[2];ibl++){ uedg[ibl][2] = uinv[ibl][2]; } } if(lvconv) { // ----- set correct cl if converged point exists qvfue(); /* if(lvisc){ if(!cpcalc(n+nw,qvis,qinf,minf,cpv)){ return false; } if(!cpcalc(n+nw,qinv,qinf,minf,cpi)){ return false; } } else if(!cpcalc(n,qinv,qinf,minf,cpi)){ return false; } */ if(lvisc){ cpcalc(n+nw,qvis,qinf,minf,cpv); cpcalc(n+nw,qinv,qinf,minf,cpi); } else cpcalc(n,qinv,qinf,minf,cpi); gamqv(); clcalc(xcmref,ycmref); cdcalc(); } // ---- set up source influence matrix if it doesn't exist if(!lwdij || !ladij) qdcalc(); return true; } bool XFoil::ViscalEnd() { /* if(!){ return false; } if(!cpcalc(n+nw,qvis,qinf,minf,cpv)){ return false; } */ cpcalc(n+nw,qinv,qinf,minf,cpi); cpcalc(n+nw,qvis,qinf,minf,cpv); if(lflap) mhinge(); return true; } bool XFoil::ViscousIter() { // Performs one iteration double eps1 =0.0001; QString str; setbl();// ------ fill newton system for bl variables blsolve();// ------ solve newton system with custom solver update();// ------ update bl variables if(lalfa) {// ------- set new freestream mach, re from new cl mrcl(cl, minf_cl, reinf_cl); comset(); } else{// ------- set new inviscid speeds qinv and uinv for new alpha qiset(); uicalc(); } qvfue();// ------ calculate edge velocities qvis(.) from uedg(..) gamqv();// ------ set gam distribution from qvis stmove();// ------ relocate stagnation point // ------ set updated cl,cd clcalc(xcmref,ycmref); cdcalc(); // ------ display changes and test for convergence if(rlx<1.0) { str =QString(" rms:%1 max:%2 at %3 %4 rlx:%5\n") .arg(rmsbl,0,'e',2).arg(rmxbl,0,'e',2).arg(imxbl).arg(ismxbl).arg(rlx,0,'f',3); } else if(qAbs(rlx-1.0)<0.001) { str =QString(" rms:%1 max:%2 at %3 %4\n") .arg(rmsbl,0,'e',2).arg(rmxbl,0,'e',2).arg(imxbl).arg(ismxbl); } WriteString(str); cdp = cd - cdf; str = QString(" a=%1 cl=%2\n cm=%3 cd=%4 => cdf=%5 cdp=%6\n\n") .arg(alfa/dtor,0,'f',3).arg(cl,0,'f',4).arg(cm,0,'f',4).arg(cd,0,'f',5).arg(cdf,0,'f',5).arg(cdp,0,'f',5); WriteString(str); int pos = str.indexOf("QN"); if(pos>0) { lvconv = false; str = "--------UNCONVERGED----------\n\n"; WriteString(str, true); return false; } if(rmsbl < eps1) { lvconv = true; avisc = alfa; mvisc = minf; str = "----------CONVERGED----------\n\n"; WriteString(str, true); } return true; } bool XFoil::xicalc() { //------------------------------------------------------------- // sets bl arc length array on each airfoil side and wake //------------------------------------------------------------- double telrat, crosp, dwdxte, aa, bb, zn; int i, ibl, is, iw; is = 1; xssi[1][is] = 0.0; for (ibl=2;ibl<= iblte[is];ibl++) { i = ipan[ibl][is]; xssi[ibl][is] = sst - s[i]; } is = 2; xssi[1][is] = 0.0; for (ibl=2;ibl<= iblte[is];ibl++) { i = ipan[ibl][is]; xssi[ibl][is] = s[i] - sst; } ibl = iblte[is] + 1; xssi[ibl][is] = xssi[ibl-1][is]; for (ibl=iblte[is]+2;ibl<= nbl[is];ibl++) { int i = ipan[ibl][is]; xssi[ibl][is] = xssi[ibl-1][is] + sqrt((x[i]-x[i-1])* (x[i]-x[i-1]) + (y[i]-y[i-1])*(y[i]-y[i-1])); } //---- trailing edge flap length to te gap ratio telrat = 2.50; //---- set up parameters for te flap cubics // dwdxte = yp[1]/xp[1] + yp[n]/xp[n] !!! bug 2/2/95 crosp = (xp[1]*yp[n] - yp[1]*xp[n]) / sqrt( (xp[1]*xp[1] + yp[1]*yp[1]) *(xp[n]*xp[n] + yp[n]*yp[n]) ); dwdxte = crosp / sqrt(1.0 - crosp*crosp); //---- limit cubic to avoid absurd te gap widths dwdxte = qMax(dwdxte,-3.0/telrat); dwdxte = qMin(dwdxte, 3.0/telrat); aa = 3.0 + telrat*dwdxte; bb = -2.0 - telrat*dwdxte; if(sharp) { for (iw=1; iw<=nw;iw++) wgap[iw] = 0.0; } else { //----- set te flap (wake gap) array is = 2; for (iw=1; iw<=nw;iw++) { ibl = iblte[is] + iw; zn = 1.0 - (xssi[ibl][is]-xssi[iblte[is]][is]) / (telrat*ante); wgap[iw] = 0.0; if(zn>=0.0) wgap[iw] = ante * (aa + bb*zn)*zn*zn; } } return true; } bool XFoil::xifset(int is) { //----------------------------------------------------- // sets forced-transition bl coordinate locations. //----------------------------------------------------- double chx, chy, chsq, str; if(xstrip[is]>=1.0) { xiforc = xssi[iblte[is]][is]; return false; } chx = xte - xle; chy = yte - yle; chsq = chx*chx + chy*chy; //---- calculate chord-based x/c, y/c for(int i=1; i<= n;i++){ w1[i] = ((x[i]-xle)*chx + (y[i]-yle)*chy) / chsq; w2[i] = ((y[i]-yle)*chx - (x[i]-xle)*chy) / chsq; } splind(w1,w3,s,n,-999.0,-999.0); splind(w2,w4,s,n,-999.0,-999.0); if(is==1) { //----- set approximate arc length of forced transition point for sinvrt str = sle + (s[1]-sle)*xstrip[is]; //----- calculate actual arc length sinvrt(str,xstrip[is],w1,w3,s,n); //----- set bl coordinate value xiforc = qMin((sst-str), xssi[iblte[is]][is]); } else{ //----- same for bottom side str = sle + (s[n]-sle)*xstrip[is]; sinvrt(str,xstrip[is],w1,w3,s,n); xiforc = qMin((str - sst) , xssi[iblte[is]][is]); } if(xiforc < 0.0) { //TRACE(" *** stagnation point is past trip on side %d\n", is); QString str = QString(QObject::tr(" *** stagnation point is past trip on side %1\n")).arg(is); WriteString(str); xiforc = xssi[iblte[is]][is]; } return true; } bool XFoil::xyWake() { //----------------------------------------------------- // sets wake coordinate array for current surface // vorticity and/or mass source distributions. //----------------------------------------------------- double ds, ds1, sx, sy, smod; double psi, psi_x,psi_y; // QString str(QObject::tr(" Calculating wake trajectory ...\n")); WriteString(str, true); // //--- number of wake points nw = n/8 + 2; if(nw>IWX) { QString str(QObject::tr(" XYWake: array size (IWX) too small.\n Last wake point index reduced.")); WriteString(str, true); nw = IWX; } ds1 = 0.5*(s[2] - s[1] + s[n] - s[n-1]); setexp(snew+n,ds1,waklen*chord,nw); xte = 0.5*(x[1]+x[n]); yte = 0.5*(y[1]+y[n]); //-- set first wake point a tiny distance behind te int i = n+1; sx = 0.5*(yp[n] - yp[1]); sy = 0.5*(xp[1] - xp[n]); smod = sqrt(sx*sx + sy*sy); nx[i] = sx / smod; ny[i] = sy / smod; x[i] = xte - 0.0001*ny[i]; y[i] = yte + 0.0001*nx[i]; s[i] = s[n]; //---- calculate streamfunction gradient components at first point psilin(i,x[i],y[i],1.0,0.0,psi,psi_x,false,false); psilin(i,x[i],y[i],0.0,1.0,psi,psi_y,false,false); //---- set unit vector normal to wake at first point nx[i+1] = -psi_x / sqrt(psi_x*psi_x + psi_y*psi_y); ny[i+1] = -psi_y / sqrt(psi_x*psi_x + psi_y*psi_y); //---- set angle of wake panel normal apanel[i] = atan2( psi_y , psi_x ); //---- set rest of wake points for(i=n+2; i<= n+nw; i++) { ds = snew[i] - snew[i-1]; //------ set new point ds downstream of last point x[i] = x[i-1] - ds*ny[i]; y[i] = y[i-1] + ds*nx[i]; s[i] = s[i-1] + ds; if(i!=n+nw) { //------- calculate normal vector for next point psilin(i,x[i],y[i],1.0,0.0,psi,psi_x,false,false); psilin(i,x[i],y[i],0.0,1.0,psi,psi_y,false,false); nx[i+1] = -psi_x / sqrt(psi_x*psi_x + psi_y*psi_y); ny[i+1] = -psi_y / sqrt(psi_x*psi_x + psi_y*psi_y); //------- set angle of wake panel normal apanel[i] = atan2( psi_y , psi_x ); } } //---- set wake presence flag and corresponding alpha lwake = true; awake = alfa; //---- old source influence matrix is invalid for the new wake geometry lwdij = false; return true; } int XFoil::arefine(double x[],double y[], double s[], double xs[], double ys[], int n, double atol, int ndim, double xnew[], double ynew[], double x1, double x2) { //------------------------------------------------------------- // adds points to a x,y spline contour wherever // the angle between adjacent segments at a node // exceeds a specified threshold. the points are // added 1/3 of a segment before and after the // offending node. // // the point adding is done only within x1..x2. // // intended for doubling the number of points // of eppler and selig airfoils so that they are // suitable for clean interpolation using xfoil's // arc-length spline routines. //------------------------------------------------------ // real x(*), y(*), s(*), xs(*), ys(*) // real xnew(ndim), ynew(ndim) bool lref; double atolr, dxm, dym, dxp, dyp, crsp, dotp, aseg, smid, xk, yk; int k, im, ip; atolr = atol * PI/180.0; k = 1; xnew[k] = x[1]; ynew[k] = y[1]; for( int i = 2; i<= n-1; i++) { im = i-1; ip = i+1; dxm = x[i] - x[i-1]; dym = y[i] - y[i-1]; dxp = x[i+1] - x[i]; dyp = y[i+1] - y[i]; crsp = dxm*dyp - dym*dxp; dotp = dxm*dxp + dym*dyp; if(crsp==0.0 && dotp==0.0) aseg = 0.0; else aseg = atan2(crsp, dotp ); lref = qAbs(aseg) > atolr; if(lref) { //------- add extra point just before this node smid = s[i] - 0.3333*(s[i]-s[i-1]); xk = seval(smid,x,xs,s,n); yk = seval(smid,y,ys,s,n); if(xk>=x1 && xk<=x2) { k = k + 1; if(k > ndim) goto stop90; xnew[k] = xk; ynew[k] = yk; } } //------ add the node itself k = k + 1; if(k > ndim) goto stop90; xnew[k] = x[i]; ynew[k] = y[i]; if(lref) { //------- add extra point just after this node smid = s[i] + 0.3333*(s[i+1]-s[i]); xk = seval(smid,x,xs,s,n); yk = seval(smid,y,ys,s,n); if(xk>=x1 && xk<=x2) { k = k + 1; if(k > ndim) goto stop90; xnew[k] = xk; ynew[k] = yk; } } } k = k + 1; if(k>ndim) goto stop90; xnew[k] = x[n]; ynew[k] = y[n]; // nnew = k; return k; stop90: QString str = "sdouble: Arrays will overflow. No action taken.\n"; WriteString(str, true); // nnew = 0; return 0; } int XFoil::cadd(int ispl, double atol, double xrf1, double xrf2) { int nnew, nbadd; // cang(xb,yb,nb,&imax,&amax); // Already done ??? if(ispl == 1) { sb[1] = 0.0; for(int i=2; i<= nb; i++){ if (xb[i]== xb[i-1] && yb[i]== yb[i-1]) sb[i] = sb[i-1]; else sb[i] = sb[i-1] + 1.0; } segspl(xb,xbp,sb,nb); segspl(yb,ybp,sb,nb); } nnew = arefine(xb,yb,sb,xbp,ybp,nb,atol,IBX,w1,w2,xrf1,xrf2); nbadd = nnew - nb; //TRACE("Number of points added: %d\n", nbadd); nb = nnew; for(int i=1; i<= nb; i++){ xb[i] = w1[i]; yb[i] = w2[i]; } scalc(xb,yb,sb,nb); segspl(xb,xbp,sb,nb); segspl(yb,ybp,sb,nb); geopar(xb,xbp,yb,ybp,sb,nb,w1,sble,chordb,areab, radble,angbte,ei11ba,ei22ba,apx1ba,apx2ba, ei11bt,ei22bt,apx1bt,apx2bt); cang(x,y,n,imax,amax); return nbadd; } void XFoil::flap() { //---------------------------------------------------- // modifies buffer airfoil for a deflected flap. // points may be added/subtracted in the flap // break vicinity to clean things up. //---------------------------------------------------- bool lchange; bool insid; int i, it2q, ib2q, idif; int npadd, ip; double atop, abot, chx, chy, fvx, fvy, crsp; double st1, st2, sb1, sb2, xt1, xt2, yt1, yt2, xb1, xb2; double yb1, yb2, sb1p, sb1q, sb2p, sb2q; double dsavg, sfrac, st1p, st1q, st2p, st2q; double dsnew; double tops, bots; double sind, cosd, dang, ang, ca, sa; double xbar, ybar; double stol; bool lt1new = false;// initialization arcds added to suppress level 4 warnings at compile time bool lt2new = false; bool lb1new = false; bool lb2new = false; int it1 = 0; int it2 = 0; int ib1 = 0; int ib2 = 0; double xt1new = 0.0; double yt1new= 0.0; double xt2new= 0.0; double yt2new= 0.0; double xb1new= 0.0; double yb1new= 0.0; double xb2new= 0.0; double yb2new= 0.0; /* if(ninput>=2) { xbf = rinput[1]; ybf = rinput[2]; } else{ xbf = -999.0; ybf = -999.0; }*/ getxyf(xb,xbp,yb,ybp,sb,nb,tops,bots,xbf, ybf); insid = inside(xb,yb,nb,xbf,ybf); // write(*,1050) xbf, ybf //1050 format(/' flap hinge: x,y =', 29.5 ) double rdef = ddef*PI/180.0;//ddef : flap deflection in degrees if(qAbs(rdef) <= 0.001) return; if(insid) { atop = qMax( 0.0 , -rdef ); abot = qMax( 0.0 , rdef ); } else{ chx = deval(bots,xb,xbp,sb,nb) - deval(tops,xb,xbp,sb,nb); chy = deval(bots,yb,ybp,sb,nb) - deval(tops,yb,ybp,sb,nb); fvx = seval(bots,xb,xbp,sb,nb) + seval(tops,xb,xbp,sb,nb); fvy = seval(bots,yb,ybp,sb,nb) + seval(tops,yb,ybp,sb,nb); crsp = chx*(ybf-0.5*fvy) - chy*(xbf-0.5*fvx); if(crsp >0.0) { //------ flap hinge is above airfoil atop = qMax(0.0, rdef); abot = qMax(0.0, rdef); } else{ //------ flap hinge is below airfoil atop = qMax(0.0, -rdef); abot = qMax(0.0, -rdef); } } //-- find upper and lower surface break arc length values... sss(tops,&st1,&st2,atop,xbf,ybf,xb,xbp,yb,ybp,sb,nb,1); sss(bots,&sb1,&sb2,abot,xbf,ybf,xb,xbp,yb,ybp,sb,nb,2); //-- ... and x,y coordinates xt1 = seval(st1,xb,xbp,sb,nb); yt1 = seval(st1,yb,ybp,sb,nb); xt2 = seval(st2,xb,xbp,sb,nb); yt2 = seval(st2,yb,ybp,sb,nb); xb1 = seval(sb1,xb,xbp,sb,nb); yb1 = seval(sb1,yb,ybp,sb,nb); xb2 = seval(sb2,xb,xbp,sb,nb); yb2 = seval(sb2,yb,ybp,sb,nb); // write(*,1100) xt1, yt1, xt2, yt2, xb1, yb1, xb2, yb2 // 1100 format(/' top breaks: x,y = ', 29.5, 4x, 29.5 // & /' bot breaks: x,y = ', 29.5, 4x, 29.5) //-- find points adjacent to breaks for(i=1; i<= nb-1; i++){ if(sb[i]<=st1 && sb[i+1]> st1) it1 = i+1; if(sb[i]< st2 && sb[i+1]>=st2) it2 = i; if(sb[i]<=sb1 && sb[i+1]> sb1) ib1 = i; if(sb[i]< sb2 && sb[i+1]>=sb2) ib2 = i+1; } dsavg = (sb[nb]-sb[1])/double(nb-1); //-- smallest fraction of s increments i+1 and i+2 away from break point sfrac = 0.33333; if(atop != 0.0) { st1p = st1 + sfrac*(sb[it1 ]-st1); st1q = st1 + sfrac*(sb[it1+1]-st1); if(sb[it1] < st1q) { //------ simply move adjacent point to ideal sfrac location xt1new = seval(st1q,xb,xbp,sb,nb); yt1new = seval(st1q,yb,ybp,sb,nb); lt1new = false; } else{ //------ make new point at sfrac location xt1new = seval(st1p,xb,xbp,sb,nb); yt1new = seval(st1p,yb,ybp,sb,nb); lt1new = true; } st2p = st2 + sfrac*(sb[it2 ]-st2); it2q = max(it2-1,1); st2q = st2 + sfrac*(sb[it2q]-st2); if(sb[it2] >st2q) { //------ simply move adjacent point xt2new = seval(st2q,xb,xbp,sb,nb); yt2new = seval(st2q,yb,ybp,sb,nb); lt2new = false; } else{ //------ make new point xt2new = seval(st2p,xb,xbp,sb,nb); yt2new = seval(st2p,yb,ybp,sb,nb); lt2new = true; } } if(abot != 0.0) { sb1p = sb1 + sfrac*(sb[ib1 ]-sb1); sb1q = sb1 + sfrac*(sb[ib1-1]-sb1); if(sb[ib1] >sb1q) { //------ simply move adjacent point xb1new = seval(sb1q,xb,xbp,sb,nb); yb1new = seval(sb1q,yb,ybp,sb,nb); lb1new = false; } else{ //------ make new point xb1new = seval(sb1p,xb,xbp,sb,nb); yb1new = seval(sb1p,yb,ybp,sb,nb); lb1new = true; } sb2p = sb2 + sfrac*(sb[ib2 ]-sb2); ib2q = qMin(ib2+1,nb); sb2q = sb2 + sfrac*(sb[ib2q]-sb2); if(sb[ib2] < sb2q) { //------ simply move adjacent point xb2new = seval(sb2q,xb,xbp,sb,nb); yb2new = seval(sb2q,yb,ybp,sb,nb); lb2new = false; } else{ //------ make new point xb2new = seval(sb2p,xb,xbp,sb,nb); yb2new = seval(sb2p,yb,ybp,sb,nb); lb2new = true; } } // dstop = qAbs(sb(it2)-sb(it1)); // dsbot = qAbs(sb(ib2)-sb(ib1)); sind = sin(rdef); cosd = cos(rdef); //-- rotate flap points about the hinge point (xbf,ybf) for (i=1; i<=nb; i++){ // if(i>=it1 && i<=ib1) go to 10 if(iib1) { xbar = xb[i] - xbf; ybar = yb[i] - ybf; xb[i] = xbf + xbar*cosd + ybar*sind; yb[i] = ybf - xbar*sind + ybar*cosd; } } idif = it1-it2-1; if(idif>0) { //--- delete points on upper airfoil surface which "disappeared". nb = nb -idif; it1 = it1-idif; ib1 = ib1-idif; ib2 = ib2-idif; for( i=it2+1; i<= nb; i++){ sb[i] = sb[i+idif]; xb[i] = xb[i+idif]; yb[i] = yb[i+idif]; } } idif = ib2-ib1-1; if(idif>0) { //--- delete points on lower airfoil surface which "disappeared". nb = nb -idif; ib2 = ib2-idif; for(i=ib1+1; i<= nb; i++){ sb[i] = sb[i+idif]; xb[i] = xb[i+idif]; yb[i] = yb[i+idif]; } } if(qAbs(atop) < 0.000001) { //---- arc length of newly created surface on top of airfoil dsnew = qAbs(rdef)*sqrt((xt1-xbf)* (xt1-xbf) + (yt1-ybf)* (yt1-ybf)); //---- number of points to be added to define newly created surface npadd = int(1.5*dsnew/dsavg + 1.0); // npadd = int(1.5*dsnew/dstop + 1.0) //---- skip everything if no points are to be added if(npadd!=0) {//go to 35 //---- increase coordinate array length to make room for the new point(s) nb = nb +npadd; it1 = it1+npadd; ib1 = ib1+npadd; ib2 = ib2+npadd; for(i=nb; i>= it1; i--){ xb[i] = xb[i-npadd]; yb[i] = yb[i-npadd]; } //---- add new points along the new surface circular arc segment dang = rdef / double(npadd); xbar = xt1 - xbf; ybar = yt1 - ybf; for(ip=1; ip<= npadd; ip++){ ang = dang*(double(ip) - 0.5); ca = cos(ang); sa = sin(ang); xb[it1-ip] = xbf + xbar*ca + ybar*sa; yb[it1-ip] = ybf - xbar*sa + ybar*ca; } } } else{ //---- set point in the corner and possibly two adjacent points npadd = 1; if(lt2new) npadd = npadd+1; if(lt1new) npadd = npadd+1; nb = nb +npadd; it1 = it1+npadd; ib1 = ib1+npadd; ib2 = ib2+npadd; for (i=nb; i>= it1; i--){ xb[i] = xb[i-npadd]; yb[i] = yb[i-npadd]; } if(lt1new) { xb[it1-1] = xt1new; yb[it1-1] = yt1new; xb[it1-2] = xt1; yb[it1-2] = yt1; } else { xb[it1 ] = xt1new; yb[it1 ] = yt1new; xb[it1-1] = xt1; yb[it1-1] = yt1; } xbar = xt2new - xbf; ybar = yt2new - ybf; if(lt2new) { xb[it2+1] = xbf + xbar*cosd + ybar*sind; yb[it2+1] = ybf - xbar*sind + ybar*cosd; } else{ xb[it2 ] = xbf + xbar*cosd + ybar*sind; yb[it2 ] = ybf - xbar*sind + ybar*cosd; } } // 35 continue if(qAbs(abot) <= 0.000001) { //---- arc length of newly created surface on top of airfoil dsnew = qAbs(rdef)*sqrt((xb1-xbf)* (xb1-xbf) + (yb1-ybf)* (yb1-ybf)); //---- number of points to be added to define newly created surface npadd = int(1.5*dsnew/dsavg + 1.0); //---- skip everything if no points are to be added if(npadd!=0) {//go to 45 //---- increase coordinate array length to make room for the new point(s) nb = nb +npadd; ib2 = ib2+npadd; for(i=nb;i>= ib2; i--){ xb[i] = xb[i-npadd]; yb[i] = yb[i-npadd]; } //---- add new points along the new surface circular arc segment dang = rdef / double(npadd); xbar = xb1 - xbf; ybar = yb1 - ybf; for(ip=1; ip<= npadd; ip++){ ang = dang*(double(ip) - 0.5); ca = cos(ang); sa = sin(ang); xb[ib1+ip] = xbf + xbar*ca + ybar*sa; yb[ib1+ip] = ybf - xbar*sa + ybar*ca; } } } else{ //---- set point in the corner and possibly two adjacent points npadd = 1; if(lb2new) npadd = npadd+1; if(lb1new) npadd = npadd+1; nb = nb +npadd; ib2 = ib2+npadd; for (i=nb; i>=ib2; i--){ xb[i] = xb[i-npadd]; yb[i] = yb[i-npadd]; } if(lb1new) { xb[ib1+1] = xb1new; yb[ib1+1] = yb1new; xb[ib1+2] = xb1; yb[ib1+2] = yb1; } else{ xb[ib1 ] = xb1new; yb[ib1 ] = yb1new; xb[ib1+1] = xb1; yb[ib1+1] = yb1; } xbar = xb2new - xbf; ybar = yb2new - ybf; if(lb2new) { xb[ib2-1] = xbf + xbar*cosd + ybar*sind; yb[ib2-1] = ybf - xbar*sind + ybar*cosd; } else{ xb[ib2 ] = xbf + xbar*cosd + ybar*sind; yb[ib2 ] = ybf - xbar*sind + ybar*cosd; } } // 45 continue //-- check new geometry for splinter segments stol = 0.2; scheck(xb,yb,&nb, stol, &lchange); //-- spline new geometry scalc(xb,yb,sb,nb); segspl(xb,xbp,sb,nb); segspl(yb,ybp,sb,nb); // geopar(xb,xbp,yb,ybp,sb,nb,w1,sble,chordb,areab, // radble,angbte,ei11ba,ei22ba,apx1ba,apx2ba, // ei11bt,ei22bt,apx1bt,apx2bt,thickb,cambrb); geopar(xb,xbp,yb,ybp,sb,nb,w1,sble,chordb,areab, radble,angbte,ei11ba,ei22ba,apx1ba,apx2ba, ei11bt,ei22bt,apx1bt,apx2bt); lbflap = true; // if(lgsym) { // write(*,*) // write(*,*) 'disabling symmetry enforcement' // lgsym = false; // } // lgeopl = false; // plot ? lgsame = false;// plot ? } bool XFoil::CheckAngles(){ cang(x,y,n, imax,amax); if(qAbs(amax)>angtol) { return true;// we have a coarse paneling } return false;// we have a fine paneling } bool XFoil::eiwset(int nc1){ //---------------------------------------------------- // calculates the uniformly-spaced circle-plane // coordinate array wc (omega), and the // corresponding complex unit numbers exp(inw) // for slow fourier transform operations. //---------------------------------------------------- // include 'circle.inc' // PI = 4.0*atan(1.0) int ic; //---- set requested number of points in circle plane nc = nc1; mc = int(nc1/4); mct = int(nc1/16); if(nc>ICX) { QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QXDirect::tr("Warning")); msgBox.setText("eiwset: Array overflow. Increase ICX."); msgBox.exec(); return false; } dwc = 2.0*PI / double(nc-1); for (ic=1; ic<=nc; ic++) wc[ic] = dwc*double(ic-1); //---- set m = 0 numbers for (ic=1; ic<=nc; ic++) eiw[ic][0] = complex(1.0, 0.0); //---- set m = 1 numbers for (ic=1; ic<=nc; ic++) eiw[ic][1] = exp(complex( 0.0 , wc[ic] ) ); //---- set m > 1 numbers by indexing appropriately from m = 1 numbers for(int m=2; m<= mc; m++){ for (int ic=1; ic<= nc;ic++){ int ic1 = m*(ic-1); ic1 = ic1%(nc-1) +1; eiw[ic][m] = eiw[ic1][1]; } } return true; } void XFoil::scinit(int n, double x[], double xp[], double y[], double yp[], double s[], double sle){ //---------------------------------------------------------- // calculates the circle-plane coordinate s(w) = sc // at each point of the current geometry. // a by-product is the complex-mapping coefficients cn. // (see cncalc header for more info). //---------------------------------------------------------- // include 'circle.inc' complex dcn, zle, zte; int ipass, ic; double sic, dxds, dyds, qim, dzwt; double ceps = 1.e-7; double seps = 5.e-7; //---- set te angle parameter agte = ( atan2(xp[n], -yp[n]) -atan2(xp[1], -yp[1]))/PI - 1.0; //---- set surface angle at first point ag0 = atan2( xp[1] , -yp[1] ); //---- temporary offset qo to make q(w)-qo = 0 at w = 0 , 2 PI // --- avoids gibbs problems with q(w)'s fourier sine transform qim0 = ag0 + 0.5*PI*(1.0+agte); xle = seval(sle,x,xp,s,n); yle = seval(sle,y,yp,s,n); //---- save te gap and airfoil chord double dxte = x[1] - x[n]; double dyte = y[1] - y[n]; dzte = complex(dxte,dyte); double chordx = 0.5*(x[1]+x[n]) - xle; double chordy = 0.5*(y[1]+y[n]) - yle; chordz = complex( chordx , chordy ); zleold = complex(xle, yle); // write(*,1100) real(dzte), imag(dzte), agte*180.0 //1100 format(/' current te gap dx dy =', 27.4, // & ' te angle =', f7.3,' deg.' / ) // write(*,*) 'initializing mapping coordinate ...' //---- set approximate slope ds/dw at airfoil nose double cvle = curv(sle,x,xp,y,yp,s,n) * s[n]; double cvabs = qAbs(cvle); double dsdwle = qMax(0.001, 0.5/cvabs ); double tops = sle/s[n]; double bots = (s[n]-sle)/s[n]; //---- set initial top surface s(w) double wwt = 1.0 - 2.0*dsdwle/tops; for (ic=1;ic<= (nc-1)/2+1;ic++) sc[ic] = tops*(1.0 - cos(wwt*wc[ic]) ) /(1.0 - cos(wwt*PI ) ); //---- set initial bottom surface s(w) wwt = 1.0 - 2.0*dsdwle/bots; for(ic=(nc-1)/2+2; ic<=nc ; ic++) sc[ic] = 1.0 - bots *(1.0 - cos(wwt*(wc[nc]-wc[ic])) ) /(1.0 - cos(wwt* PI ) ); //---- iteration loop for s(w) array for (ipass=1; ipass<= 30; ipass++){ //---- calculate imaginary part of harmonic function p(w) + iq(w) for (ic=1; ic<= nc;ic++){ sic = s[1] + (s[n]-s[1])*sc[ic]; dxds = deval(sic,x,xp,s,n); dyds = deval(sic,y,yp,s,n); //------ set q(w) - qo (qo defined so that q(w)-qo = 0 at w = 0 , 2 PI) qim = atan2(dxds, -dyds ) - 0.5*(wc[ic]-PI)*(1.0+agte)- qim0; piq[ic] = complex(0.0, qim ); } //---- fourier-decompose q(w) ftp(); //---- zero out average real part and add on qo we took out above cn[0] = complex( 0.0 , imag(cn[0])+qim0 ); //---- transform back to get entire piq = p(w) + iq(w) piqsum(); //---- save s(w) for monitoring of changes in s(w) by zccalc for (ic=1; ic<= nc;ic++) scold[ic] = sc[ic]; //---- correct n=1 complex coefficient cn for proper te gap for (int itgap=1; itgap<= 5;itgap++) { zccalc(1); //------ set current le,te locations zlefind(&zle,zc,wc,nc,piq,agte); zte = 0.5*(zc[1]+zc[nc]); dzwt = abs(zte-zle)/abs(chordz); dcn = -(zc[1] - zc[nc] - dzwt*dzte ) / (zc_cn[1][1] - zc_cn[nc][1]); cn[1] = cn[1] + dcn; piqsum(); if(std::abs(dcn) < ceps) break; // if(real(dcn)*real(dcn)+imag(dcn)*imag(dcn) < ceps*ceps) break; } double dscmax = 0.0; for(ic=1; ic<=nc;ic++) dscmax = qMax( dscmax , qAbs(sc[ic]-scold[ic]) ); if(dscmax < seps) break; } // 505 continue //---- normalize final geometry zcnorm(1); //---- set final s(w), x(w), y(w) arrays for old airfoil for (ic=1; ic<= nc; ic++){ scold[ic] = sc[ic]; xcold[ic] = real(zc[ic]); ycold[ic] = imag(zc[ic]); } for(ic=1; ic<= nc;ic++){ double sinw = 2.0*sin(0.5*wc[ic]); double sinwe = 0.0; if(sinw>0.0) sinwe = pow(sinw,(1.0-agte)); double hwc = 0.5*(wc[ic]-PI)*(1.0+agte) - 0.5*PI; zcoldw[ic] = sinwe * exp( piq[ic] + complex(0.0,hwc) ); } qimold = imag(cn[0]); return; } void XFoil::ftp(){ //---------------------------------------------------------------- // slow-fourier-transform p(w) using trapezoidal integration. //---------------------------------------------------------------- complex zsum; for (int m=0; m<= mc;m++){ zsum = complex(0.0,0.0); for(int ic=2; ic<= nc-1; ic++) zsum = zsum + piq[ic]*eiw[ic][m]; cn[m] = (0.5*(piq[1]*eiw[1][m] + piq[nc]*eiw[nc][m])+ zsum)*dwc / PI; } cn[0] = 0.5*cn[0]; return; } void XFoil::piqsum() { //--------------------------------------------- // inverse-transform to get back modified // speed function and its conjugate. //--------------------------------------------- complex zsum; for(int ic=1; ic <= nc; ic++){ zsum = complex(0.0,0.0); for(int m=0; m<= mc; m++){ zsum = zsum + cn[m]*conjg(eiw[ic][m]); } piq[ic] = zsum; } return; } complex XFoil::conjg(complex cplx) { double a = real(cplx); double b = imag(cplx); return complex(a, -b); } void XFoil::zcnorm(int mtest) { //----------------------------------------------- // normalizes the complex airfoil z(w) to // the old chord and angle, and resets the // influence coefficients dz/dcn . //----------------------------------------------- // include 'circle.inc' complex dzdw1, dzdw2; complex zcnew, zle, zte, zc_zte, zte_cn[IMX4+1]; int m, ic; //---- find current le location zlefind(&zle,zc,wc,nc,piq,agte); //---- place leading edge at origin for (ic=1; ic <= nc; ic++) { zc[ic] = zc[ic] - zle; } //---- set normalizing quantities and sensitivities zte = 0.5*(zc[1] + zc[nc]); for (m=1; m<= mtest; m++) zte_cn[m] = 0.5*(zc_cn[1][m] + zc_cn[nc][m]); //---- normalize airfoil to proper chord, put le at old position, //- and set sensitivities dz/dcn for the rescaled coordinates for (ic=1; ic<= nc; ic++){ zcnew = chordz*zc[ic]/zte; zc_zte = -zcnew/zte; zc[ic] = zcnew; for (m=1; m<= mtest; m++) zc_cn[ic][m] = chordz*zc_cn[ic][m]/zte + zc_zte*zte_cn[m]; } //---- add on rotation to mapping coefficient so qccalc gets the right alpha double qimoff = -imag( log(chordz/zte) ); cn[0] = cn[0] - complex(0.0, qimoff); //---- shift airfoil to put le at old location for (ic=1; ic<= nc; ic++) zc[ic] = zc[ic] + zleold; return; } void XFoil::zccalc(int mtest){ //-------------------------------------------------------- // calculates the airfoil geometry z(w) from the // harmonic function p(w) + iq(w). also normalizes // the coordinates to the old chord and calculates // the geometry sensitivities dz/dcn (1 < n < mtest) // for each point. //-------------------------------------------------------- // include 'circle.inc' complex dzdw1, dzdw2, dz_piq1, dz_piq2; //---- integrate upper airfoil surface coordinates from x,y = 4,0 int ic = 1; zc[ic] = complex(4.0,0.0); for (int m=1; m<= mtest; m++) zc_cn[ic][m] = complex(0.0,0.0); double sinw = 2.0*sin(0.5*wc[ic]); double sinwe = 0.0; if(sinw>0.0) sinwe = pow(sinw,(1.0-agte)); double hwc = 0.5*(wc[ic]-PI)*(1.0+agte) - 0.5*PI; dzdw1 = sinwe * exp( piq[ic] + complex(0.0,hwc) ); for (ic=2; ic<= nc; ic++){ sinw = 2.0*sin(0.5*wc[ic]); sinwe = 0.0; if(sinw>0.0) sinwe = pow(sinw,(1.0-agte)); hwc = 0.5*(wc[ic]-PI)*(1.0+agte) - 0.5*PI; dzdw2 = sinwe * exp( piq[ic] + complex(0.0,hwc)); zc[ic] = 0.5*(dzdw1+dzdw2)*dwc + zc[ic-1]; dz_piq1 = 0.5*(dzdw1 )*dwc; dz_piq2 = 0.5*( dzdw2)*dwc; for (int m=1; m<= mtest; m++){ zc_cn[ic][m] = dz_piq1*conjg(eiw[ic-1][m]) + dz_piq2*conjg(eiw[ic][m]) + zc_cn[ic-1][m]; } dzdw1 = dzdw2; } //---- set arc length array s(w) sc[1] = 0.0; for (ic=2; ic<= nc; ic++) sc[ic] = sc[ic-1] + std::abs(zc[ic]-zc[ic-1]); //---- normalize arc length for (ic=1; ic<= nc; ic++) sc[ic] = sc[ic]/sc[nc]; return; } void XFoil::zlefind(complex*zle,complexzc[],double wc[], int nc,complexpiq[], double agte){ complex dzdw1, dzdw2, zte; int ic, ic1,ic2; //---- temporary work arrays for splining near leading edge int ntx=33; double xc[33+1],yc[33+1], xcw[33+1],ycw[33+1]; int i, icle, nic; icle = 0;// added arcds zte = 0.5*(zc[1]+zc[nc]); //---- find point farthest from te double dmax = 0.0; for (ic = 1; ic<= nc;ic++){ double dist = std::abs( zc[ic] - zte); if(dist>dmax) { dmax = dist; icle = ic; } } //---- set restricted spline limits around leading edge ic1 = max( icle - (ntx-1)/2 , 1 ); ic2 = min( icle + (ntx-1)/2 , nc ); //---- set up derivatives at spline endpoints double sinw = 2.0*sin(0.5*wc[ic1]); double sinwe = pow(sinw,(1.0-agte)); double hwc = 0.5*(wc[ic1]-PI)*(1.0+agte) - 0.5*PI; dzdw1 = sinwe * exp( piq[ic1] + complex(0.0,hwc)); sinw = 2.0*sin(0.5*wc[ic2]); sinwe = pow(sinw,(1.0-agte)); hwc = 0.5*(wc[ic2]-PI)*(1.0+agte) - 0.5*PI; dzdw2 = sinwe * exp(piq[ic2] + complex(0.0,hwc)); //---- fill temporary x,y coordinate arrays for(ic=ic1; ic<=ic2;ic++){ i = ic-ic1+1; xc[i] = real(zc[ic]); yc[i] = imag(zc[ic]); } //---- calculate spline near leading edge with derivative end conditions nic = ic2 - ic1 + 1; splind(xc,xcw,wc+ic1-1,nic,real(dzdw1),real(dzdw2)); splind(yc,ycw,wc+ic1-1,nic,imag(dzdw1),imag(dzdw2)); double xcte = 0.5*real(zc[1] + zc[nc]); double ycte = 0.5*imag(zc[1] + zc[nc]); //---- initial guess for leading edge coordinate double wcle = wc[icle]; //---- newton loop for improved leading edge coordinate double xcle, ycle, dxdw, dydw, dxdd, dydd, xchord, ychord, res, resw, dwcle; bool found = false; for (int itcle=1; itcle <=10; itcle++){ xcle = seval(wcle,xc,xcw,wc+ic1-1,nic); ycle = seval(wcle,yc,ycw,wc+ic1-1,nic); dxdw = deval(wcle,xc,xcw,wc+ic1-1,nic); dydw = deval(wcle,yc,ycw,wc+ic1-1,nic); dxdd = d2val(wcle,xc,xcw,wc+ic1-1,nic); dydd = d2val(wcle,yc,ycw,wc+ic1-1,nic); xchord = xcle - xcte; ychord = ycle - ycte; //------ drive dot product between chord line and le tangent to zero res = xchord*dxdw + ychord*dydw; resw = dxdw *dxdw + dydw *dydw + xchord*dxdd + ychord*dydd; dwcle = -res/resw; wcle = wcle + dwcle; if(qAbs(dwcle)<0.00001) { found = true; break;//go to 51 } } if (!found) { QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QXDirect::tr("Warning")); msgBox.setText("zlefind: le location failed."); msgBox.exec(); wcle = wc[icle]; } // 51 continue //---- set final leading edge point complex coordinate xcle = seval(wcle,xc,xcw,wc+ic1-1, nic); ycle = seval(wcle,yc,ycw,wc+ic1-1, nic); *zle = complex(xcle,ycle); return; } void XFoil::mapgam(int iac, double &alg, double &clg, double &cmg) { //-------------------------------------------- // sets mapped q for current airfoil // for angle of attack or cl. // // iac=1: specified algam // iac=2: specified clgam //-------------------------------------------- // //---- calculate q(w), set number of circle points nsp qccalc(iac,&alg,&clg,&cmg,minf,qinf,&nsp,w1,w2,w5,w6); //---- store q(w), s(w), x(w), y(w) double chx = xte - xle; double chy = yte - yle; double chsq = chx*chx + chy*chy; for(int i=1;i<= nsp;i++){ qgamm[i] = w6[i]; sspec[i] = w5[i]; double xic = seval(s[n]*sspec[i],x,xp,s,n); double yic = seval(s[n]*sspec[i],y,yp,s,n); xspoc[i] = ((xic-xle)*chx + (yic-yle)*chy)/chsq; yspoc[i] = ((yic-yle)*chx - (xic-xle)*chy)/chsq; } ssple = sle/s[n]; return; } void XFoil::qccalc(int ispec,double *alfa, double *cl, double *cm, double minf, double qinf, int *ncir, double xcir[], double ycir[], double scir[], double qcir[]) { //--------------------------------------------------- // Calculates the surface speed from the complex // speed function so that either a prescribed // alfa or cl is achieved, depending on whether // ispec=1 or 2. The cl calculation uses the // transformed karman-tsien cp. //--------------------------------------------------- complex dz, za, eia, cmt,cft,cft_a; double rr1, rr2, rr3; int icp, ic, ipass, ll; double dalfa = 0.0; double alfcir, ppp, eppp; double sinw, sinwe; double cpinc1, cpi_q1, cpcom1,cpc_q1, cpc_a1; double cpinc2, cpi_q2, cpcom2,cpc_q2, cpc_a2; double qc_a[ICX+1]; // double minf; // double aeps = 5.0 *pow(10,-7); double aeps = 5.0e-007; //---- karman-tsien quantities double beta = sqrt(1.0 - minf*minf); double bfac = 0.5*minf*minf / (1.0 + beta); *ncir = nc; for (ll=1; ll(0.0,0.0); cft = complex(0.0,0.0); cft_a = complex(0.0,0.0); //------ set surface speed for current circle plane alpha for (ic=1; ic<= nc; ic++){ ppp = real(piq[ic]); eppp = exp(-ppp); sinw = 2.0*sin(0.5*wc[ic]); if(qAbs(agte)<=0.0001) sinwe = 1.0; else if(sinw>0.0) sinwe = pow(sinw,agte); else sinwe = 0.0; qcir[ic] = 2.0*cos(0.5*wc[ic] - alfcir)*sinwe * eppp; qc_a[ic] = 2.0*sin(0.5*wc[ic] - alfcir)*sinwe * eppp; xcir[ic] = real(zc[ic]); ycir[ic] = imag(zc[ic]); scir[ic] = sc[ic]; } //------ integrate compressible cp dz to get complex force cl + icd ic = 1; cpinc1 = 1.0 - (qcir[ic]/qinf)*(qcir[ic]/qinf); cpi_q1 = -2.0*qcir[ic]/qinf/qinf; cpcom1 = cpinc1 / (beta + bfac*cpinc1); cpc_q1 = (1.0 - bfac*cpcom1)/(beta + bfac*cpinc1) * cpi_q1; cpc_a1 = cpc_q1*qc_a[ic]; for(ic=1;ic<= nc;ic++){ icp = ic+1; if(ic==nc) icp = 1; cpinc2 = 1.0 - (qcir[icp]/qinf)*(qcir[icp]/qinf); cpi_q2 = -2.0*qcir[icp]/qinf/qinf; cpcom2 = cpinc2 / (beta + bfac*cpinc2); cpc_q2 = (1.0 - bfac*cpcom2)/(beta + bfac*cpinc2) * cpi_q2; cpc_a2 = cpc_q2*qc_a[icp]; za = (zc[icp] + zc[ic])*0.5 - complex(0.25,0.0); dz = zc[icp] - zc[ic]; cmt = cmt - 0.5*(cpcom1 + cpcom2)*dz*conjg(za) + (cpcom1 - cpcom2)*dz*conjg(dz)/12.0; cft = cft + 0.5*(cpcom1 + cpcom2)*dz; cft_a = cft_a + 0.5*(cpc_a1 + cpc_a2)*dz; cpcom1 = cpcom2; cpc_a1 = cpc_a2; } //------ rotate force vector into freestream coordinates eia = exp(complex(0.0,- *alfa)); cft = cft *eia; cft_a = cft_a*eia + cft*complex(0.0,-1.0); //------ lift is real part of complex force vector double clt = real(cft); double clt_a = real(cft_a); //------ moment is real part of complex moment *cm = real(cmt); if(ispec==1) { //------- if alpha is prescribed, we're done *cl = clt; return; } else{ //------- adjust alpha with newton-raphson to get specified cl dalfa = (*cl - clt)/clt_a; *alfa = *alfa + dalfa; if(qAbs(dalfa) < aeps) return; } } QString str = QString("qccalc: cl convergence failed. dalpha =%1").arg(dalfa,0,'f',4); QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QXDirect::tr("Warning")); msgBox.setText(str); msgBox.exec(); } void XFoil::mapgen(int n, double x[],double y[]) { //------------------------------------------------------- // calculates the geometry from the speed function // fourier coefficients cn, modifying them as needed // to achieve specified constraints. //------------------------------------------------------- // include 'circle.inc' // dimension x(nc), y(nc) // complex qq[IMX4+1][IMX4+1]; complex dcn[IMX4+1]; double dx, dy, qimoff, dcnmax; int ncn, m; //--- preset rotation offset of airfoil so that initial angle is close //- to the old airfoil's angle dx = xcold[2] - xcold[1]; dy = ycold[2] - ycold[1]; qim0 = atan2( dx , -dy ) + 0.5*PI*(1.0+agte); qimoff = qim0 - imag(cn[0]); cn[0] = cn[0] + complex( 0.0 , qimoff ); //--- inverse-transform and calculate geometry zc = z(w) //ccc call cnfilt(ffilt) piqsum(); zccalc(mct); //--- scale,rotate z(w) to get previous chord and orientation zcnorm(mct); //cc//-- put back rotation offset so speed routine qccalc gets the right alpha //cc cn[0] = cn[0] - cmplx( 0.0 , qimoff ) //--- enforce lighthill's first constraint cn[0] = complex( 0.0, imag(cn[0]) ); //--- number of free coefficients ncn = 1; //--- newton iteration loop for modified cn's for( int itercn=1; itercn<= 10;itercn++){ //----- fix te gap m = 1; dcn[m] = zc[1] - zc[nc] - dzte; for (int l=1; l<= ncn;l++){ qq[m][l] = zc_cn[1][l] - zc_cn[nc][l]; } cgauss(ncn,qq,dcn); dcnmax = 0.0; for(int m=1; m<= ncn;m++){ cn[m] = cn[m] - dcn[m]; dcnmax = qMax(std::abs(dcn[m]) , dcnmax ); } //ccc call cnfilt(ffilt) piqsum(); zccalc(mct); zcnorm(mct); // write(*,*) itercn, dcnmax if(dcnmax <= 5.0e-5) break;//go to 101 // 100 continue } // write(*,*) // write(*,*) 'mapgen: geometric constraints not fully converged' // 101 continue //--- return new airfoil coordinates n = nc; for(int i=1; i<= nc;i++){ x[i] = real(zc[i]); y[i] = imag(zc[i]); } // end ! mapgen } void XFoil::cgauss(int nn, complex z[IMX4+1][IMX4+1],complex r[IMX4+1]){ //******************************************* // solves general complex linear systems. //******************************************* // complex z(nsiz,nsiz), r(nsiz,nrhs) // nrhs = 1 // arcds : one right hand side is enough ! complex pivot, temp, ztmp; int np1; int nx; int l,k, n, np; for(np=1;np<= nn-1;np++){ np1 = np+1; //----- find max pivot index nx nx = np; for(n=np1; n<= nn;n++){ if(std::abs(z[n][np])-std::abs(z[nx][np])>0) nx = n; } pivot = complex(1.0,0.0)/z[nx][np]; //----- switch pivots z[nx][np] = z[np][np]; //----- switch rows & normalize pivot row for (l=np1; l<= nn;l++){ temp = z[nx][l]*pivot; z[nx][l] = z[np][l]; z[np][l] = temp; } // for (l=1; l<= nrhs; l++){ // temp = r[nx][l]*pivot; // r[nx][l] = r[np][l]; // r[np][l] = temp; // } temp = r[nx]*pivot; r[nx] = r[np]; r[np] = temp; //----- forward eliminate everything for(k=np1; k<= nn;k++){ ztmp = z[k][np]; // if(ztmp.eq.0.0) go to 15 for(l=np1; l<= nn;l++){ z[k][l] = z[k][l] - ztmp*z[np][l]; } // for(l=1; l<= nrhs; l++){ // r[k][l] = r[k][l] - ztmp*r[np][l]; // } r[k] = r[k] - ztmp*r[np]; } } //--- solve for last row // for(l=1; l<= nrhs;l++){ // r[nn][l] = r[nn][l]/z[nn][nn]; // } r[nn] = r[nn]/z[nn][nn]; //--- back substitute everything for(np=nn-1;np>= 1;np--){ np1 = np+1; // for(l=1; l<= nrhs; l++){ // for(k=np1; k<= nn;k++){ // r[np][l] = r[np][l] - z[np][k]*r[k][l]; // } // } for(k=np1; k<= nn;k++){ r[np] = r[np] - z[np][k]*r[k]; } } } double XFoil::qcomp(double g){ return g*(1.0-tklam) / (1.0 - tklam*(g/qinf)*(g/qinf)); } double XFoil::qincom(double qc, double qinf, double tklam){ //------------------------------------- // sets incompressible speed from // karman-tsien compressible speed //------------------------------------- if(tklam<1.0e-4 || qAbs(qc)<1.0e-4) //----- for nearly incompressible case or very small speed, use asymptotic // expansion of singular quadratic formula to avoid numerical problems return qc/(1.0 - tklam); else{ //----- use quadratic formula for typical case double tmp = 0.5*(1.0 - tklam)*qinf/(qc*tklam); return qinf*tmp*(sqrt(1.0 + 1.0/(tklam*tmp*tmp)) - 1.0); } } void XFoil::cncalc(double qc[], bool lsymm) { //---------------------------------------------------------- // calculates the complex fourier coefficients cn of // the real part of the harmonic function p(w) + iq(w) // which is set from either the current surface speed // function // e // 2 cos(w/2 - alpha) [2 sin(w/2)] // p(w) = ln ------------------------------- // q(w) // // // or the geometry function // // e // z'(w) [2 sin(w/2)] // p(w) = ln ------------------ // 2 sin(w/2) // // depending on whether the speed q(w) or the // geometry z(w) is specified for that particular // value of w. // (z(w) option is currently implemented separately in scinit) // // by fourier-transforming p(w) into a sequence // of fourier coefficients cn, its complex conjugate // function q(w) is automatically determined by an // inverse transformation in piqsum. the overall // p(w) + iq(w) then uniquely defines the overall // airfoil geometry, which is calculated in zccalc. // // if lsymm=t, then the real(cn) change from current // cn values is doubled, and imag(cn) is zeroed out. //---------------------------------------------------------- // real qc(nc) double qcw[ICX+1]; int ic,m; double wcle, alfcir; double cosw, sinw, sinwe, pfun, cnr; // common /work/ cnsav(0:imx) //c real wcj(2) if(nc > ICX) { QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QXDirect::tr("Warning")); msgBox.setText("CNCALC: array overflow."); msgBox.exec(); return; } //c//---- assume q(w) segment is entire airfoil // wcj(1) = wc(1) // wcj(2) = wc(nc) //cc // if(liqset) then //c//----- set w at q(w) segment endpoints // wcj(1) = wc[iq1] // wcj(2) = wc[iq2] // endif //---- spline q(w) splind(qc,qcw,wc,nc,-999.0,-999.0); //---- get approximate w value at stagnation point for (ic=2; ic<=nc; ic++){ if(qc[ic]<0.0) { wcle = wc[ic]; break; } } //---- set exact numerical w value at stagnation point from splined q(w) sinvrt(wcle,0.0,qc,qcw,wc,nc); //---- set corresponding circle plane alpha alfcir = 0.5*(wcle - PI); //---- calculate real part of harmonic function p(w) + iq(w) for(ic=2;ic<= nc-1;ic++){ cosw = 2.0*cos(0.5*wc[ic] - alfcir); sinw = 2.0*sin(0.5*wc[ic]); sinwe = pow(sinw,agte); //c if(wc[ic].ge.wcj(1) .and. wc[ic].le.wcj(2)) then //------- set p(w) from q(w) if(qAbs(cosw)<1.0e-4) //-------- use asymptotic form near stagnation point pfun = qAbs( sinwe/qcw[ic] ); else //-------- use actual expression pfun = qAbs( cosw*sinwe/qc[ic] ); //c else //cc ////------- set p(w) from old geometry derivative z'(w) //c pfun = abs( zcoldw[ic]*sinwe/sinw ) //cc //c endif piq[ic] = complex( log(pfun) , 0.0 ); } //---- extrapolate p(w) to te piq[1] = 3.0*piq[2] - 3.0*piq[3] + piq[4]; piq[nc] = 3.0*piq[nc-1] - 3.0*piq[nc-2] + piq[nc-3]; for(m=0; m<= mc;m++) cnsav[m] = cn[m]; //---- fourier-transform p(w) to get new cn coefficients ftp(); cn[0] = complex(0.0 , qimold); if(lsymm) { for( m=1; m<= mc; m++){ cnr = 2.0*real(cn[m]) - real(cnsav[m]); cn[m] = complex( cnr , 0.0 ); } } piqsum(); } void XFoil::qspcir() { //---------------------------------------------------- // sets qspec arrays for all design alphas or cls //---------------------------------------------------- for(int kqsp=1; kqsp<= nqsp;kqsp++) { qccalc(iacqsp,&alqsp[kqsp],&clqsp[kqsp],&cmqsp[kqsp],minf,qinf, &nsp,w1,w2,w5,qspec[kqsp]); splqsp(kqsp); } lqspec = true; } void XFoil::splqsp(int kqsp) { //------------------------------------------------------ // splines qspec(s). the end intervals are treated // specially to avoid gibbs-type problems from // blindly splining to the stagnation point. //------------------------------------------------------ int i; //---- usual spline with natural end bcs // splind(qspec[kqsp][2],qspecp[kqsp][2],sspec[2], nsp-2, -999.0,-999.0); splind(qspec[kqsp]+2-1,qspecp[kqsp]+2-1,sspec+2-1, nsp-2, -999.0,-999.0); //c//---- pseudo-monotonic spline with simple secant slope calculation //c call splina(qspec(2,kqsp),qspecp(2,kqsp),sspec(2),nsp-2) //---- end intervals are splined separately with natural bcs at // the trailing edge and matching slopes at the interior points i = 1; splind(qspec[kqsp]+i-1,qspecp[kqsp]+i-1,sspec+i-1,2,-999.0,qspecp[kqsp][i+1]); i = nsp-1; splind(qspec[kqsp]+i-1,qspecp[kqsp]+i-1,sspec+i-1,2, qspecp[kqsp][i],-999.0); } void XFoil::ExecMDES() { //----- calculate new mapping coefficients double clq; int kqsp = 1; int nqsp = 1; // for the present time if(!lqspec) { cncalc(qspec[kqsp],lqsym); //----- set new qspec(s) for all alphas or cls qspcir(); } for(kqsp=1; kqsp<= nqsp; kqsp++){ //cc call qspplt(iqmod1,iqmod2,kqsp,ntqspl) //cc if(lqsym) call qspplt(nsp-iqmod2+1,nsp-iqmod1+1,kqsp,ntqspl) qspint(kqsp, clq); //------- set new cl only if alpha is prescribed if(iacqsp==1) clqsp[kqsp] = clq; } lcnpl = false; mapgen(nb,xb,yb); //----- spline new buffer airfoil scalc(xb,yb,sb,nb); splind(xb,xbp,sb,nb,-999.0,-999.0); splind(yb,ybp,sb,nb,-999.0,-999.0); geopar(xb,xbp,yb,ybp,sb,nb, w1,sble,chordb,areab,radble,angbte, ei11ba,ei22ba,apx1ba,apx2ba,ei11bt,ei22bt,apx1bt,apx2bt); } void XFoil::qspint(int kqsp, double &clq) { //-------------------------------------------- // integrates circle-plane array surface // pressures to get cl and cm //-------------------------------------------- // include 'circle.inc' // dimension qspec(nc) // real minf int i, ip; double sa,ca, cpq1, cpq2, beta, bfac, cqinc; double dx,dy,du,ax,ay,aq; sa = sin(alqsp[kqsp]); ca = cos(alqsp[kqsp]); beta = sqrt(1.0 - minf*minf); bfac = 0.5*minf*minf / (1.0 + beta); clq = 0.0; cmqsp[kqsp] = 0.0; i = 1; cqinc = 1.0 - (qspec[kqsp][i]/qinf)*(qspec[kqsp][i]/qinf); cpq1 = cqinc / (beta + bfac*cqinc); for(i=1; i<=nc; i++){ ip = i+1; if(i==nc) ip = 1; cqinc = 1.0 - (qspec[kqsp][ip]/qinf)* (qspec[kqsp][ip]/qinf); cpq2 = cqinc / (beta + bfac*cqinc); dx = (xcold[ip] - xcold[i])*ca + (ycold[ip] - ycold[i])*sa; dy = (ycold[ip] - ycold[i])*ca - (xcold[ip] - xcold[i])*sa; du = cpq2 - cpq1; ax = 0.5*(xcold[ip]+xcold[i])*ca + 0.5*(ycold[ip]+ycold[i])*sa; ay = 0.5*(ycold[ip]+ycold[i])*ca - 0.5*(xcold[ip]+xcold[i])*sa; aq = 0.5*(cpq2 + cpq1); clq = clq + dx* aq; cmqsp[kqsp] = cmqsp[kqsp] - dx*(aq*(ax-0.25) + du*dx/12.0) - dy*(aq* ay + du*dy/12.0); cpq1 = cpq2; } } void XFoil::smooq(int kq1,int kq2,int kqsp) { //-------------------------------------------- // smooths qspec(s) inside target segment //-------------------------------------------- int i; double smool, smoosq, ds, dsm, dsp, dso, qspp1, qspp2; //------ mixed inverse: use arc length coordinate for (i=1; i<= nsp;i++){ w8[i] = sspec[i]; } if(kq2-kq1 < 2) { // write(*,*) 'segment is too short. no smoothing possible.' return; } //---- set smoothing length ( ~ distance over which data is smeared ) smool = 0.002*(w8[nsp] - w8[1]); //---- set up tri-diagonal system for smoothed qspec smoosq = smool*smool; for (i=kq1+1; i<= kq2-1; i++){ dsm = w8[i ] - w8[i-1]; dsp = w8[i+1] - w8[i ]; dso = 0.5*(w8[i+1] - w8[i-1]); w1[i] = smoosq * ( - 1.0/dsm) / dso; w2[i] = smoosq * ( 1.0/dsp + 1.0/dsm) / dso + 1.0; w3[i] = smoosq * (-1.0/dsp ) / dso; } //---- set fixed-qspec end conditions w2[kq1] = 1.0; w3[kq1] = 0.0; w1[kq2] = 0.0; w2[kq2] = 1.0; if(lqslop) { //----- also enforce slope matching at endpoints i = kq1 + 1; dsm = w8[i ] - w8[i-1]; dsp = w8[i+1] - w8[i ]; ds = w8[i+1] - w8[i-1]; w1[i] = -1.0/dsm - (dsm/ds)/dsm; w2[i] = 1.0/dsm + (dsm/ds)/dsm + (dsm/ds)/dsp; w3[i] = - (dsm/ds)/dsp; qspp1 = w1[i]*qspec[kqsp][i-1] + w2[i]*qspec[kqsp][i] + w3[i]*qspec[kqsp][i+1]; i = kq2 - 1; dsm = w8[i ] - w8[i-1]; dsp = w8[i+1] - w8[i ]; ds = w8[i+1] - w8[i-1]; w1[i] = (dsp/ds)/dsm; w2[i] = -1.0/dsp - (dsp/ds)/dsp - (dsp/ds)/dsm; w3[i] = 1.0/dsp + (dsp/ds)/dsp; qspp2 = w1[i]*qspec[kqsp][i-1] + w2[i]*qspec[kqsp][i] + w3[i]*qspec[kqsp][i+1]; qspec[kqsp][kq1+1] = qspp1; qspec[kqsp][kq2-1] = qspp2; } //---- solve for smoothed qspec array // trisol(w2[kq1],w1[kq1],w3[kq1],qspec[kqsp][kq1],(kq2-kq1+1)); trisol(w2+kq1-1,w1+kq1-1,w3+kq1-1,qspec[kqsp]+kq1-1,(kq2-kq1+1)); } void XFoil::Filter(double cfilt) { //----- apply modified hanning filter to cn coefficients double clq; cnfilt(cfilt); piqsum(); qspcir(); // write(*,1200) algam/dtor,clgam,cmgam for(int kqsp=1; kqsp<= nqsp; kqsp++) { // qspint(alqsp[kqsp],qspec[kqsp][1],qinf,minf,clq,cmqsp[kqsp]); qspint(kqsp, clq); //------- set new cl only if alpha is prescribed if(iacqsp == 1) clqsp[kqsp] = clq; // write(*,1210) kqsp,alqsp(kqsp)/dtor,clqsp(kqsp),cmqsp(kqsp) } lqspec = true; } void XFoil::cnfilt(double ffilt) { //------------------------------------- // filters out upper harmonics // with modified hanning filter. //------------------------------------- double cwt, cwtx; double freq; if(ffilt<=0.00001) return; for(int m=0; m<= mc; m++){ freq = double(m)/double(mc); cwt = 0.5*(1.0 + cos(PI*freq)); cwtx = cwt; if(ffilt>0.0) cwtx = pow(cwt,ffilt); cn[m] = complex(real(cn[m]) * cwtx, imag(cn[m]) * cwtx); } } void XFoil::pert_init(int kqsp) { double dx,dy, qimoff; //---- calculate mapping coefficients for initial airfoil shape // cncalc(qspec,false); cncalc(qspec[kqsp]+1-1,false); //---- preset rotation offset of airfoil so that initial angle is close //- to the old airfoil's angle dx = xcold[2] - xcold[1]; dy = ycold[2] - ycold[1]; qim0 = atan2(dx, -dy) + 0.5*PI*(1.0+agte); qimoff = qim0 - imag(cn[0]); cn[0] = cn[0] + complex(0.0, qimoff); // write(*,*) // write(*,*) 'current mapping coefficients...' // write(*,*) ' n re(cn) im(cn)' //cc do m = 1, nc // do m = 1, min(nc,32) // write(*,1010) m, real(cn(m)), imag(cn(m)) // 1010 format(4x,i4, 212.6) // enddo /* 10 write(*,1050) 1050 format(/4x,'enter n, delta(cnr), delta(cni): ', $) read(*,*,err=10) m, dcnr, dcni if(m.<=0) { go to 10; } else if(m>nc) { write(*,*) 'max number of modes is', nc go to 10; }*/ // cn[m] = cn[m] + complex(dcnr, dcni); } void XFoil::pert_process(int kqsp) { int m, ncn; // double dx,dy,qimoff; complex qq[IMX/4+1][IMX/4+1],dcn[IMX/4+1]; //-------------------------------------------------------- // calculates the perturbed geometry resulting from // one cn mapping coefficient being perturbed by user. //-------------------------------------------------------- // include 'circle.inc' // dimension qspec(icx) //---- inverse-transform and calculate geometry //cc call cnfilt(ffilt) piqsum(); zccalc(mct); //---- normalize chord and set exact previous alpha zcnorm(mct); //---- put back rotation offset so speed routine qccalc gets the right alpha //cc cn(0) = cn(0) - cmplx(0.0 , qimoff ) //---- enforce lighthill's first constraint cn[0] = complex(0.0, imag(cn[0]) ); //---- number of free coefficients ncn = 1; //---- newton iteration loop for modified cn's bool bConv = false; for(int itercn=1; itercn<= 10; itercn++) { //------ fix te gap m=1; dcn[m] = zc[1] - zc[nc] - dzte; for (int l=1; l<= ncn; l++){ qq[m][l] = zc_cn[1][l] - zc_cn[nc][l]; } // cgauss(IMX/4,ncn,qq,dcn,1); cgauss(ncn,qq,dcn); double dcnmax = 0.0; for (m=1; m<= ncn; m++){ cn[m] = cn[m] - dcn[m]; dcnmax = max(std::abs(dcn[m]), dcnmax ); } //cc call cnfilt(ffilt) piqsum(); zccalc(mct); zcnorm(mct); // write(*,*) itercn, dcnmax if(dcnmax<=5.0e-5){ bConv = true; break; } } if(!bConv) { QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QXDirect::tr("Warning")); msgBox.setText("TE gap,chord did not converge"); msgBox.exec(); return; } qspcir(); } void XFoil::InitMDES() { // double xsp[IBX], ysp[IBX][IPX], yspd[IBX][IPX]; int ntqspl; // save comold, argold ??? lrecalc = false; if(n==0) { // write(*,*) '*** no airfoil available ***' return; } lcnpl = false; // lsym = true; ffilt = 0.0; ntqspl = 1; if(lqslop) ntqspl = 4; //---- see if current qspec, if any, didn't come from mixed-inverse if(nsp!=nc1){ lqspec = false; iq1 = 1; iq2 = nc1; } //---- initialize fourier transform arrays if it hasn't been done if(!leiw) eiwset(nc1); leiw = true; //---- if qspec alpha has never been set, set it to current alpha if(nqsp == 0) { iacqsp = 1; alqsp[1] = alfa; nqsp = 1; } if(!lscini) { //------ initialize s(w) for current airfoil, generating its cn coefficients scinit(n,x,xp,y,yp,s,sle); lscini = true; //------ set up to initialize qspec to current conditions lqspec = false; } //---- set initial q for current alpha algam = alfa; mapgam(1,algam,clgam,cmgam); // TRACE("Current Q Operating conditions : %4 %4\n", algam/dtor, clgam); if(!lqspec) { //------ set cn coefficients from current q cncalc(qgamm,false); //------ set qspec from cn coefficients qspcir(); // write(*,1190) } } bool XFoil::InitQDES() { int ntqspl, kqtarg; double chx, chy, chsq; QString FileName = QDir::tempPath() + "/XFLR5.log"; QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return false; pXFile = &XFile; lrecalc = false; if(n==0) { // write(*,*) '*** no airfoil available ***' return false; } // lsym = true; //---- number of sub-intervals for qspec(s) plotting ntqspl = 1; if(lqslop) ntqspl = 8; //---- make sure a current solution exists specal(); //---- see if current qspec, if any, didn't come from full-inverse if(nsp!=n) { lqspec = false; liqset = false; } //---- set alpha, etc corresponding to q algam = alfa; clgam = cl; cmgam = cm; //---- set "old" speed distribution q, arc length, and x/c,y/c arrays chx = xte - xle; chy = yte - yle; chsq = chx*chx + chy*chy; nsp = n; for (int i=1; i<= nsp; i++){ qgamm[i] = gam[i]; sspec[i] = s[i]/s[n]; xspoc[i] = ((x[i]-xle)*chx + (y[i]-yle)*chy)/chsq; yspoc[i] = ((y[i]-yle)*chx - (x[i]-xle)*chy)/chsq; } ssple = sle/s[n]; // write(*,1150) algam/dtor, clgam // 1150 format(/' current q operating condition:' // & /' alpha = ', f8.3, ' deg. cl = ', f8.4 / ) if(!lqspec) { //----- initialize qspec to "old" solution and notify user nqsp = 1; kqtarg = 1; gamqsp(1); // write(*,1155); lqspec = true; } XFile.close(); XFile.remove(FileName); return true; } void XFoil::gamqsp(int kqsp) { //------------------------------------------------ // sets qspec(s,k) from current speed q(s). //------------------------------------------------ alqsp[kqsp] = algam; clqsp[kqsp] = clgam; cmqsp[kqsp] = cmgam; for (int i=1; i<= nsp; i++){ qspec[kqsp][i] = qgamm[i]; } //---- zero out qspec dofs qdof0 = 0.0; qdof1 = 0.0; qdof2 = 0.0; qdof3 = 0.0; splqsp(kqsp); //---- reset target segment endpoints if(!liqset) { iq1 = 1; iq2 = nsp; } } bool XFoil::mixed(int kqsp) { //------------------------------------------------- // performs a mixed-inverse calculation using // the specified surface speed array qspec. //------------------------------------------------- int i,inmax, igmax, j, iter; double sina, cosa; double bwt, fs, psi, psi_n; double ag1, ag2, abis, cbis, sbis; double ds1, ds2, dsmin, xbis, ybis, qbis; double res; double dnmax, dgmax; QString strong; //---- distance of internal control point ahead of sharp te // (fraction of smaller panel length adjacent to te) bwt = 0.1; cosa = cos(alfa); sina = sin(alfa); scalc(x,y,s,n); //---- zero-out and set dof shape functions for (i=1; i<= n; i++){ qf0[i] = 0.0; qf1[i] = 0.0; qf2[i] = 0.0; qf3[i] = 0.0; } //---- set dof shape functions and specified speed for(i=iq1; i<= iq2; i++){ fs = (s[i]-s[iq1]) / (s[iq2]-s[iq1]); //ccc qf0[i] = (1.0-fs)**2 //ccc qf1[i] = fs**2 qf0[i] = 1.0 - fs; qf1[i] = fs; if(lcpxx) { qf2[i] = exp(-5.0* fs ); qf3[i] = exp(-5.0*(1.0-fs)); } else{ qf2[i] = 0.0; qf3[i] = 0.0; } gam[i] = qspec[kqsp][i] + qdof0*qf0[i] + qdof1*qf1[i] + qdof2*qf2[i] + qdof3*qf3[i]; } //---- perform newton iterations on the new geometry for(iter=1; iter<= niterq; iter++){ for (i=1; i<= n+5; i++){ for (j=1; j<= n+5;j++){ q[i][j] = 0.0; } } //---- calculate normal direction vectors along which the nodes move ncalc(x,y,s,n,nx,ny); //---- go over all nodes, setting up psi = psi0 equations for(i=1; i<= n; i++){ psilin(i,x[i],y[i],nx[i],ny[i],psi,psi_n,true,false); dzdn[i] = dzdn[i] + psi_n; //------ fill columns for specified geometry location for(j=1; j<= iq1-1; j++){ q[i][j] += + dzdg[j]; } //------ fill columns for specified surface speed location for(j=iq1; j<= iq2; j++){ q[i][j] += dzdn[j]; } //------ fill columns for specified geometry location for(j=iq2+1; j<= n; j++){ q[i][j] += dzdg[j]; } //------ set residual dq[i] = psio - psi; //------ fill global unknown columns q[i][n+1] += - 1.0; q[i][n+2] += z_qdof0; q[i][n+3] += z_qdof1; q[i][n+4] += z_qdof2; q[i][n+5] += z_qdof3; } //---- set up kutta condition dq[n+1] = -( gam[1] + gam[n] ); gamlin(n+1,1,1.0); gamlin(n+1,n,1.0); if(sharp) { //----- set zero internal velocity in te corner //----- set te bisector angle ag1 = atan2(-yp[1],-xp[1] ); ag2 = atanc( yp[n], xp[n],ag1); abis = 0.5*(ag1+ag2); cbis = cos(abis); sbis = sin(abis); //----- minimum panel length adjacent to te ds1 = sqrt( (x[1]-x[2] )*(x[1]-x[2] ) + (y[1]-y[2] )*(y[1]-y[2] )); ds2 = sqrt( (x[n]-x[n-1])*(x[n]-x[n-1]) + (y[n]-y[n-1])*(y[n]-y[n-1])); dsmin = min( ds1 , ds2 ); //----- control point on bisector just ahead of te point xbis = xte - bwt*dsmin*cbis; ybis = yte - bwt*dsmin*sbis; //ccc write(*,*) xbis, ybis //----- set velocity component along bisector line psilin(0,xbis,ybis,-sbis,cbis,psi,qbis,false,true); //c//--- res = dqdgj*gamj + dqdmj*massj + qinf*(cosa*cbis + sina*sbis) res = qbis; for(j=1; j<= n+5; j++){ q[n][j] = 0.0; } //----- dres/dgamj for(j=1; j<= n; j++){ gamlin(n,j, dqdg[j]); q[n][j] = dqdg[j]; } //----- dres/dpsio q[n][n+1] = 0.0; //----- -dres/duinf dq[n] = -res; } //---- pinned iq1 point condition q[n+2][iq1] = 1.0; dq[n+2] = 0.0; //---- pinned iq2 point condition q[n+3][iq2] = 1.0; dq[n+3] = 0.0; if(iq1>1 && lcpxx) { //----- speed regularity iq1 condition res = gam[iq1-1] - 2.0* gam[iq1] + gam[iq1+1] - (qspec[kqsp][iq1-1] - 2.0*qspec[kqsp][iq1] + qspec[kqsp][iq1+1] ); gamlin(n+4,iq1-1, 1.0); gamlin(n+4,iq1 ,-2.0); gamlin(n+4,iq1+1, 1.0); dq[n+4] = -res; } else{ //----- zero dof condition q[n+4][n+4] = 1.0; dq[n+4] = -qdof2; } if(iq2 qAbs(dgmax)) { dgmax = dq[i]; igmax = i; } } //---- update panel nodes inside target segment for(i=iq1; i<= iq2; i++){ x[i] += nx[i]*dq[i]; y[i] += ny[i]*dq[i]; if(qAbs(dq[i]) > qAbs(dnmax)) { dnmax = dq[i]; inmax = i; } } //---- update surface speed gam after target segment for(i=iq2+1; i<= n; i++){ gam[i] += dq[i]; if(qAbs(dq[i]) > qAbs(dgmax)) { dgmax = dq[i]; igmax = i; } } //---- update gloabal variables psio = psio + dq[n+1]; qdof0 = qdof0 + dq[n+2]; qdof1 = qdof1 + dq[n+3]; qdof2 = qdof2 + dq[n+4]; qdof3 = qdof3 + dq[n+5]; cosa = cos(alfa); sina = sin(alfa); scalc(x,y,s,n); //---- set correct surface speed over target segment including dof contributions for(i=iq1; i<= iq2; i++){ gam[i] = qspec[kqsp][i] + qdof0*qf0[i] + qdof1*qf1[i] + qdof2*qf2[i] + qdof3*qf3[i]; } //---- update everything else tecalc(); clcalc(xcmref,ycmref); /* write(*,2000) dnmax,inmax,dgmax,igmax,cl & ,dq(n+2),dq(n+3) & ,dq(n+4),dq(n+5) 2000 format(/' dnmax =',e10.3,i4,' dqmax =',e10.3,i4,' cl =',f7.4 & /' dqf1 =',e10.3,4x,' dqf2 =',e10.3 & /' dqf3 =',e10.3,4x,' dqf4 =',e10.3)*/ dnTrace[iter] = qAbs(dnmax); dgTrace[iter] = qAbs(dgmax); // TRACE("%d dNMax = %.3e dGMax = %.3e\n",iter, dnmax, dgmax); if(qAbs(dnmax)<5.0e-5 && qAbs(dgmax)<5.0e-4) { // write(*,*) // write(*,*) 'new current airfoil generated' // write(*,*) 'old buffer airfoil unchanged' QMax = iter; return true; } } QMax = niterq; // TRACE("Unconverged - shit/Schei�e/merde !\n"); // TRACE("not quite converged. can exec again if necessary.\n"); return false; } void XFoil::gamlin(int i, int j, double coef){ //------------------------------------------------------------------- // adds on jacobian entry for point i due to node speed gam at j. // gam is either a local unknown if outside target segment, // or dependent on global qspec dof's if inside target segment. //------------------------------------------------------------------- if(j>=iq1 && j<=iq2) { //----- inside target segment q[i][n+2] += coef*qf0[j]; q[i][n+3] += coef*qf1[j]; q[i][n+4] += coef*qf2[j]; q[i][n+6] += coef*qf3[j]; } else{ //----- outside target segment q[i][j] += coef; } } bool XFoil::ExecQDES() { int kqsp, i; //---- check if target segment includes stagnation point ist = 0; for (i=iq1; i<= iq2-1; i++){ if(qgamm[i]>=0.0 && qgamm[i+1]<0.0) ist = i; } if(ist!=0) { QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QXDirect::tr("Warning")); msgBox.setText(QXDirect::tr("Target segment cannot include\nstagnation point in mixed-inverse")); msgBox.exec(); return false; } kqsp = 1; clspec = clqsp[kqsp]; //ccc call askr('enter specified cl^',clspec) //----- save current coordinates for restoration if requested for(i=1; i<= n; i++){ xb[i] = x[i]; yb[i] = y[i]; sb[i] = s[i]; xbp[i] = xp[i]; ybp[i] = yp[i]; } nb = n; lgsame = true; // write(*,*) // write(*,*) 'current airfoil saved in buffer airfoil' //----- execute mixed-inverse calculation // call aski('enter max number of iterations^',niterq) bool bRes = mixed(kqsp); adeg = alfa/dtor; //----- spline new airfoil shape scalc(x,y,s,n); splind(x,xp,s,n,-999.0,-999.0); splind(y,yp,s,n,-999.0,-999.0); ncalc(x,y,s,n,nx,ny); lefind(sle,x,xp,y,yp,s,n); xle = seval(sle,x,xp,s,n); yle = seval(sle,y,yp,s,n); chord = sqrt((0.5*(x[1]+x[n]) - xle)*(0.5*(x[1]+x[n]) - xle) +(0.5*(y[1]+y[n]) - yle)*(0.5*(y[1]+y[n]) - yle)); tecalc(); apcalc(); algam = alfa; nsp = n; for (i=1; i<= n; i++){ qgamm[i] = gam[i]; sspec[i] = s[i]/s[n]; } ssple = sle/s[n]; //----- set inviscid surface speeds and calculate compressible cp for(i=1;i<= n;i++){ qinv[i] = gam[i]; } cpcalc(n,qinv,qinf,minf,cpi); //----- influence coefficients & other stuff is no longer valid for new airfoil lgamu = false; lqinu = false; lwake = false; lqaij = false; ladij = false; lwdij = false; lipan = false; lvconv = false; lscini = false; //ccc lblini = false lgsame = false; return bRes; } void XFoil::RestoreQDES(){ // Foil is restored from CXInverse rather than from XFoil /* for (int i=1; i<= n; i++){ x[i] = xb[i]; y[i] = yb[i]; }*/ scalc(x,y,s,n); splind(x,xp,s,n,-999.0,-999.0); splind(y,yp,s,n,-999.0,-999.0); ncalc(x,y,s,n,nx,ny); lefind(sle,x,xp,y,yp,s,n); xle = seval(sle,x,xp,s,n); yle = seval(sle,y,yp,s,n); chord = sqrt((0.5*(x[1]+x[n]) - xle)*(0.5*(x[1]+x[n]) - xle) +(0.5*(y[1]+y[n]) - yle)*(0.5*(y[1]+y[n]) - yle)); tecalc(); apcalc(); lgamu = false; lqinu = false; lgsame = true; } void XFoil::tcset(double cnew, double tnew) { // dimension rinput(*) //------------------------------------------------------ // finds buffer airfoil thickness and/or camber, // plots thickness, camber and airfoil, // and scales t and/or c by user input factors //------------------------------------------------------ double cfac, tfac; //--- find the current buffer airfoil camber and thickness double xcm[IQX], ycm[IQX], xtk[IQX], ytk[IQX], ycmp[IQX], ytkp[IQX]; double txmax, tymax, cxmax, cymax; int ncm, ntk; getcam(xcm,ycm,ncm,xtk,ytk,ntk, xb,xbp,yb,ybp,sb,nb ); getmax(xcm,ycm,ycmp,ncm,cxmax,cymax); getmax(xtk,ytk,ytkp,ntk,txmax,tymax); // write(*,1000) 2.0*tymax,txmax, cymax,cxmax // 1000 format(/' max thickness = ',f8.4,' at x = ',f7.3, // & /' max camber = ',f8.4,' at x = ',f7.3/) /* if (ninput .ge. 2) then tnew = rinput(1) cnew = rinput(2) elseif(ninput .ge. 1) then tnew = rinput(1) if(lgsym) then write(*,*) 'symmetry enforced: maintaining zero camber.' else cnew = 999 call askr('enter new max camber to skip^',cnew) endif else tnew = 999 call askr('enter new max thickness to skip^',tnew) if(lgsym) then write(*,*) 'symmetry enforced: maintaining zero camber.' else cnew = 999 call askr('enter new max camber to skip^',cnew) endif endif*/ // cfac = 1.0; // tfac = 1.0; // if(cymax!=0.0 && cnew!=999.0) cfac = cnew / ( cymax) // if(tymax!=0.0 && tnew!=999.0) tfac = tnew / (2.0*tymax) cfac = cnew / ( cymax); tfac = tnew / (2.0*tymax); //---- sanity checks on scaling factors if(qAbs(tfac) > 100.0 || qAbs(cfac) > 100.0) { // write(*,1100) tfac, cfac // 1100 format(/' questionable input...' // & /' implied scaling factors are:', f13.2,' x thickness' // & /' ', f13.2,' x camber ') // call askl('apply scaling factors?^',ok) // if(.not.ok) then // write(*,*) 'no action taken' // return // endif } //ccc if (tfac.lt.0.0) tfac = 0.0 thkcam(tfac,cfac); getcam(xcm,ycm,ncm,xtk,ytk,ntk,xb,xbp,yb,ybp,sb,nb); } void XFoil::thkcam(double tfac, double cfac){ //--------------------------------------------------- // changes buffer airfoil thickness and camber //--------------------------------------------------- int i; double dxc, dyc,sbopp, xbopp, ybopp, xcavg, ycavg, xcdel, ycdel; lefind(sble,xb,xbp,yb,ybp,sb,nb); //---this fails miserably with sharp le foils, tsk,tsk,tsk hhy 4/24/01 //---- set baseline vector normal to surface at le point // dxc = -deval(sble,yb,ybp,sb,nb) // dyc = deval(sble,xb,xbp,sb,nb) // dsc = sqrt(dxc**2 + dyc**2) // dxc = dxc/dsc // dyc = dyc/dsc //---rational alternative 4/24/01 hhy xle = seval(sble,xb,xbp,sb,nb); yle = seval(sble,yb,ybp,sb,nb); xte = 0.5*(xb[1]+xb[nb]); yte = 0.5*(yb[1]+yb[nb]); chord = sqrt((xte-xle)*(xte-xle) + (yte-yle)*(yte-yle)); //---- set unit chord-line vector dxc = (xte-xle) / chord; dyc = (yte-yle) / chord; //---- go over each point, changing the y-thickness appropriately for(i=1; i<= nb; i++){ //------ coordinates of point on the opposite side with the same x value sopps(sbopp, sb[i],xb,xbp,yb,ybp,sb,nb,sble); xbopp = seval(sbopp,xb,xbp,sb,nb); ybopp = seval(sbopp,yb,ybp,sb,nb); //------ set new y coordinate by changing camber & thickness appropriately xcavg = ( 0.5*(xb[i]+xbopp)*dxc + 0.5*(yb[i]+ybopp)*dyc ); ycavg = cfac * ( 0.5*(yb[i]+ybopp)*dxc - 0.5*(xb[i]+xbopp)*dyc ); xcdel = ( 0.5*(xb[i]-xbopp)*dxc + 0.5*(yb[i]-ybopp)*dyc ); ycdel = tfac * ( 0.5*(yb[i]-ybopp)*dxc - 0.5*(xb[i]-xbopp)*dyc ); w1[i] = (xcavg+xcdel)*dxc - (ycavg+ycdel)*dyc; w2[i] = (ycavg+ycdel)*dxc + (xcavg+xcdel)*dyc; } for (i=1; i<= nb; i++){ xb[i] = w1[i]; yb[i] = w2[i]; } scalc(xb,yb,sb,nb); segspl(xb,xbp,sb,nb); segspl(yb,ybp,sb,nb); geopar(xb,xbp,yb,ybp,sb,nb, w1,sble,chordb,areab,radble,angbte, ei11ba,ei22ba,apx1ba,apx2ba,ei11bt,ei22bt,apx1bt,apx2bt); } void XFoil::inter(double x0[], double xp0[], double y0[], double yp0[], double s0[],int n0,double sle0, double x1[], double xp1[], double y1[], double yp1[], double s1[],int n1,double sle1, double x[], double y[], int n, double frac){ // ..................................................................... // // interpolates two source airfoil shapes into an "intermediate" shape. // // procedure: // The interpolated x coordinate at a given normalized spline // parameter value is a weighted average of the two source // x coordinates at the same normalized spline parameter value. // ditto for the y coordinates. The normalized spline parameter // runs from 0 at the leading edge to 1 at the trailing edge on // each surface. // ..................................................................... /* real x0(n0),y0(n0),xp0(n0),yp0(n0),s0(n0) real x1(n1),y1(n1),xp1(n1),yp1(n1),s1(n1) real x(n),y(n)*/ double f0, f1, tops0, tops1, bots0, bots1; double sn, st0, st1; //---- number of points in interpolated airfoil is the same as in airfoil 0 n = n0; //---- interpolation weighting fractions f0 = 1.0 - frac; f1 = frac; //---- top side spline parameter increments tops0 = s0[1] - sle0; tops1 = s1[1] - sle1; //---- bottom side spline parameter increments bots0 = s0[n0] - sle0; bots1 = s1[n1] - sle1; for (int i=1; i<= n; i++){ //------ normalized spline parameter is taken from airfoil 0 value if(s0[i]< sle0) sn = (s0[i] - sle0) / tops0 ;// top side else sn = (s0[i] - sle0) / bots0 ;// bottom side //------ set actual spline parameters st0 = s0[i]; if(st0< sle0) st1 = sle1 + tops1 * sn; // if(st0>=sle0) st1 = sle1 + bots1 * sn; else st1 = sle1 + bots1 * sn; //------ set interpolated x,y coordinates x[i] = f0*seval(st0,x0,xp0,s0,n0) + f1*seval(st1,x1,xp1,s1,n1); y[i] = f0*seval(st0,y0,yp0,s0,n0) + f1*seval(st1,y1,yp1,s1,n1); } } void XFoil::Interpolate(double xf1[], double yf1[], int n1, double xf2[], double yf2[], int n2, double mixt) { int i; double x1[IBX], y1[IBX], x2[IBX], y2[IBX]; double xp1[IBX], yp1[IBX], xp2[IBX], yp2[IBX]; double s1[IBX], s2[IBX]; double sleint1, sleint2; for (i=0; i0.0) { dxu = dxn / gap; dyu = dyn / gap; } else{ dxu = -.5*(ybp[nb] - ybp[1]); dyu = 0.5*(xbp[nb] - xbp[1]); } doc = qMin( qMax( blend , 0.0 ) , 1.0 ); dgap = gapnew - gap; //---- go over each point, changing the y-thickness appropriately for (int i=1; i<=nb; i++){ //------ chord-based x/c xoc = ( (xb[i]-xble)*(xbte-xble) + (yb[i]-yble)*(ybte-yble) ) / chbsq; //------ thickness factor tails off exponentially away from trailing edge if(doc == 0.0) { tfac = 0.0; if(i==1 || i==nb) tfac = 1.0; } else{ arg = qMin((1.0-xoc)*(1.0/doc-1.0), 15.0 ); tfac = exp(-arg); } if(sb[i]<=sble) { xb[i] = xb[i] + 0.5*dgap*xoc*tfac*dxu; yb[i] = yb[i] + 0.5*dgap*xoc*tfac*dyu; } else{ xb[i] = xb[i] - 0.5*dgap*xoc*tfac*dxu; yb[i] = yb[i] - 0.5*dgap*xoc*tfac*dyu; } } scalc(xb,yb,sb,nb); segspl(xb,xbp,sb,nb); segspl(yb,ybp,sb,nb); geopar(xb,xbp,yb,ybp,sb,nb,w1,sble,chordb,areab,radble,angbte, ei11ba,ei22ba,apx1ba,apx2ba,ei11bt,ei22bt,apx1bt,apx2bt); // lgeopl = false; lgsame = false; } void XFoil::lerad(double rfac, double blend) { //---------------------------- // changes buffer airfoil // leading edge radius. //---------------------------- // int i; double doc, cvmax, cv, radius; doc = qMax( blend , 0.001 ); lerscl(xb,xbp,yb,ybp,sb,nb, doc,rfac, w1,w2); for (i=1; i<= nb; i++){ xb[i] = w1[i]; yb[i] = w2[i]; } //---- spline new coordinates scalc(xb,yb,sb,nb); segspl(xb,xbp,sb,nb); segspl(yb,ybp,sb,nb); geopar(xb,xbp,yb,ybp,sb,nb,w1,sble,chordb,areab,radble,angbte, ei11ba,ei22ba,apx1ba,apx2ba,ei11bt,ei22bt,apx1bt,apx2bt); //---- find max curvature cvmax = 0.0; for(i=(int)(nb/4); i<=(3*nb)/4; i++){ cv = curv(sb[i],xb,xbp,yb,ybp,sb,nb); cvmax = qMax(qAbs(cv) , cvmax ); } radius = 1.0/cvmax; /* write(*,1000) radius 1000 format(/' new le radius = ',f7.5)*/ // lgeopl = .0alse. lgsame = false; } void XFoil::lerscl(double *x, double *xp, double* y, double *yp, double *s, int n, double doc, double rfac, double *xnew,double *ynew) { //--------------------------------------------------------- // adjusts airfoil to scale le radius by factor rfac. // blending of new shape is done with decay length doc. //--------------------------------------------------------- double dxc, dyc, srfac, xbar, ybar, sopp, xopp, yopp, ybarop, xoc, tfac, arg, ybarct; lefind(sle,x,xp,y,yp,s,n); xle = seval(sle,x,xp,s,n); yle = seval(sle,y,yp,s,n); xte = 0.5*(x[1]+x[n]); yte = 0.5*(y[1]+y[n]); chord = sqrt((xte-xle)*(xte-xle) + (yte-yle)*(yte-yle)); //---- set unit chord-line vector dxc = (xte-xle) / chord; dyc = (yte-yle) / chord; srfac = sqrt(qAbs(rfac)); //---- go over each point, changing the y-thickness appropriately for (int i=1; i<=n; i++){ xbar = (x[i]-xle)*dxc + (y[i]-yle)*dyc; ybar = (y[i]-yle)*dxc - (x[i]-xle)*dyc; //------ set point on the opposite side with the same chord x value sopps(sopp, s[i], x,xp,y,yp,s,n, sle); xopp = seval(sopp,x,xp,s,n); yopp = seval(sopp,y,yp,s,n); ybarop = (yopp-yle)*dxc - (xopp-xle)*dyc; //------ thickness factor tails off exponentially towards trailing edge xoc = xbar/chord; arg = min( xoc/doc , 15.0); tfac = 1.0 - (1.0-srfac)*exp(-arg); //------ set new chord x,y coordinates by changing thickness locally ybarct = 0.5*(ybar+ybarop) + tfac*0.5*(ybar-ybarop); xnew[i] = xle + xbar *dxc - ybarct*dyc; ynew[i] = yle + ybarct*dxc + xbar *dyc; } } void XFoil::SetFoilFlap(Foil *pFoil) { Initialize(); m_bTrace = false; for(int i =0; inb; i++){ xb[i+1] = pFoil->xb[i]; yb[i+1] = pFoil->yb[i]; } nb = pFoil->nb; lbflap = false; ddef = 0.0; xbf = 1.0; ybf = 0.0; if(Preprocess()){ if(pFoil->m_bTEFlap){ lbflap = true; //hinge position is entered as a %, so convert xbf = pFoil->m_TEXHinge/100.0; ybf = pFoil->m_TEYHinge/100.0; ddef = pFoil->m_TEFlapAngle; flap(); abcopy(); } for (int k=0; kx[k] = xb[k+1]; pFoil->y[k] = yb[k+1]; pFoil->nx[k] = nx[k+1]; pFoil->ny[k] = ny[k+1]; } pFoil->n = nb; pFoil->InitFoil(); } else{ //what do I do now ? } } void XFoil::naca4(int ides, int nside) { int n1, n2, n3, n4, ib, i; // double xx[nside], yt[nside], yc[nside], xb[2*nside], yb[2*nside] double *xx = w1; double *yt = w2;//thickness function double *yc = w3;//mean camber line function memset(w1,0,sizeof(w1)); memset(w2,0,sizeof(w2)); memset(w3,0,sizeof(w3)); double m, p, t, frac; if(nside>(int)(IQX/3)) nside = (int)(IQX/3); //---- te point bunching parameter // data an / 1.5 / double an = 1.5; double anp; n4 = ides / 1000; n3 = (ides - n4*1000 ) / 100; n2 = (ides - n4*1000 - n3*100 ) / 10; n1 = (ides - n4*1000 - n3*100 - n2*10); m = (double)(n4) / 100.0; //maximum value of the mean line in hundredths of chord, p = (double)(n3) / 10.0; //chordwise position of the maximum camber in tenths of the chord. t = (double)(n2*10 + n1) / 100.0; //maximum thickness, t/c, in percent chord. anp = an + 1.0; for (i=1; i<= nside; i++){ frac = (double)(i-1)/(double)(nside-1); xx[i] = 1.0 - anp*frac*pow((1.0-frac),an) - pow((1.0-frac),anp); yt[i] = ( 1.4845*sqrt(xx[i]) - 0.6300*xx[i] - 1.7580*xx[i]*xx[i] + 1.4215*xx[i]*xx[i]*xx[i] - 0.5075*xx[i]*xx[i]*xx[i]*xx[i] ) * t ; if(xx[i]= 1; i--){ ib = ib + 1; xb[ib] = xx[i]; yb[ib] = yc[i] + yt[i]; } for(i=2; i<= nside; i++){ ib = ib + 1; xb[ib] = xx[i]; yb[ib] = yc[i] - yt[i]; } nb = ib; scalc(xb,yb,sb,nb); segspl(xb,xbp,sb,nb); segspl(yb,ybp,sb,nb); geopar(xb,xbp,yb,ybp,sb,nb,w1,sble,chordb,areab, radble,angbte,ei11ba,ei22ba,apx1ba,apx2ba, ei11bt,ei22bt,apx1bt,apx2bt); } bool XFoil::naca5(int ides, int nside) { // real xx(nside), yt(nside), yc(nside) // real xb(2*nside), yb(2*nside) double m, c, t, anp, frac; int n1, n2, n3, n4, n5, n543, i, ib; if(nside>(int)(IQX/3)) nside = (int)(IQX/3); double *xx = w1; double *yt = w2; double *yc = w3; //---- te point bunching parameter double an = 1.5; n5 = ides / 10000; n4 = (ides - n5*10000 ) / 1000; n3 = (ides - n5*10000 - n4*1000 ) / 100; n2 = (ides - n5*10000 - n4*1000 - n3*100 ) / 10; n1 = (ides - n5*10000 - n4*1000 - n3*100 - n2*10); n543 = 100*n5 + 10*n4 + n3; if (n543 == 210){ // p = 0.05 m = 0.0580; c = 361.4; } else if (n543 == 220) { // p = 0.10 m = 0.1260; c = 51.64; } else if (n543 == 230) { // p = 0.15 m = 0.2025; c = 15.957; } else if (n543 == 240) { // p = 0.20 m = 0.2900; c = 6.643; } else if (n543 == 250) { // p = 0.25 m = 0.3910; c = 3.230; } else{ QString str("Illegal 5-digit designation\n"); str += "first three digits must be 210, 220, ... 250"; ides = 0; QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QXDirect::tr("Warning")); msgBox.setText(str); msgBox.exec(); return false; } t = (double)(n2*10 + n1) / 100.0; anp = an + 1.0; for(i=1; i<= nside; i++){ frac = (double)(i-1)/(double)(nside-1); xx[i] = 1.0 - anp*frac*pow((1.0-frac),an) - pow((1.0-frac),anp); yt[i] = ( 0.29690*sqrt(xx[i]) - 0.12600*xx[i] - 0.35160*xx[i]*xx[i] + 0.28430*xx[i]*xx[i]*xx[i] - 0.10150*xx[i]*xx[i]*xx[i]*xx[i]) * t / 0.20; if(xx[i]=1;i--){ ib = ib + 1; xb[ib] = xx[i]; yb[ib] = yc[i] + yt[i]; } for(i=2; i<= nside;i++){ ib = ib + 1; xb[ib] = xx[i]; yb[ib] = yc[i] - yt[i]; } nb = ib; return true; } void XFoil::FillHk(double ws[IVX][3], int nside1, int nside2) { int nside[3]; nside[1] = nside1; nside[2] = nside2; double thi, dsi, uei, uc, amsq, dummy; double hstinv = gamm1*(minf/qinf)*(minf/qinf) / (1.0 + 0.5*gamm1*minf*minf); //---- fill kinematic shape parameter array for (int is=1; is<=2; is++){ for(int ibl=2; ibl< nside[is]; ibl++){ thi = thet[ibl][is]; dsi = dstr[ibl][is]; uei = uedg[ibl][is]; uc = uei * (1.0-tklam) / (1.0 - tklam*(uei/qinf)*(uei/qinf)); amsq = uc*uc*hstinv / (gamm1*(1.0 - 0.5*uc*uc*hstinv)); hkin(dsi/thi, amsq, ws[ibl][is], dummy, dummy); } } } void XFoil::FillRTheta(double ws[IVX][3], int nside1, int nside2) { int nside[3]; nside[1] = nside1; nside[2] = nside2; double ue, herat, rhoe, amue, uei; //---- 1 / (total enthalpy) double hstinv = gamm1*(minf/qinf)*(minf/qinf) / (1.0 + 0.5*gamm1*minf*minf); //---- Sutherland's const./to (assumes stagnation conditions are at stp) double hvrat = 0.35; //---- fill rtheta arrays for (int is=1; is<=2; is++){ for(int ibl=2; ibl< nside[is]; ibl++){ uei = uedg[ibl][is]; ue = uei * (1.0-tklam) / (1.0 - tklam*(uei/qinf)*(uei/qinf)); herat = (1.0 - 0.5*hstinv*ue *ue) / (1.0 - 0.5*hstinv*qinf*qinf); rhoe = pow(herat, 1.0/gamm1); amue = sqrt(herat*herat*herat) * (1.0+hvrat)/(herat+hvrat); ws[ibl][is] = reinf * rhoe*ue*thet[ibl][is]/amue; } } } void XFoil::CreateXBL(double xs[IVX][3],int &nside1, int &nside2) { double xxtr[3]; int i; //---- set up cartesian bl x-arrays for plotting for(int is=1; is<= 2; is++){ for (int ibl=2; ibl<= nbl[is]; ibl++){ i = ipan[ibl][is]; xs[ibl][is] = x[i]; xxtr[is] = xle + (xte-xle)*xoctr[is] - (yte-yle)*yoctr[is]; } } nside1 = nbl[2] + iblte[1] - iblte[2]; nside2 = nbl[2]; for( int iblw=1; iblw <= nbl[2]-iblte[2]; iblw++) xs[iblte[1]+iblw][1] = xs[iblte[2]+iblw][2]; } xflr5-6.09-06/src/xdirect/XDirectStyleDlg.cpp000644 001750 000144 00000013120 12247174405 022240 0ustar00techwinderusers000000 000000 /**************************************************************************** QXDirectStyleDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "XDirectStyleDlg.h" #include "XDirect.h" #include "../misc/LinePickerDlg.h" #include #include XDirectStyleDlg::XDirectStyleDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("XDirect Styles")); m_pXDirect = NULL; SetupLayout(); OnRestoreDefaults(); } void XDirectStyleDlg::SetupLayout() { QGridLayout *StyleLayout = new QGridLayout; { m_pctrlNeutral = new LineBtn(this); m_pctrlBL = new LineBtn(this); m_pctrlPressure = new LineBtn(this); QLabel *lab1 = new QLabel(tr("Neutral Line")); QLabel *lab2 = new QLabel(tr("Boundary Layer")); QLabel *lab3 = new QLabel(tr("Pressure")); StyleLayout->addWidget(lab1,1,1); StyleLayout->addWidget(lab2,2,1); StyleLayout->addWidget(lab3,3,1); StyleLayout->addWidget(m_pctrlNeutral,1,2); StyleLayout->addWidget(m_pctrlBL,2,2); StyleLayout->addWidget(m_pctrlPressure,3,2); connect(m_pctrlNeutral, SIGNAL(clickedLB()),this, SLOT(OnNeutralStyle())); connect(m_pctrlBL, SIGNAL(clickedLB()),this, SLOT(OnBLStyle())); connect(m_pctrlPressure, SIGNAL(clickedLB()),this, SLOT(OnPressureStyle())); } QHBoxLayout *CommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); QPushButton *DefaultsButton = new QPushButton(tr("Defaults")); QPushButton *CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(DefaultsButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); connect(DefaultsButton, SIGNAL(clicked()),this, SLOT(OnRestoreDefaults())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } QVBoxLayout *MainLayout = new QVBoxLayout; { MainLayout->addLayout(StyleLayout); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); } setLayout(MainLayout); } void XDirectStyleDlg::OnNeutralStyle() { LinePickerDlg dlg(this); dlg.InitDialog(m_iNeutralStyle, m_iNeutralWidth, m_crNeutralColor); if(QDialog::Accepted==dlg.exec()) { m_iNeutralStyle = dlg.GetStyle(); m_iNeutralWidth = dlg.GetWidth(); m_crNeutralColor = dlg.GetColor(); m_pctrlNeutral->SetStyle(m_iNeutralStyle, m_iNeutralWidth, m_crNeutralColor); } OKButton->setFocus(); } void XDirectStyleDlg::OnPressureStyle() { LinePickerDlg dlg(this); dlg.InitDialog(m_iPressureStyle, m_iPressureWidth, m_crPressureColor); if(QDialog::Accepted==dlg.exec()) { m_iPressureStyle = dlg.GetStyle(); m_iPressureWidth = dlg.GetWidth(); m_crPressureColor = dlg.GetColor(); m_pctrlPressure->SetStyle(m_iPressureStyle, m_iPressureWidth, m_crPressureColor); } OKButton->setFocus(); } void XDirectStyleDlg::OnBLStyle() { LinePickerDlg dlg(this); dlg.InitDialog(m_iBLStyle, m_iBLWidth, m_crBLColor); if(QDialog::Accepted==dlg.exec()) { m_iBLStyle = dlg.GetStyle(); m_iBLWidth = dlg.GetWidth(); m_crBLColor = dlg.GetColor(); m_pctrlBL->SetStyle(m_iBLStyle, m_iBLWidth, m_crBLColor); } OKButton->setFocus(); } void XDirectStyleDlg::InitDialog() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; m_iNeutralStyle = pXDirect->m_iNeutralStyle; m_iNeutralWidth = pXDirect->m_iNeutralWidth; m_crNeutralColor = pXDirect->m_crNeutralColor; m_iBLStyle = pXDirect->m_iBLStyle; m_iBLWidth = pXDirect->m_iBLWidth; m_crBLColor = pXDirect->m_crBLColor; m_iPressureStyle = pXDirect->m_iPressureStyle; m_iPressureWidth = pXDirect->m_iPressureWidth; m_crPressureColor = pXDirect->m_crPressureColor; m_pctrlNeutral->SetStyle(m_iNeutralStyle, m_iNeutralWidth, m_crNeutralColor); m_pctrlBL->SetStyle(m_iBLStyle, m_iBLWidth, m_crBLColor); m_pctrlPressure->SetStyle(m_iPressureStyle, m_iPressureWidth, m_crPressureColor); } void XDirectStyleDlg::OnRestoreDefaults() { m_iNeutralStyle = 2; m_iNeutralWidth = 1; m_crNeutralColor = QColor(200,200,255); m_pctrlNeutral->SetStyle(m_iNeutralStyle, m_iNeutralWidth, m_crNeutralColor); m_crBLColor = QColor(200,70,70); m_iBLStyle = 1; m_iBLWidth = 1; m_pctrlBL->SetStyle(m_iBLStyle, m_iBLWidth, m_crBLColor); m_crPressureColor= QColor(0,255,0); m_iPressureStyle = 0; m_iPressureWidth = 1; m_pctrlPressure->SetStyle(m_iPressureStyle, m_iPressureWidth, m_crPressureColor); } void XDirectStyleDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus()) { OKButton->setFocus(); return; } else { accept(); return; } event->ignore(); break; } case Qt::Key_Escape: { reject(); break; } } } xflr5-6.09-06/src/xdirect/FoilCoordDlg.h000644 001750 000144 00000004215 12247174405 021207 0ustar00techwinderusers000000 000000 /**************************************************************************** FoilCoordDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef FOILCOORDDLG_H #define FOILCOORDDLG_H #include #include #include #include #include "../misc/FloatEditDelegate.h" #include "../objects/Foil.h" class FoilCoordDlg : public QDialog { Q_OBJECT friend class QXDirect; friend class QAFoil; public: FoilCoordDlg(QWidget *pParent=NULL); void InitDialog(); private slots: void OnDeletePoint(); void OnInsertPoint(); void OnRestore(); void OnApply(); void OnCellChanged(QWidget *DoubleEdit); void OnItemClicked(QModelIndex index); private: void FillList(); void SetSelection(int sel); void SetupLayout(); void ReadSectionData(int sel, double &X, double &Y); void keyPressEvent(QKeyEvent *event); void showEvent(QShowEvent *event); void resizeEvent(QResizeEvent *event); private: QPushButton *m_pctrlInsertPoint, *m_pctrlDeletePoint, *m_pctrlRestore, *m_pctrlApply; QPushButton *OKButton, *CancelButton; QTableView *m_pctrlCoordView; QStandardItemModel *m_pCoordModel; FloatEditDelegate *m_pFloatDelegate; Foil * m_pMemFoil; Foil * m_pBufferFoil; bool m_bApplied, m_bModified; void *m_pXDirect; void *m_pAFoil; }; #endif // FOILCOORDDLG_H xflr5-6.09-06/src/xdirect/NacaFoilDlg.h000644 001750 000144 00000003261 12247174410 020777 0ustar00techwinderusers000000 000000 /**************************************************************************** Naca Foil Dlg Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef NACAFOILDLG_H #define NACAFOILDLG_H #include #include #include "../objects/Foil.h" #include "../misc/IntEdit.h" class NacaFoilDlg : public QDialog { Q_OBJECT friend class QXDirect; friend class QAFoil; friend class XFoil; private slots: void EditingFinished(); void OnOK(); public: NacaFoilDlg(QWidget *pParent=NULL); void SetupLayout(); void GenerateFoil(); void keyPressEvent(QKeyEvent *event); static void *s_pXFoil; void *m_pXDirect; void *m_pAFoil; Foil *m_pBufferFoil; QPushButton *OKButton, *CancelButton; IntEdit *m_pctrlNumber; IntEdit *m_pctrlPanels; QLabel * m_pctrlMessage; bool m_bGenerated; static int s_Digits; static int s_Panels; }; #endif // NACAFOIL_H xflr5-6.09-06/src/xdirect/XFoilAdvancedDlg.cpp000644 001750 000144 00000007022 12247174410 022324 0ustar00techwinderusers000000 000000 /**************************************************************************** XFoilAdvancedDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include "XFoilAdvancedDlg.h" XFoilAdvancedDlg::XFoilAdvancedDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("XFoil Settings")); SetupLayout(); m_IterLimit = 100; m_VAccel = 0.001; m_bInitBL = true; m_bFullReport = false; connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void XFoilAdvancedDlg::SetupLayout() { QHBoxLayout *VAccelBoxLayout = new QHBoxLayout; { QLabel *lab1 = new QLabel(tr("VAccel")); lab1->setAlignment(Qt::AlignRight); m_pctrlVAccel = new DoubleEdit; m_pctrlVAccel->setAlignment(Qt::AlignRight); VAccelBoxLayout->addStretch(1); VAccelBoxLayout->addWidget(lab1); VAccelBoxLayout->addWidget(m_pctrlVAccel); } QHBoxLayout *IterBoxLayout = new QHBoxLayout; { QLabel *lab2 = new QLabel(tr("Iteration Limit")); lab2->setAlignment(Qt::AlignRight); m_pctrlIterLimit = new IntEdit; IterBoxLayout->addStretch(1); IterBoxLayout->addWidget(lab2); IterBoxLayout->addWidget(m_pctrlIterLimit); } m_pctrlInitBL = new QCheckBox(tr("Re-initialize BLs after an unconverged iteration")); m_pctrlFullReport = new QCheckBox(tr("Show full log report for an XFoil analysis")); QHBoxLayout *CommandButtonsLayout = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(OKButton); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(CancelButton); CommandButtonsLayout->addStretch(1); } QVBoxLayout *MainLayout = new QVBoxLayout; { MainLayout->addLayout(VAccelBoxLayout); MainLayout->addLayout(IterBoxLayout); MainLayout->addWidget(m_pctrlInitBL); MainLayout->addWidget(m_pctrlFullReport); MainLayout->addLayout(CommandButtonsLayout); } setLayout(MainLayout); } void XFoilAdvancedDlg::InitDialog() { m_pctrlVAccel->SetValue(m_VAccel); m_pctrlInitBL->setChecked(m_bInitBL); m_pctrlIterLimit->SetValue(m_IterLimit); m_pctrlFullReport->setChecked(m_bFullReport); } void XFoilAdvancedDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OKButton->setFocus(); } else if (OKButton->hasFocus()) { OnOK(); } break; } case Qt::Key_Escape: { reject(); return; } default: event->ignore(); } } void XFoilAdvancedDlg::OnOK() { m_IterLimit = m_pctrlIterLimit->Value(); m_VAccel = m_pctrlVAccel->Value(); m_bInitBL = m_pctrlInitBL->isChecked(); m_bFullReport = m_pctrlFullReport->isChecked(); done(1); } xflr5-6.09-06/src/xdirect/FoilGeomDlg.cpp000644 001750 000144 00000032775 12247174405 021377 0ustar00techwinderusers000000 000000 /**************************************************************************** FoilGeomDlg Class Copyright (C) 2008-2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../design/AFoil.h" #include "XDirect.h" #include "XFoil.h" #include "FoilGeomDlg.h" #include #include #include #include void *FoilGeomDlg::s_pXFoil; FoilGeomDlg::FoilGeomDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Foil Geometry")); m_pXDirect = NULL; m_pAFoil = NULL; SetupLayout(); connect(RestoreButton, SIGNAL(clicked()),this, SLOT(OnRestore())); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(m_pctrlCamber, SIGNAL(editingFinished()), this, SLOT(OnCamber())); connect(m_pctrlXCamber, SIGNAL(editingFinished()), this, SLOT(OnXCamber())); connect(m_pctrlThickness, SIGNAL(editingFinished()), this, SLOT(OnThickness())); connect(m_pctrlXThickness, SIGNAL(editingFinished()), this, SLOT(OnXThickness())); connect(m_pctrlCamberSlide, SIGNAL(sliderMoved(int)), this, SLOT(OnCamberSlide(int))); connect(m_pctrlXCamberSlide, SIGNAL(sliderMoved(int)), this, SLOT(OnXCamberSlide(int))); connect(m_pctrlThickSlide, SIGNAL(sliderMoved(int)), this, SLOT(OnThickSlide(int))); connect(m_pctrlXThickSlide, SIGNAL(sliderMoved(int)), this, SLOT(OnXThickSlide(int))); } void FoilGeomDlg::SetupLayout() { QVBoxLayout *CamberData = new QVBoxLayout; { m_pctrlCamberSlide = new QSlider; m_pctrlCamberSlide->setOrientation(Qt::Horizontal); m_pctrlCamberSlide->setTickPosition(QSlider::TicksBelow); m_pctrlCamberSlide->setMinimumWidth(200); m_pctrlCamber =new DoubleEdit; m_pctrlXCamberSlide = new QSlider; m_pctrlXCamberSlide->setOrientation(Qt::Horizontal); m_pctrlXCamberSlide->setTickPosition(QSlider::TicksBelow); m_pctrlXCamberSlide->setMinimumWidth(200); m_pctrlXCamber = new DoubleEdit; QLabel *lab1 = new QLabel(tr("Value")); QLabel *lab2 = new QLabel(tr("%Chord")); QLabel *lab3 = new QLabel(tr("0%")); QLabel *lab4 = new QLabel(tr("10%")); QLabel *lab5 = new QLabel(tr("Max x-pos")); QLabel *lab6 = new QLabel(tr("%Chord")); QLabel *lab7 = new QLabel(tr("0%")); QLabel *lab8 = new QLabel(tr("100%")); lab1->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab5->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab3->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab7->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab1->setMinimumWidth(70); lab2->setMinimumWidth(70); lab3->setMinimumWidth(50); lab4->setMinimumWidth(50); lab5->setMinimumWidth(70); lab6->setMinimumWidth(70); lab7->setMinimumWidth(50); lab8->setMinimumWidth(50); QHBoxLayout *CambVal = new QHBoxLayout; { CambVal->addWidget(lab1); CambVal->addWidget(m_pctrlCamber); CambVal->addWidget(lab2); CambVal->addStretch(1); CambVal->addWidget(lab3); CambVal->addWidget(m_pctrlCamberSlide); CambVal->addWidget(lab4); } QHBoxLayout *XCambVal = new QHBoxLayout; { XCambVal->addWidget(lab5); XCambVal->addWidget(m_pctrlXCamber); XCambVal->addWidget(lab6); XCambVal->addStretch(1); XCambVal->addWidget(lab7); XCambVal->addWidget(m_pctrlXCamberSlide); XCambVal->addWidget(lab8); } CamberData->addLayout(CambVal); CamberData->addLayout(XCambVal); } QGroupBox *CamberGroup = new QGroupBox(tr("Camber")); CamberGroup->setLayout(CamberData); QVBoxLayout *ThicknessData = new QVBoxLayout; { m_pctrlThickSlide = new QSlider; m_pctrlThickSlide->setOrientation(Qt::Horizontal); m_pctrlThickSlide->setTickPosition(QSlider::TicksBelow); m_pctrlThickSlide->setMinimumWidth(200); m_pctrlThickness =new DoubleEdit; m_pctrlXThickSlide = new QSlider; m_pctrlXThickSlide->setOrientation(Qt::Horizontal); m_pctrlXThickSlide->setTickPosition(QSlider::TicksBelow); m_pctrlXThickSlide->setMinimumWidth(200); m_pctrlXThickness = new DoubleEdit; QLabel *lab11 = new QLabel(tr("Value")); QLabel *lab12 = new QLabel(tr("%Chord")); QLabel *lab13 = new QLabel("0%"); QLabel *lab14 = new QLabel("20%"); QLabel *lab15 = new QLabel(tr("Max x-pos")); QLabel *lab16 = new QLabel(tr("%Chord")); QLabel *lab17 = new QLabel("0%"); QLabel *lab18 = new QLabel("100%"); lab11->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab15->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab13->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab17->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab11->setMinimumWidth(70); lab12->setMinimumWidth(70); lab13->setMinimumWidth(50); lab14->setMinimumWidth(50); lab15->setMinimumWidth(70); lab16->setMinimumWidth(70); lab17->setMinimumWidth(50); lab18->setMinimumWidth(50); QHBoxLayout *ThickVal = new QHBoxLayout; { ThickVal->addWidget(lab11); ThickVal->addWidget(m_pctrlThickness); ThickVal->addWidget(lab12); ThickVal->addStretch(1); ThickVal->addWidget(lab13); ThickVal->addWidget(m_pctrlThickSlide); ThickVal->addWidget(lab14); } QHBoxLayout *XThickVal = new QHBoxLayout; { XThickVal->addWidget(lab15); XThickVal->addWidget(m_pctrlXThickness); XThickVal->addWidget(lab16); XThickVal->addStretch(1); XThickVal->addWidget(lab17); XThickVal->addWidget(m_pctrlXThickSlide); XThickVal->addWidget(lab18); } ThicknessData->addLayout(ThickVal); ThicknessData->addLayout(XThickVal); } QGroupBox *ThicknessGroup = new QGroupBox(tr("Thickness")); ThicknessGroup->setLayout(ThicknessData); QHBoxLayout *CommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); RestoreButton = new QPushButton(tr("Restore")); CommandButtons->addStretch(1); CommandButtons->addWidget(RestoreButton); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); } QVBoxLayout *MainLayout = new QVBoxLayout; { MainLayout->addWidget(CamberGroup); MainLayout->addStretch(1); MainLayout->addWidget(ThicknessGroup); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); setLayout(MainLayout); } setMinimumWidth(500); setMinimumHeight(300); m_pctrlCamber->SetPrecision(2); m_pctrlXCamber->SetPrecision(2); m_pctrlThickness->SetPrecision(2); m_pctrlXThickness->SetPrecision(2); m_pctrlCamberSlide->setRange(0,100); m_pctrlCamberSlide->setTickInterval(5); m_pctrlXCamberSlide->setRange(0,1000); m_pctrlXCamberSlide->setTickInterval(100); m_pctrlThickSlide->setRange(0,200); m_pctrlThickSlide->setTickInterval(5); m_pctrlXThickSlide->setRange(0,1000); m_pctrlXThickSlide->setTickInterval(100); } void FoilGeomDlg::Apply() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; QAFoil *pAFoil = (QAFoil*)m_pAFoil; XFoil *pXFoil = (XFoil*)s_pXFoil; //reset everything and retry int i,j; for (i=0; i< m_pMemFoil->nb; i++) { pXFoil->xb[i+1] = m_pMemFoil->xb[i]; pXFoil->yb[i+1] = m_pMemFoil->yb[i]; } pXFoil->nb = m_pMemFoil->nb; pXFoil->lflap = false; pXFoil->lbflap = false; if(pXFoil->Preprocess()) { pXFoil->CheckAngles(); /* for (int k=0; kn;k++){ m_pMemFoil->nx[k] = pXFoil->nx[k+1]; m_pMemFoil->ny[k] = pXFoil->ny[k+1]; } m_pMemFoil->n = pXFoil->n;*/ } else { QMessageBox::information(window(), tr("Warning"), "Unrecognized foil format"); return; } // if(!m_bApplied) { double thickness = m_pctrlThickness->Value()/100.0; double camber = m_pctrlCamber->Value()/100.0; pXFoil->tcset(camber, thickness); m_pctrlCamberSlide->setSliderPosition((int)(camber*100*10)); m_pctrlThickSlide->setSliderPosition((int)(thickness*100*10)); m_bApplied = true; } // if(!m_bAppliedX) { double Xthickness = m_pctrlXThickness->Value()/100.0; double Xcamber = m_pctrlXCamber->Value()/100.0; pXFoil->hipnt(Xcamber, Xthickness); m_pctrlXCamberSlide->setSliderPosition((int)(Xcamber*100*10)); m_pctrlXThickSlide->setSliderPosition((int)(Xthickness*100*10)); m_bAppliedX = true; } if(pXFoil->nb>IQX) { QMessageBox::information(window(), tr("Warning"), tr("Panel number cannot exceed 300")); //reset everything and retry for (i=0; i< m_pMemFoil->nb; i++) { pXFoil->x[i+1] = m_pMemFoil->xb[i]; pXFoil->y[i+1] = m_pMemFoil->yb[i]; } pXFoil->n = m_pMemFoil->nb; } else { for (j=0; j< pXFoil->nb; j++) { m_pBufferFoil->xb[j] = pXFoil->xb[j+1]; m_pBufferFoil->yb[j] = pXFoil->yb[j+1]; } m_pBufferFoil->nb = pXFoil->nb; // pXFoil->SetFoilFlap(m_pBufferFoil); m_pBufferFoil->InitFoil(); m_pBufferFoil->SetFlap(); } m_bModified = true; if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } void FoilGeomDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Escape: { done(0); return; } case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { Apply(); OKButton->setFocus(); m_bApplied = true; m_bAppliedX = true; } else { QDialog::accept(); } break; } default: event->ignore(); break; } } void FoilGeomDlg::InitDialog() { m_fCamber = m_pMemFoil->m_fCamber; m_fThickness = m_pMemFoil->m_fThickness; m_fXCamber = m_pMemFoil->m_fXCamber; m_fXThickness = m_pMemFoil->m_fXThickness; if(qAbs(m_fCamber) <0.0001) { // m_pctrlCamb->SetWindowText("The foil's camber is too small to be scaled"); //TODO m_pctrlCamberSlide->setEnabled(false); m_pctrlCamber->setEnabled(false); } m_pctrlCamber->SetValue(m_fCamber*100.0); m_pctrlThickness->SetValue(m_fThickness*100.0); m_pctrlXCamber->SetValue(m_fXCamber*100.0); m_pctrlXThickness->SetValue(m_fXThickness*100.0); m_pctrlCamberSlide->setSliderPosition((int)(m_fCamber*1000.0)); m_pctrlThickSlide->setSliderPosition((int)(m_fThickness*1000.0)); m_pctrlXCamberSlide->setSliderPosition((int)(m_fXCamber*1000.0)); m_pctrlXThickSlide->setSliderPosition((int)(m_fXThickness*1000.0)); m_bApplied = true; m_bAppliedX = true; } void FoilGeomDlg::OnRestore() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; QAFoil* pAFoil = (QAFoil*)m_pAFoil; XFoil *pXFoil = (XFoil*)s_pXFoil; m_pBufferFoil->CopyFoil(m_pMemFoil); m_fThickness = m_pMemFoil->m_fThickness; m_fCamber = m_pMemFoil->m_fCamber; m_fXThickness = m_pMemFoil->m_fXThickness; m_fXCamber = m_pMemFoil->m_fXCamber; pXFoil->thickb = m_fThickness; pXFoil->cambrb = m_fCamber; m_pctrlThickness->SetValue(m_fThickness*100.0); m_pctrlCamber->SetValue(m_fCamber*100.0); m_pctrlThickSlide->setSliderPosition((int)(m_fThickness*1000.0)); m_pctrlCamberSlide->setSliderPosition((int)(m_fCamber*1000.0)); m_pctrlXThickness->SetValue(m_fXThickness*100.0); m_pctrlXCamber->SetValue(m_fXCamber*100.0); m_pctrlXThickSlide->setSliderPosition((int)(m_fXThickness*1000.0)); m_pctrlXCamberSlide->setSliderPosition ((int)(m_fXCamber*1000.0)); m_bApplied = true; m_bAppliedX = true; m_bModified = false; if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } void FoilGeomDlg::OnCamber() { m_bApplied = false; m_fCamber = m_pctrlCamber->Value(); m_pctrlCamberSlide->setValue(m_fCamber*10.0); Apply(); } void FoilGeomDlg::OnCamberSlide(int pos) { m_fCamber = (double)pos/10.0; m_pctrlCamber->SetValue(m_fCamber); m_bApplied = false; Apply(); } void FoilGeomDlg::OnOK() { if(!m_bApplied || !m_bAppliedX) Apply(); if(!m_bModified) done(0); else done(1); } void FoilGeomDlg::OnThickness() { m_bApplied = false; m_fThickness = m_pctrlThickness->Value(); m_pctrlThickSlide->setValue(m_fThickness*10.0); Apply(); } void FoilGeomDlg::OnThickSlide(int pos) { m_fThickness = (double)pos/10.0; m_pctrlThickness->SetValue(m_fThickness); m_bApplied = false; Apply(); } void FoilGeomDlg::OnXCamberSlide(int pos) { m_fXCamber = (double)pos/10.0; m_pctrlXCamber->SetValue(m_fXCamber); m_bAppliedX = false; Apply(); } void FoilGeomDlg::OnXCamber() { m_bAppliedX = false; m_fXCamber = m_pctrlXCamber->Value(); m_pctrlXCamberSlide->setValue(m_fXCamber*10.0); Apply(); } void FoilGeomDlg::OnXThickSlide(int pos) { m_fXThickness = (double)pos/10.0; m_pctrlXThickness->SetValue(m_fXThickness); m_bAppliedX = false; Apply(); } void FoilGeomDlg::OnXThickness() { m_bAppliedX = false; m_fXThickness = m_pctrlXThickness->Value(); m_pctrlXThickSlide->setValue(m_fXThickness*10.0); Apply(); } xflr5-6.09-06/src/xdirect/InterpolateFoilsDlg.cpp000644 001750 000144 00000021033 12247174410 023136 0ustar00techwinderusers000000 000000 /**************************************************************************** InterpolateFoilsDlg Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include "InterpolateFoilsDlg.h" #include "../mainframe.h" #include "XFoil.h" #include "XDirect.h" #include "../design/AFoil.h" void *InterpolateFoilsDlg::s_pXFoil; #define SLIDERSCALE 10000 InterpolateFoilsDlg::InterpolateFoilsDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Interpolate Foils")); m_pXDirect = NULL; m_pAFoil = NULL; m_pBufferFoil = NULL; m_poaFoil = NULL; SetupLayout(); connect(m_pctrlFoil1, SIGNAL(activated(int)), this, SLOT(OnSelChangeFoil1(int))); connect(m_pctrlFoil2, SIGNAL(activated(int)), this, SLOT(OnSelChangeFoil2(int))); connect(m_pctrlFrac, SIGNAL(editingFinished()), this, SLOT(OnFrac())); connect(m_pctrlSlider, SIGNAL(sliderMoved(int)), this, SLOT(OnVScroll(int))); } void InterpolateFoilsDlg::SetupLayout() { QVBoxLayout *LeftSide = new QVBoxLayout; { m_pctrlFoil1 = new QComboBox; m_pctrlFoil1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_pctrlFoil2 = new QComboBox; m_pctrlCamb1 = new QLabel(tr("Camb1")); m_pctrlCamb2 = new QLabel(tr("Camb2")); m_pctrlThick1 = new QLabel(tr("Thick1")); m_pctrlThick2 = new QLabel(tr("Thick2")); m_pctrlCamb1->setMinimumWidth(250); m_pctrlCamb2->setMinimumWidth(250); m_pctrlThick1->setMinimumWidth(250); m_pctrlThick2->setMinimumWidth(250); LeftSide->addWidget(m_pctrlFoil1); LeftSide->addWidget(m_pctrlCamb1); LeftSide->addWidget(m_pctrlThick1); LeftSide->addStretch(1); LeftSide->addWidget(m_pctrlFoil2); LeftSide->addWidget(m_pctrlCamb2); LeftSide->addWidget(m_pctrlThick2); } m_pctrlSlider = new QSlider; m_pctrlSlider->setMinimumHeight(300); m_pctrlSlider->setMinimum(0); m_pctrlSlider->setMaximum(SLIDERSCALE); m_pctrlSlider->setTickInterval(SLIDERSCALE/10); m_pctrlSlider->setTickPosition(QSlider::TicksLeft); QVBoxLayout *Foil3Layout = new QVBoxLayout; { m_pctrlFrac = new DoubleEdit; m_pctrlCamb3 = new QLabel(tr("Camb3")); m_pctrlCamb3->setMinimumWidth(250); m_pctrlThick3 = new QLabel(tr("Thick3")); m_pctrlThick3->setMinimumWidth(250); m_pctrlFrac->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); m_pctrlCamb3->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); m_pctrlThick3->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); Foil3Layout->addStretch(); Foil3Layout->addWidget(m_pctrlFrac); Foil3Layout->addWidget(m_pctrlCamb3); Foil3Layout->addWidget(m_pctrlThick3); Foil3Layout->addStretch(); } QHBoxLayout *CommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } QHBoxLayout *pColumnLayout = new QHBoxLayout; { pColumnLayout->addLayout(LeftSide); pColumnLayout->addStretch(1); pColumnLayout->addWidget(m_pctrlSlider); pColumnLayout->addLayout(Foil3Layout); } QVBoxLayout *pMainLayout = new QVBoxLayout; { pMainLayout->addLayout(pColumnLayout); pMainLayout->addLayout(CommandButtons); } setLayout(pMainLayout); setMinimumWidth(400); setMinimumHeight(400); } void InterpolateFoilsDlg::InitDialog() { int i; Foil* pFoil; m_pctrlFoil1->clear(); m_pctrlFoil2->clear(); for (i=0; isize(); i++) { pFoil = (Foil*)m_poaFoil->at(i); if(pFoil) { m_pctrlFoil1->addItem(pFoil->m_FoilName); m_pctrlFoil2->addItem(pFoil->m_FoilName); } } m_pctrlFoil1->setCurrentIndex(0); m_pctrlFoil2->setCurrentIndex(1); m_Frac = 0.0; m_pctrlFrac->SetValue(100); m_pctrlSlider->setSliderPosition(SLIDERSCALE); OnSelChangeFoil1(0); OnSelChangeFoil2(1); } void InterpolateFoilsDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App // Generate the foil instead switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { Update(); OKButton->setFocus(); } else if (OKButton->hasFocus()) { OnOK(); } break; } case Qt::Key_Escape: { reject(); return; } default: event->ignore(); } } void InterpolateFoilsDlg::OnSelChangeFoil1(int i) { QString strong = m_pctrlFoil1->currentText(); i=0; Foil* pFoil = MainFrame::foil(strong); if(pFoil) { QString str; str = QString(tr("Camb.=%1")).arg(pFoil->m_fCamber*100,5,'f',2); str += "%"; strong = QString(tr(" at x=%1")).arg(pFoil->m_fXCamber*100,5,'f',1); strong += "%"; str+=strong; m_pctrlCamb1->setText(str); str = QString(tr("Thick.=%1")).arg(pFoil->m_fThickness*100,5,'f',2); str += "%"; strong = QString(tr(" at x=%1")).arg(pFoil->m_fXThickness*100,5,'f',1); strong += "%"; str+=strong; m_pctrlThick1->setText(str); m_NewFoilName = pFoil->m_FoilName; } Update(); } void InterpolateFoilsDlg::OnSelChangeFoil2(int i) { i=0; QString strong = m_pctrlFoil2->currentText(); Foil* pFoil = MainFrame::foil(strong); if(pFoil) { QString str; str = QString(tr("Camb.=%1")).arg(pFoil->m_fCamber*100,5,'f',2); str += "%"; strong = QString(tr(" at x=%1")).arg(pFoil->m_fXCamber*100,5,'f',1); strong += "%"; str+=strong; m_pctrlCamb2->setText(str); str = QString(tr("Thick.=%1")).arg(pFoil->m_fThickness*100,5,'f',2); str += "%"; strong = QString(tr(" at x=%1")).arg(pFoil->m_fXThickness*100,5,'f',1); strong += "%"; str+=strong; m_pctrlThick2->setText(str); } Update(); } void InterpolateFoilsDlg::Update() { QAFoil *pAFoil = (QAFoil*)m_pAFoil; QXDirect *pXDirect = (QXDirect*)m_pXDirect; XFoil *pXFoil = (XFoil*)s_pXFoil; QString strong; strong = m_pctrlFoil1->currentText(); Foil* pFoil1 = MainFrame::foil(strong); strong = m_pctrlFoil2->currentText(); Foil* pFoil2 = MainFrame::foil(strong); if(!pFoil1 || !pFoil2) return; pXFoil->Interpolate(pFoil1->x, pFoil1->y, pFoil1->n, pFoil2->x, pFoil2->y, pFoil2->n, m_Frac/100.0); for (int j=0; j< pFoil1->n; j++) { m_pBufferFoil->x[j] = pXFoil->xb[j+1]; m_pBufferFoil->y[j] = pXFoil->yb[j+1]; m_pBufferFoil->xb[j] = pXFoil->xb[j+1]; m_pBufferFoil->yb[j] = pXFoil->yb[j+1]; } m_pBufferFoil->n = pFoil1->n; m_pBufferFoil->nb = pFoil1->n; m_pBufferFoil->InitFoil(); QString str; str = QString(tr("Camb.=%1")).arg(m_pBufferFoil->m_fCamber*100,5,'f',2); str += "%"; strong = QString(tr(" at x=%1")).arg(m_pBufferFoil->m_fXCamber*100,5,'f',1); strong += "%"; str+=strong; m_pctrlCamb3->setText(str); str = QString(tr("Thick.=%1")).arg(m_pBufferFoil->m_fThickness*100,5,'f',2); str += "%"; strong = QString(tr(" at x=%1")).arg(m_pBufferFoil->m_fXThickness*100,5,'f',1); strong += "%"; str+=strong; m_pctrlThick3->setText(str); if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } void InterpolateFoilsDlg::OnFrac() { m_Frac = m_pctrlFrac->Value(); m_pctrlSlider->setSliderPosition((int)(m_Frac/100.0*SLIDERSCALE)); m_Frac = 100.0 - m_Frac; Update(); } void InterpolateFoilsDlg::OnOK() { m_pBufferFoil->m_FoilName = m_NewFoilName; QDialog::accept(); } void InterpolateFoilsDlg::OnVScroll(int val) { val = m_pctrlSlider->sliderPosition(); m_Frac = (SLIDERSCALE - (double)val)/SLIDERSCALE*100.0; m_pctrlFrac->SetValue(100.0-m_Frac); Update(); } xflr5-6.09-06/src/xdirect/XFoilAdvancedDlg.h000644 001750 000144 00000003151 12247174410 021770 0ustar00techwinderusers000000 000000 /**************************************************************************** XFoilAdvancedDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef XFOILADVANCEDDLG_H #define XFOILADVANCEDDLG_H #include #include #include #include #include "../misc/DoubleEdit.h" #include "../misc/IntEdit.h" class XFoilAdvancedDlg : public QDialog { Q_OBJECT friend class QXDirect; public: XFoilAdvancedDlg(QWidget *pParent=NULL); void InitDialog(); private slots: void OnOK(); private: void keyPressEvent(QKeyEvent *event); void SetupLayout(); QCheckBox *m_pctrlInitBL, *m_pctrlFullReport; IntEdit *m_pctrlIterLimit; DoubleEdit * m_pctrlVAccel; QPushButton *OKButton, *CancelButton; int m_IterLimit; double m_VAccel; bool m_bInitBL; bool m_bFullReport; }; #endif // XFOILADVANCEDDLG_H xflr5-6.09-06/src/xdirect/FoilPolarDlg.cpp000644 001750 000144 00000043704 12247174410 021553 0ustar00techwinderusers000000 000000 /**************************************************************************** FoilPolarDlg Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include "FoilPolarDlg.h" #include "../globals.h" #include "../mainframe.h" FoilPolarDlg::FoilPolarDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Foil Polar Definition")); m_PolarType = FIXEDSPEEDPOLAR; m_NCrit = 9.0; m_XTopTr = 1.0; m_XBotTr = 1.0; m_Mach = 0.0; m_Reynolds = 100000.0; m_ASpec = 0.0; m_bAutoName = true; m_UnitType = 1; m_Viscosity = 1.5e-5; m_Density = 1.225; m_Chord = m_Span = m_Mass = 0.0; SetupLayout(); } void FoilPolarDlg::SetupLayout() { QFont SymbolFont("Symbol"); QGroupBox *NameGroupBox = new QGroupBox(tr("Analysis Name")); { QVBoxLayout *AnalysisLayout = new QVBoxLayout; { QHBoxLayout *autoname = new QHBoxLayout; { m_pctrlAuto1 = new QRadioButton(tr("Automatic")); m_pctrlAuto2 = new QRadioButton(tr("User Defined")); m_pctrlAnalysisName = new QLineEdit(tr("Analysis Name")); autoname->addStretch(1); autoname->addWidget(m_pctrlAuto1); autoname->addStretch(1); autoname->addWidget(m_pctrlAuto2); autoname->addStretch(1); } AnalysisLayout->addLayout(autoname); AnalysisLayout->addWidget(m_pctrlAnalysisName); } NameGroupBox->setLayout(AnalysisLayout); } QGroupBox *TypeGroup = new QGroupBox(tr("Analysis Type")); { QHBoxLayout *AnalysisType = new QHBoxLayout; { m_rbtype1 = new QRadioButton(tr("Type 1")); m_rbtype2 = new QRadioButton(tr("Type 2")); m_rbtype3 = new QRadioButton(tr("Type 3")); m_rbtype4 = new QRadioButton(tr("Type 4")); AnalysisType->addWidget(m_rbtype1); AnalysisType->addWidget(m_rbtype2); AnalysisType->addWidget(m_rbtype3); AnalysisType->addWidget(m_rbtype4); TypeGroup->setLayout(AnalysisType); } } QGroupBox *AeroGroupBox = new QGroupBox(tr("Reynolds and Mach Numbers")); { QVBoxLayout *ReMachLayout = new QVBoxLayout; { QHBoxLayout *Type2DataLayout = new QHBoxLayout; { //type 2 input data QGroupBox *PlaneDataGroup = new QGroupBox(tr("Plane Data")); { QGridLayout *PlaneDataLayout = new QGridLayout; m_pctrlChord = new DoubleEdit(0,3); m_pctrlMass = new DoubleEdit(0,3); m_pctrlSpan = new DoubleEdit(0,3); QLabel *ChordLab = new QLabel(tr("Chord")); QLabel *MassLab = new QLabel(tr("Mass")); QLabel *SpanLab = new QLabel(tr("Span")); m_pctrlLengthUnit1 = new QLabel("m"); m_pctrlLengthUnit2 = new QLabel("m"); m_pctrlMassUnit = new QLabel("kg"); PlaneDataLayout->addWidget(ChordLab,1,1); PlaneDataLayout->addWidget(m_pctrlChord,1,2); PlaneDataLayout->addWidget(m_pctrlLengthUnit1,1,3); PlaneDataLayout->addWidget(SpanLab,2,1); PlaneDataLayout->addWidget(m_pctrlSpan,2,2); PlaneDataLayout->addWidget(m_pctrlLengthUnit2,2,3); PlaneDataLayout->addWidget(MassLab,3,1); PlaneDataLayout->addWidget(m_pctrlMass,3,2); PlaneDataLayout->addWidget(m_pctrlMassUnit,3,3); PlaneDataGroup->setLayout(PlaneDataLayout); } QGroupBox *AeroDataGroup = new QGroupBox(tr("Aerodynamic Data")); { QGridLayout *AeroDataLayout = new QGridLayout; QLabel *lab9 = new QLabel(tr("Unit")); m_pctrlUnit1 = new QRadioButton(tr("International")); m_pctrlUnit2 = new QRadioButton(tr("Imperial")); m_pctrlRho = new QLabel("r ="); m_pctrlDensity = new DoubleEdit(1.225,3); m_pctrlDensityUnit = new QLabel("kg/m3"); m_pctrlNu = new QLabel("n ="); m_pctrlRho->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlNu->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlViscosity = new DoubleEdit(1.500e-5,3); m_pctrlViscosityUnit = new QLabel("m2/s"); m_pctrlRho->setFont(SymbolFont); m_pctrlNu->setFont(SymbolFont); m_pctrlDensity->SetPrecision(5); m_pctrlViscosity->SetPrecision(3); m_pctrlDensity->SetMin(0.0); m_pctrlViscosity->SetMin(0.0); AeroDataLayout->addWidget(lab9,1,1); AeroDataLayout->addWidget(m_pctrlUnit1,1,2); AeroDataLayout->addWidget(m_pctrlUnit2,1,3); AeroDataLayout->addWidget(m_pctrlRho,2,1); AeroDataLayout->addWidget(m_pctrlDensity,2,2); AeroDataLayout->addWidget(m_pctrlDensityUnit,2,3); AeroDataLayout->addWidget(m_pctrlNu,3,1); AeroDataLayout->addWidget(m_pctrlViscosity,3,2); AeroDataLayout->addWidget(m_pctrlViscosityUnit,3,3); AeroDataGroup->setLayout(AeroDataLayout); } Type2DataLayout->addWidget(PlaneDataGroup); Type2DataLayout->addWidget(AeroDataGroup); } QHBoxLayout *ReMachResultsLayout = new QHBoxLayout; { m_pctrlReLabel = new QLabel(tr(" Re =")); m_pctrlReLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlMachLabel = new QLabel(tr("Mach =")); m_pctrlMachLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlReynolds = new DoubleEdit(); m_pctrlReynolds->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlMach = new DoubleEdit(0.0, 3); m_pctrlMach->setAlignment(Qt::AlignRight | Qt::AlignVCenter); ReMachResultsLayout->addWidget(m_pctrlReLabel); ReMachResultsLayout->addWidget(m_pctrlReynolds); ReMachResultsLayout->addStretch(1); ReMachResultsLayout->addWidget(m_pctrlMachLabel); ReMachResultsLayout->addWidget(m_pctrlMach); } ReMachLayout->addLayout(Type2DataLayout); ReMachLayout->addSpacing(15); ReMachLayout->addLayout(ReMachResultsLayout); } AeroGroupBox->setLayout(ReMachLayout); } QHBoxLayout *CommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); OKButton->setAutoDefault(false); CancelButton = new QPushButton(tr("Cancel")); CancelButton->setAutoDefault(false); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } QGroupBox *TransGroup = new QGroupBox(tr("Transition settings")); { QGridLayout *Transitions = new QGridLayout; { QLabel *FreeTransLabel = new QLabel(tr("Free transitions (e^n) method")); QLabel *ForceTransLabel = new QLabel(tr("Forced transition:")); QLabel *NCritLabel = new QLabel(tr("NCrit=")); QLabel *TopTripLabel = new QLabel(tr("TripLocation (top)")); QLabel *BotTripLabel = new QLabel(tr("TripLocation (bot)")); m_pctrlNCrit = new DoubleEdit(); m_pctrlTopTrans = new DoubleEdit(); m_pctrlBotTrans = new DoubleEdit(); m_pctrlNCrit->setAlignment( Qt::AlignRight); m_pctrlTopTrans->setAlignment(Qt::AlignRight); m_pctrlBotTrans->setAlignment(Qt::AlignRight); Transitions->addWidget(FreeTransLabel, 1,1, 1,1, Qt::AlignLeft| Qt::AlignVCenter); Transitions->addWidget(ForceTransLabel, 2,1, 1,1, Qt::AlignLeft| Qt::AlignVCenter); Transitions->addWidget(NCritLabel, 1,2, 1,1, Qt::AlignRight| Qt::AlignVCenter); Transitions->addWidget(TopTripLabel, 2,2, 1,1, Qt::AlignRight| Qt::AlignVCenter); Transitions->addWidget(BotTripLabel, 3,2, 1,1, Qt::AlignRight| Qt::AlignVCenter); Transitions->addWidget(m_pctrlNCrit, 1,3, 1,1, Qt::AlignRight| Qt::AlignVCenter); Transitions->addWidget(m_pctrlTopTrans, 2,3, 1,1, Qt::AlignRight| Qt::AlignVCenter); Transitions->addWidget(m_pctrlBotTrans, 3,3, 1,1, Qt::AlignRight| Qt::AlignVCenter); TransGroup->setLayout(Transitions); } } QVBoxLayout *mainLayout = new QVBoxLayout; { mainLayout->setSpacing(10); mainLayout->addWidget(NameGroupBox); mainLayout->addWidget(TypeGroup); mainLayout->addWidget(AeroGroupBox); mainLayout->addWidget(TransGroup); mainLayout->addLayout(CommandButtons); } setLayout(mainLayout); m_pctrlTopTrans->SetPrecision(2); m_pctrlTopTrans->SetMin(0.0); m_pctrlTopTrans->SetMax(1.0); m_pctrlBotTrans->SetPrecision(2); m_pctrlBotTrans->SetMin(0.0); m_pctrlBotTrans->SetMax(1.0); m_pctrlNCrit->SetPrecision(3); m_pctrlNCrit->SetMin(0.0); m_pctrlNCrit->SetMax(1000000.0); m_pctrlReynolds->SetPrecision(0); m_pctrlReynolds->SetMin(-1.0e10); m_pctrlReynolds->SetMax(1.e10); m_pctrlMach->SetMin(0.0); m_pctrlMach->SetMax(1000.0); connect(m_pctrlAuto1, SIGNAL(clicked()), this, SLOT(OnAutoName())); connect(m_pctrlAuto2, SIGNAL(clicked()), this, SLOT(OnAutoName())); connect(m_rbtype1, SIGNAL(clicked()), this, SLOT(OnPolarType())); connect(m_rbtype2, SIGNAL(clicked()), this, SLOT(OnPolarType())); connect(m_rbtype3, SIGNAL(clicked()), this, SLOT(OnPolarType())); connect(m_rbtype4, SIGNAL(clicked()), this, SLOT(OnPolarType())); connect(m_pctrlReynolds, SIGNAL(editingFinished()), this, SLOT(EditingFinished())); connect(m_pctrlMach, SIGNAL(editingFinished()), this, SLOT(EditingFinished())); connect(m_pctrlNCrit, SIGNAL(editingFinished()), this, SLOT(EditingFinished())); connect(m_pctrlTopTrans, SIGNAL(editingFinished()), this, SLOT(EditingFinished())); connect(m_pctrlBotTrans, SIGNAL(editingFinished()), this, SLOT(EditingFinished())); connect(m_pctrlAnalysisName, SIGNAL(textEdited (const QString &)), this, SLOT(OnNameChanged())); connect(m_pctrlUnit1, SIGNAL(toggled(bool)), this, SLOT(OnUnit())); connect(m_pctrlUnit2, SIGNAL(toggled(bool)), this, SLOT(OnUnit())); connect(m_pctrlChord, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlSpan, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlMass, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlViscosity, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlDensity, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); } void FoilPolarDlg::EditingFinished() { SetPlrName(); // OKButton->setFocus(); } void FoilPolarDlg::InitDialog() { if(MainFrame::s_pCurFoil) m_FoilName = MainFrame::s_pCurFoil->m_FoilName; else m_FoilName = ""; QString str = tr("Analysis parameters for "); setWindowTitle(str+ m_FoilName); m_pctrlReynolds->SetValue(m_Reynolds); m_pctrlMach->SetValue(m_Mach); m_pctrlNCrit->SetValue(m_NCrit); m_pctrlTopTrans->SetValue(m_XTopTr); m_pctrlBotTrans->SetValue(m_XBotTr); m_bAutoName = true; m_pctrlAuto1->setChecked(true); switch(m_PolarType) { case FIXEDSPEEDPOLAR: { m_rbtype1->setChecked(true); break; } case FIXEDLIFTPOLAR: { m_rbtype2->setChecked(true); break; } case RUBBERCHORDPOLAR: { m_rbtype3->setChecked(true); break; } case FIXEDAOAPOLAR: { m_rbtype4->setChecked(true); break; } default: { m_rbtype1->setChecked(true); break; } } GetLengthUnit(str, MainFrame::s_LengthUnit); m_pctrlLengthUnit1->setText(str); m_pctrlLengthUnit2->setText(str); GetWeightUnit(str, MainFrame::s_WeightUnit); m_pctrlMassUnit->setText(str); m_pctrlUnit1->setChecked(m_UnitType==1); m_pctrlUnit2->setChecked(m_UnitType!=1); m_pctrlViscosity->SetValue(m_Viscosity); m_pctrlDensity->SetValue(m_Density); OnUnit(); m_pctrlMass->SetValue(m_Mass); m_pctrlSpan->SetValue(m_Span); m_pctrlChord->SetValue(m_Chord); OnPolarType(); } void FoilPolarDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { ReadParams(); SetPlrName(); OKButton->setFocus(); return; } else if(OKButton->hasFocus()) { OnOK(); return; } break; } case Qt::Key_Escape: { reject(); return; } default: event->ignore(); } } void FoilPolarDlg::OnAutoName() { if(m_pctrlAuto2->isChecked()) { m_bAutoName = false; m_pctrlAnalysisName->setFocus(); m_pctrlAnalysisName->selectAll(); } else { m_bAutoName = true; SetPlrName(); } } void FoilPolarDlg::OnNameChanged() { m_bAutoName = false; m_pctrlAuto1->setChecked(false); m_pctrlAuto2->setChecked(true); } void FoilPolarDlg::OnOK() { m_PlrName = m_pctrlAnalysisName->text(); accept(); } void FoilPolarDlg::OnPolarType() { if(m_rbtype1->isChecked()) { m_pctrlReLabel->setText(tr("Reynolds =")); m_pctrlMachLabel->setText(tr("Mach =")); m_pctrlReynolds->SetPrecision(0); m_pctrlReynolds->SetValue(m_Reynolds); m_PolarType = FIXEDSPEEDPOLAR; } else if(m_rbtype2->isChecked()) { m_pctrlReLabel->setText(tr("Re.sqrt(Cl) =")); m_pctrlMachLabel->setText(tr("Ma.sqrt(Cl) =")); m_pctrlReynolds->SetPrecision(0); m_pctrlReynolds->SetValue(m_Reynolds); m_PolarType = FIXEDLIFTPOLAR; } else if(m_rbtype3->isChecked()) { m_pctrlReLabel->setText(tr("Re.Cl =")); m_pctrlMachLabel->setText(tr("Mach =")); m_pctrlReynolds->SetPrecision(0); m_pctrlReynolds->SetValue(m_Reynolds); m_PolarType = RUBBERCHORDPOLAR; } else if(m_rbtype4->isChecked()) { m_pctrlReLabel->setText(tr("Alpha =")); m_pctrlMachLabel->setText(tr("Mach =")); m_pctrlReynolds->SetPrecision(2); m_pctrlReynolds->SetValue(m_ASpec); m_PolarType = FIXEDAOAPOLAR; } m_pctrlChord->setEnabled(m_PolarType==FIXEDLIFTPOLAR); m_pctrlSpan->setEnabled(m_PolarType==FIXEDLIFTPOLAR); m_pctrlMass->setEnabled(m_PolarType==FIXEDLIFTPOLAR); m_pctrlViscosity->setEnabled(m_PolarType==FIXEDLIFTPOLAR); m_pctrlDensity->setEnabled(m_PolarType==FIXEDLIFTPOLAR); m_pctrlUnit1->setEnabled(m_PolarType==FIXEDLIFTPOLAR); m_pctrlUnit2->setEnabled(m_PolarType==FIXEDLIFTPOLAR); SetPlrName(); } void FoilPolarDlg::SetPlrName() { ReadParams(); double Re = m_Reynolds/1000000.; if(m_bAutoName) { switch(m_PolarType) { case FIXEDSPEEDPOLAR: { m_PlrName = QString("T1_Re%1_M%2").arg(Re,5,'f',2).arg(m_Mach,4,'f',2); break; } case FIXEDLIFTPOLAR: { m_PlrName = QString("T2_Re%1_M%2").arg(Re,5,'f',2).arg(m_Mach,4,'f',2); break; } case RUBBERCHORDPOLAR: { m_PlrName = QString("T3_Re%1_M%2").arg(Re,5,'f',2).arg(m_Mach,4,'f',2); break; } case(FIXEDAOAPOLAR): { m_PlrName = QString("T%1_Al%2_M%3").arg(m_PolarType).arg(m_ASpec,5,'f',2).arg(m_Mach,4,'f',2); break; } default: { m_PlrName = QString("T1_Al%1_M%2").arg(m_ASpec,5,'f',2).arg(m_Mach,4,'f',2); break; } } QString str = QString("_N%1").arg(m_NCrit,3,'f',1); m_PlrName += str; m_pctrlAnalysisName->setText(m_PlrName); } } /* if(m_bAutoName) { if(m_PolarType!=FIXEDAOAPOLAR) { double Re = m_Reynolds/1000000.; m_PlrName=QString("T%1_Re%2_M%3").arg(m_PolarType).arg(Re,4,'f',3).arg(m_Mach,4,'f',2); } else { m_PlrName = QString("T%1_Al%2_M%3").arg(m_PolarType).arg(m_ASpec,5,'f',2).arg(m_Mach,4,'f',2); } QString str = QString("_N%1").arg(m_NCrit,3,'f',1); m_PlrName += str; m_pctrlAnalysisName->setText(m_PlrName); } */ void FoilPolarDlg::OnUnit() { if(m_pctrlUnit1->isChecked()) { m_UnitType = 1; m_pctrlViscosity->SetValue(m_Viscosity); m_pctrlDensityUnit->setText("kg/m3"); m_pctrlViscosityUnit->setText("m"+QString::fromUtf8("²")+"/s"); } else { m_UnitType = 2; m_pctrlViscosity->SetValue(m_Viscosity* 10.7182881); m_pctrlDensityUnit->setText("slugs/ft3"); m_pctrlViscosityUnit->setText("ft"+QString::fromUtf8("²")+"/s"); } SetDensity(); } void FoilPolarDlg::ReadParams() { bool bOK; QString str; str = m_pctrlReynolds->text(); str.replace(" ",""); if(m_PolarType==FIXEDAOAPOLAR) m_ASpec = locale().toDouble(str, &bOK); else m_Reynolds = locale().toDouble(str, &bOK); m_Mach = m_pctrlMach->Value(); m_pctrlMach->clear(); m_pctrlMach->insert(str.setNum(m_Mach,'f',3)); m_NCrit = m_pctrlNCrit->Value(); m_XTopTr = m_pctrlTopTrans->Value(); m_XBotTr = m_pctrlBotTrans->Value(); m_Mass = m_pctrlMass->Value(); m_Chord = m_pctrlChord->Value(); m_Span = m_pctrlSpan->Value(); m_Viscosity = m_pctrlViscosity->Value(); m_Density = m_pctrlDensity->Value(); } void FoilPolarDlg::SetDensity() { int exp, precision; if(m_pctrlUnit1->isChecked()) { exp = (int)log(m_Density); if(exp>1) precision = 1; else if(exp<-4) precision = 4; else precision = 3-exp; m_pctrlDensity->SetPrecision(precision); m_pctrlDensity->SetValue(m_Density); } else { exp = (int)log(m_Density* 0.00194122); if(exp>1) precision = 1; else if(exp<-4) precision = 4; else precision = 3-exp; m_pctrlDensity->SetPrecision(precision); m_pctrlDensity->SetValue(m_Density* 0.00194122); } } void FoilPolarDlg::OnEditingFinished() { ReadParams(); if(m_PolarType==2) { //compute Re.sqrt(Cl) m_pctrlReynolds->SetValue(sqrt(2.0*m_Mass*9.81*m_Density*m_Chord/m_Viscosity/m_Viscosity/m_Span)); } } xflr5-6.09-06/src/xdirect/BatchThreadDlg.cpp000644 001750 000144 00000062454 12247174410 022040 0ustar00techwinderusers000000 000000 /**************************************************************************** BatchThreadDlg Class Copyright (C) 2003-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "BatchThreadDlg.h" #include "XDirect.h" #include "ReListDlg.h" #include "../mainframe.h" #include "../xinverse/FoilSelectionDlg.h" #include #include #include #include #include #include #include #include bool BatchThreadDlg::s_bCurrentFoil=true; bool BatchThreadDlg::s_bUpdatePolarView = false; void * BatchThreadDlg::s_pXFoil; void * BatchThreadDlg::s_pMainFrame; void * BatchThreadDlg::s_pXDirect; QPoint BatchThreadDlg::s_Position; /** * The public contructor */ BatchThreadDlg::BatchThreadDlg(QWidget *pParent) : QDialog(pParent) { QString str = tr("Multi-threaded batch analysis"); setWindowTitle(str); m_PolarType = FIXEDSPEEDPOLAR; m_FoilList.clear(); m_Mach = 0.0; m_ReMin = 100000.0; m_ReMax = 300000.0; m_ReInc = 50000.0; m_ClMin = 0.0; m_ClMax = 1.0; m_ClInc = 0.1; m_NCrit = 9.0; m_XTopTr = 1.0; m_XBotTr = 1.0; m_ReList = NULL; m_MachList = NULL; m_NCritList = NULL; m_bAlpha = true; m_bFromList = false; m_bFromZero = false; m_bInitBL = false; m_bCancel = false; m_bIsRunning = false; m_IterLim = 100; m_NRe = 0; XFoil::s_bCancel = false; SetupLayout(); connect(m_pctrlFoil1, SIGNAL(clicked()), this, SLOT(OnFoilSelectionType())); connect(m_pctrlFoil2, SIGNAL(clicked()), this, SLOT(OnFoilSelectionType())); connect(m_pctrlFoilList, SIGNAL(clicked()), this, SLOT(OnFoilList())); connect(m_pctrlClose, SIGNAL(clicked()), this, SLOT(OnClose())); connect(m_pctrlAnalyze, SIGNAL(clicked()), this, SLOT(OnAnalyze())); connect(m_pctrlAlpha, SIGNAL(toggled(bool)), this, SLOT(OnAcl())); connect(m_pctrlCl, SIGNAL(toggled(bool)), this, SLOT(OnAcl())); connect(m_rbRange1, SIGNAL(toggled(bool)), this, SLOT(OnRange())); connect(m_rbRange2, SIGNAL(toggled(bool)), this, SLOT(OnRange())); connect(m_pctrlEditList, SIGNAL(clicked()), this, SLOT(OnEditReList())); connect(m_pctrlFromZero, SIGNAL(stateChanged(int)), this, SLOT(OnFromZero(int))); connect(m_pctrlSpecMin, SIGNAL(editingFinished()), this, SLOT(OnSpecChanged())); connect(m_pctrlSpecMax, SIGNAL(editingFinished()), this, SLOT(OnSpecChanged())); connect(m_pctrlSpecDelta, SIGNAL(editingFinished()), this, SLOT(OnSpecChanged())); } /** * Sets up the GUI */ void BatchThreadDlg::SetupLayout() { QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::Expanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Expanding); QSizePolicy szPolicyMinimum; szPolicyMinimum.setHorizontalPolicy(QSizePolicy::Minimum); szPolicyMinimum.setVerticalPolicy(QSizePolicy::MinimumExpanding); QSizePolicy szPolicyMaximum; szPolicyMaximum.setHorizontalPolicy(QSizePolicy::Maximum); szPolicyMaximum.setVerticalPolicy(QSizePolicy::Maximum); QGroupBox *FoilBox = new QGroupBox(tr("Foil Selection")); { QHBoxLayout *FoilLayout = new QHBoxLayout; m_pctrlFoil1 = new QRadioButton(tr("Current foil only")); m_pctrlFoil2 = new QRadioButton(tr("Foil list")); m_pctrlFoilList = new QPushButton(tr("Foil list")); FoilLayout->addWidget(m_pctrlFoil1); FoilLayout->addWidget(m_pctrlFoil2); FoilLayout->addStretch(1); FoilLayout->addWidget(m_pctrlFoilList); FoilBox->setLayout(FoilLayout); } QGroupBox *pBatchVarsGroupBox = new QGroupBox(tr("Batch Variables")); { QGridLayout *BatchVarsLayout = new QGridLayout; { m_rbRange1 = new QRadioButton(tr("Range")); m_rbRange2 = new QRadioButton(tr("Re List")); m_pctrlEditList = new QPushButton(tr("Edit List")); QLabel *MinVal = new QLabel(tr("Min")); QLabel *MaxVal = new QLabel(tr("Max")); QLabel *DeltaVal = new QLabel(tr("Increment")); MinVal->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); MaxVal->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); DeltaVal->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); m_pctrlReType = new QLabel("Reynolds="); m_pctrlMaType = new QLabel("Mach="); QLabel *NCritLabel = new QLabel(tr("NCrit=")); m_pctrlReType->setAlignment(Qt::AlignVCenter|Qt::AlignRight); NCritLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight); m_pctrlMaType->setAlignment(Qt::AlignVCenter|Qt::AlignRight); m_pctrlNCrit = new DoubleEdit(9.00); m_pctrlReMin = new DoubleEdit(100000,0); m_pctrlReMax = new DoubleEdit(150000,0); m_pctrlReDelta = new DoubleEdit(50000,0); m_pctrlMach = new DoubleEdit(0.00, 3); BatchVarsLayout->addWidget(MinVal, 2, 2); BatchVarsLayout->addWidget(MaxVal, 2, 3); BatchVarsLayout->addWidget(DeltaVal, 2, 4); BatchVarsLayout->addWidget(m_pctrlReType, 3, 1); BatchVarsLayout->addWidget(m_pctrlReMin, 3, 2); BatchVarsLayout->addWidget(m_pctrlReMax, 3, 3); BatchVarsLayout->addWidget(m_pctrlReDelta, 3, 4); BatchVarsLayout->addWidget(m_pctrlMaType, 4, 1); BatchVarsLayout->addWidget(m_pctrlMach, 4, 2); BatchVarsLayout->addWidget(NCritLabel, 5,1); BatchVarsLayout->addWidget(m_pctrlNCrit, 5, 2); } QHBoxLayout *RangeSpecLayout = new QHBoxLayout; { RangeSpecLayout->addWidget(m_rbRange1); RangeSpecLayout->addWidget(m_rbRange2); RangeSpecLayout->addStretch(1); RangeSpecLayout->addWidget(m_pctrlEditList); } QVBoxLayout *BatchVarsGroupLayout = new QVBoxLayout; { BatchVarsGroupLayout->addLayout(RangeSpecLayout); BatchVarsGroupLayout->addLayout(BatchVarsLayout); pBatchVarsGroupBox->setLayout(BatchVarsGroupLayout); } } QGroupBox *pRangeVarsGroupBox = new QGroupBox(tr("Analysis Range")); { QHBoxLayout *RangeSpecLayout = new QHBoxLayout; { QLabel *Spec = new QLabel(tr("Specify:")); m_pctrlAlpha = new QRadioButton(tr("Alpha")); m_pctrlCl = new QRadioButton(tr("Cl")); m_pctrlFromZero = new QCheckBox(tr("From Zero")); RangeSpecLayout->addWidget(Spec); RangeSpecLayout->addWidget(m_pctrlAlpha); RangeSpecLayout->addWidget(m_pctrlCl); RangeSpecLayout->addStretch(1); RangeSpecLayout->addWidget(m_pctrlFromZero); } QGridLayout *RangeVarsLayout = new QGridLayout; { QLabel *SpecMin = new QLabel(tr("Min")); QLabel *SpecMax = new QLabel(tr("Max")); QLabel *SpecDelta = new QLabel(tr("Increment")); SpecMin->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); SpecMax->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); SpecDelta->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); m_pctrlSpecVar = new QLabel(tr("Spec =")); m_pctrlSpecMin = new DoubleEdit(0.00); m_pctrlSpecMax = new DoubleEdit(1.00); m_pctrlSpecDelta = new DoubleEdit(0.50); RangeVarsLayout->addWidget(SpecMin, 1, 2); RangeVarsLayout->addWidget(SpecMax, 1, 3); RangeVarsLayout->addWidget(SpecDelta, 1, 4); RangeVarsLayout->addWidget(m_pctrlSpecVar, 2, 1); RangeVarsLayout->addWidget(m_pctrlSpecMin, 2, 2); RangeVarsLayout->addWidget(m_pctrlSpecMax, 2, 3); RangeVarsLayout->addWidget(m_pctrlSpecDelta, 2, 4); } QVBoxLayout *RangeVarsGroupLayout = new QVBoxLayout; { RangeVarsGroupLayout->addLayout(RangeSpecLayout); RangeVarsGroupLayout->addLayout(RangeVarsLayout); pRangeVarsGroupBox->setLayout(RangeVarsGroupLayout); } } QGroupBox *pTransVarsGroupBox = new QGroupBox(tr("Forced Transitions")); { QGridLayout *TransVars = new QGridLayout; { TransVars->setColumnStretch(0,4); TransVars->setColumnStretch(1,1); QLabel *TopTransLabel = new QLabel(tr("Top transition location (x/c)")); QLabel *BotTransLabel = new QLabel(tr("Bottom transition location (x/c)")); TopTransLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight); BotTransLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight); m_pctrlXTopTr = new DoubleEdit(1.00); m_pctrlXBotTr = new DoubleEdit(1.00); TransVars->addWidget(TopTransLabel, 2, 1); TransVars->addWidget(m_pctrlXTopTr, 2, 2); TransVars->addWidget(BotTransLabel, 3, 1); TransVars->addWidget(m_pctrlXBotTr, 3, 2); } pTransVarsGroupBox->setLayout(TransVars); } QHBoxLayout *OptionsLayout = new QHBoxLayout; { m_pctrlInitBL = new QCheckBox(tr("Initialize BLs between polars")); m_pctrlUpdatePolarView = new QCheckBox(tr("Update polar view")); m_pctrlUpdatePolarView->setToolTip(tr("Update the polar graphs after the completion of each foil/polar pair")); OptionsLayout->addWidget(m_pctrlInitBL); OptionsLayout->addStretch(1); OptionsLayout->addWidget(m_pctrlUpdatePolarView); } //_*_*_*_*_*_*_**_*_*_**_*_*_*_ QHBoxLayout *CommandButtons = new QHBoxLayout; { m_pctrlClose = new QPushButton(tr("Close")); m_pctrlAnalyze = new QPushButton(tr("Analyze")) ; m_pctrlAnalyze->setAutoDefault(true); CommandButtons->addStretch(1); CommandButtons->addWidget(m_pctrlAnalyze); CommandButtons->addStretch(1); CommandButtons->addWidget(m_pctrlClose); CommandButtons->addStretch(1); } QVBoxLayout *LeftSide = new QVBoxLayout; { LeftSide->addWidget(FoilBox); LeftSide->addWidget(pBatchVarsGroupBox); LeftSide->addWidget(pTransVarsGroupBox); LeftSide->addWidget(pRangeVarsGroupBox); LeftSide->addStretch(1); LeftSide->addSpacing(20); LeftSide->addLayout(CommandButtons); } QVBoxLayout *RightSide = new QVBoxLayout; { m_pctrlTextOutput = new QTextEdit; m_pctrlTextOutput->setReadOnly(true); m_pctrlTextOutput->setLineWrapMode(QTextEdit::NoWrap); m_pctrlTextOutput->setWordWrapMode(QTextOption::NoWrap); m_pctrlTextOutput->setSizePolicy(szPolicyMinimum); m_pctrlTextOutput->setMinimumWidth(350); // RightSide->addStretch(1); RightSide->addLayout(OptionsLayout); RightSide->addWidget(m_pctrlTextOutput,1); // RightSide->addStretch(1); } QHBoxLayout *BoxesLayout = new QHBoxLayout; { BoxesLayout->setSpacing(10); BoxesLayout->addLayout(LeftSide); BoxesLayout->addLayout(RightSide); } setLayout(BoxesLayout); } /** * Clean-up performed when all the threads are terminated */ void BatchThreadDlg::CleanUp() { if(m_pXFile->isOpen()) { QTextStream out(m_pXFile); out<toPlainText(); m_pXFile->close(); } m_pctrlClose->setEnabled(true); m_pctrlAnalyze->setText(tr("Analyze")); m_bIsRunning = false; m_bCancel = false; XFoil::s_bCancel = false; m_pctrlClose->setFocus(); } /** * Creates a polar object for a given set of specified input data * @param pFoil a pointer to the Foil object to which the Polar will be attached * @param Re the value of the Reynolds number * @param Mach the value of the Mach number * @param NCrit the value of the transition criterion * @return a pointer to the Polar object which has been created */ Polar * BatchThreadDlg::CreatePolar(Foil *pFoil, double Re, double Mach, double NCrit) { if(!pFoil) return NULL; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; Polar *pNewPolar = new Polar; pNewPolar->m_FoilName = pFoil->m_FoilName; pNewPolar->m_bIsVisible = true; pNewPolar->m_PolarType = m_PolarType; switch (pNewPolar->m_PolarType) { case 1: pNewPolar->m_MaType = 1; pNewPolar->m_ReType = 1; break; case 2: pNewPolar->m_MaType = 2; pNewPolar->m_ReType = 2; break; case 3: pNewPolar->m_MaType = 1; pNewPolar->m_ReType = 3; break; case 4: pNewPolar->m_MaType = 1; pNewPolar->m_ReType = 1; break; default: pNewPolar->m_ReType = 1; pNewPolar->m_MaType = 1; break; } if(m_PolarType!=FIXEDAOAPOLAR) pNewPolar->m_Reynolds = Re; else pNewPolar->m_ASpec = Re; pNewPolar->m_Mach = Mach; pNewPolar->m_ACrit = NCrit; pNewPolar->m_XTop = m_XTopTr; pNewPolar->m_XBot = m_XBotTr; pNewPolar->m_Color = pMainFrame->GetColor(1); SetPlrName(pNewPolar); Polar *pOldPolar = pMainFrame->GetPolar(pFoil->m_FoilName, pNewPolar->m_PlrName); if(pOldPolar) { delete pNewPolar; pNewPolar = pOldPolar; } else pNewPolar = pMainFrame->AddPolar(pNewPolar); return pNewPolar; } /** * Overrides the base class keyPressEvent method * @param event the keyPressEvent. */ void BatchThreadDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(m_pctrlClose->hasFocus()) done(1); else if(m_pctrlAnalyze->hasFocus()) OnAnalyze(); else m_pctrlAnalyze->setFocus(); break; } case Qt::Key_Escape: { if(m_bIsRunning) { OnAnalyze();//will cancel the threads } else { OnClose(); // will close the dialog box } break; } default: event->ignore(); } } /** * Initializes the dialog and the GUI interface */ void BatchThreadDlg::InitDialog() { if(!((MainFrame*)s_pMainFrame)->curFoil()) return; m_PolarType = FIXEDSPEEDPOLAR; //no choice... m_pctrlFoil1->setChecked(s_bCurrentFoil); m_pctrlFoil2->setChecked(!s_bCurrentFoil); m_pctrlFoilList->setEnabled(!s_bCurrentFoil); m_pctrlReMin->SetPrecision(0); m_pctrlReMax->SetPrecision(0); m_pctrlReDelta->SetPrecision(0); m_pctrlSpecMin->SetPrecision(1); m_pctrlSpecMax->SetPrecision(1); m_pctrlSpecDelta->SetPrecision(1); if(m_ReMin<=0.0) m_ReMin = qAbs(m_ReInc); m_pctrlReMin->SetValue(m_ReMin); m_pctrlReMax->SetValue(m_ReMax); m_pctrlReDelta->SetValue(m_ReInc); m_pctrlSpecMin->SetValue(m_AlphaMin); m_pctrlSpecMax->SetValue(m_AlphaMax); m_pctrlSpecDelta->SetValue(m_AlphaInc); m_pctrlMach->SetValue(m_Mach); m_pctrlNCrit->SetValue(m_NCrit); m_pctrlXTopTr->SetValue(m_XTopTr); m_pctrlXBotTr->SetValue(m_XBotTr); if(m_bAlpha) m_pctrlAlpha->setChecked(true); else m_pctrlCl->setChecked(m_bAlpha); OnAcl(); if(!m_bFromList) m_rbRange1->setChecked(true); else m_rbRange2->setChecked(true); OnRange(); if(m_bFromZero) m_pctrlFromZero->setChecked(true); else m_pctrlFromZero->setChecked(false); m_pctrlInitBL->setChecked(true); m_pctrlUpdatePolarView->setChecked(s_bUpdatePolarView); } /** * The user has switched between aoa and lift coeficient */ void BatchThreadDlg::OnAcl() { if(m_PolarType==FIXEDAOAPOLAR) return; m_bAlpha = m_pctrlAlpha->isChecked(); if(m_bAlpha) { m_pctrlSpecVar->setText(tr("Alpha")); m_pctrlSpecMin->SetValue(m_AlphaMin); m_pctrlSpecMax->SetValue(m_AlphaMax); m_pctrlSpecDelta->SetValue(m_AlphaInc); m_pctrlFromZero->setEnabled(true); } else { m_pctrlSpecVar->setText(tr("CL")); m_pctrlSpecMin->SetValue(m_ClMin); m_pctrlSpecMax->SetValue(m_ClMax); m_pctrlSpecDelta->SetValue(m_ClInc); m_bFromZero = false; m_pctrlFromZero->setChecked(false); m_pctrlFromZero->setEnabled(false); } } /** * The user has changed the range of Re values to analyze */ void BatchThreadDlg::OnSpecChanged() { ReadParams(); } /** * Launches the multi-threaded batch analysis */ void BatchThreadDlg::OnAnalyze() { if(m_bIsRunning) { m_bCancel = true; XFoilTask::s_bCancel = true; XFoil::s_bCancel = true; return; } m_bCancel = false; m_bIsRunning = true; XFoil *pXFoil = (XFoil*)s_pXFoil; m_pctrlTextOutput->setText(""); m_pctrlClose->setEnabled(false); QString FileName = QDir::tempPath() + "/XFLR5.log"; m_pXFile = new QFile(FileName); if (!m_pXFile->open(QIODevice::WriteOnly | QIODevice::Text)) m_pXFile = NULL; pXFoil->pXFile = m_pXFile; pXFoil->lvisc = true; ReadParams(); SetFileHeader(); m_bInitBL = m_pctrlInitBL->isChecked(); m_pctrlAnalyze->setFocus(); StartAnalysis(); } /** * The user has requested to quit the dialog box */ void BatchThreadDlg::OnClose() { s_bUpdatePolarView = m_pctrlUpdatePolarView->isChecked(); m_bCancel = true; XFoilTask::s_bCancel = true; QThreadPool::globalInstance()->waitForDone(); ReadParams(); accept(); } /** * The user has requested an edition of the Re list */ void BatchThreadDlg::OnEditReList() { ReListDlg dlg(this); for (int i=0; im_poaFoil; dlg.m_FoilList.clear(); for(int i=0; iisChecked(); m_pctrlFoilList->setEnabled(!s_bCurrentFoil); } /** * The user has clicked the "start from zero" checkbox * @param state the new state of the checkbox */ void BatchThreadDlg::OnFromZero(int state) { state = 0; if(m_pctrlFromZero->isChecked()) m_bFromZero = true; else m_bFromZero = false; } /** * The user has clicked the checkbox which specifies the initialization of the boundary layer **/ void BatchThreadDlg::OnInitBL(int state) { state = 0; if (m_pctrlInitBL->isChecked()) m_bInitBL = true; else m_bInitBL = false; } /** * The user has clicked the checkbox specifying which range of Re should be analyzed */ void BatchThreadDlg::OnRange() { if(m_rbRange1->isChecked()) m_bFromList = false; else m_bFromList = true; m_pctrlEditList->setEnabled(m_bFromList); m_pctrlReMin->setEnabled(!m_bFromList); m_pctrlReMax->setEnabled(!m_bFromList); m_pctrlReDelta->setEnabled(!m_bFromList); m_pctrlMach->setEnabled(!m_bFromList); m_pctrlNCrit->setEnabled(!m_bFromList); } /** * Reads the value of the input parameters from the widgets and maps the data */ void BatchThreadDlg::ReadParams() { m_bAlpha = m_pctrlAlpha->isChecked(); if(m_PolarType!=FIXEDAOAPOLAR) { m_ReInc = m_pctrlReDelta->Value(); m_ReMax = m_pctrlReMax->Value(); m_ReMin = m_pctrlReMin->Value(); if(m_bAlpha) { m_AlphaInc = qAbs(m_pctrlSpecDelta->Value()); m_AlphaMax = m_pctrlSpecMax->Value(); m_AlphaMin = m_pctrlSpecMin->Value(); } else { m_ClInc = qAbs(m_pctrlSpecDelta->Value()); m_ClMin = m_pctrlSpecMin->Value(); m_ClMax = m_pctrlSpecMax->Value(); } } if(m_ReMin<=0.0) m_ReMin = qAbs(m_ReInc); if(m_ReMax<=0.0) m_ReMax = qAbs(m_ReMax); m_Mach = m_pctrlMach->Value(); if(m_Mach<=0.0) m_Mach = 0.0; m_NCrit = m_pctrlNCrit->Value(); m_XTopTr = m_pctrlXTopTr->Value(); m_XBotTr = m_pctrlXBotTr->Value(); } /** * Initializes the header of the log file */ void BatchThreadDlg::SetFileHeader() { QTextStream out(m_pXFile); out << "\n"; out << MainFrame::versionName(); out << "\n"; if(s_bCurrentFoil) { out << MainFrame::curFoil()->m_FoilName; out << "\n"; } QDateTime dt = QDateTime::currentDateTime(); QString str = dt.toString("dd.MM.yyyy hh:mm:ss"); out << str; out << "\n___________________________________\n\n"; } /** * Creates the polar name for the input Polar * @param pNewPolar a pointer to the Polar object to name */ void BatchThreadDlg::SetPlrName(Polar *pNewPolar) { if(m_PolarType!=FIXEDAOAPOLAR) { double R = pNewPolar->m_Reynolds/1000000.; pNewPolar->m_PlrName = QString("T%1_Re%2_M%3") .arg(pNewPolar->m_PolarType+1) .arg(R,0,'f',3) .arg( pNewPolar->m_Mach,0,'f',2); } else { pNewPolar->m_PlrName = QString("T%1_Al%2_M%3") .arg(pNewPolar->m_PolarType) .arg(pNewPolar->m_ASpec,5,'f',2) .arg(pNewPolar->m_Mach,0,'f',2); } QString str; str = QString("_N%1").arg(pNewPolar->m_ACrit,0,'f',1); pNewPolar->m_PlrName += str; } /** * Adds a text message to the ouput widget * @param str the message to output */ void BatchThreadDlg::UpdateOutput(QString &str) { m_pctrlTextOutput->insertPlainText(str); m_pctrlTextOutput->ensureCursorVisible(); } /** * Adds a text message to the log file * @param str the message to output */ void BatchThreadDlg::WriteString(QString &strong) { if(!m_pXFile) return; if(!m_pXFile->isOpen()) return; QTextStream ds(m_pXFile); ds << strong; } /** * Starts the multithreaded analysis. * First, creates a pool list of all (Foil, pairs) to analyze. * Then, starts the threads which will pick the pairs from the pool and remove them once the analayis is finished. */ void BatchThreadDlg::StartAnalysis() { QXDirect *pXDirect = (QXDirect*)s_pXDirect; Foil *pFoil; Polar *pPolar; QString strong; int iRe, nRe; m_pctrlAnalyze->setText(tr("Cancel")); strong ="Launching multi-threaded batch analysis\n\n"; UpdateOutput(strong); if(s_bCurrentFoil) { m_FoilList.clear(); m_FoilList.append(MainFrame::curFoil()->m_FoilName); } if(!m_bFromList) nRe = (int)qAbs((m_ReMax-m_ReMin)/m_ReInc); else nRe = m_NRe-1; // QThreadPool::globalInstance()->setExpiryTimeout(60000);//ms //build an array of all analysis pairs to run m_nAnalysis = 0; Analysis *pAnalysis=NULL; for(int i=0; ipFoil = pFoil; if(!m_bFromList) pPolar = CreatePolar(pFoil, m_ReMin + iRe *m_ReInc, m_Mach, m_NCrit); else pPolar = CreatePolar(pFoil, m_ReList[iRe], m_MachList[iRe], m_NCritList[iRe]); pAnalysis->pPolar=pPolar; m_nAnalysis++; } } } strong = QString("Found %1 foil/polar pairs to analyze\n").arg(m_nAnalysis); UpdateOutput(strong); //Start as many threads as the system will support m_nThreads = QThread::idealThreadCount(); m_pXFoilTask = new XFoilTask[m_nThreads]; XFoilTask::s_bAutoInitBL= pXDirect->m_bAutoInitBL; XFoilTask::s_pBatchThreadDlg = this; XFoilTask::s_bCancel = false; strong = QString("Using %1 threads\n\n").arg(m_nThreads); UpdateOutput(strong); for(int it=0; itprocessEvents(); if(m_pXFoilTask) { QString str = " ...Finished "+m_pXFoilTask[event->timerId()].m_pFoil->m_FoilName+" / " +m_pXFoilTask[event->timerId()].m_pPolar->m_PlrName+"\n"; UpdateOutput(str); m_pXFoilTask[event->timerId()].m_bIsFinished = true; } //time to launch another analysis, if any is left QString strong; QXDirect *pXDirect = (QXDirect*)s_pXDirect; if(m_pctrlUpdatePolarView->isChecked()) { pXDirect->CreatePolarCurves(); pXDirect->UpdateView(); } if(m_AnalysisPair.size()<=0 || m_bCancel) { //nothing left to launch... just wait and enjoy the show bool bAllFinished = true; for (int it=0; itwaitForDone(); if(m_pXFoilTask) { delete [] m_pXFoilTask; m_pXFoilTask = NULL; if(m_bCancel) strong = "\n_____Analysis cancelled_____\n"; else strong = "\n_____Analysis completed_____\n"; UpdateOutput(strong); CleanUp(); if(pXDirect->m_bPolarView) { pXDirect->CreatePolarCurves(); pXDirect->UpdateView(); } } } } else StartThread(); // analyze a new pair } /** * Starts an individual thread */ void BatchThreadDlg::StartThread() { Analysis *pAnalysis; QString strong; // browse through the array until we find an available thread if(QThreadPool::globalInstance()->activeThreadCount()pFoil, pAnalysis->pPolar); //launch it strong = "Starting "+pAnalysis->pFoil->m_FoilName+" / "+pAnalysis->pPolar->m_PlrName+"\n"; UpdateOutput(strong); QThreadPool::globalInstance()->start(m_pXFoilTask+it); //remove it from the todo array m_AnalysisPair.removeLast(); break; } } } } void BatchThreadDlg::showEvent(QShowEvent *event) { move(s_Position); } void BatchThreadDlg::hideEvent(QHideEvent *event) { s_Position = pos(); } xflr5-6.09-06/src/xdirect/XDirect.h000644 001750 000144 00000036022 12247174410 020237 0ustar00techwinderusers000000 000000 /**************************************************************************** QXDirect Class Copyright (C) 2008-2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file * * This file implements the QXDirect class used to manage direct Foil analysis. * */ #ifndef QXDIRECT_H #define QXDIRECT_H #include #include #include #include #include #include #include #include "../misc/LineBtn.h" #include "../misc/LineCbBox.h" #include "../misc/LineDelegate.h" #include "../misc/DoubleEdit.h" #include "../objects/Polar.h" #include "../objects/Foil.h" #include "../objects/OpPoint.h" #include "../graph/QGraph.h" #include "XFoil.h" #define MAXPOLARGRAPHS 5 /** * @class QXDirect * @brief This class is the general interface for Foil direct Analysis. * This is the handling class for the QXDirect right toolbar. * It provides the methods to modify the foil geometry, define the Polar analysis, perform the analysis, and post-process the results. * One of the very first class of this project. */ class QXDirect : public QWidget { friend class MainFrame; friend class TwoDWidget; friend class XFoilAnalysisDlg; friend class BatchDlg; friend class BatchThreadDlg; friend class FoilPolarDlg; friend class EditPlrDlg; friend class XDirectStyleDlg; friend class DisplaySettingsDlg; Q_OBJECT public: QXDirect(QWidget *parent = NULL); ~QXDirect(); public slots: void UpdateView(); private slots: void OnXFoilAdvanced(); void OnCouplePolarGraphs(); void OnAllPolarGraphs(); void OnSinglePolarGraph(); void OnAllPolarGraphsSetting(); void OnCpGraphSettings(); void OnPolarFilter(); void OnInputChanged(); void OnAnalyze(); void OnAnimate(bool bChecked); void OnAnimateSpeed(int val); void OnBatchAnalysis(); void OnMultiThreadedBatchAnalysis(); void OnCpi(); void OnCurOppOnly(); void OnCurveStyle(int index); void OnCurveWidth(int index); void OnCurveColor(); void OnDeleteCurFoil(); void OnDelCurOpp(); void OnDeleteCurPolar(); void OnDeleteFoilPolars(); void OnEditCurPolar(); void OnExportCurFoil(); void OnExportCurOpp(); void OnExportPolarOpps() ; void OnExportCurPolar(); void OnExportAllPolars(); void OnHideAllOpps(); void OnHideAllPolars(); void OnHideFoilPolars(); void OnImportJavaFoilPolar(); void OnImportXFoilPolar(); void OnInitBL(); void OnOpPoints(); void OnPolars(); void OnResetAllPolarGraphsScales(); void OnResetFoilScale(); void OnResetXFoil(); void OnResetCurPolar(); void OnSavePolars(); void OnSequence(); void OnShowFoilPolarsOnly(); void OnShowFoilPolars(); void OnShowBL(); void OnShowCurve(); void OnShowNeutralLine(); void OnShowCurvePoints(); void OnShowPanels(); void OnShowAllOpps(); void OnShowAllPolars(); void OnShowPressure(); void OnDefinePolar(); void OnSpec(); void OnStoreOpp(); void OnViscous(); void OnXDirectStyle(); void OnGraphSettings(); void OnShowPolarOpps(); void OnHidePolarOpps(); void OnDeletePolarOpps(); void OnShowFoilOpps(); void OnHideFoilOpps(); void OnDeleteFoilOpps(); void OnDerotateFoil(); void OnNormalizeFoil(); void OnCadd(); void OnRefinePanelsGlobally(); void OnFoilCoordinates(); void OnFoilGeom(); void OnResetGraphLegend(); void OnSetTEGap(); void OnSetLERadius(); void OnSetFlap(); void OnInterpolateFoils(); void OnNacaFoils(); void OnManageFoils(); void OnRenamePolar(); void OnAnimateSingle(); void OnHighlightOpp(); void OnQGraph(); void OnCpGraph(); void OnExportCurXFoilResults(); void OnCtPlot(); void OnDbPlot(); void OnDtPlot(); void OnRtLPlot(); void OnRtPlot(); void OnNPlot(); void OnCdPlot(); void OnCfPlot(); void OnUePlot(); void OnHPlot(); void OnOpPointProps(); void OnPolarProps(); void OnRenameFoil(); protected: void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void wheelEvent (QWheelEvent *event); void mouseDoubleClickEvent ( QMouseEvent * event ); void AddOpData(OpPoint *pNewPoint); void SetControls(); void Connect(); void CreateOppCurves(OpPoint *pOpp= NULL); void CreatePolarCurves(); void DeleteFoil(bool bAsk); void DeleteOpPoint(bool bCurrent); void PaintPolarLegend(QPoint place, int bottom,QPainter &painter); void FillComboBoxes(bool bEnable = true); void FillPolarCurve(Curve *pCurve, Polar *pPolar, int XVar, int YVar); void FillOppCurve(OpPoint *pOpp, Graph *pGraph, Curve *pCurve, bool bInviscid=false); void InsertOpPoint(OpPoint *pNewPoint); void LoadSettings(QSettings *pSettings); void PaintBL(QPainter &painter, OpPoint* pOpPoint, double scale); void PaintPressure(QPainter &painter, OpPoint* pOpPoint, double scale); void PaintOpPoint(QPainter &painter); void PaintSingleGraph(QPainter &painter); void PaintCoupleGraphs(QPainter &painter); void PaintPolarGraphs(QPainter &painter); void PaintView(QPainter &painter); void ReadParams(); void SaveSettings(QSettings *pSettings); void SetBufferFoil(); void SetCurveParams(); void SetFoilScale(); void SetFoilScale(QRect CltRect); void SetHingeMoments(OpPoint *pOpPoint); void SetOpPointSequence(); void SetAnalysisParams(); void SetGraphTitles(Graph* pGraph, int iX, int iY); void SetGraphTitles(Graph* pGraph); void SetPolarLegendPos(); void SetupLayout(); void StopAnimate(); void UpdateCurveStyle(); void * GetVariable(Polar *pPolar, int iVar); OpPoint* GetOpPoint(double Alpha); QGraph* GetGraph(QPoint &pt); Foil* SetFoil(Foil* pFoil=NULL); Foil* SetFoil(QString FoilName); Polar *SetPolar(Polar *pPolar=NULL); Polar *SetPolar(QString PlrName); OpPoint *SetOpp(double Alpha=-123456789.0); OpPoint* AddOpPoint(Polar *pPolar = NULL, bool bStoreOpp=false); private: QStackedWidget *m_pctrlMiddleControls; QTimer *m_pAnimateTimer; QLabel *m_pctrlUnit1, *m_pctrlUnit2, *m_pctrlUnit3; QRadioButton *m_pctrlSpec1; QRadioButton *m_pctrlSpec2; QRadioButton *m_pctrlSpec3; QCheckBox *m_pctrlSequence; DoubleEdit *m_pctrlAlphaMin ; DoubleEdit *m_pctrlAlphaMax ; DoubleEdit *m_pctrlAlphaDelta; QCheckBox *m_pctrlViscous ; QCheckBox *m_pctrlInitBL; QCheckBox *m_pctrlStoreOpp; QPushButton *m_pctrlAnalyze; QCheckBox *m_pctrlShowBL, *m_pctrlShowPressure; QCheckBox* m_pctrlAnimate; QSlider* m_pctrlAnimateSpeed ; QLabel *m_pctrlPolarProps; QCheckBox *m_pctrlShowCurve; QCheckBox *m_pctrlShowPoints; LineCbBox *m_pctrlCurveStyle; LineCbBox *m_pctrlCurveWidth; LineBtn *m_pctrlCurveColor; LineDelegate *m_pStyleDelegate, *m_pWidthDelegate; bool m_bAlpha; /**< true if performing an analysis based on aoa, false if based on Cl */ bool m_bStoreOpp; /**< true if operating points should be stored after an analysis */ bool m_bViscous; /**< true if performing a viscous calculation, false if inviscid */ bool m_bInitBL; /**< true if the boundary layer should be initialized for the next xfoil calculation */ bool m_bBL; /**< true if the Boundary layer shoud be displayed */ bool m_bPressure; /**< true if the pressure distirbution should be displayed */ bool m_bPolarView; /**< true if the polar view is selected, false if the operating point view is selected */ bool m_bShowUserGraph; /**< true if the 5th polar graph should be displayed */ bool m_bAnimate; /**< true if a result animation is underway */ bool m_bAnimatePlus; /**< true if the animation is going from lower to higher alpha, false if decreasing */ bool m_bShowPanels; /**< true if the panels should be displayed on the foil surface */ bool m_bType1; /**< true if the type 1 polars are to be displayed in the graphs */ bool m_bType2; /**< true if the type 2 polars are to be displayed in the graphs */ bool m_bType3; /**< true if the type 3 polars are to be displayed in the graphs */ bool m_bType4; /**< true if the type 4 polars are to be displayed in the graphs */ bool m_bAutoInitBL; /**< true if the BL initialization is left to the code's decision */ bool m_bTrans; /**< true if the user is dragging a view */ bool m_bTransGraph; /**< true if the user is dragging a graph */ bool m_bFromList; /**< true if the batch analysis is based on a list of Re values */ bool m_bFromZero; /**< true if the batch analysis should start from Alpha=0 */ bool m_bShowTextOutput; /**< true if the batch analysis should display text result output */ bool m_bNeutralLine; /**< true if the neutral line should be displayed */ bool m_bCurOppOnly; /**< true if only the current operating point should be displayed */ bool m_bShowInviscid; /**< true if the inviscid results should be displayed */ bool m_bCpGraph; /**< true if the Cp graph should be displayed */ bool m_bSequence; /**< true if a sequential analysis is to be performed */ bool m_bXPressed; /**< true if the 'X' key is pressed */ bool m_bYPressed; /**< true if the 'Y' key is pressed */ bool m_bHighlightOpp; /**< true if the active operating point should be highlighted on the curves of the polar graphs */ int m_posAnimate; /**< the current aoa in the animation */ int m_XFoilVar; /**< defines the variable for current XFoil results */ int m_IterLim; /**< max iteratio limit for XFoil */ int m_iPlrGraph; /**< defines whch polar graph is selected if m_iPlrView=1 */ enumPolarGraphView m_iPlrView; /**< defines the number of graphs to be displayed in the polar view */ int m_FoilYPos; /**< y position for the foil display, in pixels from the bottom of the screen */ double m_fFoilScale; /**< the scale for foil display*/ double m_ReList[30]; /**< the user-defined list of Re numbers, used for batch analysis */ double m_MachList[30]; /**< the user-defined list of Mach numbers, used for batch analysis */ double m_NCritList[30]; /**< the user-defined list of NCrit numbers, used for batch analysis */ int m_NRe; /**< the number of Re values in the ReList */ double m_Alpha; /**< the min value of the aoa for a sequential analysis of Type 1, 2, or 3*/ double m_AlphaMax; /**< the max value of the aoa for a sequential analysis of Type 1, 2, or 3*/ double m_AlphaDelta; /**< the increment value of the aoa for a sequential analysis of Type 1, 2, or 3*/ double m_Cl; /**< the min value of the lift coefficient for a sequential analysis of Type 1, 2, or 3*/ double m_ClMax; /**< the max value of the aoa for a sequential analysis of Type 1, 2, or 3*/ double m_ClDelta; /**< the increment value of the aoa for a sequential analysis of Type 1, 2, or 3*/ double m_Reynolds; /**< the min value of the Reynolds number for a sequential analysis of Type 4*/ double m_ReynoldsMax; /**< the max value of the Reynolds number for a sequential analysis of Type 4*/ double m_ReynoldsDelta; /**< the increment value of the Reynolds number for a sequential analysis of Type 4*/ double m_Mach; /**< Stores the Mach number defined in the last Polar creation */ double m_ASpec; /**< Stores the aoa defined in the last Type 4 Polar creation */ double m_NCrit; /**< Stores the NCrit number defined in the last Polar creation */ double m_XTopTr; /**< Stores the position of the top transition point defined in the last Polar creation */ double m_XBotTr; /**< Stores the position of the bottom transition point defined in the last Polar creation */ enumPolarType m_PolarType; /**< Stores the type of the last polar which has been created. */ Foil m_BufferFoil; /**< used for screen drawing and temporary geometric mods */ Polar* m_pCurPolar; /**< pointer to the currently selected foil polar */ OpPoint* m_pCurOpp; /**< pointer to the currently selected foil operating point */ QList *m_poaFoil; /**< pointer to the foil object array */ QList *m_poaPolar; /**< pointer to the polar object array */ QList *m_poaOpp; /**< pointer to the OpPoint object array */ QGraph* m_pCpGraph; /**< a pointer to the Cp graph for the OpPoint view */ QGraph m_PlrGraph[MAXPOLARGRAPHS]; /**< the 5 Polar graphs */ QGraph* m_pCurGraph; /**< a pointer to the graph over which the mouse is hovering */ QFile m_XFile; /**< The instance of the log file to which the text output of the analysis is directed */ static void *s_pMainFrame; /**< a static pointer to the instance of the application's MainFrame object */ static void *s_p2DWidget; /**< a static pointer to the instance of the application's central widget used for 2D drawings */ QColor m_crBLColor; /**< the color used to draw the boundary layer */ QColor m_crPressureColor; /**< the color used to draw the pressure arrows */ QColor m_crNeutralColor; /**< the color used to draw the neutral line */ QColor m_CurveColor; /**< the color displayed in the comboboxes for the selection of curve styles */ int m_iBLStyle; /**< the index of the style used to draw the boundary layer */ int m_iBLWidth; /**< the width of the line used to draw the boundary layer */ int m_iPressureStyle; /**< the index of the style used to draw the pressure arrows*/ int m_iPressureWidth; /**< the width of the line used to draw the pressure arrows */ int m_iNeutralStyle; /**< the index of the style used to draw the neutral line */ int m_iNeutralWidth; /**< the width of the line used to draw the neutral line */ int m_CurveStyle; /**< the index of the style of the lines displayed in the comboboxes for the selection of curve styles*/ int m_CurveWidth; /**< the width of the lines displayed in the comboboxes for the selection of curve styles*/ QRect m_rCltRect; /**< the client rectangle of the central TwoDWidget */ QPoint m_PointDown; /**< the client coordinated of the last mouse left-click */ QPoint m_FoilOffset; /**< the offset position for the foil display in the client area */ QPoint m_PolarLegendOffset; /**< the offset position for the legend display in the client area */ XFoil *m_pXFoil; /**< a pointer to the unique instance of the XFoil object */ }; #endif // QXDIRECT_H xflr5-6.09-06/src/xdirect/TwoDPanelDlg.cpp000644 001750 000144 00000017117 12247261740 021523 0ustar00techwinderusers000000 000000 /**************************************************************************** TwoDPanelDlg Class Copyright (C) 2008-2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include "TwoDPanelDlg.h" #include "../params.h" #include "XFoil.h" #include "XDirect.h" #include "../design/AFoil.h" void *TwoDPanelDlg::s_pXFoil; TwoDPanelDlg::TwoDPanelDlg(QWidget *pParent) : QDialog(pParent) { SetupLayout(); m_pXDirect = NULL; m_pBufferFoil = NULL; m_bApplied = false; } void TwoDPanelDlg::SetupLayout() { setWindowTitle(tr("Global Panel Refinement")); QGridLayout *InputDataLayout = new QGridLayout; { QLabel *l1 = new QLabel(tr("Number of Panels")); QLabel *l2 = new QLabel(tr("Panel Bunching Parameter")); QLabel *l3 = new QLabel(tr("TE/LE Panel Density Ratio")); QLabel *l4 = new QLabel(tr("Refined area/LE Panel Density Ratio")); QLabel *l5 = new QLabel(tr("Top Side Refined Area x/c limits")); QLabel *l6 = new QLabel(tr("Bottom Side Refined Area x/c limits")); InputDataLayout->addWidget(l1,1,1); InputDataLayout->addWidget(l2,2,1); InputDataLayout->addWidget(l3,3,1); InputDataLayout->addWidget(l4,4,1); InputDataLayout->addWidget(l5,5,1); InputDataLayout->addWidget(l6,6,1); m_pctrlNPanels = new IntEdit(100, this); m_pctrlNPanels->SetMax(IQX); m_pctrlCVpar = new DoubleEdit; m_pctrlCTErat = new DoubleEdit; m_pctrlCTRrat = new DoubleEdit; m_pctrlXsRef1 = new DoubleEdit; m_pctrlXsRef2 = new DoubleEdit; m_pctrlXpRef1 = new DoubleEdit; m_pctrlXpRef2 = new DoubleEdit; InputDataLayout->addWidget(m_pctrlNPanels, 1, 2); InputDataLayout->addWidget(m_pctrlCVpar, 2, 2); InputDataLayout->addWidget(m_pctrlCTErat, 3, 2); InputDataLayout->addWidget(m_pctrlCTRrat, 4, 2); InputDataLayout->addWidget(m_pctrlXsRef1, 5, 2); InputDataLayout->addWidget(m_pctrlXsRef2, 5, 3); InputDataLayout->addWidget(m_pctrlXpRef1, 6, 2); InputDataLayout->addWidget(m_pctrlXpRef2, 6, 3); connect(m_pctrlNPanels, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlCVpar, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlCTErat, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlCTRrat, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlXsRef1, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlXsRef2, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlXpRef1, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlXpRef2, SIGNAL(editingFinished()), this, SLOT(OnChanged())); } QHBoxLayout *CommandButtonsLayout = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); ApplyButton = new QPushButton(tr("Apply")); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(ApplyButton); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(OKButton); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(CancelButton); CommandButtonsLayout->addStretch(1); } QVBoxLayout *mainLayout = new QVBoxLayout; { mainLayout->addStretch(1); mainLayout->addLayout(InputDataLayout); mainLayout->addStretch(1); mainLayout->addLayout(CommandButtonsLayout); mainLayout->addStretch(1); setLayout(mainLayout); } connect(ApplyButton, SIGNAL(clicked()),this, SLOT(OnApply())); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); setMinimumHeight(250); } void TwoDPanelDlg::InitDialog() { XFoil *pXFoil =(XFoil*)s_pXFoil; Foil *pMemFoil = (Foil *)m_pMemFoil; //memorize initial values // npan = pXFoil->n; npan = pMemFoil->nb; cvpar = pXFoil->cvpar; cterat = pXFoil->cterat; ctrrat = pXFoil->ctrrat; xsref1 = pXFoil->xsref1; xsref2 = pXFoil->xsref2; xpref1 = pXFoil->xpref1; xpref2 = pXFoil->xpref2; m_pctrlNPanels->SetValue(npan); m_pctrlCVpar->SetValue(cvpar); m_pctrlCTErat->SetValue(cterat); m_pctrlCTRrat->SetValue(ctrrat); m_pctrlXsRef1->SetValue(xsref1); m_pctrlXsRef2->SetValue(xsref2); m_pctrlXpRef1->SetValue(xpref1); m_pctrlXpRef2->SetValue(xpref2); m_pctrlNPanels->setFocus(); } void TwoDPanelDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Escape: { done(0); return; } case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OnApply(); OKButton->setFocus(); m_bApplied = true; } else { event->ignore(); } break; } default: event->ignore(); break; } } void TwoDPanelDlg::OnChanged() { m_bApplied = false; OnApply(); } void TwoDPanelDlg::OnApply() { if(m_bApplied) return; //reset everything and retry XFoil *pXFoil = (XFoil*)s_pXFoil; QXDirect *pXDirect = (QXDirect*)m_pXDirect; QAFoil *pAFoil = (QAFoil*)m_pAFoil; Foil *pMemFoil = (Foil*)m_pMemFoil; Foil *pBufferFoil = (Foil*)m_pBufferFoil; for (int i=0; i< pMemFoil->nb; i++) { pXFoil->xb[i+1] = pMemFoil->xb[i] ; pXFoil->yb[i+1] = pMemFoil->yb[i]; } pXFoil->nb = pMemFoil->nb; pXFoil->lflap = false; pXFoil->lbflap = false; if(pXFoil->Preprocess()) { pXFoil->CheckAngles(); } else { QMessageBox::information(this, tr("Warning"), tr("Unrecognized foil format")); return; } ReadParams(); pXFoil->pangen(); if(pXFoil->n>IQX) { QString strange = QString(tr("The total number of panels cannot exceed %1")).arg(IQX); QMessageBox::information(this, tr("Warning"), strange); //reset everything and retry for (int i=0; i< pMemFoil->nb; i++) { pXFoil->x[i+1] = pMemFoil->xb[i] ; pXFoil->y[i+1] = pMemFoil->yb[i]; } pXFoil->n = pMemFoil->nb; } else { for (int j=0; j< pXFoil->n; j++) { pBufferFoil->xb[j] = pXFoil->x[j+1]; pBufferFoil->yb[j] = pXFoil->y[j+1]; } pBufferFoil->nb = pXFoil->n; // pXFoil->SetFoilFlap(pBufferFoil); pBufferFoil->InitFoil(); pBufferFoil->SetFlap(); } m_bApplied = true; m_bModified = true; if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } void TwoDPanelDlg::OnOK() { if(!m_bModified) { done(0); } else { OnApply(); done(1); } } void TwoDPanelDlg::ReadParams() { XFoil *pXFoil = (XFoil*)s_pXFoil; pXFoil->npan = m_pctrlNPanels->Value(); pXFoil->cvpar = m_pctrlCVpar->Value(); pXFoil->cterat = m_pctrlCTErat->Value(); pXFoil->ctrrat = m_pctrlCTRrat->Value(); pXFoil->xsref1 = m_pctrlXsRef1->Value(); pXFoil->xsref2 = m_pctrlXsRef2->Value(); pXFoil->xpref1 = m_pctrlXpRef1->Value(); pXFoil->xpref2 = m_pctrlXpRef2->Value(); } xflr5-6.09-06/src/xdirect/NacaFoilDlg.cpp000644 001750 000144 00000012466 12247261740 021344 0ustar00techwinderusers000000 000000 /**************************************************************************** Naca Foil Dlg Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "NacaFoilDlg.h" #include "XDirect.h" #include "../design/AFoil.h" #include void *NacaFoilDlg::s_pXFoil; int NacaFoilDlg::s_Digits = 0; int NacaFoilDlg::s_Panels = 100; NacaFoilDlg::NacaFoilDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("NACA Foils")); m_pAFoil = NULL; m_pXDirect = NULL; m_bGenerated = false; m_pBufferFoil = NULL; SetupLayout(); m_pctrlNumber->SetValue(s_Digits); m_pctrlPanels->SetValue(s_Panels); } void NacaFoilDlg::SetupLayout() { QGridLayout *MainGridLayout = new QGridLayout; { QLabel *NacaNumber = new QLabel(tr("4 or 5 digits")); QLabel *PanelNumber = new QLabel(tr("Number of Panels")); m_pctrlNumber = new IntEdit(0, this); m_pctrlPanels = new IntEdit(100, this); m_pctrlPanels->SetMax(IQX); m_pctrlMessage = new QLabel(); m_pctrlMessage->setMinimumWidth(120); m_pctrlNumber->setAlignment(Qt::AlignRight); m_pctrlPanels->setAlignment(Qt::AlignRight); MainGridLayout->addWidget(NacaNumber, 1,1, 1,1, Qt::AlignRight); MainGridLayout->addWidget(m_pctrlNumber, 1,2, 1,1, Qt::AlignRight); MainGridLayout->addWidget(m_pctrlMessage, 2,1, 1,2, Qt::AlignRight); MainGridLayout->addWidget(PanelNumber, 3,1, 1,1, Qt::AlignRight); MainGridLayout->addWidget(m_pctrlPanels, 3,2, 1,1, Qt::AlignRight); } QHBoxLayout *CommandButtonsLayout = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); OKButton->setAutoDefault(false); CancelButton = new QPushButton(tr("Cancel")); CancelButton->setAutoDefault(false); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(OKButton); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(CancelButton); CommandButtonsLayout->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } QVBoxLayout *mainLayout = new QVBoxLayout; { mainLayout->addLayout(MainGridLayout); mainLayout->addStretch(1); mainLayout->addSpacing(30); mainLayout->addLayout(CommandButtonsLayout); } setLayout(mainLayout); connect(m_pctrlNumber, SIGNAL(editingFinished()), this, SLOT(EditingFinished())); connect(m_pctrlPanels, SIGNAL(editingFinished()), this, SLOT(EditingFinished())); } void NacaFoilDlg::EditingFinished() { s_Digits = locale().toInt(m_pctrlNumber->text().trimmed()); s_Panels = m_pctrlPanels->Value(); GenerateFoil(); OKButton->setFocus(); } void NacaFoilDlg::GenerateFoil() { int itype; QAFoil *pAFoil = (QAFoil*)m_pAFoil; QXDirect *pXDirect = (QXDirect*)m_pXDirect; XFoil *pXFoil = (XFoil*)s_pXFoil; pXFoil->lflap = false; pXFoil->lbflap = false; if(s_Digits<=25099) itype = 5; if(s_Digits<=9999 ) itype = 4; if(itype==4) pXFoil->naca4(s_Digits, (int)(s_Panels/2)); else if(itype==5) { int three = s_Digits/100; if(three!=210 && three !=220 && three !=230 && three !=240 && three !=250) { m_pctrlNumber->selectAll(); m_pctrlMessage->setText(tr("Illegal NACA Number")); m_bGenerated = false; return; } if(!pXFoil->naca5(s_Digits, s_Panels)) { m_bGenerated = false; m_pctrlMessage->setText(tr("Illegal NACA Number")); return; } } else { m_pctrlNumber->selectAll(); m_pctrlMessage->setText(tr("Illegal NACA Number")); m_bGenerated = false; return; } m_pctrlMessage->setText(" "); for (int j=0; j< pXFoil->nb; j++) { m_pBufferFoil->xb[j] = pXFoil->xb[j+1]; m_pBufferFoil->yb[j] = pXFoil->yb[j+1]; m_pBufferFoil->x[j] = pXFoil->xb[j+1]; m_pBufferFoil->y[j] = pXFoil->yb[j+1]; } m_pBufferFoil->nb = pXFoil->nb; m_pBufferFoil->n = pXFoil->nb; m_pBufferFoil->InitFoil(); if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); m_bGenerated = true; } void NacaFoilDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App // Generate the foil instead switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { GenerateFoil(); if(m_bGenerated) OKButton->setFocus(); else { m_pctrlNumber->selectAll(); } } else if (OKButton->hasFocus()) { OnOK(); } return; } case Qt::Key_Escape: { reject(); return; } } } void NacaFoilDlg::OnOK() { GenerateFoil(); accept(); } xflr5-6.09-06/src/xdirect/CAddDlg.h000644 001750 000144 00000004432 12247174405 020123 0ustar00techwinderusers000000 000000 /**************************************************************************** Corner Add class Copyright (C) 2004-2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file This file implements the class used to refine locally the points on a foil */ #ifndef CADDDLG_H #define CADDDLG_H #include #include #include #include "../objects/Foil.h" #include "../misc/DoubleEdit.h" /** * @class CAddDlg * @brief The class which interfaces with the cadd method implemented in XFoil. * * This class is used to add panels locally on a foil surface, in the areas of high surface curvature. * Refer to Xfoil documentation for more documentation * One of the early classes of this project. */ class CAddDlg : public QDialog { Q_OBJECT friend class MainFrame; friend class QXDirect; friend class QAFoil; public: CAddDlg(QWidget *pParent = NULL); void InitDialog(); void SetupLayout(); private: void keyPressEvent(QKeyEvent *event); private slots: void OnApply(); void OnUniform(); private: static void* s_pXFoil; QPushButton *ApplyButton, *OKButton, *CancelButton; QLabel *m_pctrlAtPanel; QLabel *m_pctrlTotal; QLabel *m_pctrlAdded; QLabel *m_pctrlMaxAngle; QRadioButton *m_pctrlrb1; QRadioButton *m_pctrlrb2; DoubleEdit *m_pctrlTo; DoubleEdit *m_pctrlFrom; DoubleEdit *m_pctrlAngTol; Foil* m_pMemFoil; Foil* m_pBufferFoil; void* m_pXDirect; void* m_pAFoil; double atol; int m_iSplineType; }; #endif // CADDDLG_H xflr5-6.09-06/src/xdirect/FlapDlg.h000644 001750 000144 00000004267 12247174405 020220 0ustar00techwinderusers000000 000000 /**************************************************************************** FlapDlg class Copyright (C) 2004-2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef FLAPDLG_H #define FLAPDLG_H #include #include #include #include "../objects/Foil.h" #include "../misc/DoubleEdit.h" class FlapDlg : public QDialog { Q_OBJECT public: FlapDlg(QWidget *pParent=NULL); friend class QAFoil; friend class QXDirect; private: void EnableTEFlap(bool bEnable); void EnableLEFlap(bool bEnable); void ReadParams(); void SetupLayout(); DoubleEdit *m_pctrlLEYHinge; DoubleEdit *m_pctrlLEXHinge; DoubleEdit *m_pctrlLEFlapAngle; DoubleEdit *m_pctrlTEYHinge; DoubleEdit *m_pctrlTEXHinge; DoubleEdit *m_pctrlTEFlapAngle; QCheckBox *m_pctrlLEFlapCheck; QCheckBox *m_pctrlTEFlapCheck; QPushButton *OKButton, *CancelButton, *ApplyButton; protected: void keyPressEvent(QKeyEvent *event); void InitDialog(); private slots: void OnApply(); void OnLEFlapCheck(int state); void OnTEFlapCheck(int state); void OnChanged(); virtual void OnOK(); private: bool m_bTEFlap; bool m_bLEFlap; bool m_bApplied; bool m_bModified; double m_LEXHinge, m_LEYHinge, m_LEFlapAngle; double m_TEXHinge, m_TEYHinge, m_TEFlapAngle; Foil *m_pMemFoil, *m_pBufferFoil; void *m_pXFoil; void *m_pXDirect; void *m_pAFoil; }; #endif // FLAPDLG_H xflr5-6.09-06/src/xdirect/EditPlrDlg.h000644 001750 000144 00000003600 12247174405 020667 0ustar00techwinderusers000000 000000 /**************************************************************************** EditPlrDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef EDITPLRDLG_H #define EDITPLRDLG_H #include #include //#include #include #include #include "../misc/FloatEditDelegate.h" #include "../objects/Polar.h" class EditPlrDlg : public QDialog { Q_OBJECT friend class QXDirect; friend class QMiarex; public: EditPlrDlg(QWidget *pParent=NULL); void InitDialog(); private slots: void OnDeletePoint(); void OnDeleteAllPoints(); private: void SetupLayout(); void FillTable(); void keyPressEvent(QKeyEvent *event); void resizeEvent(QResizeEvent*event); void closeEvent(QCloseEvent*event); private: QPushButton *m_pctrlDeletePoint, *m_pctrlDeleteAllPoints; QPushButton *OKButton, *CancelButton; Polar *m_pPolar; QTableView *m_pctrlPointTable; QStandardItemModel *m_pPointModel; FloatEditDelegate *m_pFloatDelegate; void *m_pXDirect; static QPoint s_WindowPos; static QSize s_WindowSize; static bool s_bWindowMaximized; }; #endif // EDITPLRDLG_H xflr5-6.09-06/src/xdirect/XDirect.cpp000644 001750 000144 00000551623 12247263457 020615 0ustar00techwinderusers000000 000000 /**************************************************************************** QXDirect Class Copyright (C) 2008-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "../globals.h" #include "../mainframe.h" #include "XDirect.h" #include "../graph/GraphDlg.h" #include "../misc/PolarFilterDlg.h" #include "../misc/ObjectPropsDlg.h" #include "../misc/RenameDlg.h" #include "EditPlrDlg.h" #include "XFoilAnalysisDlg.h" #include "XFoilAdvancedDlg.h" #include "FoilPolarDlg.h" #include "BatchThreadDlg.h" #include "BatchDlg.h" #include "TwoDPanelDlg.h" #include "InterpolateFoilsDlg.h" #include "NacaFoilDlg.h" #include "ManageFoilsDlg.h" #include "FoilCoordDlg.h" #include "FoilGeomDlg.h" #include "TEGapDlg.h" #include "LEDlg.h" #include "FlapDlg.h" #include "CAddDlg.h" #include "XDirectStyleDlg.h" void *QXDirect::s_pMainFrame; void *QXDirect::s_p2DWidget; /** *The public constructor. */ QXDirect::QXDirect(QWidget *parent) : QWidget(parent) { SetupLayout(); m_pXFoil = NULL; m_pXFoil = new XFoil(); m_CurveStyle = 0; m_CurveWidth = 1; m_CurveColor = QColor(0,0,0); m_pAnimateTimer = new QTimer(this); m_posAnimate = 0; // no animation to start with Connect(); FillComboBoxes(false); m_bAnimate = false; m_bAnimatePlus = false; m_bAutoInitBL = true; m_bCpGraph = true; m_bTransGraph = false; m_bShowPanels = false; m_bShowUserGraph = true; m_bSequence = false; m_bHighlightOpp = false; m_bXPressed = m_bYPressed = false; m_PolarType = FIXEDSPEEDPOLAR; m_bTrans = false; m_bType1 = true; m_bType2 = true; m_bType3 = true; m_bType4 = true; m_bPressure = false; m_bBL = false; m_bFromList = false; m_bFromZero = false; m_bShowTextOutput = true; m_bNeutralLine = true; m_bShowInviscid = false; m_bAlpha = true; m_bInitBL = true; m_bStoreOpp = true; m_bViscous = true; m_bCurOppOnly = true; m_iNeutralStyle = 2; m_iNeutralWidth = 1; m_crNeutralColor = QColor(200,200,255); m_crBLColor = QColor(200,70,70); m_iBLStyle = 1; m_iBLWidth = 1; m_crPressureColor= QColor(0,255,0); m_iPressureStyle = 0; m_iPressureWidth = 1; m_IterLim = 100; m_bPolarView = true; m_iPlrGraph = 0; m_iPlrView = ALLPOLARGRAPHS; m_XFoilVar = 0; m_FoilYPos = 150; m_PointDown.setX(0); m_PointDown.setY(0); m_posAnimate = 0; m_pCpGraph = NULL; m_pCurGraph = NULL; m_pCurPolar = NULL; m_pCurOpp = NULL; BatchDlg::s_bStoreOpp = false; m_NCrit = 9.0; m_XTopTr = 1.0; m_XBotTr = 1.0; m_Mach = 0.0; m_Alpha = 0.0; m_AlphaMax = 1.0; m_AlphaDelta = 0.5; m_Cl = 0.0; m_ClMax = 1.0; m_ClDelta = 0.1; m_Reynolds = 100000.0; m_ReynoldsMax = 150000.0; m_ReynoldsDelta = 10000.0; m_ASpec = 0.0; m_pCpGraph = new QGraph(); m_pCpGraph->SetVariables(0,0); m_PlrGraph[0].SetVariables(2,1); m_PlrGraph[1].SetVariables(0,1); m_PlrGraph[2].SetVariables(0,5); m_PlrGraph[3].SetVariables(6,1); m_PlrGraph[4].SetVariables(0,10); m_pCpGraph->SetXTitle(tr("X")); m_pCpGraph->SetYTitle(tr("Cp")); m_pCpGraph->SetInverted(true); m_pCpGraph->SetXMin(0.0); m_pCpGraph->SetXMax(1.0); m_pCpGraph->SetYMin(-0.1); m_pCpGraph->SetYMax(0.1); m_pCpGraph->SetMargin(50); m_pCpGraph->SetBorderColor(QColor(200,200,200)); m_pCpGraph->SetBorder(true); m_pCpGraph->SetBorderStyle(0); m_pCpGraph->SetGraphName(tr("Cp Graph")); m_PlrGraph[0].SetXMin(0.0); m_PlrGraph[0].SetXMax(0.1); m_PlrGraph[0].SetYMin(-0.1); m_PlrGraph[0].SetYMax(0.1); m_PlrGraph[0].SetType(2); m_PlrGraph[0].SetBorderColor(QColor(200,200,200)); m_PlrGraph[0].SetBorder(true); m_PlrGraph[0].SetBorderStyle(0); m_PlrGraph[0].SetBorderWidth(3); m_PlrGraph[0].SetMargin(50); m_PlrGraph[0].SetGraphName(tr("Polar Graph")); m_PlrGraph[2].SetXMin(0.0); m_PlrGraph[2].SetXMax(0.1); m_PlrGraph[2].SetYMin(-0.1); m_PlrGraph[2].SetYMax(0.1); m_PlrGraph[2].SetType(2); m_PlrGraph[2].SetBorderColor(QColor(200,200,200)); m_PlrGraph[2].SetBorder(true); m_PlrGraph[2].SetBorderStyle(0); m_PlrGraph[2].SetBorderWidth(3); m_PlrGraph[2].SetMargin(50); m_PlrGraph[2].SetGraphName(tr("Cm Graph")); m_PlrGraph[1].SetXMin(0.0); m_PlrGraph[1].SetXMax(0.1); m_PlrGraph[1].SetYMin(-0.1); m_PlrGraph[1].SetYMax(0.1); m_PlrGraph[1].SetType(2); m_PlrGraph[1].SetBorderColor(QColor(200,200,200)); m_PlrGraph[1].SetBorder(true); m_PlrGraph[1].SetBorderStyle(0); m_PlrGraph[1].SetBorderWidth(3); m_PlrGraph[1].SetMargin(50); m_PlrGraph[1].SetGraphName(tr("Cz Graph")); m_PlrGraph[3].SetXMin(0.0); m_PlrGraph[3].SetXMax(0.1); m_PlrGraph[3].SetYMin(-0.1); m_PlrGraph[3].SetYMax(0.1); m_PlrGraph[3].SetType(2); m_PlrGraph[3].SetBorderColor(QColor(200,200,200)); m_PlrGraph[3].SetBorder(true); m_PlrGraph[3].SetBorderStyle(0); m_PlrGraph[3].SetBorderWidth(3); m_PlrGraph[3].SetMargin(50); m_PlrGraph[3].SetGraphName(tr("Tr Graph")); m_PlrGraph[4].SetXMin(0.0); m_PlrGraph[4].SetXMax(0.1); m_PlrGraph[4].SetYMin(-0.1); m_PlrGraph[4].SetYMax(0.1); m_PlrGraph[4].SetType(2); m_PlrGraph[4].SetBorderColor(QColor(200,200,200)); m_PlrGraph[4].SetBorder(true); m_PlrGraph[4].SetBorderStyle(0); m_PlrGraph[4].SetBorderWidth(3); m_PlrGraph[4].SetMargin(50); m_PlrGraph[4].SetGraphName(tr("User Graph")); for(int ig=0; ign = m_pXFoil->n; pOpPoint->Cd = m_pXFoil->cd; pOpPoint->Cdp = m_pXFoil->cdp; pOpPoint->Cl = m_pXFoil->cl; pOpPoint->m_XCP = m_pXFoil->xcp; pOpPoint->Cm = m_pXFoil->cm; pOpPoint->Reynolds = m_pXFoil->reinf; pOpPoint->Mach = m_pXFoil->minf; pOpPoint->ACrit = m_pXFoil->acrit; pOpPoint->m_bTEFlap = MainFrame::s_pCurFoil->m_bTEFlap; pOpPoint->m_bLEFlap = MainFrame::s_pCurFoil->m_bLEFlap; pOpPoint->Cpmn = m_pXFoil->cpmn; for (k=0; kn; k++) { // pOpPoint->x[k] = m_pXFoil->x[k+1]; // pOpPoint->y[k] = m_pXFoil->y[k+1]; // pOpPoint->s[k] = m_pXFoil->s[k+1]; pOpPoint->Cpi[k] = m_pXFoil->cpi[k+1]; pOpPoint->Qi[k] = m_pXFoil->qgamm[k+1]; } if(m_pXFoil->lvisc && m_pXFoil->lvconv) { pOpPoint->Xtr1 =m_pXFoil->xoctr[1]; pOpPoint->Xtr2 =m_pXFoil->xoctr[2]; pOpPoint->m_bViscResults = true; pOpPoint->m_bBL = true; for (k=0; kn; k++) { pOpPoint->Cpv[k] = m_pXFoil->cpv[k+1]; pOpPoint->Qv[k] = m_pXFoil->qvis[k+1]; } } else { pOpPoint->m_bViscResults = false; } if(pOpPoint->m_bTEFlap || pOpPoint->m_bLEFlap) { SetHingeMoments(pOpPoint); /* pOpPoint->m_TEHMom = m_pXFoil->hmom; pOpPoint->XForce = m_pXFoil->hfx; pOpPoint->YForce = m_pXFoil->hfy;*/ } if(!m_pXFoil->lvisc || !m_pXFoil->lvconv) return; //---- add boundary layer on both sides of airfoil int nd1=0; int nd2=0; int nd3=0; for (is=1; is<=2; is++) { for ( ibl=2; ibl<=m_pXFoil->iblte[is];ibl++) { i = m_pXFoil->ipan[ibl][is]; pOpPoint->xd1[i] = m_pXFoil->x[i] + m_pXFoil->nx[i]*m_pXFoil->dstr[ibl][is]; pOpPoint->yd1[i] = m_pXFoil->y[i] + m_pXFoil->ny[i]*m_pXFoil->dstr[ibl][is]; nd1++; } } //---- set upper and lower wake dstar fractions based on first wake point is=2; double dstrte = m_pXFoil->dstr[m_pXFoil->iblte[is]+1][is]; double dsf1, dsf2; if(dstrte!=0.0) { dsf1 = (m_pXFoil->dstr[m_pXFoil->iblte[1]][1] + 0.5*m_pXFoil->ante) / dstrte; dsf2 = (m_pXFoil->dstr[m_pXFoil->iblte[2]][2] + 0.5*m_pXFoil->ante) / dstrte; } else { dsf1 = 0.5; dsf2 = 0.5; } //---- plot upper wake displacement surface ibl = m_pXFoil->iblte[1]; i = m_pXFoil->ipan[ibl][1]; pOpPoint->xd2[0] = m_pXFoil->x[i] + m_pXFoil->nx[i]*m_pXFoil->dstr[ibl][1]; pOpPoint->yd2[0] = m_pXFoil->y[i] + m_pXFoil->ny[i]*m_pXFoil->dstr[ibl][1]; nd2++; j= m_pXFoil->ipan[m_pXFoil->iblte[is]+1][is] -1; for (ibl=m_pXFoil->iblte[is]+1; ibl<=m_pXFoil->nbl[is]; ibl++) { i = m_pXFoil->ipan[ibl][is]; pOpPoint->xd2[i-j] = m_pXFoil->x[i] - m_pXFoil->nx[i]*m_pXFoil->dstr[ibl][is]*dsf1; pOpPoint->yd2[i-j] = m_pXFoil->y[i] - m_pXFoil->ny[i]*m_pXFoil->dstr[ibl][is]*dsf1; nd2++; } //---- plot lower wake displacement surface ibl = m_pXFoil->iblte[2]; i = m_pXFoil->ipan[ibl][2]; pOpPoint->xd3[0] = m_pXFoil->x[i] + m_pXFoil->nx[i]*m_pXFoil->dstr[ibl][2]; pOpPoint->yd3[0] = m_pXFoil->y[i] + m_pXFoil->ny[i]*m_pXFoil->dstr[ibl][2]; nd3++; j = m_pXFoil->ipan[m_pXFoil->iblte[is]+1][is] -1; for (ibl=m_pXFoil->iblte[is]+1; ibl<=m_pXFoil->nbl[is]; ibl++) { i = m_pXFoil->ipan[ibl][is]; pOpPoint->xd3[i-j] = m_pXFoil->x[i] + m_pXFoil->nx[i]*m_pXFoil->dstr[ibl][is]*dsf2; pOpPoint->yd3[i-j] = m_pXFoil->y[i] + m_pXFoil->ny[i]*m_pXFoil->dstr[ibl][is]*dsf2; nd3++; } pOpPoint->nd1 = nd1; pOpPoint->nd2 = nd2; pOpPoint->nd3 = nd3; } /** * Creates a new instance of an OpPoint. * Loads the data from the XFoil object in that OpPoint * Adds the data to the active Polar object * @param pPolar a point to the parent Polar object to which the OpPoint should be attached. * @param bStoreOpp true if the OpPoint should be stored * @return a pointer to the OpPoint which has been created, or NULL if it wasn't stored. */ OpPoint* QXDirect::AddOpPoint(Polar *pPolar, bool bStoreOpp) { MainFrame*pMainFrame = (MainFrame*)s_pMainFrame; if(!pPolar) pPolar = m_pCurPolar; OpPoint *pNewPoint = new OpPoint(); if(pNewPoint ==NULL) { return NULL; } else { if(!m_pXFoil->lvconv) { delete pNewPoint; return NULL; } pNewPoint->Alpha = m_pXFoil->alfa * 180/PI; pNewPoint->m_Color = pMainFrame->GetColor(2); pNewPoint->m_strFoilName = MainFrame::s_pCurFoil->m_FoilName; pNewPoint->m_strPlrName = pPolar->m_PlrName; AddOpData(pNewPoint); MainFrame::SetSaveState(false); } if(bStoreOpp) { //insert the OpPoint in the Operating points array InsertOpPoint(pNewPoint); } // Now insert OpPoint in the current CPolar object if(m_pXFoil->lvconv && pPolar) { if(pPolar->m_PolarType==FIXEDLIFTPOLAR || pPolar->m_PolarType==RUBBERCHORDPOLAR) { if(pNewPoint && pNewPoint->Reynolds<1.00e8) { pPolar->AddData(pNewPoint); } } else { pPolar->AddData(pNewPoint); } } if(!m_bStoreOpp) { delete pNewPoint; pNewPoint = NULL; } m_pCurOpp = pNewPoint; if(m_bPolarView) { CreatePolarCurves(); } else { SetOpp(-1.e10); } MainFrame::SetSaveState(false); return pNewPoint; } /** Sets the state of the window's widgets i.a.w. the state of the active ojbects and views. */ void QXDirect::SetControls() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(m_bPolarView) m_pctrlMiddleControls->setCurrentIndex(1); else m_pctrlMiddleControls->setCurrentIndex(0); if(m_pCurPolar) { QString PolarProps; m_pCurPolar->GetPolarProperties(PolarProps); m_pctrlPolarProps->setText(PolarProps); } else m_pctrlPolarProps->clear(); pMainFrame->OpPointsAct->setChecked(!m_bPolarView); pMainFrame->PolarsAct->setChecked(m_bPolarView); pMainFrame->showPanels->setChecked(m_bShowPanels); pMainFrame->showNeutralLine->setChecked(m_bNeutralLine); pMainFrame->showInviscidCurve->setChecked(m_bShowInviscid); pMainFrame->showCurOppOnly->setChecked(m_bCurOppOnly); pMainFrame->setCpVarGraph->setChecked(m_pCpGraph->GetYVariable()==0); pMainFrame->setQVarGraph->setChecked(m_pCpGraph->GetYVariable()==1); for(int ig=0; igPolarGraphAct[ig]->setChecked(m_iPlrView==ONEPOLARGRAPH && m_iPlrGraph== ig); pMainFrame->TwoPolarGraphsAct->setChecked(m_iPlrView==TWOPOLARGRAPHS); pMainFrame->AllPolarGraphsAct->setChecked(m_iPlrView==ALLPOLARGRAPHS); int OppVar = m_pCpGraph->GetYVariable(); pMainFrame->CurXFoilCtPlot->setChecked(!m_bPolarView && OppVar==2 && m_XFoilVar ==1); pMainFrame->CurXFoilDbPlot->setChecked(!m_bPolarView && OppVar==2 && m_XFoilVar ==2); pMainFrame->CurXFoilDtPlot->setChecked(!m_bPolarView && OppVar==2 && m_XFoilVar ==3); pMainFrame->CurXFoilRtLPlot->setChecked(!m_bPolarView && OppVar==2 && m_XFoilVar ==4); pMainFrame->CurXFoilRtPlot->setChecked(!m_bPolarView && OppVar==2 && m_XFoilVar ==5); pMainFrame->CurXFoilNPlot->setChecked(!m_bPolarView && OppVar==2 && m_XFoilVar ==6); pMainFrame->CurXFoilCdPlot->setChecked(!m_bPolarView && OppVar==2 && m_XFoilVar ==7); pMainFrame->CurXFoilCfPlot->setChecked(!m_bPolarView && OppVar==2 && m_XFoilVar ==8); pMainFrame->CurXFoilUePlot->setChecked(!m_bPolarView && OppVar==2 && m_XFoilVar ==9); pMainFrame->CurXFoilHPlot->setChecked(!m_bPolarView && OppVar==2 && m_XFoilVar ==10); m_pctrlShowPressure->setEnabled(!m_bPolarView && m_pCurOpp); m_pctrlShowBL->setEnabled(!m_bPolarView && m_pCurOpp); m_pctrlAnimate->setEnabled(!m_bPolarView && m_pCurOpp); m_pctrlAnimateSpeed->setEnabled(!m_bPolarView && m_pCurOpp); // m_pctrlHighlightOpp->setEnabled(m_bPolar); pMainFrame->currentFoilMenu->setEnabled(MainFrame::s_pCurFoil); pMainFrame->currentPolarMenu->setEnabled(m_pCurPolar); pMainFrame->renameCurFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->DuplicateFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->deleteCurFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->exportCurFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->renameCurFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->setCurFoilStyle->setEnabled(MainFrame::s_pCurFoil); pMainFrame->definePolar->setEnabled(MainFrame::s_pCurFoil); pMainFrame->defineBatch->setEnabled(MainFrame::s_pCurFoil); pMainFrame->deleteFoilOpps->setEnabled(MainFrame::s_pCurFoil); pMainFrame->deleteFoilPolars->setEnabled(MainFrame::s_pCurFoil); pMainFrame->editCurPolar->setEnabled(m_pCurPolar); pMainFrame->deletePolar->setEnabled(m_pCurPolar); pMainFrame->exportCurPolar->setEnabled(m_pCurPolar); pMainFrame->hidePolarOpps->setEnabled(m_pCurPolar); pMainFrame->showPolarOpps->setEnabled(m_pCurPolar); pMainFrame->deletePolarOpps->setEnabled(m_pCurPolar); pMainFrame->DerotateFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->NormalizeFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->RefineLocalFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->RefineGlobalFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->EditCoordsFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->ScaleFoil->setEnabled(MainFrame::s_pCurFoil); pMainFrame->SetLERadius->setEnabled(MainFrame::s_pCurFoil); pMainFrame->SetTEGap->setEnabled(MainFrame::s_pCurFoil); pMainFrame->SetFlap->setEnabled(MainFrame::s_pCurFoil); pMainFrame->InterpolateFoils->setEnabled(MainFrame::s_pCurFoil); pMainFrame->currentOppMenu->setEnabled(m_pCurOpp); pMainFrame->deleteCurOpp->setEnabled(m_pCurOpp); pMainFrame->exportCurOpp->setEnabled(m_pCurOpp); } /** * Connects signals and slots */ void QXDirect::Connect() { connect(m_pctrlSpec1, SIGNAL(clicked()), this, SLOT(OnSpec())); connect(m_pctrlSpec2, SIGNAL(clicked()), this, SLOT(OnSpec())); connect(m_pctrlSpec3, SIGNAL(clicked()), this, SLOT(OnSpec())); connect(m_pctrlAnalyze, SIGNAL(clicked()), this, SLOT(OnAnalyze())); connect(m_pctrlAlphaMin, SIGNAL(editingFinished()), this, SLOT(OnInputChanged())); connect(m_pctrlAlphaMax, SIGNAL(editingFinished()), this, SLOT(OnInputChanged())); connect(m_pctrlAlphaDelta, SIGNAL(editingFinished()), this, SLOT(OnInputChanged())); connect(m_pctrlCurveStyle, SIGNAL(activated(int)), this, SLOT(OnCurveStyle(int))); connect(m_pctrlCurveWidth, SIGNAL(activated(int)), this, SLOT(OnCurveWidth(int))); connect(m_pctrlCurveColor, SIGNAL(clickedLB()), this, SLOT(OnCurveColor())); connect(m_pctrlSequence, SIGNAL(clicked()), this, SLOT(OnSequence())); connect(m_pctrlViscous, SIGNAL(clicked()), this, SLOT(OnViscous())); connect(m_pctrlInitBL, SIGNAL(clicked()), this, SLOT(OnInitBL())); connect(m_pctrlShowBL, SIGNAL(clicked()), this, SLOT(OnShowBL())); connect(m_pctrlShowPressure, SIGNAL(clicked()), this, SLOT(OnShowPressure())); connect(m_pctrlStoreOpp, SIGNAL(clicked()), this, SLOT(OnStoreOpp())); connect(m_pctrlShowPoints, SIGNAL(clicked()), this, SLOT(OnShowCurvePoints())); connect(m_pctrlShowCurve, SIGNAL(clicked()), this, SLOT(OnShowCurve())); // connect(m_pctrlHighlightOpp, SIGNAL(clicked()), this, SLOT(OnHighlightOpp())); connect(m_pctrlAnimate, SIGNAL(clicked(bool)), this, SLOT(OnAnimate(bool))); connect(m_pctrlAnimateSpeed, SIGNAL(sliderMoved(int)), this, SLOT(OnAnimateSpeed(int))); connect(m_pAnimateTimer, SIGNAL(timeout()), this, SLOT(OnAnimateSingle())); } /** * Creates a curve of the Cp graph for a specified OpPoint instance, or for all the instances of OpPoint. * @param pOpp a pointer to the instance of the operating point, the data of which is used to build the CCurve objects */ void QXDirect::CreateOppCurves(OpPoint *pOpp) { OpPoint *pOpPoint = NULL; if(pOpp) pOpPoint = pOpp; else pOpPoint = m_pCurOpp; Curve *pCurve1; QString str; int k; m_pCpGraph->DeleteCurves(); if(m_bCurOppOnly && pOpPoint) { if(!pOpPoint || !pOpPoint->m_bIsVisible) return; pCurve1 = m_pCpGraph->AddCurve(); if(pOpPoint->m_bShowPoints) pCurve1->ShowPoints(true); pCurve1->SetStyle(pOpPoint->m_Style); pCurve1->SetColor(pOpPoint->m_Color); pCurve1->SetWidth(pOpPoint->m_Width); str = QString("-Re=%1-Alpha=%2").arg(pOpPoint->Reynolds,8,'f',0).arg(pOpPoint->Alpha,5,'f',2); str = pOpPoint->m_strFoilName+str; pCurve1->SetTitle(str); FillOppCurve(pOpPoint, m_pCpGraph, pCurve1); if(m_bShowInviscid && pOpPoint) { Curve *pCpi = m_pCpGraph->AddCurve(); if(pOpPoint->m_bShowPoints) pCpi->ShowPoints(true); pCpi->SetStyle(1); pCpi->SetColor(pOpPoint->m_Color.darker(150)); pCpi->SetWidth(pOpPoint->m_Width); str= QString("-Re=%1-Alpha=%2_Inviscid").arg(pOpPoint->Reynolds,8,'f',0).arg(pOpPoint->Alpha,5,'f',2); str = pOpPoint->m_strFoilName+str; pCpi->SetTitle(str); FillOppCurve(pOpPoint, m_pCpGraph, pCpi, true); } } else if(!m_bCurOppOnly) { for (k=0; ksize(); k++) { pOpp = (OpPoint*)m_poaOpp->at(k); if (pOpp && pOpp->m_bIsVisible) { pCurve1 = m_pCpGraph->AddCurve(); if(pOpp->m_bShowPoints) pCurve1->ShowPoints(true); pCurve1->SetStyle(pOpp->m_Style); pCurve1->SetColor(pOpp->m_Color); pCurve1->SetWidth(pOpp->m_Width); str= QString("-Re=%1-Alpha=%2").arg(pOpp->Reynolds,8,'f',0).arg(pOpp->Alpha,5,'f',2); str = pOpp->m_strFoilName+str; pCurve1->SetTitle(str); FillOppCurve(pOpp, m_pCpGraph, pCurve1); } } } } /** *Creates the curves of the graphs for all the visible polars. */ void QXDirect::CreatePolarCurves() { // curves must be entirely reconstructed each time from the // operating points database, since user may have added // or deleted points & polars int k; Polar *pPolar; QString str; m_PlrGraph[0].DeleteCurves(); m_PlrGraph[2].DeleteCurves(); m_PlrGraph[1].DeleteCurves(); m_PlrGraph[3].DeleteCurves(); m_PlrGraph[4].DeleteCurves(); for (k=0; ksize(); k++) { pPolar = (Polar*)m_poaPolar->at(k); if (pPolar->m_bIsVisible && pPolar->m_Alpha.size()>0) { if ( (pPolar->m_PolarType==FIXEDSPEEDPOLAR && m_bType1) || (pPolar->m_PolarType==FIXEDLIFTPOLAR && m_bType2) || (pPolar->m_PolarType==RUBBERCHORDPOLAR && m_bType3) || (pPolar->m_PolarType==FIXEDAOAPOLAR && m_bType4)) { Curve* pPolarCurve = m_PlrGraph[0].AddCurve(); Curve* pCmCurve = m_PlrGraph[2].AddCurve(); Curve* pCzCurve = m_PlrGraph[1].AddCurve(); Curve* pTr1Curve = m_PlrGraph[3].AddCurve(); Curve* pTr2Curve = NULL; if(m_PlrGraph[3].GetYVariable() == 6) pTr2Curve = m_PlrGraph[3].AddCurve(); Curve* pUserCurve = m_PlrGraph[4].AddCurve(); if(pPolar->m_bShowPoints) { pPolarCurve->ShowPoints(true); pCmCurve->ShowPoints(true); pCzCurve->ShowPoints(true); pTr1Curve->ShowPoints(true); if(pTr2Curve) pTr2Curve->ShowPoints(true); pUserCurve->ShowPoints(true); } pPolarCurve->SetStyle(pPolar->m_Style); pCmCurve->SetStyle(pPolar->m_Style); pCzCurve->SetStyle(pPolar->m_Style); pTr1Curve->SetStyle(pPolar->m_Style); if(pTr2Curve) pTr2Curve->SetStyle(pPolar->m_Style); pUserCurve->SetStyle(pPolar->m_Style); pPolarCurve->SetColor(pPolar->m_Color); pCmCurve->SetColor(pPolar->m_Color); pCzCurve->SetColor(pPolar->m_Color); pTr1Curve->SetColor(pPolar->m_Color); if(pTr2Curve) pTr2Curve->SetColor(pPolar->m_Color); pUserCurve->SetColor(pPolar->m_Color); pPolarCurve->SetWidth(pPolar->m_Width); pCmCurve->SetWidth(pPolar->m_Width); pCzCurve->SetWidth(pPolar->m_Width); pTr1Curve->SetWidth(pPolar->m_Width); if(pTr2Curve) pTr2Curve->SetWidth(pPolar->m_Width); pUserCurve->SetWidth(pPolar->m_Width); FillPolarCurve(pPolarCurve, pPolar, m_PlrGraph[0].GetXVariable(), m_PlrGraph[0].GetYVariable()); FillPolarCurve(pCmCurve, pPolar, m_PlrGraph[2].GetXVariable(), m_PlrGraph[2].GetYVariable()); FillPolarCurve(pCzCurve, pPolar, m_PlrGraph[1].GetXVariable(), m_PlrGraph[1].GetYVariable()); FillPolarCurve(pTr1Curve, pPolar, m_PlrGraph[3].GetXVariable(), m_PlrGraph[3].GetYVariable()); if(pTr2Curve) FillPolarCurve(pTr2Curve, pPolar, 7, 1); FillPolarCurve(pUserCurve, pPolar, m_PlrGraph[4].GetXVariable(), m_PlrGraph[4].GetYVariable()); pPolarCurve->SetTitle(pPolar->m_PlrName); pCmCurve->SetTitle(pPolar->m_PlrName); pUserCurve->SetTitle(pPolar->m_PlrName); if(pTr2Curve) { str = pPolar->m_PlrName + " / Xtr1"; pTr1Curve->SetTitle(str); str = pPolar->m_PlrName + " / Xtr2"; pTr2Curve->SetTitle(str); } else { pTr1Curve->SetTitle(pPolar->m_PlrName); } } } } } /** * Deletes instance of the active Foil object, and the associated results. * @param bAsk true if confirmation should be requested from the user priori to deletion */ void QXDirect::DeleteFoil(bool bAsk) { if(!MainFrame::s_pCurFoil || !MainFrame::s_pCurFoil->m_FoilName.length()) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(pMainFrame->DeleteFoil(MainFrame::s_pCurFoil, bAsk)) { m_pCurOpp = NULL; m_pCurPolar = NULL; MainFrame::s_pCurFoil = NULL; } } /** Deletes the current OpPoint, or all of them, depending on the input flag * * @param bCurrent true if only the current OpPoint should be deleted, false if all should be deleted. */ void QXDirect::DeleteOpPoint(bool bCurrent) { int i; if(bCurrent) { // we remove only the current OpPoint OpPoint* opt; for (i=0; isize(); i++) { opt =(OpPoint*)m_poaOpp->at(i); if (opt == m_pCurOpp) { m_poaOpp->removeAt(i); delete m_pCurOpp; m_pCurOpp = NULL; break; } } } else { // kill'em all OpPoint* pOpPoint; for (i=m_poaOpp->size()-1; i>=0;i--) { pOpPoint =(OpPoint*)m_poaOpp->at(i); if (pOpPoint->m_strFoilName == MainFrame::s_pCurFoil->m_FoilName && pOpPoint->m_strPlrName == m_pCurPolar->m_PlrName) { m_poaOpp->removeAt(i); delete pOpPoint; } } } m_pCurOpp = NULL; } /** * Initializes the comboboxes with the active OpPoint or Polar line style * @param bEnable true if the comboboxes should be enable as a result */ void QXDirect::FillComboBoxes(bool bEnable) { if(!bEnable) { m_pctrlCurveColor->setEnabled(false); m_pctrlCurveStyle->setEnabled(false); m_pctrlCurveWidth->setEnabled(false); m_pctrlShowCurve->setEnabled(false); m_pctrlShowPoints->setEnabled(false); } else { m_pctrlCurveColor->setEnabled(true); m_pctrlCurveStyle->setEnabled(true); m_pctrlCurveWidth->setEnabled(true); m_pctrlShowCurve->setEnabled(true); m_pctrlShowPoints->setEnabled(true); } int LineWidth[5]; for (int i=0; i<5;i++) LineWidth[i] = m_CurveWidth; m_pStyleDelegate->SetLineWidth(LineWidth); // the same selected width for all styles m_pStyleDelegate->SetLineColor(m_CurveColor); int LineStyle[5]; for (int i=0; i<5;i++) LineStyle[i] = m_CurveStyle; m_pWidthDelegate->SetLineStyle(LineStyle); //the same selected style for all widths m_pWidthDelegate->SetLineColor(m_CurveColor); m_pctrlCurveStyle->SetLine(m_CurveStyle, m_CurveWidth, m_CurveColor); m_pctrlCurveWidth->SetLine(m_CurveStyle, m_CurveWidth, m_CurveColor); m_pctrlCurveColor->SetColor(m_CurveColor); m_pctrlCurveColor->SetStyle(m_CurveStyle); m_pctrlCurveColor->SetWidth(m_CurveWidth); m_pctrlCurveStyle->update(); m_pctrlCurveWidth->update(); m_pctrlCurveColor->update(); m_pctrlCurveStyle->setCurrentIndex(m_CurveStyle); m_pctrlCurveWidth->setCurrentIndex(m_CurveWidth-1); } /** * Fills the Cp graph curve with the data from the OpPoint. *@param pOpp a pointer to the OpPoint for which the curve is drawn *@param pGraph a pointer to the Graph to which the curve belongs *@param pCurve a pointer to the CCurve which will be filled with the data from the OpPoint *@param bInviscid true if the inviscid resutls should be displayed, false if the viscous results should be displayed */ void QXDirect::FillOppCurve(OpPoint *pOpp, Graph *pGraph, Curve *pCurve, bool bInviscid) { int j; Foil *pOpFoil = ((MainFrame*)s_pMainFrame)->foil(pOpp->m_strFoilName); switch(m_pCpGraph->GetYVariable()) { case 0: { for (j=0; jn; j++) { if(!bInviscid) { if(pOpp->m_bViscResults) pCurve->AppendPoint(pOpFoil->x[j], pOpp->Cpv[j]); } else { pCurve->AppendPoint(pOpFoil->x[j], pOpp->Cpi[j]); } } pGraph->SetYTitle(tr("Cp")); break; } case 1: { for (j=0; jn; j++) { if(!bInviscid) { if(pOpp->m_bViscResults) pCurve->AppendPoint(pOpFoil->x[j], pOpp->Qv[j]); } else { pCurve->AppendPoint(pOpFoil->x[j], pOpp->Qi[j]); } } pGraph->SetYTitle(tr("Q")); break; } default: { for (j=0; jn; j++) { if(!bInviscid) { if(pOpp->m_bViscResults) pCurve->AppendPoint(pOpFoil->x[j], pOpp->Cpv[j]); } else{ pCurve->AppendPoint(pOpFoil->x[j], pOpp->Cpi[j]); } } pGraph->SetYTitle(tr("Cp")); break; } } } /** *Fills a CCurve object with data from a Polar object * @param pCurve a pointer to the CCurve object to be filled with the data from the Polar object * @param pPolar a pointer to the Polar object from which the data will extracted * @param XVar the index of the variable for the curve's x-axis * @param YVar the index of the variable for the curve's y-axis */ void QXDirect::FillPolarCurve(Curve *pCurve, Polar *pPolar, int XVar, int YVar) { int i; QList *pX; QList *pY; pX = (QList *) GetVariable(pPolar, XVar); pY = (QList *) GetVariable(pPolar, YVar); double fx = 1.0; double fy = 1.0; pCurve->SetSelected(-1); if(XVar == 3) fx = 10000.0; if(YVar == 3) fy = 10000.0; for (i=0; im_Alpha.size(); i++) { if (XVar==12) { if((*pX)[i]>0.0) { if (YVar==12) { if((*pY)[i]>0.0) { pCurve->AppendPoint(1.0/sqrt((*pX)[i]), 1.0/sqrt((*pY)[i])); } } else { pCurve->AppendPoint(1.0/sqrt((*pX)[i]), (*pY)[i]*fy); } } } else{ if (YVar==12) { if((*pY)[i]>0.0) { pCurve->AppendPoint((*pX)[i]*fx, 1.0/sqrt((*pY)[i])); } } else { pCurve->AppendPoint((*pX)[i]*fx, (*pY)[i]*fy); } } if(m_pCurOpp && m_bHighlightOpp) { if(qAbs(pPolar->m_Alpha[i]-m_pCurOpp->Alpha)<0.0001) { if(pPolar->m_PlrName==m_pCurOpp->m_strPlrName && MainFrame::s_pCurFoil->m_FoilName==pPolar->m_FoilName) { pCurve->SetSelected(i); } } } } } /** *Returns a pointer to the OpPoint with the specified aoa and which is attached to the active Foil and Polar. *@param Alpha the input aoa *@return a pointer to the OpPoint, or NULL if none has been found for this set of (Foil, Polar, aoa); */ OpPoint* QXDirect::GetOpPoint(double Alpha) { OpPoint* pOpPoint; for (int i=0; isize(); i++) { if(!m_pCurPolar) return NULL; pOpPoint = (OpPoint*)m_poaOpp->at(i); //since alphas are calculated at 1/100th if (pOpPoint->m_strFoilName == MainFrame::s_pCurFoil->m_FoilName) { if (pOpPoint->m_strPlrName == m_pCurPolar->m_PlrName) { if(m_pCurPolar->m_PolarType!=FIXEDAOAPOLAR) { if(qAbs(pOpPoint->Alpha - Alpha) <0.01) { return pOpPoint; } } else { if(qAbs(pOpPoint->Reynolds - Alpha) <0.1) { return pOpPoint; } } } } } return NULL;// shouldn't ever get here, fortunately } /** * Returns a void pointer to the array of the specified variable of the input Polar * @param pPolar a pointer to the Polar object * @param iVar the index of the variable for which a pointer is requested * @return a pointer to the array of the requested variable */ void * QXDirect::GetVariable(Polar *pPolar, int iVar) { void * pVar; switch (iVar){ case 0: pVar = &pPolar->m_Alpha; break; case 1: pVar = &pPolar->m_Cl; break; case 2: pVar = &pPolar->m_Cd; break; case 3: pVar = &pPolar->m_Cd; break; case 4: pVar = &pPolar->m_Cdp; break; case 5: pVar = &pPolar->m_Cm; break; case 6: pVar = &pPolar->m_XTr1; break; case 7: pVar = &pPolar->m_XTr2; break; case 8: pVar = &pPolar->m_HMom; break; case 9: pVar = &pPolar->m_Cpmn; break; case 10: pVar = &pPolar->m_ClCd; break; case 11: pVar = &pPolar->m_Cl32Cd; break; case 12: pVar = &pPolar->m_Cl; break; case 13: pVar = &pPolar->m_Re; break; case 14: pVar = &pPolar->m_XCp; break; default: pVar = &pPolar->m_Alpha; break; } return pVar; } /** * Returns a pointer to the graph to which the input client point belongs * @param pt the client point, in this case the position of the mouse * @return a pointer to the graph */ QGraph* QXDirect::GetGraph(QPoint &pt) { //pt is in client coordinates if (m_bPolarView) { if(m_iPlrView == ONEPOLARGRAPH) { if(m_iPlrGraph>=0 && m_iPlrGraphIsInDrawRect(pt)) return m_pCurGraph; else return NULL; } if(m_iPlrView == TWOPOLARGRAPHS) { if(m_PlrGraph[0].IsInDrawRect(pt)){return m_PlrGraph;} if(m_PlrGraph[4].IsInDrawRect(pt)){return m_PlrGraph+4;} return NULL; } else { QRect r; m_PlrGraph[2].GetClientRect(r); if(m_PlrGraph[0].IsInDrawRect(pt)){return m_PlrGraph;} if(m_PlrGraph[1].IsInDrawRect(pt)){return m_PlrGraph+1;} if(m_PlrGraph[2].IsInDrawRect(pt)){return m_PlrGraph+2;} if(m_PlrGraph[3].IsInDrawRect(pt)){return m_PlrGraph+3;} if(m_PlrGraph[4].IsInDrawRect(pt)){return m_PlrGraph+4;} } } else { if(m_pCpGraph->IsInDrawRect(pt)) { if(m_bCpGraph) return m_pCpGraph; else return NULL; } else return NULL; } return NULL; } /** * Inserts a new OpPoint in the array. The OpPoints are sorted by FoilName first, then by Re number, then by aoa. * If an OpPoint already exists with the same combination of (FoilName, Re, aoa), it is overwritten. * @param pNewPoint */ void QXDirect::InsertOpPoint(OpPoint *pNewPoint) { if(!pNewPoint) return; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; bool bIsInserted = false; OpPoint* pOpPoint; Polar *pPolar = pMainFrame->GetPolar(pNewPoint->m_strFoilName, pNewPoint->m_strPlrName); if(!pPolar) { delete pNewPoint; return ; } // first add the OpPoint to the OpPoint Array for the current FoilName for (int i=0; isize(); i++) { pOpPoint = (OpPoint*)m_poaOpp->at(i); if (pNewPoint->m_strFoilName.compare(pOpPoint->m_strFoilName)<0) { //insert point m_poaOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaOpp->size();// to break } else if (pNewPoint->m_strFoilName == pOpPoint->m_strFoilName) { if (pNewPoint->Reynolds < pOpPoint->Reynolds) { //insert point m_poaOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaOpp->size();// to break } else if (qAbs(pNewPoint->Reynolds-pOpPoint->Reynolds)<1.0) { if(qAbs(pNewPoint->Alpha - pOpPoint->Alpha)<0.005) { //replace existing point m_poaOpp->removeAt(i); delete pOpPoint; m_poaOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaOpp->size();// to break } else if (pNewPoint->Alpha > pOpPoint->Alpha) { //insert point m_poaOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaOpp->size();// to break } } } } if (!bIsInserted) m_poaOpp->append(pNewPoint); } /** * Overrides the QWidget's keyPressEvent method. * Dispatches the key press event * @param event the QKeyEvent */ void QXDirect::keyPressEvent(QKeyEvent *event) { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; bool bShift = false; bool bCtrl = false; if(event->modifiers() & Qt::ShiftModifier) bShift =true; if(event->modifiers() & Qt::ControlModifier) bCtrl =true; switch (event->key()) { case Qt::Key_Return: if (event->modifiers().testFlag(Qt::AltModifier)) { OnPolarProps(); break; } ReadParams(); if(m_pctrlAnalyze->hasFocus()) OnAnalyze(); else { activateWindow(); m_pctrlAnalyze->setFocus(); } break; case Qt::Key_Tab: ReadParams(); break; case Qt::Key_Escape: StopAnimate(); UpdateView(); break; case Qt::Key_H: { if(m_bPolarView && event->modifiers().testFlag(Qt::ControlModifier)) { OnHighlightOpp(); } break; } case Qt::Key_L: pMainFrame->OnLogFile(); break; case Qt::Key_X: m_bXPressed = true; break; case Qt::Key_Y: m_bYPressed = true; break; case Qt::Key_1: m_iPlrView = ONEPOLARGRAPH; m_iPlrGraph = 0; if(m_bPolarView) SetPolarLegendPos(); SetControls(); UpdateView(); break; case Qt::Key_2: m_iPlrView = ONEPOLARGRAPH; m_iPlrGraph = 1; if(m_bPolarView) SetPolarLegendPos(); SetControls(); UpdateView(); break; case Qt::Key_3: m_iPlrView = ONEPOLARGRAPH; m_iPlrGraph = 2; if(m_bPolarView) SetPolarLegendPos(); SetControls(); UpdateView(); break; case Qt::Key_4: m_iPlrView = ONEPOLARGRAPH; m_iPlrGraph = 3; if(m_bPolarView) SetPolarLegendPos(); SetControls(); UpdateView(); break; case Qt::Key_5: m_iPlrView = ONEPOLARGRAPH; m_iPlrGraph = 4; if(m_bPolarView) SetPolarLegendPos(); SetControls(); UpdateView(); break; case Qt::Key_A: m_iPlrView = ALLPOLARGRAPHS; if(m_bPolarView) SetPolarLegendPos(); SetControls(); UpdateView(); break; case Qt::Key_T: m_iPlrView = TWOPOLARGRAPHS; if(m_bPolarView) SetPolarLegendPos(); SetControls(); UpdateView(); break; case Qt::Key_G: if(m_pCurGraph) OnGraphSettings(); break; case Qt::Key_R: if(m_pCurGraph) { m_pCurGraph->SetAuto(true); UpdateView(); } else if(!m_bPolarView) { OnResetFoilScale(); } else { SetPolarLegendPos(); UpdateView(); } break; case Qt::Key_V: if(m_bPolarView && m_pCurGraph) { GraphDlg::s_ActivePage=0; OnGraphSettings(); } break; case Qt::Key_F2: { OnRenameFoil(); break; } case Qt::Key_F3: { if(bShift) OnCadd(); else OnRefinePanelsGlobally(); break; } case Qt::Key_F5: { if(!m_bPolarView) return; OnOpPoints(); break; } case Qt::Key_F6: { if (event->modifiers().testFlag(Qt::ShiftModifier)) OnBatchAnalysis(); else if (event->modifiers().testFlag(Qt::ControlModifier)) OnMultiThreadedBatchAnalysis(); else OnDefinePolar(); break; } case Qt::Key_F8: { if(m_bPolarView) return; OnPolars(); break; } case Qt::Key_F9: { OnFoilGeom(); break; } case Qt::Key_F10: { OnSetFlap(); break; } case Qt::Key_F11: { OnInterpolateFoils(); break; } default: QWidget::keyPressEvent(event); } } /** * Overrides the QWidget's keyReleaseEvent method. * Dispatches the key release event * @param event the QKeyEvent */ void QXDirect::keyReleaseEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_X: if(!event->isAutoRepeat()) m_bXPressed = false; break; case Qt::Key_Y: if(!event->isAutoRepeat()) m_bYPressed = false; break; default: QWidget::keyReleaseEvent(event); } } /** * Loads the user's default settings from the application QSettings object * @param pSettings a pointer to the QSettings object */ void QXDirect::LoadSettings(QSettings *pSettings) { QString str1, str2, str3; int r,g,b; pSettings->beginGroup("XDirect"); { m_bAlpha = pSettings->value("AlphaSpec").toBool(); m_bStoreOpp = pSettings->value("StoreOpp").toBool(); m_bViscous = pSettings->value("ViscousAnalysis").toBool(); m_bInitBL = pSettings->value("InitBL").toBool(); m_bBL = pSettings->value("BoundaryLayer").toBool(); m_bPressure = pSettings->value("Pressure").toBool(); m_bPolarView = pSettings->value("PolarView").toBool(); m_bShowUserGraph = pSettings->value("UserGraph").toBool(); m_bShowPanels = pSettings->value("ShowPanels").toBool(); m_bType1 = pSettings->value("Type1").toBool(); m_bType2 = pSettings->value("Type2").toBool(); m_bType3 = pSettings->value("Type3").toBool(); m_bType4 = pSettings->value("Type4").toBool(); m_bAutoInitBL = pSettings->value("AutoInitBL").toBool(); m_bFromList = pSettings->value("FromList").toBool(); m_bFromZero = pSettings->value("FromZero").toBool(); m_bShowTextOutput = pSettings->value("TextOutput").toBool(); m_bNeutralLine = pSettings->value("NeutralLine").toBool(); m_bCurOppOnly = pSettings->value("CurOppOnly").toBool(); m_bShowInviscid = pSettings->value("ShowInviscid").toBool(); m_bCpGraph = pSettings->value("ShowCpGraph").toBool(); m_bSequence = pSettings->value("Sequence").toBool(); m_bHighlightOpp = pSettings->value("HighlightOpp").toBool(); m_bHighlightOpp = false; r = pSettings->value("BLColorRed").toInt(); g = pSettings->value("BLColorGreen").toInt(); b = pSettings->value("BLColorBlue").toInt(); m_crBLColor = QColor(r,g,b); m_iBLStyle = pSettings->value("BLStyle").toInt(); m_iBLWidth = pSettings->value("BLWidth").toInt(); r = pSettings->value("PressureColorRed").toInt(); g = pSettings->value("PressureColorGreen").toInt(); b = pSettings->value("PressureColorBlue").toInt(); m_crPressureColor = QColor(r,g,b); m_iPressureStyle = pSettings->value("PressureStyle").toInt(); m_iPressureWidth = pSettings->value("PressureWidth").toInt(); r = pSettings->value("NeutralColorRed").toInt(); g = pSettings->value("NeutralColorGreen").toInt(); b = pSettings->value("NeutralColorBlue").toInt(); m_crNeutralColor = QColor(r,g,b); m_iNeutralStyle = pSettings->value("NeutralStyle").toInt(); m_iNeutralWidth = pSettings->value("NeutralWidth").toInt(); m_XFoilVar = pSettings->value("XFoilVar").toInt(); m_IterLim = pSettings->value("IterLim").toInt(); m_iPlrGraph = pSettings->value("PlrGraph").toInt(); switch(pSettings->value("PlrView").toInt()) { case 1: m_iPlrView = ONEPOLARGRAPH; break; case 2: m_iPlrView = TWOPOLARGRAPHS; break; default: m_iPlrView = ALLPOLARGRAPHS; break; } m_Alpha = pSettings->value("AlphaMin").toDouble(); m_AlphaMax = pSettings->value("AlphaMax").toDouble(); m_AlphaDelta = pSettings->value("AlphaDelta").toDouble(); m_Cl = pSettings->value("ClMin").toDouble(); m_ClMax = pSettings->value("ClMax").toDouble(); m_ClDelta = pSettings->value("ClDelta").toDouble(); m_Reynolds = pSettings->value("ReynoldsMin").toDouble(); m_ReynoldsMax = pSettings->value("ReynoldsMax").toDouble(); m_ReynoldsDelta = pSettings->value("ReynolsDelta").toDouble(); m_NCrit = pSettings->value("NCrit").toDouble(); m_XTopTr = pSettings->value("XTopTr").toDouble(); m_XBotTr = pSettings->value("XBotTr").toDouble(); m_Mach = pSettings->value("Mach").toDouble(); m_ASpec = pSettings->value("ASpec").toDouble(); m_pXFoil->vaccel = pSettings->value("VAccel").toDouble(); m_bAutoInitBL = pSettings->value("AutoInitBL").toBool(); m_NRe = pSettings->value("NReynolds").toInt(); m_pXFoil->m_bFullReport = pSettings->value("FullReport").toBool(); b = pSettings->value("Type").toInt(); if(b==1) m_PolarType = FIXEDSPEEDPOLAR; else if(b==2) m_PolarType = FIXEDLIFTPOLAR; else if(b==3) m_PolarType = RUBBERCHORDPOLAR; else if(b==4) m_PolarType = FIXEDAOAPOLAR; for (int i=0; ivalue(str1).toDouble(); m_MachList[i] = pSettings->value(str2).toDouble(); m_NCritList[i] = pSettings->value(str3).toDouble(); } } pSettings->endGroup(); m_PlrGraph[0].LoadSettings(pSettings); m_PlrGraph[2].LoadSettings(pSettings); m_PlrGraph[1].LoadSettings(pSettings); m_PlrGraph[3].LoadSettings(pSettings); m_PlrGraph[4].LoadSettings(pSettings); m_pCpGraph->LoadSettings(pSettings); if(m_pCpGraph->GetYVariable() == 0 || m_pCpGraph->GetYVariable()>=2) { m_pCpGraph->SetYTitle(tr("Cp")); m_pCpGraph->SetInverted(true); } else { m_pCpGraph->SetYTitle(tr("Q")); m_pCpGraph->SetInverted(false); } for(int ig=0; igIsInDrawRect(event->pos())) return; } else if(!m_pCurGraph) return; OnGraphSettings(); } /** * Overrides the QWidget's mouseMoveEvent method. * Dispatches the event * @param event the QMouseEvent */ void QXDirect::mouseMoveEvent(QMouseEvent *event) { static QPoint pt; static double xu, yu, x1, y1, xmin, ymin, xmax, ymax, scale; static int a; static MainFrame* pMainFrame; pMainFrame = (MainFrame*)s_pMainFrame; pt.setX(event->x()); pt.setY(event->y()); //client coordinates m_pCurGraph = GetGraph(pt); if(!hasFocus()) setFocus();//to catch keyboard input; if ((event->buttons() & Qt::LeftButton) && m_bTrans) { if(m_pCurGraph && m_bTransGraph) { // we translate the curves inside the graph m_pCurGraph->SetAuto(false); x1 = m_pCurGraph->ClientTox(m_PointDown.x()) ; y1 = m_pCurGraph->ClientToy(m_PointDown.y()) ; xu = m_pCurGraph->ClientTox(pt.x()); yu = m_pCurGraph->ClientToy(pt.y()); xmin = m_pCurGraph->GetXMin() - xu+x1; xmax = m_pCurGraph->GetXMax() - xu+x1; ymin = m_pCurGraph->GetYMin() - yu+y1; ymax = m_pCurGraph->GetYMax() - yu+y1; m_pCurGraph->SetWindow(xmin, xmax, ymin, ymax); m_PointDown.setX(pt.x()); m_PointDown.setY(pt.y()); if(!m_bAnimate) UpdateView(); } else if(m_bPolarView) { m_PolarLegendOffset.rx() += pt.x()-m_PointDown.x(); m_PolarLegendOffset.ry() += pt.y()-m_PointDown.y(); UpdateView(); } else if (MainFrame::s_pCurFoil && !m_bPolarView) { // we translate the airfoil m_FoilOffset.rx() += pt.x()-m_PointDown.x(); m_FoilOffset.ry() += pt.y()-m_PointDown.y(); if(!m_bAnimate) UpdateView(); } m_PointDown = pt; } else if (MainFrame::s_pCurFoil && ((event->buttons() & Qt::MidButton) || event->modifiers().testFlag(Qt::AltModifier))) { // we zoom the graph or the foil if(m_pCurGraph && m_pCurGraph->IsInDrawRect(pt) && m_bCpGraph) { //zoom graph m_pCurGraph->SetAuto(false); if(pt.y()-m_PointDown.y()<0) m_pCurGraph->Scale(1.02); else m_pCurGraph->Scale(1.0/1.02); if(!m_bAnimate) UpdateView(); } else if(MainFrame::s_pCurFoil && !m_bPolarView) { //zoom the foil scale = m_fFoilScale; if(pt.y()-m_PointDown.y()<0) m_fFoilScale *= 1.02; else m_fFoilScale /= 1.02; a = (int)((m_rCltRect.right()+m_rCltRect.left())/2); m_FoilOffset.rx() = a + (int)((m_FoilOffset.x()-a)/scale*m_fFoilScale); if(!m_bAnimate) UpdateView(); } m_PointDown = pt; } else if(m_pCurGraph && m_pCurGraph->IsInDrawRect(pt)) { x1 = m_pCurGraph->ClientTox(event->x()) ; y1 = m_pCurGraph->ClientToy(event->y()) ; pMainFrame->statusBar()->showMessage(QString("X = %1, Y = %2").arg(x1).arg(y1)); } else { pMainFrame->statusBar()->clearMessage(); } } /** * Overrides the QWidget's mousePressEvent method. * Dispatches the event * @param event the QMouseEvent */ void QXDirect::mousePressEvent(QMouseEvent *event) { QPoint pt(event->x(), event->y()); //client coordinates m_pCurGraph = GetGraph(pt); TwoDWidget *p2DWidget = (TwoDWidget*)s_p2DWidget; p2DWidget->setFocus(); if(event->buttons() & Qt::LeftButton) { if (MainFrame::s_pCurFoil || (m_pCurGraph && m_pCurGraph->IsInDrawRect(pt) && m_bCpGraph)) { m_PointDown.setX(pt.x()); m_PointDown.setY(pt.y()); m_bTrans = true; p2DWidget->setCursor(Qt::ClosedHandCursor); if (m_pCurGraph && m_pCurGraph->IsInDrawRect(pt)) m_bTransGraph = true; else m_bTransGraph = false; if(!m_bAnimate) UpdateView(); } } } /** * Overrides the QWidget's mouseReleasEvent method. * Dispatches the event * @param event the QMouseEvent */ void QXDirect::mouseReleaseEvent(QMouseEvent *event) { TwoDWidget *p2DWidget = (TwoDWidget*)s_p2DWidget; m_bTrans = false; p2DWidget->setCursor(Qt::CrossCursor); } /** * The user has requested a display of all polar graphs */ void QXDirect::OnAllPolarGraphs() { m_iPlrView = ALLPOLARGRAPHS; m_bPolarView = true; SetPolarLegendPos(); SetControls(); UpdateView(); } /** * The user has requested an edition of all polar graphs settings */ void QXDirect::OnAllPolarGraphsSetting() { QGraph graph; graph.CopySettings(m_PlrGraph); GraphDlg grDlg((MainFrame*)s_pMainFrame); grDlg.m_pMemGraph = &graph; grDlg.m_pGraph = m_PlrGraph; grDlg.m_GraphArray[0] = m_PlrGraph; grDlg.m_GraphArray[1] = m_PlrGraph+1; grDlg.m_GraphArray[2] = m_PlrGraph+2; grDlg.m_GraphArray[3] = m_PlrGraph+3; grDlg.m_GraphArray[4] = m_PlrGraph+4; grDlg.m_NGraph = 5; grDlg.SetParams(); if(grDlg.exec() == QDialog::Accepted) { } else { m_PlrGraph[0].CopySettings(&graph); m_PlrGraph[2].CopySettings(&graph); m_PlrGraph[1].CopySettings(&graph); m_PlrGraph[3].CopySettings(&graph); m_PlrGraph[4].CopySettings(&graph); } UpdateView(); } /** * The user has changed one of the analysis parameters. Reads all the data and maps it. */ void QXDirect::OnInputChanged() { ReadParams(); } /** * The user has clicked the animate checkcbox * @param bChecked the new state of the checkbox */ void QXDirect::OnAnimate(bool bChecked) { if(!MainFrame::s_pCurFoil || !m_pCurPolar) { m_bAnimate = false; return; } OpPoint* pOpPoint; int l; if(bChecked) { for (l=0; l< m_poaOpp->size(); l++) { pOpPoint = (OpPoint*)m_poaOpp->at(l); if (pOpPoint && pOpPoint->m_strPlrName == m_pCurPolar->m_PlrName && pOpPoint->m_strFoilName == MainFrame::s_pCurFoil->m_FoilName) { if(qAbs(m_pCurOpp->Alpha - pOpPoint->Alpha)<0.0001) m_posAnimate = l-1; } } m_bAnimate = true; int speed = m_pctrlAnimateSpeed->value(); m_pAnimateTimer->setInterval(800-speed); m_pAnimateTimer->start(); } else { m_pAnimateTimer->stop(); m_bAnimate = false; if(m_posAnimate<0 || m_posAnimate>=m_poaOpp->size()) return; OpPoint* pOpPoint = (OpPoint*)m_poaOpp->at(m_posAnimate); if(pOpPoint) SetOpp(pOpPoint->Alpha); // UpdateView(); return; } } /** * Called by the animation timer. * Updates the display with the data of the next OpPoint. */ void QXDirect::OnAnimateSingle() { static int indexCbBox; static QString str; bool bIsValid = false; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; OpPoint* pOpPoint; if(m_poaOpp->size()<=1) return; // find the next oppoint related to this foil and polar pair while(!bIsValid) { if(m_bAnimatePlus) { m_posAnimate++; if (m_posAnimate >= m_poaOpp->size()) { m_posAnimate = m_poaOpp->size()-2; m_bAnimatePlus = false; } } else { m_posAnimate--; if (m_posAnimate <0) { m_posAnimate = 1; m_bAnimatePlus = true; } } if(m_posAnimate<0 || m_posAnimate>=m_poaOpp->size()) return; pOpPoint = (OpPoint*)m_poaOpp->at(m_posAnimate); if (pOpPoint && pOpPoint->m_strPlrName == m_pCurPolar->m_PlrName && pOpPoint->m_strFoilName == MainFrame::s_pCurFoil->m_FoilName && pOpPoint != m_pCurOpp) { bIsValid = true; CreateOppCurves(pOpPoint); m_pCurOpp = pOpPoint; //select current OpPoint in Combobox if(m_pCurPolar->m_PolarType!=FIXEDAOAPOLAR) str = QString("%1").arg(m_pCurOpp->Alpha,8,'f',2); else str = QString("%1").arg(m_pCurOpp->Reynolds,8,'f',2); indexCbBox = pMainFrame->m_pctrlOpPoint->findText(str); if(indexCbBox>=0) pMainFrame->m_pctrlOpPoint->setCurrentIndex(indexCbBox); UpdateView(); } } } /** * the user has moved the slider which defines the animation speed * @param val the slider's new position */ void QXDirect::OnAnimateSpeed(int val) { if(m_pAnimateTimer->isActive()) { m_pAnimateTimer->setInterval(800-val); } } /** * The user has clicked the analyze button. * * Reads the input parameters, initializes the analysis dialog box, and starts the analysis. */ void QXDirect::OnAnalyze() { if(!MainFrame::s_pCurFoil || !m_pCurPolar) return; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; m_pXFoil->lvisc = m_bViscous; ReadParams(); m_pctrlAnalyze->setEnabled(false); bool bHigh = m_bHighlightOpp; m_bHighlightOpp = false; XFoilAnalysisDlg xfaDlg(pMainFrame); xfaDlg.SetAlpha(m_Alpha, m_AlphaMax, m_AlphaDelta); xfaDlg.SetCl(m_Cl, m_ClMax, m_ClDelta); xfaDlg.SetRe(m_Reynolds, m_ReynoldsMax, m_ReynoldsDelta); xfaDlg.m_bSequence = m_bSequence; xfaDlg.m_bAlpha = m_bAlpha; xfaDlg.m_bType4 = (m_pCurPolar->m_PolarType==FIXEDAOAPOLAR); xfaDlg.m_FoilName = MainFrame::s_pCurFoil->m_FoilName; xfaDlg.m_IterLim = m_IterLim; xfaDlg.m_pXFoil = m_pXFoil; xfaDlg.InitDialog(); xfaDlg.show(); xfaDlg.StartAnalysis(); xfaDlg.hide(); xfaDlg.move(xfaDlg.x(), xfaDlg.y()); // and update window m_pctrlAnalyze->setEnabled(true); m_bInitBL = !m_pXFoil->lblini; m_pctrlInitBL->setChecked(m_bInitBL);; m_pCurGraph = m_pCpGraph; pMainFrame->UpdateOpps(); SetOpp(); m_bHighlightOpp = bHigh; if(m_bPolarView) CreatePolarCurves(); SetControls(); UpdateView(); } /** * Launches a single-threaded batch analysis */ void QXDirect::OnBatchAnalysis() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(!MainFrame::s_pCurFoil) return; m_bPolarView = true; OnPolars(); UpdateView(); m_pctrlAnalyze->setEnabled(false); BatchDlg btchDlg(pMainFrame); btchDlg.m_pFoil = MainFrame::s_pCurFoil; btchDlg.m_Mach = 0.0; btchDlg.m_ReMin = m_Reynolds; btchDlg.m_ReMax = m_ReynoldsMax; btchDlg.m_ReInc = m_ReynoldsDelta; btchDlg.m_PolarType = m_PolarType; btchDlg.m_IterLim = m_IterLim; btchDlg.m_bAlpha = true; btchDlg.m_SpMin = m_Alpha; btchDlg.m_SpMax = m_AlphaMax; btchDlg.m_SpInc = m_AlphaDelta; btchDlg.m_AlphaMin = m_Alpha; btchDlg.m_AlphaMax = m_AlphaMax; btchDlg.m_AlphaInc = m_AlphaDelta; btchDlg.m_ClMin = m_Cl; btchDlg.m_ClMax = m_ClMax; btchDlg.m_ClInc = m_ClDelta; btchDlg.m_NCrit = m_NCrit; btchDlg.m_XTopTr = m_XTopTr; btchDlg.m_XBotTr = m_XBotTr; btchDlg.m_ReList = m_ReList; btchDlg.m_MachList = m_MachList; btchDlg.m_NCritList = m_NCritList; btchDlg.m_NRe = m_NRe; btchDlg.m_bFromList = m_bFromList; btchDlg.m_bFromZero = m_bFromZero; btchDlg.InitDialog(); if(btchDlg.exec()==QDialog::Accepted) MainFrame::SetSaveState(false); m_Reynolds = btchDlg.m_ReMin; m_ReynoldsMax = btchDlg.m_ReMax; m_ReynoldsDelta = btchDlg.m_ReInc; m_Alpha = btchDlg.m_AlphaMin; m_AlphaMax = btchDlg.m_AlphaMax; m_AlphaDelta = btchDlg.m_AlphaInc; m_Cl = btchDlg.m_ClMin; m_ClMax = btchDlg.m_ClMax; m_ClDelta = btchDlg.m_ClInc; m_Mach = btchDlg.m_Mach; m_PolarType = btchDlg.m_PolarType; m_NCrit = btchDlg.m_NCrit; m_XTopTr = btchDlg.m_XTopTr; m_XBotTr = btchDlg.m_XBotTr; m_NRe = btchDlg.m_NRe; m_bAlpha = btchDlg.m_bAlpha; m_bFromList = btchDlg.m_bFromList; m_bFromZero = btchDlg.m_bFromZero; SetPolar(); pMainFrame->UpdatePolars(); m_pCurOpp = NULL; m_pctrlAnalyze->setEnabled(true); SetControls(); UpdateView(); } /** * Launches a multi-threaded batch analysis * */ void QXDirect::OnMultiThreadedBatchAnalysis() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(!MainFrame::s_pCurFoil) return; if(QThread::idealThreadCount()<2) { QString strange = tr("Not enough threads available for multithreading"); QMessageBox::warning(pMainFrame, tr("Warning"), strange); return; } m_bPolarView = true; OnPolars(); UpdateView(); m_pctrlAnalyze->setEnabled(false); BatchThreadDlg *m_pBatchThreadDlg = new BatchThreadDlg(pMainFrame); m_pBatchThreadDlg->m_pCurFoil = MainFrame::s_pCurFoil; m_pBatchThreadDlg->m_Mach = 0.0; m_pBatchThreadDlg->m_ReMin = m_Reynolds; m_pBatchThreadDlg->m_ReMax = m_ReynoldsMax; m_pBatchThreadDlg->m_ReInc = m_ReynoldsDelta; m_pBatchThreadDlg->m_PolarType = FIXEDSPEEDPOLAR; m_pBatchThreadDlg->m_IterLim = m_IterLim; m_pBatchThreadDlg->m_bAlpha = true; m_pBatchThreadDlg->m_AlphaMin = m_Alpha; m_pBatchThreadDlg->m_AlphaMax = m_AlphaMax; m_pBatchThreadDlg->m_AlphaInc = m_AlphaDelta; m_pBatchThreadDlg->m_ClMin = m_Cl; m_pBatchThreadDlg->m_ClMax = m_ClMax; m_pBatchThreadDlg->m_ClInc = m_ClDelta; m_pBatchThreadDlg->m_NCrit = m_NCrit; m_pBatchThreadDlg->m_XTopTr = m_XTopTr; m_pBatchThreadDlg->m_XBotTr = m_XBotTr; m_pBatchThreadDlg->m_ReList = m_ReList; m_pBatchThreadDlg->m_MachList = m_MachList; m_pBatchThreadDlg->m_NCritList = m_NCritList; m_pBatchThreadDlg->m_NRe = m_NRe; m_pBatchThreadDlg->m_bFromList = m_bFromList; m_pBatchThreadDlg->m_bFromZero = m_bFromZero; m_pBatchThreadDlg->InitDialog(); if(m_pBatchThreadDlg->exec()==QDialog::Accepted) MainFrame::SetSaveState(false); m_Reynolds = m_pBatchThreadDlg->m_ReMin; m_ReynoldsMax = m_pBatchThreadDlg->m_ReMax; m_ReynoldsDelta = m_pBatchThreadDlg->m_ReInc; m_Alpha = m_pBatchThreadDlg->m_AlphaMin; m_AlphaMax = m_pBatchThreadDlg->m_AlphaMax; m_AlphaDelta = m_pBatchThreadDlg->m_AlphaInc; m_Cl = m_pBatchThreadDlg->m_ClMin; m_ClMax = m_pBatchThreadDlg->m_ClMax; m_ClDelta = m_pBatchThreadDlg->m_ClInc; m_Mach = m_pBatchThreadDlg->m_Mach; m_PolarType = m_pBatchThreadDlg->m_PolarType; m_NCrit = m_pBatchThreadDlg->m_NCrit; m_XTopTr = m_pBatchThreadDlg->m_XTopTr; m_XBotTr = m_pBatchThreadDlg->m_XBotTr; m_NRe = m_pBatchThreadDlg->m_NRe; m_bAlpha = m_pBatchThreadDlg->m_bAlpha; m_bFromList = m_pBatchThreadDlg->m_bFromList; m_bFromZero = m_pBatchThreadDlg->m_bFromZero; SetPolar(); pMainFrame->UpdatePolars(); m_pCurOpp = NULL; m_pctrlAnalyze->setEnabled(true); SetControls(); UpdateView(); } /** * The user has requested the plot of the Cf variable using current XFoil results. */ void QXDirect::OnCfPlot() { if(!m_pXFoil->lvconv) return; int i; double x[IVX][3],y[IVX][3]; int nside1, nside2, ibl; m_pCpGraph->SetYVariable(2); m_XFoilVar = 8; m_pCpGraph->DeleteCurves(); m_pCpGraph->ResetLimits(); m_pCpGraph->SetAuto(true); m_pCpGraph->SetInverted(false); m_pCpGraph->SetYTitle(tr("Cf")); Curve * pTopCurve = m_pCpGraph->AddCurve(); Curve * pBotCurve = m_pCpGraph->AddCurve(); pTopCurve->SetTitle(tr("Top")); pBotCurve->SetTitle(tr("Bot")); double que = 0.5*m_pXFoil->qinf*m_pXFoil->qinf; m_pXFoil->CreateXBL(x, nside1, nside2); //---- fill compressible ue arrays for (ibl=2; ibl<= nside1;ibl++) { y[ibl][1] = m_pXFoil->tau[ibl][1] / que; } for ( ibl=2; ibl<= nside2;ibl++) { y[ibl][2] = m_pXFoil->tau[ibl][2] / que; } for (i=2; i<=nside1-1; i++) { pTopCurve->AppendPoint(x[i][1], y[i][1]); } for (i=2; i<=nside2-1; i++) { pBotCurve->AppendPoint(x[i][2], y[i][2]); } m_pCpGraph->SetXScale(); SetFoilScale(); SetControls(); UpdateView(); } /** * The user has requested the plot of the Ct variable using current XFoil results. */ void QXDirect::OnCtPlot() { if(!m_pXFoil->lvconv) return; int i; m_pCpGraph->SetYVariable(2); m_XFoilVar=1; m_pCpGraph->DeleteCurves(); m_pCpGraph->ResetLimits(); m_pCpGraph->SetAuto(true); m_pCpGraph->SetInverted(false); m_pCpGraph->SetYTitle(tr("Max Shear")); Curve * pCurve0 = m_pCpGraph->AddCurve(); Curve * pCurve1 = m_pCpGraph->AddCurve(); Curve * pCurve2 = m_pCpGraph->AddCurve(); Curve * pCurve3 = m_pCpGraph->AddCurve(); pCurve0->SetTitle(tr("Top Shear")); pCurve1->SetTitle(tr("Top Shear eq")); pCurve2->SetTitle(tr("Bot Shear")); pCurve3->SetTitle(tr("Bot Shear eq")); double x[IVX][3]; int nside1, nside2; m_pXFoil->CreateXBL(x, nside1, nside2); int it1 = m_pXFoil->itran[1]; int it2 = m_pXFoil->itran[2]; for (i=it1; i<=nside1-1; i++) pCurve0->AppendPoint(x[i][1], m_pXFoil->ctau[i][1]); for (i=2; i<=nside1-1; i++) pCurve1->AppendPoint(x[i][1], m_pXFoil->ctq[i][1]); for (i=it2; i<=nside2-1; i++) pCurve2->AppendPoint(x[i][2], m_pXFoil->ctau[i][2]); for (i=2; i<=nside2-1; i++) pCurve3->AppendPoint(x[i][2], m_pXFoil->ctq[i][2]); m_pCpGraph->SetXScale(); SetFoilScale(); SetControls(); UpdateView(); } /** * The user has requested the plot of the Dt variable using current XFoil results. */ void QXDirect::OnDtPlot() { if(!m_pXFoil->lvconv) return; int i; m_pCpGraph->SetYVariable(2); m_XFoilVar=3; m_pCpGraph->DeleteCurves(); m_pCpGraph->ResetLimits(); m_pCpGraph->SetAuto(true); m_pCpGraph->SetInverted(false); m_pCpGraph->SetYTitle(" "); double x[IVX][3]; int nside1, nside2; Curve * pCurve1 = m_pCpGraph->AddCurve(); Curve * pCurve2 = m_pCpGraph->AddCurve(); pCurve1->SetTitle("D*"); pCurve2->SetTitle("Theta"); m_pXFoil->CreateXBL(x, nside1, nside2); for (i=2; iAppendPoint(x[i][1], m_pXFoil->dstr[i][1]); pCurve2->AppendPoint(x[i][1], m_pXFoil->thet[i][1]); } m_pCpGraph->SetXScale(); SetFoilScale(); SetControls(); UpdateView(); } /** * The user has requested the plot of the Db variable using current XFoil results. */ void QXDirect::OnDbPlot() { if(!m_pXFoil->lvconv) return; int i; m_pCpGraph->SetYVariable(2); m_XFoilVar = 2; m_pCpGraph->DeleteCurves(); m_pCpGraph->ResetLimits(); m_pCpGraph->SetAuto(true); m_pCpGraph->SetInverted(false); m_pCpGraph->SetYTitle(" "); double x[IVX][3]; int nside1, nside2; Curve * pCurve1 = m_pCpGraph->AddCurve(); Curve * pCurve2 = m_pCpGraph->AddCurve(); pCurve1->SetTitle("D*"); pCurve2->SetTitle("Theta"); m_pXFoil->CreateXBL(x, nside1, nside2); for (i=2; iAppendPoint(x[i][2], m_pXFoil->dstr[i][2]); pCurve2->AppendPoint(x[i][2], m_pXFoil->thet[i][2]); } m_pCpGraph->SetXScale(); SetFoilScale(); SetControls(); UpdateView(); } /** * The user has requested the plot of the Cd variable using current XFoil results. */ void QXDirect::OnCdPlot() { if(!m_pXFoil->lvconv) return; double x[IVX][3],y[IVX][3]; int nside1, nside2, ibl; int i; m_pCpGraph->SetYVariable(2); m_XFoilVar = 7; m_pCpGraph->DeleteCurves(); m_pCpGraph->ResetLimits(); m_pCpGraph->SetAuto(true); m_pCpGraph->SetInverted(false); m_pCpGraph->SetYTitle(tr("Cd'")); Curve * pTopCurve = m_pCpGraph->AddCurve(); Curve * pBotCurve = m_pCpGraph->AddCurve(); pTopCurve->SetTitle(tr("Top")); pBotCurve->SetTitle(tr("Bot")); double qrf = m_pXFoil->qinf; m_pXFoil->CreateXBL(x, nside1, nside2); //---- fill compressible ue arrays for (ibl=2; ibl<= nside1;ibl++) { y[ibl][1] = m_pXFoil->dis[ibl][1] / qrf/ qrf/ qrf; } for ( ibl=2; ibl<= nside2;ibl++) { y[ibl][2] = m_pXFoil->dis[ibl][2] / qrf/ qrf/ qrf; } for (i=2; i<=nside1-1; i++) { pTopCurve->AppendPoint(x[i][1], y[i][1]); } for (i=2; i<=nside2-1; i++) { pBotCurve->AppendPoint(x[i][2], y[i][2]); } m_pCpGraph->SetXScale(); SetFoilScale(); SetControls(); UpdateView(); } /** * The user has requested the plot of the Hk variable using current XFoil results. */ void QXDirect::OnHPlot() { if(!m_pXFoil->lvconv) return; int i; m_pCpGraph->SetYVariable(2); m_XFoilVar = 10; m_pCpGraph->DeleteCurves(); m_pCpGraph->ResetLimits(); m_pCpGraph->SetAuto(true); m_pCpGraph->SetInverted(false); m_pCpGraph->SetYTitle("Hk"); Curve * pTopCurve = m_pCpGraph->AddCurve(); Curve * pBotCurve = m_pCpGraph->AddCurve(); pTopCurve->SetTitle(tr("Top")); pBotCurve->SetTitle(tr("Bot")); double x[IVX][3],y[IVX][3]; int nside1, nside2; m_pXFoil->CreateXBL(x, nside1, nside2); m_pXFoil->FillHk(y, nside1, nside2); for (i=2; i<=nside1-1; i++) { pTopCurve->AppendPoint(x[i][1], y[i][1]); } for (i=2; i<=nside2-1; i++) { pBotCurve->AppendPoint(x[i][2], y[i][2]); } m_pCpGraph->SetXScale(); SetFoilScale(); SetControls(); UpdateView(); } /** * The user has requested the plot of the Rt variable using current XFoil results. */ void QXDirect::OnRtPlot() { if(!m_pXFoil->lvconv) return; int i; m_pCpGraph->SetYVariable(2); m_XFoilVar=5; m_pCpGraph->DeleteCurves(); m_pCpGraph->ResetLimits(); m_pCpGraph->SetAuto(true); m_pCpGraph->SetInverted(false); m_pCpGraph->SetYTitle("Re_Theta"); Curve * pTopCurve = m_pCpGraph->AddCurve(); Curve * pBotCurve = m_pCpGraph->AddCurve(); pTopCurve->SetTitle(tr("Top")); pBotCurve->SetTitle(tr("Bot")); double x[IVX][3],y[IVX][3]; int nside1, nside2; m_pXFoil->CreateXBL(x, nside1, nside2); m_pXFoil->FillRTheta(y, nside1, nside2); for (i=2; i<=nside1-1; i++) pTopCurve->AppendPoint(x[i][1], y[i][1]); for (i=2; i<=nside2-1; i++) pBotCurve->AppendPoint(x[i][2], y[i][2]); m_pCpGraph->SetXScale(); SetFoilScale(); SetControls(); UpdateView(); } /** * The user has requested the plot of the RtL variable using current XFoil results. */ void QXDirect::OnRtLPlot() { if(!m_pXFoil->lvconv) return; int i; m_pCpGraph->SetYVariable(2); m_XFoilVar=4; m_pCpGraph->DeleteCurves(); m_pCpGraph->ResetLimits(); m_pCpGraph->SetAuto(true); m_pCpGraph->SetInverted(false); m_pCpGraph->SetYTitle("Re_Theta"); Curve * pTopCurve = m_pCpGraph->AddCurve(); Curve * pBotCurve = m_pCpGraph->AddCurve(); pTopCurve->SetTitle(tr("Top")); pBotCurve->SetTitle(tr("Bot")); double x[IVX][3],y[IVX][3]; int nside1, nside2; m_pXFoil->CreateXBL(x, nside1, nside2); m_pXFoil->FillRTheta(y, nside1, nside2); for (i=2; i<=nside1-1; i++){ if (y[i][1]>0.0) y[i][1] = log10( y[i][1] ); else y[i][1] = 0.0; pTopCurve->AppendPoint(x[i][1], y[i][1]); } for (i=2; i<=nside2-1; i++){ if (y[i][2]>0.0) y[i][2] = log10( y[i][2] ); else y[i][2] = 0.0; pBotCurve->AppendPoint(x[i][2], y[i][2]); } m_pCpGraph->SetXScale(); SetFoilScale(); SetControls(); UpdateView(); } /** * The user has requested the plot of the Ue variable using current XFoil results. */ void QXDirect::OnUePlot() { if(!m_pXFoil->lvconv) return; int i; double x[IVX][3],y[IVX][3]; double uei; int nside1, nside2, ibl; m_pCpGraph->SetYVariable(2); m_XFoilVar = 9; m_pCpGraph->DeleteCurves(); m_pCpGraph->ResetLimits(); m_pCpGraph->SetAuto(true); m_pCpGraph->SetInverted(false); m_pCpGraph->SetYTitle("Ue/Vinf"); Curve * pTopCurve = m_pCpGraph->AddCurve(); Curve * pBotCurve = m_pCpGraph->AddCurve(); pTopCurve->SetTitle(tr("Top")); pBotCurve->SetTitle(tr("Bot")); m_pXFoil->CreateXBL(x, nside1, nside2); //---- fill compressible ue arrays for (ibl=2; ibl<= nside1;ibl++) { uei = m_pXFoil->uedg[ibl][1]; y[ibl][1] = uei * (1.0-m_pXFoil->tklam) / (1.0-m_pXFoil->tklam*(uei/m_pXFoil->qinf)*(uei/m_pXFoil->qinf)); } for (ibl=2; ibl<= nside2;ibl++) { uei = m_pXFoil->uedg[ibl][2]; y[ibl][2] = uei * (1.0-m_pXFoil->tklam) / (1.0-m_pXFoil->tklam*(uei/m_pXFoil->qinf)*(uei/m_pXFoil->qinf)); } for (i=2; i<=nside1-1; i++) { pTopCurve->AppendPoint(x[i][1], y[i][1]); } for (i=2; i<=nside2-1; i++) { pBotCurve->AppendPoint(x[i][2], y[i][2]); } m_pCpGraph->SetXScale(); SetFoilScale(); SetControls(); UpdateView(); } /** * The user has requested to switch to the two polar graph view */ void QXDirect::OnCouplePolarGraphs() { m_iPlrView = TWOPOLARGRAPHS; m_bPolarView = true; SetControls(); UpdateView(); } /** * The user has requested to switch to the Cp graph view */ void QXDirect::OnCpGraph() { m_bPolarView = false; if(m_pCpGraph->GetYVariable()!=0) { // m_pCpGraph->ResetLimits(); m_pCpGraph->SetAuto(true); m_pCpGraph->SetYVariable(0); } m_pCpGraph->SetYVariable(0); m_pCpGraph->SetInverted(true); CreateOppCurves(); m_pCpGraph->SetYTitle(tr("Cp")); SetControls(); m_pCpGraph->SetXScale(); SetFoilScale(); UpdateView(); } /** * The user has requested an edition of the settings of the Cp graph */ void QXDirect::OnCpGraphSettings() { QGraph graph; graph.CopySettings(m_pCpGraph); GraphDlg grDlg((MainFrame*)s_pMainFrame); grDlg.m_pMemGraph = m_pCurGraph; grDlg.m_pGraph = &graph; grDlg.SetParams(); if(grDlg.exec() == QDialog::Accepted) { m_pCpGraph->CopySettings(&graph); } UpdateView(); } /** * The user has toggled the request for the display of the inviscid Cp curve */ void QXDirect::OnCpi() { m_bShowInviscid = !m_bShowInviscid; CreateOppCurves(); SetControls(); UpdateView(); } /** * The user has toggled the switch for the display of the current OpPoint only */ void QXDirect::OnCurOppOnly() { m_bCurOppOnly = !m_bCurOppOnly; ((MainFrame*)s_pMainFrame)->showCurOppOnly->setChecked(m_bCurOppOnly); if(m_pCurOpp) m_pCurOpp->m_bIsVisible = true; CreateOppCurves(); SetAnalysisParams(); UpdateView(); } /** * The user has changed the color of the current curve */ void QXDirect::OnCurveColor() { QColor Color = QColorDialog::getColor(m_CurveColor); if(Color.isValid()) m_CurveColor = Color; FillComboBoxes(); UpdateCurveStyle(); } /** * The user has changed the style of the current curve */ void QXDirect::OnCurveStyle(int index) { m_CurveStyle = index; FillComboBoxes(); UpdateCurveStyle(); } /** * The user has changed the width of the current curve */ void QXDirect::OnCurveWidth(int index) { m_CurveWidth = index+1; FillComboBoxes(); UpdateCurveStyle(); } /** * The user has requested to define a new polar */ void QXDirect::OnDefinePolar() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(!MainFrame::s_pCurFoil) return; FoilPolarDlg fpDlg(pMainFrame); fpDlg.m_NCrit = m_NCrit; fpDlg.m_XBotTr = m_XBotTr; fpDlg.m_XTopTr = m_XTopTr; fpDlg.m_Mach = m_Mach; fpDlg.m_Reynolds = m_Reynolds; fpDlg.m_PolarType = m_PolarType; fpDlg.m_ASpec = m_ASpec; fpDlg.InitDialog(); int res = fpDlg.exec(); if (res == QDialog::Accepted) { m_pCurPolar = new Polar(); m_pCurPolar->m_FoilName = MainFrame::s_pCurFoil->m_FoilName; m_pCurPolar->m_PlrName = fpDlg.m_PlrName; m_pCurPolar->m_bIsVisible = true; m_pCurPolar->m_PolarType = fpDlg.m_PolarType; switch (m_pCurPolar->m_PolarType) { case FIXEDSPEEDPOLAR: m_pCurPolar->m_MaType = 1; m_pCurPolar->m_ReType = 1; break; case FIXEDLIFTPOLAR: m_pCurPolar->m_MaType = 2; m_pCurPolar->m_ReType = 2; break; case RUBBERCHORDPOLAR: m_pCurPolar->m_MaType = 1; m_pCurPolar->m_ReType = 3; break; case FIXEDAOAPOLAR: m_pCurPolar->m_MaType = 1; m_pCurPolar->m_ReType = 1; break; default: m_pCurPolar->m_ReType = 1; m_pCurPolar->m_MaType = 1; break; } m_PolarType = fpDlg.m_PolarType; m_NCrit = fpDlg.m_NCrit; m_XBotTr = fpDlg.m_XBotTr; m_XTopTr = fpDlg.m_XTopTr; m_Mach = fpDlg.m_Mach; m_Reynolds = fpDlg.m_Reynolds; m_ASpec = fpDlg.m_ASpec; m_pCurPolar->m_Reynolds = fpDlg.m_Reynolds; m_pCurPolar->m_Mach = fpDlg.m_Mach; m_pCurPolar->m_ASpec = fpDlg.m_ASpec; m_pCurPolar->m_ACrit = fpDlg.m_NCrit; m_pCurPolar->m_XTop = fpDlg.m_XTopTr; m_pCurPolar->m_XBot = fpDlg.m_XBotTr; m_pCurPolar->m_Color = pMainFrame->GetColor(1); m_pCurPolar = pMainFrame->AddPolar(m_pCurPolar); SetPolar(m_pCurPolar); pMainFrame->UpdatePolars(); SetBufferFoil(); UpdateView(); MainFrame::SetSaveState(false); } SetControls(); } /** * The user has requested the deletion of the current Foil. */ void QXDirect::OnDeleteCurFoil() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; MainFrame::s_pCurFoil = pMainFrame->DeleteFoil(MainFrame::s_pCurFoil,true); m_pCurOpp = NULL; m_pCurPolar = NULL; pMainFrame->UpdateFoils(); if(m_bPolarView) CreatePolarCurves(); else CreateOppCurves(); MainFrame::SetSaveState(false); SetControls(); UpdateView(); } /** * The user has requested the deletion of the current OpPoint. */ void QXDirect::OnDelCurOpp() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; OpPoint* pOpPoint = m_pCurOpp; StopAnimate(); if (!pOpPoint) return; QString strong,str; strong = tr("Are you sure you want to delete the Operating Point\n"); if(m_pCurPolar->m_PolarType!=FIXEDAOAPOLAR) str = QString("Alpha = %1").arg(pOpPoint->Alpha,0,'f',2); else str = QString("Reynolds = %1").arg(pOpPoint->Reynolds,0,'f',0); strong += str; strong += " ?"; if (QMessageBox::Yes == QMessageBox::question(pMainFrame, tr("Question"), strong, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel)) { pMainFrame->RemoveOpPoint(true); pMainFrame->UpdateOpps(); SetOpp(); UpdateView(); } SetControls(); } /** * The user has requested the deletion of the current Polar. */ void QXDirect::OnDeleteCurPolar() { if(!m_pCurPolar) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; OpPoint *pOpPoint; int l; QString str; str = tr("Are you sure you want to delete the polar :\n ") + m_pCurPolar->m_PlrName; str += tr("\n and all the associated OpPoints ?"); if (QMessageBox::Yes == QMessageBox::question(pMainFrame, tr("Question"), str, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel)) { // start by removing all OpPoints for (l=m_poaOpp->size()-1; l>=0; l--) { pOpPoint = (OpPoint*)m_poaOpp->at(l); if (pOpPoint->m_strPlrName == m_pCurPolar->m_PlrName && pOpPoint->m_strFoilName == MainFrame::s_pCurFoil->m_FoilName) { m_poaOpp->removeAt(l); delete pOpPoint; } } // then remove the CPolar and update views for (l=m_poaPolar->size()-1; l>=0; l--) { if(m_pCurPolar == m_poaPolar->at(l)) { m_poaPolar->removeAt(l); delete m_pCurPolar; break; } } m_pCurOpp = NULL; m_pCurPolar = NULL; } pMainFrame->UpdatePolars(); SetPolar(); MainFrame::SetSaveState(false); UpdateView(); } /** * The user has requested the deletion of the OpPoints associated to the current Polar. */ void QXDirect::OnDeletePolarOpps() { if(!MainFrame::s_pCurFoil || !m_pCurPolar) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; OpPoint *pOpp; for(int i=m_poaOpp->size()-1; i>=0; i--) { pOpp = (OpPoint*)m_poaOpp->at(i); if(pOpp->m_strFoilName==MainFrame::s_pCurFoil->m_FoilName && pOpp->m_strPlrName==m_pCurPolar->m_PlrName) { m_poaOpp->removeAt(i); delete pOpp; } } m_pCurOpp=NULL; MainFrame::SetSaveState(false); pMainFrame->UpdateOpps(); if(!m_bPolarView) CreateOppCurves(); SetCurveParams(); SetControls(); UpdateView(); } /** * The user has requested the deletion of the OpPoints associated to the current Foil. */ void QXDirect::OnDeleteFoilOpps() { if(!MainFrame::s_pCurFoil || !m_pCurPolar) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; OpPoint *pOpp; for(int i=m_poaOpp->size()-1; i>=0; i--) { pOpp = (OpPoint*)m_poaOpp->at(i); if(pOpp->m_strFoilName==MainFrame::s_pCurFoil->m_FoilName) { m_poaOpp->removeAt(i); delete pOpp; } } m_pCurOpp = NULL; MainFrame::SetSaveState(false); pMainFrame->UpdateOpps(); if(!m_bPolarView) CreateOppCurves(); SetCurveParams(); SetControls(); UpdateView(); } /** * The user has requested the deletion of the Polars associated to the current Foil. */ void QXDirect::OnDeleteFoilPolars() { if(!MainFrame::s_pCurFoil) return; MainFrame * pMainFrame = (MainFrame*) s_pMainFrame; int l; OpPoint *pOpPoint; StopAnimate(); QString strong; strong = tr("Are you sure you want to delete polars and OpPoints\n"); strong +=tr("associated to ")+MainFrame::s_pCurFoil->m_FoilName + " ?"; if (QMessageBox::Yes == QMessageBox::question(pMainFrame, tr("Question"), strong, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel)) { // start by removing all OpPoints for (l=m_poaOpp->size()-1; l>=0; l--) { pOpPoint = (OpPoint*)m_poaOpp->at(l); if (pOpPoint->m_strFoilName == MainFrame::s_pCurFoil->m_FoilName) { m_poaOpp->removeAt(l); delete pOpPoint; } } // then remove CPolar and update views Polar* pPolar; for (l=m_poaPolar->size()-1; l>=0; l--) { pPolar = (Polar*)m_poaPolar->at(l); if (pPolar->m_FoilName == MainFrame::s_pCurFoil->m_FoilName) { m_poaPolar->removeAt(l); delete pPolar; } } m_pCurOpp = NULL; } m_pCurPolar = NULL; SetPolar(); pMainFrame->UpdatePolars(); MainFrame::SetSaveState(false); SetControls(); UpdateView(); } /** * The user has requested a local refinement of the panels of the current foil */ void QXDirect::OnCadd() { StopAnimate(); MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(!MainFrame::s_pCurFoil) return; void* ptr = m_pCurOpp; m_pCurOpp = NULL; CreateOppCurves(); bool bPressure = m_bPressure; bool bBL = m_bBL; bool bState = m_bShowPanels; m_bPressure = false; m_bBL = false; OnOpPoints(); CAddDlg caDlg(pMainFrame); caDlg.m_pBufferFoil = &m_BufferFoil; caDlg.m_pMemFoil = MainFrame::s_pCurFoil; caDlg.m_pXDirect = this; caDlg.m_pAFoil = NULL; caDlg.InitDialog(); m_bShowPanels = true; UpdateView(); if(QDialog::Accepted == caDlg.exec()) { Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(&m_BufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 1; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; m_pCurOpp = (OpPoint*)ptr; if(!pMainFrame->SetModFoil(pNewFoil)) SetBufferFoil(); pMainFrame->UpdateFoils(); } else { m_pCurOpp = (OpPoint*)ptr; SetBufferFoil(); m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil); } m_bShowPanels = bState; m_bPressure = bPressure; m_bBL = bBL; UpdateView(); } /** * The user has requested that the foil be derotated */ void QXDirect::OnDerotateFoil() { if(!MainFrame::s_pCurFoil) return; QString str; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; StopAnimate(); Foil *pNewFoil = new Foil; pNewFoil->CopyFoil(MainFrame::s_pCurFoil); double angle = pNewFoil->DeRotate(); str = QString(tr("The foil has been de-rotated by %1 degrees")).arg(angle,6,'f',3); pMainFrame->statusBar()->showMessage(str); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; pNewFoil->m_FoilColor = pMainFrame->GetColor(0); if(!pMainFrame->SetModFoil(pNewFoil)) SetBufferFoil(); pMainFrame->UpdateFoils(); MainFrame::SetSaveState(false); UpdateView(); } /** * The user has requested to modify the parameters of the active polar */ void QXDirect::OnEditCurPolar() { if (!m_pCurPolar) return; Polar MemPolar; MemPolar.Copy(m_pCurPolar); EditPlrDlg epDlg((MainFrame*)s_pMainFrame); epDlg.m_pPolar = m_pCurPolar; epDlg.m_pXDirect = this; epDlg.move(EditPlrDlg::s_WindowPos); epDlg.resize(EditPlrDlg::s_WindowSize); if(EditPlrDlg::s_bWindowMaximized) epDlg.setWindowState(Qt::WindowMaximized); epDlg.InitDialog(); bool bPoints = m_pCurPolar->m_bShowPoints; m_pCurPolar->m_bShowPoints = true; CreatePolarCurves(); UpdateView(); if(epDlg.exec() == QDialog::Accepted) { MainFrame::SetSaveState(false); } else { m_pCurPolar->Copy(&MemPolar); } m_pCurPolar->m_bShowPoints = bPoints; CreatePolarCurves(); UpdateView(); } /** * The user has requested the export of the current results stored in the XFoil object to a text file */ void QXDirect::OnExportCurXFoilResults() { if(!m_pXFoil->lvconv) return; if(!MainFrame::s_pCurFoil) return; QString FileName, OutString, strong; double x[IVX][3],Hk[IVX][3],UeVinf[IVX][3], Cf[IVX][3], Cd[IVX][3], AA0[IVX][3]; double RTheta[IVX][3], DStar[IVX][3], Theta[IVX][3]; double uei; double que = 0.5*m_pXFoil->qinf*m_pXFoil->qinf; double qrf = m_pXFoil->qinf; int nside1, nside2, ibl; int type = 1; FileName = MainFrame::s_pCurFoil->m_FoilName; FileName.replace("/", " "); FileName = QFileDialog::getSaveFileName(this, tr("Export Current XFoil Results"), MainFrame::s_LastDirName, tr("Text File (*.txt);;Comma Separated Values (*.csv)")); if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); pos = FileName.lastIndexOf(".csv"); if(pos>0) type = 2; QFile DestFile(FileName); if (!DestFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&DestFile); out << (MainFrame::versionName()); out << ("\n"); strong = m_pXFoil->m_FoilName+ "\n"; out << (strong); if(type==1) strong = QString("Alpha = %1, Re = %2, Ma= %3, ACrit=%4\n\n") .arg(m_pXFoil->alfa*180./PI, 5, 'f',1) .arg(m_pXFoil->reinf1, 8, 'f',0) .arg(m_pXFoil->minf1, 6, 'f',4) .arg(m_pXFoil->acrit, 4, 'f',1); else strong = QString("Alpha =, %1,Re =, %3,Ma=, %3,ACrit =,%4\n\n") .arg(m_pXFoil->alfa*180./PI, 5, 'f',1) .arg(m_pXFoil->reinf1, 8, 'f',0) .arg(m_pXFoil->minf1, 6, 'f',4) .arg(m_pXFoil->acrit, 4, 'f',1); out << (strong); m_pXFoil->CreateXBL(x, nside1, nside2); //write top first m_pXFoil->FillHk(Hk, nside1, nside2); for (ibl=2; ibl<= nside1;ibl++) { uei = m_pXFoil->uedg[ibl][1]; UeVinf[ibl][1] = uei * (1.0-m_pXFoil->tklam) / (1.0-m_pXFoil->tklam*(uei/m_pXFoil->qinf)*(uei/m_pXFoil->qinf)); } for (ibl=2; ibl<= nside2;ibl++) { uei = m_pXFoil->uedg[ibl][2]; UeVinf[ibl][2] = uei * (1.0-m_pXFoil->tklam) / (1.0-m_pXFoil->tklam*(uei/m_pXFoil->qinf)*(uei/m_pXFoil->qinf)); } //---- fill compressible ue arrays for (ibl=2; ibl<= nside1;ibl++) Cf[ibl][1] = m_pXFoil->tau[ibl][1] / que; for (ibl=2; ibl<= nside2;ibl++) Cf[ibl][2] = m_pXFoil->tau[ibl][2] / que; //---- fill compressible ue arrays for (ibl=2; ibl<= nside1;ibl++) Cd[ibl][1] = m_pXFoil->dis[ibl][1] / qrf/ qrf/ qrf; for (ibl=2; ibl<= nside2;ibl++) Cd[ibl][2] = m_pXFoil->dis[ibl][2] / qrf/ qrf/ qrf; //NPlot for (ibl=2; ibl< nside1;ibl++) AA0[ibl][1] = m_pXFoil->ctau[ibl][1]; for (ibl=2; ibl< nside2;ibl++) AA0[ibl][2] = m_pXFoil->ctau[ibl][2]; m_pXFoil->FillRTheta(RTheta, nside1, nside2); for (ibl=2; ibl<= nside1; ibl++) { DStar[ibl][1] = m_pXFoil->dstr[ibl][1]; Theta[ibl][1] = m_pXFoil->thet[ibl][1]; } for (ibl=2; ibl<= nside2; ibl++) { DStar[ibl][2] = m_pXFoil->dstr[ibl][2]; Theta[ibl][2] = m_pXFoil->thet[ibl][2]; } out << tr("\nTop Side\n"); if(type==1) OutString = QString(tr(" x Hk Ue/Vinf Cf Cd A/A0 D* Theta CTq\n")); else OutString = QString(tr("x,Hk,Ue/Vinf,Cf,Cd,A/A0,D*,Theta,CTq\n")); out << (OutString); for (ibl=2; iblctq[ibl][1],8,'f',5); else OutString = QString("%1, %2, %3, %4, %5, %6, %7, %8, %9\n") .arg(x[ibl][1]) .arg(Hk[ibl][1],8,'f',5) .arg(UeVinf[ibl][1],8,'f',5) .arg(Cf[ibl][1],8,'f',5) .arg(Cd[ibl][1],8,'f',5) .arg(AA0[ibl][1],8,'f',5) .arg(DStar[ibl][1],8,'f',5) .arg(Theta[ibl][1],8,'f',5) .arg(m_pXFoil->ctq[ibl][1],8,'f',5); out << (OutString); } out << tr("\n\nBottom Side\n"); if(type==1) OutString = QString(tr(" x Hk Ue/Vinf Cf Cd A/A0 D* Theta CTq\n")); else OutString = QString(tr("x,Hk,Ue/Vinf,Cf,Cd,A/A0,D*,Theta,CTq\n")); out << (OutString); for (ibl=2; iblctq[ibl][2],8,'f',5); else OutString = QString("%1, %2, %3, %4, %5, %6, %7, %8, %9\n") .arg(x[ibl][2]) .arg(Hk[ibl][2],8,'f',5) .arg(UeVinf[ibl][2],8,'f',5) .arg(Cf[ibl][2],8,'f',5) .arg(Cd[ibl][2],8,'f',5) .arg(AA0[ibl][2],8,'f',5) .arg(DStar[ibl][2],8,'f',5) .arg(Theta[ibl][2],8,'f',5) .arg(m_pXFoil->ctq[ibl][2],8,'f',5); out << (OutString); } DestFile.close(); } /** * The user has requested the export of all polars to text files */ void QXDirect::OnExportAllPolars() { QString FileName, DirName; QFile XFile; QTextStream out(&XFile); //select the directory for output DirName = QFileDialog::getExistingDirectory(this, tr("Export Directory"), MainFrame::s_LastDirName); Polar *pPolar; for(int l=0; lsize(); l++) { pPolar = (Polar*)m_poaPolar->at(l); FileName = DirName + "/" + pPolar->m_FoilName + "_" + pPolar->m_PlrName; if(MainFrame::s_ExportFileType==TXT) FileName += ".txt"; else FileName += ".csv"; XFile.setFileName(FileName); if (XFile.open(QIODevice::WriteOnly | QIODevice::Text)) { pPolar->ExportPolar(out, MainFrame::s_ExportFileType); XFile.close(); } } } /** * The user has requested the export of the current foil to a text file */ void QXDirect::OnExportCurFoil() { if(!MainFrame::s_pCurFoil) return; QString FileName; FileName = MainFrame::s_pCurFoil->m_FoilName; FileName.replace("/", " "); FileName = QFileDialog::getSaveFileName(this, tr("Export Foil"), MainFrame::s_LastDirName+"/"+FileName+".dat", tr("Foil File (*.dat)")); if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&XFile); MainFrame::s_pCurFoil->ExportFoil(out); XFile.close(); } /** * The user has requested the export of the current OpPoint to a text file */ void QXDirect::OnExportCurOpp() { if(!MainFrame::s_pCurFoil || !m_pCurPolar || !m_pCurOpp) return; QString FileName; QString filter; if(MainFrame::s_ExportFileType==TXT) filter = "Text File (*.txt)"; else filter = "Comma Separated Values (*.csv)"; FileName = QFileDialog::getSaveFileName(this, tr("Export OpPoint"), MainFrame::s_LastDirName , tr("Text File (*.txt);;Comma Separated Values (*.csv)"), &filter); if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); pos = FileName.lastIndexOf(".csv"); if (pos>0) MainFrame::s_ExportFileType = CSV; else MainFrame::s_ExportFileType = TXT; QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&XFile); m_pCurOpp->ExportOpp(out, MainFrame::versionName(), MainFrame::s_ExportFileType); XFile.close(); } /** * The user has requested the export of the OpPoints associated to the current Polar to a text file */ void QXDirect::OnExportPolarOpps() { MainFrame * pMainFrame = (MainFrame*)s_pMainFrame; if(!m_poaPolar->size()) { QMessageBox::warning(pMainFrame, tr("Warning"), "No Operating Points to export to file"); return; } int i,j; QString FileName; QString filter; if(MainFrame::s_ExportFileType==TXT) filter = "Text File (*.txt)"; else filter = "Comma Separated Values (*.csv)"; FileName = QFileDialog::getSaveFileName(this, tr("Export OpPoint"), MainFrame::s_LastDirName , tr("Text File (*.txt);;Comma Separated Values (*.csv)"), &filter); if(!FileName.length()) return; if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); pos = FileName.lastIndexOf(".csv"); if (pos>0) MainFrame::s_ExportFileType = CSV; else MainFrame::s_ExportFileType = TXT; QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&XFile); QString Header, strong; out<m_FoilName + "\n"; out << strong; OpPoint *pOpPoint; for (i=0; isize(); i++) { pOpPoint = (OpPoint*)m_poaOpp->at(i); if(pOpPoint->m_strFoilName == m_pCurPolar->m_FoilName && pOpPoint->m_strPlrName == m_pCurPolar->m_PlrName ) { if(MainFrame::s_ExportFileType==TXT) strong = QString("Reynolds = %1 Mach = %2 NCrit = %3\n") .arg(pOpPoint->Reynolds, 7, 'f', 0) .arg(pOpPoint->Mach, 4,'f',0) .arg(pOpPoint->ACrit, 3, 'f',1); else strong = QString("Reynolds =, %1,Mach =, %2,NCrit =, %3\n") .arg(pOpPoint->Reynolds, 7, 'f', 0) .arg(pOpPoint->Mach, 4,'f',0) .arg(pOpPoint->ACrit, 3, 'f',1); out<Alpha,7,'f',3) .arg(pOpPoint->Cd,9,'f',3) .arg(pOpPoint->Cl,7,'f',3) .arg(pOpPoint->Cm,7,'f',3) .arg(pOpPoint->Xtr1,7,'f',3) .arg(pOpPoint->Xtr2,7,'f',3) .arg(pOpPoint->m_TEHMom,7,'f',4) .arg(pOpPoint->Cpmn,7,'f',4); else strong = QString("%1,%2,%3,%4,%5,%6,%7,%8\n") .arg(pOpPoint->Alpha,7,'f',3) .arg(pOpPoint->Cd,9,'f',3) .arg(pOpPoint->Cl,7,'f',3) .arg(pOpPoint->Cm,7,'f',3) .arg(pOpPoint->Xtr1,7,'f',3) .arg(pOpPoint->Xtr2,7,'f',3) .arg(pOpPoint->m_TEHMom,7,'f',4) .arg(pOpPoint->Cpmn,7,'f',4); out<n; j++) { if(pOpPoint->m_bViscResults) { if(MainFrame::s_ExportFileType==TXT) strong = QString("%1 %2\n").arg(pOpPoint->Cpi[j], 7,'f',4).arg(pOpPoint->Cpv[j], 7, 'f',4); else strong = QString("%1,%2\n").arg(pOpPoint->Cpi[j], 7,'f',4).arg(pOpPoint->Cpv[j], 7, 'f',4); } else { strong=QString("%1\n").arg(pOpPoint->Cpi[j],7,'f',4); } out << strong; } out << "\n\n"; } } XFile.close(); } /** * The user has requested the export of the current Polar to a text file */ void QXDirect::OnExportCurPolar() { if(!MainFrame::s_pCurFoil || !m_pCurPolar) return; QString FileName, filter; if(MainFrame::s_ExportFileType==TXT) filter = "Text File (*.txt)"; else filter = "Comma Separated Values (*.csv)"; FileName = m_pCurPolar->m_PlrName; FileName.replace("/", " "); FileName = QFileDialog::getSaveFileName(this, tr("Export Polar"), MainFrame::s_LastDirName + "/"+FileName, tr("Text File (*.txt);;Comma Separated Values (*.csv)"), &filter); if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); pos = FileName.lastIndexOf(".csv"); if (pos>0) MainFrame::s_ExportFileType = CSV; else MainFrame::s_ExportFileType = TXT; QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&XFile); m_pCurPolar->ExportPolar(out, MainFrame::s_ExportFileType); XFile.close(); } /** * The user has requested an edition of the current foil coordinates */ void QXDirect::OnFoilCoordinates() { if(!MainFrame::s_pCurFoil) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; StopAnimate(); bool bState = m_bShowPanels;//save current view setting void* ptr = m_pCurOpp; m_pCurOpp = NULL; CreateOppCurves(); bool bPressure = m_bPressure; bool bBL = m_bBL; m_bPressure = false; m_bBL = false; m_bPolarView = false; UpdateView(); bool bFlap = m_BufferFoil.m_bTEFlap; double FlapAngle = m_BufferFoil.m_TEFlapAngle; double Xh = m_BufferFoil.m_TEXHinge; double Yh = m_BufferFoil.m_TEXHinge; m_BufferFoil.m_bTEFlap = false; // SetFoilFlap(&m_BufferFoil); FoilCoordDlg fcoDlg(pMainFrame); fcoDlg.m_pXDirect = this; fcoDlg.m_pAFoil = NULL; fcoDlg.m_pMemFoil = MainFrame::s_pCurFoil; fcoDlg.m_pBufferFoil = &m_BufferFoil; fcoDlg.InitDialog(); m_bShowPanels = true; UpdateView(); int res = fcoDlg.exec(); if(QDialog::Accepted == res) { m_BufferFoil.m_bTEFlap = bFlap; m_BufferFoil.m_TEFlapAngle = FlapAngle; m_BufferFoil.m_TEXHinge = Xh; m_BufferFoil.m_TEYHinge = Yh; Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(&m_BufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; m_pCurOpp = (OpPoint*)ptr; if(!pMainFrame->SetModFoil(pNewFoil)) SetBufferFoil(); pMainFrame->UpdateFoils(); } else { //reset everything m_pCurOpp = (OpPoint*)ptr; m_BufferFoil.m_bTEFlap = bFlap; m_BufferFoil.m_TEFlapAngle = FlapAngle; m_BufferFoil.m_TEXHinge = Xh; m_BufferFoil.m_TEYHinge = Yh; // SetFoilFlap(&m_BufferFoil); SetBufferFoil(); m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil); } m_BufferFoil.m_iHighLight = -1; m_bShowPanels = bState;//restore as it was m_bPressure = bPressure; m_bBL = bBL; UpdateView(); } /** * The user has requested to perform an edition of the current foil's thickness and camber properties. */ void QXDirect::OnFoilGeom() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(!MainFrame::s_pCurFoil) return; StopAnimate(); m_bPolarView = false; void* ptr = m_pCurOpp; m_pCurOpp = NULL; CreateOppCurves(); UpdateView(); FoilGeomDlg fgeDlg(pMainFrame); fgeDlg.m_pMemFoil = MainFrame::s_pCurFoil; fgeDlg.m_pBufferFoil = &m_BufferFoil; fgeDlg.m_pXDirect = this; fgeDlg.m_pAFoil = NULL; fgeDlg.InitDialog(); if(fgeDlg.exec() == QDialog::Accepted) { Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(&m_BufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; m_pCurOpp = (OpPoint*)ptr; if(!pMainFrame->SetModFoil(pNewFoil)) SetBufferFoil(); pMainFrame->UpdateFoils(); } else { m_pCurOpp = (OpPoint*)ptr; SetBufferFoil(); m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil); } UpdateView(); } /** * The user has requested an edition of the current graph's settings */ void QXDirect::OnGraphSettings() { QGraph *pGraph = NULL; pGraph = m_pCurGraph; if(!pGraph) return; GraphDlg grDlg((MainFrame*)s_pMainFrame); if(!m_bPolarView) { grDlg.m_iGraphType = 51; } else { grDlg.m_iGraphType = 52; } QGraph graph; graph.CopySettings(pGraph); grDlg.m_pMemGraph = &graph; grDlg.m_pGraph = pGraph; grDlg.SetParams(); int res = grDlg.exec(); if(res == QDialog::Accepted) { if(!m_bPolarView) { if(m_pCpGraph->GetYVariable() == 0 || m_pCpGraph->GetYVariable()>=2) { m_pCpGraph->SetYTitle(tr("Cp")); m_pCpGraph->SetInverted(true); } else { m_pCpGraph->SetYTitle(tr("Q")); m_pCpGraph->SetInverted(false); } m_pCpGraph->ResetYLimits(); CreateOppCurves(); } else { if(m_PlrGraph == pGraph) { SetGraphTitles(m_PlrGraph); } else if(m_PlrGraph+1 == pGraph) { SetGraphTitles(m_PlrGraph+1); } else if(m_PlrGraph+2 == pGraph) { SetGraphTitles(m_PlrGraph+2); } else if(m_PlrGraph+3 == pGraph) { SetGraphTitles(m_PlrGraph+3); } else if(m_PlrGraph+4 == pGraph) { SetGraphTitles(m_PlrGraph+4); } if(grDlg.m_bVariableChanged) { pGraph->SetAuto(true); pGraph->SetAutoYMinUnit(true); } CreatePolarCurves(); } } else { pGraph->CopySettings(&graph); } UpdateView(); } /** * The user has requested the highlighting of the current OpPoint on the polar curves */ void QXDirect::OnHighlightOpp() { if(!m_bPolarView) return; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; m_bHighlightOpp = !m_bHighlightOpp; pMainFrame->highlightOppAct->setChecked(m_bHighlightOpp); m_PlrGraph[0].m_bHighlightPoint = m_bHighlightOpp; m_PlrGraph[2].m_bHighlightPoint = m_bHighlightOpp; m_PlrGraph[1].m_bHighlightPoint = m_bHighlightOpp; m_PlrGraph[3].m_bHighlightPoint = m_bHighlightOpp; m_PlrGraph[4].m_bHighlightPoint = m_bHighlightOpp; CreatePolarCurves(); UpdateView(); } /** * The user has requested to hide all OpPoints */ void QXDirect::OnHideAllOpps() { OpPoint *pOpp; for (int i=0; isize(); i++) { pOpp = (OpPoint*)m_poaOpp->at(i); pOpp->m_bIsVisible = false; } MainFrame::SetSaveState(false); if(!m_bPolarView) CreateOppCurves(); SetAnalysisParams(); UpdateView(); } /** * The user has requested to hide all polar curves */ void QXDirect::OnHideAllPolars() { Polar *pPolar; for (int i=0; isize(); i++) { pPolar = (Polar*)m_poaPolar->at(i); pPolar->m_bIsVisible = false; } MainFrame::SetSaveState(false); CreatePolarCurves(); SetCurveParams(); UpdateView(); } /** * The user has requested to hide all polar curves associated to the current Foil */ void QXDirect::OnHideFoilPolars() { if(!MainFrame::s_pCurFoil) return; Polar *pPolar; for (int i=0; isize(); i++) { pPolar = (Polar*)m_poaPolar->at(i); if(pPolar->m_FoilName == MainFrame::s_pCurFoil->m_FoilName) { pPolar->m_bIsVisible = false; } } MainFrame::SetSaveState(false); CreatePolarCurves(); SetCurveParams(); UpdateView(); } /** * The user has requested to hide all OpPoint curves associated to the current Foil */ void QXDirect::OnHideFoilOpps() { if(!MainFrame::s_pCurFoil || !m_pCurPolar) return; OpPoint *pOpp; for(int i=0; isize(); i++) { pOpp = (OpPoint*)m_poaOpp->at(i); if(pOpp->m_strFoilName==MainFrame::s_pCurFoil->m_FoilName) pOpp->m_bIsVisible = false; } MainFrame::SetSaveState(false); if(!m_bPolarView) CreateOppCurves(); SetCurveParams(); UpdateView(); } /** * The user has requested to hide all OpPoint curves associated to the current Polar */ void QXDirect::OnHidePolarOpps() { if(!MainFrame::s_pCurFoil || !m_pCurPolar) return; OpPoint *pOpp; for(int i=0; isize(); i++) { pOpp = (OpPoint*)m_poaOpp->at(i); if(pOpp->m_strFoilName==MainFrame::s_pCurFoil->m_FoilName && pOpp->m_strPlrName==m_pCurPolar->m_PlrName) pOpp->m_bIsVisible = false; } MainFrame::SetSaveState(false); if(!m_bPolarView) CreateOppCurves(); SetCurveParams(); UpdateView(); } /** * The user has requested to import a polar from a text file. * The Polar will be added to the array only if a Foil with the parent name exists. */ void QXDirect::OnImportXFoilPolar() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; Polar *pPolar = new Polar; double Re, alpha, CL, CD, CDp, CM, Xt, Xb,Cpmn, HMom; QString FoilName, PathName, strong, str; QByteArray textline; const char *text; PathName = QFileDialog::getOpenFileName(pMainFrame, tr("Open File"), MainFrame::s_LastDirName, tr("XFoil Polar Format (*.*)")); if(!PathName.length()) return ; int pos = PathName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = PathName.left(pos); QFile XFile(PathName); if (!XFile.open(QIODevice::ReadOnly)) { QString strange = tr("Could not read the file\n")+PathName; QMessageBox::warning(pMainFrame, tr("Warning"), strange); return; } QTextStream in(&XFile); int res, Line; bool bOK, bOK2, bRead; Line = 0; bRead = ReadAVLString(in, Line, strong);// XFoil or XFLR5 version bRead = ReadAVLString(in, Line, strong);// Foil Name FoilName = strong.right(strong.length()-22); FoilName = FoilName.trimmed(); if(!MainFrame::foil(FoilName)) { str = tr("No Foil with the name ")+FoilName; str+= tr("\ncould be found. The polar(s) will not be stored"); delete pPolar; QMessageBox::warning(pMainFrame, tr("Warning"), str); return; } pPolar->m_FoilName = FoilName; bRead = ReadAVLString(in, Line, strong);// analysis type pPolar->m_ReType = strong.mid(0,2).toInt(&bOK); pPolar->m_MaType= strong.mid(2,2).toInt(&bOK2); if(!bOK || !bOK2) { str = QString("Error reading line %1: Unrecognized Mach and Reynolds type.\nThe polar(s) will not be stored").arg(Line); delete pPolar; QMessageBox::warning(pMainFrame, tr("Warning"), str); return; } if (pPolar->m_ReType ==1 && pPolar->m_MaType ==1) pPolar->m_PolarType = FIXEDSPEEDPOLAR; else if(pPolar->m_ReType ==2 && pPolar->m_MaType ==2) pPolar->m_PolarType = FIXEDLIFTPOLAR; else if(pPolar->m_ReType ==3 && pPolar->m_MaType ==1) pPolar->m_PolarType = RUBBERCHORDPOLAR; else pPolar->m_PolarType = FIXEDSPEEDPOLAR; bRead = ReadAVLString(in, Line, strong); if(strong.length() < 34) { str = QString("Error reading line %1. The polar(s) will not be stored").arg(Line); delete pPolar; QMessageBox::warning(pMainFrame, tr("Warning"), str); return; } pPolar->m_XTop = strong.mid(9,6).toDouble(&bOK); if(!bOK) { str = QString("Error reading Bottom Transition value at line %1. The polar(s) will not be stored").arg(Line); delete pPolar; QMessageBox::warning(pMainFrame, tr("Warning"), str); return; } pPolar->m_XTop = strong.mid(28,6).toDouble(&bOK); if(!bOK) { str = QString("Error reading Top Transition value at line %1. The polar(s) will not be stored").arg(Line); delete pPolar; QMessageBox::warning(pMainFrame, tr("Warning"), str); return; } // Mach Re NCrit bRead = ReadAVLString(in, Line, strong);// blank line if(strong.length() < 50) { str = QString("Error reading line %1. The polar(s) will not be stored").arg(Line); delete pPolar; QMessageBox::warning(pMainFrame, tr("Warning"), str); return; } pPolar->m_Mach = strong.mid(8,6).toDouble(&bOK); if(!bOK) { str = QString("Error reading Mach Number at line %1. The polar(s) will not be stored").arg(Line); delete pPolar; QMessageBox::warning(pMainFrame, tr("Warning"), str); return; } Re = strong.mid(24,10).toDouble(&bOK); if(!bOK) { str = QString("Error reading Reynolds Number at line %1. The polar(s) will not be stored").arg(Line); delete pPolar; QMessageBox::warning(pMainFrame, tr("Warning"), str); return; } Re *=1000000.0; pPolar->m_ACrit = strong.mid(52,8).toDouble(&bOK); if(!bOK) { str = QString("Error reading NCrit at line %1. The polar(s) will not be stored").arg(Line); delete pPolar; QMessageBox::warning(pMainFrame, tr("Warning"), str); return; } pPolar->m_Reynolds = Re; bRead = ReadAVLString(in, Line, strong);// column titles bRead = ReadAVLString(in, Line, strong);// underscores while( bRead) { bRead = ReadAVLString(in, Line, strong);// polar data if(bRead) { if(strong.length()) { textline = strong.toLatin1(); text = textline.constData(); res = sscanf(text, "%lf%lf%lf%lf%lf%lf%lf%lf%lf", &alpha, &CL, &CD, &CDp, &CM, &Xt, &Xb, &Cpmn, &HMom); if (res == 7) { pPolar->AddPoint(alpha, CD, CDp, CL, CM, Xt, Xb, 0.0, 0.0,Re,0.0); } else if(res == 9) { pPolar->AddPoint(alpha, CD, CDp, CL, CM, Xt, Xb, Cpmn, HMom,Re,0.0); } else { bRead = false; } } } } Re = pPolar->m_Reynolds/1000000.0; pPolar->m_PlrName = QString("T%1_Re%2_M%3") .arg(pPolar->m_PolarType) .arg(Re,0,'f',2) .arg(pPolar->m_Mach,0,'f',2); str = QString("_N%1").arg(pPolar->m_ACrit,0,'f',1); pPolar->m_PlrName += str + "_Imported"; pPolar->m_Color = pMainFrame->GetColor(1); m_pCurPolar = pMainFrame->AddPolar(pPolar); m_pCurOpp = NULL; SetPolar(); pMainFrame->UpdatePolars(); UpdateView(); MainFrame::SetSaveState(false); } /** * The user has requested to import a polar from a text file in JavaFoil format * The Polar will be added to the array only if a Foil with the parent name exists. * @todo Note: this option has not been tested in years... the JavaFoil format may have changed since */ void QXDirect::OnImportJavaFoilPolar() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QString FoilName; QString strong, str; QString PathName; bool bOK; QByteArray textline; const char *text; PathName = QFileDialog::getOpenFileName(pMainFrame, tr("Open File"), MainFrame::s_LastDirName, tr("JavaFoil Polar Format (*.*)")); if(!PathName.length()) return ; int pos = PathName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = PathName.left(pos); QFile XFile(PathName); if (!XFile.open(QIODevice::ReadOnly)) { QString strange = tr("Could not read the file\n")+PathName; QMessageBox::warning(pMainFrame, tr("Warning"), strange); return; } QTextStream in(&XFile); bool bIsReading = true; int res, Line; int NPolars = 0; double Re; double alpha, CL, CD, CM, Xt, Xb; bool bRead; Line = 0; bRead = ReadAVLString(in, Line, FoilName); FoilName = FoilName.trimmed(); if(!MainFrame::foil(FoilName)) { str = tr("No Foil with the name ")+FoilName; str+= tr("\ncould be found. The polar(s) will not be stored"); QMessageBox::warning(pMainFrame, tr("Warning"), str); return; } bRead = ReadAVLString(in, Line, strong);//blank line while(bIsReading) { bRead = ReadAVLString(in, Line, strong);//Re number strong = strong.right(strong.length()-4); Re = strong.toDouble(&bOK); if(!bOK) { bIsReading = false; } else { Polar *pPolar = new Polar(); pPolar->m_FoilName = FoilName; pPolar->m_Reynolds = Re;; pPolar->m_PlrName = QString("T%1_Re2_M3_JavaFoil") .arg(pPolar->m_PolarType) .arg(pPolar->m_Reynolds/1000000.0,0,'f',2) .arg(pPolar->m_Mach,0,'f',2); pPolar->m_Color = pMainFrame->GetColor(1); m_pCurPolar = pMainFrame->AddPolar(pPolar); NPolars++; bRead = ReadAVLString(in, Line, strong);//? Cl Cd Cm 0.25 TU TL SU SL L/D bRead = ReadAVLString(in, Line, strong);//[?] [-] [-] [-] [-] [-] [-] [-] [-] res = 6; while(res==6) { bRead = ReadAVLString(in, Line, strong);//values strong = strong.trimmed(); if(strong.length()) { strong.replace(',', '.'); textline = strong.toLatin1(); text = textline.constData(); res = sscanf(text, "%lf%lf%lf%lf%lf%lf",&alpha, &CL, &CD, &CM, &Xt, &Xb); if (res == 6) pPolar->AddPoint(alpha, CD, 0.0, CL, CM, Xt, Xb, 0.0, 0.0, Re,0.0); } else { res = 0; } } } m_pCurOpp = NULL; SetPolar(); pMainFrame->UpdatePolars(); UpdateView(); MainFrame::SetSaveState(false); } } /** * The user has requested to restore the boundary layer to its default value prior to the next calculation. */ void QXDirect::OnInitBL() { if(!m_pXFoil) return; if (m_pctrlInitBL->isChecked()) { m_pXFoil->lblini = false; m_pXFoil->lipan = false; } else { m_pXFoil->lblini = true; } } /** * The user has requested the launch of the interface to create a foil from the interpolation of two existing Foil objects. */ void QXDirect::OnInterpolateFoils() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(m_poaFoil->size()<2) { QMessageBox::warning(pMainFrame, tr("Warning"), tr("At least two foils are required")); return; } StopAnimate(); bool bPressure = m_bPressure; bool bBL = m_bBL; m_bPressure = false; m_bBL = false; OnOpPoints(); InterpolateFoilsDlg ifDlg(pMainFrame); ifDlg.m_poaFoil = m_poaFoil; ifDlg.m_pBufferFoil = &m_BufferFoil;// work on the buffer foil ifDlg.m_pXDirect = this; ifDlg.m_pAFoil = NULL; ifDlg.InitDialog(); if(ifDlg.exec() == QDialog::Accepted) { Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(&m_BufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; pNewFoil->m_FoilName = ifDlg.m_NewFoilName; pMainFrame->SetModFoil(pNewFoil); pMainFrame->UpdateFoils(); } else { SetBufferFoil();// restore buffer foil.. from current foil m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil); } m_bPressure = bPressure; m_bBL = bBL; UpdateView(); } /** * The user has requested the launch of the interface to manage Foil objects. */ void QXDirect::OnManageFoils() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; ManageFoilsDlg mfDlg(pMainFrame); mfDlg.m_pMainFrame = s_pMainFrame; QString FoilName = ""; if(MainFrame::s_pCurFoil) FoilName = MainFrame::s_pCurFoil->m_FoilName; mfDlg.InitDialog(FoilName); mfDlg.exec(); if(mfDlg.m_pFoil) SetFoil(mfDlg.m_pFoil); else SetFoil(); pMainFrame->UpdateFoils(); MainFrame::SetSaveState(false); SetControls(); UpdateView(); } /** * The user has requested the launch of the interface used to create a NACA type foil. */ void QXDirect::OnNacaFoils() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StopAnimate(); m_bPolarView = false; void* ptr0 = MainFrame::s_pCurFoil; void* ptr = m_pCurOpp; MainFrame::s_pCurFoil = NULL; m_pCurOpp = NULL; CreateOppCurves(); UpdateView(); NacaFoilDlg nacaDlg(pMainFrame); nacaDlg.m_pBufferFoil = &m_BufferFoil; nacaDlg.m_pXDirect = this; nacaDlg.m_pAFoil = NULL; if (nacaDlg.exec() == QDialog::Accepted) { QString str; if(nacaDlg.s_Digits>0 && log10((double)nacaDlg.s_Digits)<4) str = QString("%1").arg(nacaDlg.s_Digits,4,10,QChar('0')); else str = QString("%1").arg(nacaDlg.s_Digits); str = "NACA "+ str; Foil *pNewFoil = new Foil; pNewFoil->CopyFoil(&m_BufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; pNewFoil->m_FoilName = str; m_pCurOpp = (OpPoint*)ptr; Foil *pOldFoil = MainFrame::foil(str); if(pOldFoil) pMainFrame->SetModFoil(pNewFoil); else pMainFrame->AddFoil(pNewFoil); SetFoil(pNewFoil); pMainFrame->UpdateFoils(); MainFrame::SetSaveState(false); } else { MainFrame::s_pCurFoil = (Foil*)ptr0; m_pCurOpp = (OpPoint*)ptr; SetBufferFoil(); m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil); } SetControls(); UpdateView(); } /** * The user has requested that the length of the current foil be normalized to 1. */ void QXDirect::OnNormalizeFoil() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(!MainFrame::s_pCurFoil) return; QString str; StopAnimate(); double length = MainFrame::s_pCurFoil->NormalizeGeometry(); m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil); SetBufferFoil(); str = QString(tr("The foil has been normalized from %1 to 1.000")).arg(length,7,'f',3); MainFrame::SetSaveState(false); pMainFrame->statusBar()->showMessage(str); UpdateView(); } /** * The user has requested a plot of the A/A0 variable using current XFoil results. */ void QXDirect::OnNPlot() { if(!m_pXFoil->lvconv) return; int i; int nside1, nside2, ibl; m_pCpGraph->SetYVariable(2); m_XFoilVar=6; m_pCpGraph->DeleteCurves(); m_pCpGraph->ResetLimits(); m_pCpGraph->SetAuto(true); m_pCpGraph->SetInverted(false); m_pCpGraph->SetYTitle("A/A0"); Curve * pTopCurve = m_pCpGraph->AddCurve(); Curve * pBotCurve = m_pCpGraph->AddCurve(); pTopCurve->SetTitle(tr("Top")); pBotCurve->SetTitle(tr("Bot")); double x[IVX][3],y[IVX][3]; m_pXFoil->CreateXBL(x, nside1, nside2); for (ibl=2; ibl< nside1;ibl++) { y[ibl][1] = m_pXFoil->ctau[ibl][1]; } for ( ibl=2; ibl< nside2;ibl++) { y[ibl][2] = m_pXFoil->ctau[ibl][2]; } for (i=2; i<=m_pXFoil->itran[1]-2; i++) { pTopCurve->AppendPoint(x[i][1], y[i][1]); } for (i=2; i<=m_pXFoil->itran[2]-2; i++) { pBotCurve->AppendPoint(x[i][2], y[i][2]); } m_pCpGraph->SetXScale(); SetFoilScale(); SetControls(); UpdateView(); } /** * The user has requested to switch to the OpPoint view */ void QXDirect::OnOpPoints() { if(!m_bPolarView) return; m_bPolarView = false; CreateOppCurves(); SetFoilScale(); SetCurveParams(); SetAnalysisParams(); SetControls(); UpdateView(); } /** * The user has requested to switch to the Polar view */ void QXDirect::OnPolars() { if(m_bPolarView) return; m_bPolarView = true; CreatePolarCurves(); SetCurveParams(); SetAnalysisParams(); SetControls(); UpdateView(); } /** * The user has requested the launch of the interface used to filter the type of polars to be displayed. */ void QXDirect::OnPolarFilter() { PolarFilterDlg pfDlg((MainFrame*)s_pMainFrame); pfDlg.m_bMiarex = false; pfDlg.m_bType1 = m_bType1; pfDlg.m_bType2 = m_bType2; pfDlg.m_bType3 = m_bType3; pfDlg.m_bType4 = m_bType4; pfDlg.InitDialog(); if(pfDlg.exec()==QDialog::Accepted) { m_bType1 = pfDlg.m_bType1; m_bType2 = pfDlg.m_bType2; m_bType3 = pfDlg.m_bType3; m_bType4 = pfDlg.m_bType4; if(m_bPolarView) { CreatePolarCurves(); UpdateView(); } } } /** * The user has requested the launch of the interface to refine globally the Foil */ void QXDirect::OnRefinePanelsGlobally() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(!MainFrame::s_pCurFoil) return; StopAnimate(); bool bState = m_bShowPanels;//save current view setting void* ptr = m_pCurOpp; m_pCurOpp = NULL; CreateOppCurves(); bool bPressure = m_bPressure; bool bBL = m_bBL; m_bPressure = false; m_bBL = false; OnOpPoints(); TwoDPanelDlg tdpDlg(pMainFrame); tdpDlg.m_pXDirect = this; tdpDlg.m_pAFoil = NULL; tdpDlg.m_pBufferFoil = &m_BufferFoil; tdpDlg.m_pMemFoil = MainFrame::s_pCurFoil; m_bShowPanels = true; UpdateView(); tdpDlg.InitDialog(); if(QDialog::Accepted == tdpDlg.exec()) { Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(&m_BufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = true; m_pCurOpp = (OpPoint*)ptr; if(!pMainFrame->SetModFoil(pNewFoil)) SetBufferFoil(); pMainFrame->UpdateFoils(); } else { //reset everything m_pCurOpp = (OpPoint*)ptr; SetBufferFoil(); m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil); } m_bShowPanels = bState;//restore as it was m_bPressure = bPressure; m_bBL = bBL; UpdateView(); } /** * The user has requested the display of the velocity in the Cp graph. */ void QXDirect::OnQGraph() { m_bPolarView = false; if(m_pCpGraph->GetYVariable()!=1) { m_pCpGraph->ResetLimits(); m_pCpGraph->SetAuto(true); m_pCpGraph->SetYVariable(1); } m_pCpGraph->SetXVariable(1); m_pCpGraph->SetInverted(false); CreateOppCurves(); m_pCpGraph->SetYTitle(tr("Q")); SetControls(); m_pCpGraph->SetXScale(); SetFoilScale(); UpdateView(); } /** * The user has requested to rename the Polar */ void QXDirect::OnRenamePolar() { if(!m_pCurPolar) return; if(!MainFrame::s_pCurFoil) return; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; int resp, k,l; Polar* pPolar = NULL; OpPoint * pOpp; QString OldName = m_pCurPolar->m_PlrName; QStringList NameList; for(k=0; ksize(); k++) { pPolar = (Polar*)m_poaPolar->at(k); if(pPolar->m_FoilName == MainFrame::s_pCurFoil->m_FoilName) NameList.append(pPolar->m_PlrName); } RenameDlg renDlg(pMainFrame); renDlg.m_pstrArray = & NameList; renDlg.m_strQuestion = tr("Enter the new name for the foil polar :"); renDlg.m_strName = m_pCurPolar->m_PlrName; renDlg.InitDialog(); bool bExists = true; while (bExists) { resp = renDlg.exec(); if(resp==QDialog::Accepted) { if (OldName == renDlg.m_strName) return; //Is the new name already used ? bExists = false; for (k=0; ksize(); k++) { pPolar = (Polar*)m_poaPolar->at(k); if ((pPolar->m_FoilName==MainFrame::s_pCurFoil->m_FoilName) && (pPolar->m_PlrName == renDlg.m_strName)) { bExists = true; break; } } if(!bExists) { m_pCurPolar->m_PlrName = renDlg.m_strName; for (l=(int)m_poaOpp->size()-1;l>=0; l--) { pOpp = (OpPoint*)m_poaOpp->at(l); if (pOpp->m_strPlrName == OldName && pOpp->m_strFoilName == MainFrame::s_pCurFoil->m_FoilName) { pOpp->m_strPlrName = renDlg.m_strName; } } } MainFrame::SetSaveState(false); } else if(resp ==10) {//user wants to overwrite if (OldName == renDlg.m_strName) return; for (k=0; ksize(); k++) { pPolar = (Polar*)m_poaPolar->at(k); if (pPolar->m_PlrName == renDlg.m_strName) { bExists = true; break; } } for (l=m_poaOpp->size()-1;l>=0; l--) { pOpp = (OpPoint*)m_poaOpp->at(l); if (pOpp->m_strPlrName == pPolar->m_PlrName) { m_poaOpp->removeAt(l); if(pOpp==m_pCurOpp) m_pCurOpp = NULL; delete pOpp; } } m_poaPolar->removeAt(k); if(pPolar==m_pCurPolar) m_pCurPolar = NULL; delete pPolar; //and rename everything m_pCurPolar->m_PlrName = renDlg.m_strName; for (l=m_poaOpp->size()-1;l>=0; l--) { pOpp = (OpPoint*)m_poaOpp->at(l); if (pOpp->m_strPlrName == OldName && pOpp->m_strFoilName == MainFrame::s_pCurFoil->m_FoilName) { pOpp->m_strPlrName = renDlg.m_strName; } } bExists = false; MainFrame::SetSaveState(false); } else { return ;//cancelled } } m_pCurPolar = NULL; m_pCurOpp = NULL; SetPolar(); pMainFrame->UpdatePolars(); UpdateView(); } /** *The user has requested the display of the detailed properties of the active OpPoint object. */ void QXDirect::OnOpPointProps() { if(!m_pCurPolar) return; ObjectPropsDlg opDlg((MainFrame*)s_pMainFrame); opDlg.m_pXDirect = this; opDlg.m_pOpp = m_pCurOpp; opDlg.m_pPolar = NULL; opDlg.m_pMiarex = NULL; opDlg.m_pWOpp = NULL; opDlg.m_pWPolar = NULL; opDlg.InitDialog(); opDlg.exec(); } /** *The user has requested the display of the detailed properties of the active Polar object. */ void QXDirect::OnPolarProps() { if(!m_pCurPolar) return; ObjectPropsDlg opDlg((MainFrame*)s_pMainFrame); opDlg.m_pXDirect = this; opDlg.m_pOpp = NULL; opDlg.m_pPolar = m_pCurPolar; opDlg.m_pMiarex = NULL; opDlg.m_pWOpp = NULL; opDlg.m_pWPolar = NULL; opDlg.InitDialog(); opDlg.exec(); } /** * The user has requested to rename the foil */ void QXDirect::OnRenameFoil() { if(!MainFrame::s_pCurFoil) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->OnRenameCurFoil(); } /** * The user has requested to reset all polar graph scales to their automatic default value */ void QXDirect::OnResetAllPolarGraphsScales() { m_PlrGraph[0].SetAuto(true); m_PlrGraph[0].ResetXLimits(); m_PlrGraph[0].ResetYLimits(); m_PlrGraph[2].SetAuto(true); m_PlrGraph[2].ResetXLimits(); m_PlrGraph[2].ResetYLimits(); m_PlrGraph[1].SetAuto(true); m_PlrGraph[1].ResetXLimits(); m_PlrGraph[1].ResetYLimits(); m_PlrGraph[3].SetAuto(true); m_PlrGraph[3].ResetXLimits(); m_PlrGraph[3].ResetYLimits(); m_PlrGraph[4].SetAuto(true); m_PlrGraph[4].ResetXLimits(); m_PlrGraph[4].ResetYLimits(); UpdateView(); } /** * The user has requested to reset the scale of the foil to its automatic default value */ void QXDirect::OnResetFoilScale() { SetFoilScale(); if(!m_bAnimate) UpdateView(); } /** * The user has requested to reset the polar legend to its default position */ void QXDirect::OnResetGraphLegend() { SetPolarLegendPos(); UpdateView(); } /** * The user has requested the deletion of the dataof the current Polar. * The associated OpPoint objects will be deleted too. */ void QXDirect::OnResetCurPolar() { if(!m_pCurPolar) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; m_pCurPolar->ResetPolar(); OpPoint*pOpp; for(int i=m_poaOpp->size()-1;i>=0;i--) { pOpp = (OpPoint*)m_poaOpp->at(i); if(pOpp->m_strFoilName==MainFrame::s_pCurFoil->m_FoilName && pOpp->m_strPlrName==m_pCurPolar->m_PlrName) { m_poaOpp->removeAt(i); delete pOpp; } } m_pCurOpp = NULL; pMainFrame->UpdateOpps(); if(m_bPolarView) CreatePolarCurves(); else CreateOppCurves(); UpdateView(); } /** * The user has requested to reset the XFoil settings and parameters to their default value. */ void QXDirect::OnResetXFoil() { m_pXFoil->Initialize(); m_pXFoil->lblini = false; m_pXFoil->lipan = false; m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil); m_pXFoil->InitXFoilAnalysis(m_pCurPolar); m_bInitBL = true; m_pctrlInitBL->setChecked(m_bInitBL); } /** * The user has requested the creation of a .plr file with the Polars of the active Foil object. */ void QXDirect::OnSavePolars() { if(!MainFrame::s_pCurFoil || !m_poaPolar->size()) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; QString FileName, FoilName; FileName = MainFrame::s_pCurFoil->m_FoilName + ".plr"; FileName.replace("/", " "); FileName = QFileDialog::getSaveFileName(this, tr("Polar File"), MainFrame::s_LastDirName+"/"+FileName, tr("Polar File (*.plr)")); if(!FileName.length()) return; QString strong = FileName.right(4); if(strong !=".plr" && strong !=".PLR") FileName += ".plr"; QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly)) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); QDataStream ar(&XFile); #if QT_VERSION >= 0x040500 ar.setVersion(QDataStream::Qt_4_5); #endif ar.setByteOrder(QDataStream::LittleEndian); pMainFrame->WritePolars(ar, MainFrame::s_pCurFoil); XFile.close(); } /** * The user has toggled the switch for a sequential analysis. */ void QXDirect::OnSequence() { m_bSequence = m_pctrlSequence->isChecked(); SetOpPointSequence(); } /** * The user has requested the launch of the interface to define a L.E. or T.E. flap. */ void QXDirect::OnSetFlap() { if(!MainFrame::s_pCurFoil) return; StopAnimate(); void* ptr = m_pCurOpp; m_pCurOpp = NULL; CreateOppCurves(); MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; bool bPressure = m_bPressure; bool bBL = m_bBL; m_bPressure = false; m_bBL = false; OnOpPoints(); FlapDlg flpDlg(pMainFrame); flpDlg.m_pBufferFoil = &m_BufferFoil; flpDlg.m_pMemFoil = MainFrame::s_pCurFoil; flpDlg.m_pXFoil = m_pXFoil; flpDlg.m_pXDirect = this; flpDlg.m_pAFoil = NULL; flpDlg.InitDialog(); if(QDialog::Accepted == flpDlg.exec()) { Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(&m_BufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; m_pCurOpp = (OpPoint*)ptr; if(!pMainFrame->SetModFoil(pNewFoil)) SetBufferFoil(); pMainFrame->UpdateFoils(); } else { //reset everything m_pCurOpp = (OpPoint*)ptr; SetBufferFoil(); m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil); } m_bPressure = bPressure; m_bBL = bBL; UpdateView(); } /** * The user has requested the launch of the interface to modify the radius of the Foil's leading edge. */ void QXDirect::OnSetLERadius() { if(!MainFrame::s_pCurFoil) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; StopAnimate(); void* ptr = m_pCurOpp; m_pCurOpp = NULL; CreateOppCurves(); bool bPressure = m_bPressure; bool bBL = m_bBL; m_bPressure = false; m_bBL = false; OnOpPoints(); LEDlg lDlg(pMainFrame); lDlg.m_pBufferFoil = &m_BufferFoil; lDlg.m_pMemFoil = MainFrame::s_pCurFoil; lDlg.m_pXDirect = this; lDlg.m_pAFoil = NULL; lDlg.InitDialog(); if(QDialog::Accepted == lDlg.exec()) { Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(&m_BufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; m_pCurOpp = (OpPoint*)ptr; if(!pMainFrame->SetModFoil(pNewFoil)) SetBufferFoil(); pMainFrame->UpdateFoils(); } else { //reset everything m_pCurOpp = (OpPoint*)ptr; SetBufferFoil(); m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil); } m_bPressure = bPressure; m_bBL = bBL; UpdateView(); } /** * The user has requested the launch of the interface to modify the gap at the Foil's trailing edge. */ void QXDirect::OnSetTEGap() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(!MainFrame::s_pCurFoil) return; StopAnimate(); void* ptr = m_pCurOpp; m_pCurOpp = NULL; CreateOppCurves(); bool bPressure = m_bPressure; bool bBL = m_bBL; m_bPressure = false; m_bBL = false; OnOpPoints(); TEGapDlg tegDlg(pMainFrame); tegDlg.m_pXDirect = this; tegDlg.m_pAFoil = NULL; tegDlg.m_pBufferFoil = &m_BufferFoil; tegDlg.m_pMemFoil = MainFrame::s_pCurFoil; tegDlg.m_Gap = MainFrame::s_pCurFoil->m_Gap; tegDlg.InitDialog(); if(QDialog::Accepted == tegDlg.exec()) { Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(&m_BufferFoil); pNewFoil->m_FoilColor = pMainFrame->GetColor(0); pNewFoil->m_nFoilStyle = 0; pNewFoil->m_nFoilWidth = 1; pNewFoil->m_bPoints = false; m_pCurOpp = (OpPoint*)ptr; if(!pMainFrame->SetModFoil(pNewFoil)) SetBufferFoil(); pMainFrame->UpdateFoils(); } else { //reset everything m_pCurOpp = (OpPoint*)ptr; SetBufferFoil(); m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil); } m_bPressure = bPressure; m_bBL = bBL; UpdateView(); } /** * The user has requested the display of all OpPoint curves. */ void QXDirect::OnShowAllOpps() { OpPoint *pOpp; m_bCurOppOnly = false; ((MainFrame*)s_pMainFrame)->showCurOppOnly->setChecked(m_bCurOppOnly); for (int i=0; isize(); i++) { pOpp = (OpPoint*)m_poaOpp->at(i); pOpp->m_bIsVisible = true; } ((MainFrame*)s_pMainFrame)->SetSaveState(false); if(!m_bPolarView) CreateOppCurves(); SetCurveParams(); UpdateView(); } /** * The user has requested the display of all Polar curves. */ void QXDirect::OnShowAllPolars() { Polar *pPolar; for (int i=0; isize(); i++) { pPolar = (Polar*)m_poaPolar->at(i); pPolar->m_bIsVisible = true; } MainFrame::SetSaveState(false); CreatePolarCurves(); SetCurveParams(); UpdateView(); } /** * The user has toggled the display of the boundary layer */ void QXDirect::OnShowBL() { if(m_pctrlShowBL->isChecked()) { if(m_bPolarView) OnOpPoints(); m_pctrlShowPressure->setChecked(false); m_bBL = true; m_bPressure = false; } else { m_bBL = false; } if(!m_bAnimate) UpdateView(); } /** * The user has toggled the display of the curve of the active object */ void QXDirect::OnShowCurve() { //user has toggled visible switch if(m_bPolarView) { if (m_pCurPolar) { m_pCurPolar->m_bIsVisible = m_pctrlShowCurve->isChecked(); } CreatePolarCurves(); } else if (m_pCurOpp) { m_pCurOpp->m_bIsVisible = m_pctrlShowCurve->isChecked(); CreateOppCurves(); } MainFrame::SetSaveState(false); UpdateView(); } /** * The user has requested the display of only the Polar curves associated to the active Foil */ void QXDirect::OnShowFoilPolarsOnly() { if(!MainFrame::s_pCurFoil) return; Polar *pPolar; for (int i=0; isize(); i++) { pPolar = (Polar*)m_poaPolar->at(i); pPolar->m_bIsVisible = (pPolar->m_FoilName == MainFrame::s_pCurFoil->m_FoilName); } MainFrame::SetSaveState(false); CreatePolarCurves(); SetCurveParams(); UpdateView(); } /** * The user has requested the display of the Polar curves associated to the active Foil */ void QXDirect::OnShowFoilPolars() { if(!MainFrame::curFoil()) return; Polar *pPolar; for (int i=0; isize(); i++) { pPolar = (Polar*)m_poaPolar->at(i); if(pPolar->m_FoilName == MainFrame::s_pCurFoil->m_FoilName) { pPolar->m_bIsVisible = true; } } MainFrame::SetSaveState(false); CreatePolarCurves(); SetCurveParams(); UpdateView(); } /** * The user has requested the display of the OpPoint curves associated to the active Foil */ void QXDirect::OnShowFoilOpps() { if(!MainFrame::s_pCurFoil || !m_pCurPolar) return; OpPoint *pOpp; m_bCurOppOnly = false; ((MainFrame*)s_pMainFrame)->showCurOppOnly->setChecked(m_bCurOppOnly); for(int i=0; isize(); i++) { pOpp = (OpPoint*)m_poaOpp->at(i); if(pOpp->m_strFoilName==MainFrame::s_pCurFoil->m_FoilName) pOpp->m_bIsVisible = true; } MainFrame::SetSaveState(false); if(!m_bPolarView) CreateOppCurves(); SetCurveParams(); UpdateView(); } /** * The user has toggled the display of the neutral line y=0. */ void QXDirect::OnShowNeutralLine() { m_bNeutralLine = !m_bNeutralLine; if(!m_bPolarView) UpdateView(); MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->showNeutralLine->setChecked(m_bNeutralLine); } /** * The user has toggled the display of the Foil's panels. */ void QXDirect::OnShowPanels() { m_bShowPanels = !m_bShowPanels; if(!m_bPolarView) UpdateView(); MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->showPanels->setChecked(m_bShowPanels); } /** * The user has toggled the display of the curve's points */ void QXDirect::OnShowCurvePoints() { if(m_bPolarView) { if (m_pCurPolar) { m_pCurPolar->m_bShowPoints = m_pctrlShowPoints->isChecked(); } CreatePolarCurves(); } else if (m_pCurOpp) { m_pCurOpp->m_bShowPoints = m_pctrlShowPoints->isChecked(); CreateOppCurves(); } MainFrame::SetSaveState(false); UpdateView(); } /** * The user has requested the display of the curves of all OpPoint objects associated to the active Polar. */ void QXDirect::OnShowPolarOpps() { if(!MainFrame::s_pCurFoil || !m_pCurPolar) return; OpPoint *pOpp; m_bCurOppOnly = false; ((MainFrame*)s_pMainFrame)->showCurOppOnly->setChecked(m_bCurOppOnly); for(int i=0; isize(); i++) { pOpp = (OpPoint*)m_poaOpp->at(i); if(pOpp->m_strFoilName==MainFrame::s_pCurFoil->m_FoilName && pOpp->m_strPlrName==m_pCurPolar->m_PlrName) pOpp->m_bIsVisible = true; } MainFrame::SetSaveState(false); if(!m_bPolarView) CreateOppCurves(); SetCurveParams(); UpdateView(); } /** * The user has toggled the display of the pressure arrows */ void QXDirect::OnShowPressure() { if(m_pctrlShowPressure->isChecked()) { if(m_bPolarView) OnOpPoints(); m_pctrlShowBL->setChecked(false); m_bBL = false; m_bPressure = true; } else { m_bPressure = false; } if(!m_bAnimate) UpdateView(); } /** * The user has requested the display of a single polar graph */ void QXDirect::OnSinglePolarGraph() { QAction *action = qobject_cast(sender()); if (!action) return; m_iPlrView = ONEPOLARGRAPH; m_iPlrGraph = action->data().toInt(); m_bPolarView = true; SetPolarLegendPos(); SetControls(); UpdateView(); } /** * The user has toggled the switch used to define the type of input parameter bewteen aoa, Cl, and Re */ void QXDirect::OnSpec() { if (m_pctrlSpec1->isChecked()) m_bAlpha = true; else if (m_pctrlSpec2->isChecked()) m_bAlpha = false; else if (m_pctrlSpec3->isChecked()) m_bAlpha = false; } /** * The user has toggled the switch which defines if OpPoints should be stored at the end of the analysis */ void QXDirect::OnStoreOpp() { m_bStoreOpp = m_pctrlStoreOpp->isChecked(); } /** * The user has toggled the switch which defines if the analysis will be viscous or inviscid */ void QXDirect::OnViscous() { m_bViscous = m_pctrlViscous->isChecked(); } /** * The user has requested the launch of the interface used to define the display style of the Foil */ void QXDirect::OnXDirectStyle() { XDirectStyleDlg xdsDlg((MainFrame*)s_pMainFrame); xdsDlg.m_pXDirect = this; xdsDlg.m_iBLStyle = m_iBLStyle; xdsDlg.m_iBLWidth = m_iBLWidth; xdsDlg.m_crBLColor = m_crBLColor; xdsDlg.m_iPressureStyle = m_iPressureStyle; xdsDlg.m_iPressureWidth = m_iPressureWidth; xdsDlg.m_crPressureColor = m_crPressureColor; xdsDlg.m_iNeutralStyle = m_iNeutralStyle; xdsDlg.m_iNeutralWidth = m_iNeutralWidth; xdsDlg.m_crNeutralColor = m_crNeutralColor; xdsDlg.InitDialog(); if(xdsDlg.exec() == QDialog::Accepted) { m_iBLStyle = xdsDlg.m_iBLStyle; m_iBLWidth = xdsDlg.m_iBLWidth; m_crBLColor = xdsDlg.m_crBLColor; m_iPressureStyle = xdsDlg.m_iPressureStyle; m_iPressureWidth = xdsDlg.m_iPressureWidth; m_crPressureColor = xdsDlg.m_crPressureColor; m_iNeutralStyle = xdsDlg.m_iNeutralStyle; m_iNeutralWidth = xdsDlg.m_iNeutralWidth; m_crNeutralColor = xdsDlg.m_crNeutralColor; } UpdateView(); } /** * The user has requested the launch of the interface used to define advanced settings for the XFoil analysis */ void QXDirect::OnXFoilAdvanced() { XFoilAdvancedDlg xfaDlg((MainFrame*)s_pMainFrame); xfaDlg.m_IterLimit = m_IterLim; xfaDlg.m_VAccel = m_pXFoil->vaccel; xfaDlg.m_bInitBL = m_bAutoInitBL; xfaDlg.m_bFullReport = m_pXFoil->m_bFullReport; xfaDlg.InitDialog(); if (QDialog::Accepted == xfaDlg.exec()) { m_pXFoil->vaccel = xfaDlg.m_VAccel; m_IterLim = xfaDlg.m_IterLimit; m_bAutoInitBL = xfaDlg.m_bInitBL; m_pXFoil->m_bFullReport = xfaDlg.m_bFullReport; } } /** * The method which draws the boundary layer in the OpPoint view. * @param painter a reference to the QPainter object with which to draw * @param pOpPoint the OpPoint object to draw * @param scale the scale of the view */ void QXDirect::PaintBL(QPainter &painter, OpPoint* pOpPoint, double scale) { QPoint offset, From, To; double x,y; int i; double alpha = -pOpPoint->Alpha*PI/180.0; double cosa = cos(alpha); double sina = sin(alpha); if(!pOpPoint->m_bViscResults || !pOpPoint->m_bBL) return; offset = m_FoilOffset; scale = scale; scale = scale; QPen WakePen(m_crBLColor); WakePen.setStyle(GetStyle(m_iBLStyle)); WakePen.setWidth(m_iBLWidth); painter.setPen(WakePen); x = (pOpPoint->xd1[1]-0.5)*cosa - pOpPoint->yd1[1]*sina + 0.5; y = (pOpPoint->xd1[1]-0.5)*sina + pOpPoint->yd1[1]*cosa; From.rx() = (int)( x*scale) + offset.x(); From.ry() = (int)(-y*scale) + offset.y(); for (i=2; i<=pOpPoint->nd1; i++) { x = (pOpPoint->xd1[i]-0.5)*cosa - pOpPoint->yd1[i]*sina + 0.5; y = (pOpPoint->xd1[i]-0.5)*sina + pOpPoint->yd1[i]*cosa; To.rx() = (int)( x*scale) + offset.x(); To.ry() = (int)(-y*scale) + offset.y(); painter.drawLine(From, To); From = To; } x = (pOpPoint->xd2[0]-0.5)*cosa - pOpPoint->yd2[0]*sina + 0.5; y = (pOpPoint->xd2[0]-0.5)*sina + pOpPoint->yd2[0]*cosa; From.rx() = (int)( x*scale) + offset.x(); From.ry() = (int)(-y*scale) + offset.y(); for (i=1; ind2; i++) { x = (pOpPoint->xd2[i]-0.5)*cosa - pOpPoint->yd2[i]*sina + 0.5; y = (pOpPoint->xd2[i]-0.5)*sina + pOpPoint->yd2[i]*cosa; To.rx() = (int)( x*scale) + offset.x(); To.ry() = (int)(-y*scale) + offset.y(); painter.drawLine(From, To); From = To; } x = (pOpPoint->xd3[0]-0.5)*cosa - pOpPoint->yd3[0]*sina + 0.5; y = (pOpPoint->xd3[0]-0.5)*sina + pOpPoint->yd3[0]*cosa; From.rx() = (int)( x*scale) + offset.x(); From.ry() = (int)(-y*scale) + offset.y(); for (i=1; ind3; i++) { x = (pOpPoint->xd3[i]-0.5)*cosa - pOpPoint->yd3[i]*sina + 0.5; y = (pOpPoint->xd3[i]-0.5)*sina + pOpPoint->yd3[i]*cosa; To.rx() = (int)( x*scale) + offset.x(); To.ry() = (int)(-y*scale) + offset.y(); painter.drawLine(From, To); From = To; } } /** * The method which draws the pressure arrows in the OpPoint view. * @param painter a reference to the QPainter object with which to draw * @param pOpPoint the OpPoint object to draw * @param scale the scale of the view */ void QXDirect::PaintPressure(QPainter &painter, OpPoint* pOpPoint, double scale) { if(!pOpPoint->m_bViscResults ) return; int i; double alpha = -pOpPoint->Alpha*PI/180.0; double cosa = cos(alpha); double sina = sin(alpha); double x, y ,xs, ys, xe, ye, dx, dy, x1, x2, y1, y2, r2; double cp; QPoint offset = m_FoilOffset; QPen CpvPen(m_crPressureColor); CpvPen.setStyle(GetStyle(m_iPressureStyle)); CpvPen.setWidth(m_iPressureWidth); painter.setPen(CpvPen); for(i=0; im_bViscResults) cp = pOpPoint->Cpv[i]; else cp = pOpPoint->Cpi[i]; x = m_BufferFoil.x[i]; y = m_BufferFoil.y[i]; xs = (x-0.5)*cosa - y*sina + 0.5; ys = (x-0.5)*sina + y*cosa; if(cp>0) { x += m_BufferFoil.nx[i] * cp * 0.05; y += m_BufferFoil.ny[i] * cp * 0.05; xe = (x-0.5)*cosa - y*sina + 0.5; ye = (x-0.5)*sina + y*cosa; painter.drawLine((int)( xs*scale) + offset.x(), (int)(-ys*scale) + offset.y(), (int)( xe*scale) + offset.x(), (int)(-ye*scale) + offset.y()); dx = xe - xs; dy = ye - ys; r2 = sqrt(dx*dx + dy*dy); if(r2!=0.0) //you can never be sure... { dx = dx/r2; dy = dy/r2; } x1 = xs + 0.0085*dx + 0.005*dy; y1 = ys + 0.0085*dy - 0.005*dx; x2 = xs + 0.0085*dx - 0.005*dy; y2 = ys + 0.0085*dy + 0.005*dx; painter.drawLine((int)( xs*scale) + offset.x(), (int)(-ys*scale) + offset.y(), (int)( x1*scale) + offset.x(), (int)(-y1*scale) + offset.y()); painter.drawLine((int)( xs*scale) + offset.x(), (int)(-ys*scale) + offset.y(), (int)( x2*scale) + offset.x(), (int)(-y2*scale) + offset.y()); } else { x += -m_BufferFoil.nx[i] * cp *0.05; y += -m_BufferFoil.ny[i] * cp *0.05; xe = (x-0.5)*cosa - y*sina+ 0.5; ye = (x-0.5)*sina + y*cosa; painter.drawLine((int)( xs*scale) + offset.x(), (int)(-ys*scale) + offset.y(), (int)( xe*scale) + offset.x(), (int)(-ye*scale) + offset.y()); dx = xe - xs; dy = ye - ys; r2 = sqrt(dx*dx + dy*dy); if(r2!=0.0) //you can never be sure... { dx = -dx/r2; dy = -dy/r2; } x1 = xe + 0.0085*dx + 0.005*dy; y1 = ye + 0.0085*dy - 0.005*dx; x2 = xe + 0.0085*dx - 0.005*dy; y2 = ye + 0.0085*dy + 0.005*dx; painter.drawLine((int)( xe*scale) + offset.x(), (int)(-ye*scale) + offset.y(), (int)( x1*scale) + offset.x(), (int)(-y1*scale) + offset.y()); painter.drawLine((int)( xe*scale) + offset.x(), (int)(-ye*scale) + offset.y(), (int)( x2*scale) + offset.x(), (int)(-y2*scale) + offset.y()); } } //last draw lift at XCP position QPen LiftPen(m_crPressureColor); LiftPen.setStyle(GetStyle(m_iPressureStyle)); LiftPen.setWidth(m_iPressureWidth+1); painter.setPen(LiftPen); xs = (pOpPoint->m_XCP-0.5)*cosa + 0.5; ys = -(pOpPoint->m_XCP-0.5)*sina ; xe = xs; ye = ys - pOpPoint->Cl/10.0; painter.drawLine((int)( xs*scale) + offset.x(), (int)(ys*scale) + offset.y(), (int)( xs*scale) + offset.x(), (int)(ye*scale) + offset.y()); dx = xe - xs; dy = ye - ys; r2 = sqrt(dx*dx + dy*dy); dx = -dx/r2; dy = -dy/r2; x1 = xe + 0.0085*dx + 0.005*dy; y1 = ye + 0.0085*dy - 0.005*dx; x2 = xe + 0.0085*dx - 0.005*dy; y2 = ye + 0.0085*dy + 0.005*dx; painter.drawLine((int)( xe*scale) + offset.x(), (int)(ye*scale) + offset.y(), (int)( x1*scale) + offset.x(), (int)(y1*scale) + offset.y()); painter.drawLine((int)( xe*scale) + offset.x(), (int)(ye*scale) + offset.y(), (int)( x2*scale) + offset.x(), (int)(y2*scale) + offset.y()); } /** * Draws a pair of polar graphs * @param painter a reference to the QPainter object with which to draw */ void QXDirect::PaintCoupleGraphs(QPainter &painter) { int h = m_rCltRect.height(); int w = m_rCltRect.width(); int w2 = (int)(w/2); int h23 = (int)(2*h/3); QRect Rect1(0,0,w2,h23); QRect Rect2(w2,0,w2,h23); QRect Rect3(0, h23, w,h-h23); painter.fillRect(Rect3, MainFrame::s_BackgroundColor); m_PlrGraph[0].DrawGraph(Rect1, painter); m_PlrGraph[4].DrawGraph(Rect2, painter); PaintPolarLegend(m_PolarLegendOffset, h, painter); } /** * Draws the Cp Graph and the foil * @param painter a reference to the QPainter object with which to draw */ void QXDirect::PaintOpPoint(QPainter &painter) { static double Alpha, FoilScale; FoilScale = m_fFoilScale; QString Result, str, str1; painter.fillRect(m_rCltRect, MainFrame::s_BackgroundColor); if (m_rCltRect.width()<150 || m_rCltRect.height()<150) return; if(m_bCpGraph) { //Draw Cp Graph m_pCpGraph->DrawGraph(painter); QPoint Place(m_rCltRect.right()/2, m_rCltRect.top() + 20); m_pCpGraph->DrawLegend(painter, Place, MainFrame::s_TextFont, MainFrame::s_TextColor);//Graph::DrawLegend uses graph's legend font and color } if(m_bNeutralLine) { QPen NeutralPen(m_crNeutralColor); NeutralPen.setStyle(GetStyle(m_iNeutralStyle)); NeutralPen.setWidth(m_iNeutralWidth); painter.setPen(NeutralPen); painter.drawLine(m_rCltRect.left(),m_FoilOffset.y(), m_rCltRect.right(),m_FoilOffset.y()); } if (!MainFrame::s_pCurFoil || !MainFrame::s_pCurFoil->m_FoilName.length()) return; if(MainFrame::s_pCurFoil) { Alpha = 0.0; if(m_pCurOpp) Alpha = m_pCurOpp->Alpha; m_BufferFoil.m_bPoints = m_bShowPanels; m_BufferFoil.DrawFoil(painter, -Alpha, m_fFoilScale, FoilScale, m_FoilOffset); if(m_bPressure && m_pCurOpp) PaintPressure(painter, m_pCurOpp, m_fFoilScale); if(m_bBL && m_pCurOpp) PaintBL(painter, m_pCurOpp, m_fFoilScale); } // Write Titles and results QString strong; painter.setFont(MainFrame::s_TextFont); int D = 0; int ZPos = m_rCltRect.bottom(); int XPos = m_rCltRect.right()-10; QPen WritePen(MainFrame::s_TextColor); painter.setPen(WritePen); QFontMetrics fm(MainFrame::s_TextFont); int dD = fm.height(); //write the foil's properties int Back = 4; if(m_BufferFoil.m_bTEFlap) Back +=3; int LeftPos = m_rCltRect.left()+10; ZPos = m_rCltRect.bottom() - 10 - Back*dD; D = 0; str = "%"; str1 = QString(tr("Thickness = %1")).arg(m_BufferFoil.m_fThickness*100.0, 6, 'f', 2); painter.drawText(LeftPos,ZPos+D, str1+str); D += dD; str1 = QString(tr("Max. Thick.pos. = %1")).arg(m_BufferFoil.m_fXThickness*100.0, 6, 'f', 2); painter.drawText(LeftPos,ZPos+D, str1+str); D += dD; str1 = QString(tr("Max. Camber = %1")).arg( m_BufferFoil.m_fCamber*100.0, 6, 'f', 2); painter.drawText(LeftPos,ZPos+D, str1+str); D += dD; str1 = QString(tr("Max. Camber pos. = %1")).arg(m_BufferFoil.m_fXCamber*100.0, 6, 'f', 2); painter.drawText(LeftPos,ZPos+D, str1+str); D += dD; str1 = QString(tr("Number of Panels = %1")).arg( m_BufferFoil.n); painter.drawText(LeftPos,ZPos+D, str1); D += dD; if(m_BufferFoil.m_bTEFlap) { str1 = QString(tr("Flap Angle = %1")+QString::fromUtf8("°")).arg( m_BufferFoil.m_TEFlapAngle, 7, 'f', 2); painter.drawText(LeftPos,ZPos+D, str1); D += dD; str1 = QString(tr("XHinge = %1")).arg( m_BufferFoil.m_TEXHinge, 6, 'f', 1); strong="%"; painter.drawText(LeftPos,ZPos+D, str1+strong); D += dD; str1 = QString(tr("YHinge = %1")).arg( m_BufferFoil.m_TEYHinge, 6, 'f', 1); strong="%"; painter.drawText(LeftPos,ZPos+D, str1+strong); D += dD; } D = 0; Back = 6; if(m_pCurOpp) { Back = 12; if(m_pCurOpp->m_bTEFlap) Back++; if(m_pCurOpp->m_bLEFlap) Back++; if(m_pCurOpp->m_bViscResults && qAbs(m_pCurOpp->Cd)>0.0) Back++; if(m_pCurPolar->m_PolarType==FIXEDLIFTPOLAR) Back++; if(m_pCurPolar->m_PolarType!=FIXEDSPEEDPOLAR && m_pCurPolar->m_PolarType!=FIXEDAOAPOLAR) Back++; } int dwidth = fm.width(tr("TE Hinge Moment/span = 123456789")); ZPos = m_rCltRect.bottom()-Back*dD - 10; XPos = m_rCltRect.right()-dwidth-20; D=0; if(m_pCurPolar) { str1 = QString(tr("Polar Type = %1")).arg( m_pCurPolar->m_PolarType); painter.drawText(XPos,ZPos, dwidth, dD, Qt::AlignRight | Qt::AlignTop, str1); D += dD; if(m_pCurPolar->m_PolarType ==1) { ReynoldsFormat(strong, m_pCurPolar->m_Reynolds ); strong ="Reynolds = " + strong; painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, strong); D += dD; strong = QString("Mach = %1").arg( m_pCurPolar->m_Mach,9,'f',3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, strong); D += dD; } if(m_pCurPolar->m_PolarType==FIXEDLIFTPOLAR) { ReynoldsFormat(strong, m_pCurPolar->m_Reynolds ); strong = tr("Re.sqrt(Cl) = ") + strong; painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, strong); D += dD; strong = QString(tr("M.sqrt(Cl) = %1")).arg(m_pCurPolar->m_Mach,9,'f',3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, strong); D += dD; } if(m_pCurPolar->m_PolarType==RUBBERCHORDPOLAR) { ReynoldsFormat(strong, m_pCurPolar->m_Reynolds ); strong = tr("Re.sqrt(Cl) = ") + strong; painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, strong); D += dD; strong = QString("Mach = %1").arg(m_pCurPolar->m_Mach,9,'f',3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, strong); D += dD; } if(m_pCurPolar->m_PolarType==FIXEDAOAPOLAR) { strong = QString("Alpha = %1 "+QString::fromUtf8("°")).arg(m_pCurPolar->m_ASpec,10,'f',2); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, strong); D += dD; strong = QString("Mach = %1").arg(m_pCurPolar->m_Mach,9,'f',3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, strong); D += dD; } strong = QString("NCrit = %1").arg(m_pCurPolar->m_ACrit,9,'f',3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, strong); D += dD; strong = QString(tr("Forced Upper Trans. = %1")).arg(m_pCurPolar->m_XTop,9,'f',3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, strong); D += dD; strong = QString(tr("Forced Lower Trans. = %1")).arg(m_pCurPolar->m_XBot, 9, 'f', 3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, strong); D += dD; if(m_pCurOpp) { if(m_pCurPolar->m_PolarType!=FIXEDSPEEDPOLAR) { ReynoldsFormat(Result, m_pCurOpp->Reynolds); Result = "Re = "+ Result; painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, Result); D += dD; } if(m_pCurPolar->m_PolarType==FIXEDLIFTPOLAR) { Result = QString("Ma = %1").arg(m_pCurOpp->Mach, 9, 'f', 4); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, Result); D += dD; } if(m_pCurPolar->m_PolarType!=FIXEDAOAPOLAR) { Result = QString(tr(" Alpha = %1 ")+QString::fromUtf8("°")).arg(m_pCurOpp->Alpha, 7, 'f', 2); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, Result); D += dD; } Result = QString(tr(" Cl = %1")).arg(m_pCurOpp->Cl, 9, 'f', 3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, Result); D += dD; Result = QString(tr(" Cm = %1")).arg(m_pCurOpp->Cm, 9, 'f', 3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, Result); D += dD; Result = QString(tr(" Cd = %1")).arg(m_pCurOpp->Cd, 9, 'f', 3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, Result); D += dD; if(m_pCurOpp->m_bViscResults && qAbs(m_pCurOpp->Cd)>0.0) { Result = QString(tr(" L/D = %1")).arg(m_pCurOpp->Cl/m_pCurOpp->Cd, 9, 'f', 3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, Result); D += dD; } Result = QString(tr("Upper Trans. = %1")).arg(m_pCurOpp->Xtr1, 9, 'f', 3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, Result); D += dD; Result = QString(tr("Lower Trans. = %1")).arg(m_pCurOpp->Xtr2, 9, 'f', 3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, Result); D += dD; if(m_pCurOpp->m_bTEFlap) { Result = QString(tr("TE Hinge Moment/span = %1")).arg(m_pCurOpp->m_TEHMom, 9, 'e', 3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, Result); D += dD; } if(m_pCurOpp->m_bLEFlap) { Result = QString(tr("LE Hinge Moment/span = %1")).arg(m_pCurOpp->m_LEHMom, 9, 'e', 3); painter.drawText(XPos,ZPos+D, dwidth, dD, Qt::AlignRight | Qt::AlignTop, Result); D += dD; } } } } /** * Paints all polar graphs * @param painter a reference to the QPainter object with which to draw */ void QXDirect::PaintPolarGraphs(QPainter &painter) { int h = m_rCltRect.height(); int w = m_rCltRect.width(); int h2 = (int)(h/2); int w2 = (int)(w/2); int w4 = (int)(w/4); QRect Rect1(0,0,w2,h2); QRect Rect2(w2,0,w4,h2); QRect Rect3(w2, h2, w4, h2); QRect Rect4(3*w4,0,w4,h2); QRect Rect5(0,h2, w2,h-h2); QRect Rect6(3*w4,h2,w4,h2); painter.fillRect(Rect5, MainFrame::s_BackgroundColor); m_PlrGraph[0].DrawGraph(Rect1, painter); m_PlrGraph[1].DrawGraph(Rect2, painter); m_PlrGraph[2].DrawGraph(Rect3, painter); m_PlrGraph[3].DrawGraph(Rect4, painter); if(m_bShowUserGraph) m_PlrGraph[4].DrawGraph(Rect6, painter); else painter.fillRect(Rect6, MainFrame::s_BackgroundColor); PaintPolarLegend(m_PolarLegendOffset, h, painter); } /** * Paints the legend of the polar graphs * @param place the top-left point where the legend will be placed * @param bottom the number of pixels to the bottom of the client area * @param painter a reference to the QPainter object with which to draw *@todo position improvement required for the two graph display */ void QXDirect::PaintPolarLegend(QPoint place, int bottom, QPainter &painter) { int LegendSize, LegendWidth, legendHeight, x1; int i,j,k,l,nc,ny,nFoils; LegendSize = 30; LegendWidth = 240; painter.setFont(MainFrame::s_TextFont); QFont fnt(MainFrame::s_TextFont); //two step to shut valgrind up QFontMetrics fm(fnt); legendHeight = fm.height()+1; QPen TextPen(MainFrame::s_TextColor); painter.setPen(TextPen); TextPen.setWidth(1); QStringList str; // we need to make an inventory of foils Polar * pPolar; Foil *pFoil; for (j=0; jsize(); j++) { pFoil = (Foil*)m_poaFoil->at(j); for (i=0; isize(); i++) { pPolar = (Polar*)m_poaPolar->at(i); if (pPolar->m_FoilName == pFoil->m_FoilName && pPolar->m_Alpha.size() && pPolar->isVisible()) { str.append(pFoil->m_FoilName); break; } }// finished inventory } nFoils= str.size(); painter.setBackgroundMode(Qt::TransparentMode); QPen LegendPen; LegendPen.setWidth(1); ny =0; for (k=0; ksize(); l++) { pPolar = (Polar*)m_poaPolar->at(l); if (pPolar->m_Alpha.size() && pPolar->m_PlrName.length() && pPolar->m_bIsVisible && pPolar->m_FoilName == str.at(k) && ((pPolar->m_PolarType==FIXEDSPEEDPOLAR && m_bType1) || (pPolar->m_PolarType==FIXEDLIFTPOLAR && m_bType2) || (pPolar->m_PolarType==RUBBERCHORDPOLAR && m_bType3) || (pPolar->m_PolarType==FIXEDAOAPOLAR && m_bType4))) FoilPlrs++; } if (FoilPlrs) { int YBotPos = place.y() + (ny+FoilPlrs+2) * legendHeight;// bottom line of this foil's legend if(abs(bottom) > abs(YBotPos)) { ny++; } else if (k>0) { // move rigth if less than client bottom area place.rx() += LegendWidth; ny=1; } else { ny=1; } painter.setPen(TextPen); painter.drawText(place.x() + (int)(0.5*LegendSize), place.y() + legendHeight*ny-(int)(legendHeight/2), str.at(k)); } for (nc=0; ncsize(); nc++) { pPolar = (Polar*)m_poaPolar->at(nc); if(str.at(k) == pPolar->m_FoilName) { if (pPolar->m_Alpha.size() && pPolar->m_PlrName.length() && pPolar->m_bIsVisible && ((pPolar->m_PolarType==FIXEDSPEEDPOLAR && m_bType1) || (pPolar->m_PolarType==FIXEDLIFTPOLAR && m_bType2) || (pPolar->m_PolarType==RUBBERCHORDPOLAR && m_bType3) || (pPolar->m_PolarType==FIXEDAOAPOLAR && m_bType4))) { //is there anything to draw ? LegendPen.setColor(pPolar->m_Color); LegendPen.setStyle(GetStyle(pPolar->m_Style)); LegendPen.setWidth(pPolar->m_Width); painter.setPen(LegendPen); painter.drawLine(place.x() + (int)(1.0*LegendSize), place.y() + (int)(1.*legendHeight*ny)+2, place.x() + (int)(2.0*LegendSize), place.y() + (int)(1.*legendHeight*ny)+2); if(pPolar->m_bShowPoints) { x1 = place.x() + (int)(1.5*LegendSize); painter.drawRect(x1-2, place.y() + (int)(1.*legendHeight*ny), 4, 4); } painter.setPen(TextPen); painter.drawText(place.x() + (int)(2.5*LegendSize), place.y() + (int)(1.*legendHeight*ny)+(int)(legendHeight/3), pPolar->m_PlrName); ny++ ; } } } if (FoilPlrs) ny++; } // painter.setBackgroundMode(Qt::OpaqueMode); } /** * Paints a single polar graph, referenced by it index m_iPlrGraph * @param painter a reference to the QPainter object with which to draw */ void QXDirect::PaintSingleGraph(QPainter &painter) { int h = m_rCltRect.height(); int w = m_rCltRect.width(); int w3 = (int)(w/3); QRect Rect1(0,0,2*w3,h); QRect Rect2(2*w3, 0, w-2*w3,h); painter.fillRect(Rect2, MainFrame::s_BackgroundColor); if(m_iPlrGraph>=0 && m_iPlrGraphDrawGraph(Rect1, painter); PaintPolarLegend(m_PolarLegendOffset, h, painter); } /** * Paints the view. Calls either the painting of the OpPoint or the polar view. * @param painter a reference to the QPainter object with which to draw */ void QXDirect::PaintView(QPainter &painter) { if(MainFrame::s_pCurFoil && !m_bPolarView) { PaintOpPoint(painter); } else if (m_bPolarView) { if(m_iPlrView==ALLPOLARGRAPHS) PaintPolarGraphs(painter); else if(m_iPlrView==ONEPOLARGRAPH) PaintSingleGraph(painter); else if(m_iPlrView==TWOPOLARGRAPHS) PaintCoupleGraphs(painter); } else { painter.fillRect(m_rCltRect, MainFrame::s_BackgroundColor); } } /** * Reads the analysis parameters from the widgets. */ void QXDirect::ReadParams() { if(!m_pCurPolar) return; if (m_pctrlSpec1->isChecked()) m_bAlpha = true; else if (m_pctrlSpec2->isChecked()) m_bAlpha = false; else if (m_pctrlSpec3->isChecked()) m_bAlpha = false; if(m_pCurPolar->m_PolarType!=FIXEDAOAPOLAR) { if(m_bAlpha) { m_Alpha = m_pctrlAlphaMin->Value(); m_AlphaMax = m_pctrlAlphaMax->Value(); m_AlphaDelta = m_pctrlAlphaDelta->Value(); } else { m_Cl = m_pctrlAlphaMin->Value(); m_ClMax = m_pctrlAlphaMax->Value(); m_ClDelta = m_pctrlAlphaDelta->Value(); } } else { m_Reynolds = m_pctrlAlphaMin->Value(); m_ReynoldsMax = m_pctrlAlphaMax->Value(); m_ReynoldsDelta = m_pctrlAlphaDelta->Value(); } m_bSequence = m_pctrlSequence->isChecked(); m_bInitBL = m_pctrlInitBL->isChecked(); m_bViscous = m_pctrlViscous->isChecked(); m_bStoreOpp = m_pctrlStoreOpp->isChecked(); } /** * Saves the user-defined settings * @param pSettings a pointer to the QSetting object. */ void QXDirect::SaveSettings(QSettings *pSettings) { QString str1, str2, str3; pSettings->beginGroup("XDirect"); { pSettings->setValue("AlphaSpec", m_bAlpha); pSettings->setValue("StoreOpp", m_bStoreOpp); pSettings->setValue("ViscousAnalysis", m_bViscous); pSettings->setValue("InitBL", m_bInitBL); pSettings->setValue("BoundaryLayer", m_bBL); pSettings->setValue("Pressure", m_bPressure); pSettings->setValue("PolarView", m_bPolarView); pSettings->setValue("UserGraph", m_bShowUserGraph); pSettings->setValue("ShowPanels", m_bShowPanels); pSettings->setValue("Type1", m_bType1); pSettings->setValue("Type2", m_bType2); pSettings->setValue("Type3", m_bType3); pSettings->setValue("Type4", m_bType4); pSettings->setValue("AutoInitBL", m_bAutoInitBL); pSettings->setValue("FromList", m_bFromList); pSettings->setValue("FromZero", m_bFromZero); pSettings->setValue("TextOutput", m_bShowTextOutput); pSettings->setValue("NeutralLine", m_bNeutralLine); pSettings->setValue("CurOppOnly", m_bCurOppOnly); pSettings->setValue("ShowInviscid", m_bShowInviscid); pSettings->setValue("ShowCpGraph", m_bCpGraph); pSettings->setValue("Sequence", m_bSequence); pSettings->setValue("HighlightOpp",m_bHighlightOpp); pSettings->setValue("BLColorRed", m_crBLColor.red()); pSettings->setValue("BLColorGreen",m_crBLColor.green()); pSettings->setValue("BLColorBlue", m_crBLColor.blue()); pSettings->setValue("BLStyle", m_iBLStyle); pSettings->setValue("BLWidth", m_iBLWidth); pSettings->setValue("PressureColorRed", m_crPressureColor.red()); pSettings->setValue("PressureColorGreen",m_crPressureColor.green()); pSettings->setValue("PressureColorBlue", m_crPressureColor.blue()); pSettings->setValue("PressureStyle", m_iPressureStyle); pSettings->setValue("PressureWidth", m_iPressureWidth); pSettings->setValue("NeutralColorRed", m_crNeutralColor.red()); pSettings->setValue("NeutralColorGreen",m_crNeutralColor.green()); pSettings->setValue("NeutralColorBlue", m_crNeutralColor.blue()); pSettings->setValue("NeutralStyle", m_iNeutralStyle); pSettings->setValue("NeutralWidth", m_iNeutralWidth); pSettings->setValue("XFoilVar", m_XFoilVar); pSettings->setValue("IterLim", m_IterLim); pSettings->setValue("PlrGraph", m_iPlrGraph); switch(m_iPlrView) { case ONEPOLARGRAPH: pSettings->setValue("PlrView", 1); break; case TWOPOLARGRAPHS: pSettings->setValue("PlrView", 2); break; default: pSettings->setValue("PlrView", 0); break; } pSettings->setValue("AlphaMin", m_Alpha); pSettings->setValue("AlphaMax", m_AlphaMax); pSettings->setValue("AlphaDelta", m_AlphaDelta); pSettings->setValue("ClMin", m_Cl); pSettings->setValue("ClMax", m_ClMax); pSettings->setValue("ClDelta", m_ClDelta); pSettings->setValue("ReynoldsMin", m_Reynolds); pSettings->setValue("ReynoldsMax", m_ReynoldsMax); pSettings->setValue("ReynolsDelta", m_ReynoldsDelta); pSettings->setValue("NCrit", m_NCrit); pSettings->setValue("XTopTr", m_XTopTr); pSettings->setValue("XBotTr", m_XBotTr); pSettings->setValue("Mach", m_Mach); pSettings->setValue("ASpec", m_ASpec); pSettings->setValue("VAccel", m_pXFoil->vaccel); pSettings->setValue("AutoInitBL", m_bAutoInitBL); pSettings->setValue("FullReport", m_pXFoil->m_bFullReport); pSettings->setValue("NReynolds", m_NRe); if(m_PolarType==FIXEDSPEEDPOLAR) pSettings->setValue("Type", 1); else if(m_PolarType==FIXEDSPEEDPOLAR) pSettings->setValue("Type", 2); else if(m_PolarType==FIXEDAOAPOLAR) pSettings->setValue("Type", 4); else if(m_PolarType==STABILITYPOLAR) pSettings->setValue("Type", 7); for (int i=0; isetValue(str1, m_ReList[i]); pSettings->setValue(str2, m_MachList[i]); pSettings->setValue(str3, m_NCritList[i]); } } pSettings->endGroup(); m_PlrGraph[0].SaveSettings(pSettings); m_PlrGraph[2].SaveSettings(pSettings); m_PlrGraph[1].SaveSettings(pSettings); m_PlrGraph[3].SaveSettings(pSettings); m_PlrGraph[4].SaveSettings(pSettings); m_pCpGraph->SaveSettings(pSettings); } /** * Initializes the widget values, depending on the type of Polar */ void QXDirect::SetAnalysisParams() { m_pctrlViscous->setChecked(m_bViscous); m_pctrlInitBL->setChecked(m_bInitBL); m_pctrlStoreOpp->setChecked(m_bStoreOpp); m_pctrlShowPressure->setChecked(m_bPressure); m_pctrlShowBL->setChecked(m_bBL); if(m_pCurPolar) { if(m_pCurPolar->m_PolarType!=FIXEDAOAPOLAR) { m_pctrlAlphaMin->SetPrecision(2); m_pctrlAlphaMax->SetPrecision(2); m_pctrlAlphaDelta->SetPrecision(2); if(m_bAlpha) m_pctrlSpec1->setChecked(true); else m_pctrlSpec2->setChecked(true); m_pctrlSpec3->setEnabled(false); } else { m_pctrlSpec3->setChecked(true); m_pctrlSpec3->setEnabled(true); m_pctrlAlphaMin->SetPrecision(0); m_pctrlAlphaMax->SetPrecision(0); m_pctrlAlphaDelta->SetPrecision(0); } } else { if(m_bAlpha) m_pctrlSpec1->setChecked(true); else m_pctrlSpec2->setChecked(true); m_pctrlSpec3->setEnabled(false); } SetOpPointSequence(); SetCurveParams(); } /** * Sets the buffer Foil as a copy of the active Foil. * All geometric modifications are made on the buffer foil. * The buffer foil is the one displayed in the OpPoint view. */ void QXDirect::SetBufferFoil() { if(!MainFrame::s_pCurFoil || !MainFrame::s_pCurFoil->m_FoilName.length()) return; m_BufferFoil.CopyFoil(MainFrame::s_pCurFoil); m_BufferFoil.m_FoilName = MainFrame::s_pCurFoil->m_FoilName; m_BufferFoil.m_FoilColor = MainFrame::s_pCurFoil->m_FoilColor; m_BufferFoil.m_nFoilStyle = MainFrame::s_pCurFoil->m_nFoilStyle; m_BufferFoil.m_nFoilWidth = MainFrame::s_pCurFoil->m_nFoilWidth; } /** * Updates the combobox widgets with the curve data from the active OpPoint or Polar, depending on the active view. */ void QXDirect::SetCurveParams() { if(m_bPolarView) { if(m_pCurPolar) { if(m_pCurPolar->m_bIsVisible) m_pctrlShowCurve->setChecked(true); else m_pctrlShowCurve->setChecked(false); if(m_pCurPolar->m_bShowPoints) m_pctrlShowPoints->setChecked(true); else m_pctrlShowPoints->setChecked(false); m_CurveColor = m_pCurPolar->m_Color; m_CurveStyle = m_pCurPolar->m_Style; m_CurveWidth = m_pCurPolar->m_Width; FillComboBoxes(); } else { FillComboBoxes(false); } } else { //set Opoint params if(m_pCurOpp) { if(m_pCurOpp->m_bIsVisible) m_pctrlShowCurve->setChecked(true); else m_pctrlShowCurve->setChecked(false); if(m_pCurOpp->m_bShowPoints) m_pctrlShowPoints->setChecked(true); else m_pctrlShowPoints->setChecked(false); m_CurveColor = m_pCurOpp->m_Color; m_CurveStyle = m_pCurOpp->m_Style; m_CurveWidth = m_pCurOpp->m_Width; FillComboBoxes(); } else { FillComboBoxes(false); } } if(m_pCurPolar) { if(m_pCurPolar->m_PolarType!=FIXEDAOAPOLAR) { m_pctrlUnit1->setText(QString::fromUtf8("°")); m_pctrlUnit2->setText(QString::fromUtf8("°")); m_pctrlUnit3->setText(QString::fromUtf8("°")); } else { m_pctrlUnit1->setText(""); m_pctrlUnit2->setText(""); m_pctrlUnit3->setText(""); } } } /** * Initializes QXDirect with the data of the input Foil object. * If no Foil is proposed in input, sets the first stock Foil in alphabetical order. * Sets the first Polar object belonging to this Foil, if any. * Sets the first OpPoint object belonging to this Polar, if any. * @param pFoil a pointer to the active Foil object, or NULL if a stock Foil should be used. * @return a pointer to the Foil object which has been set. */ Foil* QXDirect::SetFoil(Foil* pFoil) { // MainFrame* pMainFrame = (MainFrame*)m_pMainFrame; StopAnimate(); MainFrame::s_pCurFoil = pFoil; if(!MainFrame::s_pCurFoil) { //take the first in the array, if any if(m_poaFoil->size()) { MainFrame::s_pCurFoil = (Foil*)m_poaFoil->at(0); } } if(MainFrame::s_pCurFoil && !m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil)) { DeleteFoil(false); MainFrame::s_pCurFoil = NULL; } else { if(!MainFrame::s_pCurFoil) { m_pCurPolar = NULL; m_pCurOpp = NULL; } else if (m_pCurPolar && m_pCurPolar->m_FoilName !=MainFrame::s_pCurFoil->m_FoilName) { // m_pCurPolar = NULL; // m_pCurOpp = NULL; } else if (m_pCurOpp && m_pCurOpp->m_strFoilName !=MainFrame::s_pCurFoil->m_FoilName) { // m_pCurOpp = NULL; } } SetBufferFoil(); SetPolar(); return MainFrame::s_pCurFoil; } /** * Initializes QXDirect with the specified name * Sets the first Polar object belonging to this Foil, if any. * Sets the first OpPoint object belonging to this Polar, if any. * @param FoilName to name of the Foil object to set. * @return a pointer to the Foil object which has been set. */ Foil* QXDirect::SetFoil(QString FoilName) { // MainFrame* pMainFrame = (MainFrame*)m_pMainFrame; int j; StopAnimate(); if(FoilName.length()) { Foil *pFoil; MainFrame::s_pCurFoil = NULL; for (j=0; j< m_poaFoil->size(); j++) { pFoil = (Foil*)m_poaFoil->at(j); if(pFoil->m_FoilName == FoilName) { MainFrame::s_pCurFoil = pFoil; break; } } } else MainFrame::s_pCurFoil = NULL; if(MainFrame::s_pCurFoil) { if(!m_pXFoil->InitXFoilGeometry(MainFrame::s_pCurFoil)) { MainFrame::s_pCurFoil=NULL; DeleteFoil(false); SetPolar(); return NULL; } } if(!MainFrame::s_pCurFoil) { m_pCurPolar = NULL; m_pCurOpp = NULL; } else if(m_pCurPolar && m_pCurPolar->m_FoilName !=MainFrame::s_pCurFoil->m_FoilName) { // m_pCurPolar = NULL; // m_pCurOpp = NULL; } else if(m_pCurOpp && m_pCurOpp->m_strFoilName !=MainFrame::s_pCurFoil->m_FoilName) { // m_pCurOpp = NULL; } //are there 2 or more Opps associated to this foil int count = 0; OpPoint *pOpp; for (int i=0; i< m_poaOpp->size(); i++) { pOpp = (OpPoint*)m_poaOpp->at(i); if(pOpp->m_strFoilName == FoilName) count++; if(count>=2) break; } SetBufferFoil(); SetPolar(); return MainFrame::s_pCurFoil; } /** * Sets the Foil scale in the OpPoint view. * @param CltRect the size of the client rectangle */ void QXDirect::SetFoilScale(QRect CltRect) { m_rCltRect = CltRect; int w23 = (int)(2./3.*(double)m_rCltRect.width()); m_PolarLegendOffset = QPoint(w23+10, 10); SetFoilScale(); } /** * Sets the Foil scale in the OpPoint view. */ void QXDirect::SetFoilScale() { QRect rect(10, 10, + m_rCltRect.width()-20, m_rCltRect.height()-2*m_FoilYPos); m_pCpGraph->SetDrawRect(rect); m_FoilOffset.rx() = rect.left() +(int)(1.0*m_pCpGraph->GetMargin()); m_FoilOffset.ry() = m_rCltRect.bottom()-m_FoilYPos; m_fFoilScale = (rect.width()-2.0*m_pCpGraph->GetMargin()); if(m_pCpGraph->GetYVariable()>=2) { double p0 = m_pCpGraph->xToClient(0.0); double p1 = m_pCpGraph->xToClient(1.0); m_fFoilScale = (p1-p0); } } /** * Calculates the moments acting on the flap hinges * @param pOpPoint */ void QXDirect::SetHingeMoments(OpPoint *pOpPoint) { // bool bFound; int i; double hmom, hfx, hfy; double dx, dy, xmid, ymid, pmid; double xof, yof; double ymin, ymax; xof = MainFrame::s_pCurFoil->m_TEXHinge/100.0; ymin = MainFrame::s_pCurFoil->GetBaseLowerY(xof); ymax = MainFrame::s_pCurFoil->GetBaseUpperY(xof); yof = ymin + (ymax-ymin) * MainFrame::s_pCurFoil->m_TEYHinge/100.0; if(MainFrame::s_pCurFoil->m_bTEFlap) { hmom = 0.0; hfx = 0.0; hfy = 0.0; //---- integrate pressures on top and bottom sides of flap for (i=0;in-1;i++) { if (MainFrame::s_pCurFoil->x[i]>xof && MainFrame::s_pCurFoil->x[i+1]>xof) { dx = MainFrame::s_pCurFoil->x[i+1] - MainFrame::s_pCurFoil->x[i]; dy = MainFrame::s_pCurFoil->y[i+1] - MainFrame::s_pCurFoil->y[i]; xmid = 0.5*(MainFrame::s_pCurFoil->x[i+1]+MainFrame::s_pCurFoil->x[i]) - xof; ymid = 0.5*(MainFrame::s_pCurFoil->y[i+1]+MainFrame::s_pCurFoil->y[i]) - yof; if(pOpPoint->m_bViscResults) pmid = 0.5*(pOpPoint->Cpv[i+1] + pOpPoint->Cpv[i]); else pmid = 0.5*(pOpPoint->Cpi[i+1] + pOpPoint->Cpi[i]); hmom += pmid * (xmid*dx + ymid*dy); hfx -= pmid * dy; hfy += pmid * dx; } } //Next add top chunk left out in the previous loop /* bFound = false; for (i=0;in-1;i++){ if(MainFrame::g_ppCurFoil->x[i]>xof && MainFrame::g_ppCurFoil->x[i+1]m_TEHMom = hmom; pOpPoint->XForce = hfx; pOpPoint->YForce = hfy; } } /** * Initializes QXDirect with the specified Polar object. * If the specified polar is not valid, a stock polar associated to the current foil will be set. * Sets the first OpPoint object belonging to this Polar, if any. * Initializes the XFoil object with the Polar's data. * @param pPolar a pointer to the Polar object to set. If NULL, a stock polar associated to the current foil will be set. * @return a pointer to the Polar object which has been set. */ Polar * QXDirect::SetPolar(Polar *pPolar) { // Finds the plr // sets it as the active polar // and initializes XFoil StopAnimate(); if(!MainFrame::s_pCurFoil|| !MainFrame::s_pCurFoil->m_FoilName.length()) { m_pCurPolar = NULL; SetAnalysisParams(); return NULL; } if(pPolar) m_pCurPolar = pPolar; if(!m_pCurPolar) { //try to get one from the object array for(int i=0; isize(); i++) { pPolar = (Polar*)m_poaPolar->at(i); if(pPolar && pPolar->m_FoilName==MainFrame::s_pCurFoil->m_FoilName) { //set this one m_pCurPolar = pPolar; break; } } } if(m_pCurPolar) { if(m_pCurPolar->m_FoilName != MainFrame::s_pCurFoil->m_FoilName) { Polar *pOldPolar; bool bFound = false; for (int i=0; isize(); i++) { pOldPolar = (Polar*)m_poaPolar->at(i); if ((pOldPolar->m_FoilName == MainFrame::s_pCurFoil->m_FoilName) && (pOldPolar->m_PlrName == m_pCurPolar->m_PlrName)) { m_pCurPolar = pOldPolar; bFound = true; break; } } if(!bFound) { m_pCurPolar = NULL; m_pCurOpp = NULL; } } m_bInitBL = true; m_pctrlInitBL->setChecked(m_bInitBL); } m_pXFoil->InitXFoilAnalysis(m_pCurPolar); if (m_bPolarView) CreatePolarCurves(); SetAnalysisParams(); SetOpp(); return m_pCurPolar; } /** * Initializes QXDirect with the Polar with the specified name and associated to the active Foil object. * If the specified polar is not valid, a stock polar associated to the current foil will be set. * Sets the first OpPoint object belonging to this Polar, if any. * Initializes the XFoil object with the Polar's data. * @param pPolar a pointer to the Polar object to set. If NULL, a stock polar associated to the current foil will be set. * @return a pointer to the Polar object which has been set. */ Polar * QXDirect::SetPolar(QString PlrName) { // Finds the plr with name PlrName // sets it as the active polar // and initializes XFoil MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(!MainFrame::s_pCurFoil) return NULL; if(!PlrName.length()) {// try to read it if (!pMainFrame->m_pctrlPolar->count()) { m_pCurPolar = NULL; m_pCurOpp = NULL; return NULL;//give up } //else PlrName = pMainFrame->m_pctrlPolar->currentText(); } m_pCurPolar = pMainFrame->GetPolar(MainFrame::s_pCurFoil->m_FoilName, PlrName); if (!m_pCurPolar || !MainFrame::s_pCurFoil || !m_pCurPolar->m_FoilName.length() || !MainFrame::s_pCurFoil->m_FoilName.length()) { m_pCurPolar = NULL; m_pCurOpp = NULL; return NULL; } if(m_pCurPolar && (m_pCurPolar->m_FoilName == MainFrame::s_pCurFoil->m_FoilName)) { m_pXFoil->InitXFoilAnalysis(m_pCurPolar); } else { m_pCurPolar = NULL; m_pCurOpp = NULL; } m_bInitBL = true; m_pctrlInitBL->setChecked(m_bInitBL); if(m_pCurOpp) { if (m_pCurOpp->m_strFoilName != MainFrame::s_pCurFoil->m_FoilName || m_pCurOpp->m_strPlrName != PlrName) { // does the Opp exist for these Foil/plrs ? OpPoint *pOpp; bool bFound = false; for (int l =0; lsize(); l++) { pOpp = (OpPoint*)m_poaOpp->at(l); if (pOpp->m_strFoilName == MainFrame::s_pCurFoil->m_FoilName && pOpp->m_strPlrName == PlrName) { if(qAbs(pOpp->Alpha-m_pCurOpp->Alpha)<0.0001) { m_pCurOpp = pOpp; bFound = true; break; } } } if(!bFound) m_pCurOpp = NULL;//give up } } SetAnalysisParams(); SetOpp(); return m_pCurPolar; } /** * Initializes QXDirect with the OpPoint with the specified aoa. * If the OpPoint cannot be found for the active Foil and Polar, a stock OpPoint associated to the current foil and polar will be set. * @param Alpha the aoa of the OpPoint to ser * @return a pointer to the OpPoint object which has been set. */ OpPoint * QXDirect::SetOpp(double Alpha) { // set the opp, if valid // else set the current Opp, if any // else set the comboBox's first, if any // else set it to NULL OpPoint * pOpp = NULL; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; QString strong; if(!MainFrame::s_pCurFoil) return NULL; if(!m_pCurPolar) return NULL; if(Alpha < -1234567.0) //the default { if(m_pCurOpp && m_pCurOpp->m_strFoilName == MainFrame::s_pCurFoil->m_FoilName) pOpp = m_pCurOpp; else { //try to get one from the combobox if(pMainFrame->m_pctrlOpPoint->count()) { QString strong; bool bOK; int sel = pMainFrame->m_pctrlOpPoint->currentIndex(); if (sel>=0) strong = pMainFrame->m_pctrlOpPoint->itemText(sel); Alpha = strong.toFloat(&bOK); if(!bOK) pOpp = NULL; else pOpp = pMainFrame->GetOpp(Alpha); } else pOpp = NULL; } } else { pOpp = pMainFrame->GetOpp(Alpha); } if(pOpp) { //set it pMainFrame->SelectOpPoint(pOpp);//to Combobox } m_pCurOpp = pOpp; if(!m_bPolarView) CreateOppCurves(); else { if(m_bHighlightOpp) CreatePolarCurves(); } SetCurveParams(); return m_pCurOpp; } /** * Initializes the widgets with the sequence parameters for the type of the active Polar object. */ void QXDirect::SetOpPointSequence() { m_pctrlSequence->setEnabled(m_pCurPolar); m_pctrlAlphaMin->setEnabled(m_pCurPolar); m_pctrlAnalyze->setEnabled(m_pCurPolar); m_pctrlViscous->setEnabled(m_pCurPolar); m_pctrlInitBL->setEnabled(m_pCurPolar); m_pctrlStoreOpp->setEnabled(m_pCurPolar); if(m_bSequence && m_pCurPolar) { m_pctrlSequence->setCheckState(Qt::Checked); m_pctrlAlphaMax->setEnabled(true); m_pctrlAlphaDelta->setEnabled(true); } else if (m_pCurPolar) { m_pctrlSequence->setCheckState(Qt::Unchecked); m_pctrlAlphaMax->setEnabled(false); m_pctrlAlphaDelta->setEnabled(false); } else { m_pctrlAlphaMax->setEnabled(false); m_pctrlAlphaDelta->setEnabled(false); } if(m_pCurPolar && m_pCurPolar->m_PolarType!=FIXEDAOAPOLAR) { if(m_pctrlSpec3->isChecked()) { m_pctrlSpec1->setChecked(true); m_bAlpha = true; } if(m_bAlpha) { m_pctrlAlphaMin->SetValue(m_Alpha); m_pctrlAlphaMax->SetValue(m_AlphaMax); m_pctrlAlphaDelta->SetValue(m_AlphaDelta); } else { m_pctrlAlphaMin->SetValue(m_Cl); m_pctrlAlphaMax->SetValue(m_ClMax); m_pctrlAlphaDelta->SetValue(m_ClDelta); } m_pctrlSpec1->setEnabled(true); m_pctrlSpec2->setEnabled(true); m_pctrlSpec3->setEnabled(false); } else if(m_pCurPolar && m_pCurPolar->m_PolarType==FIXEDAOAPOLAR) { m_pctrlSpec3->setChecked(true); m_bAlpha = true; // no choice with type 4 polars m_pctrlAlphaMin->SetValue(m_Reynolds); m_pctrlAlphaMax->SetValue(m_ReynoldsMax); m_pctrlAlphaDelta->SetValue(m_ReynoldsDelta); m_pctrlSpec1->setEnabled(false); m_pctrlSpec2->setEnabled(false); m_pctrlSpec3->setEnabled(true); } else { m_pctrlSpec1->setEnabled(false); m_pctrlSpec2->setEnabled(false); m_pctrlSpec3->setEnabled(false); } } /** * Sets the axis titles for the specified graph * @param pGraph a pointer to the Graph object for which the titles will be set */ void QXDirect::SetGraphTitles(Graph* pGraph) { if(!pGraph) return; QString Title; Polar::GetPlrVariableName(pGraph->GetXVariable(),Title); pGraph->SetXTitle(Title); Polar::GetPlrVariableName(pGraph->GetYVariable(), Title); pGraph->SetYTitle(Title); } /** * Sets the position of the polar graph legend, depending on the number of requested graphs */ void QXDirect::SetPolarLegendPos() { int h = m_rCltRect.height(); int w = m_rCltRect.width(); int h2 = (int)(h/2); int h23 = (int)(2*h/3); int w3 = (int)(w/3); int w23 = 2*w3; int margin = 10; if(m_iPlrView == ONEPOLARGRAPH) { m_PolarLegendOffset.rx() = w23+margin; m_PolarLegendOffset.ry() = margin; } else if (m_iPlrView == TWOPOLARGRAPHS) { m_PolarLegendOffset.rx() = margin; m_PolarLegendOffset.ry() = h23+margin; } else if (m_iPlrView == ALLPOLARGRAPHS) { m_PolarLegendOffset.rx() = margin; m_PolarLegendOffset.ry() = h2+30; } } /** * Creates the GUI associated to the toolbar. */ void QXDirect::SetupLayout() { QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::Expanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Expanding); QSizePolicy szPolicyMinimum; szPolicyMinimum.setHorizontalPolicy(QSizePolicy::Minimum); szPolicyMinimum.setVerticalPolicy(QSizePolicy::Minimum); QSizePolicy szPolicyMaximum; szPolicyMaximum.setHorizontalPolicy(QSizePolicy::Maximum); szPolicyMaximum.setVerticalPolicy(QSizePolicy::Maximum); QGroupBox *AnalysisBox = new QGroupBox(tr("Analysis settings")); { QVBoxLayout *AnalysisGroup = new QVBoxLayout; { m_pctrlSequence = new QCheckBox(tr("Sequence")); m_pctrlStoreOpp = new QCheckBox(tr("Store Opp")); m_pctrlAnalyze = new QPushButton(tr("Analyze")); QHBoxLayout *SpecVarsLayout = new QHBoxLayout; { m_pctrlSpec1 = new QRadioButton("a"); m_pctrlSpec2 = new QRadioButton(tr("Cl")); m_pctrlSpec3 = new QRadioButton(tr("Re")); m_pctrlSpec1->setFont(QFont("Symbol")); SpecVarsLayout->addWidget(m_pctrlSpec1); SpecVarsLayout->addWidget(m_pctrlSpec2); SpecVarsLayout->addWidget(m_pctrlSpec3); } QGridLayout *SequenceGroupLayout = new QGridLayout; { QLabel *AlphaMinLab = new QLabel(tr("Start=")); QLabel *AlphaMaxLab = new QLabel(tr("End=")); QLabel *DeltaAlphaLab = new QLabel(tr("D=")); DeltaAlphaLab->setFont(QFont("Symbol")); DeltaAlphaLab->setAlignment(Qt::AlignRight); AlphaMinLab->setAlignment(Qt::AlignRight); AlphaMaxLab->setAlignment(Qt::AlignRight); m_pctrlUnit1 = new QLabel(QString::fromUtf8("°")); m_pctrlUnit2 = new QLabel(QString::fromUtf8("°")); m_pctrlUnit3 = new QLabel(QString::fromUtf8("°")); m_pctrlAlphaMin = new DoubleEdit(); m_pctrlAlphaMax = new DoubleEdit(); m_pctrlAlphaDelta = new DoubleEdit(); m_pctrlAlphaMin->setMinimumHeight(20); m_pctrlAlphaMax->setMinimumHeight(20); m_pctrlAlphaDelta->setMinimumHeight(20); m_pctrlAlphaMin->setAlignment(Qt::AlignRight); m_pctrlAlphaMax->setAlignment(Qt::AlignRight); m_pctrlAlphaDelta->setAlignment(Qt::AlignRight); SequenceGroupLayout->addWidget(AlphaMinLab,1,1); SequenceGroupLayout->addWidget(AlphaMaxLab,2,1); SequenceGroupLayout->addWidget(DeltaAlphaLab,3,1); SequenceGroupLayout->addWidget(m_pctrlAlphaMin,1,2); SequenceGroupLayout->addWidget(m_pctrlAlphaMax,2,2); SequenceGroupLayout->addWidget(m_pctrlAlphaDelta,3,2); SequenceGroupLayout->addWidget(m_pctrlUnit1,1,3); SequenceGroupLayout->addWidget(m_pctrlUnit2,2,3); SequenceGroupLayout->addWidget(m_pctrlUnit3,3,3); } QHBoxLayout *AnalysisSettings = new QHBoxLayout; { m_pctrlViscous = new QCheckBox(tr("Viscous")); m_pctrlInitBL = new QCheckBox(tr("Init BL")); AnalysisSettings->addWidget(m_pctrlViscous); AnalysisSettings->addWidget(m_pctrlInitBL); } AnalysisGroup->addLayout(SpecVarsLayout); AnalysisGroup->addStretch(1); AnalysisGroup->addWidget(m_pctrlSequence); AnalysisGroup->addLayout(SequenceGroupLayout); AnalysisGroup->addStretch(1); AnalysisGroup->addLayout(AnalysisSettings); AnalysisGroup->addWidget(m_pctrlStoreOpp); AnalysisGroup->addWidget(m_pctrlAnalyze); } AnalysisBox->setLayout(AnalysisGroup); } QGroupBox *DisplayBox = new QGroupBox(tr("Display")); { QVBoxLayout *DisplayGroup = new QVBoxLayout; { m_pctrlShowBL = new QCheckBox(tr("Show BL")); m_pctrlShowPressure = new QCheckBox(tr("Show Pressure")); m_pctrlAnimate = new QCheckBox(tr("Animate")); m_pctrlAnimateSpeed = new QSlider(Qt::Horizontal); m_pctrlAnimateSpeed->setMinimum(0); m_pctrlAnimateSpeed->setMaximum(500); m_pctrlAnimateSpeed->setSliderPosition(250); m_pctrlAnimateSpeed->setTickInterval(25); m_pctrlAnimateSpeed->setTickPosition(QSlider::TicksBelow); DisplayGroup->addWidget(m_pctrlShowBL); DisplayGroup->addWidget(m_pctrlShowPressure); DisplayGroup->addWidget(m_pctrlAnimate); DisplayGroup->addWidget(m_pctrlAnimateSpeed); DisplayGroup->addStretch(1); // DisplayGroup->addWidget(m_pctrlHighlightOpp); } DisplayBox->setLayout(DisplayGroup); DisplayBox->setSizePolicy(szPolicyExpanding); } QGroupBox *PolarPropsBox = new QGroupBox(tr("Polar properties")); { m_pctrlPolarProps = new QLabel; m_pctrlPolarProps->setSizePolicy(szPolicyExpanding); // m_pctrlPolarProps->setReadOnly(true); // m_pctrlPolarProps->setWordWrapMode(QTextOption::NoWrap); QHBoxLayout *PolarPropsLayout = new QHBoxLayout; { PolarPropsLayout->addWidget(m_pctrlPolarProps); PolarPropsBox->setLayout(PolarPropsLayout); } } QGroupBox *CurveBox = new QGroupBox(tr("Graph Curve Settings")); { QVBoxLayout *CurveGroup = new QVBoxLayout; { QHBoxLayout *CurveDisplay = new QHBoxLayout; { m_pctrlShowCurve = new QCheckBox(tr("Curve")); m_pctrlShowPoints = new QCheckBox(tr("Points")); CurveDisplay->addWidget(m_pctrlShowCurve); CurveDisplay->addWidget(m_pctrlShowPoints); } m_pctrlCurveStyle = new LineCbBox(this); m_pctrlCurveWidth = new LineCbBox(this); m_pctrlCurveColor = new LineBtn(this); m_pctrlCurveColor->setMinimumHeight(m_pctrlCurveStyle->minimumSizeHint().height()); for (int i=0; i<5; i++) { m_pctrlCurveStyle->addItem("item"); m_pctrlCurveWidth->addItem("item"); } m_pStyleDelegate = new LineDelegate; m_pWidthDelegate = new LineDelegate; m_pctrlCurveStyle->setItemDelegate(m_pStyleDelegate); m_pctrlCurveWidth->setItemDelegate(m_pWidthDelegate); QGridLayout *CurveStyleLayout = new QGridLayout; QLabel *lab200 = new QLabel(tr("Style")); QLabel *lab201 = new QLabel(tr("Width")); QLabel *lab202 = new QLabel(tr("Color")); lab200->setAlignment(Qt::AlignRight |Qt::AlignVCenter); lab201->setAlignment(Qt::AlignRight |Qt::AlignVCenter); lab202->setAlignment(Qt::AlignRight |Qt::AlignVCenter); CurveStyleLayout->addWidget(lab200,1,1); CurveStyleLayout->addWidget(lab201,2,1); CurveStyleLayout->addWidget(lab202,3,1); CurveStyleLayout->addWidget(m_pctrlCurveStyle,1,2); CurveStyleLayout->addWidget(m_pctrlCurveWidth,2,2); CurveStyleLayout->addWidget(m_pctrlCurveColor,3,2); CurveStyleLayout->setColumnStretch(2,5); CurveGroup->addLayout(CurveDisplay); CurveGroup->addLayout(CurveStyleLayout); CurveGroup->addStretch(1); } CurveBox->setLayout(CurveGroup); } QVBoxLayout *mainLayout = new QVBoxLayout; { m_pctrlMiddleControls = new QStackedWidget; m_pctrlMiddleControls->addWidget(DisplayBox); m_pctrlMiddleControls->addWidget(PolarPropsBox); mainLayout->addWidget(AnalysisBox); mainLayout->addStretch(1); mainLayout->addWidget(m_pctrlMiddleControls); mainLayout->addStretch(1); mainLayout->addWidget(CurveBox); mainLayout->addStretch(1); } setLayout(mainLayout); setAttribute(Qt::WA_AlwaysShowToolTips); setSizePolicy(szPolicyExpanding); } /** * Interrupts the OpPoint animation */ void QXDirect::StopAnimate() { if(m_bAnimate) { m_pAnimateTimer->stop(); m_bAnimate = false; m_pctrlAnimate->setChecked(false); SetOpp(); } } /** * Updates the curve's style based on the selection in the comboboxes. */ void QXDirect::UpdateCurveStyle() { if(m_bPolarView && m_pCurPolar) { m_pCurPolar->m_Color = m_CurveColor; m_pCurPolar->m_Style = m_CurveStyle; m_pCurPolar->m_Width = (int)m_CurveWidth; CreatePolarCurves(); } else if (!m_bPolarView && m_pCurOpp) { m_pCurOpp->m_Color = m_CurveColor; m_pCurOpp->m_Style = m_CurveStyle; m_pCurOpp->m_Width = (int)m_CurveWidth; CreateOppCurves(); } UpdateView(); MainFrame::SetSaveState(false); } /** * Refreshes the 2d central display. */ void QXDirect::UpdateView() { TwoDWidget *p2DWidget = (TwoDWidget*)s_p2DWidget; if(s_p2DWidget) { p2DWidget->update(); } } /** * Overrides the QWidget's wheelEvent method. * Dispatches the event * @param event the QWheelEvent */ void QXDirect::wheelEvent (QWheelEvent *event ) { // point is in client coordinates QPoint pt(event->x(), event->y()); //client coordinates static double ZoomFactor; if(event->delta()>0) { if(!MainFrame::s_bReverseZoom) ZoomFactor = 1./1.06; else ZoomFactor = 1.06; } else { if(!MainFrame::s_bReverseZoom) ZoomFactor = 1.06; else ZoomFactor = 1./1.06; } m_pCurGraph = GetGraph(pt); if(m_pCurGraph && m_pCurGraph->IsInDrawRect(pt) && m_bCpGraph) { if (m_bXPressed) { //zoom x scale m_pCurGraph->SetAutoX(false); m_pCurGraph->Scalex(1./ZoomFactor); } else if(m_bYPressed) { //zoom y scale m_pCurGraph->SetAutoY(false); m_pCurGraph->Scaley(1./ZoomFactor); } else { //zoom both m_pCurGraph->SetAuto(false); m_pCurGraph->Scale(1./ZoomFactor); } m_pCurGraph->SetAutoXUnit(); m_pCurGraph->SetAutoYUnit(); if(!m_bAnimate) UpdateView(); } else if(MainFrame::s_pCurFoil && !m_bPolarView) { double scale = m_fFoilScale; m_fFoilScale *= ZoomFactor; int a = (int)((m_rCltRect.right()+m_rCltRect.left())/2); m_FoilOffset.rx() = a + (int)((m_FoilOffset.x()-a)/scale*m_fFoilScale); if(!m_bAnimate) UpdateView(); } } xflr5-6.09-06/src/xdirect/TEGapDlg.h000644 001750 000144 00000003223 12247174405 020265 0ustar00techwinderusers000000 000000 /**************************************************************************** TEGapDlg Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef TEGAPDlg_H #define TEGAPDlg_H #include #include "../misc/DoubleEdit.h" #include "../objects/Foil.h" class TEGapDlg : public QDialog { Q_OBJECT friend class QXDirect; friend class QAFoil; public: TEGapDlg(QWidget *pParent=NULL); void SetupLayout(); void InitDialog(); private slots: void OnChanged(); void OnOK(); void OnApply(); private: void keyPressEvent(QKeyEvent *event); public: QPushButton *OKButton, *CancelButton, *ApplyButton; DoubleEdit *m_pctrlBlend, *m_pctrlGap; bool m_bApplied, m_bModified; double m_Gap, m_Blend; void *m_pXDirect; void *m_pAFoil; Foil* m_pBufferFoil; Foil* m_pMemFoil; static void* s_pXFoil; }; #endif // TEGAPDLG_H xflr5-6.09-06/src/xdirect/XFoil.h000644 001750 000144 00000106763 12247174410 017730 0ustar00techwinderusers000000 000000 /**************************************************************************** XFoil Class Copyright (C) 2000 Mark Drela Copyright (C) 2003 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** *@file This class defines the Xfoil object. */ #ifndef XFOIL_H #define XFOIL_H /** *@class XFoil *@brief The class which defines the XFoil object. This is a translation to C++ of the original Fortran code of Mark Drela and Harold Youngren. See http://raphael.mit.edu/xfoil for more information. */ #include #include #include #include #include "../objects/Foil.h" #include "../objects/Polar.h" using namespace std; //------ derived dimensioning limit parameters struct blData { public: double xz, uz, tz, dz, sz, amplz, uz_uei, uz_ms, dwz, hz, hz_tz, hz_dz, mz, mz_uz, mz_ms, rz, rz_uz, rz_ms, vz, vz_uz, vz_ms, vz_re, hkz, hkz_uz, hkz_tz, hkz_dz, hkz_ms, hsz, hsz_uz, hsz_tz, hsz_dz, hsz_ms, hsz_re, hcz, hcz_uz, hcz_tz, hcz_dz, hcz_ms, rtz, rtz_uz, rtz_tz, rtz_ms, rtz_re, cfz, cfz_uz, cfz_tz, cfz_dz, cfz_ms, cfz_re, diz, diz_uz, diz_tz, diz_dz, diz_sz, diz_ms, diz_re, usz, usz_uz, usz_tz, usz_dz, usz_ms, usz_re, cqz, cqz_uz, cqz_tz, cqz_dz, cqz_ms, cqz_re, dez, dez_uz, dez_tz, dez_dz, dez_ms; }; class XFoil { friend class QXDirect; friend class QXInverse; friend class FoilGeomDlg; friend class TEGapDlg; friend class LEDlg; friend class NacaFoilDlg; friend class XFoilAnalysisDlg; friend class BatchDlg; friend class BatchThreadDlg; //-----Specific Inverse MDES------------------------------- public: void inter(double x0[], double xp0[], double y0[], double yp0[], double s0[],int n0,double sle0, double x1[], double xp1[], double y1[], double yp1[], double s1[],int n1,double sle1, double x[], double y[], int n, double frac); void tcset(double cnew, double tnew); void thkcam(double tfac, double cfac); void qspint(int kqsp, double &clq); void splqsp(int kqsp); void qspcir(); void InitMDES(); bool InitQDES(); void cncalc(double qc[], bool lsymm); double qincom(double qc, double qinf, double tklam); double qcomp(double g); void qccalc(int ispec,double *alfa, double *cl, double *cm,double minf, double qinf, int *ncir, double xcir[], double ycir[], double scir[], double qcir[]); void mapgam(int iac, double &alg, double &clg, double &cmg); bool eiwset(int nc1); void cgauss(int nn,complex z[IMX4+1][IMX4+1],complex r[IMX4+1]); void zccalc(int mtest); void zcnorm(int mtest); void zlefind(complex*zle,complexzc[],double wc[],int nc,complexpiq[], double agte); void piqsum(); void ftp(); void scinit(int n, double x[], double xp[], double y[], double yp[], double s[], double sle); void mapgen(int n, double x[],double y[]); complex conjg(complex cplx); QString m_FoilName; bool m_bTrace; bool lqspec, lsym,leiw,lqslop,lscini, lrecalc, lcnpl; int nsp,nqsp,iacqsp; int nc,nc1,mc,mct; int iq1, iq2; // int kqtarg,nname,nprefix; double agte,ag0,qim0,qimold; double ssple, dwc,algam,clgam,cmgam; double wc[ICX+1],sc[ICX+1]; double scold[ICX+1],xcold[ICX+1],ycold[ICX+1]; double sspec[IBX+1],xspoc[IBX+1],yspoc[IBX+1], qgamm[IBX+1]; double qspec[IPX+1][IBX+1],qspecp[IPX+1][IBX+1]; double alqsp[IPX+1],clqsp[IPX+1],cmqsp[IPX+1]; double qf0[IQX+1],qf1[IQX+1],qf2[IQX+1],qf3[IQX+1]; double qdof0,qdof1,qdof2,qdof3,clspec,ffilt; complex dzte, chordz, zleold, zcoldw[ICX+1]; complex zc[ICX+1], zc_cn[ICX+1][IMX4+1]; complex piq[ICX+1], cn[IMX+1], eiw[ICX+1][IMX+1]; complex cnsav[IMX+1]; double dnTrace[100];//... added arcds double dgTrace[100];//... added arcds int QMax; // complex zcoldw, dzte, chordz, zleold, zc, zc_cn, piq, cn, eiw; //----- CIRCLE.INC include file for circle-plane operations // NC number of circle plane points, must be 2**n + 1 // MC number of Fourier harmonics of P(w) + iQ(w) // MCT number of Fourier harmonics for which dZC/dCN are calculated // // PI 3.1415926 // AGTE trailing edge angle/pi // AG0 angle of airfoil surface at first point // QIM0 Q(w) offset = Q(0) // QIMOLD Q(w) offset for old airfoil // DWC increment of circle-plane coordinate w, DWC = 2 pi/(NC-1) // WC(.) circle plane coordinate w for Fourier operations // SC(.) normalized arc length array s(w) // SCOLD(.) normalized arc length s(w) of old airfoil // XCOLD(.) x coordinate x(w) of old airfoil // YCOLD(.) y coordinate y(w) of old airfoil // // DZTE trailing edge gap specified in the complex plane // CHORDZ airfoil chord specified in the complex plane // ZLEOLD leading edge of old airfoil // ZCOLDW(.) d(x+iy)/dw of old airfoil // ZC(.) complex airfoil coordinates derived from P(w) + iQ(w) // ZC_CN(..) sensitivities dZC/dCN for driving geometry constraints // PIQ(.) complex harmonic function P(w) + iQ(w) // CN(.) Fourier coefficients of P(w) + iQ(w) // EIW(..) complex number exp(inw) array on the unit circle //-----End Specific Inverse MDES------------------------------- public: void SetFoilFlap(Foil *pFoil); void Interpolate(double xf1[], double yf1[], int n1, double xf2[], double yf2[], int n2, double mixt); void gamlin(int i, int j, double coef); bool mixed(int kqsp); void gamqsp(int kqsp); void pert_process(int kqsp); void pert_init(int kqsp); void cnfilt(double ffilt); void Filter(double cfilt); void smooq(int kq1,int kq2,int kqsp); void ExecMDES(); bool ExecQDES(); void RestoreQDES(); bool CheckAngles(); bool SetMach(); void scheck(double x[], double y[], int *n, double stol, bool *lchange); void sss(double ss, double *s1, double *s2, double del, double xbf, double ybf, double x[], double xp[], double y[], double yp[], double s[],int n, int iside); bool inside(double xb[], double yb[], int nb, double xbf, double ybf); void flap(); //____________FUNCTION & METHODS___________________________________________________ int cadd(int ispl, double atol, double xrf1, double xrf2); int arefine(double x[],double y[], double s[], double xs[], double ys[], int n, double atol, int ndim, double xnew[], double ynew[], double x1, double x2); bool abcopy(); bool comset(); bool mrcl(double cls, double &m_cls, double &r_cls); bool fcpmin(); bool Initialize(); bool InitXFoilGeometry(Foil *pFoil); bool InitXFoilAnalysis(Polar *pPolar); void pangen(); bool Preprocess(); bool restoreblData(int icom); bool saveblData(int icom); bool specal(); bool speccl(); bool viscal(); bool ViscalEnd(); bool ViscousIter(); XFoil(); virtual ~XFoil(); //____________VARIABLES___________________________________________________ double thickb,cambrb; bool lalfa, lvisc, lvconv, lwake; bool lbflap,lflap; bool lblini, lipan,lcpxx,lqsym; int n, nb,iblte[ISX],ipan[IVX][ISX],nbl[ISX]; int npan; int imax;// needed for preprocessing int retyp, matyp; int niterq; double x[IZX],y[IZX],xstrip[ISX],xoctr[ISX],yoctr[ISX]; double dstr[IVX][ISX]; double cl,cm,cd,cdp,cdf,cpi[IZX],cpv[IZX],acrit; double xcp; double amax;// needed for preprocessing double cvpar,cterat,ctrrat,xsref1,xsref2,xpref1,xpref2; double minf1,vaccel; double rmxbl,rlx; double xbf,ybf; double xb[IBX],yb[IBX],nx[IZX],ny[IZX]; double alfa, avisc, awake, reinf1, qinf, mvisc, rmsbl, ante; double ddef; // flap angle double hmom,hfx,hfy; double cpmn; double minf, reinf; double minf_cl, reinf_cl; double angtol; QFile *pXFile; protected: double DeRotate(); //____________FUNCTION & METHODS___________________________________________________ bool aecalc(int n, double x[], double y[], double t[], int itype, double &area, double &xcen, double &ycen, double &ei11, double &ei22, double &apx1, double &apx2); bool apcalc(); bool axset( double hk1, double t1, double rt1, double a1, double hk2, double t2, double rt2, double a2, double acrit, double &ax, double &ax_hk1, double &ax_t1, double &ax_rt1, double &ax_a1, double &ax_hk2, double &ax_t2, double &ax_rt2, double &ax_a2); bool baksub(int n, double a[IQX][IQX],int indx[], double b[]); bool bldif(int ityp); bool blkin(); bool blmid(int ityp); bool blprv(double xsi,double ami,double cti,double thi,double dsi,double dswaki,double uei); bool blsolve(); bool blsys(); bool blvar(int ityp); bool cang(double x[], double y[], int n, int &imax, double &amax); bool cdcalc(); bool cfl(double hk, double rt, double &cf, double &cf_hk, double &cf_rt, double &cf_msq); bool cft(double hk, double rt, double msq, double &cf, double &cf_hk, double &cf_rt, double &cf_msq); bool clcalc(double xref, double yref); bool cpcalc(int n, double q[], double qinf, double minf, double cp[]); bool dampl(double hk, double th, double rt, double &ax, double &ax_hk, double &ax_th, double &ax_rt); bool dil(double hk, double rt, double &di, double &di_hk, double &di_rt); bool dilw(double hk, double rt, double &di, double &di_hk, double &di_rt); bool dslim(double &dstr, double thet, double msq, double hklim); bool gamqv(); bool Gauss(int nn, double z[][6], double r[5]); bool Gauss(int nn, double z[IQX][IQX], double r[IQX]); bool geopar(double x[], double xp[], double y[], double yp[], double s[], int n, double t[], double &sle, double &chord, double &area, double &radle, double &angte, double &ei11a, double &ei22a, double &apx1a, double &apx2a, double &ei11t, double &ei22t, double &apx1t, double &apx2t); void sopps(double &sopp, double si, double x[], double xp[], double y[], double yp[], double s[], int n, double sle); void getcam(double xcm[],double ycm[], int &ncm,double xtk[],double ytk[],int &ntk, double x[],double xp[],double y[],double yp[],double s[],int n ); void getmax(double x[],double y[], double yp[], int n,double &xmax, double &ymax); void hipnt(double xhc, double xht); void xlfind(double &sle, double x[], double xp[], double y[], double yp[], double s[], int n); void sortol(double tol,int &kk,double s[],double w[]); bool getxyf(double x[],double xp[],double y[],double yp[],double s[], int n, double &tops, double &bots,double xf,double &yf); bool ggcalc(); bool hct(double hk, double msq, double &hc, double &hc_hk, double &hc_msq); bool hkin(double h, double msq, double &hk, double &hk_h, double &hk_msq); bool hsl(double hk, double &hs, double &hs_hk, double &hs_rt, double &hs_msq); bool hst(double hk, double rt, double msq, double &hs, double &hs_hk, double &hs_rt, double &hs_msq ); bool iblpan(); bool iblsys(); bool lefind(double &sle, double x[], double xp[], double y[], double yp[], double s[], int n); void lerscl(double *x, double *xp, double* y, double *yp, double *s, int n, double doc, double rfac, double *xnew,double *ynew); bool ludcmp(int n, double a[IQX][IQX],int indx[IQX]); bool mhinge(); bool mrchdu(); bool mrchue(); bool ncalc(double x[], double y[], double s[], int n, double xn[], double yn[]); bool psilin(int i, double xi,double yi,double nxi, double nyi, double &psi, double &psi_ni, bool geolin, bool siglin); bool pswlin(int i,double xi, double yi, double nxi, double nyi, double &psi, double &psi_ni); bool qdcalc(); bool qiset(); bool qvfue(); bool qwcalc(); bool scalc(double x[], double y[], double s[], int n); bool segspl( double x[], double xs[], double s[], int n); bool segspld(double x[], double xs[], double s[], int n, double xs1, double xs2); bool setbl(); bool setexp(double s[],double ds1,double smax,int nn); bool sinvrt(double &si,double xi,double x[],double xs[],double s[],int n); void splina(double x[], double xs[], double s[], int n); void tgap(double gapnew, double blend); void lerad(double rfac, double blend); bool splind(double x[600], double xs[600], double s[600], int n, double xs1, double xs2); bool stepbl(); bool stfind(); bool stmove(); bool tecalc(); bool tesys(double cte, double tte, double dte); bool trchek(); bool trdif(); bool trisol(double a[],double b[], double c[], double d[], int kk); bool ueset(); bool uicalc(); bool update(); bool xicalc(); bool xifset(int is); bool xyWake(); double aint(double number); double atanc(double y, double x, double thold); double curv(double ss, double x[], double xs[], double y[], double ys[], double s[], int n); double d2val(double ss, double x[], double xs[], double s[], int n); double deval(double ss, double x[], double xs[], double s[], int n); double seval(double ss, double x[], double xs[], double s[], int n); double sign(double a, double b); void naca4(int ides, int nside); bool naca5(int ides, int nside); private: void CreateXBL(double xs[IVX][3],int &nside1, int &nside2); void FillHk(double ws[IVX][3], int nside1, int nside2); void FillRTheta(double ws[IVX][3], int nside1, int nside2); void WriteString(QString str, bool bFullReport = false); //____________VARIABLES___________________________________________________ blData blsav[3]; // int nax, npx, nfx; // double com2[74], com1[74]; // int ncom; // QString labref; // QString fname, pfname, pfnamx; // QString oname, prefix; // QString name, namepol, codepol, nameref; // QString ispars; static bool s_bCancel; bool m_bFullReport; // bool lpacc,lqvdes,,lqrefl,lcpref,lforef,lpfile,lpfilx; // bool lppsho,lplot,lclip,lvlab,lcurs,lcminp, lhmomp,lland; // bool lplcam,lgparm,lnorm,,lgsym,lgslop, lcslop,lclock, bool limage,lgamu,sharp,lqaij,ladij,lwdij; bool lqinu,lgsame;// ??? // bool lgtick, lplegn,,lplist, lpgrid,lblgrd,lblsym, // lcpgrd,lggrid,lgeopl, lpcdw,lqsppl, liqset, lqgrid; bool liqset; double sccon, gacon, gbcon, gbc0, gbc1, gccon, dlcon, ctcon; //---- dimension temporary work and storage arrays [equivalenced below] double w1[6*IQX], w2[6*IQX], w3[6*IQX], w4[6*IQX]; double w5[6*IQX], w6[6*IQX], w7[6*IQX], w8[6*IQX]; int nsys; int itran[3],isys[IVX][ISX]; double xbp[IBX],ybp[IBX],sb[IBX],snew[4*IBX]; double xof,yof,sble,chordb; // double xbmin,xbmax,ybmin,ybmax; double areab,radble,angbte; double ei11ba,ei22ba,apx1ba,apx2ba,ei11bt,ei22bt,apx1bt,apx2bt; // double xcm[1200],ycm[1200],scm[1200],xcmp[1200],ycmp[1200]; // double xtk[1200],ytk[1200],stk[1200]; // double xtkp[1200],ytkp[1200]; double xp[IZX],yp[IZX],s[IZX],sle,xle,yle,xte,yte; double chord,yimage,wgap[IWX],waklen; // double size,scrnfr,plotar, pfac,qfac,vfac,xwind,ywind; // double xpage,ypage,xmarg,ymarg, chg, chq,xofair,yofair,facair, xofa,yofa,faca,uprwt; // double cpmin,cpmax,cpdel; // double cpolplf[3][4]; // double xcdwid,xalwid,xocwid; double ch; int nw,ist; // int kimage,nseqex; int aijpiv[IQX]; // int idev,idevrp,ipslu,ncolor,icols[5],nover, ncm,ntk; double adeg, xcmref, ycmref, cl_alf, cl_msq; double psio,cosa,sina,gamma,gamm1; // double circ; double tklam,tkl_msq,cpstar,qstar,cpmni,cpmnv,xcpmni,xcpmnv; double arad;//added arcds double xssi[IVX][ISX],uedg[IVX][ISX],uinv[IVX][ISX],mass[IVX][ISX]; double thet[IVX][ISX],ctau[IVX][ISX],delt[IVX][ISX]; double uslp[IVX][ISX],guxq[IVX][ISX],guxd[IVX][ISX]; double dis[IVX][ISX],ctq[IVX][ISX],tau[IVX][ISX],vti[IVX][ISX]; double xssitr[ISX],uinv_a[IVX][ISX]; double gam[IQX],gam_a[IQX],gamu[IQX][ISX],sig[IZX]; double apanel[IZX],sst,sst_go,sst_gp,gamte,sigte; // double sigte_a,gamte_a; double dste,aste; double qinv[IZX],qvis[IZX],qinvu[IZX][3], qinv_a[IZX]; double q[IQX][IQX],dq[IQX],dzdg[IQX],dzdn[IQX],dzdm[IZX],dqdg[IQX]; double dqdm[IZX],qtan1,qtan2,z_qinf,z_alfa,z_qdof0,z_qdof1,z_qdof2,z_qdof3; double aij[IQX][IQX]; double bij[IQX][IZX],dij[IZX][IZX]; double cij[IWX][IQX]; double hopi,qopi,dtor; double vs1[5][6],vs2[5][6],vsrez[5],vsr[5],vsm[5],vsx[5]; bool tforce[ISX]; bool trforc, simi,tran,turb,wake, trfree; double dwte, qinfbl, tkbl, tkbl_ms, rstbl, rstbl_ms, hstinv, hstinv_ms; double reybl, reybl_ms, reybl_re, gambl, gm1bl, hvrat, bule, xiforc, amcrit; double x2, u2, t2, d2, s2, ampl2, u2_uei, u2_ms, dw2, h2, h2_t2, h2_d2, m2, m2_u2,m2_ms, r2, r2_u2,r2_ms, v2, v2_u2,v2_ms,v2_re, hk2, hk2_u2, hk2_t2, hk2_d2,hk2_ms, hs2, hs2_u2, hs2_t2, hs2_d2,hs2_ms, hs2_re, hc2, hc2_u2, hc2_t2, hc2_d2,hc2_ms, rt2, rt2_u2, rt2_t2,rt2_ms, rt2_re, cf2, cf2_u2, cf2_t2, cf2_d2,cf2_ms, cf2_re, di2, di2_u2, di2_t2, di2_d2, di2_s2, di2_ms, di2_re, us2, us2_u2, us2_t2, us2_d2,us2_ms, us2_re, cq2, cq2_u2, cq2_t2, cq2_d2,cq2_ms, cq2_re, de2, de2_u2, de2_t2, de2_d2,de2_ms; double x1, u1, t1, d1, s1, ampl1, u1_uei, u1_ms, dw1, h1, h1_t1, h1_d1, m1, m1_u1,m1_ms,r1, r1_u1,r1_ms,v1, v1_u1,v1_ms, v1_re,hk1, hk1_u1, hk1_t1, hk1_d1,hk1_ms,hs1, hs1_u1, hs1_t1, hs1_d1,hs1_ms, hs1_re, hc1, hc1_u1, hc1_t1, hc1_d1,hc1_ms, rt1, rt1_u1, rt1_t1,rt1_ms, rt1_re, cf1, cf1_u1, cf1_t1, cf1_d1,cf1_ms, cf1_re, di1, di1_u1, di1_t1, di1_d1, di1_s1, di1_ms, di1_re, us1, us1_u1, us1_t1, us1_d1, us1_ms, us1_re, cq1, cq1_u1, cq1_t1, cq1_d1,cq1_ms, cq1_re, de1, de1_u1, de1_t1, de1_d1,de1_ms; // double xoff,yoff,xgmin,xgmax,ygmin,ygmax,dxyg,xcmin,xcmax,ycmin,ycmax,dxyc,dyoffc,xpmin,xpmax,ypmin,ypmax,dxyp,dyoffp,ysfp,gtick; int imxbl,ismxbl; double xsf,ysf; QString vmxbl; // double cpol[800][iptot][9],cpolsd[800][3][jptot][9];//what's iptot ??? // double xpref[300],cpref[300], verspol[9],cpolxy[300][2][9] // double machp1[9], reynp1[9],acritp[9],xstripp[3][9],cpolref[128][2][4][9]; double cfm, cfm_ms, cfm_re, cfm_u1, cfm_t1, cfm_d1, cfm_u2, cfm_t2, cfm_d2; double xt, xt_a1, xt_ms, xt_re, xt_xf, xt_x1, xt_t1, xt_d1, xt_u1, xt_x2, xt_t2, xt_d2, xt_u2; double va[4][3][IZX],vb[4][3][IZX],vdel[4][3][IZX],vm[4][IZX][IZX],vz[4][3]; // int ncpref, napol[9], npol, ipact, nlref, icolp[9],icolr[9],imatyp[9],iretyp[9], nxypol[9],npolref, ndref[4][9]; // double c1sav[74], c2sav[74]; /* c c- sccon = shear coefficient lag constant c- gacon = g-beta locus constants... c- gbcon = g = gacon * sqrt(1.0 + gbcon*beta) c- gccon = + gccon / [h*rtheta*sqrt(cf/2)] <-- wall term c- dlcon = wall/wake dissipation length ratio lo/l c- ctcon = ctau weighting coefficient (implied by g-beta constants) c version version number of this xfoil implementation c c fname airfoil data filename c pfname[.] polar append filename c pfnamx[.] polar append x/c dump filename c oname default overlay airfoil filename c prefix default filename prefix c name airfoil name c c ispars ises domain parameters [not used in xfoil] c c q[..] generic coefficient matrix c dq[.] generic matrix righthand side c c dzdg[.] dpsi/dgam c dzdn[.] dpsi/dn c dzdm[.] dpsi/dsig c c dqdg[.] dqtan/dgam c dqdm[.] dqtan/dsig c qtan1 qtan at alpha = 0 deg. c qtan2 qtan at alpha = 90 deg. c c z_qinf dpsi/dqinf c z_alfa dpsi/dalfa c z_qdof0 dpsi/dqdof0 c z_qdof1 dpsi/dqdof1 c z_qdof2 dpsi/dqdof2 c z_qdof3 dpsi/dqdof3 c c aij[..] dpsi/dgam influence coefficient matrix [factored if lqaij=t] c bij[..] dgam/dsig influence coefficient matrix c cij[..] dqtan/dgam influence coefficient matrix c dij[..] dqtan/dsig influence coefficient matrix c qinv[.] tangential velocity due to surface vorticity c qvis[.] tangential velocity due to surface vorticity & mass sources c qinvu[..] qinv for alpha = 0, 90 deg. c qinv_a[.] dqinv/dalpha c c x[.],y[.] airfoil [1panel pointers ipan have been calculated c lqaij .true. if dpsi/dgam matrix has been computed and factored c ladij .true. if dq/dsig matrix for the airfoil has been computed c lwdij .true. if dq/dsig matrix for the wake has been comphd c lqvdes .true. if viscous ue is to be plotted in qdes routines c lqspec .true. if qspec has been initialized c lqrefl .true. if reflected qspec is to be plotted in qdes routines c lvconv .true. if converged bl solution exists c lcpref .true. if reference data is to be plotted on cp vs x/c plots c lclock .true. if source airfoil coordinates are clockwise c lpfile .true. if polar file is ready to be appended to c lpfilx .true. if polar dump file is ready to be appended to c lppsho .true. if cl-cd polar is plotted during point sequence c lbflap .true. if buffer airfoil flap parameters are defined c lflap .true. if current airfoil flap parameters are defined c leiw .true. if unit circle complex number array is initialized c lscini .true. if old-airfoil circle-plane arc length s[w] exists c lforef .true. if cl,cd... data is to be plotted on cp vs x/c plots c lnorm .true. if input buffer airfoil is to be normalized c lgsame .true. if current and buffer airfoils are identical c c lplcam .true. if thickness and camber are to be plotted c lqsym .true. if symmetric qspec will be enforced c lgsym .true. if symmetric geometry will be enforced c lqgrid .true. if grid is to overlaid on qspec[s] plot c lggrid .true. if grid is to overlaid on buffer airfoil geometry plot c lgtick .true. if node tick marks are to be plotted on buffer airfoil c lqslop .true. if modified qspec[s] segment is to match slopes c lgslop .true. if modified geometry segment is to match slopes c lcslop .true. if modified camber line segment is to match slopes c lqsppl .true. if current qspec[s] in in plot c lgeopl .true. if current geometry in in plot c lcpgrd .true. if grid is to be plotted on cp plots c lblgrd .true. if grid is to be plotted on bl variable plots c lblsym .true. if symbols are to be plotted on bl variable plots c lcminp .true. if min cp is to be written to polar file for cavitation c lhmomp .true. if hinge moment is to be written to polar file c c lpgrid .true. if polar grid overlay is enabled c lpcdw .true. if polar cdwave is plotted c lplist .true. if polar listing lines [at top of plot] are enabled c lplegn .true. if polar legend is enabled c c lplot .true. if plot page is open c lsym .true. if symbols are to be plotted in qdes routines c liqset .true. if inverse target segment is marked off in qdes c lclip .true. if line-plot clipping is to be performed c lvlab .true. if label is to be plotted on viscous-variable plots c lcurs .true. if cursor input is to be used for blowups, etc. c lland .true. if landscape orientation for postscript is used c c c xb[.],yb[.] buffer airfoil coordinate arrays c xbp[.] dxb/dsb c ybp[.] dyb/dsb c sb[.] spline parameter for buffer airfoil c snew[.] new panel endpoint arc length array c c xbf,ybf buffer airfoil flap hinge coordinates c xof,yof current airfoil flap hinge coordinates c hmom moment of flap about hinge point c hfx x-force of flap on hinge point c hfy y-force of flap on hinge point c c~~~~~~~~~~~~~~ properties of current buffer airfoil c c xbmin,xbmax limits of xb array c ybmin,ybmax limits of yb array c sble le tangency-point sb location c chordb chord c areab area c radble le radius c angbte te angle [rad] c c ei11ba bending inertia about axis 1 x^2 dx dy c ei22ba bending inertia about axis 2 y^2 dx dy c apx1ba principal axis 1 angle c apx2ba principal axis 2 angle c c ei11bt bending inertia about axis 1 x^2 t ds c ei22bt bending inertia about axis 2 y^2 t ds c apx1bt principal axis 1 angle c apx2bt principal axis 2 angle c c thickb max thickness c cambrb max camber c c~~~~~~~~~~~~~~ c c xssi[..] bl arc length coordinate array on each surface c uedg[..] bl edge velocity array c uinv[..] bl edge velocity array without mass defect influence c mass[..] bl mass defect array [ = uedg*dstr ] c thet[..] bl momentum thickness array c dstr[..] bl displacement thickness array c ctau[..] sqrt[max shear coefficient] array c [in laminar regions, log of amplification ratio] c c tau[..] wall shear stress array [for plotting only] c dis[..] dissipation array [for plotting only] c ctq[..] sqrt[equilibrium max shear coefficient] array [ " ] c vti[..] +/-1 conversion factor between panel and bl variables c uinv_a[..] duinv/dalfa array c c reinf1 reynolds number vinf c / ve for cl=1 c reinf reynolds number for current cl c reinf_cl dreinf/dcl c c acrit log [critical amplification ratio] c xstrip[.] transition trip x/c locations [if xtrip > 0], c transition trip -s/s_side locations [if xtrip < 0], c xoctr[.] actual transition x/c locations c yoctr[.] actual transition y/c locations c xssitr[.] actual transition xi locations c c iblte[.] bl array index at trailing edge c nbl[.] max bl array index c ipan[..] panel index corresponding to bl location c isys[..] bl newton system line number corresponding to bl location c nsys total number of lines in bl newton system c itran[.] bl array index of transition interval c tforce[.] .true. if transition is forced due to transition strip c c va,vb[...] diagonal and off-diagonal blocks in bl newton system c vz[..] way-off-diagonal block at te station line c vm[...] mass-influence coefficient vectors in bl newton system c vdel[..] residual and solution vectors in bl newton system c c rmsbl rms change from bl newton system solution c rmxbl max change from bl newton system solution c imxbl location of max change c ismxbl index of bl side containing max change c vmxbl character identifying variable with max change c rlx underrelaxation factor for newton update c vaccel parameter for accelerating bl newton system solution c [any off-diagonal element < vaccel is not eliminated, c which speeds up each iteration, but may increase c iteration count] c can be set to zero for unadulterated newton method c c xoff,yoff x and y offsets for windowing in qdes,gdes routines c xsf ,ysf x and y scaling factors for windowing in qdes,gdes routines c c xgmin airfoil grid plot limits c xgmax c ygmin c ygmax c dxyg airfoil grid-plot annotation increment c gtick airfoil-plot tick marks size [as fraction of arc length] */ }; #endif xflr5-6.09-06/src/xdirect/TEGapDlg.cpp000644 001750 000144 00000013034 12247174405 020621 0ustar00techwinderusers000000 000000 /**************************************************************************** TEGapDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "TEGapDlg.h" #include "XFoil.h" #include "XDirect.h" #include "../design/AFoil.h" #include #include void *TEGapDlg::s_pXFoil; TEGapDlg::TEGapDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("T.E. Gap")); m_Gap = 0.0; m_Blend = 0.8; m_pAFoil = NULL; m_pXDirect = NULL; m_bModified = false; m_bApplied = true; SetupLayout(); connect(m_pctrlGap, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlBlend, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(ApplyButton, SIGNAL(clicked()),this, SLOT(OnApply())); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void TEGapDlg::SetupLayout() { QHBoxLayout *GapValue = new QHBoxLayout; QLabel *lab1 = new QLabel(tr("T.E. Gap Value")); lab1->setAlignment(Qt::AlignRight); lab1->setMinimumWidth(150); QLabel *lab2 = new QLabel(tr("% chord")); m_pctrlGap = new DoubleEdit; GapValue->addWidget(lab1); GapValue->addWidget(m_pctrlGap); GapValue->addWidget(lab2); QHBoxLayout *BlendValue = new QHBoxLayout; QLabel *lab3 = new QLabel(tr("Blending Distance from L.E.")); lab3->setAlignment(Qt::AlignRight); lab3->setMinimumWidth(150); QLabel *lab4 = new QLabel(tr("% chord")); m_pctrlBlend = new DoubleEdit; BlendValue->addWidget(lab3); BlendValue->addWidget(m_pctrlBlend); BlendValue->addWidget(lab4); QHBoxLayout *CommandButtons = new QHBoxLayout; OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); ApplyButton = new QPushButton(tr("Apply")); CommandButtons->addStretch(1); CommandButtons->addWidget(ApplyButton); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addStretch(1); MainLayout->addLayout(GapValue); MainLayout->addStretch(1); MainLayout->addLayout(BlendValue); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); setLayout(MainLayout); } void TEGapDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Escape: { done(0); return; } case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OnApply(); OKButton->setFocus(); m_bApplied = true; } else { QDialog::accept(); } break; } default: event->ignore(); break; } } void TEGapDlg::InitDialog() { m_pctrlGap->SetMin( 0.0); m_pctrlGap->SetMax(100.0); m_pctrlBlend->SetMin( 0.0); m_pctrlBlend->SetMax(100.0); m_pctrlGap->SetValue(m_pMemFoil->m_Gap*100.0); m_pctrlBlend->SetValue(m_Blend*100.0); } void TEGapDlg::OnChanged() { m_bApplied = false; } void TEGapDlg::OnOK() { if(!m_bApplied) OnApply(); if(!m_bModified) done(0); else done(1); } void TEGapDlg::OnApply() { if(m_bApplied) return; //reset everything and retry QXDirect *pXDirect = (QXDirect*)m_pXDirect; QAFoil *pAFoil = (QAFoil*)m_pAFoil; XFoil *pXFoil = (XFoil*)s_pXFoil; int i, j; for (i=0; i< m_pMemFoil->nb; i++) { pXFoil->xb[i+1] = m_pMemFoil->xb[i] ; pXFoil->yb[i+1] = m_pMemFoil->yb[i]; } pXFoil->nb = m_pMemFoil->nb; pXFoil->lflap = false; pXFoil->lbflap = false; if(pXFoil->Preprocess()) { pXFoil->CheckAngles(); /* for (int k=0; kn;k++) { m_pMemFoil->nx[k] = pXFoil->nx[k+1]; m_pMemFoil->ny[k] = pXFoil->ny[k+1]; } m_pMemFoil->n = pXFoil->n;*/ } else { QMessageBox::information(window(), tr("Warning"), tr("Unrecognized foil format")); return; } m_Gap = m_pctrlGap->Value(); m_Blend = m_pctrlBlend->Value(); pXFoil->tgap(m_Gap/100.0,m_Blend/100.0); if(pXFoil->n>IQX) { QMessageBox::information(window(), tr("Warning"), tr("Panel number cannot exceed 300")); //reset everything and retry for (i=0; i< m_pMemFoil->nb; i++) { pXFoil->x[i+1] = m_pMemFoil->xb[i] ; pXFoil->y[i+1] = m_pMemFoil->yb[i]; } pXFoil->n = m_pMemFoil->nb; } else { for (j=0; j< pXFoil->n; j++) { m_pBufferFoil->xb[j] = pXFoil->xb[j+1]; m_pBufferFoil->yb[j] = pXFoil->yb[j+1]; } m_pBufferFoil->nb = pXFoil->nb; // pXFoil->SetFoilFlap(m_pBufferFoil); m_pBufferFoil->InitFoil(); m_pBufferFoil->SetFlap(); } m_bApplied = true; m_bModified = true; if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } xflr5-6.09-06/src/xdirect/TwoDPanelDlg.h000644 001750 000144 00000003542 12247174410 021162 0ustar00techwinderusers000000 000000 /**************************************************************************** TwoDPanelDlg Class Copyright (C) 2008-2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef TWODPANELDLG_H #define TWODPANELDLG_H #include #include "../misc/IntEdit.h" #include "../misc/DoubleEdit.h" class TwoDPanelDlg : public QDialog { Q_OBJECT friend class QAFoil; friend class QXDirect; private slots: void OnApply(); void OnOK(); void OnChanged(); public: TwoDPanelDlg(QWidget *pParent=NULL); static void *s_pXFoil; void InitDialog(); private: void keyPressEvent(QKeyEvent *event); void SetupLayout(); void ReadParams(); QPushButton *OKButton, *CancelButton, *ApplyButton; IntEdit *m_pctrlNPanels; DoubleEdit *m_pctrlCVpar, *m_pctrlCTErat, *m_pctrlCTRrat; DoubleEdit *m_pctrlXsRef1, *m_pctrlXsRef2, *m_pctrlXpRef1, *m_pctrlXpRef2; bool m_bApplied; bool m_bModified; int npan; double cvpar; double cterat; double ctrrat; double xsref1; double xsref2; double xpref1; double xpref2; void *m_pBufferFoil; void *m_pMemFoil; void *m_pXDirect; void *m_pAFoil; }; #endif // TWODPANELDLG_H xflr5-6.09-06/src/xdirect/BatchDlg.cpp000644 001750 000144 00000105320 12247174410 020676 0ustar00techwinderusers000000 000000 /**************************************************************************** BatchDlg Class Copyright (C) 2003-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "BatchDlg.h" #include "XDirect.h" #include "ReListDlg.h" #include "../mainframe.h" #include "../xinverse/FoilSelectionDlg.h" #include #include #include #include #include #include #include bool BatchDlg::s_bStoreOpp = false; bool BatchDlg::s_bCurrentFoil=true; void * BatchDlg::s_pXFoil; void * BatchDlg::s_pMainFrame; void * BatchDlg::s_pXDirect; QPoint BatchDlg::s_Position; BatchDlg::BatchDlg(QWidget *pParent) : QDialog(pParent) { QString str = tr("Batch foil analysis"); setWindowTitle(str); m_FoilList.clear(); m_PolarType = FIXEDSPEEDPOLAR; m_Mach = 0.0; m_ReMin = 100000.0; m_ReInc = 50000.0; m_ReMax = 300000.0; m_SpMin = 0.0; m_SpMax = 1.0; m_SpInc = 0.5; m_ClMin = 0.0; m_ClMax = 1.0; m_ClInc = 0.1; m_NCrit = 9.0; m_XTopTr = 1.0; m_XBotTr = 1.0; m_ReList = NULL; m_MachList = NULL; m_NCritList = NULL; m_bOutput = true; m_bAlpha = true; m_bFromList = false; m_bFromZero = false; m_bInitBL = false; m_bCancel = false; m_bSkipPoint = false; m_bSkipPolar = false; m_bIsRunning = false; m_Iterations = 0; m_IterLim = 100; m_NRe = 0; m_IterRect.setRect(327,158,620-327,398-158); m_RmsGraph.SetXTitle(tr("Iter")); m_RmsGraph.SetYTitle("");//Change from bl newton system solution m_RmsGraph.SetAuto(true); m_RmsGraph.SetXMajGrid(true, QColor(120,120,120),2,1); m_RmsGraph.SetYMajGrid(true, QColor(120,120,120),2,1); m_RmsGraph.SetXMin(0.0); m_RmsGraph.SetXMax(50); m_RmsGraph.SetYMin(-1.0); m_RmsGraph.SetYMax( 1.0); m_RmsGraph.SetType(1); m_RmsGraph.SetMargin(40); XFoil::s_bCancel = false; SetupLayout(); connect(m_pctrlFoil1, SIGNAL(clicked()), this, SLOT(OnFoilSelectionType())); connect(m_pctrlFoil2, SIGNAL(clicked()), this, SLOT(OnFoilSelectionType())); connect(m_pctrlFoilList, SIGNAL(clicked()), this, SLOT(OnFoilList())); connect(m_pctrlClose, SIGNAL(clicked()), this, SLOT(OnClose())); connect(m_pctrlAnalyze, SIGNAL(clicked()), this, SLOT(OnAnalyze())); connect(m_pctrlSkipOpp, SIGNAL(clicked()), this, SLOT(OnSkipPoint())); connect(m_pctrlSkipPolar, SIGNAL(clicked()), this, SLOT(OnSkipPolar())); connect(m_rbtype1, SIGNAL(clicked()), this, SLOT(OnPolarType())); connect(m_rbtype2, SIGNAL(clicked()), this, SLOT(OnPolarType())); connect(m_rbtype3, SIGNAL(clicked()), this, SLOT(OnPolarType())); connect(m_rbtype4, SIGNAL(clicked()), this, SLOT(OnPolarType())); connect(m_rbspec1, SIGNAL(toggled(bool)), this, SLOT(OnAcl())); connect(m_rbspec2, SIGNAL(toggled(bool)), this, SLOT(OnAcl())); connect(m_rbRange1, SIGNAL(toggled(bool)), this, SLOT(OnRange())); connect(m_rbRange2, SIGNAL(toggled(bool)), this, SLOT(OnRange())); connect(m_pctrlEditList, SIGNAL(clicked()), this, SLOT(OnEditReList())); connect(m_pctrlFromZero, SIGNAL(stateChanged(int)), this, SLOT(OnFromZero(int))); connect(m_pctrlSpecMin, SIGNAL(editingFinished()), this, SLOT(OnSpecChanged())); connect(m_pctrlSpecMax, SIGNAL(editingFinished()), this, SLOT(OnSpecChanged())); connect(m_pctrlSpecDelta, SIGNAL(editingFinished()), this, SLOT(OnSpecChanged())); } void BatchDlg::SetupLayout() { QGroupBox *pFoilBox = new QGroupBox(tr("Foil Selection")); { QHBoxLayout *FoilLayout = new QHBoxLayout; { m_pctrlFoil1 = new QRadioButton(tr("Current foil only")); m_pctrlFoil2 = new QRadioButton(tr("Foil list")); m_pctrlFoilList = new QPushButton(tr("Foil list")); FoilLayout->addWidget(m_pctrlFoil1); FoilLayout->addWidget(m_pctrlFoil2); FoilLayout->addStretch(1); FoilLayout->addWidget(m_pctrlFoilList); } pFoilBox->setLayout(FoilLayout); } QGroupBox *pAnalysisTypeGroupBox = new QGroupBox(tr("Analysis Type")); { QHBoxLayout *AnalysisTypeLayout = new QHBoxLayout; { m_rbtype1 = new QRadioButton(tr("Type 1")); m_rbtype2 = new QRadioButton(tr("Type 2")); m_rbtype3 = new QRadioButton(tr("Type 3")); m_rbtype4 = new QRadioButton(tr("Type 4")); AnalysisTypeLayout->addWidget(m_rbtype1); AnalysisTypeLayout->addWidget(m_rbtype2); AnalysisTypeLayout->addWidget(m_rbtype3); AnalysisTypeLayout->addWidget(m_rbtype4); } pAnalysisTypeGroupBox->setLayout(AnalysisTypeLayout); } QGroupBox *pBatchVarsGroupBox = new QGroupBox(tr("Batch Variables")); { QGridLayout *BatchVarsLayout = new QGridLayout; { m_rbRange1 = new QRadioButton(tr("Range")); m_rbRange2 = new QRadioButton(tr("Re List")); m_pctrlEditList = new QPushButton(tr("Edit List")); QLabel *MinVal = new QLabel(tr("Min")); QLabel *MaxVal = new QLabel(tr("Max")); QLabel *DeltaVal = new QLabel(tr("Increment")); MinVal->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); MaxVal->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); DeltaVal->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); m_pctrlReType = new QLabel("Reynolds="); m_pctrlMaType = new QLabel("Mach="); m_pctrlReType->setAlignment(Qt::AlignVCenter|Qt::AlignRight); m_pctrlMaType->setAlignment(Qt::AlignVCenter|Qt::AlignRight); m_pctrlReMin = new DoubleEdit(100000,0); m_pctrlReMax = new DoubleEdit(150000,0); m_pctrlReDelta = new DoubleEdit(50000,0); m_pctrlMach = new DoubleEdit(0.0, 3); QLabel *NCritLabel = new QLabel(tr("NCrit=")); NCritLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight); m_pctrlNCrit = new DoubleEdit(9.00); BatchVarsLayout->addWidget(m_rbRange1, 1, 2); BatchVarsLayout->addWidget(m_rbRange2, 1, 3); BatchVarsLayout->addWidget(m_pctrlEditList, 1, 4); BatchVarsLayout->addWidget(MinVal, 2, 2); BatchVarsLayout->addWidget(MaxVal, 2, 3); BatchVarsLayout->addWidget(DeltaVal, 2, 4); BatchVarsLayout->addWidget(m_pctrlReType, 3, 1); BatchVarsLayout->addWidget(m_pctrlReMin, 3, 2); BatchVarsLayout->addWidget(m_pctrlReMax, 3, 3); BatchVarsLayout->addWidget(m_pctrlReDelta, 3, 4); BatchVarsLayout->addWidget(m_pctrlMaType, 4, 1); BatchVarsLayout->addWidget(m_pctrlMach, 4, 2); BatchVarsLayout->addWidget(NCritLabel, 5, 1); BatchVarsLayout->addWidget(m_pctrlNCrit, 5,2); } pBatchVarsGroupBox->setLayout(BatchVarsLayout); } QGroupBox *pRangeVarsGroupBox = new QGroupBox(tr("Analysis Range")); { QGridLayout *RangeVarsLayout = new QGridLayout; { QLabel *Spec = new QLabel(tr("Specify")); m_rbspec1 = new QRadioButton(tr("Alpha")); m_rbspec2 = new QRadioButton(tr("Cl")); m_pctrlFromZero = new QCheckBox(tr("From Zero")); QLabel *SpecMin = new QLabel(tr("Min")); QLabel *SpecMax = new QLabel(tr("Max")); QLabel *SpecDelta = new QLabel(tr("Increment")); SpecMin->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); SpecMax->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); SpecDelta->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); m_pctrlSpecVar = new QLabel(tr("Spec =")); m_pctrlSpecMin = new DoubleEdit(0.00); m_pctrlSpecMax = new DoubleEdit(1.00); m_pctrlSpecDelta = new DoubleEdit(0.50); RangeVarsLayout->addWidget(Spec, 1, 1); RangeVarsLayout->addWidget(m_rbspec1, 1, 2); RangeVarsLayout->addWidget(m_rbspec2, 1, 3); RangeVarsLayout->addWidget(m_pctrlFromZero, 1, 4); RangeVarsLayout->addWidget(SpecMin, 2, 2); RangeVarsLayout->addWidget(SpecMax, 2, 3); RangeVarsLayout->addWidget(SpecDelta, 2, 4); RangeVarsLayout->addWidget(m_pctrlSpecVar, 3, 1); RangeVarsLayout->addWidget(m_pctrlSpecMin, 3, 2); RangeVarsLayout->addWidget(m_pctrlSpecMax, 3, 3); RangeVarsLayout->addWidget(m_pctrlSpecDelta, 3, 4); } pRangeVarsGroupBox->setLayout(RangeVarsLayout); } QGroupBox *pTransVarsGroupBox = new QGroupBox(tr("Forced transitions")); { QGridLayout *TransVarsLayout = new QGridLayout; { TransVarsLayout->setColumnStretch(0,4); TransVarsLayout->setColumnStretch(1,1); QLabel *TopTransLabel = new QLabel(tr("Top transition location (x/c)")); QLabel *BotTransLabel = new QLabel(tr("Bottom transition location (x/c)")); TopTransLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight); BotTransLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight); m_pctrlXTopTr = new DoubleEdit(1.00); m_pctrlXBotTr = new DoubleEdit(1.00); TransVarsLayout->addWidget(TopTransLabel, 1, 1); TransVarsLayout->addWidget(m_pctrlXTopTr, 1, 2); TransVarsLayout->addWidget(BotTransLabel, 2, 1); TransVarsLayout->addWidget(m_pctrlXBotTr, 2, 2); } pTransVarsGroupBox->setLayout(TransVarsLayout); } QHBoxLayout *OptionsLayout = new QHBoxLayout; { m_pctrlInitBL = new QCheckBox(tr("Initialize BLs between polars")); m_pctrlStoreOpp = new QCheckBox(tr("Store OpPoints")); OptionsLayout->addWidget(m_pctrlInitBL); OptionsLayout->addWidget(m_pctrlStoreOpp); } //_*_*_*_*_*_*_**_*_*_**_*_*_*_ QHBoxLayout *CommandButtonsLayout = new QHBoxLayout; { m_pctrlClose = new QPushButton(tr("Close")); m_pctrlAnalyze = new QPushButton(tr("Analyze")) ; m_pctrlSkipOpp = new QPushButton(tr("Skip Opp")); m_pctrlSkipPolar = new QPushButton(tr("Skip Polar")); m_pctrlAnalyze->setAutoDefault(true); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(m_pctrlAnalyze); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(m_pctrlSkipOpp); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(m_pctrlSkipPolar); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(m_pctrlClose); CommandButtonsLayout->addStretch(1); } QVBoxLayout *LeftSideLayout = new QVBoxLayout; { LeftSideLayout->addWidget(pFoilBox); LeftSideLayout->addWidget(pAnalysisTypeGroupBox); LeftSideLayout->addWidget(pBatchVarsGroupBox); LeftSideLayout->addWidget(pTransVarsGroupBox); LeftSideLayout->addWidget(pRangeVarsGroupBox); LeftSideLayout->addSpacing(20); LeftSideLayout->addStretch(1); LeftSideLayout->addLayout(CommandButtonsLayout); } QVBoxLayout *RightSideLayout = new QVBoxLayout; { m_pctrlTextOutput = new QTextEdit; m_pctrlTextOutput->setReadOnly(true); m_pctrlTextOutput->setLineWrapMode(QTextEdit::NoWrap); m_pctrlTextOutput->setWordWrapMode(QTextOption::NoWrap); m_pctrlGraphOutput = new GraphWidget; m_pctrlGraphOutput->m_pGraph = &m_RmsGraph; // m_pctrlGraphOutput->setMinimumHeight(300); RightSideLayout->addLayout(OptionsLayout); RightSideLayout->addWidget(m_pctrlTextOutput,1); RightSideLayout->addWidget(m_pctrlGraphOutput,2); } QHBoxLayout *mainLayout= new QHBoxLayout; { mainLayout->setSpacing(10); mainLayout->addLayout(LeftSideLayout); mainLayout->addLayout(RightSideLayout); } setLayout(mainLayout); } void BatchDlg::AddOpPoint() { QXDirect *pXDirect = (QXDirect*)s_pXDirect; XFoil *pXFoil = (XFoil*)s_pXFoil; if(s_bStoreOpp) pXDirect->AddOpPoint(m_pCurPolar, true); else { m_pCurPolar->AddData(pXFoil); } if(pXDirect->m_bPolarView) { pXDirect->CreatePolarCurves(); pXDirect->UpdateView(); } m_RmsGraph.ResetYLimits(); } void BatchDlg::AlphaLoop() { XFoil *pXFoil = (XFoil*)s_pXFoil; // QXDirect* pXDirect = (QXDirect*)s_pXDirect; QString str, str2; QString strong = ""; int iRe, iAlpha, nAlpha; double alphadeg; QPoint Place(m_pctrlGraphOutput->rect().left()+m_RmsGraph.GetMargin()*2, m_pctrlGraphOutput->rect().top()+m_RmsGraph.GetMargin()/2); nAlpha = (int)(qAbs((m_SpMax-m_SpMin)*1.000/m_SpInc));//*1.0001 to make sure upper limit is included for (iAlpha=0; iAlpha<=nAlpha; iAlpha++) { qApp->processEvents(); if(m_bCancel) break; alphadeg = m_SpMin + iAlpha*m_SpInc; pXFoil->alfa = alphadeg*PI/180.0; str = QString("Alpha = %1\n").arg(alphadeg,0,'f',2); strong+= str; UpdateOutput(str); int total = (int)(qAbs((m_ReMax-m_ReMin)*1.0001/m_ReInc)); m_pCurPolar = CreatePolar(alphadeg, pXFoil->minf1, pXFoil->acrit);// Do something if(!m_pCurPolar) return; pXFoil->InitXFoilAnalysis(m_pCurPolar); if (m_bInitBL) { pXFoil->lblini = false; pXFoil->lipan = false; } m_bSkipPolar = false; for (iRe=0; iRe<=total; iRe++) { ResetCurves(); if(!m_bCancel && !m_bSkipPolar) { pXFoil->reinf1 = m_ReMin + iRe *m_ReInc; pXFoil->lalfa = true; pXFoil->qinf = 1.0; str = QString("Re=%1 Ma=%2 Nc=%3\n").arg(pXFoil->reinf1,8,'f',0).arg(pXFoil->minf1,5,'f',3).arg(pXFoil->acrit,5,'f',2); strong+=str; UpdateOutput(str); str = QString("Alpha=%1").arg(alphadeg,5,'f',2); str += QString::fromUtf8("°"); str2 = QString(" / Re=%1").arg(pXFoil->reinf1,8,'f',0); str += str2; m_pctrlGraphOutput->SetTitle(str, Place); // here we go ! if (!pXFoil->specal()) { str = tr("Invalid Analysis Settings\nCpCalc: local speed too large\n Compressibility corrections invalid "); // QMessageBox::information(this, tr("Warning"), str); UpdateOutput(str); m_bCancel = true; CleanUp(); return; } if (qAbs(pXFoil->alfa-pXFoil->awake) > 0.00001) pXFoil->lwake = false; if (qAbs(pXFoil->alfa-pXFoil->avisc) > 0.00001) pXFoil->lvconv = false; if (qAbs(pXFoil->minf-pXFoil->mvisc) > 0.00001) pXFoil->lvconv = false; pXFoil->lwake = false; pXFoil->lvconv = false; m_Iterations = 0; m_bSkipPoint = false; while(!Iterate()){} if(pXFoil->lvconv) { AddOpPoint(); } else if(m_bSkipPoint || m_bSkipPolar) { str = QString(tr(" ...skipped after %1 iterations")+"\n").arg(m_Iterations); strong+= str; UpdateOutput(str); } else { str = QString(tr(" ...unconverged after %1 iterations")+"\n").arg(m_Iterations); strong+= str; UpdateOutput(str); } } else { break; } }// end Alpha or Cl loop strong+="\n"; if(m_bCancel) { strong+=tr("Analysis interrupted")+"\n"; break; } }//end Re loop // WriteString(strong); } void BatchDlg::Analysis2() { if(m_bAlpha) { m_AlphaMin = m_SpMin; m_AlphaMax = m_SpMax; if(m_AlphaMin< m_AlphaMax) m_AlphaInc = qAbs(m_SpInc); else m_AlphaInc = -qAbs(m_SpInc); } else { m_ClMin = m_SpMin ; m_ClMax = m_SpMax ; if(m_ClMin< m_ClMax) m_ClInc = qAbs(m_ClInc); else m_ClInc = -qAbs(m_ClInc); } if(m_ReMin < m_ReMax) m_ReInc = qAbs(m_ReInc); else m_ReInc = -qAbs(m_ReInc); } void BatchDlg::Analysis3() { // m_bType4 = true; // m_bAlpha = false; m_AlphaMin = m_SpMin ; m_AlphaMax = m_SpMax ; if(m_SpMin< m_SpMax) m_AlphaInc = qAbs(m_SpInc); else m_AlphaInc = -qAbs(m_SpInc); if(m_ReMin < m_ReMax) m_ReInc = qAbs(m_ReInc); else m_ReInc = -qAbs(m_ReInc); } void BatchDlg::CleanUp() { ResetCurves(); if(m_pXFile->isOpen()) m_pXFile->close(); m_pctrlClose->setEnabled(true); m_pctrlSkipOpp->setEnabled(false); m_pctrlSkipPolar->setEnabled(false); m_pctrlAnalyze->setText(tr("Analyze")); m_bIsRunning = false; m_bCancel = false; m_bSkipPoint = false; m_bSkipPolar = false; XFoil::s_bCancel = false; m_pctrlClose->setFocus(); } Polar *BatchDlg::CreatePolar(double Spec, double Mach, double NCrit) { if(!m_pFoil) return NULL; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; Polar *pPolar = new Polar; pPolar->m_FoilName = m_pFoil->m_FoilName; pPolar->m_bIsVisible = true; pPolar->m_PolarType = m_PolarType; switch (pPolar->m_PolarType) { case FIXEDSPEEDPOLAR: pPolar->m_MaType = 1; pPolar->m_ReType = 1; break; case FIXEDLIFTPOLAR: pPolar->m_MaType = 2; pPolar->m_ReType = 2; break; case RUBBERCHORDPOLAR: pPolar->m_MaType = 1; pPolar->m_ReType = 3; break; case FIXEDAOAPOLAR: pPolar->m_MaType = 1; pPolar->m_ReType = 1; break; default: pPolar->m_ReType = 1; pPolar->m_MaType = 1; break; } if(m_PolarType!=FIXEDAOAPOLAR) { pPolar->m_Reynolds = Spec; } else { pPolar->m_ASpec = Spec; } pPolar->m_Mach = Mach; pPolar->m_ACrit = NCrit; pPolar->m_XTop = m_XTopTr; pPolar->m_XBot = m_XBotTr; pPolar->m_Color = pMainFrame->GetColor(1); SetPlrName(pPolar); Polar *pOldPolar = pMainFrame->GetPolar(m_pFoil->m_FoilName, pPolar->m_PlrName); if(pOldPolar) { delete pPolar; pPolar = pOldPolar; } else pPolar = pMainFrame->AddPolar(pPolar); return pPolar; } void BatchDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(m_pctrlClose->hasFocus()) done(1); else if(m_pctrlAnalyze->hasFocus()) OnAnalyze(); else m_pctrlAnalyze->setFocus(); break; } case Qt::Key_Escape: { if(m_bIsRunning) { m_bSkipPoint = true; m_bSkipPolar = true; m_bCancel = true; XFoil::s_bCancel = true; } else { reject(); //close the dialog box } break; } default: event->ignore(); } } void BatchDlg::InitDialog() { // CRect WndRect; // GetWindowRect(WndRect); // SetWindowPos(NULL,GetSystemMetrics(SM_CXSCREEN)-WndRect.Width()-10,60,0,0,SWP_NOSIZE); if(!m_pFoil) return; // QXDirect* pXDirect = (QXDirect*)s_pXDirect; m_pctrlFoil1->setChecked(s_bCurrentFoil); m_pctrlFoil2->setChecked(!s_bCurrentFoil); m_pctrlFoilList->setEnabled(!s_bCurrentFoil); if(m_bAlpha) { m_SpMin = m_AlphaMin; m_SpMax = m_AlphaMax; m_SpInc = m_AlphaInc; } else { m_SpMin = m_ClMin; m_SpMax = m_ClMax; m_SpInc = m_ClInc; } if(m_PolarType!=FIXEDAOAPOLAR) { m_pctrlReMin->SetPrecision(0); m_pctrlReMax->SetPrecision(0); m_pctrlReDelta->SetPrecision(0); m_pctrlSpecMin->SetPrecision(1); m_pctrlSpecMax->SetPrecision(1); m_pctrlSpecDelta->SetPrecision(1); } else { m_pctrlReMin->SetPrecision(1); m_pctrlReMax->SetPrecision(1); m_pctrlReDelta->SetPrecision(1); m_pctrlSpecMin->SetPrecision(0); m_pctrlSpecMax->SetPrecision(0); m_pctrlSpecDelta->SetPrecision(0); } if(m_ReMin<=0.0) m_ReMin = qAbs(m_ReInc); if(m_PolarType!=FIXEDAOAPOLAR) { m_pctrlReMin->SetValue(m_ReMin); m_pctrlReMax->SetValue(m_ReMax); m_pctrlReDelta->SetValue(m_ReInc); m_pctrlSpecMin->SetValue(m_SpMin); m_pctrlSpecMax->SetValue(m_SpMax); m_pctrlSpecDelta->SetValue(m_SpInc); } else { m_pctrlReMin->SetValue(m_SpMin); m_pctrlReMax->SetValue(m_SpMax); m_pctrlReDelta->SetValue(m_SpInc); m_pctrlSpecMin->SetValue(m_ReMin); m_pctrlSpecMax->SetValue(m_ReMax); m_pctrlSpecDelta->SetValue(m_ReInc); } m_pctrlMach->SetValue(m_Mach); m_pctrlNCrit->SetValue(m_NCrit); m_pctrlXTopTr->SetValue(m_XTopTr); m_pctrlXBotTr->SetValue(m_XBotTr); if(m_bAlpha) m_rbspec1->setChecked(true); else m_rbspec2->setChecked(true); OnAcl(); if(m_PolarType==FIXEDSPEEDPOLAR) m_rbtype1->setChecked(true); else if(m_PolarType==FIXEDLIFTPOLAR) m_rbtype2->setChecked(true); else if(m_PolarType==RUBBERCHORDPOLAR) m_rbtype3->setChecked(true); else if(m_PolarType==FIXEDAOAPOLAR) m_rbtype4->setChecked(true); OnPolarType(); if(!m_bFromList) m_rbRange1->setChecked(true); else m_rbRange2->setChecked(true); OnRange(); if(m_bFromZero) m_pctrlFromZero->setChecked(true); else m_pctrlFromZero->setChecked(false); m_pctrlInitBL->setChecked(true); m_pctrlStoreOpp->setChecked(s_bStoreOpp); m_pctrlSkipOpp->setEnabled(false); m_pctrlSkipPolar->setEnabled(false); m_Iterations = 0; ResetCurves(); MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(pMainFrame) m_RmsGraph.CopySettings(&pMainFrame->m_RefGraph, false); } bool BatchDlg::Iterate() { QString str; XFoil *pXFoil = (XFoil*)s_pXFoil; QXDirect* pXDirect = (QXDirect*)s_pXDirect; if(!pXFoil->viscal()) { pXFoil->lvconv = false;//point is unconverged str =tr("CpCalc: local speed too large\n Compressibility corrections invalid"); // QMessageBox::information(this, tr("Warning"), str); UpdateOutput(str); WriteString(str); m_bCancel = true; CleanUp(); return true; } while(m_Iterationslvconv && !m_bCancel && !m_bSkipPoint && !m_bSkipPolar) { qApp->processEvents(); if(pXFoil->ViscousIter()) { m_Iterations++; OutputIter(m_Iterations); } else { m_Iterations = m_IterLim; } } OutputIter(0); if(m_bCancel) return true; if(m_bSkipPoint || m_bSkipPolar) { pXFoil->lblini = false; pXFoil->lipan = false; return true; } if(!pXFoil->ViscalEnd()) { pXFoil->lvconv = false;//point is unconverged str =tr("CpCalc: local speed too large\n Compressibility corrections invalid"); // QMessageBox::information(this, tr("Warning"), str); m_bCancel = true; UpdateOutput(str); WriteString(str); CleanUp(); pXFoil->lblini = false; pXFoil->lipan = false; return true;// to exit loop } // m_bCalc = true; if(m_Iterations>=m_IterLim && !pXFoil->lvconv) { if(pXDirect->m_bAutoInitBL) { pXFoil->lblini = false; pXFoil->lipan = false; } pXFoil->fcpmin();// Is it of any use ? return true; } if(!pXFoil->lvconv) { pXFoil->fcpmin();// Is it of any use ? return false; } else { //converged at last pXFoil->fcpmin();// Is it of any use ? return true; } return false; } void BatchDlg::OnAcl() { if(m_PolarType==FIXEDAOAPOLAR) return; if(m_rbspec1->isChecked()) { m_pctrlSpecVar->setText(tr("Alpha =")); m_pctrlSpecMin->SetValue(m_AlphaMin); m_pctrlSpecMax->SetValue(m_AlphaMax); m_pctrlSpecDelta->SetValue(m_AlphaInc); m_bAlpha = true; m_pctrlFromZero->setEnabled(true); } else { m_pctrlSpecVar->setText(tr("Cl =")); m_pctrlSpecMin->SetValue(m_ClMin); m_pctrlSpecMax->SetValue(m_ClMax); m_pctrlSpecDelta->SetValue(m_ClInc); m_bAlpha = false; m_pctrlFromZero->setEnabled(false); } } void BatchDlg::OnSpecChanged() { ReadParams(); if(m_bAlpha) { m_AlphaMin = m_SpMin; m_AlphaMax = m_SpMax; m_AlphaInc = m_SpInc; } else { m_ClMin = m_SpMin; m_ClMax = m_SpMax; m_ClInc = m_SpInc; } } void BatchDlg::OnPolarType() { if(m_rbtype1->isChecked()) { m_pctrlReType->setText(tr("Reynolds =")); m_pctrlMaType->setText(tr("Mach =")); m_pctrlEditList->setEnabled(true); m_PolarType = FIXEDSPEEDPOLAR; } else if(m_rbtype2->isChecked()) { m_pctrlReType->setText(tr("Re.sqrt(Cl) =")); m_pctrlMaType->setText(tr("Ma.sqrt(Cl) =")); m_pctrlEditList->setEnabled(true); m_PolarType = FIXEDLIFTPOLAR; } else if(m_rbtype3->isChecked()) { m_pctrlReType->setText(tr("Re.Cl =")); m_pctrlMaType->setText(tr("Mach =")); m_pctrlEditList->setEnabled(true); m_PolarType = RUBBERCHORDPOLAR; } else if(m_rbtype4->isChecked()) { m_pctrlReType->setText(tr("Alpha =")); m_pctrlMaType->setText(tr("Mach =")); m_pctrlEditList->setEnabled(false); m_rbspec1->setChecked(true); m_PolarType = FIXEDAOAPOLAR; } if(m_PolarType!=FIXEDAOAPOLAR) { m_pctrlReMin->SetPrecision(0); m_pctrlReMax->SetPrecision(0); m_pctrlReDelta->SetPrecision(0); m_pctrlSpecMin->SetPrecision(2); m_pctrlSpecMax->SetPrecision(2); m_pctrlSpecDelta->SetPrecision(2); m_rbspec1->setEnabled(true); m_rbspec2->setEnabled(true); OnAcl(); m_pctrlReMin->SetValue(m_ReMin); m_pctrlReMax->SetValue(m_ReMax); m_pctrlReDelta->SetValue(m_ReInc); m_pctrlSpecMin->SetValue(m_SpMin); m_pctrlSpecMax->SetValue(m_SpMax); m_pctrlSpecDelta->SetValue(m_SpInc); } else { m_pctrlReMin->SetPrecision(2); m_pctrlReMax->SetPrecision(2); m_pctrlReDelta->SetPrecision(2); m_pctrlSpecMin->SetPrecision(0); m_pctrlSpecMax->SetPrecision(0); m_pctrlSpecDelta->SetPrecision(0); m_pctrlSpecVar->setText(tr("Reynolds =")); m_rbspec1->setEnabled(false); m_rbspec2->setEnabled(false); m_pctrlReMin->SetValue(m_SpMin); m_pctrlReMax->SetValue(m_SpMax); m_pctrlReDelta->SetValue(m_SpInc); m_pctrlSpecMin->SetValue(m_ReMin); m_pctrlSpecMax->SetValue(m_ReMax); m_pctrlSpecDelta->SetValue(m_ReInc); } } void BatchDlg::OutputIter(int iter) { XFoil *pXFoil = (XFoil*)s_pXFoil; if(iter) { m_RmsGraph.GetCurve(0)->AppendPoint(iter, pXFoil->rmsbl); m_RmsGraph.GetCurve(1)->AppendPoint(iter, pXFoil->rmxbl); UpdateGraph(); } } void BatchDlg::OnAnalyze() { if(m_bIsRunning) { XFoil::s_bCancel = true; m_bCancel = true; return; } m_bCancel = false; m_bIsRunning = true; XFoil *pXFoil = (XFoil*)s_pXFoil; m_pctrlTextOutput->setText(""); m_pctrlClose->setEnabled(false); QString FileName = QDir::tempPath() + "/XFLR5.log"; m_pXFile = new QFile(FileName); if (!m_pXFile->open(QIODevice::WriteOnly | QIODevice::Text)) m_pXFile = NULL; pXFoil->pXFile = m_pXFile; ReadParams(); SetFileHeader(); m_bInitBL = m_pctrlInitBL->isChecked(); s_bStoreOpp = m_pctrlStoreOpp->isChecked(); if(m_PolarType!=FIXEDAOAPOLAR) Analysis2(); else Analysis3(); pXFoil->lvisc = true; pXFoil->m_bTrace = false; m_pctrlAnalyze->setText(tr("Cancel")); m_pctrlSkipOpp->setEnabled(true); m_pctrlSkipPolar->setEnabled(true); m_pctrlAnalyze->setFocus(); StartAnalysis(); } void BatchDlg::OnClose() { m_bCancel = true; ReadParams(); done(1); } void BatchDlg::OnEditReList() { ReListDlg dlg(this); for (int i=0; im_poaFoil; if(m_pFoil) dlg.m_FoilName = m_pFoil->m_FoilName; dlg.m_FoilList.clear(); for(int i=0; iisChecked(); m_pctrlFoilList->setEnabled(!s_bCurrentFoil); } void BatchDlg::OnFromZero(int state) { state = 0; if(m_pctrlFromZero->isChecked()) m_bFromZero = true; else m_bFromZero = false; } void BatchDlg::OnInitBL(int state) { state = 0; if (m_pctrlInitBL->isChecked()) m_bInitBL = true; else m_bInitBL = false; } void BatchDlg::OnRange() { if(m_rbRange1->isChecked()) m_bFromList = false; else m_bFromList = true; m_pctrlEditList->setEnabled(m_bFromList); m_pctrlReMin->setEnabled(!m_bFromList); m_pctrlReMax->setEnabled(!m_bFromList); m_pctrlReDelta->setEnabled(!m_bFromList); m_pctrlMach->setEnabled(!m_bFromList); m_pctrlNCrit->setEnabled(!m_bFromList); // m_pctrlXBotTr->setEnabled(!m_bFromList); // m_pctrlXTopTr->setEnabled(!m_bFromList); } void BatchDlg::OnSkipPoint() { m_bSkipPoint = true; } void BatchDlg::OnSkipPolar() { m_bSkipPolar = true; } void BatchDlg::ReadParams() { if(m_PolarType!=FIXEDAOAPOLAR) { m_ReInc = m_pctrlReDelta->Value(); m_ReMax = m_pctrlReMax->Value(); m_ReMin = m_pctrlReMin->Value(); m_SpInc = m_pctrlSpecDelta->Value(); m_SpMax = m_pctrlSpecMax->Value(); m_SpMin = m_pctrlSpecMin->Value(); } else { m_SpInc = m_pctrlReDelta->Value(); m_SpMax = m_pctrlReMax->Value(); m_SpMin = m_pctrlReMin->Value(); m_ReInc = m_pctrlSpecDelta->Value(); m_ReMax = m_pctrlSpecMax->Value(); m_ReMin = m_pctrlSpecMin->Value(); } if(m_ReMin<=0.0) m_ReMin = qAbs(m_ReInc); if(m_ReMax<=0.0) m_ReMax = qAbs(m_ReMax); m_SpInc = qAbs(m_SpInc); m_Mach = m_pctrlMach->Value(); if(m_Mach<=0.0) m_Mach = 0.0; m_NCrit = m_pctrlNCrit->Value(); m_XTopTr = m_pctrlXTopTr->Value(); m_XBotTr = m_pctrlXBotTr->Value(); s_bStoreOpp = m_pctrlStoreOpp->isChecked(); } void BatchDlg::ReLoop() { XFoil *pXFoil = (XFoil*)s_pXFoil; QString str; QString strong = ""; double alphadeg; int ia, iRe, nRe, series, total, MaxSeries; double SpMin, SpMax, SpInc; QPoint Place(m_pctrlGraphOutput->rect().left()+20, m_pctrlGraphOutput->rect().top()+m_RmsGraph.GetMargin()/2); if(!m_bFromList) nRe = (int)qAbs((m_ReMax-m_ReMin)/m_ReInc); else nRe = m_NRe-1; for (iRe=0; iRe<=nRe; iRe++) { if(!m_bFromList) { pXFoil->reinf1 = m_ReMin + iRe *m_ReInc; pXFoil->minf1 = m_Mach; pXFoil->acrit = m_NCrit; } else { pXFoil->reinf1 = m_ReList[iRe]; pXFoil->minf1 = m_MachList[iRe]; pXFoil->acrit = m_NCritList[iRe]; } str = QString("Re=%1 Ma=%2 Nc=%3\n").arg(pXFoil->reinf1,8,'f',0).arg(pXFoil->minf1,5,'f',3).arg(pXFoil->acrit,5,'f',2); strong+= str; UpdateOutput(str); if (m_bFromZero && m_SpMin*m_SpMax<0) { MaxSeries = 2; SpMin = 0.0; SpMax = m_SpMax; } else { MaxSeries = 1; SpMin = m_SpMin; SpMax = m_SpMax; } SpInc = qAbs(m_SpInc); if(SpMin > SpMax) SpInc = -qAbs(SpInc); m_bSkipPolar = false; for (series=0; seriesprocessEvents(); if(m_bCancel) break; total = (int)qAbs((SpMax*1.0001-SpMin)/SpInc);//*1.0001 to make sure upper limit is included m_pCurPolar = CreatePolar(pXFoil->reinf1, pXFoil->minf1, pXFoil->acrit); if(!m_pCurPolar) return; pXFoil->InitXFoilAnalysis(m_pCurPolar); if (m_bInitBL) { pXFoil->lblini = false; pXFoil->lipan = false; } for (ia=0; ia<=total; ia++) { ResetCurves(); if(!m_bCancel && !m_bSkipPolar) { if(m_bAlpha) { alphadeg = SpMin+ia*SpInc; pXFoil->alfa = alphadeg * PI/180.0; pXFoil->lalfa = true; pXFoil->qinf = 1.0; str = QString("Alpha = %1").arg(alphadeg,9,'f',3); strong+=str; UpdateOutput(str); str = m_pFoil->m_FoilName+" / "; str += QString("Re=%1 / Alpha=%2").arg(pXFoil->reinf1,8,'f',0).arg(alphadeg,5,'f',2); str += QString::fromUtf8("°"); m_pctrlGraphOutput->SetTitle(str, Place); // here we go ! if (!pXFoil->specal()) { str = tr("Invalid Analysis Settings\nCpCalc: local speed too large\n Compressibility corrections invalid "); UpdateOutput(str); WriteString(str); m_bCancel = true; CleanUp(); return; } } else { pXFoil->lalfa = false; pXFoil->alfa = 0.0; pXFoil->qinf = 1.0; pXFoil->clspec = SpMin+ia*SpInc; str = QString(tr("Cl = %1")).arg(pXFoil->clspec,9,'f',3); strong+=str; UpdateOutput(str); if(!pXFoil->speccl()) { str = tr("Invalid Analysis Settings\nCpCalc: local speed too large\n Compressibility corrections invalid "); UpdateOutput(str); WriteString(str); m_bCancel = true; CleanUp(); return; } } pXFoil->lwake = false; pXFoil->lvconv = false; m_Iterations = 0; m_bSkipPoint = false; while(!Iterate()){} if(pXFoil->lvconv) { str = QString(tr(" ...converged after %1 iterations\n")).arg(m_Iterations); strong+= str; UpdateOutput(str); AddOpPoint(); // m_pCurPolar->AddData(pXFoil); } else if(m_bSkipPoint || m_bSkipPolar) { str = QString(tr(" ...skipped after %1 iterations\n")).arg(m_Iterations); strong+= str; UpdateOutput(str); } else { str = QString(tr(" ...unconverged after %1 iterations\n")).arg(m_Iterations); strong+= str; UpdateOutput(str); } } else { break; } }// end Alpha or Cl loop SpMin = 0; SpMax = m_SpMin; SpInc = -SpInc; } strong+="\n"; if(m_bCancel) break; }//end Re loop WriteString(strong); } void BatchDlg::ResetCurves() { m_RmsGraph.DeleteCurves(); m_RmsGraph.AddCurve(); m_RmsGraph.AddCurve(); QString str = "rms"; m_RmsGraph.GetCurve(0)->SetTitle(str); str = "max"; m_RmsGraph.GetCurve(1)->SetTitle(str); m_RmsGraph.GetCurve(1)->SetStyle(0); m_RmsGraph.SetAutoX(false); m_RmsGraph.SetXMin(0.0); m_RmsGraph.SetXMax((double)m_IterLim); m_RmsGraph.SetXUnit((int)(m_IterLim/10.0)); m_RmsGraph.SetYMin(-1.0); m_RmsGraph.SetYMax( 1.0); m_RmsGraph.SetX0(0.0); m_RmsGraph.SetY0(0.0); } void BatchDlg::SetFileHeader() { QXDirect *pXDirect = (QXDirect*)s_pXDirect; QTextStream out(m_pXFile); out << "\n"; out << MainFrame::versionName(); out << "\n"; out << m_pFoil->m_FoilName; out << "\n"; if(pXDirect && pXDirect->m_pCurPolar) { // out << pXDirect->m_pCurPolar->m_PlrName; // out << "\n"; } QDateTime dt = QDateTime::currentDateTime(); QString str = dt.toString("dd.MM.yyyy hh:mm:ss"); out << str; out << "\n___________________________________\n\n"; } void BatchDlg::SetPlrName(Polar *pPolar) { if(pPolar->m_PolarType!=FIXEDAOAPOLAR) { double R = pPolar->m_Reynolds/1000000.; pPolar->m_PlrName = QString("T%1_Re%2_M%3") .arg(pPolar->m_PolarType+1) .arg(R,0,'f',3) .arg( pPolar->m_Mach,0,'f',2); } else { pPolar->m_PlrName = QString("T4_Al%2_M%3") .arg(pPolar->m_ASpec,5,'f',2) .arg(pPolar->m_Mach,0,'f',2); } QString str; str = QString("_N%1").arg(pPolar->m_ACrit,0,'f',1); pPolar->m_PlrName += str; } void BatchDlg::StartAnalysis() { QXDirect *pXDirect = (QXDirect*)s_pXDirect; Foil *pFoil; QString strong; m_pctrlAnalyze->setText(tr("Cancel")); if(s_bCurrentFoil) { if(m_PolarType!=FIXEDAOAPOLAR) ReLoop(); else AlphaLoop(); } else { XFoil *pXFoil = (XFoil*)s_pXFoil; for(int i=0; iInitXFoilGeometry(pFoil); pXFoil->lvisc=true; strong = tr("Analyzing ")+pFoil->m_FoilName+("\n"); UpdateOutput(strong); if(m_PolarType!=FIXEDAOAPOLAR) ReLoop(); else AlphaLoop(); strong = "\n\n"; UpdateOutput(strong); } } if(pXDirect->m_bPolarView) { pXDirect->CreatePolarCurves(); pXDirect->UpdateView(); } strong = tr("Analysis completed"); UpdateOutput(strong); CleanUp(); } void BatchDlg::UpdateGraph() { m_pctrlGraphOutput->update(); } void BatchDlg::UpdateOutput(QString &str) { m_pctrlTextOutput->insertPlainText(str); m_pctrlTextOutput->ensureCursorVisible(); } void BatchDlg::WriteString(QString &strong) { if(!m_pXFile) return; if(!m_pXFile->isOpen()) return; QTextStream ds(m_pXFile); ds << strong; } void BatchDlg::showEvent(QShowEvent *event) { move(s_Position); } void BatchDlg::hideEvent(QHideEvent *event) { s_Position = pos(); } xflr5-6.09-06/src/xdirect/LEDlg.h000644 001750 000144 00000003213 12247174405 017624 0ustar00techwinderusers000000 000000 /**************************************************************************** LEDlg Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef LEDLG_H #define LEDLG_H #include #include "../misc/DoubleEdit.h" #include "../objects/Foil.h" class LEDlg : public QDialog { Q_OBJECT friend class QXDirect; friend class QAFoil; public: LEDlg(QWidget *pParent=NULL); void SetupLayout(); void InitDialog(); private slots: void OnChanged(); void OnOK(); void OnApply(); private: void keyPressEvent(QKeyEvent *event); public: static void* s_pXFoil; private: QPushButton *OKButton, *CancelButton, *ApplyButton; DoubleEdit *m_pctrlBlend, *m_pctrlLE; bool m_bApplied, m_bModified; double m_LErfac, m_Blend; void *m_pAFoil; void *m_pXDirect; Foil* m_pBufferFoil; Foil* m_pMemFoil; }; #endif // LEDLG_H xflr5-6.09-06/src/xdirect/BatchThreadDlg.h000644 001750 000144 00000015135 12247174410 021477 0ustar00techwinderusers000000 000000 /**************************************************************************** BatchThreadDlg Class Copyright (C) 2003-2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file * This file implements the multi-threaded batch foil analysis */ #ifndef BATCHTHREADDLG_H #define BATCHTHREADDLG_H #include #include #include #include #include #include #include "../graph/GraphWidget.h" #include "../objects/Foil.h" #include "../objects/Polar.h" #include "../misc/DoubleEdit.h" #include "XFoilTask.h" /** * @struct Analysis a pair of foil and polar used by a thread to perform one foil polar analysis. */ struct Analysis { Foil *pFoil; /**< a pointer to the Foil to be analyzed by the thread */ Polar *pPolar; /**< a pointer to the polar to be analyzed by the thread */ }; /** * @brief This class implements an interface to perform a multi-threaded batch foil analysis. */ class BatchThreadDlg : public QDialog { Q_OBJECT friend class QXDirect; friend class MainFrame; friend class QReListDlg; friend class XFoilTask; public: BatchThreadDlg(QWidget *pParent=NULL); void SetupLayout(); void InitDialog(); private: void CleanUp(); Polar * CreatePolar(Foil *pFoil, double Re, double Mach, double NCrit); void keyPressEvent(QKeyEvent *event); void showEvent(QShowEvent *event); void hideEvent(QHideEvent *event); void ReadParams(); void SetFileHeader(); void SetPlrName(Polar *pNewPolar); void StartAnalysis(); void StartThread(); void UpdateOutput(QString &str); void WriteString(QString &strong); void timerEvent(QTimerEvent *event); private slots: void OnSpecChanged(); void OnAnalyze(); void OnRange(); void OnAcl(); void OnEditReList(); void OnClose(); void OnFromZero(int state); void OnInitBL(int state); void OnFoilList(); void OnFoilSelectionType(); private: QRadioButton * m_pctrlFoil1, * m_pctrlFoil2; QPushButton *m_pctrlFoilList; QRadioButton *m_rbRange1, *m_rbRange2; QRadioButton *m_pctrlAlpha, *m_pctrlCl; QPushButton *m_pctrlEditList; DoubleEdit *m_pctrlReMin, *m_pctrlReMax, *m_pctrlReDelta, *m_pctrlMach; DoubleEdit *m_pctrlSpecMin, *m_pctrlSpecMax, *m_pctrlSpecDelta; DoubleEdit *m_pctrlNCrit, *m_pctrlXTopTr, *m_pctrlXBotTr; QLabel *m_pctrlSpecVar; QLabel *m_pctrlMaType, *m_pctrlReType; QCheckBox *m_pctrlInitBL, *m_pctrlFromZero, *m_pctrlUpdatePolarView; QPushButton *m_pctrlClose, *m_pctrlAnalyze; QTextEdit *m_pctrlTextOutput; static void* s_pXFoil; /**< a void pointer to the instance of the XFoil object */ static void* s_pXDirect; /**< a void pointer to the unique instance of the QXDirect class */ static void *s_pMainFrame; /**< a void pointer to the instance of the application's MainFrame class */ static bool s_bCurrentFoil; /**< true if the analysis should be performed only for the current foil */ static bool s_bUpdatePolarView; /**< true if the polar graphs should be updated during the analysis */ static QPoint s_Position; /**< the position on the client area of the dialog's topleft corner */ double m_ReMin; /**< the min Re for a range analysis */ double m_ReMax; /**< the max Re for a range analysis */ double m_ReInc; /**< the incement Re for a range analysis */ double m_AlphaMin; /**< The starting aoa */ double m_AlphaMax; /**< The ending aoa */ double m_AlphaInc; /**< The aoa increment */ double m_ClMin; /**< The starting Cl coefficient */ double m_ClMax; /**< The ending Cl coefficient */ double m_ClInc; /**< The Cl increment */ // bool m_bOutput; /**< true if the output should be displayed in the text widget */ bool m_bAlpha; /**< true if the analysis should be performed for a range of aoa rather than lift coefficient */ bool m_bFromList; /**< true if the analysis should be performed for a list of Re values rather than for a range */ bool m_bFromZero; /**< true if the iterations should start from aoa=0 rather than aoa=alpha_min */ bool m_bInitBL; /**< true if the boundary layer should be restored to the default value before each polar analysis */ bool m_bCancel; /**< true if the user has clicked the cancel button */ bool m_bIsRunning; /**< true until all the pairs of (foil, polar) have been calculated */ enumPolarType m_PolarType; /**< the type of analysis to perform */ int m_IterLim; /**< the maximum number of iterations for each aoa */ int m_nAnalysis; /**< the number of analysis pairs to run */ int m_nThreads; /**< the number of available threads */ double m_Mach; /**< the Mach number used if not from the list of Re numbers */ double m_NCrit; /**< the transition criterion used if not from the list of Re numbers */ double m_XTopTr; /**< the point of forced transition on the upper surface */ double m_XBotTr; /**< the point of forced transition on the lower surface */ double *m_ReList; /**< a pointer to the array of Re numbers to analyze */ double *m_MachList; /**< a pointer to the array of Mach numbers to analyze */ double *m_NCritList; /**< a pointer to the array of NCrit numbers to analyze */ int m_NRe; /**< the number of (Re, Ma, NCrit) sets to analyze for each selected foil */ QList m_AnalysisPair; /**< the list of all analysis to be performed. Once performed, an analysis is removed from the list. */ XFoilTask *m_pXFoilTask; /**< the task for a thread */ QFile *m_pXFile; /**< a pointer to the output log file */ Foil *m_pCurFoil; /**< a pointer to the current Foil */ QStringList m_FoilList; /**< the list of foils to analyze */ }; #endif // BATCHTHREADDLG_H xflr5-6.09-06/src/xdirect/InterpolateFoilsDlg.h000644 001750 000144 00000003666 12247174410 022617 0ustar00techwinderusers000000 000000 /**************************************************************************** InterpolateFoilsDlg Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef INTERPOLATEFOILSDLG_H #define INTERPOLATEFOILSDLG_H #include #include #include #include #include "../objects/Foil.h" #include "../misc/DoubleEdit.h" class InterpolateFoilsDlg : public QDialog { Q_OBJECT private slots: void OnSelChangeFoil1(int i); void OnSelChangeFoil2(int i); void OnFrac(); void OnOK(); void OnVScroll(int val); void keyPressEvent(QKeyEvent *event); public: InterpolateFoilsDlg(QWidget *pParent=NULL); void InitDialog(); void SetupLayout(); void Update(); static void *s_pXFoil; Foil* m_pBufferFoil; QList *m_poaFoil; QComboBox *m_pctrlFoil1, *m_pctrlFoil2; QLabel *m_pctrlCamb1, *m_pctrlCamb2, *m_pctrlThick1, *m_pctrlThick2; QLabel *m_pctrlCamb3, *m_pctrlThick3; QSlider *m_pctrlSlider; DoubleEdit *m_pctrlFrac; QPushButton *OKButton, *CancelButton; void *m_pXDirect; void *m_pAFoil; double m_Frac; QString m_NewFoilName; }; #endif // INTERPOLATEFOILSDLG_H xflr5-6.09-06/src/xdirect/ReListDlg.h000644 001750 000144 00000003414 12247174405 020531 0ustar00techwinderusers000000 000000 /**************************************************************************** ReListDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef RELISTDLG_H #define RELISTDLG_H #include #include #include #include #include "../misc/FloatEditDelegate.h" class ReListDlg : public QDialog { Q_OBJECT friend class BatchDlg; friend class BatchThreadDlg; public: ReListDlg(QWidget *pParent=NULL); void InitDialog(); private slots: void OnDelete(); void OnInsert(); void OnOK(); void OnCellChanged(QWidget *DoubleEdit); private: void FillReModel(); void SetupLayout(); void SortData(); void keyPressEvent(QKeyEvent *event); private: QPushButton *m_pctrlInsert, *m_pctrlDelete; QPushButton *OKButton, *CancelButton; QTableView *m_pctrlReView; QStandardItemModel *m_pReModel; FloatEditDelegate *m_pFloatDelegate; double m_ReList[30]; double m_MachList[30]; double m_NCritList[30]; int m_NRe; int m_iSelection; }; #endif // RELISTDLG_H xflr5-6.09-06/src/xdirect/CAddDlg.cpp000644 001750 000144 00000015371 12247174406 020463 0ustar00techwinderusers000000 000000 /**************************************************************************** Corner Add class Copyright (C) 2004-2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include "CAddDlg.h" #include #include "XDirect.h" #include "../design/AFoil.h" #include "XFoil.h" void *CAddDlg::s_pXFoil; CAddDlg::CAddDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Local Panel Refinement")); m_pAFoil = NULL; m_pXDirect = NULL; m_pBufferFoil = NULL; m_pMemFoil = NULL; m_iSplineType = 0; SetupLayout(); connect(ApplyButton, SIGNAL(clicked()),this, SLOT(OnApply())); connect(OKButton, SIGNAL(clicked()),this, SLOT(accept())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void CAddDlg::SetupLayout() { QGridLayout *RefineGrid =new QGridLayout; QLabel *lab1 = new QLabel(tr("Angle Criterion ")+QString::fromUtf8("(°)")); QLabel *lab2 = new QLabel(tr("Type of Spline")); QLabel *lab3 = new QLabel(tr("Refinement X Limits")); QLabel *lab4 = new QLabel(tr("From")); QLabel *lab5 = new QLabel(tr("To")); lab4->setAlignment(Qt::AlignCenter); lab5->setAlignment(Qt::AlignCenter); m_pctrlAngTol = new DoubleEdit; m_pctrlFrom = new DoubleEdit; m_pctrlTo = new DoubleEdit; m_pctrlrb1 = new QRadioButton(tr("Uniform")); m_pctrlrb2 = new QRadioButton(tr("Arc Length")); RefineGrid->addWidget(lab1,1,1); RefineGrid->addWidget(lab2,2,1); RefineGrid->addWidget(lab3,5,1); RefineGrid->addWidget(m_pctrlAngTol,1,2); RefineGrid->addWidget(m_pctrlrb1,2,2); RefineGrid->addWidget(m_pctrlrb2,2,3); RefineGrid->addWidget(lab4, 4, 2); RefineGrid->addWidget(lab5, 4, 3); RefineGrid->addWidget(m_pctrlFrom,5,2); RefineGrid->addWidget(m_pctrlTo,5,3); m_pctrlTotal = new QLabel(tr("Total")); m_pctrlAdded = new QLabel(tr("Added")); m_pctrlMaxAngle = new QLabel(tr("MaxAngle")); m_pctrlAtPanel = new QLabel(tr("At Panel")); QHBoxLayout *CommandButtons = new QHBoxLayout; OKButton = new QPushButton(tr("Accept")); CancelButton = new QPushButton(tr("Cancel")); ApplyButton = new QPushButton(tr("Apply")); CommandButtons->addStretch(1); CommandButtons->addWidget(ApplyButton); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addLayout(RefineGrid); MainLayout->addStretch(1); MainLayout->addWidget(m_pctrlTotal); MainLayout->addWidget(m_pctrlAdded); MainLayout->addWidget(m_pctrlMaxAngle); MainLayout->addWidget(m_pctrlAtPanel); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); setLayout(MainLayout); setMinimumHeight(300); } void CAddDlg::OnApply() { XFoil *pXFoil = (XFoil*)s_pXFoil; QAFoil * pAFoil = (QAFoil*)m_pAFoil; QXDirect *pXDirect = (QXDirect*)m_pXDirect; int i; for (i=0; i< m_pMemFoil->nb; i++) { pXFoil->xb[i+1] = m_pMemFoil->xb[i] ; pXFoil->yb[i+1] = m_pMemFoil->yb[i]; } pXFoil->nb = m_pMemFoil->nb; pXFoil->lflap = false; pXFoil->lbflap = false; if(pXFoil->Preprocess()) { pXFoil->CheckAngles(); /* for (int k=0; kn;k++){ m_pMemFoil->nx[k] = pXFoil->nx[k+1]; m_pMemFoil->ny[k] = pXFoil->ny[k+1]; } m_pMemFoil->n = pXFoil->n;*/ } else { QMessageBox::information(window(), tr("Warning"), tr("Unrecognized foil format")); return; } if (m_pctrlrb1->isChecked()) m_iSplineType = 1; else m_iSplineType = 2; int added = pXFoil->cadd(m_iSplineType, m_pctrlAngTol->Value(), m_pctrlFrom->Value(), m_pctrlTo->Value()); pXFoil->abcopy(); QString strong; strong =QString(tr("Total number of points is %1")).arg(pXFoil->n); m_pctrlTotal->setText(strong); strong = QString(tr("(added %1 points to original foil)")).arg(added); m_pctrlAdded->setText(strong); for (i=0; i< pXFoil->n; i++) { m_pBufferFoil->xb[i] = pXFoil->x[i+1]; m_pBufferFoil->yb[i] = pXFoil->y[i+1]; } m_pBufferFoil->nb = pXFoil->n; // pXFoil->SetFoilFlap(m_pBufferFoil); m_pBufferFoil->InitFoil(); m_pBufferFoil->SetFlap(); pXFoil->CheckAngles(); strong = QString(tr("Maximum panel angle is %1")).arg( pXFoil->amax,0,'f',1); m_pctrlMaxAngle->setText(strong); strong = QString(tr("at panel position %1")).arg(pXFoil->imax); m_pctrlAtPanel->setText(strong); if(pXDirect) pXDirect->UpdateView(); else if(pAFoil) pAFoil->UpdateView(); } void CAddDlg::OnUniform() { if(m_pctrlrb1->isChecked()) m_iSplineType = 1; else m_iSplineType = 2; } void CAddDlg::InitDialog() { XFoil *pXFoil = (XFoil*)s_pXFoil; double xbmin, xbmax, xrf1, xrf2; xbmin = pXFoil->xb[1]; xbmax = pXFoil->xb[1]; for( int i=1; i<= pXFoil->nb; i++) { xbmin = qMin(xbmin, pXFoil->xb[i]); xbmax = qMax(xbmax, pXFoil->xb[i]); } //----- default inputs atol = 0.5 * pXFoil->amax; xrf1 = xbmin - 0.1*(xbmax-xbmin); xrf2 = xbmax + 0.1*(xbmax-xbmin); m_pctrlrb1->setChecked(1); m_iSplineType = 1; m_pctrlFrom->SetValue(xrf1); m_pctrlTo->SetValue(xrf2); m_pctrlAngTol->SetValue(atol); QString strong; pXFoil->CheckAngles(); strong = QString(tr("Maximum panel angle is %1 deg")).arg(pXFoil->amax,0,'f',1); m_pctrlMaxAngle->setText(strong); strong = QString(tr("at panel position %1")).arg(pXFoil->imax); m_pctrlAtPanel->setText(strong); m_pctrlAdded->setText(" "); strong = QString(tr("Total number of points is %1")).arg(pXFoil->n); m_pctrlTotal->setText(strong); } void CAddDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing dialog switch (event->key()) { case Qt::Key_Escape: { done(0); return; } case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OnApply(); OKButton->setFocus(); } else { QDialog::accept(); } break; } default: event->ignore(); } } xflr5-6.09-06/src/xdirect/ReListDlg.cpp000644 001750 000144 00000016775 12247174405 021102 0ustar00techwinderusers000000 000000 /**************************************************************************** ReListDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include "XDirect.h" #include "ReListDlg.h" #include "../misc/DoubleEdit.h" ReListDlg::ReListDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Reynolds Number List")); memset(m_ReList, 0, sizeof(m_ReList)); memset(m_MachList, 0, sizeof(m_MachList)); memset(m_NCritList, 0, sizeof(m_NCritList)); m_NRe = 0; m_iSelection = 0; SetupLayout(); connect(m_pctrlDelete, SIGNAL(clicked()),this, SLOT(OnDelete())); connect(m_pctrlInsert, SIGNAL(clicked()),this, SLOT(OnInsert())); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void ReListDlg::InitDialog() { m_pReModel = new QStandardItemModel; m_pReModel->setRowCount(10);//temporary m_pReModel->setColumnCount(3); m_pReModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Re")); m_pReModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Mach")); m_pReModel->setHeaderData(2, Qt::Horizontal, QObject::tr("NCrit")); m_pctrlReView->setModel(m_pReModel); int w = m_pctrlReView->width(); m_pctrlReView->setColumnWidth(0,(int)(w/3)); m_pctrlReView->setColumnWidth(1,(int)(w/3)); m_pctrlReView->setColumnWidth(2,(int)(w/3)); QHeaderView *HorizontalHeader = m_pctrlReView->horizontalHeader(); HorizontalHeader->setStretchLastSection(true); m_pFloatDelegate = new FloatEditDelegate; m_pctrlReView->setItemDelegate(m_pFloatDelegate); int *precision = new int[3]; precision[0] = 0;//no digits for Re Number precision[1] = 2;//two digits for Mach and NCrit precision[2] = 2;//two digits for Mach and NCrit m_pFloatDelegate->SetPrecision(precision); connect(m_pFloatDelegate, SIGNAL(closeEditor(QWidget *)), this, SLOT(OnCellChanged(QWidget *))); FillReModel(); } void ReListDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus()) OKButton->setFocus(); else accept(); break; } case Qt::Key_Escape: { reject(); return; } default: event->ignore(); } } void ReListDlg::OnCellChanged(QWidget *DoubleEdit) { //sort the data in case the Re Number was changed SortData(); } void ReListDlg::SetupLayout() { QVBoxLayout *CommandButtons = new QVBoxLayout; { m_pctrlInsert = new QPushButton(tr("Insert")); m_pctrlDelete = new QPushButton(tr("Delete")); OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(m_pctrlInsert); CommandButtons->addWidget(m_pctrlDelete); CommandButtons->addStretch(2); CommandButtons->addWidget(OKButton); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); } m_pctrlReView = new QTableView(this); m_pctrlReView->setMinimumHeight(500); m_pctrlReView->setMinimumWidth(250); m_pctrlReView->setSelectionBehavior(QAbstractItemView::SelectRows); m_pctrlReView->setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed | QAbstractItemView::AnyKeyPressed); QHBoxLayout * MainLayout = new QHBoxLayout(this); { MainLayout->addWidget(m_pctrlReView); MainLayout->addLayout(CommandButtons); } setLayout(MainLayout); } void ReListDlg::FillReModel() { m_pReModel->setColumnCount(3); m_pReModel->setRowCount(m_NRe); for (int i=0; iindex(i, 0, QModelIndex()); m_pReModel->setData(Xindex, m_ReList[i]); QModelIndex Yindex =m_pReModel->index(i, 1, QModelIndex()); m_pReModel->setData(Yindex, m_MachList[i]); QModelIndex Zindex =m_pReModel->index(i, 2, QModelIndex()); m_pReModel->setData(Zindex, m_NCritList[i]); } m_pctrlReView->resizeRowsToContents(); // m_pctrlReView->resizeColumnsToContents(); m_pctrlReView->setWindowTitle(QObject::tr("Re List")); } void ReListDlg::OnDelete() { int i, sel; QModelIndex index = m_pctrlReView->currentIndex(); sel = index.row(); if(sel<0) return; for (i=sel;icurrentIndex().row(); // if(sel<0) return; for (i=m_NRe; i>sel; i--) { m_ReList[i] = m_ReList[i-1]; m_MachList[i] = m_MachList[i-1]; m_NCritList[i] = m_NCritList[i-1]; } if(sel>0) m_ReList[sel] = (m_ReList[sel-1]+m_ReList[sel+1]) /2.0; else if(sel==0) m_ReList[sel] = m_ReList[sel+1] /2.0; else m_ReList[0] = 100000.0; if(sel>=0) { m_MachList[sel] = m_MachList[sel+1]; m_NCritList[sel] = m_NCritList[sel+1]; } else { sel = 0; m_MachList[sel] = 0.0; m_NCritList[sel] = 0.0; } m_NRe ++; FillReModel(); QModelIndex index = m_pReModel->index(sel, 0, QModelIndex()); m_pctrlReView->setCurrentIndex(index); m_pctrlReView->openPersistentEditor(index); } void ReListDlg::OnOK() { for (int i=0; iindex(i, 0, QModelIndex()); m_ReList[i] = index.data().toDouble(); index = m_pReModel->index(i, 1, QModelIndex()); m_MachList[i] = index.data().toDouble(); index = m_pReModel->index(i, 2, QModelIndex()); m_NCritList[i] = index.data().toDouble(); } done(1); } void ReListDlg::SortData() { int i; double ReList[30]; double MachList[30]; double NCritList[30]; // unfortunately, the signal doesn't tell us which cell was changed // so we sort it all... great // hopefully, only one at most is out of order : the latest one which was changed //first read the data for (i=0; iindex(i, 0, QModelIndex()).data().toDouble(); MachList[i] = m_pReModel->index(i, 1, QModelIndex()).data().toDouble(); NCritList[i] = m_pReModel->index(i, 2, QModelIndex()).data().toDouble(); } bool bNotSorted = true; double tmp; while(bNotSorted) { bNotSorted = false; for(i=1; i #include "../objects/Polar.h" // this class runs an XFoil analysis in a thread separate from the main thread /** *@class XFoilTask * This file implements the management task of an XFoil calculation. Used in multithreaded analysis. */ class XFoilTask : public QRunnable { public: XFoilTask(); public: void run(); bool AlphaSequence(); bool Init(Foil *pFoil, Polar *pPolar); bool Iterate(); static bool s_bCancel; /**< true if the user has asked to cancel the analysis */ static bool s_bAutoInitBL; /**< true if the BL initialization is left to the code's decision */ static void *s_pBatchThreadDlg; /**< A static pointer to the instance of the calling BathThreadDlg class */ int m_Id; /**< @todo check usage */ int m_Iterations; /**< The number of iterations already performed */ Foil *m_pFoil; /**< A pointer to the instance of the Foil object for which the calculation is performed */ Polar *m_pPolar; /**< A pointer to the instance of the Polar object for which the calculation is performed */ bool m_bIsFinished; /**< true if the calculation is over */ XFoil XFoilInstance; /**< An instance of the XFoil class specific for this object @todo check the behaviour of static variables in XFoil methods */ }; #endif // XFOILTASK_H xflr5-6.09-06/src/xdirect/ManageFoilsDlg.cpp000644 001750 000144 00000023323 12247174405 022050 0ustar00techwinderusers000000 000000 /**************************************************************************** ManageFoilsDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include #include "XDirect.h" #include "../mainframe.h" #include "ManageFoilsDlg.h" ManageFoilsDlg::ManageFoilsDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Foil Management")); m_pMainFrame = NULL; m_pXDirect = NULL; SetupLayout(); connect(m_pctrlDelete, SIGNAL(clicked()),this, SLOT(OnDelete())); connect(m_pctrlRename, SIGNAL(clicked()),this, SLOT(OnRename())); connect(m_pctrlExport, SIGNAL(clicked()),this, SLOT(OnExport())); connect(m_pctrlFoilTable, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(OnDoubleClickTable(const QModelIndex &))); connect(CloseButton, SIGNAL(clicked()),this, SLOT(accept())); } void ManageFoilsDlg::InitDialog(QString FoilName) { FillFoilTable(); QString strong; if(m_pFoilModel->rowCount()) { if(FoilName.length()) { QModelIndex ind; for(int i=0; i< m_pFoilModel->rowCount(); i++) { ind = m_pFoilModel->index(i, 0, QModelIndex()); strong = ind.model()->data(ind, Qt::EditRole).toString(); if(strong == FoilName) { m_pctrlFoilTable->selectRow(i); break; } } } else { m_pctrlFoilTable->selectRow(0); QStandardItem *pItem = m_pFoilModel->item(0,0); FoilName = pItem->text(); } m_pFoil = MainFrame::foil(FoilName); } else { m_pFoil = NULL; } } void ManageFoilsDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Return: { if(!CloseButton->hasFocus()) CloseButton->setFocus(); else accept(); break; } case Qt::Key_Escape: { reject(); return; } default: event->ignore(); } } void ManageFoilsDlg::SetupLayout() { QVBoxLayout *CommandButtons = new QVBoxLayout; { m_pctrlDelete = new QPushButton(tr("Delete")); m_pctrlRename = new QPushButton(tr("Rename")); m_pctrlExport = new QPushButton(tr("Export Foil")); CloseButton = new QPushButton(tr("Close")); CommandButtons->addStretch(1); CommandButtons->addWidget(m_pctrlDelete); CommandButtons->addWidget(m_pctrlRename); CommandButtons->addWidget(m_pctrlExport); CommandButtons->addStretch(2); CommandButtons->addWidget(CloseButton); CommandButtons->addStretch(1); } m_pctrlFoilTable = new QTableView(this); m_pctrlFoilTable->setSelectionMode(QAbstractItemView::SingleSelection); m_pctrlFoilTable->setSelectionBehavior(QAbstractItemView::SelectRows); m_pctrlFoilTable->horizontalHeader()->setStretchLastSection(true); QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::MinimumExpanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Expanding); m_pctrlFoilTable->setSizePolicy(szPolicyExpanding); m_pctrlFoilTable->setMinimumWidth(800); QHBoxLayout * MainLayout = new QHBoxLayout(this); { MainLayout->addWidget(m_pctrlFoilTable); MainLayout->addLayout(CommandButtons); } setLayout(MainLayout); connect(m_pctrlFoilTable, SIGNAL(clicked(const QModelIndex &)), this, SLOT(OnFoilClicked(const QModelIndex&))); connect(m_pctrlFoilTable, SIGNAL(pressed(const QModelIndex &)), this, SLOT(OnFoilClicked(const QModelIndex&))); m_pFoilModel = new QStandardItemModel; m_pFoilModel->setRowCount(10);//temporary m_pFoilModel->setColumnCount(12); m_pFoilModel->setHeaderData(0, Qt::Horizontal, tr("Name")); m_pFoilModel->setHeaderData(1, Qt::Horizontal, tr("Thickness (%)")); m_pFoilModel->setHeaderData(2, Qt::Horizontal, tr("at (%)")); m_pFoilModel->setHeaderData(3, Qt::Horizontal, tr("Camber (%)")); m_pFoilModel->setHeaderData(4, Qt::Horizontal, tr("at (%)")); m_pFoilModel->setHeaderData(5, Qt::Horizontal, tr("Points")); m_pFoilModel->setHeaderData(6, Qt::Horizontal, tr("TE Flap (")+QString::fromUtf8("°")+")"); m_pFoilModel->setHeaderData(7, Qt::Horizontal, tr("TE XHinge")); m_pFoilModel->setHeaderData(8, Qt::Horizontal, tr("TE YHinge")); m_pFoilModel->setHeaderData(9, Qt::Horizontal, tr("LE Flap (")+QString::fromUtf8("°")+")"); m_pFoilModel->setHeaderData(10, Qt::Horizontal, tr("LE XHinge")); m_pFoilModel->setHeaderData(11, Qt::Horizontal, tr("LE YHinge")); m_pctrlFoilTable->setModel(m_pFoilModel); m_pctrlFoilTable->setWindowTitle(tr("Foils")); m_pFoilDelegate = new FoilTableDelegate; m_pctrlFoilTable->setItemDelegate(m_pFoilDelegate); m_pFoilDelegate->m_pFoilModel = m_pFoilModel; int *precision = new int[12]; precision[0] = 2; precision[1] = 2; precision[2] = 2; precision[3] = 2; precision[4] = 2; precision[5] = 0; precision[6] = 2; precision[7] = 2; precision[8] = 2; precision[9] = 2; precision[10] = 2; precision[11] = 2; m_pFoilDelegate->m_Precision = precision; } void ManageFoilsDlg::FillFoilTable() { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; int i; m_pFoilModel->setRowCount(pMainFrame->s_oaFoil.size()); for(i=0; is_oaFoil.size(); i++) { FillTableRow(i); } } void ManageFoilsDlg::FillTableRow(int row) { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; QString str, strong; QModelIndex ind; Foil *pFoil = (Foil*)pMainFrame->s_oaFoil.at(row); ind = m_pFoilModel->index(row, 0, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_FoilName); if(pFoil->m_FoilDescription.length()) m_pFoilModel->setData(ind, pFoil->m_FoilDescription, Qt::ToolTipRole); ind = m_pFoilModel->index(row, 1, QModelIndex()); m_pFoilModel->setData(ind, pFoil->m_fThickness); ind = m_pFoilModel->index(row, 2, QModelIndex()); m_pFoilModel->setData(ind, pFoil->m_fXThickness); ind = m_pFoilModel->index(row, 3, QModelIndex()); m_pFoilModel->setData(ind, pFoil->m_fCamber); ind = m_pFoilModel->index(row, 4, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_fXCamber); ind = m_pFoilModel->index(row, 5, QModelIndex()); m_pFoilModel->setData(ind,pFoil->n); if(pFoil && pFoil->m_bTEFlap) { ind = m_pFoilModel->index(row, 6, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_TEFlapAngle); ind = m_pFoilModel->index(row, 7, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_TEXHinge/100.0); ind = m_pFoilModel->index(row, 8, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_TEYHinge/100.0); } if(pFoil && pFoil->m_bLEFlap) { ind = m_pFoilModel->index(row, 9, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_LEFlapAngle); ind = m_pFoilModel->index(row, 10, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_LEXHinge/100.0); ind = m_pFoilModel->index(row, 11, QModelIndex()); m_pFoilModel->setData(ind,pFoil->m_LEYHinge/100.0); } } void ManageFoilsDlg::OnRename() { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; if (m_pFoil) { pMainFrame->RenameFoil(m_pFoil); FillFoilTable(); MainFrame::SetSaveState(false); } } void ManageFoilsDlg::OnExport() { if(!m_pFoil) return; QString FileName; FileName = m_pFoil->m_FoilName; FileName.replace("/", " "); FileName = QFileDialog::getSaveFileName(this, tr("Export Foil"), MainFrame::s_LastDirName+"/"+FileName+".dat", tr("Foil File (*.dat)")); if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&XFile); m_pFoil->ExportFoil(out); XFile.close(); } void ManageFoilsDlg::OnDelete() { if(!m_pFoil) return; MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; pMainFrame->DeleteFoil(m_pFoil); QModelIndex index = m_pctrlFoilTable->currentIndex(); int sel = qMax(index.row()-1,0); FillFoilTable(); if(m_pFoilModel->rowCount()>0) { m_pctrlFoilTable->selectRow(sel); QStandardItem *pItem = m_pFoilModel->item(sel,0); QString FoilName = pItem->text(); m_pFoil = MainFrame::foil(FoilName); } else m_pFoil = NULL; } void ManageFoilsDlg::OnDoubleClickTable(const QModelIndex &index) { if(index.row()>=0) accept(); } void ManageFoilsDlg::OnFoilClicked(const QModelIndex& index) { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; if(index.row()>=pMainFrame->s_oaFoil.size()) return; QStandardItem *pItem = m_pFoilModel->item(index.row(),0); QString FoilName =pItem->text(); m_pFoil= MainFrame::foil(FoilName); } void ManageFoilsDlg::resizeEvent(QResizeEvent *event) { int w = m_pctrlFoilTable->width(); int w12 = (int)((double)w/13.0); int w14 = (int)((double)w/15.0); m_pctrlFoilTable->setColumnWidth(1,w12); m_pctrlFoilTable->setColumnWidth(2,w12); m_pctrlFoilTable->setColumnWidth(3,w12); m_pctrlFoilTable->setColumnWidth(4,w12); m_pctrlFoilTable->setColumnWidth(5,w14);//points m_pctrlFoilTable->setColumnWidth(6,w14);//TE Flap m_pctrlFoilTable->setColumnWidth(7,w12);//TE XHinge m_pctrlFoilTable->setColumnWidth(8,w12);//TE YHinge m_pctrlFoilTable->setColumnWidth(9, w14);//LE Flap m_pctrlFoilTable->setColumnWidth(10,w12);//LE XHinge m_pctrlFoilTable->setColumnWidth(11,w12);//LE YHinge m_pctrlFoilTable->setColumnWidth(0,w-8*w12-3*w14-40); } xflr5-6.09-06/src/xdirect/FoilGeomDlg.h000644 001750 000144 00000004265 12247174405 021035 0ustar00techwinderusers000000 000000 /**************************************************************************** FoilGeomDlg Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef FOILGEOMDLG_H #define FOILGEOMDLG_H #include #include #include "../misc/DoubleEdit.h" #include "../objects/Foil.h" class FoilGeomDlg : public QDialog { Q_OBJECT friend class QAFoil; friend class QXDirect; friend class MainFrame; public: FoilGeomDlg(QWidget *pParent=NULL); void InitDialog(); private slots: void OnRestore(); void OnOK(); void OnCamberSlide(int pos); void OnXCamberSlide(int pos); void OnThickSlide(int pos); void OnXThickSlide(int pos); void OnCamber(); void OnXCamber(); void OnThickness(); void OnXThickness(); private: void keyPressEvent(QKeyEvent *event); void SetupLayout(); void Apply(); private: QSlider *m_pctrlCamberSlide, *m_pctrlThickSlide, *m_pctrlXThickSlide, *m_pctrlXCamberSlide; DoubleEdit *m_pctrlXCamber; DoubleEdit *m_pctrlXThickness; DoubleEdit *m_pctrlThickness; DoubleEdit *m_pctrlCamber; QPushButton *OKButton, *CancelButton, *RestoreButton; private: static void* s_pXFoil; double m_fCamber; double m_fThickness; double m_fXCamber; double m_fXThickness; Foil* m_pBufferFoil; Foil* m_pMemFoil; void *m_pXDirect; void *m_pAFoil; bool m_bApplied,m_bAppliedX, m_bModified; }; #endif // FOILGEOMDLG_H xflr5-6.09-06/src/xdirect/BatchDlg.h000644 001750 000144 00000007712 12247174410 020351 0ustar00techwinderusers000000 000000 /**************************************************************************** BatchDlg Class Copyright (C) 2003-2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef BATCHDLG_H #define BATCHDLG_H #include #include #include #include #include #include #include #include "../graph/QGraph.h" #include "../graph/GraphWidget.h" #include "../objects/Foil.h" #include "../objects/Polar.h" #include "../misc/DoubleEdit.h" class BatchDlg : public QDialog { Q_OBJECT friend class QXDirect; friend class MainFrame; friend class QReListDlg; public: BatchDlg(QWidget *pParent=NULL); void SetupLayout(); void InitDialog(); private: void keyPressEvent(QKeyEvent *event); void showEvent(QShowEvent *event); void hideEvent(QHideEvent *event); void AddOpPoint(); void AlphaLoop(); void Analysis2(); void Analysis3(); void CleanUp(); Polar* CreatePolar(double Spec, double Mach, double NCrit); bool Iterate(); void OutputIter(int iter); void ReadParams(); void ReLoop(); void ResetCurves(); void SetFileHeader(); void SetPlrName(Polar *pPolar); void StartAnalysis(); void UpdateGraph(); void UpdateOutput(QString &str); void WriteString(QString &strong); private slots: void OnSpecChanged(); void OnAnalyze(); void OnRange(); void OnAcl(); void OnEditReList(); void OnPolarType(); void OnClose(); void OnFromZero(int state); void OnSkipPoint(); void OnSkipPolar(); void OnInitBL(int state); void OnFoilList(); void OnFoilSelectionType(); private: static QPoint s_Position; /**< the position on the client area of the dialog's topleft corner */ QRadioButton * m_pctrlFoil1, * m_pctrlFoil2; QPushButton *m_pctrlFoilList; QRadioButton *m_rbtype1, *m_rbtype2, *m_rbtype3, *m_rbtype4, *m_rbRange1, *m_rbRange2; QRadioButton *m_rbspec1, *m_rbspec2; QPushButton *m_pctrlEditList; DoubleEdit *m_pctrlReMin, *m_pctrlReMax, *m_pctrlReDelta, *m_pctrlMach; DoubleEdit *m_pctrlSpecMin, *m_pctrlSpecMax, *m_pctrlSpecDelta; DoubleEdit *m_pctrlNCrit, *m_pctrlXTopTr, *m_pctrlXBotTr; QLabel *m_pctrlSpecVar; QLabel *m_pctrlMaType, *m_pctrlReType; QCheckBox *m_pctrlInitBL, *m_pctrlFromZero, *m_pctrlStoreOpp; QPushButton *m_pctrlSkipOpp, *m_pctrlSkipPolar; QPushButton *m_pctrlClose, *m_pctrlAnalyze; QTextEdit *m_pctrlTextOutput; GraphWidget *m_pctrlGraphOutput; static bool s_bStoreOpp; static void* s_pXFoil; static void* s_pXDirect; static void * s_pMainFrame; static bool s_bCurrentFoil; enumPolarType m_PolarType; double m_Mach; double m_ReMin, m_ReMax, m_ReInc; double m_SpMin, m_SpMax, m_SpInc; double m_AlphaMin, m_AlphaMax, m_AlphaInc; double m_ClMin, m_ClMax, m_ClInc; double m_NCrit; double m_XTopTr; double m_XBotTr; double *m_ReList; double *m_MachList; double *m_NCritList; bool m_bOutput; bool m_bAlpha; bool m_bFromList; bool m_bFromZero; bool m_bInitBL; bool m_bCancel, m_bSkipPoint, m_bSkipPolar; bool m_bIsRunning; int m_Iterations; int m_IterLim; int m_NRe; QFile *m_pXFile; Foil *m_pFoil; Polar *m_pCurPolar; QFont m_RFont; QFont m_TitleFont; QStringList m_FoilList; QString m_PlrName; QGraph m_RmsGraph; QRect m_IterRect; Curve* m_pIterCurve; }; #endif // BATCHDLG_H xflr5-6.09-06/src/xdirect/XFoilAnalysisDlg.h000644 001750 000144 00000005306 12247174410 022052 0ustar00techwinderusers000000 000000 /**************************************************************************** XFoilAnalysisDlg Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef XFOILANALYSISDLG_H #define XFOILANALYSISDLG_H #include #include #include #include #include #include #include #include #include "../graph/QGraph.h" #include "../graph/GraphWidget.h" #include "XFoil.h" class XFoilAnalysisDlg : public QDialog { Q_OBJECT friend class MainFrame; friend class QXDirect; public: XFoilAnalysisDlg(QWidget *pParent=NULL); void InitDialog(); private slots: void OnCancelAnalysis(); void OnSkipPoint(); private: void showEvent(QShowEvent *event); void hideEvent(QHideEvent *event); void accept(); void reject(); void AddOpPoint(); void ResetCurves(); void SetAlpha(double AlphaMin, double AlphaMax, double DeltaAlpha); void SetCl(double ClMin, double ClMax, double DeltaCl); void SetRe(double ReMin, double ReMax, double DeltaRe); void SetFileHeader(); void SetupLayout(); void StartAnalysis(); void UpdateView(); void UpdateOutput(QString &strong); void WriteString(QString &strong); bool AlphaLoop(); bool Iterate(); bool ReLoop(); //variables static QPoint s_Position; /**< the position on the client area of he dialog's topleft corner */ GraphWidget * m_pGraphWidget; QTextEdit *m_pctrlTextOutput; QPushButton* m_pctrlCancel, *m_pctrlSkip; bool m_bAlpha; bool m_bType4; bool m_bSequence; bool m_bSkip, m_bExit, m_bFinished, m_bAutoInitBL; int m_Iterations, m_IterLim; double m_AlphaMin, m_AlphaMax, m_DeltaAlpha; double m_ClMin, m_ClMax, m_DeltaCl; double m_ReMin, m_ReMax, m_DeltaRe; static void *s_pXDirect; static void *s_pMainFrame; QTimer *EventTimer; QFile *m_pXFile; QPoint m_LegendPlace; QRect m_ViscRect; QString m_FoilName; QGraph m_RmsGraph; XFoil* m_pXFoil; }; #endif xflr5-6.09-06/src/threedwidget.cpp000644 001750 000144 00000053251 12247174404 020253 0ustar00techwinderusers000000 000000 /**************************************************************************** ThreeDWidget Class Copyright (C) 2009-2012 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /* #define GLMIAREXVIEW 3 #define GLBODYVIEW 5 #define GLWINGVIEW 7 */ #include #include "mainframe.h" #include "miarex/Miarex.h" #include #include "graph/Curve.h" #include "miarex/GL3dBodyDlg.h" #include "miarex/GL3dWingDlg.h" #include "misc/W3dPrefsDlg.h" #include "threedwidget.h" void *ThreeDWidget::s_pMiarex; void *ThreeDWidget::s_pMainFrame; /** *The public constructor */ ThreeDWidget::ThreeDWidget(QWidget *parent) : QGLWidget(parent) { m_pParent = parent; m_iView = GLMIAREXVIEW; setAutoFillBackground(false); setMouseTracking(true); setCursor(Qt::CrossCursor); } /** *Overrides the contextMenuEvent method of the base class. *Dispatches the handling to the active child application. */ void ThreeDWidget::contextMenuEvent (QContextMenuEvent * event) { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QPoint ScreenPt = event->globalPos(); if(m_iView == GLMIAREXVIEW) { QMiarex *pMiarex = (QMiarex *)s_pMiarex; if(pMiarex->m_iView==WSTABVIEW && pMiarex->m_iStabilityView==STAB3DVIEW) { pMainFrame->W3DStabCtxMenu->exec(ScreenPt); } else if (pMiarex->m_iView==W3DVIEW) pMainFrame->W3DCtxMenu->exec(ScreenPt); } else if(m_iView ==GLBODYVIEW) { GL3dBodyDlg *pDlg = (GL3dBodyDlg*)m_pParent; pDlg->ShowContextMenu(event); } else if(m_iView == GLWINGVIEW) { // GL3dWingDlg *pDlg = (GL3dWingDlg*)m_pParent; // pDlg->ShowContextMenu(event); } } /** *Overrides the mousePressEvent method of the base class. *Dispatches the handling to the active child application. */ void ThreeDWidget::mousePressEvent(QMouseEvent *event) { if(m_iView == GLMIAREXVIEW) { QMiarex* pMiarex = (QMiarex*)s_pMiarex; pMiarex->mousePressEvent(event); } else if(m_iView == GLBODYVIEW) { GL3dBodyDlg *pDlg = (GL3dBodyDlg*)m_pParent; pDlg->mousePressEvent(event); } else if(m_iView == GLWINGVIEW) { GL3dWingDlg *pDlg = (GL3dWingDlg*)m_pParent; pDlg->MousePressEvent(event); } } /** *Overrides the mouseReleaseEvent method of the base class. *Dispatches the handling to the active child application. */ void ThreeDWidget::mouseReleaseEvent(QMouseEvent *event) { if(m_iView == GLMIAREXVIEW) { QMiarex* pMiarex = (QMiarex*)s_pMiarex; pMiarex->mouseReleaseEvent(event); } else if(m_iView == GLBODYVIEW) { GL3dBodyDlg *pDlg = (GL3dBodyDlg*)m_pParent; pDlg->mouseReleaseEvent(event); } else if(m_iView == GLWINGVIEW) { GL3dWingDlg *pDlg = (GL3dWingDlg*)m_pParent; pDlg->MouseReleaseEvent(event); } } /** *Overrides the mouseMoveEvent method of the base class. *Dispatches the handling to the active child application. */ void ThreeDWidget::mouseMoveEvent(QMouseEvent *event) { if(m_iView == GLMIAREXVIEW) { QMiarex* pMiarex = (QMiarex*)s_pMiarex; pMiarex->mouseMoveEvent(event); } else if(m_iView == GLBODYVIEW) { GL3dBodyDlg *pDlg = (GL3dBodyDlg*)m_pParent; pDlg->mouseMoveEvent(event); } else if(m_iView == GLWINGVIEW) { GL3dWingDlg *pDlg = (GL3dWingDlg*)m_pParent; pDlg->MouseMoveEvent(event); } } /** *Overrides the mouseDoubleClickEvent method of the base class. *Dispatches the handling to the active child application. */ void ThreeDWidget::mouseDoubleClickEvent ( QMouseEvent * event ) { if(m_iView == GLMIAREXVIEW) { QMiarex* pMiarex = (QMiarex*)s_pMiarex; pMiarex->mouseDoubleClickEvent(event ); } else if(m_iView == GLBODYVIEW) { GL3dBodyDlg *pDlg = (GL3dBodyDlg*)m_pParent; pDlg->mouseDoubleClickEvent(event); } else if(m_iView == GLWINGVIEW) { GL3dWingDlg *pDlg = (GL3dWingDlg*)m_pParent; pDlg->MouseDoubleClickEvent(event); } } /** *Overrides the wheelEvent method of the base class. *Dispatches the handling to the active child application. */ void ThreeDWidget::wheelEvent(QWheelEvent *event) { if(m_iView == GLMIAREXVIEW) { QMiarex* pMiarex = (QMiarex*)s_pMiarex; pMiarex->wheelEvent(event); } else if(m_iView == GLBODYVIEW) { GL3dBodyDlg *pDlg = (GL3dBodyDlg*)m_pParent; pDlg->wheelEvent(event); } else if(m_iView == GLWINGVIEW) { GL3dWingDlg *pDlg = (GL3dWingDlg*)m_pParent; pDlg->WheelEvent(event); } } /*void ThreeDWidget::initializeGL() { glClearColor(.1, 0.0784, 0.1569, 1.0); }*/ /** *Overrides the keyPressEvent method of the base class. *Dispatches the handling to the active child application. */ void ThreeDWidget::keyPressEvent(QKeyEvent *event) { if(m_iView == GLMIAREXVIEW) { QMiarex* pMiarex = (QMiarex*)s_pMiarex; pMiarex->keyPressEvent(event); } else if(m_iView == GLBODYVIEW) { GL3dBodyDlg *pDlg = (GL3dBodyDlg*)m_pParent; pDlg->keyPressEvent(event); } else if(m_iView == GLWINGVIEW) { GL3dWingDlg *pDlg = (GL3dWingDlg*)m_pParent; pDlg->keyPressEvent(event); } } /** *Overrides the keyReleaseEvent method of the base class. *Dispatches the handling to the active child application. */ void ThreeDWidget::keyReleaseEvent(QKeyEvent *event) { if(m_iView ==GLMIAREXVIEW) { QMiarex* pMiarex = (QMiarex*)s_pMiarex; pMiarex->keyReleaseEvent(event); } else if(m_iView == GLBODYVIEW) { GL3dBodyDlg *pDlg = (GL3dBodyDlg*)m_pParent; pDlg->keyReleaseEvent(event); } else if(m_iView == GLWINGVIEW) { GL3dWingDlg *pDlg = (GL3dWingDlg*)m_pParent; pDlg->keyReleaseEvent(event); } } /** *Overrides the paintGL method of the base class. *Dispatches the handling to the active child application. */ void ThreeDWidget::paintGL() { glColor3d(MainFrame::s_TextColor.redF(),MainFrame::s_TextColor.greenF(),MainFrame::s_TextColor.blueF()); if(m_iView==GLMIAREXVIEW) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); QMiarex* pMiarex = (QMiarex*)s_pMiarex; pMiarex->GLDraw3D(); if(pMiarex->m_iView==W3DVIEW) pMiarex->GLRenderView(); else if(pMiarex->m_iView==WSTABVIEW) { pMiarex->GLRenderView(); } } else if(m_iView == GLBODYVIEW) { GL3dBodyDlg *pDlg = (GL3dBodyDlg*)m_pParent; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); pDlg->GLDraw3D(); pDlg->GLRenderBody(); } else if(m_iView == GLWINGVIEW) { GL3dWingDlg *pDlg = (GL3dWingDlg*)m_pParent; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); pDlg->GLDraw3D(); pDlg->GLRenderView(); } } /** *Overrides the resizeGL method of the base class. * Sets the GL viewport to fit in the client area. * Sets the scaling factors for the objects to be drawn in the viewport. *@param width the width in pixels of the client area *@param height the height in pixels of the client area */ void ThreeDWidget::resizeGL(int width, int height) { double w, h; m_rCltRect = geometry(); int side = qMax(width, height); w = (double)width; h = (double)height; #ifdef Q_WS_MAC glViewport(0,0, width, height); #else glViewport((width - side) / 2, (height - side) / 2, side, side); #endif // d = qMax(w,h); // glViewport(0,0, d, d); glMatrixMode(GL_PROJECTION); glLoadIdentity(); double s = 1.0; #ifdef Q_WS_MAC glOrtho(-s,s,-(h*s)/w,(h*s)/w,-100.0*s,100.0*s); #else glOrtho(-s,s,-s,s,-100.0*s,100.0*s); #endif // glFrustum(-1.0, +1.0, -1.0, 1.0, 5.0, 60.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if(w>h) m_GLViewRect.SetRect(-s, s*h/w, s, -s*h/w); else m_GLViewRect.SetRect(-s*w/h, s, s*w/h, -s*h/w); if(m_iView == GLMIAREXVIEW) { QMiarex* pMiarex = (QMiarex*)s_pMiarex; pMiarex->m_ArcBall.GetMatrix(); // pMiarex->SetScale(m_rCltRect); pMiarex->m_bIs3DScaleSet = false; pMiarex->Set3DScale(); } else if(m_iView == GLWINGVIEW) { // GL3dWingDlg *pDlg = (GL3dWingDlg*)m_pParent; // pDlg->m_3DWingRect = m_rCltRect; } else if(m_iView == GLBODYVIEW) { GL3dBodyDlg *pDlg = (GL3dBodyDlg*)m_pParent; pDlg->m_bIs3DScaleSet = false; pDlg->SetRectangles(); pDlg->SetBodyScale(); pDlg->SetBodyLineScale(); pDlg->SetFrameScale(); } } /** *Creates the OpenGL List for the ArcBall. *@param ArcBall the ArcBall object associated to the view *@param GLScale the overall scaling factor for the view @deprecated and unused */ void ThreeDWidget::CreateArcballList(ArcBall &ArcBall, double GLScale) { int row, col, NumAngles, NumCircles; double R, lat_incr, lon_incr, phi, theta; ArcBall.GetMatrix(); CVector eye(0.0,0.0,1.0); CVector up(0.0,1.0,0.0); ArcBall.SetZoom(0.45,eye,up); glNewList(ARCBALL,GL_COMPILE); { glColor3d(0.3,0.3,.5); glLineWidth(1.0); R = ArcBall.ab_sphere; NumAngles = 50; NumCircles = 6; lat_incr = 90.0 / NumAngles; lon_incr = 360.0 / NumCircles; for (col = 0; col < NumCircles; col++) { glBegin(GL_LINE_STRIP); { phi = (col * lon_incr) * PI/180.0; for (row = 1; row < NumAngles-1; row++) { theta = (row * lat_incr) * PI/180.0; glVertex3d(R*cos(phi)*cos(theta)*GLScale, R*sin(theta)*GLScale, R*sin(phi)*cos(theta)*GLScale); } } glEnd(); glBegin(GL_LINE_STRIP); { phi = (col * lon_incr ) * PI/180.0; for (row = 1; row < NumAngles-1; row++) { theta = -(row * lat_incr) * PI/180.0; glVertex3d(R*cos(phi)*cos(theta)*GLScale, R*sin(theta)*GLScale, R*sin(phi)*cos(theta)*GLScale); } } glEnd(); } glBegin(GL_LINE_STRIP); { theta = 0.; for(col=1; col<35; col++) { phi = (0.0 + (double)col*360.0/72.0) * PI/180.0; glVertex3d(R * cos(phi) * cos(theta)*GLScale, R * sin(theta)*GLScale, R * sin(phi) * cos(theta)*GLScale); } } glEnd(); glBegin(GL_LINE_STRIP); { theta = 0.; for(col=1; col<35; col++) { phi = (0.0 + (double)col*360.0/72.0) * PI/180.0; glVertex3d(R * cos(-phi) * cos(theta)*GLScale, R * sin(theta)*GLScale, R * sin(-phi) * cos(theta)*GLScale); } } glEnd(); } glEndList(); glNewList(ARCPOINT,GL_COMPILE); { glColor3d(0.3,0.1,.2); glLineWidth(2.0); NumAngles = 10; lat_incr = 30.0 / NumAngles; lon_incr = 30.0 / NumAngles; glBegin(GL_LINE_STRIP); { phi = 0.0;//longitude for (row = -NumAngles; row < NumAngles; row++) { theta = (row * lat_incr) * PI/180.0; glVertex3d(R*cos(phi)*cos(theta)*GLScale, R*sin(theta)*GLScale, R*sin(phi)*cos(theta)*GLScale); } } glEnd(); glBegin(GL_LINE_STRIP); { theta = 0.; for(col=-NumAngles; col0) { glPushMatrix(); glScaled(radius, radius, radius); glCallList(GLLISTSPHERE); glScaled(1./radius, 1./radius, 1./radius); glPopMatrix(); } } /** * Calculates two vectors, using the middle point as the common origin */ void ThreeDWidget::NormalVector(GLdouble p1[3], GLdouble p2[3], GLdouble p3[3], GLdouble n[3]) { GLdouble v1[3], v2[3], d; v1[0] = p3[0] - p1[0]; v1[1] = p3[1] - p1[1]; v1[2] = p3[2] - p1[2]; v2[0] = p3[0] - p2[0]; v2[1] = p3[1] - p2[1]; v2[2] = p3[2] - p2[2]; // calculate the cross product of the two vectors n[0] = v1[1] * v2[2] - v2[1] * v1[2]; n[1] = v1[2] * v2[0] - v2[2] * v1[0]; n[2] = v1[0] * v2[1] - v2[0] * v1[1]; // normalize the vector d = ( n[0] * n[0] + n[1] * n[1] + n[2] * n[2] ); // try to catch very small vectors if (d < (GLdouble)0.00000001) { d = (GLdouble)100000000.0; } else { d = (GLdouble)1.0 / sqrt(d); } n[0] *= d; n[1] *= d; n[2] *= d; } /** *Initializes the light parameters of the GL Viewport *@param pglLightParams a pointer to the instance of the GLLightDlg which holds the user-defined settings for the light. *@param Offset_y *@param LightFactor a global factor for all light intensities. */ void ThreeDWidget::GLSetupLight(double Offset_y, double LightFactor) { glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); // the ambient light glDisable(GL_LIGHT1); glDisable(GL_LIGHT2); glDisable(GL_LIGHT3); glDisable(GL_LIGHT4); glDisable(GL_LIGHT5); glDisable(GL_LIGHT6); glDisable(GL_LIGHT7); float fLightAmbient0[4]; float fLightDiffuse0[4]; float fLightSpecular0[4]; float fLightPosition0[4]; if(LightFactor>1.0) LightFactor = 1.0f; // the ambient light conditions. fLightAmbient0[0] = LightFactor*GLLightDlg::s_Ambient * GLLightDlg::s_Red; // red component fLightAmbient0[1] = LightFactor*GLLightDlg::s_Ambient * GLLightDlg::s_Green; // green component fLightAmbient0[2] = LightFactor*GLLightDlg::s_Ambient * GLLightDlg::s_Blue; // blue component fLightAmbient0[3] = 1.0; // alpha fLightDiffuse0[0] = LightFactor*GLLightDlg::s_Diffuse * GLLightDlg::s_Red; // red component fLightDiffuse0[1] = LightFactor*GLLightDlg::s_Diffuse * GLLightDlg::s_Green; // green component fLightDiffuse0[2] = LightFactor*GLLightDlg::s_Diffuse * GLLightDlg::s_Blue; // blue component fLightDiffuse0[3] = 1.0; // alpha fLightSpecular0[0] = LightFactor*GLLightDlg::s_Specular * GLLightDlg::s_Red; // red component fLightSpecular0[1] = LightFactor*GLLightDlg::s_Specular * GLLightDlg::s_Green; // green component fLightSpecular0[2] = LightFactor*GLLightDlg::s_Specular * GLLightDlg::s_Blue; // blue component fLightSpecular0[3] = 1.0; // alpha // And finally, its position fLightPosition0[0] = (GLfloat)((GLLightDlg::s_XLight)); fLightPosition0[1] = (GLfloat)((GLLightDlg::s_YLight + Offset_y)); fLightPosition0[2] = (GLfloat)((GLLightDlg::s_ZLight)); fLightPosition0[3] = 1.0; // W (positional light) // Enable the basic light glLightfv(GL_LIGHT0, GL_AMBIENT, fLightAmbient0); glLightfv(GL_LIGHT0, GL_DIFFUSE, fLightDiffuse0); glLightfv(GL_LIGHT0, GL_SPECULAR, fLightSpecular0); glLightfv(GL_LIGHT0, GL_POSITION, fLightPosition0); float fMatAmbient[4] = {GLLightDlg::s_MatAmbient, GLLightDlg::s_MatAmbient, GLLightDlg::s_MatAmbient, 1.0f}; float fMatSpecular[4] = {GLLightDlg::s_MatSpecular, GLLightDlg::s_MatSpecular, GLLightDlg::s_MatSpecular, 1.0f}; float fMatDiffuse[4] = {GLLightDlg::s_MatDiffuse, GLLightDlg::s_MatDiffuse, GLLightDlg::s_MatDiffuse, 1.0f}; float fMatEmission[4] = {GLLightDlg::s_MatEmission, GLLightDlg::s_MatEmission, GLLightDlg::s_MatEmission, 1.0f}; if(GLLightDlg::s_bColorMaterial) { glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // glColorMaterial(GL_FRONT, GL_AMBIENT); // glColorMaterial(GL_FRONT, GL_DIFFUSE); // glColorMaterial(GL_FRONT, GL_SPECULAR); } else { glDisable(GL_COLOR_MATERIAL); } glMaterialfv(GL_FRONT, GL_SPECULAR, fMatSpecular); glMaterialfv(GL_FRONT, GL_AMBIENT, fMatAmbient); glMaterialfv(GL_FRONT, GL_DIFFUSE, fMatDiffuse); glMaterialfv(GL_FRONT, GL_EMISSION, fMatEmission); glMateriali( GL_FRONT, GL_SHININESS, GLLightDlg::s_iMatShininess); if(GLLightDlg::s_bDepthTest) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); if(GLLightDlg::s_bCullFaces) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); if(GLLightDlg::s_bSmooth) glEnable(GL_POLYGON_SMOOTH); else glDisable(GL_POLYGON_SMOOTH); if(GLLightDlg::s_bShade) glShadeModel(GL_SMOOTH); else glShadeModel(GL_FLAT); if(GLLightDlg::s_bLocalView) glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER ,0); else glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER ,1); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0); } /** *Converts Client coordinates to OpenGL Viewport coordinates. *@param point the client coordinates. *@param real the viewport coordinates. */ void ThreeDWidget::ClientToGL(QPoint const &point, CVector &real) { // // In input, takes the 2D point in screen client area coordinates // In output, returns the 2D OpenGL point // static double h2, w2; h2 = (double)geometry().height() /2.0; w2 = (double)geometry().width() /2.0; if(w2>h2) { real.x = ((double)point.x() - w2) / w2; real.y = -((double)point.y() - h2) / w2; } else { real.x = ((double)point.x() - w2) / h2; real.y = -((double)point.y() - h2) / h2; } } /** *Converts OpenGL Viewport coordinates to client coordinates *@param real the viewport coordinates. *@param point the client coordinates. */ void ThreeDWidget::GLToClient(CVector const &real, QPoint &point) { // //converts an opengl 2D vector to screen client coordinates // static double dx, dy, h2, w2; h2 = m_GLViewRect.height() /2.0; w2 = m_GLViewRect.width() /2.0; dx = ( real.x + w2)/2.0; dy = (-real.y + h2)/2.0; if(w2>h2) { point.setX((int)(dx * (double)geometry().width())); point.setY((int)(dy * (double)geometry().width())); } else { point.setX((int)(dx * (double)geometry().height())); point.setY((int)(dy * (double)geometry().height())); } } /** *Converts OpenGL Viewport coordinates to client coordinates *@param x the viewport x-coordinate. *@param y the viewport y-coordinate. *@param point the client coordinates. */ void ThreeDWidget::GLToClient(double const &x, double const &y, QPoint &point) { // //converts an opengl 2D vector to screen client coordinates // static double dx, dy, h2, w2; h2 = m_GLViewRect.height() /2.0; w2 = m_GLViewRect.width() /2.0; dx = ( x + w2)/2.0; dy = (-y + h2)/2.0; if(w2>h2) { point.setX((int)(dx * (double)geometry().width())); point.setY((int)(dy * (double)geometry().width())); } else { point.setX((int)(dx * (double)geometry().height())); point.setY((int)(dy * (double)geometry().height())); } } xflr5-6.09-06/src/XFLR5Application.cpp000644 001750 000144 00000007052 12247174406 020620 0ustar00techwinderusers000000 000000 /**************************************************************************** XFLR5Application Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com Francesco Meschia francesco.meschia@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include "XFLR5Application.h" #include "mainframe.h" XFLR5Application::XFLR5Application(int &argc, char** argv) : QApplication(argc, argv) { QPixmap pixmap; pixmap.load(":/images/splash.png"); QSplashScreen splash(pixmap); splash.setWindowFlags(Qt::SplashScreen); splash.show(); QString StyleName; QString LanguagePath =""; QString str; int a,b,c,d,k; a=150; b=50; c=800; d=700; #ifdef Q_WS_MAC QSettings settings(QSettings::NativeFormat,QSettings::UserScope,"sourceforge.net","xflr5"); #else QSettings settings(QSettings::IniFormat,QSettings::UserScope,"XFLR5"); #endif qsrand(QDateTime::currentDateTime().toTime_t()); bool bMaximized = true; bool bOK; settings.beginGroup("MainFrame"); { k = settings.value("FrameGeometryx").toInt(&bOK); if(bOK) a = k; k = settings.value("FrameGeometryy").toInt(&bOK); if(bOK) b = k; k = settings.value("SizeWidth").toInt(&bOK); if(bOK) c = k; k = settings.value("SizeHeight").toInt(&bOK); if(bOK) d = k; bMaximized = settings.value("SizeMaximized").toBool(); str = settings.value("LanguageFilePath").toString(); if(str.length()) LanguagePath = str; str = settings.value("StyleName").toString(); if(str.length()) StyleName = str; } settings.endGroup(); QTranslator xflr5Translator; if(LanguagePath.length()) { if(xflr5Translator.load(LanguagePath)) installTranslator(&xflr5Translator); } QPoint pt(a,b); QSize sz(c,d); if(StyleName.length()) qApp->setStyle(StyleName); MainFrame *w = MainFrame::self(); if(bMaximized) MainFrame::self()->showMaximized(); else { MainFrame::self()->resize(sz); MainFrame::self()->move(pt); MainFrame::self()->show(); } #ifndef Q_WS_MAC QString PathName, Extension; PathName=argv[1]; Extension = PathName.right(4); if(Extension.compare(".wpa",Qt::CaseInsensitive)==0 || Extension.compare(".plr",Qt::CaseInsensitive)==0) { int iApp = w->LoadXFLR5File(PathName); if (iApp == MIAREX) w->OnMiarex(); else if (iApp == XFOILANALYSIS) w->OnXDirect(); } #endif splash.finish(w); } bool XFLR5Application::event(QEvent *event) { int iApp; switch (event->type()) { case QEvent::FileOpen: { iApp = MainFrame::self()->LoadXFLR5File(static_cast(event)->file()); if (iApp == MIAREX) MainFrame::self()->OnMiarex(); else if (iApp == XFOILANALYSIS) MainFrame::self()->OnXDirect(); return true; } default: return QApplication::event(event); } } xflr5-6.09-06/src/twodwidget.cpp000644 001750 000144 00000024603 12250545544 017755 0ustar00techwinderusers000000 000000 /**************************************************************************** TwoDWidget Class Copyright (C) 2009-2012 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include "mainframe.h" #include "graph/QGraph.h" #include "graph/Curve.h" #include "miarex/Miarex.h" #include "xdirect/XDirect.h" #include "design/AFoil.h" #include "xinverse/XInverse.h" #include "twodwidget.h" /** *The public constructor */ TwoDWidget::TwoDWidget(QWidget *parent) : QWidget(parent) { m_pMainFrame = NULL; m_pXDirect = NULL; m_pMiarex = NULL; m_pAFoil = NULL; setMouseTracking(true); setCursor(Qt::CrossCursor); } /** *Overrides the keyPressEvent method of the base class. *Dispatches the handling to the active child application. */ void TwoDWidget::keyPressEvent(QKeyEvent *event) { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; if(pMainFrame->m_iApp == XFOILANALYSIS && m_pXDirect) { QXDirect* pXDirect = (QXDirect*)m_pXDirect; pXDirect->keyPressEvent(event); } else if(pMainFrame->m_iApp == MIAREX && m_pMiarex) { QMiarex* pMiarex = (QMiarex*)m_pMiarex; pMiarex->keyPressEvent(event); } else if(pMainFrame->m_iApp == DIRECTDESIGN && m_pAFoil) { QAFoil *pAFoil= (QAFoil*)m_pAFoil; pAFoil->keyPressEvent(event); } else if(pMainFrame->m_iApp == INVERSEDESIGN && m_pXInverse) { QXInverse *pXInverse= (QXInverse*)m_pXInverse; pXInverse->keyPressEvent(event); } } /** *Overrides the keyReleaseEvent method of the base class. *Dispatches the handling to the active child application. */ void TwoDWidget::keyReleaseEvent(QKeyEvent *event) { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; if(pMainFrame->m_iApp == XFOILANALYSIS && m_pXDirect) { QXDirect* pXDirect = (QXDirect*)m_pXDirect; pXDirect->keyReleaseEvent(event); } else if(pMainFrame->m_iApp == MIAREX && m_pMiarex) { QMiarex* pMiarex = (QMiarex*)m_pMiarex; pMiarex->keyReleaseEvent(event); } else if(pMainFrame->m_iApp == DIRECTDESIGN && m_pAFoil) { QAFoil *pAFoil= (QAFoil*)m_pAFoil; pAFoil->keyReleaseEvent(event); } else if(pMainFrame->m_iApp == INVERSEDESIGN && m_pXInverse) { QXInverse *pXInverse= (QXInverse*)m_pXInverse; pXInverse->keyReleaseEvent(event); } } /** *Overrides the mousePressEvent method of the base class. *Dispatches the handling to the active child application. */ void TwoDWidget::mousePressEvent(QMouseEvent *event) { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; if(pMainFrame->m_iApp == XFOILANALYSIS && m_pXDirect) { QXDirect* pXDirect = (QXDirect*)m_pXDirect; pXDirect->mousePressEvent(event); } else if(pMainFrame->m_iApp == MIAREX && m_pMiarex) { QMiarex* pMiarex = (QMiarex*)m_pMiarex; pMiarex->mousePressEvent(event); } else if(pMainFrame->m_iApp == DIRECTDESIGN && m_pAFoil) { QAFoil *pAFoil= (QAFoil*)m_pAFoil; pAFoil->mousePressEvent(event); } else if(pMainFrame->m_iApp == INVERSEDESIGN && m_pXInverse) { QXInverse *pXInverse= (QXInverse*)m_pXInverse; pXInverse->mousePressEvent(event); } } /** *Overrides the mouseReleaseEvent method of the base class. *Dispatches the handling to the active child application. */ void TwoDWidget::mouseReleaseEvent(QMouseEvent *event) { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; if(pMainFrame->m_iApp == XFOILANALYSIS && m_pXDirect) { QXDirect* pXDirect = (QXDirect*)m_pXDirect; pXDirect->mouseReleaseEvent(event); } else if(pMainFrame->m_iApp == MIAREX && m_pMiarex) { QMiarex* pMiarex = (QMiarex*)m_pMiarex; pMiarex->mouseReleaseEvent(event); } else if(pMainFrame->m_iApp == DIRECTDESIGN && m_pAFoil) { QAFoil *pAFoil= (QAFoil*)m_pAFoil; pAFoil->mouseReleaseEvent(event); } else if(pMainFrame->m_iApp == INVERSEDESIGN && m_pXInverse) { QXInverse *pXInverse= (QXInverse*)m_pXInverse; pXInverse->mouseReleaseEvent(event); } } /** *Overrides the mouseMoveEvent method of the base class. *Dispatches the handling to the active child application. */ void TwoDWidget::mouseMoveEvent(QMouseEvent *event) { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; if(pMainFrame->m_iApp == XFOILANALYSIS && m_pXDirect) { QXDirect* pXDirect = (QXDirect*)m_pXDirect; pXDirect->mouseMoveEvent(event); } else if(pMainFrame->m_iApp == MIAREX && m_pMiarex) { QMiarex* pMiarex = (QMiarex*)m_pMiarex; pMiarex->mouseMoveEvent(event); } else if(pMainFrame->m_iApp == DIRECTDESIGN && m_pAFoil) { QAFoil *pAFoil= (QAFoil*)m_pAFoil; pAFoil->mouseMoveEvent(event); } else if(pMainFrame->m_iApp == INVERSEDESIGN && m_pXInverse) { QXInverse *pXInverse= (QXInverse*)m_pXInverse; pXInverse->mouseMoveEvent(event); } } /** *Overrides the mouseDoubleClickEvent function of the base class. *Dispatches the handling to the active child application. */ void TwoDWidget::mouseDoubleClickEvent ( QMouseEvent * event ) { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; if(pMainFrame->m_iApp == XFOILANALYSIS && m_pXDirect) { QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->mouseDoubleClickEvent(event ); } else if(pMainFrame->m_iApp == DIRECTDESIGN && m_pAFoil) { QAFoil *pAFoil= (QAFoil*)m_pAFoil; pAFoil->mouseDoubleClickEvent(event); } else if(pMainFrame->m_iApp == MIAREX && m_pMiarex) { QMiarex* pMiarex = (QMiarex*)m_pMiarex; pMiarex->mouseDoubleClickEvent(event ); } else if(pMainFrame->m_iApp == DIRECTDESIGN && m_pAFoil) { // QAFoil *pAFoil= (QAFoil*)m_pAFoil; // pAFoil->SetScale(rect()); } else if(pMainFrame->m_iApp == INVERSEDESIGN && m_pXInverse) { QXInverse *pXInverse= (QXInverse*)m_pXInverse; pXInverse->mouseDoubleClickEvent(event ); } } /** *Overrides the resizeEvent function of the base class. *Dispatches the handling to the active child application. */ void TwoDWidget::resizeEvent(QResizeEvent *event) { // MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; QXDirect *pXDirect = (QXDirect*)m_pXDirect; QMiarex *pMiarex = (QMiarex*)m_pMiarex; QAFoil *pAFoil = (QAFoil*)m_pAFoil; QXInverse *pXInverse = (QXInverse*)m_pXInverse; // m_rCltRect = rect(); if(m_pXDirect) { pXDirect->SetFoilScale(rect()); pXDirect->SetPolarLegendPos(); } if(m_pMiarex) { pMiarex->m_bIs2DScaleSet = false; pMiarex->Set2DScale(); if(pMiarex->m_iView==WOPPVIEW) pMiarex->SetWingLegendPos(); if(pMiarex->m_iView==WPOLARVIEW) pMiarex->SetWPlrLegendPos(); } if(m_pAFoil) { pAFoil->SetScale(rect()); } if(m_pXInverse) { pXInverse->SetScale(rect()); } } /** *Overrides the wheelEvent function of the base class. *Dispatches the handling to the active child application. */ void TwoDWidget::wheelEvent(QWheelEvent *event) { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; if(pMainFrame->m_iApp == XFOILANALYSIS && m_pXDirect) { QXDirect* pXDirect = (QXDirect*)m_pXDirect; pXDirect->wheelEvent(event); } else if(pMainFrame->m_iApp == MIAREX && m_pMiarex) { QMiarex* pMiarex = (QMiarex*)m_pMiarex; pMiarex->wheelEvent(event); } else if(pMainFrame->m_iApp == DIRECTDESIGN && m_pAFoil) { QAFoil *pAFoil= (QAFoil*)m_pAFoil; pAFoil->wheelEvent(event); } else if(pMainFrame->m_iApp == INVERSEDESIGN && m_pXInverse) { QXInverse *pXInverse= (QXInverse*)m_pXInverse; pXInverse->wheelEvent(event); } } /** *Overrides the paintEvent function of the base class. *Dispatches the handling to the active child application. */ void TwoDWidget::paintEvent(QPaintEvent *event) { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; if(pMainFrame->m_iApp == XFOILANALYSIS && m_pXDirect) { QXDirect* pXDirect = (QXDirect*)m_pXDirect; QPainter painter(this); pXDirect->PaintView(painter); } else if(pMainFrame->m_iApp == MIAREX && m_pMiarex) { QMiarex* pMiarex = (QMiarex*)m_pMiarex; QPainter painter(this); pMiarex->PaintView(painter); } else if(pMainFrame->m_iApp == DIRECTDESIGN && m_pAFoil) { QAFoil *pAFoil= (QAFoil*)m_pAFoil; QPainter painter(this); pAFoil->PaintView(painter); } else if(pMainFrame->m_iApp == INVERSEDESIGN && m_pXInverse) { QXInverse *pXInverse= (QXInverse*)m_pXInverse; QPainter painter(this); pXInverse->PaintView(painter); } else { QPainter painter(this); painter.fillRect(rect(), MainFrame::s_BackgroundColor); } } /** *Overrides the contextMenuEvent function of the base class. *Dispatches the handling to the active child application. */ void TwoDWidget::contextMenuEvent (QContextMenuEvent * event) { MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; QPoint ScreenPt = event->globalPos(); QPoint CltPt = event->pos(); switch(pMainFrame->m_iApp) { case MIAREX: { QMiarex *pMiarex = (QMiarex*)m_pMiarex; if(event->reason()==QContextMenuEvent::Keyboard) { ScreenPt.rx() = pMiarex->m_LastPoint.x()+pMainFrame->pos().x()+geometry().x(); ScreenPt.ry() = pMiarex->m_LastPoint.y()+pMainFrame->pos().y()+geometry().y(); } pMiarex->m_pCurGraph = pMiarex->GetGraph(CltPt); if(pMiarex->m_iView==WOPPVIEW) pMainFrame->WOppCtxMenu->exec(ScreenPt); else if (pMiarex->m_iView==WPOLARVIEW) pMainFrame->WPlrCtxMenu->exec(ScreenPt); else if (pMiarex->m_iView==WCPVIEW) pMainFrame->WCpCtxMenu->exec(ScreenPt); else if(pMiarex->m_iView==WSTABVIEW) { if(pMiarex->m_iStabilityView==STABTIMEVIEW) pMainFrame->WTimeCtxMenu->exec(ScreenPt); else if(pMiarex->m_iStabilityView==STABPOLARVIEW) pMainFrame->WPlrCtxMenu->exec(ScreenPt); } break; } case XFOILANALYSIS: { QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->m_pCurGraph = pXDirect->GetGraph(CltPt); if(pXDirect->m_bPolarView) pMainFrame->OperPolarCtxMenu->exec(ScreenPt); else pMainFrame->OperFoilCtxMenu->exec(ScreenPt); break; } case DIRECTDESIGN: { pMainFrame->AFoilCtxMenu->exec(ScreenPt); break; } case INVERSEDESIGN: { pMainFrame->InverseContextMenu->exec(ScreenPt); break; } default: break; } } xflr5-6.09-06/src/mainframe.cpp000644 001750 000144 00000623732 12250656031 017535 0ustar00techwinderusers000000 000000 /**************************************************************************** MainFrame Class Copyright (C) 2008-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "mainframe.h" #include "globals.h" #include "design/AFoil.h" #include "miarex/Miarex.h" #include "miarex/InertiaDlg.h" #include "miarex/BodyTransDlg.h" #include "miarex/GL3dWingDlg.h" #include "miarex/GL3dBodyDlg.h" #include "miarex/GL3DScales.h" #include "miarex/StabViewDlg.h" #include "miarex/WPolarDlg.h" #include "miarex/StabPolarDlg.h" #include "miarex/PlaneDlg.h" #include "miarex/StabViewDlg.h" #include "miarex/ManageUFOsDlg.h" #include "miarex/UFOTableDelegate.h" #include "miarex/NURBSDomDoc.h" #include "misc/AboutQ5.h" #include "misc/ObjectPropsDlg.h" #include "misc/LinePickerDlg.h" #include "misc/DisplaySettingsDlg.h" #include "misc/SaveOptionsDlg.h" #include "misc/TranslatorDlg.h" #include "misc/RenameDlg.h" #include "misc/UnitsDlg.h" #include "misc/W3dPrefsDlg.h" #include "graph/GraphDlg.h" #include "xdirect/XDirect.h" #include "xdirect/BatchDlg.h" #include "xdirect/BatchThreadDlg.h" #include "xdirect/NacaFoilDlg.h" #include "xdirect/InterpolateFoilsDlg.h" #include "xdirect/CAddDlg.h" #include "xdirect/TwoDPanelDlg.h" #include "xdirect/FoilCoordDlg.h" #include "xdirect/FoilGeomDlg.h" #include "xdirect/TEGapDlg.h" #include "xdirect/LEDlg.h" #include "xdirect/XFoilAnalysisDlg.h" #include "xdirect/FoilPolarDlg.h" #include "xinverse/XInverse.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_WS_MAC #include #endif QPointer MainFrame::_self = 0L; QString MainFrame::s_VersionName = QString::fromLatin1("XFLR5 v6.09.06"); QString MainFrame::s_ProjectName = ""; QString MainFrame::s_LastDirName = ""; QString MainFrame::s_LanguageFilePath = ""; QDir MainFrame::s_StylesheetDir; QDir MainFrame::s_TranslationDir; Foil * MainFrame::s_pCurFoil=NULL; QFont MainFrame::s_TextFont; QColor MainFrame::s_TextColor = QColor(220,220,220); QColor MainFrame::s_BackgroundColor = QColor(0, 5, 10); bool MainFrame::s_bAlphaChannel = true; bool MainFrame::s_bReverseZoom = false; bool MainFrame::s_bTrace = false; bool MainFrame::s_bSaved = true; QFile *MainFrame::s_pTraceFile = NULL; enumTextFileType MainFrame::s_ExportFileType; /**< Defines if the list separator for the output text files should be a space or a comma. */ double MainFrame::s_mtoUnit = 1.0; double MainFrame::s_mstoUnit = 1.0; double MainFrame::s_m2toUnit = 1.0; double MainFrame::s_kgtoUnit = 1.0; double MainFrame::s_NtoUnit = 1.0; double MainFrame::s_NmtoUnit = 1.0; int MainFrame::s_LengthUnit = 0; int MainFrame::s_AreaUnit = 1; int MainFrame::s_WeightUnit = 1; int MainFrame::s_SpeedUnit = 0; int MainFrame::s_ForceUnit = 0; int MainFrame::s_MomentUnit = 0; QList MainFrame::s_oaFoil; QList MainFrame::s_oaPolar; QList MainFrame::s_oaPlane; QList MainFrame::s_oaWing; QList MainFrame::s_oaBody; QLabel *MainFrame::m_pctrlProjectName = NULL; MainFrame::MainFrame(QWidget * parent, Qt::WindowFlags flags) : QMainWindow(parent, flags) { if(s_bTrace) { QString FileName = QDir::homePath() + "/Trace.log"; s_pTraceFile = new QFile(FileName); if (!s_pTraceFile->open(QIODevice::ReadWrite | QIODevice::Text)) s_bTrace = false; } QString jpegPluginPath; //Jpeg format requires a specific plugin to be loaded dynmically at run time #ifdef Q_WS_MAC // F.Meschia 20101101 -- this is unnecessary, in fact, so I commented it out QDir dir(qApp->applicationDirPath()); dir.cdUp(); jpegPluginPath = dir.canonicalPath() + "/PlugIns/imageformats/libqjpeg.dylib"; #endif #ifdef Q_OS_WIN QDir dir(qApp->applicationDirPath()); jpegPluginPath = dir.canonicalPath() + "/imageformats/qjpeg4.dll"; #endif #ifdef Q_OS_LINUX QDir dir(qApp->applicationDirPath()); jpegPluginPath = dir.canonicalPath() + "/imageformats/libqjpeg.so"; #endif if (dir.exists(jpegPluginPath)) { /* QPluginLoader jpegPluginLoad(jpegPluginPath); jpegPluginLoad.load(); if (!jpegPluginLoad.isLoaded()) { QString errorMessage = jpegPluginLoad.errorString() + " : " +jpegPluginPath; QMessageBox::information(window(), tr("Info"), errorMessage); }*/ } setWindowTitle(s_VersionName); setWindowIcon(QIcon(":/images/xflr5_64.png")); if(!QGLFormat::hasOpenGL()) { QMessageBox::warning(this, tr("Warning"), tr("Your system does not provide support for OpenGL.\nXFLR5 will not operate correctly.")); } UndoAFoilAct = RedoAFoilAct = NULL; CreateDockWindows(); s_TextFont.setStyleHint(QFont::TypeWriter, QFont::OpenGLCompatible); s_TextFont.setFamily(s_TextFont.defaultFamily()); s_TextFont.setPointSize(10); m_RefGraph.SetGraphName("Reference Graph"); m_ImageFormat = PNG; s_ExportFileType = TXT; m_bSaveOpps = false; m_bSaveWOpps = true; m_bSaveSettings = true; m_GraphExportFilter = "Comma Separated Values (*.csv)"; s_LastDirName = QDir::homePath(); QAFoil *pAFoil = (QAFoil*)m_pAFoil; QXDirect *pXDirect = (QXDirect*)m_pXDirect; QXInverse *pXInverse = (QXInverse*)m_pXInverse; QMiarex *pMiarex = (QMiarex*)m_pMiarex; #ifdef Q_WS_MAC QSettings settings(QSettings::NativeFormat,QSettings::UserScope,"sourceforge.net","xflr5"); #else QSettings settings(QSettings::IniFormat,QSettings::UserScope,"XFLR5"); #endif QString str; int kx=117, ky=57; bool bOK; settings.beginGroup("MainFrame"); { str = settings.value("LanguageFilePath").toString(); if(str.length()) s_LanguageFilePath = str; kx = settings.value("FrameGeometryx", 117).toInt(&bOK); ky = settings.value("FrameGeometryy", 57).toInt(&bOK); } settings.endGroup(); XFoilAnalysisDlg::s_Position = QPoint(kx+31, ky+31); BatchThreadDlg::s_Position = QPoint(kx+31, ky+31); BatchDlg::s_Position = QPoint(kx+31, ky+31); LLTAnalysisDlg::s_Position = QPoint(kx+31, ky+31); PanelAnalysisDlg::s_Position = QPoint(kx+31, ky+31); if(s_LanguageFilePath.length()) { qApp->removeTranslator(&m_Translator); if(m_Translator.load(s_LanguageFilePath)) { qApp->installTranslator(&m_Translator); } } if(LoadSettings()) { m_RefGraph.LoadSettings(&settings); pAFoil->LoadSettings(&settings); pXDirect->LoadSettings(&settings); pMiarex->LoadSettings(&settings); pXInverse->LoadSettings(&settings); GL3DScales::LoadSettings(&settings); W3dPrefsDlg::LoadSettings(&settings); } SetupDataDir(); SetUnits(s_LengthUnit, s_AreaUnit, s_SpeedUnit, s_WeightUnit, s_ForceUnit, s_MomentUnit, s_mtoUnit, s_m2toUnit, s_mstoUnit, s_kgtoUnit, s_NtoUnit, s_NmtoUnit); pXDirect->SetAnalysisParams(); CreateActions(); CreateMenus(); CreateToolbars(); CreateStatusBar(); m_ColorList.append(QColor(255,0,0)); m_ColorList.append(QColor(0,255,0)); m_ColorList.append(QColor(0,0,255)); m_ColorList.append(QColor(255,255,0)); m_ColorList.append(QColor(255,0,255)); m_ColorList.append(QColor(0,255,255)); m_ColorList.append(QColor(200,60,60)); m_ColorList.append(QColor(0,160,0)); m_ColorList.append(QColor(100,100,240)); m_ColorList.append(QColor(170,170,0)); m_ColorList.append(QColor(130,0,130)); m_ColorList.append(QColor(0,130,130)); m_ColorList.append(QColor(255,128,128)); m_ColorList.append(QColor(0,255,128)); m_ColorList.append(QColor(64,200,255)); m_ColorList.append(QColor(170,170,100)); m_ColorList.append(QColor(190,100,190)); m_ColorList.append(QColor(100,170,170)); m_ColorList.append(QColor(228,150,70)); m_ColorList.append(QColor(170,255,170)); m_ColorList.append(QColor(120,120,255)); m_ColorList.append(QColor(228,228,128)); m_ColorList.append(QColor(255,170,255)); m_ColorList.append(QColor(170,255,255)); m_ColorList.append(QColor(87,64,30)); m_ColorList.append(QColor(117,81,26)); m_ColorList.append(QColor(143,107,50)); m_ColorList.append(QColor(179,146,93)); m_ColorList.append(QColor(222,188,133)); m_ColorList.append(QColor(0,110,41)); m_ColorList.append(QColor(55,164,44)); m_ColorList.append(QColor(177,210,143)); m_ColorList.append(QColor(0,167,169)); m_ColorList.append(QColor(0,96,102)); m_ColorList.append(QColor(50,50,50)); m_ColorList.append(QColor(90,90,90)); m_ColorList.append(QColor(130,130,130)); m_ColorList.append(QColor(170,170,170)); m_ColorList.append(QColor(210,210,210)); m_ColorList.append(QColor(255,255,255)); s_bSaved = true; m_bHighlightOpp = m_bHighlightWOpp = false; m_iApp = NOAPP; m_pctrlAFoilToolBar->hide(); m_pctrlXDirectToolBar->hide(); m_pctrlXInverseToolBar->hide(); m_pctrlMiarexToolBar->hide(); m_pctrlStabViewWidget->hide(); SetMenus(); QString styleSheet; if(DisplaySettingsDlg::s_bStyleSheets) { ReadStyleSheet(DisplaySettingsDlg::s_StyleSheetName, styleSheet); } } MainFrame::~MainFrame() { if(s_pTraceFile) s_pTraceFile->close(); for(int ioa=s_oaFoil.size()-1; ioa>=0; ioa--) { delete (Foil*)s_oaFoil.at(ioa); s_oaFoil.removeAt(ioa); } for(int ioa=s_oaPolar.size()-1; ioa>=0; ioa--) { delete (Polar*)s_oaPolar.at(ioa); s_oaPolar.removeAt(ioa); } for(int ioa=m_oaOpp.size()-1; ioa>=0; ioa--) { delete (OpPoint*)m_oaOpp.at(ioa); m_oaOpp.removeAt(ioa); } for(int ioa=s_oaPlane.size()-1; ioa>=0; ioa--) { delete (Plane*)s_oaPlane.at(ioa); s_oaPlane.removeAt(ioa); } for(int ioa=s_oaWing.size()-1; ioa>=0; ioa--) { delete (Wing*)s_oaWing.at(ioa); s_oaWing.removeAt(ioa); } for(int ioa=m_oaWPolar.size()-1; ioa>=0; ioa--) { delete (WPolar*)m_oaWPolar.at(ioa); m_oaWPolar.removeAt(ioa); } for(int ioa=m_oaWOpp.size()-1; ioa>=0; ioa--) { delete (WingOpp*)m_oaWOpp.at(ioa); m_oaWOpp.removeAt(ioa); } for(int ioa=m_oaPOpp.size()-1; ioa>=0; ioa--) { delete (PlaneOpp*)m_oaPOpp.at(ioa); m_oaPOpp.removeAt(ioa); } for(int ioa=s_oaBody.size()-1; ioa>=0; ioa--) { delete (Body*)s_oaBody.at(ioa); s_oaBody.removeAt(ioa); } } void MainFrame::AboutQt() { #ifndef QT_NO_MESSAGEBOX QMessageBox::aboutQt( #ifdef Q_WS_MAC this #else // activeWindow() this #endif // Q_WS_MAC ); #endif // QT_NO_MESSAGEBOX } void MainFrame::AboutQFLR5() { AboutQ5 dlg(this); dlg.exec(); } void MainFrame::AddFoil(Foil *pFoil) { Foil *pOldFoil = foil(pFoil->m_FoilName); if(pOldFoil) { DeleteFoil(pOldFoil, false); } bool IsInserted = false; for (int i=0; im_FoilName < pOldFoil->m_FoilName) { s_oaFoil.insert(i, pFoil); IsInserted = true; break; } } if (!IsInserted) s_oaFoil.append(pFoil); pFoil->InitFoil(); s_pCurFoil = pFoil; } Polar* MainFrame::AddPolar(Polar *pPolar) { if(!pPolar) return NULL; bool bExists = false; bool bInserted = false; bool bFound; Polar *pOldPlr; Polar *pOld2Plr; QString strong; int i,j,k,l,p; for (i=0; im_PlrName == pPolar->m_PlrName && pOldPlr->m_FoilName == pPolar->m_FoilName) bExists = true; } while(!bInserted) { if(!bExists) { for (j=0; jm_FoilName.compare(pOldPlr->m_FoilName, Qt::CaseInsensitive)<0) { s_oaPolar.insert(j, pPolar); bInserted = true; break; } else if (pPolar->m_FoilName == pOldPlr->m_FoilName) { if(pPolar->m_PolarType < pOldPlr->m_PolarType) { s_oaPolar.insert(j, pPolar); bInserted = true; break; } else if(pPolar->m_PolarType == pOldPlr->m_PolarType) { if (pPolar->m_PolarType != FIXEDAOAPOLAR) { //sort by re Nbr if(pPolar->m_Reynolds < pOldPlr->m_Reynolds) { s_oaPolar.insert(j, pPolar); bInserted = true; break; } } else { //Type 4, sort by Alphas if(pPolar->m_ASpec < pOldPlr->m_ASpec) { s_oaPolar.insert(j, pPolar); bInserted = true; break; } } } } } if(!bInserted) { s_oaPolar.append(pPolar); bInserted = true; } return pPolar; } else { for (l=0; lm_FoilName == pPolar->m_FoilName && pOldPlr->m_PlrName == pPolar->m_PlrName) { p = 2; bFound = true; while(bFound) { strong = QString(" (%1)").arg( p); strong = pPolar->m_PlrName + strong; for (k=0; km_FoilName == pPolar->m_FoilName && pOld2Plr->m_PlrName == strong) { p++; bFound = true; break; } } } pPolar->m_PlrName = strong; } } bExists = false; } } return NULL; } void MainFrame::AddRecentFile(const QString &PathName) { m_RecentFiles.removeAll(PathName); m_RecentFiles.prepend(PathName); while (m_RecentFiles.size() > MAXRECENTFILES) m_RecentFiles.removeLast(); updateRecentFileActions(); } void MainFrame::closeEvent (QCloseEvent * event) { if(!s_bSaved) { int resp = QMessageBox::question(this, tr("Exit"), tr("Save the project before exit ?"), QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes); if(resp == QMessageBox::Yes) { if(!SaveProject(m_FileName)) { event->ignore(); return; } AddRecentFile(m_FileName); } else if (resp==QMessageBox::Cancel) { event->ignore(); return; } } DeleteProject(true); SaveSettings(); event->accept();//continue closing } void MainFrame::contextMenuEvent (QContextMenuEvent * event) { if(m_pctrlCentralWidget->currentIndex()==0) m_p2DWidget->contextMenuEvent(event); else m_pGLWidget->contextMenuEvent(event); } void MainFrame::CreateActions() { newProjectAct = new QAction(QIcon(":/images/new.png"), tr("New Project"), this); newProjectAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_N)); newProjectAct->setStatusTip(tr("Save and close the current project, create a new project")); connect(newProjectAct, SIGNAL(triggered()), this, SLOT(OnNewProject())); closeProjectAct = new QAction(QIcon(":/images/new.png"), tr("Close the Project"), this); closeProjectAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_W)); closeProjectAct->setStatusTip(tr("Save and close the current project")); connect(closeProjectAct, SIGNAL(triggered()), this, SLOT(OnNewProject())); openAct = new QAction(QIcon(":/images/open.png"), tr("&Open..."), this); openAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_O)); openAct->setStatusTip(tr("Open an existing file")); connect(openAct, SIGNAL(triggered()), this, SLOT(OnLoadFile())); insertAct = new QAction(tr("&Insert Project..."), this); insertAct->setStatusTip(tr("Insert an existing project in the current project")); connect(insertAct, SIGNAL(triggered()), this, SLOT(OnInsertProject())); OnAFoilAct = new QAction(tr("&Direct Foil Design"), this); OnAFoilAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_1)); OnAFoilAct->setStatusTip(tr("Open Foil Design application")); connect(OnAFoilAct, SIGNAL(triggered()), this, SLOT(OnAFoil())); OnXInverseAct = new QAction(tr("&XFoil Inverse Design"), this); OnXInverseAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_3)); OnXInverseAct->setStatusTip(tr("Open XFoil inverse analysis application")); connect(OnXInverseAct, SIGNAL(triggered()), this, SLOT(OnXInverse())); OnMixedInverseAct = new QAction(tr("&XFoil Mixed Inverse Design"), this); OnMixedInverseAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_4)); OnMixedInverseAct->setStatusTip(tr("Open XFoil Mixed Inverse analysis application")); connect(OnMixedInverseAct, SIGNAL(triggered()), this, SLOT(OnXInverseMixed())); OnXDirectAct = new QAction(tr("&XFoil Direct Analysis"), this); OnXDirectAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_5)); OnXDirectAct->setStatusTip(tr("Open XFoil direct analysis application")); connect(OnXDirectAct, SIGNAL(triggered()), this, SLOT(OnXDirect())); OnMiarexAct = new QAction(tr("&Wing and Plane Design"), this); OnMiarexAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_6)); OnMiarexAct->setStatusTip(tr("Open Wing/plane design and analysis application")); connect(OnMiarexAct, SIGNAL(triggered()), this, SLOT(OnMiarex())); saveAct = new QAction(QIcon(":/images/save.png"), tr("Save"), this); saveAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S)); saveAct->setStatusTip(tr("Save the project to disk")); connect(saveAct, SIGNAL(triggered()), this, SLOT(OnSaveProject())); saveProjectAsAct = new QAction(tr("Save Project As..."), this); saveProjectAsAct->setStatusTip(tr("Save the current project under a new name")); connect(saveProjectAsAct, SIGNAL(triggered()), this, SLOT(OnSaveProjectAs())); saveOptionsAct = new QAction(tr("Save Options"), this); saveOptionsAct->setStatusTip(tr("Define the save options for operating points")); connect(saveOptionsAct, SIGNAL(triggered()), this, SLOT(OnSaveOptions())); unitsAct = new QAction(tr("Units..."), this); unitsAct->setStatusTip(tr("Define the units for this project")); connect(unitsAct, SIGNAL(triggered()), this, SLOT(OnUnits())); languageAct = new QAction(tr("Language..."), this); languageAct->setStatusTip(tr("Define the default language for the application")); connect(languageAct, SIGNAL(triggered()), this, SLOT(OnLanguage())); restoreToolbarsAct = new QAction(tr("Restore toolbars"), this); restoreToolbarsAct->setStatusTip(tr("Restores the toolbars to their original state")); connect(restoreToolbarsAct, SIGNAL(triggered()), this, SLOT(OnRestoreToolbars())); saveViewToImageFileAct = new QAction(tr("Save View to Image File"), this); saveViewToImageFileAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_I)); saveViewToImageFileAct->setStatusTip(tr("Saves the current view to a file on disk")); connect(saveViewToImageFileAct, SIGNAL(triggered()), this, SLOT(OnSaveViewToImageFile())); resetSettingsAct = new QAction(tr("Reset Default Settings"), this); resetSettingsAct->setStatusTip(tr("will revert to default settings at the next session")); connect(resetSettingsAct, SIGNAL(triggered()), this, SLOT(OnResetSettings())); for (int i = 0; i < MAXRECENTFILES; ++i) { recentFileActs[i] = new QAction(this); recentFileActs[i]->setVisible(false); connect(recentFileActs[i], SIGNAL(triggered()), this, SLOT(openRecentFile())); } styleAct = new QAction(tr("General Display Settings"), this); styleAct->setStatusTip(tr("Define the color and font options for all views and graphs")); connect(styleAct, SIGNAL(triggered()), this, SLOT(OnStyle())); exportCurGraphAct = new QAction(tr("Export Graph"), this); exportCurGraphAct->setStatusTip(tr("Export the current graph data to a text file")); connect(exportCurGraphAct, SIGNAL(triggered()), this, SLOT(OnExportCurGraph())); resetCurGraphScales = new QAction(QIcon(":/images/OnResetGraphScale.png"), tr("Reset Graph Scales")+"\t(R)", this); resetCurGraphScales->setStatusTip(tr("Restores the graph's x and y scales")); connect(resetCurGraphScales, SIGNAL(triggered()), this, SLOT(OnResetCurGraphScales())); exitAct = new QAction(tr("E&xit"), this); exitAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); exitAct->setStatusTip(tr("Exit the application")); connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); guidelinesAct = new QAction(tr("&Guidelines"), this); guidelinesAct->setStatusTip(tr("Show the guidelines for some help")); connect(guidelinesAct, SIGNAL(triggered()), this, SLOT(OnGuidelines())); aboutAct = new QAction(tr("&About"), this); aboutAct->setStatusTip(tr("More information about XFLR5")); connect(aboutAct, SIGNAL(triggered()), this, SLOT(AboutQFLR5())); aboutQtAct = new QAction(tr("About Qt"), this); connect(aboutQtAct, SIGNAL(triggered()), this, SLOT(AboutQt())); ShowPolarProps = new QAction(tr("Properties"), this); ShowPolarProps->setStatusTip(tr("Show the properties of the currently selected polar")); ShowPolarProps->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Return)); connect(ShowPolarProps, SIGNAL(triggered()), this, SLOT(OnPolarProps())); ShowWOppProps = new QAction(tr("Properties"), this); ShowWOppProps->setStatusTip(tr("Show the properties of the currently selected operating point")); ShowWOppProps->setShortcut(QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Return)); connect(ShowWOppProps, SIGNAL(triggered()), this, SLOT(OnWOppProps())); CreateAFoilActions(); CreateXDirectActions(); CreateXInverseActions(); CreateMiarexActions(); } void MainFrame::CreateAFoilActions() { QAFoil *pAFoil = (QAFoil*)m_pAFoil; AFoilGridAct= new QAction(tr("Grid Options"), this); AFoilGridAct->setStatusTip(tr("Define the grid settings for the view")); connect(AFoilGridAct, SIGNAL(triggered()), pAFoil, SLOT(OnGrid())); storeSplineAct= new QAction(QIcon(":/images/OnStoreFoil.png"), tr("Store Splines as Foil"), this); storeSplineAct->setStatusTip(tr("Store the current splines in the foil database")); connect(storeSplineAct, SIGNAL(triggered()), pAFoil, SLOT(OnStoreSplines())); splineControlsAct= new QAction(tr("Splines Params"), this); splineControlsAct->setStatusTip(tr("Define parameters for the splines : degree, number of out points")); connect(splineControlsAct, SIGNAL(triggered()), pAFoil, SLOT(OnSplineControls())); exportSplinesToFileAct= new QAction(tr("Export Splines To File"), this); exportSplinesToFileAct->setStatusTip(tr("Define parameters for the splines : degree, number of out points")); connect(exportSplinesToFileAct, SIGNAL(triggered()), pAFoil, SLOT(OnExportSplinesToFile())); newSplinesAct= new QAction(tr("New Splines"), this); newSplinesAct->setStatusTip(tr("Reset the splines")); connect(newSplinesAct, SIGNAL(triggered()), pAFoil, SLOT(OnNewSplines())); InsertSplinePt = new QAction(tr("Insert Control Point")+"\tShift+Click", this); connect(InsertSplinePt, SIGNAL(triggered()), pAFoil, SLOT(OnInsertCtrlPt())); RemoveSplinePt = new QAction(tr("Remove Control Point")+"\tCtrl+Click", this); connect(RemoveSplinePt, SIGNAL(triggered()), pAFoil, SLOT(OnRemoveCtrlPt())); ResetXScaleAct= new QAction(QIcon(":/images/OnResetXScale.png"), tr("Reset X Scale"), this); ResetXScaleAct->setStatusTip(tr("Resets the scale to fit the current screen width")); connect(ResetXScaleAct, SIGNAL(triggered()), pAFoil, SLOT(OnResetXScale())); ResetXYScaleAct= new QAction(QIcon(":/images/OnResetFoilScale.png"), tr("Reset Scales")+"\t(R)", this); ResetXYScaleAct->setStatusTip(tr("Resets the x and y scales to screen size")); connect(ResetXYScaleAct, SIGNAL(triggered()), pAFoil, SLOT(OnResetScales())); UndoAFoilAct= new QAction(QIcon(":/images/OnUndo.png"), tr("Undo"), this); UndoAFoilAct->setShortcut(Qt::CTRL + Qt::Key_Z); UndoAFoilAct->setStatusTip(tr("Cancels the last modification")); connect(UndoAFoilAct, SIGNAL(triggered()), pAFoil, SLOT(OnUndo())); RedoAFoilAct= new QAction(QIcon(":/images/OnRedo.png"), tr("Redo"), this); RedoAFoilAct->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_Z); RedoAFoilAct->setStatusTip(tr("Restores the last cancelled modification")); connect(RedoAFoilAct, SIGNAL(triggered()), pAFoil, SLOT(OnRedo())); ShowAllFoils= new QAction(tr("Show All Foils"), this); connect(ShowAllFoils, SIGNAL(triggered()), pAFoil, SLOT(OnShowAllFoils())); HideAllFoils= new QAction(tr("Hide All Foils"), this); connect(HideAllFoils, SIGNAL(triggered()), pAFoil, SLOT(OnHideAllFoils())); AFoilDelete = new QAction(tr("Delete..."), this); connect(AFoilDelete, SIGNAL(triggered()), pAFoil, SLOT(OnDelete())); AFoilRename = new QAction(tr("Rename..."), this); AFoilRename->setShortcut(Qt::Key_F2); connect(AFoilRename, SIGNAL(triggered()), pAFoil, SLOT(OnRenameFoil())); AFoilExport = new QAction(tr("Export..."), this); connect(AFoilExport, SIGNAL(triggered()), pAFoil, SLOT(OnExportCurFoil())); ShowCurrentFoil= new QAction(tr("Show Current Foil"), this); connect(ShowCurrentFoil, SIGNAL(triggered()), pAFoil, SLOT(OnShowCurrentFoil())); HideCurrentFoil= new QAction(tr("Hide Current Foil"), this); connect(HideCurrentFoil, SIGNAL(triggered()), pAFoil, SLOT(OnHideCurrentFoil())); ResetYScaleAct= new QAction(tr("Reset Y Scale"), this); connect(ResetYScaleAct, SIGNAL(triggered()), pAFoil, SLOT(OnResetYScale())); zoomInAct= new QAction(QIcon(":/images/OnZoomIn.png"), tr("Zoom in"), this); zoomInAct->setStatusTip(tr("Zoom the view by drawing a rectangle in the client area")); connect(zoomInAct, SIGNAL(triggered()), pAFoil, SLOT(OnZoomIn())); zoomLessAct= new QAction(QIcon(":/images/OnZoomLess.png"), tr("Zoom Less"), this); zoomLessAct->setStatusTip(tr("Zoom Less")); connect(zoomLessAct, SIGNAL(triggered()), pAFoil, SLOT(OnZoomLess())); zoomYAct= new QAction(QIcon(":/images/OnZoomYScale.png"), tr("Zoom Y Scale Only"), this); zoomYAct->setStatusTip(tr("Zoom Y scale Only")); connect(zoomYAct, SIGNAL(triggered()), pAFoil, SLOT(OnZoomYOnly())); AFoilDerotateFoil = new QAction(tr("De-rotate the Foil"), this); connect(AFoilDerotateFoil, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilDerotateFoil())); AFoilNormalizeFoil = new QAction(tr("Normalize the Foil"), this); connect(AFoilNormalizeFoil, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilNormalizeFoil())); AFoilRefineGlobalFoil = new QAction(tr("Refine Globally")+"\t(F3)", this); connect(AFoilRefineGlobalFoil, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilPanels())); AFoilRefineLocalFoil = new QAction(tr("Refine Locally")+"\t(Shift+F3)", this); connect(AFoilRefineLocalFoil, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilCadd())); AFoilEditCoordsFoil = new QAction(tr("Edit Foil Coordinates"), this); connect(AFoilEditCoordsFoil, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilFoilCoordinates())); AFoilScaleFoil = new QAction(tr("Scale camber and thickness")+"\t(F9)", this); connect(AFoilScaleFoil, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilFoilGeom())); AFoilSetTEGap = new QAction(tr("Set T.E. Gap"), this); connect(AFoilSetTEGap, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilSetTEGap())); AFoilSetLERadius = new QAction(tr("Set L.E. Radius"), this); connect(AFoilSetLERadius, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilSetLERadius())); AFoilLECircle = new QAction(tr("Show LE Circle"), this); connect(AFoilLECircle, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilLECircle())); m_pShowLegend = new QAction(tr("Show Legend"), this); m_pShowLegend->setCheckable(true); connect(m_pShowLegend, SIGNAL(triggered()), pAFoil, SLOT(OnShowLegend())); AFoilSetFlap = new QAction(tr("Set Flap")+"\t(F10)", this); connect(AFoilSetFlap, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilSetFlap())); AFoilInterpolateFoils = new QAction(tr("Interpolate Foils")+"\t(F11)", this); connect(AFoilInterpolateFoils, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilInterpolateFoils())); AFoilNacaFoils = new QAction(tr("Naca Foils"), this); connect(AFoilNacaFoils, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilNacaFoils())); AFoilTableColumns = new QAction(tr("Set Table Columns"), this); connect(AFoilTableColumns, SIGNAL(triggered()), pAFoil, SLOT(OnAFoilTableColumns())); AFoilTableColumnWidths = new QAction(tr("Reset column widths"), this); connect(AFoilTableColumnWidths, SIGNAL(triggered()), pAFoil, SLOT(OnColumnWidths())); AFoilLoadImage = new QAction(tr("Load background image") +"\tCtrl+Shift+I", this); connect(AFoilLoadImage, SIGNAL(triggered()), pAFoil, SLOT(OnLoadBackImage())); AFoilClearImage = new QAction(tr("Clear background image") +"\tCtrl+Shift+I", this); connect(AFoilClearImage, SIGNAL(triggered()), pAFoil, SLOT(OnClearBackImage())); } // void MainFrame::CreateAFoilMenus() { AFoilViewMenu = menuBar()->addMenu(tr("&View")); AFoilViewMenu->addAction(ShowCurrentFoil); AFoilViewMenu->addAction(HideCurrentFoil); AFoilViewMenu->addAction(ShowAllFoils); AFoilViewMenu->addAction(HideAllFoils); AFoilViewMenu->addSeparator(); AFoilViewMenu->addAction(zoomInAct); AFoilViewMenu->addAction(zoomLessAct); AFoilViewMenu->addAction(ResetXScaleAct); AFoilViewMenu->addAction(ResetYScaleAct); AFoilViewMenu->addAction(ResetXYScaleAct); AFoilViewMenu->addSeparator(); AFoilViewMenu->addAction(m_pShowLegend); AFoilViewMenu->addAction(AFoilLECircle); AFoilViewMenu->addAction(AFoilGridAct); AFoilViewMenu->addSeparator(); AFoilViewMenu->addAction(AFoilLoadImage); AFoilViewMenu->addAction(AFoilClearImage); AFoilViewMenu->addSeparator(); AFoilViewMenu->addAction(saveViewToImageFileAct); AFoilDesignMenu = menuBar()->addMenu(tr("F&oil")); AFoilDesignMenu->addAction(AFoilRename); AFoilDesignMenu->addAction(AFoilDelete); AFoilDesignMenu->addAction(AFoilExport); AFoilDesignMenu->addAction(DuplicateFoil); AFoilDesignMenu->addSeparator(); AFoilDesignMenu->addAction(HideAllFoils); AFoilDesignMenu->addAction(ShowAllFoils); AFoilDesignMenu->addSeparator(); AFoilDesignMenu->addAction(AFoilNormalizeFoil); AFoilDesignMenu->addAction(AFoilDerotateFoil); AFoilDesignMenu->addAction(AFoilRefineLocalFoil); AFoilDesignMenu->addAction(AFoilRefineGlobalFoil); AFoilDesignMenu->addAction(AFoilEditCoordsFoil); AFoilDesignMenu->addAction(AFoilScaleFoil); AFoilDesignMenu->addAction(AFoilSetTEGap); AFoilDesignMenu->addAction(AFoilSetLERadius); AFoilDesignMenu->addAction(AFoilSetFlap); AFoilDesignMenu->addSeparator(); AFoilDesignMenu->addAction(AFoilInterpolateFoils); AFoilDesignMenu->addAction(AFoilNacaFoils); AFoilDesignMenu->addAction(ManageFoilsAct); AFoilSplineMenu = menuBar()->addMenu(tr("&Splines")); AFoilSplineMenu->addAction(InsertSplinePt); AFoilSplineMenu->addAction(RemoveSplinePt); AFoilSplineMenu->addSeparator(); AFoilSplineMenu->addAction(UndoAFoilAct); AFoilSplineMenu->addAction(RedoAFoilAct); AFoilSplineMenu->addSeparator(); AFoilSplineMenu->addAction(newSplinesAct); AFoilSplineMenu->addAction(splineControlsAct); AFoilSplineMenu->addAction(storeSplineAct); AFoilSplineMenu->addAction(exportSplinesToFileAct); //AFoil Context Menu AFoilCtxMenu = new QMenu(tr("Context Menu"),this); AFoilCtxMenu->addMenu(AFoilDesignMenu); AFoilCtxMenu->addSeparator(); AFoilCtxMenu->addMenu(AFoilSplineMenu); AFoilCtxMenu->addSeparator(); AFoilCtxMenu->addAction(ShowAllFoils); AFoilCtxMenu->addAction(HideAllFoils); AFoilCtxMenu->addSeparator(); AFoilCtxMenu->addAction(ResetXScaleAct); AFoilCtxMenu->addAction(ResetYScaleAct); AFoilCtxMenu->addAction(ResetXYScaleAct); AFoilCtxMenu->addSeparator(); AFoilCtxMenu->addAction(m_pShowLegend); AFoilCtxMenu->addAction(AFoilLECircle); AFoilCtxMenu->addAction(AFoilGridAct); AFoilCtxMenu->addSeparator(); AFoilCtxMenu->addAction(AFoilLoadImage); AFoilCtxMenu->addAction(AFoilClearImage); AFoilCtxMenu->addSeparator(); AFoilCtxMenu->addAction(saveViewToImageFileAct); AFoilCtxMenu->addSeparator(); AFoilCtxMenu->addAction(AFoilTableColumns); AFoilCtxMenu->addAction(AFoilTableColumnWidths); //Context menu to be displayed when user right clicks on a foil in the table AFoilTableCtxMenu = new QMenu(tr("Foil Actions"),this); AFoilTableCtxMenu->addAction(AFoilRename); AFoilTableCtxMenu->addAction(AFoilDelete); AFoilTableCtxMenu->addAction(AFoilExport); AFoilTableCtxMenu->addAction(DuplicateFoil); AFoilTableCtxMenu->addSeparator(); AFoilTableCtxMenu->addAction(AFoilNormalizeFoil); AFoilTableCtxMenu->addAction(AFoilDerotateFoil); AFoilTableCtxMenu->addAction(AFoilRefineLocalFoil); AFoilTableCtxMenu->addAction(AFoilRefineGlobalFoil); AFoilTableCtxMenu->addAction(AFoilEditCoordsFoil); AFoilTableCtxMenu->addAction(AFoilScaleFoil); AFoilTableCtxMenu->addAction(AFoilSetTEGap); AFoilTableCtxMenu->addAction(AFoilSetLERadius); AFoilTableCtxMenu->addAction(AFoilSetFlap); AFoilTableCtxMenu->addSeparator(); AFoilTableCtxMenu->addAction(AFoilTableColumns); AFoilTableCtxMenu->addAction(AFoilTableColumnWidths); } void MainFrame::CreateAFoilToolbar() { m_pctrlAFoilToolBar = addToolBar(tr("Foil")); m_pctrlAFoilToolBar->addAction(newProjectAct); m_pctrlAFoilToolBar->addAction(openAct); m_pctrlAFoilToolBar->addAction(saveAct); m_pctrlAFoilToolBar->addSeparator(); m_pctrlAFoilToolBar->addAction(zoomInAct); m_pctrlAFoilToolBar->addAction(zoomLessAct); m_pctrlAFoilToolBar->addAction(ResetXYScaleAct); m_pctrlAFoilToolBar->addAction(ResetXScaleAct); m_pctrlAFoilToolBar->addAction(zoomYAct); m_pctrlAFoilToolBar->addSeparator(); m_pctrlAFoilToolBar->addAction(UndoAFoilAct); m_pctrlAFoilToolBar->addAction(RedoAFoilAct); m_pctrlAFoilToolBar->addSeparator(); m_pctrlAFoilToolBar->addAction(storeSplineAct); } void MainFrame::CreateDockWindows() { QAFoil::s_pMainFrame = this; QXDirect::s_pMainFrame = this; QXInverse::s_pMainFrame = this; QMiarex::s_pMainFrame = this; ManageUFOsDlg::s_pMainFrame = this; GL3dBodyDlg::s_pMainFrame = this; ThreeDWidget::s_pMainFrame = this; PlaneDlg::s_pMainFrame = this; Body::s_pMainFrame = this; LLTAnalysisDlg::s_pMainFrame = this; XFoilAnalysisDlg::s_pMainFrame = this; BatchDlg::s_pMainFrame = this; BatchThreadDlg::s_pMainFrame = this; GraphDlg::s_pMainFrame = this; m_pctrlXDirectWidget = new QDockWidget("XDirect", this); m_pctrlXDirectWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); addDockWidget(Qt::RightDockWidgetArea, m_pctrlXDirectWidget); m_pctrlXInverseWidget = new QDockWidget("XInverse", this); m_pctrlXInverseWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); addDockWidget(Qt::RightDockWidgetArea, m_pctrlXInverseWidget); m_pctrlMiarexWidget = new QDockWidget("Miarex", this); m_pctrlMiarexWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); addDockWidget(Qt::RightDockWidgetArea, m_pctrlMiarexWidget); m_pctrlAFoilWidget = new QDockWidget("AFoil", this); m_pctrlAFoilWidget->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea); addDockWidget(Qt::BottomDockWidgetArea, m_pctrlAFoilWidget); m_p2DWidget = new TwoDWidget(this); m_pGLWidget = new ThreeDWidget(this); m_pXDirect = new QXDirect(this); QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->setAttribute(Qt::WA_DeleteOnClose, false); m_pctrlXDirectWidget->setWidget(pXDirect); m_pctrlXDirectWidget->setVisible(false); m_pctrlXDirectWidget->setFloating(true); m_pctrlXDirectWidget->move(960,60); m_pXInverse = new QXInverse(this); QXInverse *pXInverse = (QXInverse*)m_pXInverse; pXInverse->setAttribute(Qt::WA_DeleteOnClose, false); m_pctrlXInverseWidget->setWidget(pXInverse); m_pctrlXInverseWidget->setVisible(false); m_pctrlXInverseWidget->setFloating(true); m_pctrlXInverseWidget->move(960,60); m_pMiarex = new QMiarex; QMiarex * pMiarex = (QMiarex*)m_pMiarex; pMiarex->setAttribute(Qt::WA_DeleteOnClose, false); m_pctrlMiarexWidget->setWidget(pMiarex); m_pctrlMiarexWidget->setVisible(false); m_pctrlMiarexWidget->setFloating(true); m_pctrlMiarexWidget->move(960,60); m_pGL3DScales = new GL3DScales(this); GL3DScales * pGL3DScales = (GL3DScales*)m_pGL3DScales; pGL3DScales->m_pMiarex = m_pMiarex; pGL3DScales->m_pMainFrame = this; pGL3DScales->setAttribute(Qt::WA_DeleteOnClose, false); m_pctrl3DScalesWidget = new QDockWidget(tr("3D Scales"), this); m_pctrl3DScalesWidget->setAllowedAreas(Qt::LeftDockWidgetArea); addDockWidget(Qt::LeftDockWidgetArea, m_pctrl3DScalesWidget); m_pctrl3DScalesWidget->setWidget(pGL3DScales); m_pctrl3DScalesWidget->setVisible(false); m_pctrl3DScalesWidget->setFloating(true); m_pctrl3DScalesWidget->move(60,60); StabViewDlg::s_pMiarex = m_pMiarex; m_pStabView = new StabViewDlg(this); StabViewDlg * pStabView = (StabViewDlg*)m_pStabView; pStabView->setAttribute(Qt::WA_DeleteOnClose, false); m_pctrlStabViewWidget = new QDockWidget(tr("Stability"), this); m_pctrlStabViewWidget->setAllowedAreas(Qt::LeftDockWidgetArea); addDockWidget(Qt::LeftDockWidgetArea, m_pctrlStabViewWidget); m_pctrlStabViewWidget->setWidget(pStabView); m_pctrlStabViewWidget->setVisible(false); m_pctrlStabViewWidget->setFloating(true); m_pctrlStabViewWidget->move(60,60); m_pctrlCentralWidget = new QStackedWidget; m_pctrlCentralWidget->addWidget(m_p2DWidget); m_pctrlCentralWidget->addWidget(m_pGLWidget); setCentralWidget(m_pctrlCentralWidget); m_pAFoil = new QAFoil(this); QAFoil *pAFoil = (QAFoil*)m_pAFoil; pAFoil->setAttribute(Qt::WA_DeleteOnClose, false); m_pctrlAFoilWidget->setWidget(pAFoil); m_pctrlAFoilWidget->setVisible(false); m_p2DWidget->m_pXDirect = pXDirect; m_p2DWidget->m_pXInverse = pXInverse; m_p2DWidget->m_pMiarex = pMiarex; m_p2DWidget->m_pAFoil = pAFoil; m_p2DWidget->m_pMainFrame = this; QSizePolicy sizepol; sizepol.setHorizontalPolicy(QSizePolicy::Expanding); sizepol.setVerticalPolicy(QSizePolicy::Expanding); m_p2DWidget->setSizePolicy(sizepol); QMiarex::s_p2dWidget = m_p2DWidget; QMiarex::s_p3dWidget = m_pGLWidget; pMiarex->m_ArcBall.m_p3dWidget = m_pGLWidget; pMiarex->m_poaBody = &s_oaBody; pMiarex->m_poaPlane = &s_oaPlane; pMiarex->m_poaWing = &s_oaWing; pMiarex->m_poaWPolar = &m_oaWPolar; pMiarex->m_poaWOpp = &m_oaWOpp; pMiarex->m_poaPOpp = &m_oaPOpp; QXDirect::s_p2DWidget = m_p2DWidget; pXDirect->m_pCpGraph->m_pParent = m_p2DWidget; for(int ig=0; igm_PlrGraph[ig].m_pParent = m_p2DWidget; pXDirect->m_poaFoil = &s_oaFoil; pXDirect->m_poaPolar = &s_oaPolar; pXDirect->m_poaOpp = &m_oaOpp; QAFoil::s_p2DWidget = m_p2DWidget; pAFoil->m_poaFoil = &s_oaFoil; pAFoil->m_pXFoil = pXDirect->m_pXFoil; QXInverse::s_p2DWidget = m_p2DWidget; pXInverse->s_pMainFrame = this; pXInverse->m_pXFoil = pXDirect->m_pXFoil; pXInverse->s_p2DWidget = m_p2DWidget; pXInverse->m_poaFoil = &s_oaFoil; GL3dWingDlg::s_poaFoil = &s_oaFoil; GL3dWingDlg::s_pMiarex = m_pMiarex; ThreeDWidget::s_pMiarex = m_pMiarex; PlaneDlg::s_pMiarex = m_pMiarex; Wing::s_pMiarex = m_pMiarex; WPolar::s_pMiarex = m_pMiarex; LLTAnalysisDlg::s_pMiarex = m_pMiarex; PanelAnalysisDlg::s_pMiarex = m_pMiarex; ManageUFOsDlg::s_pMiarex = m_pMiarex; StabPolarDlg::s_pMiarex = m_pMiarex; UFOTableDelegate::s_pMiarex = m_pMiarex; WPolarDlg::s_pMiarex = m_pMiarex; Plane::SetParents(this, m_pMiarex); XFoilAnalysisDlg::s_pXDirect = m_pXDirect; NacaFoilDlg::s_pXFoil = pXDirect->m_pXFoil; InterpolateFoilsDlg::s_pXFoil = pXDirect->m_pXFoil; CAddDlg::s_pXFoil = pXDirect->m_pXFoil; TwoDPanelDlg::s_pXFoil = pXDirect->m_pXFoil; FoilGeomDlg::s_pXFoil = pXDirect->m_pXFoil; TEGapDlg::s_pXFoil = pXDirect->m_pXFoil; LEDlg::s_pXFoil = pXDirect->m_pXFoil; BatchDlg::s_pXFoil = pXDirect->m_pXFoil; BatchDlg::s_pXDirect = m_pXDirect; BatchThreadDlg::s_pXFoil = pXDirect->m_pXFoil; BatchThreadDlg::s_pXDirect = m_pXDirect; GraphDlg::s_ActivePage = 0; } void MainFrame::CreateMenus() { fileMenu = menuBar()->addMenu(tr("&File")); fileMenu->addAction(newProjectAct); fileMenu->addAction(openAct); fileMenu->addAction(insertAct); fileMenu->addAction(closeProjectAct); fileMenu->addSeparator(); fileMenu->addAction(saveAct); fileMenu->addAction(saveProjectAsAct); fileMenu->addSeparator(); fileMenu->addAction(OnAFoilAct); fileMenu->addAction(OnXInverseAct); fileMenu->addAction(OnXDirectAct); fileMenu->addAction(OnMiarexAct); separatorAct = fileMenu->addSeparator(); for (int i = 0; i < MAXRECENTFILES; ++i) fileMenu->addAction(recentFileActs[i]); fileMenu->addSeparator(); fileMenu->addAction(exitAct); updateRecentFileActions(); optionsMenu = menuBar()->addMenu(tr("Options")); optionsMenu->addSeparator(); optionsMenu->addAction(languageAct); optionsMenu->addSeparator(); optionsMenu->addAction(unitsAct); optionsMenu->addSeparator(); optionsMenu->addAction(styleAct); optionsMenu->addSeparator(); optionsMenu->addAction(saveOptionsAct); optionsMenu->addSeparator(); optionsMenu->addAction(restoreToolbarsAct); optionsMenu->addSeparator(); optionsMenu->addAction(resetSettingsAct); helpMenu = menuBar()->addMenu(tr("&?")); // helpMenu->addAction(guidelinesAct); helpMenu->addAction(aboutQtAct); helpMenu->addAction(aboutAct); //Create Application-Specific Menus CreateXDirectMenus(); CreateXInverseMenus(); CreateMiarexMenus(); CreateAFoilMenus(); } void MainFrame::CreateMiarexActions() { QMiarex *pMiarex = (QMiarex*)m_pMiarex; WOppAct = new QAction(QIcon(":/images/OnWOppView.png"), tr("OpPoint View")+"\tF5", this); WOppAct->setCheckable(true); WOppAct->setStatusTip(tr("Switch to the Operating point view")); // WOppAct->setShortcut(Qt::Key_F5); connect(WOppAct, SIGNAL(triggered()), pMiarex, SLOT(OnWOpps())); WPolarAct = new QAction(QIcon(":/images/OnPolarView.png"), tr("Polar View")+"\tF8", this); WPolarAct->setCheckable(true); WPolarAct->setStatusTip(tr("Switch to the Polar view")); // WPolarAct->setShortcut(Qt::Key_F8); connect(WPolarAct, SIGNAL(triggered()), pMiarex, SLOT(OnWPolars())); StabTimeAct = new QAction(QIcon(":/images/OnStabView.png"),tr("Time Response Vew")+"\tShift+F8", this); StabTimeAct->setCheckable(true); StabTimeAct->setStatusTip(tr("Switch to stability analysis post-processing")); // StabTimeAct->setShortcut(tr("Shift+F8")); connect(StabTimeAct, SIGNAL(triggered()), pMiarex, SLOT(OnTimeView())); RootLocusAct = new QAction(QIcon(":/images/OnRootLocus.png"),tr("Root Locus View")+"\tCtrl+F8", this); RootLocusAct->setCheckable(true); RootLocusAct->setStatusTip(tr("Switch to root locus view")); connect(RootLocusAct, SIGNAL(triggered()), pMiarex, SLOT(OnRootLocusView())); W3DAct = new QAction(QIcon(":/images/On3DView.png"), tr("3D View")+"\tF4", this); W3DAct->setCheckable(true); W3DAct->setStatusTip(tr("Switch to the 3D view")); connect(W3DAct, SIGNAL(triggered()), pMiarex, SLOT(On3DView())); CpViewAct = new QAction(QIcon(":/images/OnCpView.png"), tr("Cp View")+"\tF9", this); CpViewAct->setCheckable(true); CpViewAct->setStatusTip(tr("Switch to the Cp view")); connect(CpViewAct, SIGNAL(triggered()), pMiarex, SLOT(OnCpView())); W3DPrefsAct = new QAction(tr("3D Color Preferences"), this); W3DPrefsAct->setStatusTip(tr("Define the style and color preferences for the 3D view")); connect(W3DPrefsAct, SIGNAL(triggered()), pMiarex, SLOT(On3DPrefs())); MiarexPolarFilter = new QAction(tr("Polar Filter"), this); MiarexPolarFilter->setStatusTip(tr("Define which type of polars should be shown or hidden")); connect(MiarexPolarFilter, SIGNAL(triggered()), pMiarex, SLOT(OnPolarFilter())); W3DScalesAct = new QAction(tr("3D Scales"), this); W3DScalesAct->setStatusTip(tr("Define the scales for the 3D display of lift, moment, drag, and downwash")); W3DScalesAct->setCheckable(true); connect(W3DScalesAct, SIGNAL(triggered()), pMiarex, SLOT(OnGL3DScale())); W3DLightAct = new QAction(tr("3D Light Options"), this); W3DLightAct->setStatusTip(tr("Define the light options in 3D view")); connect(W3DLightAct, SIGNAL(triggered()), pMiarex, SLOT(OnSetupLight())); DefineWingAct = new QAction(tr("Define a New Wing")+"\tF3", this); DefineWingAct->setStatusTip(tr("Shows a dialogbox for editing a new wing definition")); connect(DefineWingAct, SIGNAL(triggered()), pMiarex, SLOT(OnNewWing())); halfWingAct = new QAction(tr("Half Wing"), this); halfWingAct->setCheckable(true); connect(halfWingAct, SIGNAL(triggered()), pMiarex, SLOT(OnHalfWing())); definePlaneAct = new QAction(tr("Define a New Plane")+"\tCtrl+F3", this); definePlaneAct->setStatusTip(tr("Shows a dialogbox to create a new plane definition")); connect(definePlaneAct, SIGNAL(triggered()), pMiarex, SLOT(OnNewPlane())); editUFOAct = new QAction(tr("Edit...")+"\tShift+F3", this); editUFOAct->setStatusTip(tr("Shows a dialogbox to edit the currently selected wing or plane")); connect(editUFOAct, SIGNAL(triggered()), pMiarex, SLOT(OnEditUFO())); renameCurUFO = new QAction(tr("Rename...")+"\tF2", this); renameCurUFO->setStatusTip(tr("Rename the currently selected object")); connect(renameCurUFO, SIGNAL(triggered()), pMiarex, SLOT(OnRenameCurUFO())); editCurBodyAct = new QAction(tr("Edit Body..."), this); editCurBodyAct->setStatusTip(tr("Edit the body of the currently selected plane")); editCurBodyAct->setShortcut(QKeySequence(Qt::SHIFT+Qt::Key_F10)); connect(editCurBodyAct, SIGNAL(triggered()), pMiarex, SLOT(OnEditCurBody())); exporttoAVL = new QAction(tr("Export to AVL..."), this); exporttoAVL->setStatusTip(tr("Export the current plane or wing to a text file in the format required by AVL")); connect(exporttoAVL, SIGNAL(triggered()), pMiarex, SLOT(OnExporttoAVL())); exportCurWOpp = new QAction(tr("Export..."), this); exportCurWOpp->setStatusTip(tr("Export the current operating point to a text or csv file")); connect(exportCurWOpp, SIGNAL(triggered()), pMiarex, SLOT(OnExportCurWOpp())); resetWOppLegend = new QAction(tr("Reset Legend Position"), this); resetWOppLegend->setStatusTip(tr("Reset the legend position to its default value")); connect(resetWOppLegend, SIGNAL(triggered()), pMiarex, SLOT(OnResetWOppLegend())); resetWPlrLegend = new QAction(tr("Reset Legend Position"), this); resetWPlrLegend->setStatusTip(tr("Reset the legend position to its default value")); connect(resetWPlrLegend, SIGNAL(triggered()), pMiarex, SLOT(OnResetWPlrLegend())); resetWingScale = new QAction(tr("Reset Wing Scale"), this); resetWingScale ->setStatusTip(tr("Reset the wing scale to its default value")); connect(resetWingScale, SIGNAL(triggered()), pMiarex, SLOT(OnResetWingScale())); scaleWingAct = new QAction(tr("Scale Wing"), this); scaleWingAct->setStatusTip(tr("Scale the dimensions of the currently selected wing")); connect(scaleWingAct, SIGNAL(triggered()), pMiarex, SLOT(OnScaleWing())); manageUFOsAct = new QAction(tr("Manage objects"), this); manageUFOsAct->setStatusTip(tr("Rename or delete the planes and wings stored in the database")); manageUFOsAct->setShortcut(Qt::Key_F7); connect(manageUFOsAct, SIGNAL(triggered()), pMiarex, SLOT(OnManageUFOs())); m_pImportWPolar = new QAction(tr("Import Polar"), this); m_pImportWPolar->setStatusTip(tr("Import a polar from a text file")); connect(m_pImportWPolar, SIGNAL(triggered()), pMiarex, SLOT(OnImportWPolar())); m_pUFOInertia = new QAction(tr("Define Inertia")+"\tF12", this); m_pUFOInertia->setStatusTip(tr("Define the inertia for the current plane or wing")); connect(m_pUFOInertia, SIGNAL(triggered()), pMiarex, SLOT(OnUFOInertia())); showCurWOppOnly = new QAction(tr("Show Current OpPoint Only"), this); showCurWOppOnly->setStatusTip(tr("Hide all the curves except for the one corresponding to the currently selected operating point")); showCurWOppOnly->setCheckable(true); connect(showCurWOppOnly, SIGNAL(triggered()), pMiarex, SLOT(OnCurWOppOnly())); showAllWOpps = new QAction(tr("Show All OpPoints"), this); showAllWOpps->setStatusTip(tr("Show the graph curves of all operating points")); connect(showAllWOpps, SIGNAL(triggered()), pMiarex, SLOT(OnShowAllWOpps())); hideAllWOpps = new QAction(tr("Hide All OpPoints"), this); hideAllWOpps->setStatusTip(tr("Hide the graph curves of all operating points")); connect(hideAllWOpps, SIGNAL(triggered()), pMiarex, SLOT(OnHideAllWOpps())); deleteAllWOpps = new QAction(tr("Delete All OpPoints"), this); deleteAllWOpps->setStatusTip(tr("Delete all the operating points of all planes and polars")); connect(deleteAllWOpps, SIGNAL(triggered()), pMiarex, SLOT(OnDeleteAllWOpps())); showAllWPlrOpps = new QAction(tr("Show Associated OpPoints"), this); showAllWPlrOpps->setStatusTip(tr("Show the curves of all the operating points of the currently selected polar")); connect(showAllWPlrOpps, SIGNAL(triggered()), pMiarex, SLOT(OnShowAllWPlrOpps())); hideAllWPlrOpps = new QAction(tr("Hide Associated OpPoints"), this); hideAllWPlrOpps->setStatusTip(tr("Hide the curves of all the operating points of the currently selected polar")); connect(hideAllWPlrOpps, SIGNAL(triggered()), pMiarex, SLOT(OnHideAllWPlrOpps())); deleteAllWPlrOpps = new QAction(tr("Delete Associated OpPoints"), this); deleteAllWPlrOpps->setStatusTip(tr("Delete all the operating points of the currently selected polar")); connect(deleteAllWPlrOpps, SIGNAL(triggered()), pMiarex, SLOT(OnDeleteAllWPlrOpps())); showEllipticCurve = new QAction(tr("Show Elliptic Curve"), this); showEllipticCurve->setStatusTip(tr("Show the theoretical optimal elliptic lift curve on all graphs for which the selected variable is the local lift")); showEllipticCurve->setCheckable(true); connect(showEllipticCurve, SIGNAL(triggered()), pMiarex, SLOT(OnShowEllipticCurve())); showXCmRefLocation = new QAction(tr("Show XCG location"), this); showXCmRefLocation->setStatusTip(tr("Show the position of the center of gravity defined in the analysis")); showXCmRefLocation->setCheckable(true); connect(showXCmRefLocation, SIGNAL(triggered()), pMiarex, SLOT(OnShowXCmRef())); showStabCurve = new QAction(tr("Show Elevator Curve"), this); showStabCurve->setStatusTip(tr("Show the graph curves for the elevator")); showStabCurve->setCheckable(true); connect(showStabCurve, SIGNAL(triggered()), pMiarex, SLOT(OnStabCurve())); showFinCurve = new QAction(tr("Show Fin Curve"), this); showFinCurve->setStatusTip(tr("Show the graph curves for the fin")); showFinCurve->setCheckable(true); connect(showFinCurve, SIGNAL(triggered()), pMiarex, SLOT(OnFinCurve())); showWing2Curve = new QAction(tr("Show Second Wing Curve"), this); showWing2Curve->setStatusTip(tr("Show the graph curves for the second wing")); showWing2Curve->setCheckable(true); connect(showWing2Curve, SIGNAL(triggered()), pMiarex, SLOT(OnWing2Curve())); defineWPolar = new QAction(tr("Define an Analysis")+" \t(F6)", this); defineWPolar->setStatusTip(tr("Define an analysis for the current wing or plane")); connect(defineWPolar, SIGNAL(triggered()), pMiarex, SLOT(OnDefineWPolar())); editWPolar = new QAction(tr("Edit...")+" \t(Ctrl+F6)", this); editWPolar->setStatusTip(tr("Modify the analysis parameters of this polar")); connect(editWPolar, SIGNAL(triggered()), pMiarex, SLOT(OnEditCurWPolar())); defineStabPolar = new QAction(tr("Define a Stability Analysis")+"\t(Shift+F6)", this); defineStabPolar->setStatusTip(tr("Define a stability analysis for the current wing or plane")); // defineStabPolar->setShortcut(tr("Ctrl+F6")); connect(defineStabPolar, SIGNAL(triggered()), pMiarex, SLOT(OnDefineStabPolar())); MiarexGraphDlg = new QAction(tr("Define Graph Settings")+"\t(G)", this); MiarexGraphDlg->setStatusTip(tr("Define the settings for the selected graph")); connect(MiarexGraphDlg, SIGNAL(triggered()), pMiarex, SLOT(OnGraphSettings())); twoGraphs = new QAction(tr("Two Graphs")+"\t(T)", this); twoGraphs->setStatusTip(tr("Display the first two graphs")); twoGraphs->setCheckable(true); connect(twoGraphs, SIGNAL(triggered()), pMiarex, SLOT(OnTwoGraphs())); fourGraphs = new QAction(tr("All Graphs")+"\t(A)", this); fourGraphs->setStatusTip(tr("Display all four graphs")); fourGraphs->setCheckable(true); connect(fourGraphs, SIGNAL(triggered()), pMiarex, SLOT(OnFourGraphs())); Graph1 = new QAction(tr("Graph 1")+"\t(1)", this); Graph1->setStatusTip(tr("Display only the first graph")); Graph1->setCheckable(true); connect(Graph1, SIGNAL(triggered()), pMiarex, SLOT(OnSingleGraph1())); Graph2 = new QAction(tr("Graph 2")+"\t(2)", this); Graph2->setStatusTip(tr("Display only the second graph")); Graph2->setCheckable(true); connect(Graph2, SIGNAL(triggered()), pMiarex, SLOT(OnSingleGraph2())); Graph3 = new QAction(tr("Graph 3")+"\t(3)", this); Graph3->setStatusTip(tr("Display only the third graph")); Graph3->setCheckable(true); connect(Graph3, SIGNAL(triggered()), pMiarex, SLOT(OnSingleGraph3())); Graph4 = new QAction(tr("Graph 4")+"\t(4)", this); Graph4->setStatusTip(tr("Display only the fourth graph")); Graph4->setCheckable(true); connect(Graph4, SIGNAL(triggered()), pMiarex, SLOT(OnSingleGraph4())); highlightWOppAct = new QAction(tr("Highlight Current OpPoint")+"\t(Ctrl+H)", this); highlightWOppAct->setCheckable(true); highlightWOppAct->setStatusTip(tr("Highlights on the polar curve the currently selected operating point")); connect(highlightWOppAct, SIGNAL(triggered()), pMiarex, SLOT(OnHighlightWOpp())); ResetWingGraphScale = new QAction(QIcon(":/images/OnResetGraphScale.png"), tr("Reset Graph Scales")+"\t(R)", this); ResetWingGraphScale->setStatusTip(tr("Reset the scale of the current operating point graph")); connect(ResetWingGraphScale, SIGNAL(triggered()), pMiarex, SLOT(OnResetWingGraphScale())); allWingGraphsScalesAct = new QAction(tr("Reset All Graph Scales"), this); allWingGraphsScalesAct->setStatusTip(tr("Reset the scales of all four operating point graphs")); connect(allWingGraphsScalesAct, SIGNAL(triggered()), pMiarex, SLOT(OnAllWingGraphScales())); allWPolarGraphsScalesAct = new QAction(tr("Reset All Graph Scales"), this); allWPolarGraphsScalesAct->setStatusTip(tr("Reset the scales of all four polar graphs")); connect(allWPolarGraphsScalesAct, SIGNAL(triggered()), pMiarex, SLOT(OnAllWPolarGraphScales())); allWingGraphsSettings = new QAction(tr("All Graph Settings"), this); allWingGraphsSettings->setStatusTip(tr("Define the settings of all four operating point graphs")); connect(allWingGraphsSettings, SIGNAL(triggered()), pMiarex, SLOT(OnAllWingGraphSettings())); allWPolarGraphsSettings = new QAction(tr("All Graph Settings"), this); allWPolarGraphsSettings->setStatusTip(tr("Define the settings of all four polar graphs")); connect(allWPolarGraphsSettings, SIGNAL(triggered()), pMiarex, SLOT(OnAllWPolarGraphSettings())); hideUFOWPlrs = new QAction(tr("Hide Associated Polars"), this); hideUFOWPlrs->setStatusTip(tr("Hide all the polar curves associated to the currently selected wing or plane")); connect(hideUFOWPlrs, SIGNAL(triggered()), pMiarex, SLOT(OnHideUFOWPolars())); showUFOWPlrsOnly = new QAction(tr("Show Only Associated Polars"), this); connect(showUFOWPlrsOnly, SIGNAL(triggered()), pMiarex, SLOT(OnShowUFOWPolarsOnly())); showUFOWPlrs = new QAction(tr("Show Associated Polars"), this); showUFOWPlrs->setStatusTip(tr("Show all the polar curves associated to the currently selected wing or plane")); connect(showUFOWPlrs, SIGNAL(triggered()), pMiarex, SLOT(OnShowUFOWPolars())); deleteUFOWPlrs = new QAction(tr("Delete Associated Polars"), this); deleteUFOWPlrs->setStatusTip(tr("Delete all the polars associated to the currently selected wing or plane")); connect(deleteUFOWPlrs, SIGNAL(triggered()), pMiarex, SLOT(OnDeleteUFOWPolars())); hideAllWPlrs = new QAction(tr("Hide All Polars"), this); hideAllWPlrs->setStatusTip(tr("Hide all the polar curves of all wings and planes")); connect(hideAllWPlrs, SIGNAL(triggered()), pMiarex, SLOT(OnHideAllWPolars())); showAllWPlrs = new QAction(tr("Show All Polars"), this); showAllWPlrs->setStatusTip(tr("Show all the polar curves of all wings and planes")); connect(showAllWPlrs, SIGNAL(triggered()), pMiarex, SLOT(OnShowAllWPolars())); hideUFOWOpps = new QAction(tr("Hide Associated OpPoints"), this); hideUFOWOpps->setStatusTip(tr("Hide all the operating point curves of the currently selected wing or plane")); connect(hideUFOWOpps, SIGNAL(triggered()), pMiarex, SLOT(OnHideUFOWOpps())); showUFOWOpps = new QAction(tr("Show Associated OpPoints"), this); showUFOWOpps->setStatusTip(tr("Show all the operating point curves of the currently selected wing or plane")); connect(showUFOWOpps, SIGNAL(triggered()), pMiarex, SLOT(OnShowUFOWOpps())); deleteUFOWOpps = new QAction(tr("Delete Associated OpPoints"), this); deleteUFOWOpps->setStatusTip(tr("Delete all the operating points of the currently selected wing or plane")); connect(deleteUFOWOpps, SIGNAL(triggered()), pMiarex, SLOT(OnDeleteUFOWOpps())); deleteCurUFO = new QAction(tr("Delete..."), this); deleteCurUFO->setStatusTip(tr("Delete the currently selected wing or plane")); connect(deleteCurUFO, SIGNAL(triggered()), pMiarex, SLOT(OnDeleteCurUFO())); duplicateCurUFO = new QAction(tr("Duplicate..."), this); duplicateCurUFO->setStatusTip(tr("Duplicate the currently selected wing or plane")); connect(duplicateCurUFO, SIGNAL(triggered()), pMiarex, SLOT(OnDuplicateCurUFO())); SaveUFOAsProject = new QAction(tr("Save as Project..."), this); SaveUFOAsProject->setStatusTip(tr("Save the currently selected wing or plane as a new separate project")); connect(SaveUFOAsProject, SIGNAL(triggered()), this, SLOT(OnSaveUFOAsProject())); renameCurWPolar = new QAction(tr("Rename..."), this); renameCurWPolar->setStatusTip(tr("Rename the currently selected polar")); connect(renameCurWPolar, SIGNAL(triggered()), pMiarex, SLOT(OnRenameCurWPolar())); exportCurWPolar = new QAction(tr("Export ..."), this); exportCurWPolar->setStatusTip(tr("Export the currently selected polar to a text or csv file")); connect(exportCurWPolar, SIGNAL(triggered()), pMiarex, SLOT(OnExportCurWPolar())); resetCurWPolar = new QAction(tr("Reset ..."), this); resetCurWPolar->setStatusTip(tr("Delete all the points of the currently selected polar, but keep the analysis settings")); connect(resetCurWPolar, SIGNAL(triggered()), pMiarex, SLOT(OnResetCurWPolar())); deleteCurWPolar = new QAction(tr("Delete ..."), this); deleteCurWPolar->setStatusTip(tr("Delete the currently selected polar")); connect(deleteCurWPolar, SIGNAL(triggered()), pMiarex, SLOT(OnDeleteCurWPolar())); deleteCurWOpp = new QAction(tr("Delete..."), this); deleteCurWOpp->setStatusTip(tr("Delete the currently selected operating point")); connect(deleteCurWOpp, SIGNAL(triggered()), pMiarex, SLOT(OnDeleteCurWOpp())); advancedSettings = new QAction(tr("Advanced Settings..."), this); advancedSettings->setStatusTip(tr("Define the settings for LLT, VLM and Panel analysis")); connect(advancedSettings, SIGNAL(triggered()), pMiarex, SLOT(OnAdvancedSettings())); } void MainFrame::CreateMiarexMenus() { //MainMenu for Miarex Application MiarexViewMenu = menuBar()->addMenu(tr("&View")); { MiarexViewMenu->addAction(WOppAct); MiarexViewMenu->addAction(WPolarAct); MiarexViewMenu->addAction(W3DAct); MiarexViewMenu->addAction(CpViewAct); MiarexViewMenu->addAction(StabTimeAct); MiarexViewMenu->addAction(RootLocusAct); MiarexViewMenu->addSeparator(); MiarexViewMenu->addAction(W3DPrefsAct); MiarexViewMenu->addAction(W3DLightAct); MiarexViewMenu->addAction(W3DScalesAct); MiarexViewMenu->addSeparator(); MiarexViewMenu->addAction(saveViewToImageFileAct); } UFOMenu = menuBar()->addMenu(tr("&Wing-Plane")); { UFOMenu->addAction(DefineWingAct); UFOMenu->addAction(definePlaneAct); UFOMenu->addAction(manageUFOsAct); currentUFOMenu = UFOMenu->addMenu(tr("Current UFO")); { currentUFOMenu->addAction(editUFOAct); currentUFOMenu->addAction(renameCurUFO); currentUFOMenu->addAction(duplicateCurUFO); currentUFOMenu->addAction(deleteCurUFO); currentUFOMenu->addAction(SaveUFOAsProject); currentUFOMenu->addSeparator(); currentUFOMenu->addAction(editCurBodyAct); currentUFOMenu->addSeparator(); currentUFOMenu->addAction(scaleWingAct); currentUFOMenu->addSeparator(); currentUFOMenu->addAction(m_pUFOInertia); currentUFOMenu->addSeparator(); currentUFOMenu->addAction(exporttoAVL); currentUFOMenu->addSeparator(); currentUFOMenu->addAction(showUFOWPlrsOnly); currentUFOMenu->addAction(showUFOWPlrs); currentUFOMenu->addAction(hideUFOWPlrs); currentUFOMenu->addAction(deleteUFOWPlrs); currentUFOMenu->addSeparator(); currentUFOMenu->addAction(hideUFOWOpps); currentUFOMenu->addAction(showUFOWOpps); currentUFOMenu->addAction(deleteUFOWOpps); } } MiarexWPlrMenu = menuBar()->addMenu(tr("&Polars")); { curWPlrMenu = MiarexWPlrMenu->addMenu(tr("Current Polar")); { curWPlrMenu->addAction(ShowPolarProps); curWPlrMenu->addAction(editWPolar); curWPlrMenu->addAction(renameCurWPolar); curWPlrMenu->addAction(deleteCurWPolar); curWPlrMenu->addAction(exportCurWPolar); curWPlrMenu->addAction(resetCurWPolar); curWPlrMenu->addSeparator(); curWPlrMenu->addAction(showAllWPlrOpps); curWPlrMenu->addAction(hideAllWPlrOpps); curWPlrMenu->addAction(deleteAllWPlrOpps); } MiarexWPlrMenu->addSeparator(); MiarexWPlrMenu->addAction(m_pImportWPolar); MiarexWPlrMenu->addSeparator(); MiarexWPlrMenu->addAction(MiarexPolarFilter); MiarexWPlrMenu->addSeparator(); MiarexWPlrMenu->addAction(hideAllWPlrs); MiarexWPlrMenu->addAction(showAllWPlrs); MiarexWPlrMenu->addSeparator(); WPlrGraphMenu = MiarexWPlrMenu->addMenu(tr("Graphs")); { WPlrGraphMenu->addAction(Graph1); WPlrGraphMenu->addAction(Graph2); WPlrGraphMenu->addAction(Graph3); WPlrGraphMenu->addAction(Graph4); WPlrGraphMenu->addSeparator(); WPlrGraphMenu->addAction(twoGraphs); WPlrGraphMenu->addAction(fourGraphs); WPlrGraphMenu->addSeparator(); WPlrGraphMenu->addAction(allWPolarGraphsSettings); WPlrGraphMenu->addAction(allWPolarGraphsScalesAct); WPlrGraphMenu->addAction(resetWPlrLegend); WPlrGraphMenu->addSeparator(); WPlrGraphMenu->addAction(highlightWOppAct); } } MiarexWOppMenu = menuBar()->addMenu(tr("&OpPoint")); { curWOppMenu = MiarexWOppMenu->addMenu(tr("Current OpPoint")); { curWOppMenu->addAction(ShowWOppProps); curWOppMenu->addAction(exportCurWOpp); curWOppMenu->addAction(deleteCurWOpp); } MiarexWOppMenu->addSeparator(); MiarexWOppMenu->addAction(showCurWOppOnly); MiarexWOppMenu->addAction(showAllWOpps); MiarexWOppMenu->addAction(hideAllWOpps); MiarexWOppMenu->addAction(deleteAllWOpps); MiarexWOppMenu->addSeparator(); MiarexWOppMenu->addAction(halfWingAct); MiarexWOppMenu->addAction(showEllipticCurve); MiarexWOppMenu->addAction(showXCmRefLocation); MiarexWOppMenu->addAction(showWing2Curve); MiarexWOppMenu->addAction(showStabCurve); MiarexWOppMenu->addAction(showFinCurve); MiarexWOppMenu->addSeparator(); WOppGraphMenu = MiarexWOppMenu->addMenu(tr("Graphs")); { WOppGraphMenu->addAction(Graph1); WOppGraphMenu->addAction(Graph2); WOppGraphMenu->addAction(Graph3); WOppGraphMenu->addAction(Graph4); WOppGraphMenu->addSeparator(); WOppGraphMenu->addAction(twoGraphs); WOppGraphMenu->addAction(fourGraphs); WOppGraphMenu->addSeparator(); WOppGraphMenu->addAction(allWingGraphsSettings); WOppGraphMenu->addAction(allWingGraphsScalesAct); WOppGraphMenu->addAction(resetWOppLegend); } } //Miarex Analysis Menu MiarexAnalysisMenu = menuBar()->addMenu(tr("&Analysis")); { MiarexAnalysisMenu->addAction(defineWPolar); MiarexAnalysisMenu->addAction(defineStabPolar); MiarexAnalysisMenu->addSeparator(); MiarexAnalysisMenu->addAction(viewLogFile); MiarexAnalysisMenu->addAction(advancedSettings); } //WOpp View Context Menu WOppCtxMenu = new QMenu(tr("Context Menu"),this); { WOppCtxMenu->addMenu(currentUFOMenu); WOppCtxMenu->addSeparator(); WOppCtxMenu->addMenu(curWPlrMenu); WOppCtxMenu->addSeparator(); WOppCtxMenu->addMenu(curWOppMenu); WOppCtxMenu->addSeparator(); WOppCtxMenu->addAction(showCurWOppOnly); WOppCtxMenu->addAction(showAllWOpps); WOppCtxMenu->addAction(hideAllWOpps); WOppCtxMenu->addAction(deleteAllWOpps); WOppCtxMenu->addSeparator(); WOppCurGraphMenu = WOppCtxMenu->addMenu(tr("Current Graph")); { WOppCurGraphMenu->addAction(MiarexGraphDlg); WOppCurGraphMenu->addAction(exportCurGraphAct); } WOppCtxMenu->addMenu(WOppCurGraphMenu); WOppCtxMenu->addMenu(WOppGraphMenu); WOppCtxMenu->addAction(ResetWingGraphScale); WOppCtxMenu->addSeparator(); WOppCtxMenu->addAction(halfWingAct); WOppCtxMenu->addAction(showEllipticCurve); WOppCtxMenu->addAction(showXCmRefLocation); WOppCtxMenu->addAction(showWing2Curve); WOppCtxMenu->addAction(showStabCurve); WOppCtxMenu->addAction(showFinCurve); WOppCtxMenu->addSeparator(); WOppCtxMenu->addAction(resetWingScale); WOppCtxMenu->addSeparator(); WOppCtxMenu->addAction(viewLogFile); WOppCtxMenu->addAction(saveViewToImageFileAct); } //WOpp View Context Menu WCpCtxMenu = new QMenu(tr("Context Menu"),this); { WCpCtxMenu->addMenu(currentUFOMenu); WCpCtxMenu->addSeparator(); WCpCtxMenu->addMenu(curWPlrMenu); WCpCtxMenu->addSeparator(); WCpCtxMenu->addMenu(curWOppMenu); WCpCtxMenu->addSeparator(); WCpCtxMenu->addMenu(WOppCurGraphMenu); WCpCtxMenu->addAction(ResetWingGraphScale); WCpCtxMenu->addSeparator(); WCpCtxMenu->addAction(showWing2Curve); WCpCtxMenu->addAction(showStabCurve); WCpCtxMenu->addAction(showFinCurve); WCpCtxMenu->addSeparator(); WCpCtxMenu->addAction(viewLogFile); WCpCtxMenu->addAction(saveViewToImageFileAct); } //WTime View Context Menu WTimeCtxMenu = new QMenu(tr("Context Menu"),this); { WTimeCtxMenu->addMenu(currentUFOMenu); WTimeCtxMenu->addSeparator(); WTimeCtxMenu->addMenu(curWPlrMenu); WTimeCtxMenu->addSeparator(); WTimeCtxMenu->addMenu(curWOppMenu); WTimeCtxMenu->addSeparator(); WTimeCtxMenu->addAction(showCurWOppOnly); WTimeCtxMenu->addAction(showAllWOpps); WTimeCtxMenu->addAction(hideAllWOpps); WTimeCtxMenu->addAction(deleteAllWOpps); WTimeCtxMenu->addSeparator(); WTimeCtxMenu->addMenu(WOppCurGraphMenu); WTimeCtxMenu->addMenu(WOppGraphMenu); WTimeCtxMenu->addSeparator(); WTimeCtxMenu->addAction(viewLogFile); WTimeCtxMenu->addAction(saveViewToImageFileAct); } //Polar View Context Menu WPlrCtxMenu = new QMenu(tr("Context Menu"),this); { WPlrCtxMenu->addMenu(currentUFOMenu); WPlrCtxMenu->addSeparator(); WPlrCtxMenu->addMenu(curWPlrMenu); WPlrCtxMenu->addSeparator(); WPlrCtxMenu->addMenu(WPlrGraphMenu); WPlrCurGraphMenu = WPlrCtxMenu->addMenu(tr("Current Graph")); { WPlrCurGraphMenu->addAction(MiarexGraphDlg); WPlrCurGraphMenu->addAction(exportCurGraphAct); } WPlrCtxMenu->addAction(resetCurGraphScales); WPlrCtxMenu->addSeparator(); WPlrCtxMenu->addAction(hideAllWPlrs); WPlrCtxMenu->addAction(showAllWPlrs); WPlrCtxMenu->addSeparator(); WPlrCtxMenu->addAction(viewLogFile); WPlrCtxMenu->addAction(saveViewToImageFileAct); } //W3D View Context Menu W3DCtxMenu = new QMenu(tr("Context Menu"),this); { W3DCtxMenu->addMenu(currentUFOMenu); W3DCtxMenu->addSeparator(); W3DCtxMenu->addMenu(curWPlrMenu); W3DCtxMenu->addSeparator(); W3DCtxMenu->addMenu(curWOppMenu); W3DCtxMenu->addSeparator(); W3DCtxMenu->addAction(deleteAllWOpps); W3DCtxMenu->addSeparator(); W3DCtxMenu->addAction(W3DScalesAct); W3DCtxMenu->addAction(W3DLightAct); W3DCtxMenu->addSeparator(); W3DCtxMenu->addAction(viewLogFile); W3DCtxMenu->addAction(saveViewToImageFileAct); } //W3D Stab View Context Menu W3DStabCtxMenu = new QMenu(tr("Context Menu"),this); { W3DStabCtxMenu->addMenu(currentUFOMenu); W3DStabCtxMenu->addSeparator(); W3DStabCtxMenu->addMenu(curWPlrMenu); W3DStabCtxMenu->addSeparator(); W3DStabCtxMenu->addMenu(curWOppMenu); W3DStabCtxMenu->addSeparator(); W3DStabCtxMenu->addAction(W3DLightAct); W3DStabCtxMenu->addSeparator(); W3DStabCtxMenu->addAction(viewLogFile); W3DStabCtxMenu->addAction(saveViewToImageFileAct); } } void MainFrame::CreateMiarexToolbar() { m_pctrlUFO = new QComboBox(); m_pctrlWPolar = new QComboBox; m_pctrlWOpp = new QComboBox; m_pctrlUFO->setMinimumWidth(150); m_pctrlWPolar->setMinimumWidth(150); m_pctrlWOpp->setMinimumWidth(80); m_pctrlUFO->setSizeAdjustPolicy(QComboBox::AdjustToContents); m_pctrlWPolar->setSizeAdjustPolicy(QComboBox::AdjustToContents); m_pctrlWOpp->setSizeAdjustPolicy(QComboBox::AdjustToContents); m_pctrlUFO->setMaxVisibleItems(23); m_pctrlWPolar->setMaxVisibleItems(23); m_pctrlWOpp->setMaxVisibleItems(23); m_pctrlMiarexToolBar = addToolBar(tr("UFO")); m_pctrlMiarexToolBar->addAction(newProjectAct); m_pctrlMiarexToolBar->addAction(openAct); m_pctrlMiarexToolBar->addAction(saveAct); m_pctrlMiarexToolBar->addSeparator(); m_pctrlMiarexToolBar->addAction(WOppAct); m_pctrlMiarexToolBar->addAction(WPolarAct); m_pctrlMiarexToolBar->addAction(W3DAct); m_pctrlMiarexToolBar->addAction(CpViewAct); m_pctrlMiarexToolBar->addAction(RootLocusAct); m_pctrlMiarexToolBar->addAction(StabTimeAct); m_pctrlMiarexToolBar->addSeparator(); m_pctrlMiarexToolBar->addWidget(m_pctrlUFO); m_pctrlMiarexToolBar->addWidget(m_pctrlWPolar); m_pctrlMiarexToolBar->addWidget(m_pctrlWOpp); connect(m_pctrlUFO, SIGNAL(activated(int)), this, SLOT(OnSelChangeUFO(int))); connect(m_pctrlWPolar, SIGNAL(activated(int)), this, SLOT(OnSelChangeWPolar(int))); connect(m_pctrlWOpp, SIGNAL(activated(int)), this, SLOT(OnSelChangeWOpp(int))); } void MainFrame::CreateStatusBar() { statusBar()->showMessage(tr("Ready")); m_pctrlProjectName = new QLabel(" "); m_pctrlProjectName->setMinimumWidth(200); statusBar()->addPermanentWidget(m_pctrlProjectName); } void MainFrame::CreateToolbars() { CreateXDirectToolbar(); CreateXInverseToolbar(); CreateMiarexToolbar(); CreateAFoilToolbar(); } void MainFrame::CreateXDirectToolbar() { m_pctrlFoil = new QComboBox; m_pctrlPolar = new QComboBox; m_pctrlOpPoint = new QComboBox; m_pctrlFoil->setMaxVisibleItems(23); m_pctrlPolar->setMaxVisibleItems(23); m_pctrlOpPoint->setMaxVisibleItems(23); m_pctrlFoil->setMinimumWidth(150); m_pctrlPolar->setMinimumWidth(150); m_pctrlOpPoint->setMinimumWidth(80); m_pctrlFoil->setSizeAdjustPolicy(QComboBox::AdjustToContents); m_pctrlPolar->setSizeAdjustPolicy(QComboBox::AdjustToContents); m_pctrlOpPoint->setSizeAdjustPolicy(QComboBox::AdjustToContents); m_pctrlXDirectToolBar = addToolBar(tr("Foil")); m_pctrlXDirectToolBar->addAction(newProjectAct); m_pctrlXDirectToolBar->addAction(openAct); m_pctrlXDirectToolBar->addAction(saveAct); m_pctrlXDirectToolBar->addSeparator(); m_pctrlXDirectToolBar->addAction(OpPointsAct); m_pctrlXDirectToolBar->addAction(PolarsAct); m_pctrlXDirectToolBar->addSeparator(); m_pctrlXDirectToolBar->addWidget(m_pctrlFoil); m_pctrlXDirectToolBar->addWidget(m_pctrlPolar); m_pctrlXDirectToolBar->addWidget(m_pctrlOpPoint); connect(m_pctrlFoil, SIGNAL(activated(int)), this, SLOT(OnSelChangeFoil(int))); connect(m_pctrlPolar, SIGNAL(activated(int)), this, SLOT(OnSelChangePolar(int))); connect(m_pctrlOpPoint, SIGNAL(activated(int)), this, SLOT(OnSelChangeOpp(int))); } void MainFrame::CreateXDirectActions() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; OpPointsAct = new QAction(QIcon(":/images/OnCpView.png"), tr("OpPoint view")+"\tF5", this); OpPointsAct->setCheckable(true); OpPointsAct->setStatusTip(tr("Show Operating point view")); connect(OpPointsAct, SIGNAL(triggered()), pXDirect, SLOT(OnOpPoints())); PolarsAct = new QAction(QIcon(":/images/OnPolarView.png"), tr("Polar view")+"\tF8", this); PolarsAct->setCheckable(true); PolarsAct->setStatusTip(tr("Show Polar view")); connect(PolarsAct, SIGNAL(triggered()), pXDirect, SLOT(OnPolars())); defineCpGraphSettings = new QAction(tr("Define Cp Graph Settings")+"\t(G)", this); connect(defineCpGraphSettings, SIGNAL(triggered()), pXDirect, SLOT(OnCpGraphSettings())); XDirectPolarFilter = new QAction(tr("Polar Filter"), this); connect(XDirectPolarFilter, SIGNAL(triggered()), pXDirect, SLOT(OnPolarFilter())); allPolarGraphsSettingsAct = new QAction(tr("All Polar Graph Settings"), this); allPolarGraphsSettingsAct->setStatusTip("Modifies the setting for all polar graphs simultaneously"); connect(allPolarGraphsSettingsAct, SIGNAL(triggered()), pXDirect, SLOT(OnAllPolarGraphsSetting())); allPolarGraphsScales = new QAction(tr("Reset All Polar Graph Scales"), this); connect(allPolarGraphsScales, SIGNAL(triggered()), pXDirect, SLOT(OnResetAllPolarGraphsScales())); XDirectGraphDlg = new QAction(tr("Define Graph Settings")+"\t(G)", this); connect(XDirectGraphDlg, SIGNAL(triggered()), pXDirect, SLOT(OnGraphSettings())); resetGraphLegend = new QAction(tr("Reset Legend Position"), this); connect(resetGraphLegend, SIGNAL(triggered()), pXDirect, SLOT(OnResetGraphLegend())); TwoPolarGraphsAct = new QAction(tr("Two Polar Graphs")+"\t(T)", this); TwoPolarGraphsAct->setCheckable(true); connect(TwoPolarGraphsAct, SIGNAL(triggered()), pXDirect, SLOT(OnCouplePolarGraphs())); AllPolarGraphsAct = new QAction(tr("All Polar Graphs")+"\t(A)", this); AllPolarGraphsAct->setCheckable(true); connect(AllPolarGraphsAct, SIGNAL(triggered()), pXDirect, SLOT(OnAllPolarGraphs())); for (int i = 0; i < 5; ++i) { PolarGraphAct[i] = new QAction(this); PolarGraphAct[i]->setData(i); PolarGraphAct[i]->setCheckable(true); connect(PolarGraphAct[i], SIGNAL(triggered()), pXDirect, SLOT(OnSinglePolarGraph())); } PolarGraphAct[0]->setText(tr("Cl vs. Cd") +"\t(1)"); PolarGraphAct[1]->setText(tr("Cl vs.Alpha")+ "\t(2)"); PolarGraphAct[2]->setText(tr("Cl vs. Xtr.")+ "\t(3)"); PolarGraphAct[3]->setText(tr("Cm vs.Alpha")+ "\t(4)"); PolarGraphAct[4]->setText(tr("Glide ratio vs. alpha")+ "\t(5)"); highlightOppAct = new QAction(tr("Highlight Current OpPoint")+"\t(Ctrl+H)", this); highlightOppAct->setCheckable(true); highlightOppAct->setStatusTip(tr("Highlights on the polar curve the currently selected operating point")); connect(highlightOppAct, SIGNAL(triggered()), pXDirect, SLOT(OnHighlightOpp())); deleteCurFoil = new QAction(tr("Delete..."), this); connect(deleteCurFoil, SIGNAL(triggered()), pXDirect, SLOT(OnDeleteCurFoil())); renameCurFoil = new QAction(tr("Rename...")+"\tF2", this); connect(renameCurFoil, SIGNAL(triggered()), this, SLOT(OnRenameCurFoil())); exportCurFoil = new QAction(tr("Export..."), this); connect(exportCurFoil, SIGNAL(triggered()), pXDirect, SLOT(OnExportCurFoil())); setCurFoilStyle = new QAction(tr("Set Style..."), this); connect(setCurFoilStyle, SIGNAL(triggered()), this, SLOT(OnCurFoilStyle())); deleteFoilPolars = new QAction(tr("Delete associated polars"), this); deleteFoilPolars->setStatusTip(tr("Delete all the polars associated to this foil")); connect(deleteFoilPolars, SIGNAL(triggered()), pXDirect, SLOT(OnDeleteFoilPolars())); showFoilPolarsOnly = new QAction(tr("Show only associated polars"), this); connect(showFoilPolarsOnly, SIGNAL(triggered()), pXDirect, SLOT(OnShowFoilPolarsOnly())); showFoilPolars = new QAction(tr("Show associated polars"), this); connect(showFoilPolars, SIGNAL(triggered()), pXDirect, SLOT(OnShowFoilPolars())); hideFoilPolars = new QAction(tr("Hide associated polars"), this); connect(hideFoilPolars, SIGNAL(triggered()), pXDirect, SLOT(OnHideFoilPolars())); saveFoilPolars = new QAction(tr("Save associated polars"), this); connect(saveFoilPolars, SIGNAL(triggered()), pXDirect, SLOT(OnSavePolars())); hidePolarOpps = new QAction(tr("Hide associated OpPoints"), this); connect(hidePolarOpps, SIGNAL(triggered()), pXDirect, SLOT(OnHidePolarOpps())); showPolarOpps = new QAction(tr("Show associated OpPoints"), this); connect(showPolarOpps, SIGNAL(triggered()), pXDirect, SLOT(OnShowPolarOpps())); deletePolarOpps = new QAction(tr("Delete associated OpPoints"), this); connect(deletePolarOpps, SIGNAL(triggered()), pXDirect, SLOT(OnDeletePolarOpps())); exportPolarOpps = new QAction(tr("Export associated OpPoints"), this); connect(exportPolarOpps, SIGNAL(triggered()), pXDirect, SLOT(OnExportPolarOpps())); hideFoilOpps = new QAction(tr("Hide associated OpPoints"), this); connect(hideFoilOpps, SIGNAL(triggered()), pXDirect, SLOT(OnHideFoilOpps())); showFoilOpps = new QAction(tr("Show associated OpPoints"), this); connect(showFoilOpps, SIGNAL(triggered()), pXDirect, SLOT(OnShowFoilOpps())); deleteFoilOpps = new QAction(tr("Delete associated OpPoints"), this); connect(deleteFoilOpps, SIGNAL(triggered()), pXDirect, SLOT(OnDeleteFoilOpps())); definePolar = new QAction(tr("Define an Analysis")+"\tF6", this); definePolar->setStatusTip(tr("Defines a single analysis/polar")); connect(definePolar, SIGNAL(triggered()), pXDirect, SLOT(OnDefinePolar())); defineBatch = new QAction(tr("Batch Analysis")+"\tShift+F6", this); defineBatch->setStatusTip(tr("Launches a batch of analysis calculation for a specified range or list of Reynolds numbers")); connect(defineBatch, SIGNAL(triggered()), pXDirect, SLOT(OnBatchAnalysis())); MultiThreadedBatchAct = new QAction(tr("Multi-threaded Batch Analysis")+"\tCtrl+F6", this); MultiThreadedBatchAct->setStatusTip(tr("Launches a batch of analysis calculation using all available computer CPU cores")); connect(MultiThreadedBatchAct, SIGNAL(triggered()), pXDirect, SLOT(OnMultiThreadedBatchAnalysis())); deletePolar = new QAction(tr("Delete"), this); deletePolar->setStatusTip(tr("Deletes the currently selected polar")); connect(deletePolar, SIGNAL(triggered()), pXDirect, SLOT(OnDeleteCurPolar())); resetCurPolar = new QAction(tr("Reset"), this); resetCurPolar->setStatusTip(tr("Deletes the contents of the currently selected polar")); connect(resetCurPolar, SIGNAL(triggered()), pXDirect, SLOT(OnResetCurPolar())); editCurPolar = new QAction(tr("Edit"), this); editCurPolar->setStatusTip(tr("Remove the unconverged or erroneaous points of the currently selected polar")); connect(editCurPolar, SIGNAL(triggered()), pXDirect, SLOT(OnEditCurPolar())); exportCurPolar = new QAction(tr("Export"), this); connect(exportCurPolar, SIGNAL(triggered()), pXDirect, SLOT(OnExportCurPolar())); exportAllPolars = new QAction(tr("Export all polars"), this); connect(exportAllPolars, SIGNAL(triggered()), pXDirect, SLOT(OnExportAllPolars())); XDirectStyleAct = new QAction(tr("Define Styles"), this); XDirectStyleAct->setStatusTip(tr("Define the style for the boundary layer and the pressure arrows")); connect(XDirectStyleAct, SIGNAL(triggered()), pXDirect, SLOT(OnXDirectStyle())); ManageFoilsAct = new QAction(tr("Manage Foils"), this); ManageFoilsAct->setShortcut(Qt::Key_F7); connect(ManageFoilsAct, SIGNAL(triggered()), pXDirect, SLOT(OnManageFoils())); RenamePolarAct = new QAction(tr("Rename"), this); connect(RenamePolarAct, SIGNAL(triggered()), pXDirect, SLOT(OnRenamePolar())); showPanels = new QAction(tr("Show Panels"), this); showPanels->setCheckable(true); showPanels->setStatusTip(tr("Show the foil's panels")); connect(showPanels, SIGNAL(triggered()), pXDirect, SLOT(OnShowPanels())); resetFoilScale = new QAction(tr("Reset Foil Scale"), this); resetFoilScale->setStatusTip(tr("Resets the foil's scale to original size")); connect(resetFoilScale, SIGNAL(triggered()), pXDirect, SLOT(OnResetFoilScale())); showInviscidCurve = new QAction(tr("Show Inviscid Curve"), this); showInviscidCurve->setCheckable(true); showInviscidCurve->setStatusTip(tr("Display the Opp's inviscid curve")); connect(showInviscidCurve, SIGNAL(triggered()), pXDirect, SLOT(OnCpi())); showNeutralLine = new QAction(tr("Neutral Line"), this); showNeutralLine->setCheckable(true); connect(showNeutralLine, SIGNAL(triggered()), pXDirect, SLOT(OnShowNeutralLine())); showAllPolars = new QAction(tr("Show All Polars"), this); connect(showAllPolars, SIGNAL(triggered()), pXDirect, SLOT(OnShowAllPolars())); hideAllPolars = new QAction(tr("Hide All Polars"), this); connect(hideAllPolars, SIGNAL(triggered()), pXDirect, SLOT(OnHideAllPolars())); showCurOppOnly = new QAction(tr("Show Current Opp Only"), this); showCurOppOnly->setCheckable(true); connect(showCurOppOnly, SIGNAL(triggered()), pXDirect, SLOT(OnCurOppOnly())); showAllOpPoints = new QAction(tr("Show All Opps"), this); connect(showAllOpPoints, SIGNAL(triggered()), pXDirect, SLOT(OnShowAllOpps())); hideAllOpPoints = new QAction(tr("Hide All Opps"), this); connect(hideAllOpPoints, SIGNAL(triggered()), pXDirect, SLOT(OnHideAllOpps())); exportCurOpp = new QAction(tr("Export"), this); connect(exportCurOpp, SIGNAL(triggered()), pXDirect, SLOT(OnExportCurOpp())); deleteCurOpp = new QAction(tr("Delete"), this); connect(deleteCurOpp, SIGNAL(triggered()), pXDirect, SLOT(OnDelCurOpp())); resetXFoil = new QAction(tr("Reset XFoil"), this); connect(resetXFoil, SIGNAL(triggered()), pXDirect, SLOT(OnResetXFoil())); viewXFoilAdvanced = new QAction(tr("XFoil Advanced Settings"), this); defineBatch->setStatusTip(tr("Tip : you don't want to use that option...")); connect(viewXFoilAdvanced, SIGNAL(triggered()), pXDirect, SLOT(OnXFoilAdvanced())); viewLogFile = new QAction(tr("View Log File")+"\t(L)", this); connect(viewLogFile, SIGNAL(triggered()), this, SLOT(OnLogFile())); DerotateFoil = new QAction(tr("De-rotate the Foil"), this); connect(DerotateFoil, SIGNAL(triggered()), pXDirect, SLOT(OnDerotateFoil())); NormalizeFoil = new QAction(tr("Normalize the Foil"), this); connect(NormalizeFoil, SIGNAL(triggered()), pXDirect, SLOT(OnNormalizeFoil())); RefineLocalFoil = new QAction(tr("Refine Locally")+"\t(Shift+F3)", this); connect(RefineLocalFoil, SIGNAL(triggered()), pXDirect, SLOT(OnCadd())); RefineGlobalFoil = new QAction(tr("Refine Globally")+"\t(F3)", this); connect(RefineGlobalFoil, SIGNAL(triggered()), pXDirect, SLOT(OnRefinePanelsGlobally())); EditCoordsFoil = new QAction(tr("Edit Foil Coordinates"), this); connect(EditCoordsFoil, SIGNAL(triggered()), pXDirect, SLOT(OnFoilCoordinates())); ScaleFoil = new QAction(tr("Scale camber and thickness")+"\t(F9)", this); connect(ScaleFoil, SIGNAL(triggered()), pXDirect, SLOT(OnFoilGeom())); SetTEGap = new QAction(tr("Set T.E. Gap"), this); connect(SetTEGap, SIGNAL(triggered()), pXDirect, SLOT(OnSetTEGap())); SetLERadius = new QAction(tr("Set L.E. Radius"), this); connect(SetLERadius, SIGNAL(triggered()), pXDirect, SLOT(OnSetLERadius())); SetFlap = new QAction(tr("Set Flap")+"\t(F10)", this); connect(SetFlap, SIGNAL(triggered()), pXDirect, SLOT(OnSetFlap())); InterpolateFoils = new QAction(tr("Interpolate Foils")+"\t(F11)", this); connect(InterpolateFoils, SIGNAL(triggered()), pXDirect, SLOT(OnInterpolateFoils())); NacaFoils = new QAction(tr("Naca Foils"), this); connect(NacaFoils, SIGNAL(triggered()), pXDirect, SLOT(OnNacaFoils())); DuplicateFoil = new QAction(tr("Duplicate"), this); connect(DuplicateFoil, SIGNAL(triggered()), this, SLOT(OnDuplicateFoil())); setCpVarGraph = new QAction(tr("Cp Variable"), this); setCpVarGraph->setCheckable(true); setCpVarGraph->setStatusTip(tr("Sets Cp vs. chord graph")); connect(setCpVarGraph, SIGNAL(triggered()), pXDirect, SLOT(OnCpGraph())); setQVarGraph = new QAction(tr("Q Variable"), this); setQVarGraph->setCheckable(true); setQVarGraph->setStatusTip(tr("Sets Speed vs. chord graph")); connect(setQVarGraph, SIGNAL(triggered()), pXDirect, SLOT(OnQGraph())); CurXFoilResExport = new QAction(tr("Export Cur. XFoil Results"), this); CurXFoilResExport->setStatusTip(tr("Sets Speed vs. chord graph")); connect(CurXFoilResExport, SIGNAL(triggered()), pXDirect, SLOT(OnExportCurXFoilResults())); CurXFoilCtPlot = new QAction(tr("Max. Shear Coefficient"), this); CurXFoilCtPlot->setCheckable(true); connect(CurXFoilCtPlot, SIGNAL(triggered()), pXDirect, SLOT(OnCtPlot())); CurXFoilDbPlot = new QAction(tr("Bottom Side D* and Theta"), this); CurXFoilDbPlot->setCheckable(true); connect(CurXFoilDbPlot, SIGNAL(triggered()), pXDirect, SLOT(OnDbPlot())); CurXFoilDtPlot = new QAction(tr("Top Side D* and Theta"), this); CurXFoilDtPlot->setCheckable(true); connect(CurXFoilDtPlot, SIGNAL(triggered()), pXDirect, SLOT(OnDtPlot())); CurXFoilRtLPlot = new QAction(tr("Log(Re_Theta)"), this); CurXFoilRtLPlot->setCheckable(true); connect(CurXFoilRtLPlot, SIGNAL(triggered()), pXDirect, SLOT(OnRtLPlot())); CurXFoilRtPlot = new QAction(tr("Re_Theta"), this); CurXFoilRtPlot->setCheckable(true); connect(CurXFoilRtPlot, SIGNAL(triggered()), pXDirect, SLOT(OnRtPlot())); CurXFoilNPlot = new QAction(tr("Amplification Ratio"), this); CurXFoilNPlot->setCheckable(true); connect(CurXFoilNPlot, SIGNAL(triggered()), pXDirect, SLOT(OnNPlot())); CurXFoilCdPlot = new QAction(tr("Dissipation Coefficient"), this); CurXFoilCdPlot->setCheckable(true); connect(CurXFoilCdPlot, SIGNAL(triggered()), pXDirect, SLOT(OnCdPlot())); CurXFoilCfPlot = new QAction(tr("Skin Friction Coefficient"), this); CurXFoilCfPlot->setCheckable(true); connect(CurXFoilCfPlot, SIGNAL(triggered()), pXDirect, SLOT(OnCfPlot())); CurXFoilUePlot = new QAction(tr("Edge Velocity"), this); CurXFoilUePlot->setCheckable(true); connect(CurXFoilUePlot, SIGNAL(triggered()), pXDirect, SLOT(OnUePlot())); CurXFoilHPlot = new QAction(tr("Kinematic Shape Parameter"), this); CurXFoilHPlot->setCheckable(true); connect(CurXFoilHPlot, SIGNAL(triggered()), pXDirect, SLOT(OnHPlot())); // m_pImportJavaFoilPolar = new QAction(tr("Import JavaFoil Polar"), this); // connect(m_pImportJavaFoilPolar, SIGNAL(triggered()), pXDirect, SLOT(OnImportJavaFoilPolar())); m_pImportXFoilPolar = new QAction(tr("Import XFoil Polar"), this); connect(m_pImportXFoilPolar, SIGNAL(triggered()), pXDirect, SLOT(OnImportXFoilPolar())); } void MainFrame::CreateXDirectMenus() { //MainMenu for XDirect Application XDirectViewMenu = menuBar()->addMenu(tr("&View")); XDirectViewMenu->addAction(OpPointsAct); XDirectViewMenu->addAction(PolarsAct); XDirectViewMenu->addSeparator(); XDirectViewMenu->addAction(saveViewToImageFileAct); FoilMenu = menuBar()->addMenu(tr("&Foil")); FoilMenu->addAction(ManageFoilsAct); FoilMenu->addSeparator(); currentFoilMenu = FoilMenu->addMenu(tr("Current Foil")); currentFoilMenu->addAction(setCurFoilStyle); currentFoilMenu->addSeparator(); currentFoilMenu->addAction(exportCurFoil); currentFoilMenu->addAction(renameCurFoil); currentFoilMenu->addAction(deleteCurFoil); currentFoilMenu->addAction(DuplicateFoil); currentFoilMenu->addSeparator(); currentFoilMenu->addAction(showFoilPolarsOnly); currentFoilMenu->addAction(showFoilPolars); currentFoilMenu->addAction(hideFoilPolars); currentFoilMenu->addAction(deleteFoilPolars); currentFoilMenu->addAction(saveFoilPolars); currentFoilMenu->addSeparator(); currentFoilMenu->addAction(showFoilOpps); currentFoilMenu->addAction(hideFoilOpps); currentFoilMenu->addAction(deleteFoilOpps); FoilMenu->addSeparator(); FoilMenu->addAction(resetFoilScale); FoilMenu->addAction(showPanels); FoilMenu->addAction(showNeutralLine); FoilMenu->addAction(XDirectStyleAct); DesignMenu = menuBar()->addMenu(tr("&Design")); DesignMenu->addAction(NormalizeFoil); DesignMenu->addAction(DerotateFoil); DesignMenu->addAction(RefineGlobalFoil); DesignMenu->addAction(RefineLocalFoil); DesignMenu->addAction(EditCoordsFoil); DesignMenu->addAction(ScaleFoil); DesignMenu->addAction(SetTEGap); DesignMenu->addAction(SetLERadius); DesignMenu->addAction(SetFlap); DesignMenu->addSeparator(); DesignMenu->addAction(InterpolateFoils); DesignMenu->addAction(NacaFoils); XFoilAnalysisMenu = menuBar()->addMenu(tr("Analysis")); XFoilAnalysisMenu->addAction(definePolar); XFoilAnalysisMenu->addAction(defineBatch); XFoilAnalysisMenu->addAction(MultiThreadedBatchAct); XFoilAnalysisMenu->addSeparator(); XFoilAnalysisMenu->addAction(resetXFoil); XFoilAnalysisMenu->addAction(viewXFoilAdvanced); XFoilAnalysisMenu->addAction(viewLogFile); PolarMenu = menuBar()->addMenu(tr("&Polars")); currentPolarMenu = PolarMenu->addMenu(tr("Current Polar")); currentPolarMenu->addAction(ShowPolarProps); currentPolarMenu->addAction(editCurPolar); currentPolarMenu->addAction(resetCurPolar); currentPolarMenu->addAction(deletePolar); currentPolarMenu->addAction(RenamePolarAct); currentPolarMenu->addAction(exportCurPolar); currentPolarMenu->addSeparator(); currentPolarMenu->addAction(showPolarOpps); currentPolarMenu->addAction(hidePolarOpps); currentPolarMenu->addAction(deletePolarOpps); currentPolarMenu->addAction(exportPolarOpps); PolarMenu->addSeparator(); PolarMenu->addAction(m_pImportXFoilPolar); // PolarMenu->addAction(m_pImportJavaFoilPolar); PolarMenu->addSeparator(); PolarMenu->addAction(exportAllPolars); PolarMenu->addSeparator(); PolarMenu->addAction(XDirectPolarFilter); PolarMenu->addSeparator(); PolarMenu->addAction(showAllPolars); PolarMenu->addAction(hideAllPolars); PolarMenu->addSeparator(); GraphPolarMenu = PolarMenu->addMenu(tr("Polar Graphs")); GraphPolarMenu->addAction(allPolarGraphsSettingsAct); GraphPolarMenu->addAction(allPolarGraphsScales); GraphPolarMenu->addAction(resetGraphLegend); GraphPolarMenu->addSeparator(); GraphPolarMenu->addAction(AllPolarGraphsAct); GraphPolarMenu->addAction(TwoPolarGraphsAct); GraphPolarMenu->addSeparator(); for(int i=0; i<5; i++) GraphPolarMenu->addAction(PolarGraphAct[i]); GraphPolarMenu->addSeparator(); GraphPolarMenu->addAction(highlightOppAct); OpPointMenu = menuBar()->addMenu(tr("Operating Points")); currentOppMenu = OpPointMenu->addMenu(tr("Current OpPoint")); currentOppMenu->addAction(ShowWOppProps); currentOppMenu->addAction(exportCurOpp); currentOppMenu->addAction(deleteCurOpp); CpGraphMenu = OpPointMenu->addMenu(tr("Cp Graph")); CpGraphMenu->addAction(setCpVarGraph); CpGraphMenu->addAction(setQVarGraph); CpGraphMenu->addSeparator(); CpGraphMenu->addAction(showInviscidCurve); CpGraphMenu->addSeparator(); CurXFoilResults = CpGraphMenu->addMenu(tr("Current XFoil Results")); CurXFoilResults->addAction(CurXFoilResExport); CurXFoilResults->addSeparator(); CurXFoilResults->addAction(CurXFoilCtPlot); CurXFoilResults->addAction(CurXFoilDbPlot); CurXFoilResults->addAction(CurXFoilDtPlot); CurXFoilResults->addAction(CurXFoilRtLPlot); CurXFoilResults->addAction(CurXFoilRtPlot); CurXFoilResults->addAction(CurXFoilNPlot); CurXFoilResults->addAction(CurXFoilCdPlot); CurXFoilResults->addAction(CurXFoilCfPlot); CurXFoilResults->addAction(CurXFoilUePlot); CurXFoilResults->addAction(CurXFoilHPlot); CpGraphMenu->addSeparator(); CpGraphMenu->addAction(resetCurGraphScales); CpGraphMenu->addAction(defineCpGraphSettings); CpGraphMenu->addAction(exportCurGraphAct); OpPointMenu->addSeparator(); OpPointMenu->addAction(showCurOppOnly); OpPointMenu->addAction(hideAllOpPoints); OpPointMenu->addAction(showAllOpPoints); //XDirect foil Context Menu OperFoilCtxMenu = new QMenu(tr("Context Menu"),this); OperFoilCtxMenu->addMenu(currentFoilMenu); OperFoilCtxMenu->addSeparator();//_______________ OperFoilCtxMenu->addMenu(currentPolarMenu); OperFoilCtxMenu->addSeparator();//_______________ OperFoilCtxMenu->addMenu(DesignMenu); OperFoilCtxMenu->addSeparator();//_______________ CurOppCtxMenu = OperFoilCtxMenu->addMenu(tr("Current OpPoint")); CurOppCtxMenu->addAction(ShowWOppProps); CurOppCtxMenu->addAction(exportCurOpp); CurOppCtxMenu->addAction(deleteCurOpp); OperFoilCtxMenu->addSeparator();//_______________ // CurGraphCtxMenu = OperFoilCtxMenu->addMenu(tr("Cp graph")); OperFoilCtxMenu->addMenu(CpGraphMenu); OperFoilCtxMenu->addSeparator();//_______________ OperFoilCtxMenu->addAction(definePolar); OperFoilCtxMenu->addAction(defineBatch); OperFoilCtxMenu->addAction(MultiThreadedBatchAct); OperFoilCtxMenu->addSeparator();//_______________ OperFoilCtxMenu->addAction(showAllPolars); OperFoilCtxMenu->addAction(hideAllPolars); OperFoilCtxMenu->addSeparator();//_______________ OperFoilCtxMenu->addAction(showCurOppOnly); OperFoilCtxMenu->addAction(showAllOpPoints); OperFoilCtxMenu->addAction(hideAllOpPoints); OperFoilCtxMenu->addSeparator();//_______________ OperFoilCtxMenu->addAction(resetFoilScale); OperFoilCtxMenu->addAction(showPanels); OperFoilCtxMenu->addAction(showNeutralLine); OperFoilCtxMenu->addAction(XDirectStyleAct); OperFoilCtxMenu->addSeparator();//_______________ OperFoilCtxMenu->addAction(saveViewToImageFileAct); //End XDirect foil Context Menu //XDirect polar Context Menu OperPolarCtxMenu = new QMenu(tr("Context Menu"),this); OperPolarCtxMenu->addMenu(currentFoilMenu); OperPolarCtxMenu->addMenu(currentPolarMenu); OperPolarCtxMenu->addSeparator();//_______________ CurGraphCtxMenu = OperPolarCtxMenu->addMenu(tr("Current Graph")); CurGraphCtxMenu->addAction(resetCurGraphScales); CurGraphCtxMenu->addAction(XDirectGraphDlg); CurGraphCtxMenu->addAction(exportCurGraphAct); OperPolarCtxMenu->addSeparator();//_______________ OperPolarCtxMenu->addMenu(GraphPolarMenu); OperPolarCtxMenu->addSeparator();//_______________ OperPolarCtxMenu->addAction(definePolar); OperPolarCtxMenu->addAction(defineBatch); OperPolarCtxMenu->addAction(MultiThreadedBatchAct); OperPolarCtxMenu->addSeparator();//_______________ OperPolarCtxMenu->addAction(showAllPolars); OperPolarCtxMenu->addAction(hideAllPolars); OperPolarCtxMenu->addAction(showAllOpPoints); OperPolarCtxMenu->addAction(hideAllOpPoints); OperPolarCtxMenu->addSeparator();//_______________ OperPolarCtxMenu->addAction(saveViewToImageFileAct); //End XDirect polar Context Menu } void MainFrame::CreateXInverseActions() { QXInverse *pXInverse = (QXInverse*)m_pXInverse; StoreFoil = new QAction(QIcon(":/images/OnStoreFoil.png"), tr("Store Foil"), this); StoreFoil->setStatusTip(tr("Store Foil in database")); connect(StoreFoil, SIGNAL(triggered()), pXInverse, SLOT(OnStoreFoil())); ExtractFoil = new QAction(QIcon(":/images/OnExtractFoil.png"),tr("Extract Foil"), this); ExtractFoil->setStatusTip(tr("Extract a Foil from the database for modification")); connect(ExtractFoil, SIGNAL(triggered()), pXInverse, SLOT(OnExtractFoil())); InverseStyles = new QAction(tr("Define Styles"), this); InverseStyles->setStatusTip(tr("Define the styles for this view")); connect(InverseStyles, SIGNAL(triggered()), pXInverse, SLOT(OnInverseStyles())); InverseResetScale = new QAction(QIcon(":/images/OnResetFoilScale.png"), tr("Reset foil scale")+"\t(R)", this); InverseResetScale->setStatusTip(tr("Resets the scale to fit the screen size")); connect(InverseResetScale, SIGNAL(triggered()), pXInverse, SLOT(OnResetFoilScale())); InverseInsertCtrlPt = new QAction(tr("Insert Control Point")+"\tShift+Click", this); connect(InverseInsertCtrlPt, SIGNAL(triggered()), pXInverse, SLOT(OnInsertCtrlPt())); InverseRemoveCtrlPt = new QAction(tr("Remove Control Point")+"\tCtrl+Click", this); connect(InverseRemoveCtrlPt, SIGNAL(triggered()), pXInverse, SLOT(OnRemoveCtrlPt())); InvQInitial = new QAction(tr("Show Q-Initial"), this); InvQInitial->setCheckable(true); connect(InvQInitial, SIGNAL(triggered()), pXInverse, SLOT(OnQInitial())); InvQSpec = new QAction(tr("Show Q-Spec"), this); InvQSpec->setCheckable(true); connect(InvQSpec, SIGNAL(triggered()), pXInverse, SLOT(OnQSpec())); InvQViscous = new QAction(tr("Show Q-Viscous"), this); InvQViscous->setCheckable(true); connect(InvQViscous, SIGNAL(triggered()), pXInverse, SLOT(OnQViscous())); InvQPoints = new QAction(tr("Show Points"), this); InvQPoints->setCheckable(true); connect(InvQPoints, SIGNAL(triggered()), pXInverse, SLOT(OnQPoints())); InvQReflected = new QAction(tr("Show Reflected"), this); InvQReflected->setCheckable(true); connect(InvQReflected, SIGNAL(triggered()), pXInverse, SLOT(OnQReflected())); XInverseGraphDlg = new QAction(tr("Define Graph Settings")+"\t(G)", this); connect(XInverseGraphDlg, SIGNAL(triggered()), pXInverse, SLOT(OnGraphSettings())); InverseZoomIn = new QAction(QIcon(":/images/OnZoomIn.png"), tr("Zoom in"), this); InverseZoomIn->setStatusTip(tr("Zoom the view by drawing a rectangle in the client area")); connect(InverseZoomIn, SIGNAL(triggered()), pXInverse, SLOT(OnZoomIn())); InverseZoomX = new QAction(QIcon(":/images/OnZoomGraphX.png"), tr("Zoom X Scale"), this); InverseZoomX->setStatusTip(tr("Zoom X Scale Only")); connect(InverseZoomX, SIGNAL(triggered()), pXInverse, SLOT(OnZoomX())); InverseZoomY = new QAction(QIcon(":/images/OnZoomGraphY.png"), tr("Zoom Y Scale"), this); InverseZoomY->setStatusTip(tr("Zoom Y Scale Only")); connect(InverseZoomY, SIGNAL(triggered()), pXInverse, SLOT(OnZoomY())); } void MainFrame::CreateXInverseMenus() { //MainMenu for XInverse Application XInverseViewMenu = menuBar()->addMenu(tr("&View")); XInverseViewMenu->addAction(InverseStyles); XInverseViewMenu->addAction(XInverseGraphDlg); XInverseViewMenu->addSeparator(); XInverseViewMenu->addAction(saveViewToImageFileAct); InverseGraphMenu = menuBar()->addMenu(tr("&Graph")); InverseGraphMenu->addAction(XInverseGraphDlg); InverseGraphMenu->addAction(resetCurGraphScales); InverseGraphMenu->addAction(exportCurGraphAct); InverseFoilMenu = menuBar()->addMenu(tr("&Foil")); InverseFoilMenu->addAction(StoreFoil); InverseFoilMenu->addAction(ExtractFoil); InverseFoilMenu->addAction(InverseResetScale); InverseFoilMenu->addSeparator(); InverseFoilMenu->addAction(InvQInitial); InverseFoilMenu->addAction(InvQSpec); InverseFoilMenu->addAction(InvQViscous); InverseFoilMenu->addAction(InvQPoints); InverseFoilMenu->addAction(InvQReflected); //Context Menu for XInverse Application InverseContextMenu = new QMenu(tr("Context Menu"),this); InverseContextMenu->addAction(InverseStyles); InverseContextMenu->addAction(InverseResetScale); InverseContextMenu->addAction(resetCurGraphScales); InverseContextMenu->addAction(XInverseGraphDlg); InverseContextMenu->addSeparator(); InverseContextMenu->addAction(InverseInsertCtrlPt); InverseContextMenu->addAction(InverseRemoveCtrlPt); InverseContextMenu->addSeparator(); InverseContextMenu->addAction(InvQInitial); InverseContextMenu->addAction(InvQSpec); InverseContextMenu->addAction(InvQViscous); InverseContextMenu->addAction(InvQPoints); InverseContextMenu->addAction(InvQReflected); } void MainFrame::CreateXInverseToolbar() { m_pctrlFullInverse = new QRadioButton(tr("Full Inverse")); m_pctrlMixedInverse = new QRadioButton(tr("Mixed Inverse")); QXInverse *pXInverse = (QXInverse*)m_pXInverse; connect(m_pctrlFullInverse, SIGNAL(clicked()), pXInverse, SLOT(OnInverseApp())); connect(m_pctrlMixedInverse, SIGNAL(clicked()), pXInverse, SLOT(OnInverseApp())); m_pctrlXInverseToolBar = addToolBar(tr("XInverse")); m_pctrlXInverseToolBar->addAction(newProjectAct); m_pctrlXInverseToolBar->addAction(openAct); m_pctrlXInverseToolBar->addAction(saveAct); m_pctrlXInverseToolBar->addSeparator(); m_pctrlXInverseToolBar->addWidget(m_pctrlFullInverse); m_pctrlXInverseToolBar->addWidget(m_pctrlMixedInverse); m_pctrlXInverseToolBar->addSeparator(); m_pctrlXInverseToolBar->addAction(ExtractFoil); m_pctrlXInverseToolBar->addAction(StoreFoil); m_pctrlXInverseToolBar->addSeparator(); m_pctrlXInverseToolBar->addAction(InverseZoomIn); m_pctrlXInverseToolBar->addAction(InverseZoomX); m_pctrlXInverseToolBar->addAction(InverseZoomY); m_pctrlXInverseToolBar->addAction(resetCurGraphScales); m_pctrlXInverseToolBar->addAction(InverseResetScale); } Foil* MainFrame::DeleteFoil(Foil *pFoil, bool bAsk) { QXDirect *pXDirect = (QXDirect*)m_pXDirect; if(!pFoil || !pFoil->m_FoilName.length()) return NULL; QString strong; Foil *pOldFoil, *pNextFoil=NULL; OpPoint * pOpPoint; Polar* pPolar; int j; if(bAsk) { strong = tr("Are you sure you want to delete") +"\n"+ pFoil->m_FoilName +"\n"; strong+= tr("and all associated OpPoints and Polars ?"); int resp = QMessageBox::question(this,tr("Question"), strong, QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); if(resp != QMessageBox::Yes) return NULL; } for (j= m_oaOpp.size()-1; j>=0; j--) { pOpPoint = (OpPoint*)m_oaOpp[j]; if(pOpPoint->m_strFoilName == pFoil->m_FoilName) { m_oaOpp.removeAt(j); delete pOpPoint; } } for (j= s_oaPolar.size()-1;j>=0; j--) { pPolar = (Polar*)s_oaPolar.at(j); if(pPolar->m_FoilName == pFoil->m_FoilName) { s_oaPolar.removeAt(j); delete pPolar; } } for (j=0; j< s_oaFoil.size(); j++) { pOldFoil = (Foil*)s_oaFoil.at(j); if (pOldFoil == pFoil) { if(j>0) pNextFoil = (Foil*)s_oaFoil.at(j-1); else if(s_oaFoil.size()>1) pNextFoil = (Foil*)s_oaFoil.at(1); else pNextFoil = NULL; s_oaFoil.removeAt(j); delete pOldFoil; if(s_pCurFoil == pOldFoil) s_pCurFoil = NULL; break; } } pXDirect->m_pCurOpp = NULL; pXDirect->m_pCurPolar = NULL; s_pCurFoil = NULL; pXDirect->SetControls(); SetSaveState(false); return pNextFoil; } void MainFrame::DeletePlane(void *pPlanePtr, bool bResultsOnly) { Plane *pPlane = (Plane*)pPlanePtr; if(!pPlane || !pPlane->PlaneName().length()) return ; QMiarex *pMiarex = (QMiarex*)m_pMiarex; WPolar* pWPolar; PlaneOpp * pPOpp; Plane *pOldPlane; SetSaveState(false); int i; //first remove all POpps associated to the plane for (i=m_oaPOpp.size()-1; i>=0; i--) { pPOpp = (PlaneOpp*)m_oaPOpp.at(i); if(pPOpp->m_PlaneName == pPlane->PlaneName()) { m_oaPOpp.removeAt(i); delete pPOpp; } } pMiarex->m_pCurPOpp = NULL; pMiarex->m_pCurWOpp = NULL; //next remove all PPolars associated to the plane for (i=m_oaWPolar.size()-1; i>=0; i--) { pWPolar = (WPolar*)m_oaWPolar.at(i); if (pWPolar->m_UFOName == pPlane->PlaneName()) { if(!bResultsOnly) { m_oaWPolar.removeAt(i); if(pWPolar == pMiarex->m_pCurWPolar) { pMiarex->m_pCurWPolar = NULL; } delete pWPolar; } else { pWPolar->ResetWPlr(); //results only... means that the areas and spans have been edited... update polar if( pWPolar->m_RefAreaType==PLANFORMAREA) { pWPolar->m_WArea = pMiarex->m_pCurWing->m_PlanformArea; pWPolar->m_WSpan = pMiarex->m_pCurWing->m_PlanformSpan; } else { pWPolar->m_WArea = pMiarex->m_pCurWing->m_ProjectedArea; pWPolar->m_WSpan = pMiarex->m_pCurWing->m_ProjectedSpan; } pWPolar->m_WMAChord = pMiarex->m_pCurWing->m_MAChord; } } } if(bResultsOnly) return; for (i=s_oaPlane.size()-1; i>=0; i--) { pOldPlane = (Plane*)s_oaPlane.at(i); if (pOldPlane == pPlane) { s_oaPlane.removeAt(i); delete pPlane; if(pPlane == pMiarex->m_pCurPlane) { pMiarex->m_pCurPlane = NULL; pMiarex->m_pCurWing = NULL; for(int iw=0; iwm_pWingList[iw] = NULL; } break; } } } void MainFrame::DeleteProject(bool bClosing) { // clear everything int i; void *pObj; for (i=s_oaPlane.size()-1; i>=0; i--) { pObj = s_oaPlane.at(i); s_oaPlane.removeAt(i); delete (Plane*)pObj; } for (i=m_oaPOpp.size()-1; i>=0; i--) { pObj = m_oaPOpp.at(i); m_oaPOpp.removeAt(i); delete (PlaneOpp*)pObj; } for (i=s_oaWing.size()-1; i>=0; i--) { pObj = s_oaWing.at(i); s_oaWing.removeAt(i); delete (Wing*)pObj; } for (i=m_oaWPolar.size()-1; i>=0; i--) { pObj = m_oaWPolar.at(i); m_oaWPolar.removeAt(i); delete (WPolar*)pObj; } for (i=m_oaWOpp.size()-1; i>=0; i--) { pObj = m_oaWOpp.at(i); m_oaWOpp.removeAt(i); delete (WingOpp*)pObj; } for (i=s_oaFoil.size()-1; i>=0; i--) { pObj = s_oaFoil.at(i); s_oaFoil.removeAt(i); delete (Foil*)pObj; } for (i=s_oaPolar.size()-1; i>=0; i--) { pObj = s_oaPolar.at(i); s_oaPolar.removeAt(i); delete (Polar*)pObj; } for (i=m_oaOpp.size()-1; i>=0; i--) { pObj = m_oaOpp.at(i); m_oaOpp.removeAt(i); delete (OpPoint*)pObj; } for (i=s_oaBody.size()-1; i>=0; i--) { pObj = s_oaBody.at(i); s_oaBody.removeAt(i); delete (Body*)pObj; } QMiarex * pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_pCurPlane = NULL; pMiarex->m_pCurPOpp = NULL; pMiarex->m_pCurWing = NULL; pMiarex->m_pCurWPolar = NULL; pMiarex->m_pCurWOpp = NULL; pMiarex->m_bStream = false; if(!bClosing) { UpdateUFOs(); pMiarex->SetUFO(); if(pMiarex->m_iView==WPOLARVIEW) pMiarex->CreateWPolarCurves(); else if(pMiarex->m_iView==WOPPVIEW) pMiarex->CreateWOppCurves(); else if(pMiarex->m_iView==WCPVIEW) pMiarex->CreateCpCurves(); if(m_iApp==MIAREX) pMiarex->SetControls(); QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->m_pXFoil->m_FoilName = ""; s_pCurFoil = NULL; pXDirect->m_pCurPolar = NULL; pXDirect->m_pCurOpp = NULL; pXDirect->SetFoil(); UpdateFoils(); if(pXDirect->m_bPolarView) pXDirect->CreatePolarCurves(); else pXDirect->CreateOppCurves(); QAFoil *pAFoil = (QAFoil*)m_pAFoil; pAFoil->FillFoilTable(); pAFoil->SelectFoil(); QXInverse *pXInverse =(QXInverse*)m_pXInverse; pXInverse->Clear(); SetProjectName(""); SetSaveState(true); } } void MainFrame::DeleteWing(void *pWingPtr, bool bResultsOnly) { int i; QMiarex *pMiarex = (QMiarex*)m_pMiarex; if(!pWingPtr) return; Wing *pThisWing = (Wing*)pWingPtr; SetSaveState(false); //first remove all WOpps associated to the wing WingOpp * pWOpp; for (i=m_oaWOpp.size()-1; i>=0; i--) { pWOpp = (WingOpp*)m_oaWOpp.at(i); if(pWOpp->m_WingName == pThisWing->m_WingName) { m_oaWOpp.removeAt(i); if(pWOpp == pMiarex->m_pCurWOpp) pMiarex->m_pCurWOpp = NULL; delete pWOpp; } pMiarex->m_pCurWOpp = NULL; } //next remove all WPolars associated to the wing WPolar* pWPolar; for (i=m_oaWPolar.size()-1; i>=0; i--) { pWPolar = (WPolar*)m_oaWPolar.at(i); if (pWPolar->m_UFOName == pThisWing->m_WingName) { if(!bResultsOnly) { m_oaWPolar.removeAt(i); if(pWPolar == pMiarex->m_pCurWPolar) { pMiarex->m_pCurWPolar = NULL; } delete pWPolar; } else { pWPolar->ResetWPlr(); //results only... means that the geometry have been edited... update polar if( pWPolar->m_RefAreaType==PLANFORMAREA) { pWPolar->m_WArea = pMiarex->m_pCurWing->m_PlanformArea; pWPolar->m_WSpan = pMiarex->m_pCurWing->m_PlanformSpan; } else { pWPolar->m_WArea = pMiarex->m_pCurWing->m_ProjectedArea; pWPolar->m_WSpan = pMiarex->m_pCurWing->m_ProjectedSpan; } pWPolar->m_WMAChord = pMiarex->m_pCurWing->m_MAChord; } } } if(bResultsOnly) return;// that's enough // ... Find the wing in the object array and remove it... Wing* pWing; for (i=s_oaWing.size()-1; i>=0; i--) { pWing = (Wing*)s_oaWing.at(i); if (pWing == pThisWing) { s_oaWing.removeAt(i); delete pWing; if(pWing == pMiarex->m_pCurWing) pMiarex->m_pCurWing = NULL; break; } } } QColor MainFrame::GetColor(int type) { //type // 0=Foil // 1=Polar // 2=Opp // 3=Wing (unused) // 4=WPolar // 5=WOpp // 6=POpp QColor color = QColor(255,0,0); int i,j; bool bFound = false; switch (type) { case 0: { Foil *pFoil; for (j=0; jm_FoilColor == m_ColorList.at(j)) { bFound = true; break; } } if(!bFound) return m_ColorList.at(j); } return QColor((int)((double)qrand()/(double)RAND_MAX*255.0), (int)((double)qrand()/(double)RAND_MAX*255.0), (int)((double)qrand()/(double)RAND_MAX*255.0)); } case 1: { Polar *pPolar; for (j=0; jm_Color == m_ColorList.at(j)) { bFound = true; break; } } if(!bFound) return m_ColorList.at(j); } return QColor((int)((double)qrand()/(double)RAND_MAX*255.0), (int)((double)qrand()/(double)RAND_MAX*255.0), (int)((double)qrand()/(double)RAND_MAX*255.0)); } case 2: { OpPoint *pOpPoint; for (j=0; jm_Color == m_ColorList.at(j)) { bFound = true; break; } } if(!bFound) return m_ColorList.at(j); } return QColor((int)((double)qrand()/(double)RAND_MAX*255.0), (int)((double)qrand()/(double)RAND_MAX*255.0), (int)((double)qrand()/(double)RAND_MAX*255.0)); } case 4: { WPolar *pWPolar; for (j=0; jm_Color == m_ColorList.at(j)) { bFound = true; break; } } if(!bFound) return m_ColorList.at(j); } return QColor((int)((double)qrand()/(double)RAND_MAX*255.0), (int)((double)qrand()/(double)RAND_MAX*255.0), (int)((double)qrand()/(double)RAND_MAX*255.0)); } case 5: { WingOpp *pWOpp; for (j=0; jm_Color == m_ColorList.at(j)) { bFound = true; break; } } if(!bFound) return m_ColorList.at(j); } return QColor((int)((double)qrand()/(double)RAND_MAX*255.0), (int)((double)qrand()/(double)RAND_MAX*255.0), (int)((double)qrand()/(double)RAND_MAX*255.0)); } case 6: { PlaneOpp *pPOpp; for (j=0; jm_Color == m_ColorList.at(j)) { bFound = true; break; } } if(!bFound) return m_ColorList.at(j); } return QColor((int)((double)qrand()/(double)RAND_MAX*255.0), (int)((double)qrand()/(double)RAND_MAX*255.0), (int)((double)qrand()/(double)RAND_MAX*255.0)); } default: { return QColor(255,0,0); } } return color; } Foil* MainFrame::foil(QString strFoilName) { //returns a pointer to the foil with the corresponding name // returns NULL if not found if(!strFoilName.length()) return NULL; Foil* pFoil; for (int i=0; im_FoilName == strFoilName) { return pFoil; } } return NULL; } Polar *MainFrame::GetPolar(QString m_FoilName, QString PolarName) { if (!PolarName.length()) { //try to get the first from the Combobox if(!m_pctrlPolar->count()) return NULL; //nothing more to try PolarName = m_pctrlPolar->itemText(0); //... and carry on } Polar *pPolar; for (int i=0; im_FoilName == m_FoilName && pPolar->m_PlrName == PolarName) { return pPolar; } } return NULL; } OpPoint *MainFrame::GetOpp(double Alpha) { OpPoint* pOpPoint; QXDirect *pXDirect = (QXDirect*)m_pXDirect; Polar *pCurPolar = pXDirect->m_pCurPolar; if(!pCurPolar) return NULL; for (int i=0; im_strFoilName == s_pCurFoil->m_FoilName) { if (pOpPoint->m_strPlrName == pCurPolar->m_PlrName) { if(pCurPolar->m_PolarType != FIXEDAOAPOLAR) { if(qAbs(pOpPoint->Alpha - Alpha) <0.001) { return pOpPoint; } } else { if(qAbs(pOpPoint->Reynolds - Alpha) <0.1) { return pOpPoint; } } } } } return NULL;// shouldn't ever get here, fortunately } void MainFrame::keyPressEvent(QKeyEvent *event) { if(m_iApp == XFOILANALYSIS && m_pXDirect) { QXDirect* pXDirect = (QXDirect*)m_pXDirect; pXDirect->keyPressEvent(event); } else if(m_iApp == MIAREX && m_pMiarex) { QMiarex* pMiarex = (QMiarex*)m_pMiarex; pMiarex->keyPressEvent(event); } else if(m_iApp == DIRECTDESIGN && m_pAFoil) { QAFoil *pAFoil= (QAFoil*)m_pAFoil; pAFoil->keyPressEvent(event); } else if(m_iApp == INVERSEDESIGN && m_pXInverse) { QXInverse *pXInverse= (QXInverse*)m_pXInverse; pXInverse->keyPressEvent(event); } else { switch (event->key()) { case Qt::Key_F1: { OnMiarex(); break; } case Qt::Key_L: { OnLogFile(); break; } case Qt::Key_Control: { QMiarex* pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_bArcball = true; UpdateView(); break; } default: event->ignore(); } } } void MainFrame::keyReleaseEvent(QKeyEvent *event) { if(m_iApp == XFOILANALYSIS && m_pXDirect) { QXDirect* pXDirect = (QXDirect*)m_pXDirect; pXDirect->keyReleaseEvent(event); } else if(m_iApp == MIAREX && m_pMiarex) { QMiarex* pMiarex = (QMiarex*)m_pMiarex; if (event->key()==Qt::Key_Control) { pMiarex->m_bArcball = false; UpdateView(); } else pMiarex->keyReleaseEvent(event); } else if(m_iApp == DIRECTDESIGN && m_pAFoil) { QAFoil *pAFoil= (QAFoil*)m_pAFoil; pAFoil->keyReleaseEvent(event); } else if(m_iApp == INVERSEDESIGN && m_pXInverse) { QXInverse *pXInverse= (QXInverse*)m_pXInverse; pXInverse->keyReleaseEvent(event); } } bool MainFrame::LoadPolarFileV3(QDataStream &ar, bool bIsStoring, int ArchiveFormat) { Foil *pFoil; Polar *pPolar = NULL; Polar *pOldPlr; OpPoint *pOpp, *pOldOpp; //first read all available foils int i,l,n; ar>>n; for (i=0;iSerialize(ar, bIsStoring)) { delete pFoil; return false; } AddFoil(pFoil); } //next read all available polars ar>>n; for (i=0;im_Color = GetColor(1); if (!pPolar->Serialize(ar, bIsStoring)) { delete pPolar; return false; } for (l=0; lm_FoilName == pPolar->m_FoilName && pOldPlr->m_PlrName == pPolar->m_PlrName) { //just overwrite... s_oaPolar.removeAt(l); delete pOldPlr; //... and continue to add } } pPolar = AddPolar(pPolar); } //Last read all available operating points ar>>n; for (i=0;im_Color = m_ColorList[m_oaOpp.size()%24]; if(ArchiveFormat>=100002) { if (!pOpp->Serialize(ar, bIsStoring, 100002)) { delete pOpp; return false; } else { pFoil = foil(pOpp->m_strFoilName); if(pFoil) { // memcpy(pOpp->x, pFoil->x, sizeof(pOpp->x)); // memcpy(pOpp->y, pFoil->y, sizeof(pOpp->y)); } else { delete pOpp; } } } else { if (!pOpp->Serialize(ar, bIsStoring)) { delete pOpp; return false; } else { pFoil = foil(pOpp->m_strFoilName); if(pFoil) { // memcpy(pOpp->x, pFoil->x, sizeof(pOpp->x)); // memcpy(pOpp->y, pFoil->y, sizeof(pOpp->y)); } else { delete pOpp; } } } if(pOpp) { for (int l=m_oaOpp.size()-1;l>=0; l--) { pOldOpp = (OpPoint*)m_oaOpp.at(l); if (pOldOpp->m_strFoilName == pOpp->m_strFoilName && pOldOpp->m_strPlrName == pOpp->m_strPlrName && qAbs(pOldOpp->Alpha-pOpp->Alpha)<0.001) { //just overwrite... m_oaOpp.removeAt(l); delete pOldOpp; //... and continue to add } } } ((QXDirect*)m_pXDirect)->InsertOpPoint(pOpp); } return true; } bool MainFrame::LoadSettings() { QPoint pt; bool bFloat; int SettingsFormat; QSize size; #ifdef Q_WS_MAC QSettings settings(QSettings::NativeFormat,QSettings::UserScope,"sourceforge.net","xflr5"); #else QSettings settings(QSettings::IniFormat,QSettings::UserScope,"XFLR5"); #endif settings.beginGroup("MainFrame"); { SettingsFormat = settings.value("SettingsFormat").toInt(); if(SettingsFormat != SETTINGSFORMAT) return false; DisplaySettingsDlg::s_StyleName = settings.value("StyleName","").toString(); s_LanguageFilePath = settings.value("LanguageFilePath").toString(); m_GraphExportFilter = settings.value("GraphExportFilter",".csv").toString(); bFloat = settings.value("Miarex_Float").toBool(); pt.rx() = settings.value("Miarex_x").toInt(); pt.ry() = settings.value("Miarex_y").toInt(); size = settings.value("MiarexSize").toSize(); m_pctrlMiarexWidget->setFloating(bFloat); if(bFloat) m_pctrlMiarexWidget->move(pt); m_pctrlMiarexWidget->resize(size); bFloat = settings.value("XDirect_Float").toBool(); pt.rx() = settings.value("XDirect_x").toInt(); pt.ry() = settings.value("XDirect_y").toInt(); size = settings.value("XDirectSize").toSize(); m_pctrlXDirectWidget->setFloating(bFloat); if(bFloat) m_pctrlXDirectWidget->move(pt); m_pctrlXDirectWidget->resize(size); bFloat = settings.value("AFoil_Float").toBool(); pt.rx() = settings.value("AFoil_x").toInt(); pt.ry() = settings.value("AFoil_y").toInt(); size = settings.value("AFoilSize").toSize(); m_pctrlAFoilWidget->setFloating(bFloat); if(bFloat) m_pctrlAFoilWidget->move(pt); m_pctrlAFoilWidget->resize(size); bFloat = settings.value("XInverse_Float").toBool(); pt.rx() = settings.value("XInverse_x").toInt(); pt.ry() = settings.value("XInverse_y").toInt(); size = settings.value("XInverseSize").toSize(); m_pctrlXInverseWidget->setFloating(bFloat); if(bFloat) m_pctrlXInverseWidget->move(pt); m_pctrlXInverseWidget->resize(size); bFloat = settings.value("StabView_Float").toBool(); pt.rx() = settings.value("StabView_x").toInt(); pt.ry() = settings.value("StabView_y").toInt(); size = settings.value("StabSize").toSize(); m_pctrlStabViewWidget->setFloating(bFloat); if(bFloat) m_pctrlStabViewWidget->move(pt); m_pctrlStabViewWidget->resize(size); s_LastDirName = settings.value("LastDirName").toString(); m_ImageDirName = settings.value("ImageDirName").toString(); m_ExportLastDirName = settings.value("ExportLastDirName").toString(); s_LengthUnit = settings.value("LengthUnit").toInt(); s_AreaUnit = settings.value("AreaUnit").toInt(); s_WeightUnit = settings.value("WeightUnit").toInt(); s_SpeedUnit = settings.value("SpeedUnit").toInt(); s_ForceUnit = settings.value("ForceUnit").toInt(); s_MomentUnit = settings.value("MomentUnit").toInt(); s_BackgroundColor.setRed(settings.value("BackgroundColorRed").toInt()); s_BackgroundColor.setGreen(settings.value("BackgroundColorGreen").toInt()); s_BackgroundColor.setBlue(settings.value("BackgroundColorBlue").toInt()); s_TextColor.setRed(settings.value("TextColorRed").toInt()); s_TextColor.setGreen(settings.value("TextColorGreen").toInt()); s_TextColor.setBlue(settings.value("TextColorBlue").toInt()); s_TextFont = QFont(settings.value("TextFontFamily", "Courier").toString()); s_TextFont.setPointSize(settings.value("TextFontPointSize", 10).toInt()); s_TextFont.setItalic(settings.value("TextFontItalic", false).toBool()); s_TextFont.setBold(settings.value("TextFontBold", false).toBool()); s_TextFont.setStyleStrategy(QFont::OpenGLCompatible); switch(settings.value("ImageFormat").toInt()) { case 0: m_ImageFormat = PNG; break; case 1: m_ImageFormat = JPEG; break; case 2: m_ImageFormat = BMP; break; default: m_ImageFormat = PNG; break; } m_bSaveOpps = settings.value("SaveOpps").toBool(); m_bSaveWOpps = settings.value("SaveWOpps").toBool(); // a = settings.value("RecentFileSize").toInt(); QString RecentF,strange; m_RecentFiles.clear(); int n=0; do { RecentF = QString("RecentFile_%1").arg(n); strange = settings.value(RecentF).toString(); if(strange.length()) { m_RecentFiles.append(strange); n++; } else break; }while(n0) s_LastDirName = PathName.left(pos); if(end==".plr") { QDataStream ar(&XFile); #if QT_VERSION >= 0x040500 ar.setVersion(QDataStream::Qt_4_5); #endif ar.setByteOrder(QDataStream::LittleEndian); Foil *pFoil = ReadPolarFile(ar); pXDirect->m_bPolarView = true; pXDirect->m_pCurPolar = NULL; pXDirect->m_pCurOpp = NULL; s_pCurFoil = pXDirect->SetFoil(pFoil); pXDirect->SetPolar(); XFile.close(); AddRecentFile(PathName); SetSaveState(false); pXDirect->SetControls(); return XFOILANALYSIS; } else { if(end==".dat") { QTextStream ar(&XFile); Foil *pFoil = ReadFoilFile(ar); XFile.close(); if(pFoil) { AddFoil(pFoil); s_pCurFoil = pFoil; pXDirect->m_pCurPolar = NULL; pXDirect->m_pCurOpp = NULL; s_pCurFoil = pXDirect->SetFoil(pFoil); pXDirect->SetPolar(); QAFoil *pAFoil= (QAFoil*)m_pAFoil; pAFoil->SelectFoil(pFoil); XFile.close(); SetSaveState(false); AddRecentFile(PathName); pXDirect->SetControls(); return XFOILANALYSIS; } } else { if(end==".wpa") { if(!s_bSaved) { QString strong = tr("Save the current project ?"); int resp = QMessageBox::question(this ,tr("Save"), strong, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel); if(resp==QMessageBox::Cancel) { XFile.close(); return NOAPP; } else if (resp==QMessageBox::Yes) { if(!SaveProject(m_FileName)) { XFile.close(); return NOAPP; } } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); DeleteProject(); QDataStream ar(&XFile); #if QT_VERSION >= 0x040500 ar.setVersion(QDataStream::Qt_4_5); #endif ar.setByteOrder(QDataStream::LittleEndian); if(SerializeProject(ar, false)) { s_pCurFoil = pXDirect->SetFoil(); UpdateFoils(); UpdateView(); QApplication::restoreOverrideCursor(); } else { QApplication::restoreOverrideCursor(); QMessageBox::warning(this,tr("Warning"), tr("Error reading the file")+"\n"+tr("Saved the valid part")); // DeleteProject(); } AddRecentFile(PathName); SetSaveState(true); SetProjectName(PathName); XFile.close(); pXDirect->SetControls(); if(s_oaPlane.size() || s_oaWing.size()) return MIAREX; else return XFOILANALYSIS; } } } XFile.close(); return NOAPP; } void MainFrame::OnAFoil() { QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->StopAnimate(); QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->StopAnimate(); m_iApp = DIRECTDESIGN; m_pctrlMiarexToolBar->hide(); m_pctrlStabViewWidget->hide(); m_pctrlXDirectToolBar->hide(); m_pctrlXInverseToolBar->hide(); m_pctrlAFoilToolBar->show(); m_pctrlMiarexWidget->hide(); m_pctrlXDirectWidget->hide(); m_pctrlXInverseWidget->hide(); m_pctrlAFoilWidget->show(); SetCentralWidget(); SetMenus(); QAFoil *pAFoil = (QAFoil*)m_pAFoil; pAFoil->SetParams(); } void MainFrame::OnCurFoilStyle() { if(!s_pCurFoil) return; LinePickerDlg dlg(this); dlg.InitDialog(s_pCurFoil->m_nFoilStyle, s_pCurFoil->m_nFoilWidth, s_pCurFoil->m_FoilColor); if(QDialog::Accepted==dlg.exec()) { s_pCurFoil->m_FoilColor = dlg.GetColor(); s_pCurFoil->m_nFoilStyle = dlg.GetStyle(); s_pCurFoil->m_nFoilWidth = dlg.GetWidth(); QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->m_BufferFoil.m_FoilColor = s_pCurFoil->m_FoilColor; pXDirect->m_BufferFoil.m_nFoilStyle = s_pCurFoil->m_nFoilStyle; pXDirect->m_BufferFoil.m_nFoilWidth = s_pCurFoil->m_nFoilWidth; SetSaveState(false); } UpdateView(); } void MainFrame::OnExportCurGraph() { QGraph *pGraph = NULL; switch(m_iApp) { case MIAREX: { QMiarex *pMiarex = (QMiarex*)m_pMiarex; pGraph = pMiarex->m_pCurGraph; break; } case XFOILANALYSIS: { QXDirect *pXDirect = (QXDirect*)m_pXDirect; pGraph = pXDirect->m_pCurGraph; break; } default: pGraph = NULL; } if(!pGraph) return; QString FileName; pGraph->GetGraphName(FileName); FileName = QFileDialog::getSaveFileName(this, tr("Export Graph"), m_ExportLastDirName, tr("Text File (*.txt);;Comma Separated Values (*.csv)"), &m_GraphExportFilter); if(!FileName.length()) return; int pos; enumTextFileType type; pos = FileName.lastIndexOf("/"); if(pos>0) m_ExportLastDirName = FileName.left(pos); QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; pos = FileName.indexOf(".csv"); if(pos>0) type=CSV; else type=TXT; pGraph->ExportToFile(XFile, type); } void MainFrame::OnGuidelines() { #ifdef Q_WS_MAC CFURLRef appUrlRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); CFStringRef macPath = CFURLCopyFileSystemPath(appUrlRef, kCFURLPOSIXPathStyle); QString bundlePath(CFStringGetCStringPtr(macPath, CFStringGetSystemEncoding())); QFileInfo fileInfo(bundlePath); QDir dir = fileInfo.dir(); QString FileName = dir.absoluteFilePath("Guidelines.pdf"); CFRelease(appUrlRef); CFRelease(macPath); #endif #ifdef Q_OS_WIN QDir dir(qApp->applicationDirPath()); QString FileName = dir.canonicalPath() + "/Guidelines.pdf" ; #endif #ifdef Q_OS_LINUX QDir dir("/usr/share/xflr5"); QString FileName = dir.canonicalPath() + "/Guidelines.pdf" ; #endif QDesktopServices::openUrl(QUrl::fromLocalFile(FileName)); } void MainFrame::OnInsertProject() { QString PathName; QAFoil *pAFoil = (QAFoil*)m_pAFoil; QXDirect *pXDirect = (QXDirect*)m_pXDirect; QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_bArcball = false; PathName = QFileDialog::getOpenFileName(this, tr("Open File"), s_LastDirName, tr("Project file (*.wpa)")); if(!PathName.length()) return; int pos = PathName.lastIndexOf("/"); if(pos>0) s_LastDirName = PathName.left(pos); QFile XFile(PathName); if (!XFile.open(QIODevice::ReadOnly)) { QString strange = tr("Could not read the file\n") + PathName; QMessageBox::information(window(), tr("Warning"), strange); return; } QDataStream ar(&XFile); #if QT_VERSION >= 0x040500 ar.setVersion(QDataStream::Qt_4_5); #endif ar.setByteOrder(QDataStream::LittleEndian); SerializeProject(ar, false); SetSaveState(false); if(m_iApp == MIAREX) { UpdateUFOs(); pMiarex->SetUFO(); if(pMiarex->m_iView==WPOLARVIEW) pMiarex->CreateWPolarCurves(); else if(pMiarex->m_iView==WOPPVIEW) pMiarex->CreateWOppCurves(); else if(pMiarex->m_iView==WCPVIEW) pMiarex->CreateCpCurves(); } else if(m_iApp == XFOILANALYSIS) { if(pXDirect->m_bPolarView) pXDirect->CreatePolarCurves(); else pXDirect->CreateOppCurves(); UpdateFoils(); } else if(m_iApp == DIRECTDESIGN) { pAFoil->FillFoilTable(); pAFoil->SelectFoil(); } UpdateView(); } void MainFrame::OnLanguage() { TranslatorDlg tDlg(this); tDlg.InitDialog(); if(tDlg.exec()==QDialog::Accepted) { } } void MainFrame::OnLoadFile() { QStringList PathNames; QString PathName; enumApp App = NOAPP; bool warn_non_airfoil_multiload = false; QXDirect *pXDirect = (QXDirect*)m_pXDirect; QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_bArcball = false; PathNames = QFileDialog::getOpenFileNames(this, tr("Open File"), s_LastDirName, tr("XFLR5 file (*.dat *.plr *.wpa)")); if(!PathNames.size()) return; if(PathNames.size() > 1) { for (int i=0; i0) s_LastDirName = PathName.left(pos); App = LoadXFLR5File(PathName); } if(m_iApp==NOAPP) { m_iApp = App; QString strange = PathName.right(4); strange = strange.toLower(); if(strange == ".dat" || strange==".plr") OnXDirect(); else if(strange==".wpa" && (s_oaWing.size() || s_oaPlane.size())) OnMiarex(); else OnXDirect(); } if(App==0) { } else if(m_iApp==XFOILANALYSIS) { if(s_oaPolar.size()) { if(pXDirect->m_bPolarView) pXDirect->CreatePolarCurves(); else pXDirect->CreateOppCurves(); } UpdateFoils(); UpdateView(); } else if(m_iApp==MIAREX) { UpdateUFOs(); pMiarex->SetUFO(); pMiarex->m_bArcball = false; pMiarex->m_bIs2DScaleSet = false; pMiarex->Set2DScale(); pMiarex->SetControls(); UpdateView(); } else if(m_iApp==DIRECTDESIGN) { QAFoil *pAFoil = (QAFoil*)m_pAFoil; pAFoil->SetParams(); pAFoil->SelectFoil(s_pCurFoil); UpdateView(); } else if(m_iApp==INVERSEDESIGN) { OnXInverse(); UpdateView(); } } void MainFrame::OnLogFile() { QString FileName = QDir::tempPath() + "/XFLR5.log"; // 20090605 Francesco Meschia QDesktopServices::openUrl(QUrl::fromLocalFile(FileName)); } void MainFrame::OnMiarex() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->StopAnimate(); QMiarex *pMiarex = (QMiarex*)m_pMiarex; m_iApp = MIAREX; m_pctrlXDirectToolBar->hide(); m_pctrlXInverseToolBar->hide(); m_pctrlAFoilToolBar->hide(); m_pctrlMiarexToolBar->show(); m_pctrlXDirectWidget->hide(); m_pctrlAFoilWidget->hide(); m_pctrlXInverseWidget->hide(); m_pctrlMiarexWidget->show(); // pMiarex->SetControls(); pMiarex->SetUFO(); pMiarex->m_bArcball = false; UpdateUFOs(); SetMenus(); SetCentralWidget(); // pMiarex->SetControls(); UpdateView(); } void MainFrame::OnNewProject() { QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_bArcball = false; if(!s_bSaved) { int resp = QMessageBox::question(this, tr("Question"), tr("Save the current project ?"), QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel); if (QMessageBox::Cancel == resp) { return; } else if (QMessageBox::Yes == resp) { if(SaveProject(m_FileName)) { SetSaveState(true); DeleteProject(); statusBar()->showMessage(tr("The project ") + s_ProjectName + tr(" has been saved")); } else return; //save failed, don't close } else if (QMessageBox::No == resp) { DeleteProject(); } } else { DeleteProject(); } UpdateView(); } void MainFrame::OnResetCurGraphScales() { QGraph *pGraph = NULL; switch(m_iApp) { case MIAREX: { QMiarex *pMiarex = (QMiarex*)m_pMiarex; pGraph = pMiarex->m_pCurGraph; break; } case XFOILANALYSIS: { QXDirect *pXDirect = (QXDirect*)m_pXDirect; if(!pXDirect->m_bPolarView) pGraph = pXDirect->m_pCpGraph; else pGraph = pXDirect->m_pCurGraph; break; } case INVERSEDESIGN: { QXInverse *pXInverse = (QXInverse*)m_pXInverse; pGraph = &pXInverse->m_QGraph; pXInverse->ReleaseZoom(); break; } default: pGraph = NULL; } if(!pGraph) return; pGraph->SetAuto(true); UpdateView(); } void MainFrame::OnRenameCurFoil() { if(!s_pCurFoil) return; RenameFoil(s_pCurFoil); QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->SetFoil(s_pCurFoil); UpdateFoils(); UpdateView(); } void MainFrame::OnResetSettings() { int resp = QMessageBox::question(this, tr("Default Settings"), tr("Are you sure you want to reset the default settings ?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); if(resp == QMessageBox::Yes) { QMessageBox::warning(this,tr("Default Settings"), tr("The settings will be reset at the next session")); #ifdef Q_WS_MAC QSettings settings(QSettings::NativeFormat,QSettings::UserScope,"sourceforge.net","xflr5"); #else QSettings settings(QSettings::IniFormat,QSettings::UserScope,"XFLR5"); #endif settings.clear(); s_LastDirName = QDir::homePath(); // do not save on exit m_bSaveSettings = false; } } void MainFrame::OnRestoreToolbars() { if(m_iApp==XFOILANALYSIS) { m_pctrlXInverseToolBar->hide(); m_pctrlAFoilToolBar->hide(); m_pctrlMiarexToolBar->hide(); m_pctrlStabViewWidget->hide(); m_pctrl3DScalesWidget->hide(); m_pctrlAFoilWidget->hide(); m_pctrlXInverseWidget->hide(); m_pctrlMiarexWidget->hide(); m_pctrlXDirectToolBar->show(); m_pctrlXDirectWidget->show(); } else if(m_iApp==DIRECTDESIGN) { m_pctrlXInverseToolBar->hide(); m_pctrlMiarexToolBar->hide(); m_pctrlXDirectToolBar->hide(); m_pctrl3DScalesWidget->hide(); m_pctrlXDirectWidget->hide(); m_pctrlXInverseWidget->hide(); m_pctrlMiarexWidget->hide(); m_pctrlStabViewWidget->hide(); m_pctrlAFoilToolBar->show(); m_pctrlAFoilWidget->show(); } else if(m_iApp==INVERSEDESIGN) { m_pctrlAFoilToolBar->hide(); m_pctrlMiarexToolBar->hide(); m_pctrlXDirectToolBar->hide(); m_pctrl3DScalesWidget->hide(); m_pctrlStabViewWidget->hide(); m_pctrlAFoilWidget->hide(); m_pctrlXDirectWidget->hide(); m_pctrlMiarexWidget->hide(); m_pctrlXInverseToolBar->show(); m_pctrlXInverseWidget->show(); } else if(m_iApp==MIAREX) { m_pctrlXInverseToolBar->hide(); m_pctrlAFoilToolBar->hide(); m_pctrlXDirectToolBar->hide(); m_pctrl3DScalesWidget->hide(); m_pctrlAFoilWidget->hide(); m_pctrlXDirectWidget->hide(); m_pctrlXInverseWidget->hide(); m_pctrlMiarexWidget->show(); m_pctrlMiarexToolBar->show(); QMiarex *pMiarex = (QMiarex*)m_pMiarex; if(pMiarex->m_iView==WSTABVIEW) m_pctrlStabViewWidget->show(); else m_pctrlStabViewWidget->hide(); } } void MainFrame::OnSaveOptions() { SaveOptionsDlg soDlg(this); soDlg.InitDialog(m_bSaveOpps, m_bSaveWOpps); if(soDlg.exec()==QDialog::Accepted) { m_bSaveOpps = soDlg.m_bOpps; m_bSaveWOpps = soDlg.m_bWOpps; } } void MainFrame::OnSaveProject() { if (!s_ProjectName.length() || s_ProjectName=="*") { OnSaveProjectAs(); return; } if(SaveProject(m_FileName)) { SetSaveState(true); statusBar()->showMessage(tr("The project ") + s_ProjectName + tr(" has been saved")); } QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_bArcball = false; pMiarex->UpdateView(); } bool MainFrame::OnSaveProjectAs() { if(SaveProject()) { SetProjectName(m_FileName); AddRecentFile(m_FileName); statusBar()->showMessage(tr("The project ") + s_ProjectName + tr(" has been saved")); SetSaveState(true); } QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_bArcball = false; return true; } void MainFrame::OnSaveUFOAsProject() { QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_bArcball = false; QString strong; if(pMiarex->m_pCurPlane) strong = pMiarex->m_pCurPlane->PlaneName(); else if(pMiarex->m_pCurWing) strong = pMiarex->m_pCurWing->m_WingName; else { QMessageBox::warning(this, tr("Warning"), tr("Nothing to save")); return ; } QString PathName; QString Filter = ".wpa"; QString FileName = strong; PathName = QFileDialog::getSaveFileName(this, tr("Save the Project File"), s_LastDirName+"/"+FileName, tr("XFLR5 Project File (*.wpa)"), &Filter); if(!PathName.length()) return;//nothing more to do int pos = PathName.indexOf(".wpa", Qt::CaseInsensitive); if(pos<0) PathName += ".wpa"; PathName.replace(QDir::separator(), "/"); // Qt sometimes uses the windows \ separator pos = PathName.lastIndexOf("/"); if(pos>0) s_LastDirName = PathName.left(pos); QFile fp(PathName); if (!fp.open(QIODevice::WriteOnly)) { QMessageBox::warning(window(), tr("Warning"), tr("Could not open the file for writing")); return; } QDataStream ar(&fp); #if QT_VERSION >= 0x040500 ar.setVersion(QDataStream::Qt_4_5); #endif ar.setByteOrder(QDataStream::LittleEndian); SerializeUFOProject(ar); fp.close(); } void MainFrame::OnSaveViewToImageFile() { QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_bArcball = false; QSize sz(m_p2DWidget->geometry().width(), m_p2DWidget->geometry().height()); QImage img(sz, QImage::Format_RGB32); QPainter painter(&img); QString FileName, Filter; switch(m_ImageFormat) { case PNG : { Filter = "Portable Network Graphics (*.png)"; break; } case JPEG : { Filter = "JPEG (*.jpg)"; break; } case BMP : { Filter = "Windows Bitmap (*.bmp)"; break; } } FileName = QFileDialog::getSaveFileName(this, tr("Save Image"), m_ImageDirName, "Portable Network Graphics (*.png);;JPEG (*.jpg);;Windows Bitmap (*.bmp)", &Filter); if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) m_ImageDirName = FileName.left(pos); if(Filter == "Portable Network Graphics (*.png)") { if(FileName.right(4)!=".png") FileName+= ".png"; m_ImageFormat = PNG; } else if(Filter == "JPEG (*.jpg)") { if(FileName.right(4)!=".jpg") FileName+= ".jpg"; m_ImageFormat = JPEG; } else if(Filter == "Windows Bitmap (*.bmp)") { if(FileName.right(4)!=".bmp") FileName+= ".bmp"; m_ImageFormat = BMP; } switch(m_iApp) { case XFOILANALYSIS: { QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->PaintView(painter); break; } case DIRECTDESIGN: { QAFoil *pAFoil = (QAFoil*)m_pAFoil; pAFoil->PaintView(painter); break; } case INVERSEDESIGN: { QXInverse *pXInverse = (QXInverse*)m_pXInverse; pXInverse->PaintView(painter); break; } case MIAREX: { QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_bArcball = false; if(pMiarex->m_iView==W3DVIEW) { pMiarex->UpdateView(); pMiarex->SnapClient(FileName); return; } else pMiarex->PaintView(painter); break; } default: break; } img.save(FileName); } void MainFrame::OnSelChangeUFO(int i) { // Gets the new selected wing name and notifies Miarex // then updates WPolar combobox // and selects either the current WPolar // or the first one in the list, if any QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->StopAnimate(); QString strong; // int sel = m_pctrlUFO->currentIndex(); if (i >=0) strong = m_pctrlUFO->itemText(i); pMiarex->SetUFO(strong); m_iApp = MIAREX; // UpdateWPolars(); // UpdateWOpps(); // pMiarex->SetWPlr(false); pMiarex->m_bIs2DScaleSet = false; pMiarex->Set2DScale(); pMiarex->SetControls(); pMiarex->UpdateView(); } void MainFrame::OnSelChangeWPolar(int i) { QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->StopAnimate(); QString strong; // int sel = m_pctrlWPolar->currentIndex(); if (i>=0) strong = m_pctrlWPolar->itemText(i); m_iApp = MIAREX; pMiarex->SetWPolar(false, strong); // pMiarex->SetWingOpp(true); pMiarex->SetControls(); pMiarex->UpdateView(); } void MainFrame::OnSelChangeWOpp(int i) { QString strong; QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->StopAnimate(); // Gets the new selected WOpp name and notifies Miarex if(!m_pctrlWOpp->count()) { pMiarex->m_pCurWOpp = NULL; if (pMiarex->m_iView==WOPPVIEW) pMiarex->CreateWOppCurves(); else if(pMiarex->m_iView==WCPVIEW) pMiarex->CreateCpCurves(); pMiarex->UpdateView(); return; } if (i>=0) strong = m_pctrlWOpp->itemText(i); else { m_pctrlWOpp->setCurrentIndex(0); strong = m_pctrlWOpp->itemText(0).trimmed(); } if(strong.length()) { bool bOK; double x = locale().toDouble(strong, &bOK); if(bOK) { m_iApp = MIAREX; pMiarex->SetWingOpp(false, x); pMiarex->UpdateView(); } else { QMessageBox::warning(window(), tr("Warning"), tr("Unidentified Operating Point")); pMiarex->m_pCurWOpp = NULL; pMiarex->SetWingOpp(true); } } } void MainFrame::OnSelChangeFoil(int i) { QXDirect *pXDirect = (QXDirect*)m_pXDirect; i=0; // Gets the new selected foil name and notifies XDirect // sets a polar, if any // then updates the polar combobox pXDirect->m_bAnimate = false; QString strong; int sel = m_pctrlFoil->currentIndex(); if (sel >=0) strong = m_pctrlFoil->itemText(sel); s_pCurFoil = foil(strong); pXDirect->SetFoil(s_pCurFoil); pXDirect->SetPolar(); m_iApp = XFOILANALYSIS; UpdatePolars(); pXDirect->SetControls(); UpdateView(); } void MainFrame::OnSelChangePolar(int i) { i=0; QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->m_bAnimate = false; // Gets the new selected polar name and notifies XDirect QString strong; int sel = m_pctrlPolar->currentIndex(); if (sel >= 0) strong = m_pctrlPolar->itemText(sel); m_iApp = XFOILANALYSIS; pXDirect->SetPolar(strong); UpdateOpps(); pXDirect->SetControls(); UpdateView(); } void MainFrame::OnSelChangeOpp(int i) { QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->m_bAnimate = false; // Gets the new selected Opp name and notifies XDirect QString strong; if (i>=0) strong = m_pctrlOpPoint->itemText(i); m_iApp = XFOILANALYSIS; double Alpha; bool bOK; Alpha = strong.toFloat(&bOK); if(bOK) { pXDirect->SetOpp(Alpha); } else { QMessageBox::warning(window(), tr("Warning"), tr("Unidentified Operating Point")); pXDirect->m_pCurOpp = NULL; pXDirect->SetOpp(); } UpdateView(); } void MainFrame::OnStyle() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; QMiarex *pMiarex = (QMiarex*)m_pMiarex; // QXInverse *pXInverse = (QXInverse*)m_pXInverse; DisplaySettingsDlg DSdlg(this); DSdlg.m_BackgroundColor = s_BackgroundColor; DSdlg.m_TextColor = s_TextColor; DSdlg.m_TextFont = s_TextFont; DSdlg.m_pRefGraph = &m_RefGraph; DSdlg.m_bReverseZoom = s_bReverseZoom; DSdlg.m_bAlphaChannel = s_bAlphaChannel; DSdlg.InitDialog(); if(DSdlg.exec() ==QDialog::Accepted) { s_BackgroundColor = DSdlg.m_BackgroundColor; s_TextColor = DSdlg.m_TextColor; s_TextFont = DSdlg.m_TextFont; s_bReverseZoom = DSdlg.m_pctrlReverseZoom->isChecked(); s_bAlphaChannel = DSdlg.m_pctrlAlphaChannel->isChecked(); pMiarex->m_bResetglGeom = true; pMiarex->m_bResetglBody = true; pMiarex->m_bResetglLegend = true; if(DSdlg.m_bIsGraphModified) { SetGraphSettings(&m_RefGraph); } } // m_DlgPos = m_DisplaySettingsDlg->pos(); pXDirect->m_pCpGraph->SetInverted(true); pMiarex->m_CpGraph.SetInverted(true); UpdateView(); } void MainFrame::OnUnits() { UnitsDlg uDlg(this); uDlg.m_Length = s_LengthUnit; uDlg.m_Area = s_AreaUnit; uDlg.m_Weight = s_WeightUnit; uDlg.m_Speed = s_SpeedUnit; uDlg.m_Force = s_ForceUnit; uDlg.m_Moment = s_MomentUnit; uDlg.InitDialog(); if(uDlg.exec()==QDialog::Accepted) { s_LengthUnit = uDlg.m_Length; s_AreaUnit = uDlg.m_Area; s_WeightUnit = uDlg.m_Weight; s_SpeedUnit = uDlg.m_Speed; s_ForceUnit = uDlg.m_Force; s_MomentUnit = uDlg.m_Moment; SetUnits(s_LengthUnit, s_AreaUnit, s_SpeedUnit, s_WeightUnit, s_ForceUnit, s_MomentUnit, s_mtoUnit, s_m2toUnit, s_mstoUnit, s_kgtoUnit, s_NtoUnit, s_NmtoUnit); SetSaveState(false); if(m_iApp==MIAREX) { QMiarex *pMiarex= (QMiarex*)m_pMiarex; pMiarex->UpdateUnits(); } } // m_DlgPos = m_UnitsDlg->pos(); } void MainFrame::OnXDirect() { UpdateFoils(); QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->StopAnimate(); QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->SetFoilScale(); m_iApp = XFOILANALYSIS; m_pctrlMiarexToolBar->hide(); m_pctrlStabViewWidget->hide(); m_pctrlAFoilToolBar->hide(); m_pctrlXInverseToolBar->hide(); m_pctrlXDirectToolBar->show(); m_pctrlAFoilWidget->hide(); m_pctrlMiarexWidget->hide(); m_pctrlXInverseWidget->hide(); m_pctrlXDirectWidget->show(); SetCentralWidget(); SetMenus(); pXDirect->SetPolarLegendPos(); pXDirect->SetControls(); pXDirect->UpdateView(); } void MainFrame::OnXInverse() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->StopAnimate(); QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->StopAnimate(); QXInverse *pXInverse = (QXInverse*)m_pXInverse; // pXInverse->SetScale(); m_iApp = INVERSEDESIGN; m_pctrlMiarexToolBar->hide(); m_pctrlStabViewWidget->hide(); m_pctrlAFoilToolBar->hide(); m_pctrlXDirectToolBar->hide(); m_pctrlXInverseToolBar->show(); m_pctrlAFoilWidget->hide(); m_pctrlMiarexWidget->hide(); m_pctrlXDirectWidget->hide(); m_pctrlXInverseWidget->show(); SetCentralWidget(); // pXInverse->m_bFullInverse = true; SetMenus(); pXInverse->SetParams(); pXInverse->UpdateView(); } void MainFrame::OnXInverseMixed() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->StopAnimate(); QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->StopAnimate(); QXInverse *pXInverse = (QXInverse*)m_pXInverse; // pXInverse->SetScale(); m_iApp = INVERSEDESIGN; m_pctrlMiarexToolBar->hide(); m_pctrlStabViewWidget->hide(); m_pctrlAFoilToolBar->hide(); m_pctrlXDirectToolBar->hide(); m_pctrlXInverseToolBar->show(); m_pctrlAFoilWidget->hide(); m_pctrlMiarexWidget->hide(); m_pctrlXDirectWidget->hide(); m_pctrlXInverseWidget->show(); pXInverse->m_bFullInverse = false; SetCentralWidget(); SetMenus(); pXInverse->SetParams(); pXInverse->UpdateView(); } void MainFrame::openRecentFile() { QAction *action = qobject_cast(sender()); if (!action) return; QXDirect *pXDirect = (QXDirect*) m_pXDirect; QMiarex *pMiarex = (QMiarex*) m_pMiarex; enumApp App = LoadXFLR5File(action->data().toString()); if(m_iApp==NOAPP) m_iApp = App; if(App==NOAPP) { m_iApp = App; QString FileName = action->data().toString(); m_RecentFiles.removeAll(FileName); updateRecentFileActions(); } else if(m_iApp==XFOILANALYSIS) { if(s_oaPolar.size()) { if(pXDirect->m_bPolarView) pXDirect->CreatePolarCurves(); else pXDirect->CreateOppCurves(); } OnXDirect(); UpdateFoils(); UpdateView(); } else if(m_iApp==MIAREX) { pMiarex->m_bIs2DScaleSet = false; pMiarex->Set2DScale(); OnMiarex(); } else if(m_iApp==DIRECTDESIGN) { QAFoil *pAFoil = (QAFoil*)m_pAFoil; pAFoil->SetParams(); UpdateView(); } else if(m_iApp==INVERSEDESIGN) { OnXInverse(); UpdateView(); } } Foil* MainFrame::ReadFoilFile(QTextStream &in) { QString Strong; QString tempStr; QString FoilName; Foil* pFoil = NULL; int pos, res, i, ip; pos = 0; double x,y, z,area; bool bRead; pFoil = new Foil(); if(!pFoil) return NULL; while(tempStr.length()==0 && !in.atEnd()) { FoilName = Strong; Strong = in.readLine(); pos = Strong.indexOf("#",0); // ignore everything after # (including #) if(pos>0)Strong.truncate(pos); tempStr = Strong; tempStr.remove(" "); } if(!in.atEnd()) { // FoilName contains the last comment ReadValues(Strong, res,x,y,z); if(res==2) { //there isn't a name on the first line FoilName = "New Foil"; { pFoil->xb[0] = x; pFoil->yb[0] = y; pFoil->nb=1; } } else FoilName = Strong; // remove fore and aft spaces FoilName = FoilName.trimmed(); } bRead = true; do { Strong = in.readLine(); pos = Strong.indexOf("#",0); // ignore everything after # (including #) if(pos>0)Strong.truncate(pos); tempStr = Strong; tempStr.remove(" "); if (!Strong.isNull() && bRead && tempStr.length()) { ReadValues(Strong, res, x,y,z); if(res==2) { pFoil->xb[pFoil->nb] = x; pFoil->yb[pFoil->nb] = y; pFoil->nb++; if(pFoil->nb>IQX) { delete pFoil; return NULL; } } else bRead = false; } }while (bRead && !Strong.isNull()); pFoil->m_FoilName = FoilName; // Check if the foil was written clockwise or counter-clockwise area = 0.0; for (i=0; inb; i++) { if(i==pFoil->nb-1) ip = 0; else ip = i+1; area += 0.5*(pFoil->yb[i]+pFoil->yb[ip])*(pFoil->xb[i]-pFoil->xb[ip]); } if(area < 0.0) { //reverse the points order double xtmp, ytmp; for (int i=0; inb/2; i++) { xtmp = pFoil->xb[i]; ytmp = pFoil->yb[i]; pFoil->xb[i] = pFoil->xb[pFoil->nb-i-1]; pFoil->yb[i] = pFoil->yb[pFoil->nb-i-1]; pFoil->xb[pFoil->nb-i-1] = xtmp; pFoil->yb[pFoil->nb-i-1] = ytmp; } } memcpy(pFoil->x, pFoil->xb, sizeof(pFoil->xb)); memcpy(pFoil->y, pFoil->yb, sizeof(pFoil->yb)); pFoil->n=pFoil->nb; pFoil->m_FoilColor = GetColor(0); pFoil->InitFoil(); return pFoil; } /** *Reads a Foil and its related Polar objects from a binary stream associated to a .plr file. * @param ar the binary stream * @return the pointer to the Foil object which has been created, or NULL if failure. */ Foil * MainFrame::ReadPolarFile(QDataStream &ar) { Foil* pFoil = NULL; Polar *pPolar = NULL; Polar * pOldPolar; int i, n, l; ar >> n; if(n<100000) { //old format QMessageBox::warning(window(), tr("Warning"), tr("Obsolete format, cannot read")); return NULL; } else if (n >=100000) { //new format XFLR5 v1.99+ //first read all available foils ar>>n; for (i=0;iSerialize(ar, false)) { delete pFoil; return NULL; } AddFoil(pFoil); } //next read all available polars ar>>n; for (i=0;im_Color = QColor(56,128,188,127); ; if (!pPolar->Serialize(ar, false)) { delete pPolar; return pFoil; } for (l=0; lm_FoilName == pPolar->m_FoilName && pOldPolar->m_PlrName == pPolar->m_PlrName) { //just overwrite... s_oaPolar.removeAt(l); delete pOldPolar; //... and continue to add } } pPolar = AddPolar(pPolar); } } return pFoil; } void MainFrame::RemoveOpPoint(bool bCurrent) { int i; QXDirect *pXDirect =(QXDirect*)m_pXDirect; if(bCurrent) { // we remove only the current OpPoint OpPoint* pOpPoint = pXDirect->m_pCurOpp; OpPoint* opt; for (i=0; i=0;i--) { pOpPoint =(OpPoint*)m_oaOpp.at(i); if (pOpPoint->m_strFoilName == s_pCurFoil->m_FoilName && pOpPoint->m_strPlrName == pXDirect->m_pCurPolar->m_PlrName) { m_oaOpp.removeAt(i); delete pOpPoint; } } } pXDirect->m_pCurOpp = NULL; } void MainFrame::RenameFoil(Foil *pFoil) { if(!pFoil) return; QXDirect *pXDirect = (QXDirect*)m_pXDirect; QString strong; bool bNotFound = true; int i,k,l; Foil*pOldFoil; Polar * pPolar; OpPoint * pOpPoint; QString OldName = pFoil->m_FoilName; while(bNotFound) { QStringList NameList; for(k=0; km_FoilName); } RenameDlg renDlg(this); renDlg.m_pstrArray = & NameList; renDlg.m_strQuestion = tr("Enter the foil's new name"); renDlg.m_strName = OldName; bool bExists = false; renDlg.InitDialog(); int resp = renDlg.exec(); strong = renDlg.m_strName; if(QDialog::Accepted == resp) { if (strong==OldName) { // do nothing bNotFound = false; } else { for (l=0; lm_FoilName == strong) { bExists = true; break; } } if (!bExists) { bNotFound = false;// at last (users !...) // so rename the foil and associated polars and opps pFoil->m_FoilName = strong; bool bInserted = false; for(i=0;im_FoilName.compare(pOldFoil->m_FoilName, Qt::CaseInsensitive)<0) { //then insert before s_oaFoil.insert(l, pFoil); bInserted = true; break; } } if(!bInserted) s_oaFoil.append(pFoil); break; } } for (i=0; im_FoilName == OldName) { pPolar->m_FoilName = strong; } } for (i=0; im_strFoilName == OldName) { pOpPoint->m_strFoilName = strong; } } SetSaveState(false); } } } else if(resp==10) { // user wants to overwrite an existing airfoil if (strong==OldName) { // do nothing bNotFound = false; } else { //So delete any foil with that name for (l=s_oaFoil.size()-1;l>=0; l--) { pOldFoil = (Foil*)s_oaFoil.at(l); if(pOldFoil->m_FoilName == strong) { if(s_pCurFoil == pOldFoil) s_pCurFoil = NULL; if(s_pCurFoil == pOldFoil) s_pCurFoil = NULL; s_oaFoil.removeAt(l); delete pOldFoil; } } // delete all associated OpPoints OpPoint * pOpPoint; for (l=m_oaOpp.size()-1;l>=0;l--) { pOpPoint = (OpPoint*)m_oaOpp[l]; if (pOpPoint->m_strFoilName == strong) { if(pOpPoint == pXDirect->m_pCurOpp) pXDirect->m_pCurOpp = NULL; m_oaOpp.removeAt(l); delete pOpPoint; } } // delete all Polar results for that airfoil Polar * pPolar; for (l=s_oaPolar.size()-1;l>=0;l--) { pPolar = (Polar*) s_oaPolar.at(l); if (pPolar->m_FoilName == strong) { if(pXDirect->m_pCurPolar == pPolar) pXDirect->m_pCurPolar = NULL; s_oaPolar.removeAt(l); delete pPolar; } } // finally add to array pFoil->m_FoilName = strong; for (i=0; im_FoilName == OldName) { pPolar->m_FoilName = strong; } } for (i=0; im_strFoilName == OldName) { pOpPoint->m_strFoilName = strong; } } // UpdateFoils(); SetSaveState(false); bNotFound = false;//exit loop } } else { // Cancel so exit bNotFound = false;//exit loop } } } bool MainFrame::SaveProject(QString PathName) { QString Filter = "XFLR5 v6 Project File (*.wpa)"; QString FileName = s_ProjectName; if(!PathName.length()) { if(FileName.right(1)=="*") FileName = FileName.left(FileName.length()-1); PathName = QFileDialog::getSaveFileName(this, tr("Save the Project File"), s_LastDirName+"/"+FileName, tr("XFLR5 v6 Project File (*.wpa)"), &Filter); if(!PathName.length()) return false;//nothing more to do int pos = PathName.indexOf(".wpa", Qt::CaseInsensitive); if(pos<0) PathName += ".wpa"; PathName.replace(QDir::separator(), "/"); // Qt sometimes uses the windows \ separator pos = PathName.lastIndexOf("/"); if(pos>0) s_LastDirName = PathName.left(pos); } QFile fp(PathName); if (!fp.open(QIODevice::WriteOnly)) { QMessageBox::warning(window(), tr("Warning"), tr("Could not open the file for writing")); return false; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QDataStream ar(&fp); #if QT_VERSION >= 0x040500 ar.setVersion(QDataStream::Qt_4_5); #endif ar.setByteOrder(QDataStream::LittleEndian); SerializeProject(ar,true); m_FileName = PathName; fp.close(); SaveSettings(); QApplication::restoreOverrideCursor(); return true; } void MainFrame::SaveSettings() { QAFoil *pAFoil = (QAFoil*)m_pAFoil; QMiarex *pMiarex = (QMiarex*)m_pMiarex; QXDirect *pXDirect = (QXDirect*)m_pXDirect; QXInverse *pXInverse = (QXInverse*)m_pXInverse; if(!m_bSaveSettings) return; #ifdef Q_WS_MAC QSettings settings(QSettings::NativeFormat,QSettings::UserScope,"sourceforge.net","xflr5"); #else QSettings settings(QSettings::IniFormat,QSettings::UserScope,"XFLR5"); #endif settings.beginGroup("MainFrame"); { settings.setValue("SettingsFormat", SETTINGSFORMAT); settings.setValue("FrameGeometryx", frameGeometry().x()); settings.setValue("FrameGeometryy", frameGeometry().y()); settings.setValue("SizeWidth", size().width()); settings.setValue("SizeHeight", size().height()); settings.setValue("SizeMaximized", isMaximized()); settings.setValue("StyleName", DisplaySettingsDlg::s_StyleName); settings.setValue("GraphExportFilter", m_GraphExportFilter); settings.setValue("Miarex_Float", m_pctrlMiarexWidget->isFloating()); settings.setValue("XDirect_Float", m_pctrlXDirectWidget->isFloating()); settings.setValue("AFoil_Float", m_pctrlAFoilWidget->isFloating()); settings.setValue("XInverse_Float", m_pctrlXInverseWidget->isFloating()); settings.setValue("StabView_Float", m_pctrlStabViewWidget->isFloating()); settings.setValue("Miarex_x", m_pctrlMiarexWidget->frameGeometry().x()); settings.setValue("Miarex_y", m_pctrlMiarexWidget->frameGeometry().y()); settings.setValue("XDirect_x", m_pctrlXDirectWidget->frameGeometry().x()); settings.setValue("XDirect_y", m_pctrlXDirectWidget->frameGeometry().y()); settings.setValue("AFoil_x", m_pctrlAFoilWidget->frameGeometry().x()); settings.setValue("AFoil_y", m_pctrlAFoilWidget->frameGeometry().y()); settings.setValue("XInverse_x", m_pctrlXInverseWidget->frameGeometry().x()); settings.setValue("XInverse_y", m_pctrlXInverseWidget->frameGeometry().y()); settings.setValue("StabView_x", m_pctrlStabViewWidget->frameGeometry().x()); settings.setValue("StabView_y", m_pctrlStabViewWidget->frameGeometry().y()); settings.setValue("XDirectSize", m_pctrlXDirectWidget->size()); settings.setValue("AFoilSize", m_pctrlAFoilWidget->size()); settings.setValue("XInverseSize", m_pctrlXInverseWidget->size()); settings.setValue("MiarexSize", m_pctrlMiarexWidget->size()); settings.setValue("StabSize", m_pctrlStabViewWidget->size()); settings.setValue("LastDirName", s_LastDirName); settings.setValue("ImageDirName", m_ImageDirName); settings.setValue("ExportLastDirName", m_ExportLastDirName); settings.setValue("LengthUnit", s_LengthUnit); settings.setValue("AreaUnit", s_AreaUnit); settings.setValue("WeightUnit", s_WeightUnit); settings.setValue("SpeedUnit", s_SpeedUnit); settings.setValue("ForceUnit", s_ForceUnit); settings.setValue("MomentUnit", s_MomentUnit); settings.setValue("BackgroundColorRed", s_BackgroundColor.red()); settings.setValue("BackgroundColorGreen", s_BackgroundColor.green()); settings.setValue("BackgroundColorBlue", s_BackgroundColor.blue()); settings.setValue("TextColorRed", s_TextColor.red()); settings.setValue("TextColorGreen", s_TextColor.green()); settings.setValue("TextColorBlue", s_TextColor.blue()); settings.setValue("TextFontFamily", s_TextFont.family()); settings.setValue("TextFontPointSize", s_TextFont.pointSize()); settings.setValue("TextFontItalic", s_TextFont.italic()); settings.setValue("TextFontBold", s_TextFont.bold()); settings.setValue("LanguageFilePath", s_LanguageFilePath); settings.setValue("ImageFormat", m_ImageFormat); settings.setValue("SaveOpps", m_bSaveOpps); settings.setValue("SaveWOpps", m_bSaveWOpps); settings.setValue("RecentFileSize", m_RecentFiles.size()); settings.setValue("ShowStyleSheets", DisplaySettingsDlg::s_bStyleSheets); settings.setValue("ReverseZoom", s_bReverseZoom); settings.setValue("AlphaChannel", s_bAlphaChannel); settings.setValue("StyleSheetName", DisplaySettingsDlg::s_StyleSheetName); QString RecentF; for(int i=0; iSaveSettings(&settings); pXDirect->SaveSettings(&settings); pMiarex->SaveSettings(&settings); pXInverse->SaveSettings(&settings); GL3DScales::SaveSettings(&settings); W3dPrefsDlg::SaveSettings(&settings); m_RefGraph.SaveSettings(&settings); } void MainFrame::SetCentralWidget() { QMiarex *pMiarex = (QMiarex*)m_pMiarex; if(m_iApp!=MIAREX) { m_pctrlCentralWidget->setCurrentIndex(0); } else if(m_iApp==MIAREX) { if(pMiarex->m_iView==WOPPVIEW || pMiarex->m_iView==WPOLARVIEW || pMiarex->m_iView==WCPVIEW) m_pctrlCentralWidget->setCurrentIndex(0); else if(pMiarex->m_iView==W3DVIEW) m_pctrlCentralWidget->setCurrentIndex(1); else if(pMiarex->m_iView==WSTABVIEW) { if(pMiarex->m_iStabilityView==STABTIMEVIEW || pMiarex->m_iStabilityView==STABPOLARVIEW ) m_pctrlCentralWidget->setCurrentIndex(0); else m_pctrlCentralWidget->setCurrentIndex(1); } /* if(m_pctrlCentralWidget->currentIndex()==0) pMiarex->Set2DScale(); else pMiarex->Set3DScale();*/ } } void MainFrame::SelectOpPoint(OpPoint *pOpp) { //Selects pOpp in the combobox and returns true //On error, selects the first and returns false QXDirect *pXDirect = (QXDirect*)m_pXDirect; Polar *pCurPlr = pXDirect->m_pCurPolar; if(!pOpp || !pCurPlr) return; QString strange; double val; bool bOK; for(int i=0; icount(); i++) { strange = m_pctrlOpPoint->itemText(i); val = locale().toDouble(strange, &bOK); if(pCurPlr->m_PolarType != FIXEDAOAPOLAR) { if(bOK && qAbs(val-pOpp->Alpha)<0.001) { m_pctrlOpPoint->setCurrentIndex(i); break; } } else { if(bOK && qAbs(val-pOpp->Reynolds)<1.0) { m_pctrlOpPoint->setCurrentIndex(i); break; } } } } void MainFrame::SelectWOpp(WingOpp *pWingOpp) { if(pWingOpp) { if(pWingOpp->m_WPolarTypem_Alpha); else if(pWingOpp->m_WPolarType==FIXEDAOAPOLAR) SelectWOpp(pWingOpp->m_QInf); else if(pWingOpp->m_WPolarType==STABILITYPOLAR) SelectWOpp(pWingOpp->m_Ctrl); } else SelectWOpp(); } void MainFrame::SelectWOpp(PlaneOpp *pPlaneOpp) { if(pPlaneOpp) { if(pPlaneOpp->m_WPolarTypem_Alpha); else if(pPlaneOpp->m_WPolarType==FIXEDAOAPOLAR) SelectWOpp(pPlaneOpp->m_QInf); else if(pPlaneOpp->m_WPolarType==STABILITYPOLAR) SelectWOpp(pPlaneOpp->m_Ctrl); } else SelectWOpp(); } void MainFrame::SelectWOpp(double x) { //Selects a pOpp in the combobox QMiarex *pMiarex = (QMiarex*)m_pMiarex; WPolar *pCurWPlr = pMiarex->m_pCurWPolar; double val; bool bOK; QString strange; m_pctrlWOpp->blockSignals(true); // x = (double)qRound(x*100.0)/100.0; for(int i=0; icount(); i++) { strange = m_pctrlWOpp->itemText(i); val = locale().toDouble(strange, &bOK); if(pCurWPlr->m_WPolarTypesetCurrentIndex(i); break; } } else if(pCurWPlr->m_WPolarType==FIXEDAOAPOLAR) { if(bOK && qAbs(val-x)<1.0) { m_pctrlWOpp->setCurrentIndex(i); break; } } else if(pCurWPlr->m_WPolarType==STABILITYPOLAR) { if(bOK && qAbs(val-x)<.001) { m_pctrlWOpp->setCurrentIndex(i); break; } } } m_pctrlWOpp->blockSignals(false); } bool MainFrame::SerializeUFOProject(QDataStream &ar) { QMiarex * pMiarex = (QMiarex*)m_pMiarex; if(!pMiarex->m_pCurWing) { QMessageBox::warning(this, tr("Warning"), tr("Nothing to save")); return false; } QString UFOName; //saves only the UFO with its associated plrs, foils and other results Plane *pPlane = pMiarex->m_pCurPlane; Wing *pWing = pMiarex->m_pCurWing; Wing *pStab = pMiarex->m_pWingList[2]; Wing *pFin = pMiarex->m_pWingList[3]; WPolar *pWPolar = NULL; // CWOpp *pWOpp = NULL; Foil *pFoil = NULL; Polar * pPolar = NULL; if(pPlane) UFOName = pPlane->PlaneName(); else UFOName = pWing->m_WingName; int i,j; // storing code ar << 100014; // 100014 : removed Point Foil // 100013 : Added CoG serialization // 100012 : Added sideslip // 100011 : Added Body serialization // 100010 : Converted to I.S. units // 100009 : added serialization of opps in numbered format // 100008 : Added m_WPolarDlg.m_bTiltedGeom, m_WPolarDlg.m_bWakeRollUp // 100006 : version 2.99Beta001 format // 100005 : version 2.00 format //Archive format introduced in Beta V22 // Write units //added in Beta v16 // Save analysis settings // added in Beta v22 ar << s_LengthUnit; ar << s_AreaUnit; ar << s_WeightUnit; ar << s_SpeedUnit; ar << s_ForceUnit; ar << s_MomentUnit; if(WPolarDlg::s_WPolar.m_WPolarType==FIXEDSPEEDPOLAR) ar<<1; else if(WPolarDlg::s_WPolar.m_WPolarType==FIXEDLIFTPOLAR) ar<<2; else if(WPolarDlg::s_WPolar.m_WPolarType==FIXEDAOAPOLAR) ar<<4; else if(WPolarDlg::s_WPolar.m_WPolarType==STABILITYPOLAR) ar<<7; else ar << 0; ar << (float)WPolarDlg::s_WPolar.m_Mass; ar << (float)WPolarDlg::s_WPolar.m_QInf; ar << (float)WPolarDlg::s_WPolar.m_CoG.x; ar << (float)WPolarDlg::s_WPolar.m_CoG.y; ar << (float)WPolarDlg::s_WPolar.m_CoG.z; ar << (float)WPolarDlg::s_WPolar.m_Density; ar << (float)WPolarDlg::s_WPolar.m_Viscosity; ar << (float)WPolarDlg::s_WPolar.m_ASpec; ar << (float)WPolarDlg::s_WPolar.m_Beta; if(WPolarDlg::s_WPolar.m_AnalysisMethod==LLTMETHOD) ar << 1; else if(WPolarDlg::s_WPolar.m_AnalysisMethod==VLMMETHOD) ar << 2; else if(WPolarDlg::s_WPolar.m_AnalysisMethod==PANELMETHOD) ar << 3; if (pMiarex->m_bVLM1) ar << 1; else ar << 0; // if (WPolarDlg::m_bMiddle) ar << 1; else ar << 0; ar <<1; if (WPolarDlg::s_WPolar.m_bTiltedGeom) ar << 1; else ar << 0; if (WPolarDlg::s_WPolar.m_bWakeRollUp) ar << 1; else ar << 0; // Store the wing, if any if(!pPlane) { ar << 1;//just one wing pWing->SerializeWing(ar, true); } else ar <<0; // now store all the WPolars associated to the UFO //start by listing the number int size = 0; for (i=0; im_UFOName == UFOName) size++; } ar << size; for (i=0; im_UFOName == UFOName) pWPolar->SerializeWPlr(ar, true); } ar << 0;//no WOpps // then the foils, polars and Opps //list the foils to be saved QStringList FoilList; bool bFound = false; if(pWing) { for (i=0; iNWingSection(); i++) { pFoil = foil(pWing->RightFoil(i)); bFound = false; for(j=0;jm_FoilName == FoilList.at(j)) { bFound = true; break; } } if(!bFound) FoilList.append(pFoil->m_FoilName); } if(!pWing->m_bSymetric) { for (i=0; iNWingSection(); i++) { pFoil = foil(pWing->LeftFoil(i)); bFound = false; for(j=0;jm_FoilName == FoilList.at(j)) { bFound = true; break; } } if(!bFound) FoilList.append(pFoil->m_FoilName); } } } if(pStab) { for (i=0; iNWingSection(); i++) { pFoil = foil(pStab->RightFoil(i)); bFound = false; for(j=0;jm_FoilName == FoilList.at(j)) { bFound = true; break; } } if(!bFound) FoilList.append(pFoil->m_FoilName); } if(!pStab->m_bSymetric) { for (i=0; iNWingSection(); i++) { pFoil = foil(pStab->LeftFoil(i)); bFound = false; for(j=0;jm_FoilName == FoilList.at(j)){ bFound = true; break; } } if(!bFound) FoilList.append(pFoil->m_FoilName); } } } if(pFin) { for (i=0; iNWingSection(); i++) { pFoil = foil(pFin->RightFoil(i)); bFound = false; for(j=0;jm_FoilName == FoilList.at(j)) { bFound = true; break; } } if(!bFound) FoilList.append(pFoil->m_FoilName); } if(!pFin->m_bSymetric) { for (i=0; iNWingSection(); i++) { pFoil = foil(pFin->LeftFoil(i)); bFound = false; for(j=0;jm_FoilName == FoilList.at(j)) { bFound = true; break; } } if(!bFound) FoilList.append(pFoil->m_FoilName); } } } //write the number of foils ar << 100001;//unused ar << FoilList.size(); for (i=0; iSerialize(ar, true); } int n = 0; for (i=0; im_FoilName == pFoil->m_FoilName) n++; } } //then write polars ar << n; for (i=0; im_FoilName == pFoil->m_FoilName) { pPolar->Serialize(ar, true); } } } ar<<0;//no Opps // next the bodies if(pPlane && pPlane->body()) { ar << 1; pPlane->body()->SerializeBody(ar, true); } else ar <<0; //no plane // last write the plane... if(pPlane) { ar <<1; pPlane->SerializePlane(ar, true); } else ar <<0; ar << 0;//no POpps QAFoil *pAFoil = (QAFoil*)m_pAFoil; pAFoil->m_pSF->Serialize(ar, true); // pAFoil->m_pPF->Serialize(ar, true); return true; } bool MainFrame::SerializeProject(QDataStream &ar, bool bIsStoring) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QMiarex *pMiarex = (QMiarex*)m_pMiarex; QAFoil *pAFoil = (QAFoil*)m_pAFoil; Wing *pWing = NULL; WPolar *pWPolar = NULL; WingOpp *pWOpp = NULL; PlaneOpp *pPOpp = NULL; Plane *pPlane = NULL; Body *pBody = NULL; Polar *pPolar = NULL; Foil *pFoil = NULL; QString str; int i, n, j, k; float f; if (bIsStoring) { // storing code ar << 100014; // 100014 : Removed Point Foil // 100013 : Added CoG serialization // 100012 : Added sideslip // 100011 : Added Body serialization // 100010 : Converted to I.S. units // 100009 : added serialization of opps in numbered format // 100008 : Added m_WPolarDlg.m_bTiltedGeom, m_WPolarDlg.m_bWakeRollUp // 100006 : version 2.99Beta001 format // 100005 : version 2.00 format //Archive format introduced in Beta V22 // Write units //added in Beta v16 // Save analysis settings // added in Beta v22 ar << s_LengthUnit; ar << s_AreaUnit; ar << s_WeightUnit; ar << s_SpeedUnit; ar << s_ForceUnit; ar << s_MomentUnit; if(WPolarDlg::s_WPolar.m_WPolarType==FIXEDSPEEDPOLAR) ar<<1; else if(WPolarDlg::s_WPolar.m_WPolarType==FIXEDLIFTPOLAR) ar<<2; else if(WPolarDlg::s_WPolar.m_WPolarType==FIXEDAOAPOLAR) ar<<4; else if(WPolarDlg::s_WPolar.m_WPolarType==STABILITYPOLAR) ar<<7; else ar << 0; ar << (float)WPolarDlg::s_WPolar.m_Mass; ar << (float)WPolarDlg::s_WPolar.m_QInf; ar << (float)WPolarDlg::s_WPolar.m_CoG.x; ar << (float)WPolarDlg::s_WPolar.m_CoG.y; ar << (float)WPolarDlg::s_WPolar.m_CoG.z; ar << (float)WPolarDlg::s_WPolar.m_Density; ar << (float)WPolarDlg::s_WPolar.m_Viscosity; ar << (float)WPolarDlg::s_WPolar.m_ASpec; ar << (float)WPolarDlg::s_WPolar.m_Beta; if(WPolarDlg::s_WPolar.m_AnalysisMethod==LLTMETHOD) ar << 1; else if(WPolarDlg::s_WPolar.m_AnalysisMethod==VLMMETHOD) ar << 2; else if(WPolarDlg::s_WPolar.m_AnalysisMethod==PANELMETHOD) ar << 3; if (pMiarex->m_bVLM1) ar << 1; else ar << 0; ar <<123; if (WPolarDlg::s_WPolar.m_bTiltedGeom) ar << 1; else ar << 0; if (WPolarDlg::s_WPolar.m_bWakeRollUp) ar << 1; else ar << 0; ar << s_oaWing.size() ;//number of wings // Store the wings for (i=0; iSerializeWing(ar, true); } // now store all the WPolars ar << m_oaWPolar.size(); for (i=0; iSerializeWPlr(ar, bIsStoring); } // next store all the WOpps if(m_bSaveWOpps) { ar << m_oaWOpp.size(); for (i=0; iSerializeWingOpp(ar, bIsStoring); } } else ar << 0; // then the foils, polars and Opps WritePolars(ar, NULL); /** @deprecated body array is deprecated; kept to insure compatibility with versions prior to v6.09.06 */ ar << s_oaBody.size(); for (i=0; iSerializeBody(ar, bIsStoring); } // last write the planes... ar << s_oaPlane.size(); for (i=0; iSerializePlane(ar, bIsStoring); } if(m_bSaveWOpps) { // not forgetting their POpps ar << m_oaPOpp.size(); for (i=0; iSerializePOpp(ar, bIsStoring); } } else ar << 0; pAFoil->m_pSF->Serialize(ar, bIsStoring); // pAFoil->m_pPF->Serialize(ar, bIsStoring); QApplication::restoreOverrideCursor(); return true; } else { // LOADING CODE int ArchiveFormat; ar >> n; if(n<100000) { // then n is the number of wings to load // up to v1.99beta15 ArchiveFormat = 100000; } else { // then n is the ArchiveFormat number ArchiveFormat = n; ar >> s_LengthUnit; ar >> s_AreaUnit; ar >> s_WeightUnit; ar >> s_SpeedUnit; ar >> s_ForceUnit; if(ArchiveFormat>=100005) { ar >> s_MomentUnit; } SetUnits(s_LengthUnit, s_AreaUnit, s_SpeedUnit, s_WeightUnit, s_ForceUnit, s_MomentUnit, s_mtoUnit, s_m2toUnit, s_mstoUnit, s_kgtoUnit, s_NtoUnit, s_NmtoUnit); if(ArchiveFormat>=100004) { ar >>k; if(k==1) WPolarDlg::s_WPolar.m_WPolarType = FIXEDSPEEDPOLAR; else if(k==2) WPolarDlg::s_WPolar.m_WPolarType = FIXEDLIFTPOLAR; else if(k==4) WPolarDlg::s_WPolar.m_WPolarType = FIXEDAOAPOLAR; else if(k==7) WPolarDlg::s_WPolar.m_WPolarType = STABILITYPOLAR; ar >> f; WPolarDlg::s_WPolar.m_Mass=f; ar >> f; WPolarDlg::s_WPolar.m_QInf=f; if(ArchiveFormat>=100013) { ar >> f; WPolarDlg::s_WPolar.m_CoG.x=f; ar >> f; WPolarDlg::s_WPolar.m_CoG.y=f; ar >> f; WPolarDlg::s_WPolar.m_CoG.z=f; } else { ar >> f; WPolarDlg::s_WPolar.m_CoG.x=f; WPolarDlg::s_WPolar.m_CoG.y=0; WPolarDlg::s_WPolar.m_CoG.z=0; } if(ArchiveFormat<100010) WPolarDlg::s_WPolar.m_CoG.x=f/1000.0; ar >> f; WPolarDlg::s_WPolar.m_Density = f; ar >> f; WPolarDlg::s_WPolar.m_Viscosity = f; ar >> f; WPolarDlg::s_WPolar.m_ASpec = f; if(ArchiveFormat>=100012) { ar >>f; WPolarDlg::s_WPolar.m_Beta=f; } ar >> k; if(k==1) WPolarDlg::s_WPolar.m_AnalysisMethod=LLTMETHOD; else if(k==2) WPolarDlg::s_WPolar.m_AnalysisMethod=VLMMETHOD; else if(k==3) WPolarDlg::s_WPolar.m_AnalysisMethod=PANELMETHOD; } if(ArchiveFormat>=100006) { ar >> k; if (k) pMiarex->m_bVLM1 = true; else pMiarex->m_bVLM1 = false; ar >> k; // if (k) WPolarDlg::m_bMiddle = true; // else WPolarDlg::m_bMiddle = false; } if(ArchiveFormat>=100008) { ar >> k; if (k) WPolarDlg::s_WPolar.m_bTiltedGeom = true; else WPolarDlg::s_WPolar.m_bTiltedGeom = false; ar >> k; if (k) WPolarDlg::s_WPolar.m_bWakeRollUp = true; else WPolarDlg::s_WPolar.m_bWakeRollUp = false; } // and read n again ar >> n; } // WINGS FIRST for (i=0;iSerializeWing(ar, bIsStoring)) { if(pWing) delete pWing; QApplication::restoreOverrideCursor(); return false; } if(pWing) { pWing = pMiarex->AddWing(pWing); } else { if(pWing) delete pWing; } } //THEN WPOLARS ar >> n;// number of WPolars to load bool bWPolarOK; for (i=0;iSerializeWPlr(ar, bIsStoring); //force compatibilty if(pWPolar->m_AnalysisMethod==PANELMETHOD && pWPolar->m_WPolarType==STABILITYPOLAR) pWPolar->m_bThinSurfaces = true; if (!bWPolarOK) { if(pWPolar) delete pWPolar; QApplication::restoreOverrideCursor(); return false; } if(!pWPolar->m_AnalysisMethod==LLTMETHOD && ArchiveFormat <100003) pWPolar->ResetWPlr();//former VLM version was flawed // if(pWPolar->m_WPolarType==STABILITYPOLAR) pWPolar->m_bThinSurfaces = true; if(pWPolar->m_PolarFormat!=1020 || pWPolar->m_WPolarType!=STABILITYPOLAR)//v601 stability polars are obsolete pWPolar = pMiarex->AddWPolar(pWPolar); } //THEN WOPPS ar >> n;// number of WOpps to load bool bWOppOK; for (i=0;iSerializeWingOpp(ar, bIsStoring); if(pWOpp && bWOppOK) { pWing = pMiarex->GetWing(pWOpp->m_WingName); if(pWing) pWOpp->m_MAChord = pWing->m_MAChord; else bWOppOK = false; } } if (!bWOppOK) { if(pWOpp) delete pWOpp; QApplication::restoreOverrideCursor(); return false; } if(pWOpp->m_AnalysisMethod==LLTMETHOD || ArchiveFormat >=100006)//former VLM version was flawed pMiarex->InsertWOpp(pWOpp); else delete pWOpp; } ar >> n; //=100000 ... unused //THEN FOILS, POLARS and OPPS if(ArchiveFormat>=100009) { if(!LoadPolarFileV3(ar, bIsStoring,100002)) { QApplication::restoreOverrideCursor(); return false; } } else { if(ArchiveFormat>=100006) { if(!LoadPolarFileV3(ar, bIsStoring)) { QApplication::restoreOverrideCursor(); return false; } } else { QApplication::restoreOverrideCursor(); return false; } } if(n==100000) { for (j=0; jm_FoilName==pPolar->m_FoilName) { pPolar->m_ACrit = 9.0; pPolar->m_XTop = 1.0; pPolar->m_XBot = 1.0; str = QString("_N%1").arg(9.0,4,'f',1); pPolar->m_PlrName += str; break; } } } } if(ArchiveFormat>=100011) { ar >> n;// number of Bodies to load for (i=0;iSerializeBody(ar, bIsStoring)) { s_oaBody.append(pBody); } else { if(pBody) delete pBody; QApplication::restoreOverrideCursor(); return false; } } } if(ArchiveFormat>=100006) { //read the planes ar >> n; for (i=0; iSerializePlane(ar, bIsStoring)) { pMiarex->AddPlane(pPlane); } else { if(pPlane) delete pPlane; QApplication::restoreOverrideCursor(); return false; } } } // attach the body pointers to the Plane objects for (int ib=0; ibAddBody(pBody); } //and their pPolars if(ArchiveFormat <100007) { ar >> n;// number of WPolars to load for (i=0;iSerializeWPlr(ar, bIsStoring)) { if(pWPolar) delete pWPolar; QApplication::restoreOverrideCursor(); return false; } if(!pWPolar->m_AnalysisMethod==LLTMETHOD && ArchiveFormat <100003) pWPolar->ResetWPlr(); pMiarex->AddWPolar(pWPolar); } } ar >> n;// number of PlaneOpps to load for (i=0;iSerializePOpp(ar, bIsStoring)) { if(pPOpp) delete pPOpp; QApplication::restoreOverrideCursor(); return false; } pMiarex->AddPOpp(false, NULL, NULL, NULL, pPOpp); } } pMiarex->m_pCurPOpp = NULL; pAFoil->m_pSF->Serialize(ar, bIsStoring); for (i=0; iComputeGeometry(); } if(m_iApp==MIAREX) pMiarex->SetUFO(); pMiarex->UpdateUnits(); QApplication::restoreOverrideCursor(); return true; } } void MainFrame::SetCurrentFoil(Foil* pFoil) { QXDirect *pXDirect = (QXDirect*)m_pXDirect; QAFoil *pAFoil = (QAFoil*)m_pAFoil; pXDirect->SetFoil(pFoil); pAFoil->SelectFoil(pFoil); s_pCurFoil = pFoil; } void MainFrame::SetMenus() { if(m_iApp==NOAPP) { menuBar()->clear(); menuBar()->addMenu(fileMenu); menuBar()->addMenu(optionsMenu); menuBar()->addMenu(helpMenu); } else if(m_iApp==XFOILANALYSIS) { menuBar()->clear(); menuBar()->addMenu(fileMenu); menuBar()->addMenu(XDirectViewMenu); menuBar()->addMenu(FoilMenu); menuBar()->addMenu(DesignMenu); menuBar()->addMenu(XFoilAnalysisMenu); menuBar()->addMenu(PolarMenu); menuBar()->addMenu(OpPointMenu); menuBar()->addMenu(optionsMenu); menuBar()->addMenu(helpMenu); } else if(m_iApp==INVERSEDESIGN) { menuBar()->clear(); menuBar()->addMenu(fileMenu); menuBar()->addMenu(XInverseViewMenu); menuBar()->addMenu(InverseFoilMenu); menuBar()->addMenu(optionsMenu); menuBar()->addMenu(helpMenu); } else if(m_iApp==DIRECTDESIGN) { menuBar()->clear(); menuBar()->addMenu(fileMenu); menuBar()->addMenu(AFoilViewMenu); menuBar()->addMenu(AFoilDesignMenu); menuBar()->addMenu(AFoilSplineMenu); menuBar()->addMenu(optionsMenu); menuBar()->addMenu(helpMenu); } else if(m_iApp== MIAREX) { menuBar()->clear(); menuBar()->addMenu(fileMenu); menuBar()->addMenu(MiarexViewMenu); menuBar()->addMenu(UFOMenu); menuBar()->addMenu(MiarexWPlrMenu); menuBar()->addMenu(MiarexWOppMenu); menuBar()->addMenu(MiarexAnalysisMenu); menuBar()->addMenu(optionsMenu); menuBar()->addMenu(helpMenu); } } Foil* MainFrame::SetModFoil(Foil* pNewFoil, bool bKeepExistingFoil) { // Adds the buffer foil to the ObArray, // gives it a proper name, FoilName or another, // selects it , // and initializes XFoil, comboboxes and everything. QXDirect *pXDirect = (QXDirect*)m_pXDirect; QAFoil *pAFoil = (QAFoil*)m_pAFoil; int j,k,l; bool bExists = false; bool bNotFound = true; pNewFoil->m_bSaved = false; Foil*pOldFoil; if(!pNewFoil->m_FoilName.length()) { bExists = true; } else { for (j=0; jm_FoilName == pNewFoil->m_FoilName) { bExists = true; if(bKeepExistingFoil) { delete pNewFoil; pNewFoil = NULL; s_pCurFoil = NULL; return pOldFoil; } break; } } } if(bExists) { while(bNotFound) { Foil *pFoil; QStringList NameList; for(k=0; km_FoilName); } RenameDlg renDlg(this); renDlg.m_pstrArray = & NameList; renDlg.m_strQuestion = tr("A foil of that name already exists\nPlease enter a new name"); renDlg.m_strName = pNewFoil->m_FoilName; renDlg.InitDialog(); bool exists = false; QString strong; int resp = renDlg.exec(); strong = renDlg.m_strName; if(QDialog::Accepted == resp) { strong = renDlg.m_strName; for (l=0; lm_FoilName == strong) exists = true; } if (!exists) { bNotFound = false;// at last (users !...) // so create and add foil to array pNewFoil->m_FoilName = strong; AddFoil(pNewFoil); SetSaveState(false); } } else if(resp==10) { // the user wants to overwrite existing airfoil // So delete any foil with that name for (l=s_oaFoil.size()-1;l>=0; l--) { pOldFoil = (Foil*)s_oaFoil.at(l); if(pOldFoil->m_FoilName == strong) { pNewFoil->m_FoilColor = pOldFoil->m_FoilColor; pNewFoil->m_nFoilStyle = pOldFoil->m_nFoilStyle; pNewFoil->m_nFoilWidth = pOldFoil->m_nFoilWidth; pNewFoil->m_bPoints = pOldFoil->m_bPoints; s_oaFoil.removeAt(l); delete pOldFoil; if(s_pCurFoil == pOldFoil) s_pCurFoil = NULL; } } // delete all associated OpPoints OpPoint * pOpPoint; for (l=m_oaOpp.size()-1;l>=0;l--) { pOpPoint = (OpPoint*)m_oaOpp[l]; if (pOpPoint->m_strFoilName == strong) { m_oaOpp.removeAt(l); if(pOpPoint == pXDirect->m_pCurOpp) pXDirect->m_pCurOpp = NULL; delete pOpPoint; } } // delete all Polar results for that airfoil, but keep polar for analysis Polar * pPolar; for (l=0; l m_FoilName == strong) { pPolar->ResetPolar(); } } // finally add to array pNewFoil->m_FoilName = strong; AddFoil(pNewFoil); SetSaveState(false); bNotFound = false;//exit loop } else { // Cancel so exit delete pNewFoil; pNewFoil = NULL; s_pCurFoil = NULL; return NULL;// foil not added } } } else { AddFoil(pNewFoil); SetSaveState(false); } pAFoil->SelectFoil(pNewFoil); pXDirect->SetFoil(pNewFoil); s_pCurFoil = pNewFoil; return pNewFoil;// foil added } void MainFrame::SetProjectName(QString PathName) { m_FileName = PathName; int pos = PathName.lastIndexOf("/"); if (pos>0) s_ProjectName = PathName.right(PathName.length()-pos-1); else s_ProjectName = PathName; if(s_ProjectName.length()>4) { s_ProjectName = s_ProjectName.left(s_ProjectName.length()-4); m_pctrlProjectName->setText(s_ProjectName); } } void MainFrame::SetSaveState(bool bSave) { s_bSaved = bSave; int len = s_ProjectName.length(); if(s_ProjectName.right(1)=="*") s_ProjectName = s_ProjectName.left(len-1); if (!bSave) { s_ProjectName += "*"; } m_pctrlProjectName->setText(s_ProjectName); } void MainFrame::SetGraphSettings(Graph *pGraph) { QXDirect *pXDirect = (QXDirect*)m_pXDirect; QMiarex *pMiarex = (QMiarex*)m_pMiarex; QXInverse *pXInverse = (QXInverse*)m_pXInverse; pXDirect->m_pCpGraph->CopySettings(pGraph, false); for(int ig=0; igm_PlrGraph[ig].CopySettings(pGraph, false); } pXInverse->m_QGraph.CopySettings(pGraph, false); pMiarex->m_LongRLGraph.CopySettings(pGraph, false); pMiarex->m_LatRLGraph.CopySettings(pGraph, false); pMiarex->m_CpGraph.CopySettings(pGraph, false); for(int ig=0; igm_WPlrGraph[ig].CopySettings(pGraph, false); pMiarex->m_WingGraph[ig].CopySettings(pGraph, false); pMiarex->m_TimeGraph[ig].CopySettings(pGraph, false); } } QString MainFrame::ShortenFileName(QString &PathName) { QString strong, strange; if(PathName.length()>60) { int pos = PathName.lastIndexOf('/'); if (pos>0) { strong = '/'+PathName.right(PathName.length()-pos-1); strange = PathName.left(60-strong.length()-6); pos = strange.lastIndexOf('/'); if(pos>0) strange = strange.left(pos)+"/... "; strong = strange+strong; } else { strong = PathName.left(40); } } else strong = PathName; return strong; } void MainFrame::UpdateUFOs() { // fills combobox with wing and plane names // then selects the current wing or plane, if any // else selects the first, if any // else disables the combobox int i; QString strong; m_pctrlUFO->clear(); QMiarex *pMiarex= (QMiarex*)m_pMiarex; Wing *pWing, *pCurWing; Plane *pPlane, *pCurPlane; pCurWing = pMiarex->m_pCurWing; pCurPlane = pMiarex->m_pCurPlane; QStringList UFONames; for (i=0; im_WingName); } for (i=0; iPlaneName()); } UFONames.sort(); m_pctrlUFO->addItems(UFONames); if (m_pctrlUFO->count()) { m_pctrlUFO->setEnabled(true); //select the current Wing, if any... if(pCurPlane) { int pos = m_pctrlUFO->findText(pCurPlane->PlaneName()); if(pos>=0) { m_pctrlUFO->setCurrentIndex(pos); } else { // if error, select the first m_pctrlUFO->setCurrentIndex(0); strong = m_pctrlUFO->itemText(0); } } else if(pCurWing) { int pos = m_pctrlUFO->findText(pCurWing->m_WingName); if(pos>=0) { m_pctrlUFO->setCurrentIndex(pos); } else { // if error, select the first m_pctrlUFO->setCurrentIndex(0); strong = m_pctrlUFO->itemText(0); } } //... else select the first else { m_pctrlUFO->setCurrentIndex(0); strong = m_pctrlUFO->itemText(0); } } else { m_pctrlUFO->clear(); m_pctrlUFO->setEnabled(false); pMiarex->m_pCurPlane = NULL; pMiarex->m_pCurWing = NULL; pMiarex->m_pCurWPolar = NULL; pMiarex->m_pCurWOpp = NULL; pMiarex->m_pCurPOpp = NULL; } UpdateWPolars(); } void MainFrame::UpdateWPolars() { // fills the combobox with WPolar names associated to Miarex's current wing // then selects Miarex current WPolar if any, else selects the first, if any // else disables the combobox QMiarex * pMiarex = (QMiarex*)m_pMiarex; WPolar *pWPolar; QString UFOName; int i; m_pctrlWPolar->clear(); Plane *pCurPlane = pMiarex->m_pCurPlane; Wing *pCurWing = pMiarex->m_pCurWing; WPolar *pCurWPlr = pMiarex->m_pCurWPolar; if(pCurPlane) UFOName = pCurPlane->PlaneName(); else if(pCurWing) UFOName = pCurWing->m_WingName; else UFOName = ""; if(!UFOName.length()) { pMiarex->m_pCurWPolar = NULL; m_pctrlWPolar->setEnabled(false); return; } int size = 0; //count the number of WPolars associated to the current Wing for(i=0; im_UFOName == UFOName) { size++; } } if(size) { // if any m_pctrlWPolar->blockSignals(true); m_pctrlWPolar->setEnabled(true); for (i=0; im_UFOName == UFOName) { m_pctrlWPolar->addItem(pWPolar->m_PlrName); } } //select the current Wing Polar, if any... if(pCurWPlr) { int pos = m_pctrlWPolar->findText(pCurWPlr->m_PlrName); if(pos>=0) m_pctrlWPolar->setCurrentIndex(pos); else { // if error, select the first m_pctrlWPolar->setCurrentIndex(0); } } //... else select the first else { m_pctrlWPolar->setCurrentIndex(0); } m_pctrlWPolar->blockSignals(false); } else { // otherwise disable control m_pctrlWPolar->setEnabled(false); pMiarex->m_pCurWPolar = NULL; pMiarex->m_pCurWOpp = NULL; } } /** * Fills the combobox with the WOpp parameters associated to Miarex' current WPLr, * then selects the current WingOpp or PlaneOpp if any, else selects the first, if any, * else disables the combobox. */ void MainFrame::UpdateWOpps() { QMiarex * pMiarex = (QMiarex*)m_pMiarex; WingOpp *pWOpp; PlaneOpp *pPOpp; int i; QString str; m_pctrlWOpp->clear(); Plane *pCurPlane = pMiarex->m_pCurPlane; Wing *pCurWing = pMiarex->m_pCurWing; WPolar *pCurWPlr = pMiarex->m_pCurWPolar; if (!pCurWing || !pCurWing->m_WingName.length() || !pCurWPlr || !pCurWPlr->m_PlrName.length()) { m_pctrlWOpp->setEnabled(false); pMiarex->m_pCurWOpp = NULL; return; } if(pCurPlane) { int size = 0; //count the number of POpps associated to the current Wing & WPolar for (i=0; im_PlaneName==pCurPlane->PlaneName() && pPOpp->m_PlrName==pCurWPlr->m_PlrName) { size++; } } if (size) { // if any m_pctrlWOpp->setEnabled(true); for (int i=0; im_PlaneName == pCurPlane->PlaneName() && pPOpp->m_PlrName == pCurWPlr->m_PlrName) { if(pCurWPlr->m_WPolarTypem_Alpha,8,'f',3); else if(pCurWPlr->m_WPolarType==FIXEDAOAPOLAR) str = QString("%L1").arg(pPOpp->m_QInf,8,'f',3); else if(pCurWPlr->m_WPolarType==STABILITYPOLAR) str = QString("%L1").arg(pPOpp->m_Ctrl,8,'f',3); m_pctrlWOpp->addItem(str); } } if(pMiarex->m_pCurPOpp) SelectWOpp(pMiarex->m_pCurPOpp); else m_pctrlWOpp->setCurrentIndex(0); } else { // otherwise disable control m_pctrlWOpp->setEnabled(false); pMiarex->m_pCurPOpp = NULL; } } else { int size = 0; //count the number of WOpps associated to the current Wing & WPolar for (i=0; im_WingName == pCurWing->m_WingName && pWOpp->m_PlrName == pCurWPlr->m_PlrName) { size++; } } if (size) { // if any m_pctrlWOpp->setEnabled(true); for (int i=0; im_WingName == pCurWing->m_WingName && pWOpp->m_PlrName == pCurWPlr->m_PlrName) { if(pCurWPlr->m_WPolarTypem_Alpha,8,'f',3); else if(pCurWPlr->m_WPolarType==FIXEDAOAPOLAR) str = QString("%L1").arg(pWOpp->m_QInf,8,'f',3); else if(pCurWPlr->m_WPolarType==STABILITYPOLAR) str = QString("%L1").arg(pWOpp->m_Ctrl,8,'f',3); m_pctrlWOpp->addItem(str); } } if(pMiarex->m_pCurWOpp) SelectWOpp(pMiarex->m_pCurWOpp); else m_pctrlWOpp->setCurrentIndex(0); } else { // otherwise disable control m_pctrlWOpp->setEnabled(false); pMiarex->m_pCurWOpp = NULL; // Miarex.SetWOpp(true); } } } /** * Fills the combobox with the Foil names, * then selects the current Foil if any, else selects the first, if any, * else disables the combobox */ void MainFrame::UpdateFoils() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; int i, pos; QString strong; m_pctrlFoil->clear(); Foil *pFoil; for (i=0; iaddItem(pFoil->m_FoilName); } if (m_pctrlFoil->count()) { m_pctrlFoil->setEnabled(true); //select the current foil, if any... if (s_pCurFoil) { pos = m_pctrlFoil->findText(s_pCurFoil->m_FoilName); if (pos>=0) m_pctrlFoil->setCurrentIndex(pos); else { // if error, select the first... m_pctrlFoil->setCurrentIndex(0); strong = m_pctrlFoil->itemText(0); //...and set it // g_ppCurFoil = GetFoil(strong); // pXDirect->SetFoil(strong); } } //... else select the first else { // if error, select the first... m_pctrlFoil->setCurrentIndex(0); strong = m_pctrlFoil->itemText(0); //...and set it pXDirect->SetFoil(foil(strong)); } } else { m_pctrlFoil->clear(); m_pctrlFoil->setEnabled(false); pXDirect->SetFoil(); } UpdatePolars(); } /** * Fills the combobox with polar names associated to the current foil, * then selects XDirect current polar if any, else selects the first, if any, * else disables the combobox, */ void MainFrame::UpdatePolars() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; int i, size, pos; Polar *pPolar; QString strong; m_pctrlPolar->clear(); s_pCurFoil = s_pCurFoil; if(!s_pCurFoil || !s_pCurFoil->m_FoilName.length()) { m_pctrlPolar->setEnabled(false); m_pctrlOpPoint->clear(); m_pctrlOpPoint->setEnabled(false); return; } size = 0; //count the number of polars associated to the current foil for (i=0; im_FoilName == s_pCurFoil->m_FoilName) { size++; } } if (size) { // if any m_pctrlPolar->setEnabled(true); for (i=0; im_FoilName == s_pCurFoil->m_FoilName) { m_pctrlPolar->addItem(pPolar->m_PlrName); } } if(pXDirect->m_pCurPolar) { pos = m_pctrlPolar->findText(pXDirect->m_pCurPolar->m_PlrName); if(pos>=0) m_pctrlPolar->setCurrentIndex(pos); else { m_pctrlPolar->setCurrentIndex(0); strong = m_pctrlPolar->itemText(0); } } else { m_pctrlPolar->setCurrentIndex(0); strong = m_pctrlPolar->itemText(0); } } else { // otherwise disable control m_pctrlPolar->setEnabled(false); } UpdateOpps(); } /** * Fills the combobox with the OpPoint values associated to the current foil, * then selects the current OpPoint if any, else selects the first, if any, * else disables the combobox. */ void MainFrame::UpdateOpps() { QXDirect *pXDirect = (QXDirect*)m_pXDirect; int i, pos; OpPoint *pOpp; QString strong, str; m_pctrlOpPoint->clear(); Polar *pCurPlr = pXDirect->m_pCurPolar; if (!s_pCurFoil || !s_pCurFoil->m_FoilName.length() || !pCurPlr || !pCurPlr->m_PlrName.length()) { m_pctrlOpPoint->clear(); m_pctrlOpPoint->setEnabled(false); return; } int size = 0; //count the number of Opps associated to the current foil & polar for (i=0; im_strFoilName == s_pCurFoil->m_FoilName && pOpp->m_strPlrName == pCurPlr->m_PlrName) { size++; } } if (size) { // if any m_pctrlOpPoint->setEnabled(true); for (i=0; im_strFoilName == s_pCurFoil->m_FoilName && pOpp->m_strPlrName == pCurPlr->m_PlrName) { if (pCurPlr->m_PolarType !=FIXEDAOAPOLAR) { // if(qAbs(pOpp->Alpha)<0.0001) pOpp->Alpha = 0.0001; str = QString("%L1").arg(pOpp->Alpha,8,'f',3); m_pctrlOpPoint->addItem(str); } else { str = QString("%L1").arg(pOpp->Reynolds,8,'f',0); m_pctrlOpPoint->addItem(str); } } } if (pXDirect->m_pCurOpp && pXDirect->m_pCurOpp->m_strFoilName==s_pCurFoil->m_FoilName) { //select it if (pCurPlr->m_PolarType !=FIXEDAOAPOLAR) { str = QString("%8.2f").arg(pXDirect->m_pCurOpp->Alpha); } else { str = QString("%8.0f").arg(pXDirect->m_pCurOpp->Reynolds); } pos = m_pctrlOpPoint->findText(str); if(pos>=0) m_pctrlOpPoint->setCurrentIndex(pos); } else { //select the first m_pctrlOpPoint->setCurrentIndex(0); str = m_pctrlOpPoint->itemText(0); QByteArray textline; const char *text; double x; textline = str.toLatin1(); text = textline.constData(); int res = sscanf(text, "%lf", &x); if(res==1) pXDirect->SetOpp(x); else pXDirect->SetOpp(); if(!pXDirect->m_pCurOpp) { m_pctrlOpPoint->setEnabled(false); pXDirect->m_pCurOpp = NULL; } } if (m_pctrlOpPoint->count()) m_pctrlOpPoint->setEnabled(true); else m_pctrlOpPoint->setEnabled(false); } else { // otherwise disable control m_pctrlOpPoint->setEnabled(false); pXDirect->m_pCurOpp = NULL; m_pctrlOpPoint->clear(); } } void MainFrame::updateRecentFileActions() { int numRecentFiles = qMin(m_RecentFiles.size(), MAXRECENTFILES); QString text; for (int i = 0; i < numRecentFiles; ++i) { text = tr("&%1 %2").arg(i + 1).arg(ShortenFileName(m_RecentFiles[i])); recentFileActs[i]->setText(text); recentFileActs[i]->setData(m_RecentFiles[i]); recentFileActs[i]->setVisible(true); } for (int j = numRecentFiles; j < MAXRECENTFILES; ++j) recentFileActs[j]->setVisible(false); separatorAct->setVisible(numRecentFiles > 0); } void MainFrame::UpdateView() { switch(m_iApp) { case XFOILANALYSIS: { QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->UpdateView(); break; } case DIRECTDESIGN: { QAFoil *pAFoil= (QAFoil*)m_pAFoil; pAFoil->UpdateView(); break; } case MIAREX: { QMiarex *pMiarex= (QMiarex*)m_pMiarex; pMiarex->UpdateView(); break; } case INVERSEDESIGN: { QXInverse *pXInverse = (QXInverse*)m_pXInverse; pXInverse->UpdateView(); break; } default: break; } } void MainFrame::WritePolars(QDataStream &ar, Foil *pFoil) { int i; if(!pFoil) { ar << 100003; //100003 : added foil comment //100002 : means we are serializings opps in the new numbered format //100001 : transferred NCrit, XTopTr, XBotTr to polar file //first write foils ar << s_oaFoil.size(); for (i=0; iSerialize(ar, true); } //then write polars ar << s_oaPolar.size(); Polar * pPolar ; for (i=0; iSerialize(ar, true); } } else { ar << 100003; //100003 : added foil comment //100002 : means we are serializings opps in the new numbered format //100001 : transferred NCrit, XTopTr, XBotTr to polar file //first write foil ar << 1;//only one this time pFoil->Serialize(ar,true); //count polars associated to the foil Polar * pPolar ; int n=0; for (i=0; im_FoilName == pFoil->m_FoilName) n++; } //then write polars ar << n; for (i=0; im_FoilName == pFoil->m_FoilName) pPolar->Serialize(ar, true); } } if(m_bSaveOpps) { ar << m_oaOpp.size(); OpPoint * pOpp ; for (i=0; iSerialize(ar,true,100002); } } else ar << 0; } void MainFrame::OnPolarProps() { if(m_iApp==XFOILANALYSIS) { QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->OnPolarProps(); } else if(m_iApp==MIAREX) { QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->OnWPolarProps(); } } void MainFrame::OnWOppProps() { if(m_iApp==XFOILANALYSIS) { QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->OnOpPointProps(); } else if(m_iApp==MIAREX) { QMiarex *pMiarex = (QMiarex*)m_pMiarex; pMiarex->OnWOppProps(); } } void MainFrame::OnDuplicateFoil() { if(!s_pCurFoil) return; Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(s_pCurFoil); pNewFoil->InitFoil(); if(SetModFoil(pNewFoil)) { if(m_iApp==XFOILANALYSIS) { QXDirect *pXDirect = (QXDirect*)m_pXDirect; pXDirect->m_BufferFoil.CopyFoil(pNewFoil); pXDirect->SetFoil(pNewFoil); } else if(m_iApp==DIRECTDESIGN) { QAFoil *pAFoil= (QAFoil*)m_pAFoil; //then duplicate the buffer foil and add it Foil *pNewFoil = new Foil(); pNewFoil->CopyFoil(pAFoil->m_pBufferFoil); pAFoil->FillFoilTable(); pAFoil->SelectFoil(pNewFoil); } UpdateFoils(); UpdateView(); SetSaveState(false); } } void MainFrame::SetupDataDir() { #ifdef Q_WS_MAC s_TranslationDir.setPath(qApp->applicationDirPath()+"/translations/"); s_StylesheetDir.setPath(qApp->applicationDirPath()+"/qss/"); #endif #ifdef Q_OS_WIN s_TranslationDir.setPath(qApp->applicationDirPath()+"/translations"); s_StylesheetDir.setPath(qApp->applicationDirPath()+"/qss"); #endif #ifdef Q_OS_LINUX s_TranslationDir.setPath("/usr/share/xflr5/translations"); s_StylesheetDir.setPath("/usr/share/xflr5/qss"); #endif } void MainFrame::ReadStyleSheet(QString styleSheetName, QString &styleSheet) { QFile file(s_StylesheetDir.canonicalPath()+"/"+styleSheetName+".qss"); if(file.open(QFile::ReadOnly)) { styleSheet = QLatin1String(file.readAll()); qApp->setStyleSheet(styleSheet); } } xflr5-6.09-06/src/objects/000755 001750 000144 00000000000 12250003437 016502 5ustar00techwinderusers000000 000000 xflr5-6.09-06/src/objects/WingOpp.h000644 001750 000144 00000020637 12247174403 020256 0ustar00techwinderusers000000 000000 /**************************************************************************** WingOpp Class Copyright (C) 2005-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file * * This class defines the operating point object for the 3D analysis of wings. * */ #ifndef WINGOPP_H #define WINGOPP_H /** *@brief * This class implements the operating point object which stores the data of plane analysis * In the case of an analysis of an independant wing, the instance of this WingOpp class is uniquely associated to an instance of a WPolar, which is itself uniquely associated to the Wing object. Alternatively, the WingOpp may be a member variable of a PlaneOpp object. The data is stored in International Standard Units, i.e. meters, seconds, kg, and Newtons. Angular data is stored in degrees. */ #include "CVector.h" #include "../params.h" #include #include #include #include using namespace std; class WingOpp { friend class QMiarex; friend class MainFrame; friend class WPolar; friend class PlaneOpp; friend class StabViewDlg; friend class PanelAnalysisDlg; friend class ObjectPropsDlg; public: WingOpp(int PanelArraySize=0); ~WingOpp(); private: //________________METHODS____________________________________ bool SerializeWingOpp(QDataStream &ar, bool bIsStoring); bool Export(QTextStream &out, enumTextFileType FileType); void GetWingOppProperties(QString &WingOppProperties); double GetMaxLift(); void Allocate(int PanelArraySize); void ReleasePanelSizeArrays(); private: QString m_WingName; // the wing name to which the WingOpp belongs QString m_PlrName; // the polar name to which the WingOpp belongs bool m_bIsVisible; /**< true if the WingOpp's curve is visible in the active view */ bool m_bShowPoints; /**< true if the WingOpp's curve points are visible in the active graphs */ bool m_bVLM1; /**< true if the WingOpp is the result of a horseshoe VLM calculation, flase if quad ring */ bool m_bThinSurface; /**< true if the WingOpp is the results of a calculation on the middle surface */ bool m_bTiltedGeom; /**< true if the WingOpp is the results of a calculation on the tilted geometry */ int m_Style; /**< the index of the style with which to draw the WingOpp's curve */ int m_Width; /**< the width with which to draw the WingOpp's curve */ QColor m_Color; /**< the color with which to draw the WingOpp's curve */ // int m_WingType; //0 for wing, 1 for elevator, 2 for fin int m_nWakeNodes; /**< the number of wake nodes */ int m_NXWakePanels; /**< the number of wake panels */ int m_nControls; /**< the number of control surfaces associated to the WingOpp */ double m_FirstWakePanel; /**< the size of the first wake panel in the array. */ double m_WakeFactor; /**< the geometric progression factor of the panel lengths in a column of wake panels */ double m_Weight; float m_Twist[MAXSPANSTATIONS+1]; /**< the twist at span stations */ //RESULTS float m_Re[MAXSPANSTATIONS+1]; /**< the calculated Reynolds number at span stations */ float m_Cm[MAXSPANSTATIONS+1]; /**< the otal pitching moment coefficient at span stations */ float m_CmAirf[MAXSPANSTATIONS+1]; /**< the airfoil pitching moment coefficient about 1/4 chord point, at span stations */ float m_BendingMoment[MAXSPANSTATIONS+1]; /**< the bending moment at span stations */ double m_CX; /**< the total drag coefficient */ double m_CY; /**< the side force coefficient */ float m_MaxBending; /**< the bending moment at the root chord */ //non dimensional stability derivatives double CXu, CZu, Cmu, CXa, CLa, Cma, CXq, CLq, Cmq, CYb, CYp, CYr, Clb, Clp, Clr, Cnb, Cnp, Cnr; //non-dimensional control derivatives double CXe,CYe,CZe; double CLe,CMe,CNe; double m_ALong[4][4]; /**< the longitudinal state matrix */ double m_ALat[4][4]; /**< the lateral state matrix */ double m_BLong[4]; /**< the longitudinal control vector */ double m_BLat[4]; /**< the lateral control vector */ public: bool m_bOut; /**< true if there was an interpolation error of the viscous properties for this WingOpp */ int m_NVLMPanels; /**< the number of panels */ int m_NStation; /**< the number of stations along the span */ int m_nFlaps; /**< the number of trailing edge flaps */ enumAnalysisMethod m_AnalysisMethod; /**< defines by whih type of method (LLT, VLM, PANEL), this WingOpp was calculated */ enumPolarType m_WPolarType; /**< defines the type of the parent WPolar */ float *m_Cp; /**< a pointer to the array of lift coefficient for each panel */ float *m_G; /**< a pointer to the array of vortice or doublet strengths */ float *m_Sigma; /**< a pointer to the array of source strengths */ double m_Span; /**< the parent's Wing span */ double m_MAChord; /**< the parent's Wing mean aerodynamic chord*/ double m_QInf; /**< the freestream velocity */ double m_Alpha; /**< the aoa */ double m_Beta; /**< the sideslip angle */ double m_Phi; /**< the bank angle */ float m_SpanPos[MAXSPANSTATIONS+1]; /**< the spanwise position of the stations */ float m_Ai[MAXSPANSTATIONS+1]; /**< the calculated induced angles, in degrees */ float m_Chord[MAXSPANSTATIONS+1]; /**< the chord lengths at stations */ float m_ICd[MAXSPANSTATIONS+1]; /**< the induced drag coefficient at stations */ float m_PCd[MAXSPANSTATIONS+1]; /**< the viscous drag coefficient at stations */ float m_Cl[MAXSPANSTATIONS+1]; /**< the lift coefficient at stations */ float m_XCPSpanRel[MAXSPANSTATIONS+1]; /**< the relative position of the centre of pressure on each chordwise strip, in chord % */ float m_XCPSpanAbs[MAXSPANSTATIONS+1]; /**< the absolute position of the centre of pressure on each chordwise strip */ float m_StripArea[MAXSPANSTATIONS+1]; /**< the area of the chordwise strips */ float m_XTrTop[MAXSPANSTATIONS+1]; /**< the transition location on the top surface*/ float m_XTrBot[MAXSPANSTATIONS+1]; /**< the transition location on the bottom suface */ CVector m_Vd[MAXSPANSTATIONS]; /**< the downwash at the trailing edge */ CVector m_F[MAXSPANSTATIONS]; /**< the force acting on the chordwise = sum of the panel forces on this strip*/ double m_FlapMoment[MAXSPANSECTIONS]; /**< the flap hinge moments */ double m_CL; /**< the wing lift coefficient */ double m_VCD; /**< the wing viscous drag coefficient */ double m_ICD; /**< the wing induced drag coefficient */ double m_GCm; /**< the wing pitching moment */ double m_GRm; /**< the wing rolling moment */ double m_VCm; /**< the pitching moment induced by the viscous drag forces */ double m_ICm; /**< the pitching moment induced by the pressure forces */ double m_GYm; /**< the total yawing moment */ double m_VYm; /**< the wing viscous yawing moment */ double m_IYm; /**< the wing induced yawing moment */ double m_Ctrl; /**< the control variable */ double m_XNP; /**< the neutral point position resulting from a stability calculations */ CVector m_CP; /**< the position of the centre of pressure */ complex m_EigenValue[8]; /**< the eigenvalues of the four longitudinal and four lateral modes */ complex m_EigenVector[8][4]; /**< the mongitudinal and lateral eigenvectors (4 longitudinal + 4 lateral) x 4 components */ }; #endif xflr5-6.09-06/src/objects/Surface.cpp000644 001750 000144 00000104501 12247174403 020607 0ustar00techwinderusers000000 000000 /**************************************************************************** CSurface Class Copyright (C) 2005-2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include "Surface.h" #include "../objects/Quaternion.h" CVector Surface::LA;//save time by preventing allocation & release of memory CVector Surface::LB; CVector Surface::TA; CVector Surface::TB; CVector Surface::VTemp; CVector *Surface::s_pNode; Panel *Surface::s_pPanel; /** * The public constructor */ Surface::Surface() { m_bTEFlap = false; m_Length = 0.0; m_TwistA = 0.0; m_TwistB = 0.0; m_posATE = 1.0; m_posBTE = 1.0; m_NXPanels = 1; m_NYPanels = 2; m_NXLead = 1; m_NXFlap = 0; m_XDistType = COSINE; m_YDistType = UNIFORM; m_pLeftSurface = m_pRightSurface = NULL; m_pFoilA = NULL; m_pFoilB = NULL; m_NElements = 0; m_bIsInSymPlane = false; m_bIsTipLeft = false; m_bIsTipRight = false; m_bIsLeftSurf = false; m_bIsRightSurf = false; m_bIsCenterSurf = false; m_bJoinRight = true; m_nFlapNodes = 0; m_nFlapPanels = 0; memset(m_xPointA, 0, sizeof(m_xPointA)); memset(m_xPointB, 0, sizeof(m_xPointB)); memset(m_FlapNode, 0, sizeof(m_FlapNode)); memset(m_FlapPanel, 0, sizeof(m_FlapPanel)); } /** * Adds the reference of thE input panel to the array of flap panel indexes. * @param pPanel the pointer of the panel to add to the flap panel list. */ void Surface::AddFlapPanel(Panel *pPanel) { bool bFound = false; int i; //Add Nodes for (i=0; im_iLA==m_FlapNode[i]; if(pPanel->m_iLA== m_FlapNode[i]) { bFound = true; break; } } if(!bFound) { m_FlapNode[m_nFlapNodes] = pPanel->m_iLA; m_nFlapNodes++; } bFound = false; for (i=0; i< m_nFlapNodes; i++) { if(pPanel->m_iLB== m_FlapNode[i]) { bFound = true; break; } } if(!bFound) { m_FlapNode[m_nFlapNodes] = pPanel->m_iLB; m_nFlapNodes++; } for (i=0; i< m_nFlapNodes; i++) { if(pPanel->m_iTA== m_FlapNode[i]) { bFound = true; break; } } if(!bFound) { m_FlapNode[m_nFlapNodes] = pPanel->m_iTA; m_nFlapNodes++; } bFound = false; for (i=0; i< m_nFlapNodes; i++) { if(pPanel->m_iTB== m_FlapNode[i]) { bFound = true; break; } } if(!bFound) { m_FlapNode[m_nFlapNodes] = pPanel->m_iTB; m_nFlapNodes++; } //Add panel; bFound=false; for(i=0; im_iElement==m_FlapPanel[i]) { bFound =true; break; } } if(!bFound) { m_FlapPanel[m_nFlapPanels] = pPanel->m_iElement; m_nFlapPanels++; } } /** * Copy the data from another Surface object to this Surface * @param Surface the source Surface from which the data shall be duplicated */ void Surface::Copy(Surface const &Surface) { m_LA.Copy(Surface.m_LA); m_LB.Copy(Surface.m_LB); m_TA.Copy(Surface.m_TA); m_TB.Copy(Surface.m_TB); m_XDistType = Surface.m_XDistType; m_YDistType = Surface.m_YDistType; m_NElements = Surface.m_NElements; m_Length = Surface.m_Length; m_NXPanels = Surface.m_NXPanels; m_NYPanels = Surface.m_NYPanels; m_pFoilA = Surface.m_pFoilA; m_pFoilB = Surface.m_pFoilB; m_TwistA = Surface.m_TwistA; m_TwistB = Surface.m_TwistB; Normal = Surface.Normal; NormalA = Surface.NormalA; NormalB = Surface.NormalB; m_bIsTipLeft = Surface.m_bIsTipLeft; m_bIsTipRight = Surface.m_bIsTipRight; m_bIsLeftSurf = Surface.m_bIsLeftSurf; m_bIsRightSurf = Surface.m_bIsRightSurf; m_bIsCenterSurf = Surface.m_bIsCenterSurf; m_bJoinRight = Surface.m_bJoinRight; m_bIsInSymPlane = Surface.m_bIsInSymPlane; m_bTEFlap = Surface.m_bTEFlap; m_nFlapNodes = Surface.m_nFlapNodes; m_nFlapPanels = Surface.m_nFlapPanels; m_HingePoint = Surface.m_HingePoint; m_HingeVector = Surface.m_HingeVector; memcpy(m_FlapNode, Surface.m_FlapNode, sizeof(m_FlapNode)); memcpy(m_FlapPanel, Surface.m_FlapPanel, sizeof(m_FlapPanel)); memcpy(m_xPointA, Surface.m_xPointA, sizeof(m_xPointA)); memcpy(m_xPointB, Surface.m_xPointB, sizeof(m_xPointB)); } /** * Creates a surface symetric about the XZ plane * @param Surface the source Surface which shall be reflected */ void Surface::CreateXZSymetric(Surface const &Surface) { //reflects the surface m_LA.x = Surface.m_LB.x; m_LA.y = -Surface.m_LB.y; m_LA.z = Surface.m_LB.z; m_LB.x = Surface.m_LA.x; m_LB.y = -Surface.m_LA.y; m_LB.z = Surface.m_LA.z; m_TA.x = Surface.m_TB.x; m_TA.y = -Surface.m_TB.y; m_TA.z = Surface.m_TB.z; m_TB.x = Surface.m_TA.x; m_TB.y = -Surface.m_TA.y; m_TB.z = Surface.m_TA.z; m_Length = Surface.m_Length; m_XDistType = Surface.m_XDistType; m_YDistType = Surface.m_YDistType; m_NXPanels = Surface.m_NXPanels; m_NYPanels = Surface.m_NYPanels; m_NElements = Surface.m_NElements; Normal.x = Surface.Normal.x; Normal.y = -Surface.Normal.y; Normal.z = Surface.Normal.z; NormalA.x = Surface.NormalB.x; NormalA.y = -Surface.NormalB.y; NormalA.z = Surface.NormalB.z; NormalB.x = Surface.NormalA.x; NormalB.y = -Surface.NormalA.y; NormalB.z = Surface.NormalA.z; m_pFoilA = Surface.m_pFoilB; m_pFoilB = Surface.m_pFoilA; m_TwistA = Surface.m_TwistB; m_TwistB = Surface.m_TwistA; m_bIsTipLeft = Surface.m_bIsTipRight; m_bIsTipRight = Surface.m_bIsTipLeft; m_bIsLeftSurf = Surface.m_bIsRightSurf; m_bIsRightSurf = Surface.m_bIsLeftSurf; m_bIsInSymPlane = Surface.m_bIsInSymPlane; m_NXFlap = Surface.m_NXFlap; m_NXLead = Surface.m_NXLead; memcpy(m_xPointA, Surface.m_xPointB, sizeof(m_xPointA)); memcpy(m_xPointB, Surface.m_xPointA, sizeof(m_xPointB)); } /** * Returns the quarter-chord point of a specified strip * @param k the 0-based index of the strip for which the quarter-chord point shall be returned. * @param Pt the quarter-chord point * @param tau the relative span position of the Pt */ void Surface::GetC4(int k, CVector &Pt, double &tau) { GetPanel(k,m_NXPanels-1,MIDSURFACE); double xl = (LA.x+LB.x)/2.0; double yl = (LA.y+LB.y)/2.0; double zl = (LA.z+LB.z)/2.0; GetPanel(k,0,MIDSURFACE); double xt = (TA.x+TB.x)/2.0; double yt = (TA.y+TB.y)/2.0; double zt = (TA.z+TB.z)/2.0; Pt.x = xl*.75 + xt*.25; Pt.y = yl*.75 + yt*.25; Pt.z = zl*.75 + zt*.25; tau = sqrt((Pt.y-m_LA.y)*(Pt.y-m_LA.y) + (Pt.z-m_LA.z)*(Pt.z-m_LA.z)) / m_Length; } /** * Returns the chord length of the specified strip * @param k the 0-based index of the strip for which the chord shall be returned. * @return the chord length */ double Surface::GetChord(int const &k) { static double y1, y2; GetyDist(k, y1, y2); return GetChord((y1+y2)/2.0); } /** * Returns the chord length at the specified relative span position. * @param tau the relative percentage of the Surface's span length * @return the chord length */ double Surface::GetChord(double const &tau) { //assumes LA-TB have already been loaded static CVector V1, V2; static double ChordA, ChordB; V1 = m_TA-m_LA; V2 = m_TB-m_LB; ChordA = V1.VAbs(); ChordB = V2.VAbs(); return ChordA + (ChordB-ChordA) * qAbs(tau); } /** * Returns the strip's offset in the x direction at the specified relative span position. * @param tau the relative percentage of the Surface's span length * @return the offset in the x-direction */ double Surface::GetOffset(double const &tau) { //chord spacing return m_LA.x + (m_LB.x-m_LA.x) * qAbs(tau); } /** * Returns the area of the virtual foil at a specified relative span position. Used in Inertia calaculations. * @param tau the relative percentage of the Surface's span length * @return the cross area at the specified location */ double Surface::GetFoilArea(double const &tau) { double area, chord; if(m_pFoilA && m_pFoilB) { chord = GetChord(tau); area = (m_pFoilA->GetArea() + m_pFoilB->GetArea())/2.0*chord*chord;//m2 return area; } else return 0.0; } /** * Returns the normal vector at a specified relative span position. * @param tau the relative percentage of the Surface's span length * @return N the average normal at the specified location */ void Surface::GetNormal(double yrel, CVector &N) { N = NormalA * (1.0-yrel) + NormalB * yrel; N.Normalize(); } /** * Returns the leading point of the specified strip * @param k the 0-based index of the strip for which the leading point shall be returned. * @param C the strip's leading point. */ void Surface::GetLeadingPt(int k, CVector &C) { GetPanel(k,m_NXPanels-1, MIDSURFACE); C.x = (LA.x+LB.x)/2.0; C.y = (LA.y+LB.y)/2.0; C.z = (LA.z+LB.z)/2.0; } /** * Returns the trailing point of the specified strip * @param k the 0-based index of the strip for which the trailing point shall be returned. * @param C the strip's leading point. */ void Surface::GetTrailingPt(int k, CVector &C) { GetPanel(k,0,MIDSURFACE); C.x = (TA.x+TB.x)/2.0; C.y = (TA.y+TB.y)/2.0; C.z = (TA.z+TB.z)/2.0; } /** * Calculates the corner points of the panel with index k in the span direction and index l in the chordwise direction. * The point coordinates are loaded in the memeber variables LA, LB, TA, TB. * * Assumes the side points have been set previously * * @param k the index of the strip 0<=kGetUpperY(xArel)*GetChord(0.0); TopB = m_pFoilB->GetUpperY(xBrel)*GetChord(1.0); APt.x += Normal.x * TopA; APt.y += Normal.y * TopA; APt.z += Normal.z * TopA; BPt.x += Normal.x * TopB; BPt.y += Normal.y * TopB; BPt.z += Normal.z * TopB; } else if(pos==-1 && m_pFoilA && m_pFoilB) { BotA = m_pFoilA->GetLowerY(xArel)*GetChord(0.0); BotB = m_pFoilB->GetLowerY(xBrel)*GetChord(1.0); APt.x += Normal.x * BotA; APt.y += Normal.y * BotA; APt.z += Normal.z * BotA; BPt.x += Normal.x * BotB; BPt.y += Normal.y * BotB; BPt.z += Normal.z * BotB; } Point.x = APt.x * (1.0-yrel)+ BPt.x * yrel ; Point.y = APt.y * (1.0-yrel)+ BPt.y * yrel ; Point.z = APt.z * (1.0-yrel)+ BPt.z * yrel ; } /** * Returns the postion of a surface point at the position specified by the input parameters. * @param xArel the relative position at the left Foil * @param xBrel the relative position at the right Foil * @param yrel the relative span position * @param Point a reference of the requested point's position * @param PtNormal the normal to the surface at the requested point * @param pos defines on which surface (BOTSURFACE, TOPSURFACE, MIDSURFACE) the point is calculated */ void Surface::GetSurfacePointNormal(double const &xArel, double const &xBrel, double const &yrel, CVector &Point, CVector &PtNormal, int const &pos) { static CVector APt, BPt, Nc, u; static double TopA, TopB, BotA, BotB, nxA, nxB, nyA, nyB, theta; static Quaternion q; //define the strip's normal GetNormal(yrel, Nc); //define the quaternion to rotate the unit vector (0,0,1) to Nc //use the dot product to get the rotation angle, and the crossproduct to get the rotation vector theta = acos(Nc.z); u.x = -Nc.y; u.y = Nc.x; u.z = 0.0; q.Set(theta*180.0/PI, u); APt.x = m_LA.x * (1.0-xArel) + m_TA.x * xArel; APt.y = m_LA.y * (1.0-xArel) + m_TA.y * xArel; APt.z = m_LA.z * (1.0-xArel) + m_TA.z * xArel; BPt.x = m_LB.x * (1.0-xBrel) + m_TB.x * xBrel; BPt.y = m_LB.y * (1.0-xBrel) + m_TB.y * xBrel; BPt.z = m_LB.z * (1.0-xBrel) + m_TB.z * xBrel; if(pos==1 && m_pFoilA && m_pFoilB) { m_pFoilA->GetUpperY(xArel, TopA, nxA, nyA); m_pFoilB->GetUpperY(xBrel, TopB, nxB, nyB); TopA *= GetChord(0.0); TopB *= GetChord(1.0); // rotate the point's normal vector i.a.w. dihedral and local washout PtNormal.x = nxA * (1.0-yrel) + nxB * yrel; PtNormal.y = 0.0; PtNormal.z = nyA * (1.0-yrel) + nyB * yrel; q.Conjugate(PtNormal.x, PtNormal.y, PtNormal.z); APt.x += NormalA.x * TopA; APt.y += NormalA.y * TopA; APt.z += NormalA.z * TopA; BPt.x += NormalB.x * TopB; BPt.y += NormalB.y * TopB; BPt.z += NormalB.z * TopB; } else if(pos==-1 && m_pFoilA && m_pFoilB) { m_pFoilA->GetLowerY(xArel, BotA, nxA, nyA); m_pFoilB->GetLowerY(xBrel, BotB, nxB, nyB); BotA *= GetChord(0.0); BotB *= GetChord(1.0); // rotate the point's normal vector i.a.w. dihedral and local washout PtNormal.x = nxA * (1.0-yrel) + nxB * yrel; PtNormal.y = 0.0; PtNormal.z = nyA * (1.0-yrel) + nyB * yrel; q.Conjugate(PtNormal.x, PtNormal.y, PtNormal.z); APt.x += NormalA.x * BotA; APt.y += NormalA.y * BotA; APt.z += NormalA.z * BotA; BPt.x += NormalB.x * BotB; BPt.y += NormalB.y * BotB; BPt.z += NormalB.z * BotB; } Point.x = APt.x * (1.0-yrel)+ BPt.x * yrel ; Point.y = APt.y * (1.0-yrel)+ BPt.y * yrel ; Point.z = APt.z * (1.0-yrel)+ BPt.z * yrel ; } /** * Returns the chord length, cross-section area, and quarter-chord point of a given strip, * @param tau the relative percentage of the Surface's span length * @param Chord a reference to the chord length * @param Area a reference to the cross-section area * @param PtC4 a reference to the quarter-chord point */ void Surface::GetSection(double const &tau, double &Chord, double &Area, CVector &PtC4) { //explicit double calculations are much faster than vector algebra LA.x = m_LA.x * (1.0-tau) + m_LB.x * tau; LA.y = m_LA.y * (1.0-tau) + m_LB.y * tau; LA.z = m_LA.z * (1.0-tau) + m_LB.z * tau; TA.x = m_TA.x * (1.0-tau) + m_TB.x * tau; TA.y = m_TA.y * (1.0-tau) + m_TB.y * tau; TA.z = m_TA.z * (1.0-tau) + m_TB.z * tau; PtC4.x = .75 * LA.x + .25 * TA.x; PtC4.y = .75 * LA.y + .25 * TA.y; PtC4.z = .75 * LA.z + .25 * TA.z; Chord = sqrt((LA.x-TA.x)*(LA.x-TA.x) + (LA.y-TA.y)*(LA.y-TA.y) + (LA.z-TA.z)*(LA.z-TA.z)); if(m_pFoilA && m_pFoilB) { Area = (m_pFoilA->GetArea() * tau + m_pFoilB->GetArea() * (1.0-tau))*Chord*Chord;//m2 } else { Area = 0.0; } } /** * Returns the absolute position of a specified strip. * * Returns the average span position of the strip; necessary for strips 'distorted' by the fuselage; * * @param k the 0-based index of the strip for which the position shall be returned. * @return the absolute position of the strip */ double Surface::GetStripSpanPos(int const &k) { int l; double YPos = 0.0; double ZPos = 0.0; for(l=0; lm_TEFlapAngle - m_pFoilB->m_TEFlapAngle)>0.1) { QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QObject::tr("Warning")); msgBox.setText(QObject::tr("Continuous foils for surface do not have the same initial flap angle... aborting\n")); msgBox.exec(); return false; } alpha0 = (m_pFoilA->m_TEFlapAngle + m_pFoilB->m_TEFlapAngle)/2.0; Quat.Set(Angle-alpha0, m_HingeVector); for (k=0; km_bTEFlap) { m_posATE = m_pFoilA->m_TEXHinge/100.0; if(m_posATE>1.0) m_posATE = 1.0; else if(m_posATE<0.0) m_posATE = 0.0; } else m_posATE = 1.0; if(m_pFoilB && m_pFoilB->m_bTEFlap) { m_posBTE = m_pFoilB->m_TEXHinge/100.0; if(m_posBTE>1.0) m_posBTE = 1.0; else if(m_posBTE<0.0) m_posBTE = 0.0; } else m_posBTE = 1.0; if(m_pFoilA && m_pFoilB) m_bTEFlap = m_pFoilA->m_bTEFlap && m_pFoilB->m_bTEFlap; else m_bTEFlap = false; if(m_pFoilA && m_pFoilB && m_pFoilA->m_bTEFlap && m_pFoilB->m_bTEFlap) { CVector HB; //create a hinge unit vector and initialize hinge moment GetSurfacePoint(m_posATE, m_posBTE, 0.0, m_HingePoint, 0); GetSurfacePoint(m_posATE, m_posBTE, 1.0, HB, 0); m_HingeVector = HB-m_HingePoint; m_HingeVector.Normalize(); } } /** Sets the surface average normal vector */ void Surface::SetNormal() { static CVector LATB, TALB; LATB = m_TB - m_LA; TALB = m_LB - m_TA; Normal = LATB * TALB; Normal.Normalize(); } /** * Creates the master points on the left and right ends. * One of the most difficult part of the code to implement. The algorithm still isn't very robust. * @param pBody a pointer to the Body object, or NULL if none. * @param dx the x-component of the translation to apply to the body. * @param dz the z-component of the translation to apply to the body. */ void Surface::SetSidePoints(Body * pBody, double dx, double dz) { //creates the left and right tip points between which the panels will be interpolated int l; static double zA, zB; double cosdA, cosdB; static Body TBody; if(pBody) { TBody.Duplicate(pBody); TBody.Translate(dx, 0.0, dz); } cosdA = Normal.dot(NormalA); cosdB = Normal.dot(NormalB); chordA = GetChord(0.0);//todo : compare with |m_LA-m_TA| chordB = GetChord(1.0); cosdA = cosdB = 1.0; //SideA, SideB are mid points (VLM) or bottom points (3DPanels) //SideA_T, SideB_T, are top points (3DPanels); if(m_pFoilA && m_pFoilB) { zA = m_pFoilA->GetLowerY(m_xPointA[0])*chordA; zB = m_pFoilB->GetLowerY(m_xPointB[0])*chordB; SideA_B[0] = m_TA + NormalA * zA/cosdA; SideB_B[0] = m_TB + NormalB * zB/cosdB; zA = m_pFoilA->GetUpperY(m_xPointA[0])*chordA; zB = m_pFoilB->GetUpperY(m_xPointB[0])*chordB; SideA_T[0] = m_TA + NormalA * zA/cosdA; SideB_T[0] = m_TB + NormalB * zB/cosdB; zA = m_pFoilA->GetMidY(m_xPointA[0])*chordA; zB = m_pFoilB->GetMidY(m_xPointB[0])*chordB; SideA[0] = m_TA + NormalA * zA/cosdA; SideB[0] = m_TB + NormalB * zB/cosdB; } else { SideA[0] = m_TA; SideB[0] = m_TB; SideA_T[0] = m_TA; SideB_T[0] = m_TB; SideA_B[0] = m_TA; SideB_B[0] = m_TB; } if(pBody && m_bIsCenterSurf && m_bIsLeftSurf) { if(TBody.Intersect(SideA_B[0], SideB_B[0], SideB_B[0], false)) m_bJoinRight = false; if(TBody.Intersect(SideA_T[0], SideB_T[0], SideB_T[0], false)) m_bJoinRight = false; if(TBody.Intersect(SideA[0], SideB[0], SideB[0], false)) m_bJoinRight = false;; } else if(pBody && m_bIsCenterSurf && m_bIsRightSurf) { TBody.Intersect(SideA_B[0], SideB_B[0], SideA_B[0], true); TBody.Intersect(SideA_T[0], SideB_T[0], SideA_T[0], true); TBody.Intersect(SideA[0], SideB[0], SideA[0], true); } for (l=0; lGetLowerY(xLA)*chordA; zB = m_pFoilB->GetLowerY(xLB)*chordB; SideA_B[l+1] = LA + NormalA * zA/cosdA; SideB_B[l+1] = LB + NormalB * zB/cosdB; //create top surface side points zA = m_pFoilA->GetUpperY(xLA)*chordA; zB = m_pFoilB->GetUpperY(xLB)*chordB; SideA_T[l+1] = LA + NormalA * zA/cosdA; SideB_T[l+1] = LB + NormalB * zB/cosdB; //create middle surface side points zA = m_pFoilA->GetMidY(xLA)*chordA; zB = m_pFoilB->GetMidY(xLB)*chordB; SideA[l+1] = LA + NormalA * zA/cosdA; SideB[l+1] = LB + NormalB * zB/cosdB; } else { SideA[l+1] = LA; SideB[l+1] = LB; SideA_T[l+1] = LA; SideB_T[l+1] = LB; SideA_B[l+1] = LA; SideB_B[l+1] = LB; } if(pBody && m_bIsCenterSurf && m_bIsLeftSurf) { if(TBody.Intersect(SideA_B[l+1], SideB_B[l+1], SideB_B[l+1], false)) m_bJoinRight = false; if(TBody.Intersect(SideA_T[l+1], SideB_T[l+1], SideB_T[l+1], false)) m_bJoinRight = false; if(TBody.Intersect(SideA[l+1], SideB[l+1], SideB[l+1], false)) m_bJoinRight = false; } else if(pBody && m_bIsCenterSurf && m_bIsRightSurf) { TBody.Intersect(SideA_B[l+1], SideB_B[l+1], SideA_B[l+1], true); TBody.Intersect(SideA_T[l+1], SideB_T[l+1], SideA_T[l+1], true); TBody.Intersect(SideA[l+1], SideB[l+1], SideA[l+1], true); } } //merge trailing edge points in case the foil has a T.E. gap CVector Node; Node = (SideA_B[0] + SideA_T[0])/2.0; SideA_B[0].Set(Node); SideA_T[0].Set(Node); Node = (SideB_B[0] + SideB_T[0])/2.0; SideB_B[0].Set(Node); SideB_T[0].Set(Node); } /** * Translates the entire Surface. * @param T the translation vector. */ void Surface::Translate(CVector const &T) { m_LA.Translate(T); m_LB.Translate(T); m_TA.Translate(T); m_TB.Translate(T); m_HingePoint.Translate(T); } /** * Translates the entire Surface. * @param tx the x-component of the translation. */ void Surface::Translate(double tx, double ty, double tz) { m_LA.Translate(tx, ty, tz); m_LB.Translate(tx, ty, tz); m_TA.Translate(tx, ty, tz); m_TB.Translate(tx, ty, tz); m_HingePoint.Translate(tx, ty, tz); } /** * Creates relative position of the master points at the left and right tip of the Surface. * The chordwise panel distribution is set i.a.w. with the flap hinges, if any. * The positions are stored in the member variables m_xPointA and m_xPointB. */ void Surface::CreateXPoints() { int l; int NXFlapA, NXFlapB, NXLeadA, NXLeadB; double dl, dl2; double xHingeA, xHingeB; if(m_pFoilA && m_pFoilA->m_bTEFlap) xHingeA=m_pFoilA->m_TEXHinge/100.0; else xHingeA=1.0; if(m_pFoilB && m_pFoilB->m_bTEFlap) xHingeB=m_pFoilB->m_TEXHinge/100.0; else xHingeB=1.0; NXFlapA = (int)((1.0-xHingeA) * (double)m_NXPanels*1.000123);// to avoid numerical errors if exact division NXFlapB = (int)((1.0-xHingeB) * (double)m_NXPanels *1.000123); if(m_pFoilA && m_pFoilA->m_bTEFlap && NXFlapA==0) NXFlapA++; if(m_pFoilB && m_pFoilB->m_bTEFlap && NXFlapB==0) NXFlapB++; NXLeadA = m_NXPanels - NXFlapA; NXLeadB = m_NXPanels - NXFlapB; m_NXFlap = qMax(NXFlapA, NXFlapB); if(m_NXFlap>m_NXPanels/2) m_NXFlap=(int)m_NXPanels/2; m_NXLead = m_NXPanels - m_NXFlap; for(l=0; l #include "CVector.h" #include "Quaternion.h" #include "../globals.h" void CVector::Rotate(CVector const &R, double Angle) { //rotate the vector around R with an angle Angle Quaternion Qt; Qt.Set(Angle, R); Qt.Conjugate(x,y,z); } void CVector::Rotate(CVector &O, CVector const &R, double Angle) { //rotate the point defined by the vector around origin O, rotation vector R and angle Angle Quaternion Qt; Qt.Set(Angle, R); CVector OP; OP.x = x-O.x; OP.y = y-O.y; OP.z = z-O.z; Qt.Conjugate(OP); x = O.x + OP.x; y = O.y + OP.y; z = O.z + OP.z; } void CVector::RotateX(CVector const &O, double XTilt) { //Rotate the vector around the X-axis, by an angle XTilt CVector OP; OP.x = x-O.x; OP.y = y-O.y; OP.z = z-O.z; XTilt *=PI/180.0; y = O.y + OP.y * cos(XTilt) - OP.z * sin(XTilt); z = O.z + OP.y * sin(XTilt) + OP.z * cos(XTilt); } void CVector::RotateY(CVector const &O, double YTilt) { //Rotate the vector around the Y-axis, by an angle YTilt CVector OP; OP.x = x-O.x; OP.y = y-O.y; OP.z = z-O.z; YTilt *=PI/180.0; x = O.x + OP.x * cos(YTilt) + OP.z * sin(YTilt); z = O.z - OP.x * sin(YTilt) + OP.z * cos(YTilt); } void CVector::RotateZ(CVector const &O, double ZTilt) { //Rotate the vector around the Z-axis, by an angle ZTilt CVector OP; OP.x = x-O.x; OP.y = y-O.y; OP.z = z-O.z; ZTilt *=PI/180.0; x = O.x + OP.x * cos(ZTilt) + OP.y * sin(ZTilt); y = O.y - OP.x * sin(ZTilt) + OP.y * cos(ZTilt); } void CVector::RotateY(double YTilt) { YTilt *=PI/180.0; double xo = x; double zo = z; x = xo * cos(YTilt) + zo * sin(YTilt); z = -xo * sin(YTilt) + zo * cos(YTilt); } xflr5-6.09-06/src/objects/CVector.h000644 001750 000144 00000007753 12247174403 020244 0ustar00techwinderusers000000 000000 /**************************************************************************** CVector Class Copyright (C) 2008 Andre Deperrois sail7@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file This file implements the CVetor class */ #include #ifndef CVector_H #define CVector_H /** @brief * A simple class which implements the usual properties, methods and operators associated to a 3D Vector. * * Caution : although the definition of operators allows for compact programming, * the operations take much longer at run time probably due to the temporary memory allocations. * If speed is required, implement directly the vectorial operations component by component in the source code. */ class CVector { public: double x; double y; double z; //inline constructors CVector() { x = 0.0; y = 0.0; z = 0.0; } CVector(double const &xi, double const &yi, double const &zi) { x = xi; y = yi; z = zi; } //inline operators double operator[](const int &i) { if(i==0) return x; if(i==1) return y; if(i==2) return z; return 0.0; } bool operator ==(CVector const &V) { //used only to compare point positions return (V.x-x)*(V.x-x) + (V.y-y)*(V.y-y) + (V.z-z)*(V.z-z)<0.000000001; } void operator =(CVector const &T) { x = T.x; y = T.y; z = T.z; } void operator+=(CVector const &T) { x += T.x; y += T.y; z += T.z; } void operator-=(CVector const &T) { x -= T.x; y -= T.y; z -= T.z; } void operator*=(double const &d) { x *= d; y *= d; z *= d; } CVector operator *(double const &d) { CVector T(x*d, y*d, z*d); return T; } CVector operator *(CVector const &T) { CVector C; C.x = y*T.z - z*T.y; C.y = -x*T.z + z*T.x; C.z = x*T.y - y*T.x; return C; } CVector operator /(double const &d) { CVector T(x/d, y/d, z/d); return T; } CVector operator +(CVector const &V) const { CVector T(x+V.x, y+V.y, z+V.z); return T; } CVector operator -(CVector const &V) const { CVector T(x-V.x, y-V.y, z-V.z); return T; } //inline methods void Copy(CVector const &V) { x = V.x; y = V.y; z = V.z; } void Set(double const &x0, double const &y0, double const &z0) { x = x0; y = y0; z = z0; } void Set(CVector const &V) { x = V.x; y = V.y; z = V.z; } void Normalize() { double abs = VAbs(); if(abs< 1.e-10) return; x/=abs; y/=abs; z/=abs; } double VAbs() { return sqrt(x*x+y*y+z*z); } double dot(CVector const &V) { return x*V.x + y*V.y + z*V.z; } bool IsSame(CVector const &V) { //used only to compare point positions return (V.x-x)*(V.x-x) + (V.y-y)*(V.y-y) + (V.z-z)*(V.z-z)<0.000000001; } void Translate(CVector const &T) { x += T.x; y += T.y; z += T.z; } void Translate(const double &tx, const double &ty, const double &tz) { x += tx; y += ty; z += tz; } int size() const { return 3;//dimension } //other methods void Rotate(CVector const &R, double Angle); void Rotate(CVector &O, CVector const &R, double Angle); void RotateX(CVector const &O, double XTilt); void RotateY(CVector const &O, double YTilt); void RotateZ(CVector const &O, double ZTilt); void RotateX(double Bank); void RotateY(double YTilt); void RotateZ(double ZRot); }; #endif xflr5-6.09-06/src/objects/Quaternion.h000644 001750 000144 00000007210 12247174403 021010 0ustar00techwinderusers000000 000000 /**************************************************************************** Quaternion Class Copyright (C) 2008-20013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file * * This class defines the Quaternion used for the calculation of rotations in 3D display * */ #ifndef QUATERNION_H #define QUATERNION_H /** *@class Quaternion *@brief * The class which defines the quaternion object used for the calculation of rotations in 3D display. Home made class. Since it was written, Qt has developed and provided a QQuaternion class. */ #include "CVector.h" #include "../params.h" class Quaternion { private: double theta; double t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t15, t19, t20, t24; CVector R; public: double a, qx, qy,qz; void QuattoMat(double m[][4]); void Normalize(); void operator*=(Quaternion Q); void operator ~(); void operator =(Quaternion Q); Quaternion operator *(Quaternion Q); //inline constructors Quaternion(void) { a=0.0; qx= 0.0; qy=0.0; qz = 0.0; theta = 0.0; Settxx(); }; Quaternion(double const &t, double const &x, double const &y, double const &z) { a=t; qx= x; qy=y; qz = z; theta = 2.0*acos(t); Settxx(); }; Quaternion(double const &Angle, CVector const &R) { CVector N; N = R; N.Normalize(); theta = Angle*PI/180.0; a = cos(theta/2.0); double sina = sin(theta/2.0); qx = N.x*sina; qy = N.y*sina; qz = N.z*sina; Settxx(); }; //inline functions void Conjugate(CVector const &Vin, CVector &Vout) { Vout.x = 2.0*( (t8 + t10)*Vin.x + (t6 - t4)*Vin.y + (t3 + t7)*Vin.z ) + Vin.x; Vout.y = 2.0*( (t4 + t6)*Vin.x + (t5 + t10)*Vin.y + (t9 - t2)*Vin.z ) + Vin.y; Vout.z = 2.0*( (t7 - t3)*Vin.x + (t2 + t9)*Vin.y + (t5 + t8)*Vin.z ) + Vin.z; }; void Conjugate(CVector &V) { R.x = V.x; R.y = V.y; R.z = V.z; V.x = 2.0*( (t8 + t10)*R.x + (t6 - t4)*R.y + (t3 + t7)*R.z ) + R.x; V.y = 2.0*( (t4 + t6)*R.x + (t5 + t10)*R.y + (t9 - t2)*R.z ) + R.y; V.z = 2.0*( (t7 - t3)*R.x + (t2 + t9)*R.y + (t5 + t8)*R.z ) + R.z; }; void Conjugate(double &x, double &y, double &z) { R.x = x; R.y = y; R.z = z; x = 2.0*( (t8 + t10)*R.x + (t6 - t4)*R.y + (t3 + t7)*R.z ) + R.x; y = 2.0*( (t4 + t6)*R.x + (t5 + t10)*R.y + (t9 - t2)*R.z ) + R.y; z = 2.0*( (t7 - t3)*R.x + (t2 + t9)*R.y + (t5 + t8)*R.z ) + R.z; }; void Settxx() { t2 = a*qx; t3 = a*qy; t4 = a*qz; t5 = -qx*qx; t6 = qx*qy; t7 = qx*qz; t8 = -qy*qy; t9 = qy*qz; t10 = -qz*qz; }; void Set(double const &real, double const &x, double const &y, double const &z) { a = real; qx = x; qy = y; qz = z; Settxx(); }; void Set(double const &Angle, CVector const &R) { CVector N; N = R; N.Normalize(); theta = Angle*PI/180.0; a = cos(theta/2.0); double sina = sin(theta/2.0); qx = N.x*sina; qy = N.y*sina; qz = N.z*sina; Settxx(); }; }; #endif xflr5-6.09-06/src/objects/SplineFoil.h000644 001750 000144 00000007510 12247174403 020732 0ustar00techwinderusers000000 000000 /**************************************************************************** Spline Foil Class Copyright (C) 2003-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** *@file This class defines the splined foil object used in foil design. */ #ifndef SPLINEFOIL_H #define SPLINEFOIL_H #include "Foil.h" #include "Spline.h" /** *@class SplineFoil *@brief The class which defines the splined foil object. The foil is contructed based on one spline for the upper surface and one spline for the lower surface. @todo This class mixes the construction methods and the GUI; would be better to move the GUI to a derived child class for polymorphism. */ class SplineFoil { friend class QAFoil; friend class MainFrame; friend class SplineCtrlsDlg; friend class FoilTableDelegate; public: SplineFoil(); SplineFoil(SplineFoil *pSF); private: void CompMidLine(); void InitSplineFoil(); bool Serialize(QDataStream &ar, bool bIsStoring); void Copy(SplineFoil* pSF); void DrawCtrlPoints(QPainter &painter, double scalex, double scaley, QPoint Offset); void DrawMidLine(QPainter &painter, double scalex, double scaley, QPoint Offset); void DrawFoil(QPainter &painter, double scalex, double scaley, QPoint Offset); void DrawOutPoints(QPainter &painter, double scalex, double scaley, QPoint Offset); void ExportToBuffer(Foil *pFoil); void ExportToFile(QTextStream &out); void UpdateSplineFoil(); void SetCurveParams(int style, int width, QColor color); bool m_bModified; /**< false if the SplineFoil has been serialized in its current dtate, false otherwise */ bool m_bVisible; /**< true if this SplineFoil object is visible */ bool m_bOutPoints; /**< true if the ouput line points should be displayed */ bool m_bCenterLine; /**< true if the SplineFoil's mean camber line is to be displayed */ bool m_bSymetric; /**< true if the SplineFoil is symetric. In which case the lower surface is set as symetric of the upper surface. */ int m_OutPoints; /**< the number of output points with which to draw the SplineFoil. */ int m_FoilStyle; /**< the index of the style with which to draw the SplineFoil */ int m_FoilWidth; /**< the width with which to draw the SplineFoil */ QColor m_FoilColor; /**< the color with which to draw the SplineFoil */ double m_fCamber; /**< the SplineFoil's max camber */ double m_fThickness; /**< the SplineFoil's max thickness */ double m_fxCambMax; /**< the x-position of the SplineFoil's max camber point */ double m_fxThickMax; /**< the x-position of the SplineFoil's max thickness point */ QString m_strFoilName; /**< the SplineFoil's name */ Spline m_Extrados; /**< the spline which defines the upper surface */ Spline m_Intrados; /**< the spline which defines the lower surface */ CVector m_rpMid[MIDPOINTCOUNT]; /**< the points on ths SplineFoil's mid camber line @todo replace with a QVarLengthArray */ }; #endif xflr5-6.09-06/src/objects/Quaternion.cpp000644 001750 000144 00000005040 12247174403 021342 0ustar00techwinderusers000000 000000 /**************************************************************************** Quaternion Class Copyright (C) 2008-2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "Quaternion.h" #include #include void Quaternion::QuattoMat(double m[][4]) { if(qAbs(a)<=1.0) theta = 2.0 * acos(a); else theta = 0.0; t1 = cos(theta); t2 = 1.0 - t1; t3 = qx*qx; t6 = t2*qx; t7 = t6*qy; t8 = sin(theta); t9 = t8*qz; t11 = t6*qz; t12 = t8*qy; t15 = qy*qy; t19 = t2*qy*qz; t20 = t8*qx; t24 = qz*qz; m[0][0] = t1 + t2*t3; m[0][1] = t7 - t9; m[0][2] = t11 + t12; m[1][0] = t7 + t9; m[1][1] = t1 + t2*t15; m[1][2] = t19 - t20; m[2][0] = t11 - t12; m[2][1] = t19 + t20; m[2][2] = t1 + t2*t24; } void Quaternion::operator *=(Quaternion Q) { double t1,t2,t3,t4; t1 = a*Q.a - qx*Q.qx - qy*Q.qy - qz*Q.qz; t2 = a*Q.qx + qx*Q.a + qy*Q.qz - qz*Q.qy ; t3 = a*Q.qy + qy*Q.a + qz*Q.qx - qx*Q.qz ; t4 = a*Q.qz + qz*Q.a + qx*Q.qy - qy*Q.qx ; a = t1; qx = t2; qy = t3; qz = t4; Settxx(); } Quaternion Quaternion::operator *(Quaternion Q) { Quaternion prod; prod.a = a*Q.a - qx*Q.qx - qy*Q.qy - qz*Q.qz; prod.qx = a*Q.qx + qx*Q.a + qy*Q.qz - qz*Q.qy ; prod.qy = a*Q.qy + qy*Q.a + qz*Q.qx - qx*Q.qz ; prod.qz = a*Q.qz + qz*Q.a + qx*Q.qy - qy*Q.qx ; prod.Settxx(); return prod; } void Quaternion::operator =(Quaternion Q) { a = Q.a; qx = Q.qx; qy = Q.qy; qz = Q.qz; Settxx(); } void Quaternion::operator ~() { qx = -qx; qy = -qy; qz = -qz; Settxx(); } void Quaternion::Normalize() { double norm = sqrt(a*a + qx*qx + qy*qy + qz*qz); if (norm < 1.0e-10) { a = 1.0; qx = 0.0; qy = 0.0; qz = 0.0; } else { a *= 1/norm; qx *= 1/norm; qy *= 1/norm; qz *= 1/norm; } Settxx(); } xflr5-6.09-06/src/objects/Frame.h000644 001750 000144 00000005273 12247174403 017724 0ustar00techwinderusers000000 000000 /**************************************************************************** CFrame Class Copyright (C) 2007-2012 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file This file implements the Frame class used in the definition of Body objects */ #ifndef FRAME_H #define FRAME_H #include "CVector.h" #include #include /** *@class Frame This class defines a frame in the yz plane, on which the body surface is built. * This is similar to the way a real life body is designed and built. * The Frame's points may be used indiferently by a spline-type or a flat-panel-type body. * The Frmae's points are defined from bottom to top, i.e. for crescending z values, and for the body's left (port) side. * The x-value of the control points is unused, the frame's position is defined by the variable m_Position. */ class Frame { public: Frame(int nCtrlPts=0); void AppendPoint(CVector const& Pt); void CopyFrame(Frame *pFrame); void CopyPoints(QList *pPointList); double Height(); int IsPoint(CVector const &Point, double const &ZoomFactor); void InsertPoint(int n); void InsertPoint(int n, const CVector &Pt); int InsertPoint(CVector const &Real, int iAxis); int PointCount() {return m_CtrlPoint.size();} bool RemovePoint(int n); void RotateFrameY(double Angle); bool SerializeFrame(QDataStream &ar, bool bIsStoring); void SetPosition(CVector Pos); void SetuPosition(double u); void SetvPosition(double v); void SetwPosition(double w); double zPos(); QList m_CtrlPoint; /**< the array of points which define the frame. */ int m_iHighlight; /**< the point over which the mouse hovers, or -1 if none */ int m_iSelect; /**< the selected pointed, i.e. the last point on which the user has clicked, or -1 if none */ CVector m_Position; /**< the translation vector for the Frame's origin */ }; #endif xflr5-6.09-06/src/objects/Panel.cpp000644 001750 000144 00000032570 12247174403 020264 0ustar00techwinderusers000000 000000 /**************************************************************************** Panel Class Copyright (C) 2006-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include "Panel.h" #include double Panel::s_VortexPos = 0.25; double Panel::s_CtrlPos = 0.75; double Panel::mat[9]; double Panel::det; CVector Panel::smp, Panel::smq, Panel::MidA, Panel::MidB; CVector *Panel::s_pNode; CVector Panel::ILA, Panel::ILB, Panel::ITA, Panel::ITB, Panel::T, Panel::V, Panel::W; CVector Panel::P; CVector Panel::LATB, Panel::TALB; /** * The public constructor */ Panel::Panel() { Reset(); } /** * Resets the panel geometry to default initialization values */ void Panel::Reset() { dl = 0.0; Size = 0.0; SMP = 0.0; SMQ = 0.0; Area = 0.0; m_bIsLeading = false; m_bIsTrailing = false; m_bIsInSymPlane = false; m_bIsLeftPanel = false; m_bIsWakePanel = false; m_Pos = MIDSURFACE; m_iElement = -1; m_iSym = -1; m_iLA = 0; m_iLB = 0; m_iTA = 0; m_iTB = 0; m_iPL = -1; m_iPR = -1; m_iPU = -1; m_iPD = -1; m_iWake = -1; m_iWakeColumn = -1; memset(lij, 0, sizeof(lij)); } /** * Defines the vortex and panel geometrical properties necessary for the VLM and panel calculations. */ void Panel::SetFrame() { //set the boundary conditions from existing nodes SetFrame(s_pNode[m_iLA], s_pNode[m_iLB], s_pNode[m_iTA], s_pNode[m_iTB]); } /** * Constructs the vortex and panel properties necessary for the VLM and panel calculations, based on the absolute position of the four corner nodes. * * @param LA the position of the leading edge left node. * @param LB the position of the leading edge right node. * @param TA the position of the trailing edge left node. * @param TB the position of the trailing edge rightt node. */ void Panel::SetFrame(CVector const &LA, CVector const &LB, CVector const &TA, CVector const &TB) { LATB.x = TB.x - LA.x; LATB.y = TB.y - LA.y; LATB.z = TB.z - LA.z; TALB.x = LB.x - TA.x; TALB.y = LB.y - TA.y; TALB.z = LB.z - TA.z; Normal = LATB * TALB; Area = Normal.VAbs()/2.0; Normal.Normalize(); VA.x = LA.x*(1.0-s_VortexPos)+TA.x*s_VortexPos; VA.y = LA.y*(1.0-s_VortexPos)+TA.y*s_VortexPos; VA.z = LA.z*(1.0-s_VortexPos)+TA.z*s_VortexPos; VB.x = LB.x*(1.0-s_VortexPos)+TB.x*s_VortexPos; VB.y = LB.y*(1.0-s_VortexPos)+TB.y*s_VortexPos; VB.z = LB.z*(1.0-s_VortexPos)+TB.z*s_VortexPos; Vortex.x = VB.x - VA.x; Vortex.y = VB.y - VA.y; Vortex.z = VB.z - VA.z; dl = Vortex.VAbs(); VortexPos.x = (VA.x+VB.x)/2.0; VortexPos.y = (VA.y+VB.y)/2.0; VortexPos.z = (VA.z+VB.z)/2.0; if(qAbs(LA.y)<1.e-5 && qAbs(TA.y)<1.e-5 && qAbs(LB.y)<1.e-5 && qAbs(TB.y)<1.e-5) m_bIsInSymPlane = true; else m_bIsInSymPlane = false; MidA.x = LA.x*(1.0-s_CtrlPos)+TA.x*s_CtrlPos; MidA.y = LA.y*(1.0-s_CtrlPos)+TA.y*s_CtrlPos; MidA.z = LA.z*(1.0-s_CtrlPos)+TA.z*s_CtrlPos; MidB.x = LB.x*(1.0-s_CtrlPos)+TB.x*s_CtrlPos; MidB.y = LB.y*(1.0-s_CtrlPos)+TB.y*s_CtrlPos; MidB.z = LB.z*(1.0-s_CtrlPos)+TB.z*s_CtrlPos; CtrlPt.x = (MidA.x+MidB.x)/2.0; CtrlPt.y = (MidA.y+MidB.y)/2.0; CtrlPt.z = (MidA.z+MidB.z)/2.0; CollPt.x = (LA.x + LB.x + TA.x + TB.x)/4.0; CollPt.y = (LA.y + LB.y + TA.y + TB.y)/4.0; CollPt.z = (LA.z + LB.z + TA.z + TB.z)/4.0; //Use VSAERO figure 8. p23 // if(m_iPos==THINSURFACE || m_Pos==TOPSURFACE || m_Pos==BODYSURFACE) // { m.x = (LB.x + TB.x) *0.5 - CollPt.x; m.y = (LB.y + TB.y) *0.5 - CollPt.y; m.z = (LB.z + TB.z) *0.5 - CollPt.z; /* } else { m.x = (LA.x + TA.x) *0.5 - CollPt.x; m.y = (LA.y + TA.y) *0.5 - CollPt.y; m.z = (LA.z + TA.z) *0.5 - CollPt.z; }*/ m.Normalize(); l.x = m.y * Normal.z - m.z * Normal.y; l.y = -m.x * Normal.z + m.z * Normal.x; l.z = m.x * Normal.y - m.y * Normal.x; smq.x = (LB.x + TB.x) * 0.5 - CollPt.x; smq.y = (LB.y + TB.y) * 0.5 - CollPt.y; smq.z = (LB.z + TB.z) * 0.5 - CollPt.z; smp.x = (TB.x + TA.x) * 0.5 - CollPt.x; smp.y = (TB.y + TA.y) * 0.5 - CollPt.y; smp.z = (TB.z + TA.z) * 0.5 - CollPt.z; SMP = smp.VAbs(); SMQ = smq.VAbs(); Size = SMP + SMQ; //create the transformation matrix lij[0]=l.x; lij[1]=m.x; lij[2]=Normal.x; lij[3]=l.y; lij[4]=m.y; lij[5]=Normal.y; lij[6]=l.z; lij[7]=m.z; lij[8]=Normal.z; Invert33(lij); if(m_Pos>MIDSURFACE) { P1.x = lij[0]*(LA.x-CollPt.x) + lij[1]*(LA.y-CollPt.y) + lij[2]*(LA.z-CollPt.z); P1.y = lij[3]*(LA.x-CollPt.x) + lij[4]*(LA.y-CollPt.y) + lij[5]*(LA.z-CollPt.z); P1.z = lij[6]*(LA.x-CollPt.x) + lij[7]*(LA.y-CollPt.y) + lij[8]*(LA.z-CollPt.z); P2.x = lij[0]*(LB.x-CollPt.x) + lij[1]*(LB.y-CollPt.y) + lij[2]*(LB.z-CollPt.z); P2.y = lij[3]*(LB.x-CollPt.x) + lij[4]*(LB.y-CollPt.y) + lij[5]*(LB.z-CollPt.z); P2.z = lij[6]*(LB.x-CollPt.x) + lij[7]*(LB.y-CollPt.y) + lij[8]*(LB.z-CollPt.z); P3.x = lij[0]*(TB.x-CollPt.x) + lij[1]*(TB.y-CollPt.y) + lij[2]*(TB.z-CollPt.z); P3.y = lij[3]*(TB.x-CollPt.x) + lij[4]*(TB.y-CollPt.y) + lij[5]*(TB.z-CollPt.z); P3.z = lij[6]*(TB.x-CollPt.x) + lij[7]*(TB.y-CollPt.y) + lij[8]*(TB.z-CollPt.z); P4.x = lij[0]*(TA.x-CollPt.x) + lij[1]*(TA.y-CollPt.y) + lij[2]*(TA.z-CollPt.z); P4.y = lij[3]*(TA.x-CollPt.x) + lij[4]*(TA.y-CollPt.y) + lij[5]*(TA.z-CollPt.z); P4.z = lij[6]*(TA.x-CollPt.x) + lij[7]*(TA.y-CollPt.y) + lij[8]*(TA.z-CollPt.z); } else { P1.x = lij[0]*(LB.x-CollPt.x) + lij[1]*(LB.y-CollPt.y) + lij[2]*(LB.z-CollPt.z); P1.y = lij[3]*(LB.x-CollPt.x) + lij[4]*(LB.y-CollPt.y) + lij[5]*(LB.z-CollPt.z); P1.z = lij[6]*(LB.x-CollPt.x) + lij[7]*(LB.y-CollPt.y) + lij[8]*(LB.z-CollPt.z); P2.x = lij[0]*(LA.x-CollPt.x) + lij[1]*(LA.y-CollPt.y) + lij[2]*(LA.z-CollPt.z); P2.y = lij[3]*(LA.x-CollPt.x) + lij[4]*(LA.y-CollPt.y) + lij[5]*(LA.z-CollPt.z); P2.z = lij[6]*(LA.x-CollPt.x) + lij[7]*(LA.y-CollPt.y) + lij[8]*(LA.z-CollPt.z); P3.x = lij[0]*(TA.x-CollPt.x) + lij[1]*(TA.y-CollPt.y) + lij[2]*(TA.z-CollPt.z); P3.y = lij[3]*(TA.x-CollPt.x) + lij[4]*(TA.y-CollPt.y) + lij[5]*(TA.z-CollPt.z); P3.z = lij[6]*(TA.x-CollPt.x) + lij[7]*(TA.y-CollPt.y) + lij[8]*(TA.z-CollPt.z); P4.x = lij[0]*(TB.x-CollPt.x) + lij[1]*(TB.y-CollPt.y) + lij[2]*(TB.z-CollPt.z); P4.y = lij[3]*(TB.x-CollPt.x) + lij[4]*(TB.y-CollPt.y) + lij[5]*(TB.z-CollPt.z); P4.z = lij[6]*(TB.x-CollPt.x) + lij[7]*(TB.y-CollPt.y) + lij[8]*(TB.z-CollPt.z); } } /** * Inverts in place a 3x3 matrix */ bool Panel::Invert33(double *l) { memcpy(mat,l,sizeof(mat)); /* a0 b1 c2 d3 e4 f5 g6 h7 i8 1 (ei-fh) (bi-ch) (bf-ce) ----------------------------- x (fg-di) (ai-cg) (cd-af) a(ei-fh) - b(di-fg) + c(dh-eg) (dh-eg) (bg-ah) (ae-bd)*/ det = mat[0] *(mat[4] * mat[8] - mat[5]* mat[7]); det -= mat[1] *(mat[3] * mat[8] - mat[5]* mat[6]); det += mat[2] *(mat[3] * mat[7] - mat[4]* mat[6]); if(det==0.0) return false; * l = (mat[4] * mat[8] - mat[5] * mat[7])/det; *(l+1) = (mat[2] * mat[7] - mat[1] * mat[8])/det; *(l+2) = (mat[1] * mat[5] - mat[2] * mat[4])/det; *(l+3) = (mat[5] * mat[6] - mat[3] * mat[8])/det; *(l+4) = (mat[0] * mat[8] - mat[2] * mat[6])/det; *(l+5) = (mat[2] * mat[3] - mat[0] * mat[5])/det; *(l+6) = (mat[3] * mat[7] - mat[4] * mat[6])/det; *(l+7) = (mat[1] * mat[6] - mat[0] * mat[7])/det; *(l+8) = (mat[0] * mat[4] - mat[1] * mat[3])/det; return true; } /** * Converts the global coordinates of the input vector in local panel coordinates. *@param V the global coordinates *@return The CVector holding the local coordinates *@todo check if a reference of the vector can be returned instead of a new instance, in order to speed up calculations. */ CVector Panel::GlobalToLocal(CVector const &V) { CVector L; L.x = lij[0]*V.x +lij[1]*V.y +lij[2]*V.z; L.y = lij[3]*V.x +lij[4]*V.y +lij[5]*V.z; L.z = lij[6]*V.x +lij[7]*V.y +lij[8]*V.z; return L; } /** * Converts the global coordinates of the input vector in local panel coordinates. *@param Vx the global x-coordinate *@param Vy the global y-coordinate *@param Vz the global z-coordinate *@return The CVector holding the local coordinates *@todo check if a reference of the vector can be returned instead of a new instance, in order to speed up calculations. */ CVector Panel::GlobalToLocal(double const &Vx, double const &Vy, double const &Vz) { CVector L; L.x = lij[0]*Vx +lij[1]*Vy +lij[2]*Vz; L.y = lij[3]*Vx +lij[4]*Vy +lij[5]*Vz; L.z = lij[6]*Vx +lij[7]*Vy +lij[8]*Vz; return L; } /** * Converts the local coordinates of the input vector in the global referential *@param V the locaal coordinates *@return The CVector holding the global coordinates *@todo check if a reference of the vector can be returned instead of a new instance, in order to speed up calculations. */ CVector Panel::LocalToGlobal(CVector const &V) { CVector L; L.x = V.x * l.x + V.y * m.x + V.z * Normal.x; L.y = V.x * l.y + V.y * m.y + V.z * Normal.y; L.z = V.x * l.z + V.y * m.z + V.z * Normal.z; return L; } /** * Finds the intersection point of a ray with the panel. * The ray is defined by a point and a direction vector. *@param A the ray's origin *@param U the ray's direction *@param I the intersection point *@param dist the distance of A to the panel in the direction of the panel's normal */ bool Panel::Intersect(CVector const &A, CVector const &U, CVector &I, double &dist) { bool b1, b2, b3, b4; double r,s; ILA.Copy(s_pNode[m_iLA]); ITA.Copy(s_pNode[m_iTA]); ILB.Copy(s_pNode[m_iLB]); ITB.Copy(s_pNode[m_iTB]); r = (CollPt.x-A.x)*Normal.x + (CollPt.y-A.y)*Normal.y + (CollPt.z-A.z)*Normal.z ; s = U.x*Normal.x + U.y*Normal.y + U.z*Normal.z; dist = 10000.0; if(qAbs(s)>0.0) { dist = r/s; //inline operations to save time P.x = A.x + U.x * dist; P.y = A.y + U.y * dist; P.z = A.z + U.z * dist; // P is inside the panel if on left side of each panel side W.x = P.x - ITA.x; W.y = P.y - ITA.y; W.z = P.z - ITA.z; V.x = ITB.x - ITA.x; V.y = ITB.y - ITA.y; V.z = ITB.z - ITA.z; T.x = V.y * W.z - V.z * W.y; T.y = -V.x * W.z + V.z * W.x; T.z = V.x * W.y - V.y * W.x; if(T.x*T.x+T.y*T.y+T.z*T.z <1.0e-10 || T.x*Normal.x+T.y*Normal.y+T.z*Normal.z>=0.0) b1 = true; else b1 = false; W.x = P.x - ITB.x; W.y = P.y - ITB.y; W.z = P.z - ITB.z; V.x = ILB.x - ITB.x; V.y = ILB.y - ITB.y; V.z = ILB.z - ITB.z; T.x = V.y * W.z - V.z * W.y; T.y = -V.x * W.z + V.z * W.x; T.z = V.x * W.y - V.y * W.x; if(T.x*T.x+T.y*T.y+T.z*T.z <1.0e-10 || T.x*Normal.x+T.y*Normal.y+T.z*Normal.z>=0.0) b2 = true; else b2 = false; W.x = P.x - ILB.x; W.y = P.y - ILB.y; W.z = P.z - ILB.z; V.x = ILA.x - ILB.x; V.y = ILA.y - ILB.y; V.z = ILA.z - ILB.z; T.x = V.y * W.z - V.z * W.y; T.y = -V.x * W.z + V.z * W.x; T.z = V.x * W.y - V.y * W.x; if(T.x*T.x+T.y*T.y+T.z*T.z <1.0e-10 || T.x*Normal.x+T.y*Normal.y+T.z*Normal.z>=0.0) b3 = true; else b3 = false; W.x = P.x - ILA.x; W.y = P.y - ILA.y; W.z = P.z - ILA.z; V.x = ITA.x - ILA.x; V.y = ITA.y - ILA.y; V.z = ITA.z - ILA.z; T.x = V.y * W.z - V.z * W.y; T.y = -V.x * W.z + V.z * W.x; T.z = V.x * W.y - V.y * W.x; if(T.x*T.x+T.y*T.y+T.z*T.z <1.0e-10 || T.x*Normal.x+T.y*Normal.y+T.z*Normal.z>=0.0) b4 = true; else b4 = false; if(b1 && b2 && b3 && b4) { I.Set(P.x, P.y, P.z); return true; } } return false; } /** *Returns the panel's area *@return the panel's area */ double Panel::GetArea() { return Area; } /** *Returns the panel's width, measured at the leading edge */ double Panel::Width() { return sqrt( (s_pNode[m_iLB].y - s_pNode[m_iLA].y)*(s_pNode[m_iLB].y - s_pNode[m_iLA].y) +(s_pNode[m_iLB].z - s_pNode[m_iLA].z)*(s_pNode[m_iLB].z - s_pNode[m_iLA].z)); } /** *Rotates the boundary condition properties which are used in stability analysis with variable control positions. *@param HA is the center of rotation *@param Qt the quaternion which defines the 3D rotation */ void Panel::RotateBC(CVector const &HA, Quaternion &Qt) { // Qt.Conjugate(Vortex); W.x = VortexPos.x - HA.x; W.y = VortexPos.y - HA.y; W.z = VortexPos.z - HA.z; Qt.Conjugate(W); VortexPos.x = W.x + HA.x; VortexPos.y = W.y + HA.y; VortexPos.z = W.z + HA.z; W.x = VA.x - HA.x; W.y = VA.y - HA.y; W.z = VA.z - HA.z; Qt.Conjugate(W); VA.x = W.x + HA.x; VA.y = W.y + HA.y; VA.z = W.z + HA.z; W.x = VB.x - HA.x; W.y = VB.y - HA.y; W.z = VB.z - HA.z; Qt.Conjugate(W); VB.x = W.x + HA.x; VB.y = W.y + HA.y; VB.z = W.z + HA.z; W.x = CtrlPt.x - HA.x; W.y = CtrlPt.y - HA.y; W.z = CtrlPt.z - HA.z; Qt.Conjugate(W); CtrlPt.x = W.x + HA.x; CtrlPt.y = W.y + HA.y; CtrlPt.z = W.z + HA.z; W.x = CollPt.x - HA.x; W.y = CollPt.y - HA.y; W.z = CollPt.z - HA.z; Qt.Conjugate(W); CollPt.x = W.x + HA.x; CollPt.y = W.y + HA.y; CollPt.z = W.z + HA.z; Qt.Conjugate(Vortex); Qt.Conjugate(Normal); } xflr5-6.09-06/src/objects/PlaneOpp.cpp000644 001750 000144 00000020371 12247174403 020737 0ustar00techwinderusers000000 000000 /**************************************************************************** POpp Class Copyright (C) 2006-2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "PlaneOpp.h" #include "../globals.h" /** *The public constructor */ PlaneOpp::PlaneOpp(int PanelArraySize) { m_PlaneName = ""; m_PlrName = ""; m_NStation = 0; m_NPanels = 0; m_Color = QColor(255,0,0); m_Style = 0; m_Width = 1; m_WPolarType = FIXEDSPEEDPOLAR; m_bIsVisible = true; m_bShowPoints = false; m_bOut = false; m_bVLM1 = true; m_Alpha = 0.0; m_Beta = 0.0; m_Bank = 0.0; m_QInf = 0.0; m_Ctrl = 0.0; // for (int iw=0; iwm_Color = m_Color; } /** * The public destructor */ PlaneOpp::~PlaneOpp() { Release(); } /** Allocate memory to the arrays */ void PlaneOpp::Allocate(int PanelArraySize) { Release(); m_NPanels = PanelArraySize; m_Cp = new float[PanelArraySize]; m_Sigma = new float[PanelArraySize]; m_G = new float[PanelArraySize]; memset(m_G, 0, PanelArraySize * sizeof(float)); memset(m_Sigma, 0, PanelArraySize * sizeof(float)); memset(m_Cp, 0, PanelArraySize * sizeof(float)); } /** * Releases memory allocated on the heap */ void PlaneOpp::Release() { if(m_Cp) delete [] m_Cp; if(m_Sigma) delete [] m_Sigma; if(m_G) delete [] m_G; m_Cp = NULL; m_Sigma = NULL; m_G = NULL; for (int iw=0; iwSerializeWingOpp(ar, bIsStoring); } } } else { ar >> ArchiveFormat; if(ArchiveFormat<1000 || ArchiveFormat>1100) return false; //read variables ReadCString(ar, m_PlaneName); ReadCString(ar, m_PlrName); //always a main wing if(m_pPlaneWOpp[0]!=NULL) delete m_pPlaneWOpp[0]; m_pPlaneWOpp[0] = new WingOpp(); if(ArchiveFormat>=1005) { ar >> a; if (a!=0 && a!=1) return false; if(a) { if(m_pPlaneWOpp[1]!=NULL) delete m_pPlaneWOpp[1]; m_pPlaneWOpp[1] = new WingOpp(); } } ar >> a; if (a!=0 && a!=1) return false; if(a) { if(m_pPlaneWOpp[2]!=NULL) delete m_pPlaneWOpp[2]; m_pPlaneWOpp[2] = new WingOpp(); } ar >> a; if (a!=0 && a!=1) return false; if(a) { if(m_pPlaneWOpp[3]!=NULL) delete m_pPlaneWOpp[3]; m_pPlaneWOpp[3] = new WingOpp(); } ar >> a; if (a!=0 && a!=1) return false; if(a) m_bIsVisible = true; else m_bIsVisible = false; ar >> a; if (a!=0 && a!=1) return false; if(a) m_bShowPoints = true; else m_bShowPoints = false; ar >> a; if (a!=0 && a!=1) return false; if(a) m_bOut = true; else m_bOut = false; ar >> a; if (a!=0 && a!=1) return false; if(a) m_bVLM1 = true; else m_bVLM1 = false; ar >> a; if (a!=0 && a!=1) return false; // if(a) m_bMiddle = true; else m_bMiddle = false; ar >> m_Style >> m_Width; ReadCOLORREF(ar, m_Color); ar >>k; if(k==1) m_WPolarType = FIXEDSPEEDPOLAR; else if(k==2) m_WPolarType = FIXEDLIFTPOLAR; else if(k==4) m_WPolarType = FIXEDAOAPOLAR; else if(k==7) m_WPolarType = STABILITYPOLAR; else return false; ar >> m_NStation; ar >> f; m_Alpha = f; ar >> f; m_QInf = f; ar >> f;// m_Weight = f; if(ArchiveFormat>=1007) { ar>>f; m_Beta = f; } if(ArchiveFormat<1002) { ar >> f; ar >> f; ar >> f; ar >> f; ar >> f; ar >> f; ar >> f; ar >> f; ar >> f; ar >> f; ar >> f; } if(ArchiveFormat<1001) { for (k=0; k<=m_NStation; k++) { ar >> f; } for (k=0; k<=m_NStation; k++) { ar >> f; } for (k=0; k<=m_NStation; k++) { ar >> f; } } if(ArchiveFormat>=1002 ) { ar >>m_NPanels; if(ArchiveFormat<=1007) { for (k=0; k<=m_NPanels; k++) { ar >> f; // m_Cp[k] = f; } } } if(ArchiveFormat>=1003 && ArchiveFormat<=1007) { for (k=0; k<=m_NPanels; k++) { ar >> f; // if(ArchiveFormat<1004) m_G[k] = f/1000.0; // else m_G[k] = f; } } if(ArchiveFormat>=1006 && ArchiveFormat<=1007) { for (k=0; k<=m_NPanels; k++) { ar >> f; // m_Sigma[k] = f; } } if(ArchiveFormat>=1009) { if(m_G!=NULL) delete [] m_G; if(m_Sigma!=NULL) delete [] m_Sigma; if(m_Cp!=NULL) delete [] m_Cp; m_G = new float[m_NPanels]; m_Sigma = new float[m_NPanels]; m_Cp = new float[m_NPanels]; for (k=0; k> f >> g >> h; m_Cp[k] = f; m_Sigma[k] = g; m_G[k] = h; } } ar >> k; //VLMType if (!m_pPlaneWOpp[0]->SerializeWingOpp(ar, bIsStoring)) { return false; } if(ArchiveFormat>=1005) { if(m_pPlaneWOpp[1]) { if (!m_pPlaneWOpp[1]->SerializeWingOpp(ar, bIsStoring)) { return false; } } } if(m_pPlaneWOpp[2]) { if (!m_pPlaneWOpp[2]->SerializeWingOpp(ar, bIsStoring)) { return false; } } if(m_pPlaneWOpp[3]) { if (!m_pPlaneWOpp[3]->SerializeWingOpp(ar, bIsStoring)) { return false; } } m_Ctrl = m_pPlaneWOpp[0]->m_Ctrl; //forgot to save the variable in the POpp serialization... } return true; } xflr5-6.09-06/src/objects/Polar.cpp000644 001750 000144 00000062510 12247174403 020277 0ustar00techwinderusers000000 000000 /**************************************************************************** Polar Class Copyright (C) 2003 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "Polar.h" #include "../mainframe.h" #include "../globals.h" #include "../xdirect/XFoil.h" /** *The public constructor. */ Polar::Polar() { m_bIsVisible = true; m_bShowPoints = false; m_Style = 0;// = PS_SOLID m_Width = 1; m_ASpec = 0.0; m_PolarType = FIXEDSPEEDPOLAR; m_ReType = 1; m_MaType = 1; m_Reynolds = 100000.0; m_Mach = 0.0; m_ACrit = 9.0; m_XTop = 1.0; m_XBot = 1.0; m_FoilName = ""; m_PlrName = ""; } /** * Exports the data of the polar to a text file * @param out the instance of output QtextStream * @param FileType TXT if the data is separated by spaces, CSV for a comma separator * @param bDataOnly true if the analysis parameters should not be output */ void Polar::ExportPolar(QTextStream &out, enumTextFileType FileType, bool bDataOnly) { QString Header, strong; int j; if(!bDataOnly) { strong =MainFrame::versionName() + "\n\n"; out << strong; strong =(" Calculated polar for: "); strong += m_FoilName + "\n\n"; out << strong; strong = QString(" %1 %2").arg(m_ReType).arg(m_MaType); if(m_ReType==1) strong += (" Reynolds number fixed "); else if(m_ReType==2) strong += (" Reynolds number ~ 1/sqrt(CL)"); else if(m_ReType==3) strong += (" Reynolds number ~ 1/CL "); if(m_MaType==1) strong += (" Mach number fixed "); else if(m_MaType==2) strong += (" Mach number ~ 1/sqrt(CL) "); else if(m_MaType==3) strong += (" Mach number ~ 1/CL "); strong +="\n\n"; out << strong; strong=QString((" xtrf = %1 (top) %2 (bottom)\n")) .arg(m_XTop,0,'f',3).arg(m_XBot,0,'f',3); out << strong; strong = QString(" Mach = %1 Re = %2 e 6 Ncrit = %3\n\n") .arg(m_Mach,7,'f',3).arg(m_Reynolds/1.e6,9,'f',3).arg(m_ACrit,7,'f',3); out << strong; } if(m_PolarType!=FIXEDAOAPOLAR) { if(FileType==TXT) Header = (" alpha CL CD CDp Cm Top Xtr Bot Xtr Cpmin Chinge XCp \n"); else Header = ("alpha,CL,CD,CDp,Cm,Top Xtr,Bot Xtr,Cpmin,Chinge,XCp\n"); out << Header; if(FileType==TXT) { Header=QString(" ------- -------- --------- --------- -------- ------- ------- -------- --------- ---------\n"); out << Header; } for (j=0; jm_bViscResults) return; m_ACrit = pOpPoint->ACrit; AddPoint(pOpPoint->Alpha, pOpPoint->Cd, pOpPoint->Cdp, pOpPoint->Cl, pOpPoint->Cm, pOpPoint->Xtr1, pOpPoint->Xtr2, pOpPoint->m_TEHMom, pOpPoint->Cpmn, pOpPoint->Reynolds, pOpPoint->m_XCP); } /** * Adds the data from the instance of the XFoil object to the data arrays * The index used to insert the data is the aoa for type 1, 2 and 3 polars, and the freestream velocity for type 4 polars. * If a point with identical index exists, the data is replaced. * If not, the data is inserted for this index. * * @param *ptrXFoil a pointer to the instance of the XFoil class where the calculation has been performed. */ void Polar::AddData(void* ptrXFoil) { XFoil *pXFoil = (XFoil*)ptrXFoil; if(!pXFoil->lvisc) return; double alpha = pXFoil->alfa*180.0/PI; m_ACrit = pXFoil->acrit; AddPoint(alpha, pXFoil->cd, pXFoil->cdp, pXFoil->cl, pXFoil->cm, pXFoil->xoctr[1], pXFoil->xoctr[2], pXFoil->hmom, pXFoil->cpmn, pXFoil->reinf1, pXFoil->xcp); } /** * Adds the parameter data to the data arrays * The index used to insert the data is the aoa for type 1, 2 and 3 polars, and the freestream velocity for type 4 polars. * If a point with identical index exists, the data is replaced. * If not, the data is inserted for this index. * */ void Polar::AddPoint(double Alpha, double Cd, double Cdp, double Cl, double Cm, double Xtr1, double Xtr2, double HMom, double Cpmn, double Reynolds, double XCp) { int i; bool bInserted = false; int size = (int)m_Alpha.size(); if(size) { for ( i=0; i0.0) m_RtCl[i] = 1.0/sqrt(Cl); else m_RtCl[i] = 0.0; if (Cl>=0.0) m_Cl32Cd[i] = pow(Cl, 1.5)/ Cd; else m_Cl32Cd[i] = -pow(-Cl, 1.5)/ Cd; if(m_PolarType==FIXEDSPEEDPOLAR) m_Re[i] = Reynolds; else if (m_PolarType==FIXEDLIFTPOLAR) { if(Cl>0.0) m_Re[i] = Reynolds/ sqrt(Cl); else m_Re[i] = 0.0; } else if (m_PolarType==RUBBERCHORDPOLAR) { if(Cl>0.0) m_Re[i] = Reynolds/(Cl); else m_Re[i] = 0.0; } bInserted = true; break; } else if (Alpha < m_Alpha[i]) { // sort by crescending alphas m_Alpha.insert(i, Alpha); m_Cd.insert(i, Cd); m_Cdp.insert(i, Cdp); m_Cl.insert(i, Cl); m_Cm.insert(i, Cm); m_XTr1.insert(i, Xtr1); m_XTr2.insert(i, Xtr2); m_HMom.insert(i, HMom); m_Cpmn.insert(i, Cpmn); m_ClCd.insert(i, Cl/Cd); m_XCp.insert(i, XCp); if(Cl>0.0) m_RtCl.insert(i, 1.0/sqrt(Cl)); else m_RtCl.insert(i, 0.0); if (Cl>=0.0) m_Cl32Cd.insert(i,pow(Cl, 1.5)/ Cd); else m_Cl32Cd.insert(i,-pow(-Cl, 1.5)/ Cd); if(m_PolarType==FIXEDSPEEDPOLAR) m_Re.insert(i, Reynolds); else if (m_PolarType==FIXEDLIFTPOLAR) { if(Cl>0) m_Re.insert(i, Reynolds/sqrt(Cl)); else m_Re[i] = 0.0; } else if (m_PolarType==RUBBERCHORDPOLAR) { if(Cl>0.0) m_Re.insert(i, Reynolds/Cl); else m_Re.insert(i, 0.0); } bInserted = true; break; } } else { //m_PolarType 4 polar, sort by Reynolds numbers if (qAbs(Reynolds - m_Re[i]) < 0.1) { // then erase former result m_Alpha[i] = Alpha; m_Cd[i] = Cd; m_Cdp[i] = Cdp; m_Cl[i] = Cl; m_Cm[i] = Cm; m_XTr1[i] = Xtr1; m_XTr2[i] = Xtr2; m_HMom[i] = HMom; m_Cpmn[i] = Cpmn; m_ClCd[i] = Cl/Cd; m_XCp[i] = XCp; if(Cl>0.0) m_RtCl[i] = 1.0/sqrt(Cl); else m_RtCl[i] = 0.0; if (Cl>=0.0) m_Cl32Cd[i] = pow(Cl, 1.5)/ Cd; else m_Cl32Cd[i] = -pow(-Cl, 1.5)/ Cd; m_Re[i] = Reynolds; bInserted = true; break; } else if (Reynolds < m_Re[i]) { // sort by crescending Reynolds numbers m_Alpha.insert(i, Alpha); m_Cd.insert(i, Cd); m_Cdp.insert(i, Cdp); m_Cl.insert(i, Cl); m_Cm.insert(i, Cm); m_XTr1.insert(i, Xtr1); m_XTr2.insert(i, Xtr2); m_HMom.insert(i, HMom); m_Cpmn.insert(i, Cpmn); m_ClCd.insert(i, Cl/Cd); m_XCp.insert(i, XCp); if(Cl>0.0) m_RtCl.insert(i, 1.0/(double)sqrt(Cl)); else m_RtCl.insert(i, 0.0); if (Cl>=0.0) m_Cl32Cd.insert(i, pow(Cl, 1.5)/ Cd); else m_Cl32Cd.insert(i,-pow(-Cl, 1.5)/ Cd); m_Re.insert(i, Reynolds); bInserted = true; break; } } } } if(!bInserted) { // data is appended at the end m_Alpha.insert(size, Alpha); m_Cd.insert(size, Cd); m_Cdp.insert(size, Cdp); m_Cl.insert(size, Cl); m_Cm.insert(size, Cm); m_XTr1.insert(size, Xtr1); m_XTr2.insert(size, Xtr2); m_HMom.insert(size, HMom); m_Cpmn.insert(size, Cpmn); m_ClCd.insert(size, Cl/Cd); m_XCp.insert(size, XCp); if(Cl>0.0) m_RtCl.insert(size, 1.0/(double)sqrt(Cl)); else m_RtCl.insert(size, 0.0); if (Cl>=0.0) m_Cl32Cd.insert(size,(double)pow(Cl, 1.5)/ Cd); else m_Cl32Cd.insert(size,-(double)pow(-Cl, 1.5)/ Cd); if(m_PolarType==FIXEDSPEEDPOLAR || m_PolarType==FIXEDAOAPOLAR) m_Re.insert(size, Reynolds); else if (m_PolarType==FIXEDLIFTPOLAR) { if(Cl>0) m_Re.insert(size, Reynolds/(double) sqrt(Cl)); else m_Re.insert(size, 0.0); } else if (m_PolarType==RUBBERCHORDPOLAR) { if(Cl>0.0) m_Re.insert(size, Reynolds/Cl); else m_Re.insert(size, 0.0); } } } /** * Copies the polar's data from an existing polar * @param pPolar a pointer to the instance of the reference Polar object from which the data should be copied */ void Polar::Copy(Polar *pPolar) { int i; int size = (int)m_Alpha.size(); for(i=size-1; i>=0; i--) Remove(i); size = (int)pPolar->m_Alpha.size(); for(i=0; im_Alpha[i]); m_Cd.insert(i, pPolar->m_Cd[i]); m_Cdp.insert(i, pPolar->m_Cdp[i]); m_Cl.insert(i, pPolar-> m_Cl[i]); m_Cm.insert(i, pPolar->m_Cm[i]); m_XTr1.insert(i, pPolar->m_XTr1[i]); m_XTr2.insert(i, pPolar->m_XTr2[i]); m_HMom.insert(i, pPolar->m_HMom[i]); m_Cpmn.insert(i, pPolar->m_Cpmn[i]); m_ClCd.insert(i, pPolar->m_ClCd[i]); m_RtCl.insert(i, pPolar->m_RtCl[i]); m_Cl32Cd.insert(i, pPolar->m_Cl32Cd[i]); m_Re.insert(i, pPolar->m_Re[i]); m_XCp.insert(i, pPolar->m_XCp[i]); } } /** * Loads or saves the data of this polar to a binary file * @param ar the QDataStream object from/to which the data should be serialized * @param bIsStoring true if saving the data, false if loading * @return true if the operation was successful, false otherwise */ bool Polar::Serialize(QDataStream &ar, bool bIsStoring) { int i, j, n, l, k; int ArchiveFormat;// identifies the format of the file float f; // qint32 colorref; // int r,g,b; if(bIsStoring) { //write variables n = (int)m_Alpha.size(); ar << 1004; // identifies the format of the file // 1004 : added XCp // 1003 : re-instated NCrit, XtopTr and XBotTr with polar WriteCString(ar, m_FoilName); WriteCString(ar, m_PlrName); if(m_PolarType==FIXEDSPEEDPOLAR) ar<<1; else if(m_PolarType==FIXEDLIFTPOLAR) ar<<2; else if(m_PolarType==RUBBERCHORDPOLAR) ar<<3; else if(m_PolarType==FIXEDAOAPOLAR) ar<<4; else ar<<1; ar << m_MaType << m_ReType ; ar << (int)m_Reynolds << (float)m_Mach ; ar << (float)m_ASpec; ar << n << (float)m_ACrit; ar << (float)m_XTop << (float)m_XBot; WriteCOLORREF(ar,m_Color); ar << m_Style << m_Width; if (m_bIsVisible) ar<<1; else ar<<0; if (m_bShowPoints) ar<<1; else ar<<0; for (i=0; i< m_Alpha.size(); i++){ ar << (float)m_Alpha[i] << (float)m_Cd[i] ; ar << (float)m_Cdp[i] << (float)m_Cl[i] << (float)m_Cm[i]; ar << (float)m_XTr1[i] << (float)m_XTr2[i]; ar << (float)m_HMom[i] << (float)m_Cpmn[i]; ar << (float)m_Re[i]; ar << (float)m_XCp[i]; } ar << m_ACrit << m_XTop << m_XBot; return true; } else { //read variables float Alpha, Cd, Cdp, Cl, Cm, XTr1, XTr2, HMom, Cpmn, Re, XCp; int iRe; ar >> ArchiveFormat; if (ArchiveFormat <1001 ||ArchiveFormat>1100) { return false; } ReadCString(ar, m_FoilName); ReadCString(ar, m_PlrName); if(m_FoilName =="" || m_PlrName =="" ) { return false; } ar >>k; if(k==1) m_PolarType = FIXEDSPEEDPOLAR; else if(k==2) m_PolarType = FIXEDLIFTPOLAR; else if(k==3) m_PolarType = RUBBERCHORDPOLAR; else if(k==4) m_PolarType = FIXEDAOAPOLAR; else m_PolarType = FIXEDSPEEDPOLAR; ar >> m_MaType >> m_ReType; if(m_MaType!=1 && m_MaType!=2 && m_MaType!=3) { return false; } if(m_ReType!=1 && m_ReType!=2 && m_ReType!=3) { return false; } ar >> iRe; m_Reynolds = (double) iRe; ar >> f; m_Mach =f; ar >> f; m_ASpec =f; ar >> n; ar >> f; m_ACrit =f; ar >> f; m_XTop =f; ar >> f; m_XBot =f; ReadCOLORREF(ar, m_Color); ar >> m_Style >> m_Width; if(ArchiveFormat>=1002) { ar >> l; if(l!=0 && l!=1 ) { return false; } if (l) m_bIsVisible =true; else m_bIsVisible = false; } ar >> l; if(l!=0 && l!=1 ) { return false; } if (l) m_bShowPoints =true; else m_bShowPoints = false; bool bExists; for (i=0; i< n; i++) { ar >> Alpha >> Cd >> Cdp >> Cl >> Cm; ar >> XTr1 >> XTr2; ar >> HMom >> Cpmn; if(ArchiveFormat >=4) ar >> Re; else Re = (float)m_Reynolds; if(ArchiveFormat>=1004) ar>> XCp; else XCp = 0.0; bExists = false; if(m_PolarType!=FIXEDAOAPOLAR) { for (j=0; j=1003) ar >> m_ACrit >> m_XTop >> m_XBot; } return true; } /** * Removes the data for the point at a given index of the data arrays * @param i the index of the point to be removed **/ void Polar::Remove(int i) { m_Alpha.removeAt(i); m_Cl.removeAt(i); m_Cd.removeAt(i); m_Cdp.removeAt(i); m_Cm.removeAt(i); m_XTr1.removeAt(i); m_XTr2.removeAt(i); m_HMom.removeAt(i); m_Cpmn.removeAt(i); m_ClCd.removeAt(i); m_RtCl.removeAt(i); m_Cl32Cd.removeAt(i); m_Re.removeAt(i); m_XCp.removeAt(i); } /** * Returns the minimum and maximum angles of attack stored in the polar. * Since the data is sorted by crescending aoa, this is a matter of returning the first and last values of the array. *@param &amin the miminum aoa *@param &amax the maximum aoa */ void Polar::GetAlphaLimits(double &amin, double &amax) { if(!m_Alpha.size()){ amin = 0.0; amax = 0.0; } else { amin = m_Alpha[0]; amax = m_Alpha[m_Alpha.size()-1]; } } /** * Returns the minimum and maximum lift coefficients stored in the polar. *@param &Clmin the miminum lift coefficient *@param &Clmax the maximum lift coefficient */ void Polar::GetClLimits(double &Clmin, double &Clmax) { if(!m_Cl.size()) { Clmin = 0.0; Clmax = 0.0; } else { Clmin = 10000.0; Clmax =-10000.0; double Cl; for (int i=0;iCl) Clmin = Cl; if(Clmax0. * If no such pair is found, the method returns 0. *@return Cm0 */ double Polar::GetCm0() { int i; double Clmin = 1000.0; double Clmax = -1000.0; for (i=0; i0.0)) return 0.0; int k=0; // double rr = m_Cl[k]; // double rr1 = m_Cl[k+1]; while (m_Cl[k+1]<0.0) { // rr = m_Cl[k]; // rr1 = m_Cl[k+1]; k++; } if(k+1>=m_Cm.size()) return 0.0; double Cm0 = m_Cm[k] + (m_Cm[k+1]-m_Cm[k])*(0.0-m_Cl[k])/(m_Cl[k+1]-m_Cl[k]); return Cm0; } /** * Returns the value of the aoa such that Cl=0. * The zero lift angle is interpolated between the two points in the array such that Cl[i]<0 and Cl[i+1]>0. * If no such pair is found, the method returns 0. *@return Cm0 */ double Polar::GetZeroLiftAngle() { double Clmin = 1000.0; double Clmax = -1000.0; for (int i=0; i0.0)) return 0.0; int k=0; // double rr = m_Cl[k]; // double rr1 = m_Cl[k+1]; while (m_Cl[k+1]<0.0) { // rr = m_Cl[k]; // rr1 = m_Cl[k+1]; k++; } if(k+1>=m_Alpha.size()) return 0.0; double Alpha0 = m_Alpha[k] + (m_Alpha[k+1]-m_Alpha[k])*(0.0-m_Cl[k])/(m_Cl[k+1]-m_Cl[k]); return Alpha0; } /** * Linearizes Cl vs. Alpha set of points by least square method * @param Alpha0 the zero-lift angle, i.e.such that Cl = 0, in degrees * @param slope the slope of the curve Cl=f(aoa), in units 1/° */ void Polar::GetLinearizedCl(double &Alpha0, double &slope) { int n = (int)m_Cl.size(); if(n<=1) { Alpha0 = 0.0; slope = 2.0*PI*PI/180.0; return; } double fn = (double)n; double sum1 = 0.0; double sum2 = 0.0; double sum3 = 0.0; double sum4 = 0.0; double b1, b2; for (int k=0; k #include "../globals.h" #include #include /** * The public constructor. */ Foil::Foil() { m_nFoilStyle = 0; m_nFoilWidth = 1; m_FoilColor = QColor(255,0,0,127); m_iHighLight = -1; m_bCenterLine = false; m_bPoints = false; m_bVisible = true; m_bSaved = true; m_FoilName = ""; m_FoilDescription = ""; m_fCamber = 0.0; m_fXCamber = 0.0; m_fThickness = 0.0; m_fXThickness = 0.0; n = 0; memset(x, 0, sizeof(x)); memset(y, 0, sizeof(y)); memset(nx, 0, sizeof(nx)); memset(ny, 0, sizeof(ny)); nb = 0; memset(xb, 0, sizeof(xb)); memset(yb, 0, sizeof(yb)); m_iInt = 0; m_iExt = 0; m_iBaseExt = 0; m_iBaseInt = 0; m_Gap = 0.0; memset(m_rpExtrados, 0, sizeof(m_rpExtrados)); memset(m_rpIntrados, 0, sizeof(m_rpIntrados)); memset(m_rpMid, 0, sizeof(m_rpMid)); memset(m_BaseExtrados, 0, sizeof(m_BaseExtrados)); memset(m_BaseIntrados, 0, sizeof(m_BaseIntrados)); m_bTEFlap = false; m_TEFlapAngle = 0.0; m_TEXHinge = 80.0; m_TEYHinge = 50.0; m_bLEFlap = false; m_LEFlapAngle = 0.0; m_LEXHinge = 20.0; m_LEYHinge = 50.0; } /** * Constructs the postion of the foil's mid camber line. * Calculates the foil's thickness and camber, if requested. *@param bParams true if the max thickness and camber properties shold be calculated */ void Foil::CompMidLine(bool bParams) { static int l; static double xt, yex, yin, step; if(bParams) { m_fThickness = 0.0; m_fCamber = 0.0; m_fXCamber = 0.0; m_fXThickness = 0.0; } // double length = GetLength(); step = (m_rpExtrados[m_iExt].x-m_rpExtrados[0].x)/(double)MIDPOINTCOUNT; for (l=0; lm_fThickness) { m_fThickness = qAbs(yex-yin); m_fXThickness = xt; } if(qAbs(m_rpMid[l].y)>qAbs(m_fCamber)) { m_fCamber = m_rpMid[l].y; m_fXCamber = xt; } } } m_rpMid[0].x = 0.0; m_rpMid[0].y = 0.0; m_rpMid[MIDPOINTCOUNT-1].x = 1.0; m_rpMid[MIDPOINTCOUNT-1].y = 0.0; } /** * Copies the data from an existing foil and maps it to this foil's variables. *@param pSrcFoil a pointer to the reference foil from which the data wil be copied */ void Foil::CopyFoil(Foil *pSrcFoil) { memcpy(x, pSrcFoil->x, sizeof(pSrcFoil->x)); memcpy(y, pSrcFoil->y, sizeof(pSrcFoil->y)); memcpy(xb,pSrcFoil->xb, sizeof(pSrcFoil->xb)); memcpy(yb,pSrcFoil->yb, sizeof(pSrcFoil->yb)); memcpy(nx,pSrcFoil->nx, sizeof(pSrcFoil->nx)); memcpy(ny,pSrcFoil->ny, sizeof(pSrcFoil->ny)); memcpy(m_rpMid, pSrcFoil->m_rpMid, sizeof(m_rpMid)); memcpy(m_rpExtrados, pSrcFoil->m_rpExtrados, sizeof(m_rpExtrados)); memcpy(m_rpIntrados, pSrcFoil->m_rpIntrados, sizeof(m_rpIntrados)); memcpy(m_BaseExtrados, pSrcFoil->m_BaseExtrados, sizeof(m_BaseExtrados)); memcpy(m_BaseIntrados, pSrcFoil->m_BaseIntrados, sizeof(m_BaseIntrados)); m_iExt = pSrcFoil->m_iExt; m_iInt = pSrcFoil->m_iInt; m_iBaseExt = pSrcFoil->m_iBaseExt; m_iBaseInt = pSrcFoil->m_iBaseInt; m_Gap = pSrcFoil->m_Gap; m_LE.x = pSrcFoil->m_LE.x; m_LE.y = pSrcFoil->m_LE.y; m_fThickness = pSrcFoil->m_fThickness; m_fXThickness = pSrcFoil->m_fXThickness; m_fCamber = pSrcFoil->m_fCamber; m_fXCamber = pSrcFoil->m_fXCamber; n = pSrcFoil->n; nb = pSrcFoil->nb; m_FoilName = pSrcFoil->m_FoilName; m_bLEFlap = pSrcFoil->m_bLEFlap; m_LEFlapAngle = pSrcFoil->m_LEFlapAngle; m_LEXHinge = pSrcFoil->m_LEXHinge; m_LEYHinge = pSrcFoil->m_LEYHinge; m_bTEFlap = pSrcFoil->m_bTEFlap; m_TEFlapAngle = pSrcFoil->m_TEFlapAngle; m_TEXHinge = pSrcFoil->m_TEXHinge; m_TEYHinge = pSrcFoil->m_TEYHinge; m_FoilColor = pSrcFoil->m_FoilColor; m_nFoilStyle = pSrcFoil->m_nFoilStyle; m_nFoilWidth = pSrcFoil->m_nFoilWidth; m_bCenterLine = pSrcFoil->m_bCenterLine; m_bPoints = pSrcFoil->m_bPoints; } /** * Derotates the fol's geometry i.e. aligns the mid-line with the x-axis. *@return the angle, in degrees, by which the foil has been de-rotated */ double Foil::DeRotate() { //De-rotates the foil, double xle, xte, yle, yte; double angle, cosa, sina; int i; // first find offset //and translate the leading edge to the origin point for (i=0; i=0) { HighPen.setWidth(2); painter.setPen(HighPen); pt1.rx() = (int)( x[m_iHighLight]*scalex + Offset.x() - width); pt1.ry() = (int)(-y[m_iHighLight]*scaley + Offset.y() - width); painter.drawRect(pt1.x(), pt1.y(), 4, 4); } } /** * Exports the foil geometry to a text .dat file. * @param out the QtextStream to which the output will be directed * @return true if the operation has been successful, false otherwise */ bool Foil::ExportFoil(QTextStream &out) { int i; QString strOut; out << m_FoilName +"\n"; for (i=0; i< n; i++) { strOut = QString("%1 %2\n").arg(x[i],8,'f',5).arg(y[i],8,'f',5); out << strOut; } return true; } /** * Returns the area defined by the foil's contour, in normalized units. * @return the foil's internal area */ double Foil::GetArea() { int i; double area = 0.0; for (i=0; i=1.0) { double dx = m_rpMid[MIDPOINTCOUNT-1].x-m_rpMid[MIDPOINTCOUNT-2].x; double dy = m_rpMid[MIDPOINTCOUNT-1].y-m_rpMid[MIDPOINTCOUNT-2].y; return atan2(dy,dx); } return 0.0; } /** * Returns the foil's name. * @param FoilName the foil's name as a QString */ void Foil::foilName(QString &FoilName) { FoilName = m_FoilName; } /** *Returns the foil's length. *@return the foil's length, in relative units */ double Foil::length() { return qMax(m_rpExtrados[m_iExt].x, m_rpExtrados[m_iInt].x); } /** * Returns the y-coordinate on the current foil's lower surface at the x position. *@param x the chordwise position *@return the position on the lower surface */ double Foil::GetLowerY(double x) { x = m_rpIntrados[0].x + x*(m_rpIntrados[m_iInt].x-m_rpIntrados[0].x);//in case there is a flap which reduces the length static double y; for (int i=0; ix = 0.0; M->y = 0.0; M->z = 0.0; AB.Set(B.x-A.x, B.y-A.y, B.z-A.z); CD.Set(D.x-C.x, D.y-C.y, D.z-C.z); //Cramer's rule Det = -AB.x * CD.y + CD.x * AB.y; if(Det==0.0) { //vectors are parallel, no intersection return false; } Det1 = -(C.x-A.x)*CD.y + (C.y-A.y)*CD.x; Det2 = -(C.x-A.x)*AB.y + (C.y-A.y)*AB.x; t = Det1/Det; u = Det2/Det; M->x = A.x + t*AB.x; M->y = A.y + t*AB.y; if (0.0<=t && t<=1.0 && 0.0<=u && u<=1.0) return true;//M is between A and B else return false;//M is outside } /** *Returns the index of foil's point which coincides with the input point, if any, otherwise returns -10. *@param &Real the Cvector which defines the input point */ int Foil::IsPoint(CVector const &Real) { static int k; for (k=0; k> ArchiveFormat; ReadCString(ar, m_FoilName); if(ArchiveFormat>=1006) { ReadCString(ar, m_FoilDescription); } if(ArchiveFormat>=1002) { ar >> m_nFoilStyle >> m_nFoilWidth; ReadCOLORREF(ar, m_FoilColor); } if(ArchiveFormat>=1003) { ar >> p; if(p) m_bVisible = true; else m_bVisible = false; } if(ArchiveFormat>=1004) { ar >> p; if(p) m_bPoints = true; else m_bPoints = false; ar >> p; if(p) m_bCenterLine = true; else m_bCenterLine = false; } if(ArchiveFormat>=1005) { ar >> p; if (p) m_bLEFlap = true; else m_bLEFlap = false; ar >> f; m_LEFlapAngle =f; ar >> f; m_LEXHinge = f; ar >> f; m_LEYHinge = f; } ar >> p; if (p) m_bTEFlap = true; else m_bTEFlap = false; ar >> f; m_TEFlapAngle =f; ar >> f; m_TEXHinge = f; ar >> f; m_TEYHinge = f; ar >> f >> f >> f; //formerly transition parameters ar >> nb; if(nb>IBX) return false; for (j=0; j> f >> ff; xb[j] = f; yb[j]=ff; } if(ArchiveFormat>=1001) { ar >> n; if(n>IBX) return false; for (j=0; j> f >> ff; x[j]=f; y[j]=ff; } if(nb==0 && n!=0) { nb = n; memcpy(xb,x, sizeof(xb)); memcpy(yb,y, sizeof(yb)); } } else { memcpy(x,xb, sizeof(xb)); memcpy(y,yb, sizeof(yb)); n=nb; } return true; } } /** * Reset the foil to a default Naca 009 geometry. */ void Foil::SetNaca009() { x[0] = 1.00000 ; y[0] = 0.00000; x[1] = 0.99572 ; y[1] = 0.00057; x[2] = 0.98296 ; y[2] = 0.00218; x[3] = 0.96194 ; y[3] = 0.00463; x[4] = 0.93301 ; y[4] = 0.00770; x[5] = 0.89668 ; y[5] = 0.01127; x[6] = 0.85355 ; y[6] = 0.01522; x[7] = 0.80438 ; y[7] = 0.01945; x[8] = 0.75000 ; y[8] = 0.02384; x[9] = 0.69134 ; y[9] = 0.02823; x[10] = 0.62941 ; y[10] = 0.03247; x[11] = 0.56526 ; y[11] = 0.03638; x[12] = 0.50000 ; y[12] = 0.03978; x[13] = 0.43474 ; y[13] = 0.04248; x[14] = 0.37059 ; y[14] = 0.04431; x[15] = 0.33928 ; y[15] = 0.04484; x[16] = 0.30866 ; y[16] = 0.04509; x[17] = 0.27886 ; y[17] = 0.04504; x[18] = 0.25000 ; y[18] = 0.04466; x[19] = 0.22221 ; y[19] = 0.04397; x[20] = 0.19562 ; y[20] = 0.04295; x[21] = 0.17033 ; y[21] = 0.04161; x[22] = 0.14645 ; y[22] = 0.03994; x[23] = 0.12408 ; y[23] = 0.03795; x[24] = 0.10332 ; y[24] = 0.03564; x[25] = 0.08427 ; y[25] = 0.03305; x[26] = 0.06699 ; y[26] = 0.03023; x[27] = 0.05156 ; y[27] = 0.02720; x[28] = 0.03806 ; y[28] = 0.02395; x[29] = 0.02653 ; y[29] = 0.02039; x[30] = 0.01704 ; y[30] = 0.01646; x[31] = 0.00961 ; y[31] = 0.01214; x[32] = 0.00428 ; y[32] = 0.00767; x[33] = 0.00107 ; y[33] = 0.00349; x[34] = 0.00000 ; y[34] = 0.00000; for (int i=0; i<34; i++){ x[i+35] = x[33-i]; y[i+35] = -y[33-i]; } n = 69; nb = 69; memcpy(xb,x, sizeof(x)); InitFoil(); } /** * Sets the properties for the trailing edge flap. * @param bFlap true if a flap is applied to the trailing edge * @param xhinge the relative x-position of the flap's hinge * @param yhinge the relative y-position of the flap's hinge * @param angle the flap angle in degrees */ void Foil::SetTEFlapData(bool bFlap, double xhinge, double yhinge, double angle) { m_bTEFlap = bFlap; m_TEXHinge = xhinge; m_TEYHinge = yhinge; m_TEFlapAngle = angle; } /** * Sets the properties for the leading edge flap. * @param bFlap true if a flap is applied to the leading edge * @param xhinge the relative x-position of the flap's hinge * @param yhinge the relative y-position of the flap's hinge * @param angle the flap angle in degrees */ void Foil::SetLEFlapData(bool bFlap, double xhinge, double yhinge, double angle) { m_bLEFlap = bFlap; m_LEXHinge = xhinge; m_LEYHinge = yhinge; m_LEFlapAngle = angle; } /** * Modifies the geometry of the current foil by setting the leading edge flap. * The specification for the flap is assumed to have been set previously */ void Foil::SetLEFlap() { int i, j, k, l, p, i1, i2; i=j=k=l=p=i1=i2=0; double xh, yh, dx, dy; CVector M; bool bIntersect; double cosa, sina; cosa = cos(m_LEFlapAngle*PI/180.0); sina = sin(m_LEFlapAngle*PI/180.0); //first convert xhinge and yhinge in absolute coordinates xh = m_LEXHinge/100.0; double ymin = GetBaseLowerY(xh); double ymax = GetBaseUpperY(xh); yh = ymin + m_LEYHinge/100.0 * (ymax-ymin); // insert a breakpoint at xhinge location, if there isn't one already int iUpperh = 0; int iLowerh = 0; for (i=0; ixh) { //insert one for(j=m_iExt+1; j>i; j--) { m_rpExtrados[j].x = m_rpExtrados[j-1].x; m_rpExtrados[j].y = m_rpExtrados[j-1].y; } m_rpExtrados[i].x = xh; m_rpExtrados[i].y = ymax; iUpperh = i; m_iExt+=1; break; } } for (i=0; ixh) {//insert one for(j=m_iInt+1; j>i; j--) { m_rpIntrados[j].x = m_rpIntrados[j-1].x; m_rpIntrados[j].y = m_rpIntrados[j-1].y; } m_rpIntrados[i].x = xh; m_rpIntrados[i].y = ymin; iLowerh = i; m_iInt+=1; break; } } // rotate all points upstream of xh if(m_LEFlapAngle>0.0) { //insert an extra point on intrados for (i=m_iInt+1; i>iLowerh; i--) { m_rpIntrados[i] = m_rpIntrados[i-1]; } m_rpIntrados[iLowerh] = m_rpIntrados[iLowerh+1]; iLowerh++; m_iInt++; // extend to infinity last segments around hinge on flap internal side to make sure // they intersect the spline on the other side m_rpIntrados[iLowerh-1].x += 30.0*(m_rpIntrados[iLowerh-1].x-m_rpIntrados[iLowerh-2].x); m_rpIntrados[iLowerh-1].y += 30.0*(m_rpIntrados[iLowerh-1].y-m_rpIntrados[iLowerh-2].y); m_rpIntrados[iLowerh].x += 30.0*(m_rpIntrados[iLowerh].x - m_rpIntrados[iLowerh+1].x); m_rpIntrados[iLowerh].y += 30.0*(m_rpIntrados[iLowerh].y - m_rpIntrados[iLowerh+1].y); } if(m_LEFlapAngle<0.0) { //insert an extra point on extrados for (i=m_iExt+1; i>iUpperh; i--) { m_rpExtrados[i] = m_rpExtrados[i-1]; } m_rpExtrados[iUpperh] = m_rpExtrados[iUpperh+1]; iUpperh++; m_iExt++; // extend to infinity last segments around hinge on flap internal side to make sure // they intersect the spline on the other side m_rpExtrados[iUpperh-1].x += 30.0 * (m_rpExtrados[iUpperh-1].x - m_rpExtrados[iUpperh-2].x); m_rpExtrados[iUpperh-1].y += 30.0 * (m_rpExtrados[iUpperh-1].y - m_rpExtrados[iUpperh-2].y); m_rpExtrados[iUpperh].x += 30.0 * (m_rpExtrados[iUpperh].x - m_rpExtrados[iUpperh+1].x); m_rpExtrados[iUpperh].y += 30.0 * (m_rpExtrados[iUpperh].y - m_rpExtrados[iUpperh+1].y); } for (i=0; i= m_rpIntrados[iLowerh].x) M = (m_rpIntrados[iLowerh-1] + m_rpIntrados[iLowerh])/2.0; LinkSpline.InsertPoint(m_rpIntrados[iLowerh-1].x,m_rpIntrados[iLowerh-1].y); LinkSpline.InsertPoint(M.x, M.y); LinkSpline.InsertPoint(m_rpIntrados[iLowerh].x,m_rpIntrados[iLowerh].y); LinkSpline.SplineKnots(); LinkSpline.SplineCurve(); //retrieve point 1 and 2 and insert them for (i=m_iInt; i>=iLowerh; i--) { m_rpIntrados[i+2].x = m_rpIntrados[i].x; m_rpIntrados[i+2].y = m_rpIntrados[i].y; } m_rpIntrados[iLowerh+1].x = LinkSpline.m_Output[2].x; m_rpIntrados[iLowerh+1].y = LinkSpline.m_Output[2].y; m_rpIntrados[iLowerh].x = LinkSpline.m_Output[1].x; m_rpIntrados[iLowerh].y = LinkSpline.m_Output[1].y; m_iInt+=2; } if(m_LEFlapAngle>0.0) { //define a 3 ctrl-pt spline to smooth the connection between foil and flap on bottom side Intersect(m_rpExtrados[iUpperh-2], m_rpExtrados[iUpperh-1], m_rpExtrados[iUpperh], m_rpExtrados[iUpperh+1], &M); //sanity check if(M.x <= m_rpExtrados[iUpperh-1].x || M.x >= m_rpExtrados[iUpperh].x) M = (m_rpExtrados[iUpperh-1] + m_rpExtrados[iUpperh])/2.0; LinkSpline.InsertPoint(m_rpExtrados[iUpperh-1].x,m_rpExtrados[iUpperh-1].y); LinkSpline.InsertPoint(M.x, M.y); LinkSpline.InsertPoint(m_rpExtrados[iUpperh].x,m_rpExtrados[iUpperh].y); LinkSpline.SplineKnots(); LinkSpline.SplineCurve(); //retrieve point 1 and 2 and insert them for (i=m_iExt; i>=iUpperh; i--) { m_rpExtrados[i+2].x = m_rpExtrados[i].x; m_rpExtrados[i+2].y = m_rpExtrados[i].y; } m_rpExtrados[iUpperh+1].x = LinkSpline.m_Output[2].x; m_rpExtrados[iUpperh+1].y = LinkSpline.m_Output[2].y; m_rpExtrados[iUpperh].x = LinkSpline.m_Output[1].x; m_rpExtrados[iUpperh].y = LinkSpline.m_Output[1].y; m_iExt+=2; } // trim upper surface first i1 = iUpperh; i2 = iUpperh-1; p=0; bIntersect = false; for (j=i2-1; j>0; j--) { for (k=i1;k0; j--) { for (k=i1;kxh) { for(j=m_iExt+1; j>i; j--) { m_rpExtrados[j].x = m_rpExtrados[j-1].x; m_rpExtrados[j].y = m_rpExtrados[j-1].y; } m_rpExtrados[i].x = xh; m_rpExtrados[i].y = ymax; iUpperh = i; m_iExt++; break; } } for (i=0; ixh) { for(j=m_iInt+1; j>i; j--) { m_rpIntrados[j].x = m_rpIntrados[j-1].x; m_rpIntrados[j].y = m_rpIntrados[j-1].y; } m_rpIntrados[i].x = xh; m_rpIntrados[i].y = ymin; iLowerh = i; m_iInt++; break; } } // rotate all points downstream of xh if(m_TEFlapAngle>0.0) { //insert an extra point on intrados for (i=m_iInt+1; i>iLowerh; i--) { m_rpIntrados[i] = m_rpIntrados[i-1]; } m_iInt++; // extend to infinity last segments around hinge on flap internal side to make sure // they intersect the spline on the other side m_rpIntrados[iLowerh+1].x += 30.0*(m_rpIntrados[iLowerh+1].x - m_rpIntrados[iLowerh+2].x); m_rpIntrados[iLowerh+1].y += 30.0*(m_rpIntrados[iLowerh+1].y - m_rpIntrados[iLowerh+2].y); m_rpIntrados[iLowerh].x += 30.0*(m_rpIntrados[iLowerh].x - m_rpIntrados[iLowerh-1].x); m_rpIntrados[iLowerh].y += 30.0*(m_rpIntrados[iLowerh].y - m_rpIntrados[iLowerh-1].y); } if(m_TEFlapAngle<0.0) { //insert an extra point on extrados for (i=m_iExt+1; i>iUpperh; i--) { m_rpExtrados[i] = m_rpExtrados[i-1]; } m_iExt++; // extend to infinity last segments around hinge on flap internal side to make sure // they intersect the spline on the other side m_rpExtrados[iUpperh+1].x += 30.0*(m_rpExtrados[iUpperh+1].x-m_rpExtrados[iUpperh+2].x); m_rpExtrados[iUpperh+1].y += 30.0*(m_rpExtrados[iUpperh+1].y-m_rpExtrados[iUpperh+2].y); m_rpExtrados[iUpperh].x += 30.0 * (m_rpExtrados[iUpperh].x-m_rpExtrados[iUpperh-1].x); m_rpExtrados[iUpperh].y += 30.0 * (m_rpExtrados[iUpperh].y-m_rpExtrados[iUpperh-1].y); } for (i=iUpperh+1; i<=m_iExt; i++) { dx = m_rpExtrados[i].x-xh; dy = m_rpExtrados[i].y-yh; m_rpExtrados[i].x = xh + cosa * dx + sina * dy; m_rpExtrados[i].y = yh - sina * dx + cosa * dy; } for (i=iLowerh+1; i<=m_iInt; i++) { dx = m_rpIntrados[i].x-xh; dy = m_rpIntrados[i].y-yh; m_rpIntrados[i].x = xh + cosa * dx + sina * dy; m_rpIntrados[i].y = yh - sina * dx + cosa * dy; } Spline LinkSpline; LinkSpline.m_iRes = 4; LinkSpline.m_iDegree = 2; LinkSpline.m_CtrlPoint.clear(); if(m_TEFlapAngle<0.0) { //define a 3 ctrl-pt spline to smooth the connection between foil and flap on bottom side Intersect(m_rpIntrados[iLowerh-1], m_rpIntrados[iLowerh], m_rpIntrados[iLowerh+1], m_rpIntrados[iLowerh+2], &M); //sanity check if(M.x <= m_rpIntrados[iLowerh].x || M.x >= m_rpIntrados[iLowerh+1].x) M = (m_rpIntrados[iLowerh] + m_rpIntrados[iLowerh+1])/2.0; LinkSpline.InsertPoint(m_rpIntrados[iLowerh].x,m_rpIntrados[iLowerh].y); LinkSpline.InsertPoint(M.x, M.y); LinkSpline.InsertPoint(m_rpIntrados[iLowerh+1].x,m_rpIntrados[iLowerh+1].y); LinkSpline.SplineKnots(); LinkSpline.SplineCurve(); //retrieve point 1 and 2 and insert them for (i=m_iInt; i>=iLowerh+1; i--) { m_rpIntrados[i+2].x = m_rpIntrados[i].x; m_rpIntrados[i+2].y = m_rpIntrados[i].y; } m_rpIntrados[iLowerh+2].x = LinkSpline.m_Output[2].x; m_rpIntrados[iLowerh+2].y = LinkSpline.m_Output[2].y; m_rpIntrados[iLowerh+1].x = LinkSpline.m_Output[1].x; m_rpIntrados[iLowerh+1].y = LinkSpline.m_Output[1].y; m_iInt+=2; } else if(m_TEFlapAngle>0.0) { //define a 3 ctrl-pt spline to smooth the connection between foil and flap on top side Intersect(m_rpExtrados[iUpperh-1], m_rpExtrados[iUpperh], m_rpExtrados[iUpperh+1], m_rpExtrados[iUpperh+2], &M); //sanity check if(M.x <= m_rpExtrados[iUpperh].x || M.x >= m_rpExtrados[iUpperh+1].x) M = (m_rpExtrados[iUpperh] + m_rpExtrados[iUpperh+1])/2.0; LinkSpline.InsertPoint(m_rpExtrados[iUpperh].x,m_rpExtrados[iUpperh].y); LinkSpline.InsertPoint(M.x, M.y); LinkSpline.InsertPoint(m_rpExtrados[iUpperh+1].x,m_rpExtrados[iUpperh+1].y); LinkSpline.SplineKnots(); LinkSpline.SplineCurve(); //retrieve point 1 and 2 and insert them for (i=m_iExt; i>=iUpperh+1; i--) { m_rpExtrados[i+2].x = m_rpExtrados[i].x; m_rpExtrados[i+2].y = m_rpExtrados[i].y; } m_rpExtrados[iUpperh+2].x = LinkSpline.m_Output[2].x; m_rpExtrados[iUpperh+2].y = LinkSpline.m_Output[2].y; m_rpExtrados[iUpperh+1].x = LinkSpline.m_Output[1].x; m_rpExtrados[iUpperh+1].y = LinkSpline.m_Output[1].y; m_iExt+=2; } // trim upper surface first i1 = iUpperh; i2 = iUpperh+1; p=0; bIntersect = false; k=0; for (j=i2; j0; k--) { if(Intersect(m_rpExtrados[j], m_rpExtrados[j+1], m_rpExtrados[k], m_rpExtrados[k-1], &M)) { bIntersect = true; break; } } if(bIntersect) break; } if(bIntersect) { m_rpExtrados[k] = M; p=1; for (l=j+1;l<=m_iExt; l++) { m_rpExtrados[k+p] = m_rpExtrados[l]; p++; } m_iExt = k+p-1; } // trim lower surface next i1 = iLowerh; i2 = iLowerh+1; p=0; bIntersect = false; for (j=i2; j0; k--) { if(Intersect(m_rpIntrados[j], m_rpIntrados[j+1], m_rpIntrados[k], m_rpIntrados[k-1], &M)) { bIntersect = true; break; } } if(bIntersect) break; } if(bIntersect) { m_rpIntrados[k] = M; p=1; for (l=j+1;l<=m_iInt; l++) { m_rpIntrados[k+p] = m_rpIntrados[l]; p++; } m_iInt = k+p-1; } } /** * Creates the leading and trailing edge flaps on the current geometry. */ void Foil::SetFlap() { int i; // modifies the current airfoil's geometry // by setting a flap i.a.w. the member variables //copy the base foil to the current foil memcpy(m_rpExtrados, m_BaseExtrados, sizeof(m_rpExtrados)); memcpy(m_rpIntrados, m_BaseIntrados, sizeof(m_rpIntrados)); m_iExt = m_iBaseExt; m_iInt = m_iBaseInt; if(m_bLEFlap) SetLEFlap(); if(m_bTEFlap) SetTEFlap(); //And finally rebuild the current foil for (i=m_iExt; i>=0; i--) { x[m_iExt-i] = m_rpExtrados[i].x; y[m_iExt-i] = m_rpExtrados[i].y; } for (i=1; i<=m_iInt; i++) { x[m_iExt+i] = m_rpIntrados[i].x; y[m_iExt+i] = m_rpIntrados[i].y; } n = m_iExt + m_iInt + 1; // InitFoil();//normals are set in InitXFoil() at calculation time } xflr5-6.09-06/src/objects/Foil.h000644 001750 000144 00000017271 12247174403 017564 0ustar00techwinderusers000000 000000 /**************************************************************************** Reference Foil Class Copyright (C) 2003-2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** *@file * * This class defines the foil object used in 2d and 3d calculations * */ #ifndef FOIL_H #define FOIL_H #include #include #include #include "../params.h" #include "CVector.h" #include "CRectangle.h" #include #define MIDPOINTCOUNT 500 /** *@class Foil *@brief * The class which defines the Foil object used in 2D and 3D calculations. The class stores two geometries: - the base foil, which unless advised otherwise is unchanged from the moment it has been first loaded or created - the current foil, on which the geometrical modifications are applied such as flap deflection, camber and thickness scaling @todo One of the very early classes in this project. Would need a general revision. Also it mixes the construction methods and the GUI; would be better to move the GUI to a derived child class for polymorphism. */ class Foil { friend class QAFoil; friend class SplineFoil; friend class Surface; friend class ThreeDWidget; friend class QXDirect; friend class QXInverse; friend class QMiarex; friend class XFoil; friend class OpPoint; friend class FoilPolarDlg; friend class Wing; friend class MainFrame; friend class NacaFoilDlg; friend class FoilCoordDlg; friend class TwoDPanelDlg; friend class InverseOptionsDlg; friend class InterpolateFoilsDlg; friend class FoilGeomDlg; friend class TEGapDlg; friend class LEDlg; friend class FlapDlg; friend class CAddDlg; friend class BatchDlg; friend class BatchThreadDlg; friend class XFoilTask; friend class GL3dWingDlg; friend class WingDlg; friend class FoilSelectionDlg; friend class ManageFoilsDlg; friend class FoilTableDelegate; public: Foil(); void foilName(QString &FoilName); int IsPoint(CVector const &Real); void DrawFoil(QPainter &painter, double const &alpha, double const &scalex, double const &scaley, QPoint const &Offset); void DrawPoints(QPainter &painter, double const &scalex, double const &scaley, QPoint const &Offset); void DrawMidLine(QPainter &painter, double const &scalex, double const &scaley, QPoint const &Offset); void GetLowerY(double x, double &y, double &normx, double &normy); void GetUpperY(double x, double &y, double &normx, double &normy); double DeRotate(); double GetBaseUpperY(double const &x); double GetBaseLowerY(double const &x); double GetMidY(double const &x); double GetLowerY(double x); double GetUpperY(double x); double GetCamber(double const &x); double GetCamberSlope(double const &x); double length(); double GetArea(); double GetTopSlope(double const &x); double GetBotSlope(double const &x); double NormalizeGeometry(); void CompMidLine(bool bParams); bool ExportFoil(QTextStream &out); void InitFoil(); void CopyFoil(Foil *pSrcFoil); bool Serialize(QDataStream &ar, bool bIsStoring); void SetFlap(); void SetTEFlap(); void SetLEFlap(); void SetNaca009(); void SetLEFlapData(bool bFlap, double xhinge, double yhinge, double angle); void SetTEFlapData(bool bFlap, double xhinge, double yhinge, double angle); bool Intersect(CVector const &A, CVector const &B, CVector const &C, CVector const &D, CVector *M); private: QString m_FoilDescription; /**< a free description */ bool m_bVisible; /**< true if the foil is to be displayed */ bool m_bCenterLine; /**< true if the foil mid camber line is to be displayed */ bool m_bPoints; /**< true if the foil's panels are to be displayed */ bool m_bSaved; /**< true if the design modifications have been saved */ int m_iBaseInt; /**< the number of points on the lower surface of the base foil */ int m_iBaseExt; /**< the number of points on the upper surface of the base foil */ int m_iInt; /**< the number of points on the lower surface of the current foil */ int m_iExt; /**< the number of points on the upper surface of the current foil */ int m_nFoilStyle; /**< the index of the style with which to draw the Foil */ int m_nFoilWidth; /**< the width with which to draw the Foil */ QColor m_FoilColor; /**< the color with which to draw the Foil */ int m_iHighLight; /**< the index of the point to highlight in the display */ int n; /**< the number of points of the current foil */ double x[IBX]; /**< the array of x-coordinates of the current foil points */ double y[IBX]; /**< the array of y-coordinates of the current foil points*/ double nx[IBX]; /**< the array of x-coordinates of the current foil normal vectors*/ double ny[IBX]; /**< the array of x-coordinates of the current foil normal vectors*/ // Base geometry; int nb; /**< the number of points of the base foil */ double xb[IBX]; /**< the array of x-coordinates of the base foil points */ double yb[IBX]; /**< the array of y-coordinates of the base foil points*/ double m_fCamber; /**< the Foil's max camber */ double m_fThickness; /**< the Foil's max thickness */ double m_fXCamber; /**< the x-position of the Foil's max camber point */ double m_fXThickness; /**< the x-position of the Foil's max thickness point */ double m_Gap; /**< the trailing edge gap */ CVector m_TE; /**< the trailing edge point */ CVector m_LE; /**< the leading edge point */ CVector m_rpBaseMid[MIDPOINTCOUNT]; /**< the mid camber line points of the base geometry */ CVector m_BaseExtrados[IQX]; /**< the upper surface points of the base geometry */ CVector m_BaseIntrados[IQX]; /**< the lower surface points of the base geometry */ CVector m_rpMid[MIDPOINTCOUNT]; /**< the mid camber line points */ CVector m_rpExtrados[IQX]; /**< the upper surface points */ CVector m_rpIntrados[IQX]; /**< the lower surface points */ public: QString m_FoilName; /**< the foil's name... */ bool m_bTEFlap; /**< true if the foil has a trailing edge flap */ double m_TEFlapAngle; /**< the trailing edge flap angle */ double m_TEXHinge; /**< the x-position of the trailing edge flap, in chord % */ double m_TEYHinge; /**< the y-position of the trailng edge flap, in chord %*/ bool m_bLEFlap; /**< true if the foil has a leading edge flap */ double m_LEFlapAngle; /**< the leading edge flap angle */ double m_LEXHinge; /**< the x-position of the leading edge flap, in chord % */ double m_LEYHinge; /**< the y-position of the leading edge flap, in chord %*/ }; #endif xflr5-6.09-06/src/objects/OpPoint.cpp000644 001750 000144 00000021036 12247174403 020610 0ustar00techwinderusers000000 000000 /**************************************************************************** OpPoint Class Copyright (C) 2003 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "OpPoint.h" #include "../globals.h" #include "../mainframe.h" /** * The public constructor */ OpPoint::OpPoint() { m_bViscResults = false;//not a viscous point a priori m_bBL = false;// no boundary layer surface either m_bTEFlap = false; m_bLEFlap = false; Xtr1 = 0.0; Xtr2 = 0.0; XForce = 0.0; YForce = 0.0; Cpmn = 0.0; m_XCP = 0.0; m_LEHMom = 0.0; m_TEHMom = 0.0; memset(Qi, 0, sizeof(Qi)); memset(Qv, 0, sizeof(Qv)); memset(Cpi, 0, sizeof(Cpi)); memset(Cpv, 0, sizeof(Cpv)); // memset(x, 0, sizeof(x)); // memset(y, 0, sizeof(y)); memset(xd1, 0, sizeof(xd1)); memset(xd2, 0, sizeof(xd2)); memset(xd3, 0, sizeof(xd3)); memset(yd1, 0, sizeof(yd1)); memset(yd2, 0, sizeof(yd2)); memset(yd3, 0, sizeof(yd3)); nd1 = 0; nd2 = 0; nd3 = 0; // Format = 1; m_bIsVisible = true; m_bShowPoints = false; m_Style = 0; m_Width = 1; m_Color = QColor(255,0,100,127); } /** * Loads or saves the data of this OpPoint to a binary file * @param ar the QDataStream object from/to which the data should be serialized * @param bIsStoring true if saving the data, false if loading * @return true if the operation was successful, false otherwise */ bool OpPoint::Serialize(QDataStream &ar, bool bIsStoring, int ArchiveFormat) { int a, b, k, Format; float f,gg; if(bIsStoring) { ar << 100003; //100003 : suppressed archiving of s coordinate //100002 : first numbered archiveformat //write variables WriteCString(ar, m_strFoilName); WriteCString(ar, m_strPlrName); ar << (float)Reynolds << (float)Mach << (float)Alpha; ar << n << nd1 << nd2 << nd3; if(m_bViscResults) a=1; else a=0; if(m_bBL) b=1; else b=0; ar << a << b; ar << (float)Cl << (float)Cm << (float)Cd << (float)Cdp; ar << (float)Xtr1 << (float)Xtr2 << (float)ACrit << (float)m_TEHMom << (float)Cpmn; for (k=0; k=100002) ar>>Format; else Format = 0; //read variables ReadCString(ar, m_strFoilName); ReadCString(ar, m_strPlrName); ar >> f; Reynolds =f; ar >> f; Mach = f; ar >> f; Alpha = f; ar >> n >> nd1 >> nd2 >> nd3; ar >> a >> b; if(a) m_bViscResults = true; else m_bViscResults = false; if(a!=0 && a!=1) return false; if(b) m_bBL = true; else m_bBL = false; if(b!=0 && b!=1) return false; ar >> f; Cl = f; ar >> f; Cm = f; ar >> f; Cd = f; ar >> f; Cdp = f; ar >> f; Xtr1 = f; ar >> f; Xtr2 = f; ar >> f; ACrit =f; ar >> f; m_TEHMom = f; ar >> f; Cpmn = f; for (k=0; k> f; Cpv[k] = f; ar >> f; Cpi[k] = f; } // if (Format ==2) { for (k=0; k> f; //s[k] = f; ar >> f; Qv[k] = f; ar >> f; Qi[k] = f; } // } for (k=0; k<=nd1; k++) { ar >> f >> gg; xd1[k] = f; yd1[k] = gg; } for (k=0; k> f >> gg; xd2[k] = f; yd2[k] = gg; } for (k=0; k> f >> gg; xd3[k] = f; yd3[k] = gg; } if(ArchiveFormat>=100002) { ar>>m_Style>>m_Width; ReadCOLORREF(ar, m_Color); ar >> a ; if(a!=0 && a!=1) return false; if(a) m_bIsVisible = true; else m_bIsVisible = false; ar >> a ; if(a!=0 && a!=1) return false; if(a) m_bShowPoints = true; else m_bShowPoints = false; } } return true; } /** * Exports the data of the polar to a text file * @param out the instance of output QtextStream * @param Version the version name of the program * @param FileType TXT if the data is separated by spaces, CSV for a comma separator * @param bDataOnly true if the analysis parameters should not be output */ void OpPoint::ExportOpp(QTextStream &out, QString Version, enumTextFileType FileType, bool bDataOnly) { int k; QString strong; if(!bDataOnly) { out << Version+"\n"; strong = m_strFoilName + "\n"; out<< strong; strong = m_strPlrName + "\n"; out<< strong; if(FileType==TXT) strong=QString("Alpha = %1, Re = %2, Ma = %3, ACrit =%4 \n\n") .arg(Alpha,5,'f',1).arg(Reynolds,8,'f',0).arg(Mach,6,'f',4).arg(ACrit,4,'f',1); else strong=QString("Alpha =, %1, Re =, %2, Ma =, %3, ACrit =, %4 \n\n") .arg(Alpha,5,'f',1).arg(Reynolds,8,'f',0).arg(Mach,6,'f',4).arg(ACrit,4,'f',1); out<< strong; } if(FileType==TXT) out << " x Cpi Cpv Qi Qv\n"; else out << "x,Cpi,Cpv,Qi,Qv\n"; for (k=0; kx[k],7,'f',4).arg(Cpi[k],7,'f',3).arg(Cpv[k],7,'f',3).arg(Qi[k],7,'f',3).arg(Qv[k],7,'f',3); else strong=QString("%1,%2,%3,%4,%5\n") .arg(MainFrame::curFoil()->x[k],7,'f',4).arg(Cpi[k],7,'f',3).arg(Cpv[k],7,'f',3).arg(Qi[k],7,'f',3).arg(Qv[k],7,'f',3); out<< strong; } out << "\n\n"; } /** * Returns a QString object holding the description and value of the OpPoint's parameters * @param &OpPointProperties the reference of the QString object to be filled with the description * @param bData true if the analysis data should be appended to the string */ void OpPoint::GetOppProperties(QString &OpPointProperties, bool bData) { QString strong; OpPointProperties.clear(); strong = QString(QObject::tr("Re")+" = %1 ").arg(Reynolds,7,'f',0); OpPointProperties += strong +"\n"; strong = QString(QObject::tr("Alpha")+" = %1").arg(Alpha,6,'f',2); OpPointProperties += strong +QString::fromUtf8("°")+"\n"; strong = QString(QObject::tr("Mach")+" = %1 ").arg(Mach,7,'f',3); OpPointProperties += strong + "\n"; strong = QString(QObject::tr("NCrit")+" = %1 ").arg(ACrit,5,'f',1); OpPointProperties += strong + "\n"; strong = QString(QObject::tr("CL")+" = %1 ").arg(Cl,9,'f',5); OpPointProperties += strong + "\n"; strong = QString(QObject::tr("CD")+" = %1 ").arg(Cd,9,'f',5); OpPointProperties += strong + "\n"; strong = QString(QObject::tr("Cm")+" = %1 ").arg(Cm,9,'f',5); OpPointProperties += strong + "\n"; strong = QString(QObject::tr("Cdp")+" = %1 ").arg(Cdp,9,'f',5); OpPointProperties += strong + "\n"; strong = QString(QObject::tr("Cpmn")+" = %1 ").arg(Cpmn,9,'f',5); OpPointProperties += strong + "\n"; strong = QString(QObject::tr("XCP")+" = %1 ").arg(m_XCP,9,'f',5); OpPointProperties += strong + "\n"; strong = QString(QObject::tr("Top Transition")+" = %1 ").arg(Xtr1,9,'f',5); OpPointProperties += strong + "\n"; strong = QString(QObject::tr("Bot Transition")+" = %1 ").arg(Xtr2,9,'f',5); OpPointProperties += strong + "\n"; if(m_bTEFlap) { strong = QString(QObject::tr("T.E. Flap moment")+" = %1 ").arg(m_TEHMom,9,'f',5); OpPointProperties += strong + "\n"; } if(m_bLEFlap) { strong = QString(QObject::tr("L.E. Flap moment")+" = %1 ").arg(m_LEHMom,9,'f',5); OpPointProperties += strong + "\n"; } if(!bData) return; QTextStream out; strong.clear(); out.setString(&strong); ExportOpp(out, MainFrame::versionName(), MainFrame::s_ExportFileType, true); OpPointProperties += "\n"+strong; } xflr5-6.09-06/src/objects/Body.h000644 001750 000144 00000015247 12247174403 017571 0ustar00techwinderusers000000 000000 /**************************************************************************** CBody Class Copyright (C) 2007-2012 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file * This file implements the definition of the Body class. */ #ifndef BODY_H #define BODY_H #include "Panel.h" #include "NURBSSurface.h" #include "PointMass.h" #include #include typedef enum {BODYPANELTYPE, BODYSPLINETYPE } enumBodyLineType; /**< Label for a spline type body */ /** * This class : * - defines the body object, * - provides the methods for the calculation of the plane's geometric properties, * - porvides methods for the panel calculations. * The data is stored in International Standard Units, i.e. meters, kg, and seconds. * Angular data is stored in degrees. */ class Body { public: Body(); bool Gauss(double *A, int n, double *B, int m); bool IsInNURBSBody(CVector Pt); bool Intersect(CVector A, CVector B, CVector &I, bool bRight); bool IntersectPanels(CVector A, CVector B, CVector &I); bool IntersectNURBS(CVector A, CVector B, CVector &I, bool bRight); bool SerializeBody(QDataStream &ar, bool bIsStoring); bool ImportDefinition(QTextStream &inStream, double mtoUnit); bool ExportDefinition(); int InsertFrame(CVector Real); int InsertPoint(CVector Real); int IsFramePos(CVector Real, double ZoomFactor); int RemoveFrame(int n); int ReadFrame(QTextStream &in, int &Line, Frame *pFrame, double const &Unit); double Length(); double Getu(double x); double Getv(double u, CVector r, bool bRight); double GetSectionArcLength(double x); CVector LeadingPoint(); void ClearPointMasses(); void ComputeAero(double *Cp, double &XCP, double &YCP, double &ZCP, double &GCm, double &GRm, double &GYm, double &Alpha, CVector &CoG); void Duplicate(Body *pBody); void ExportGeometry(QTextStream &outStream, int type, double mtoUnit, int nx, int nh); void GetPoint(double u, double v, bool bRight, CVector &Pt); void InsertSideLine(int SideLine); void InterpolateCurve(CVector *D, CVector *P, double *v, double *knots, int degree, int Size); void RemoveActiveFrame(); void RemoveSideLine(int SideLine); void Scale(double XFactor, double YFactor, double ZFactor, bool bFrameOnly=false, int FrameID=0); void Translate(double XTrans, double YTrans, double ZTrans, bool bFrameOnly=false, int FrameID=0); void Translate(CVector T, bool bFrameOnly=false, int FrameID=0); void SetKnots(); void SetPanelPos(); void SetEdgeWeight(double uw, double vw); Frame *getFrame(int k); Frame *activeFrame(); void SetActiveFrame(Frame *pFrame); double FramePosition(int iFrame); int FrameSize() {return m_SplineSurface.FrameSize();} int FramePointCount() {return m_SplineSurface.FramePointCount();} int SideLineCount() {return m_SplineSurface.FramePointCount();}// same as FramePointCount(); void ComputeBodyAxisInertia(); void ComputeVolumeInertia(CVector &CoG, double &CoGIxx, double &CoGIyy, double &CoGIzz, double &CoGIxz); double TotalMass(); //____________________VARIABLES_____________________________________________ static void* s_pMainFrame; /**< a void pointer to the application's MainFrame window */ QString m_BodyName; /**< the Body's name, used as its reference */ QString m_BodyDescription; /**< a free description for the Body */ NURBSSurface m_SplineSurface; /**< the spline surface which defines the left (port) side of the body */ enumBodyLineType m_LineType; /**< the type of body definition 1=lines 2=B-Splines */ int m_iActiveFrame; /**< the currently selected frame for display */ int m_iHighlight; /**< the currently selected point to highlight */ int m_iRes; /**< the number of output points in one direction of the NURBS surface */ int m_NElements; /**< the number of mesh elements for this Body object = m_nxPanels * m_nhPanels *2 */ int m_nxPanels; /**< the number of mesh elements in the direction of the x-axis */ int m_nhPanels; /**< the number of mesh elements in the hoop direction */ int m_BodyStyle; /**< the index of the spline's style */ int m_BodyWidth; /**< the width of the spline */ QColor m_BodyColor; /**< the Body's display color */ double m_Bunch; /**< a bunch parameter to set the density of the points of the NURBS surface; unused */ double m_VolumeMass; /**< the mass of the Body's structure, excluding point masses */ double m_TotalMass; /**< the wing's total mass, i.e. the sum of the volume mass and of the point masses */ QList m_PointMass; /**< the array of PointMass objects */ double m_CoGIxx; /**< the Ixx component of the inertia tensor, calculated at the CoG */ double m_CoGIyy; /**< the Ixx component of the inertia tensor, calculated at the CoG */ double m_CoGIzz; /**< the Ixx component of the inertia tensor, calculated at the CoG */ double m_CoGIxz; /**< the Ixx component of the inertia tensor, calculated at the CoG */ CVector m_CoG; /**< the position of the CoG */ int m_xPanels[MAXBODYFRAMES]; /**< the number of mesh panels between two frames */ int m_hPanels[MAXSIDELINES]; /**< the number of mesh panels in the hoop direction, on one side of the Body */ Panel *m_pBodyPanel; /** A pointer to the first body panel in the array */ //allocate temporary variables to //avoid lengthy memory allocation times on the stack double value, eps, bs, cs; CVector t_R, t_Prod, t_Q, t_r, t_N; // CVector P0, P1, P2, PI; static double s_XPanelPos[300]; }; #endif xflr5-6.09-06/src/objects/WPolar.h000644 001750 000144 00000027140 12247174403 020073 0ustar00techwinderusers000000 000000 /**************************************************************************** WPolar Class Copyright (C) 2005-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /*! \file * * This class defines the polar object for the 3D analysis of wings and planes * */ #ifndef WPOLAR_H #define WPOLAR_H /** *@brief * This class defines the polar object used in 2D and 3D calculations * The class stores both the analysis parameters and the analysis results. Each instance of this class is uniquely associated to an instance of a Wing or a Plane object. The data is stored in International Standard Units, i.e. meters, seconds, kg, and Newtons. Angular data is stored in degrees */ #include "WingOpp.h" #include "PlaneOpp.h" class WPolar { friend class Wing; friend class QMiarex; friend class MainFrame; friend class WPolarDlg; friend class StabPolarDlg; friend class LLTAnalysisDlg; friend class LLTAnalysis; friend class PanelAnalysisDlg; friend class ObjectPropsDlg; friend class StabViewDlg; friend class ManageBodiesDlg; public: WPolar(); void AddPoint(WingOpp* pWOpp); void AddPoint(PlaneOpp* pPOpp); void AddPoint(double alpha, double CL, double ICd, double PCd, double CY, double GCm, double VCm, double ICm, double GRm, double GYm, double IYm, double QInf, double XCP); void CalculatePoint(int i); void Copy(WPolar *pWPolar); void DuplicateSpec(WPolar *pWPolar); void Export(QTextStream &out, enumTextFileType FileType, bool bDataOnly=false); void GetPolarProperties(QString &Properties, bool bData=false); void *GetUFOPlrVariable(int iVar); void Remove(int i); void Remove(double alpha); void ResetWPlr(); void RetrieveInertia(void *ptr, bool bPlane); bool SerializeWPlr(QDataStream &ar, bool bIsStoring); enumAnalysisMethod analysisMethod() {return m_AnalysisMethod;} /**< returns the analysis method of the polar as an index in the enumeration. */ double density() {return m_Density;} /**< returns the fluid's density, in IS units. */ bool pointsVisible() {return m_bShowPoints;} /**< returns true if the polar curve's points should be displayed in the graphs. */ QString polarName() {return m_PlrName;} /**< returns the polar's name as a QString object. */ enumPolarType polarType() {return m_WPolarType;} /**< returns the type of the polar as an index in the enumeration. */ double sideSlip() {return m_Beta;} /**< returns the sideslip angle, in degrees. */ QString UFOName() {return m_UFOName;} /**< returns the name of the polar's parent object as a QString object. */ double viscosity() {return m_Viscosity;} /**< returns the fluid's kinematic viscosity, in IS units. */ bool visible() {return m_bIsVisible;} /**< returns true if the polar curve should be displayed the graphs. */ bool thinSurfaces() {return m_bThinSurfaces;} /**< returns true if the analysis if using thin surfaces, i.e. VLM, false if 3D Panels for the Wing objects. */ static void GetUFOPlrVariableName(int iVar, QString &Name); private: static void* s_pMiarex; /**< a pointer to the unique instance of the application's QMiarex class */ double m_AMem; /**< A variable which stores the last aoa displayed for this polar. Used to display the same aoa when the user switches to another polar */ double m_ASpec; /**< the angle of attack for type 4 polars */ double m_BankAngle; /**< The bank angle */ bool m_bAutoInertia; /**< true if the inertia to be taken into account is the one of the parent plane */ bool m_bDirichlet; /**< true if Dirichlet boundary conditions should be applied, false if Neumann */ double m_Beta; /**< The sideslip angle*/ bool m_bGround; /**< true if ground effect should be taken into account in the analysis */ bool m_bIgnoreBodyPanels; /**< true if the body panels should be ignored in the analysis */ bool m_bIsVisible; /**< true if the polar curve is visible in the graphs */ bool m_bShowPoints; /**< true if the polar points are visible in the graphs */ bool m_bThinSurfaces; /**< true if VLM, false if 3D-panels */ bool m_bTiltedGeom; /**< true if the analysis should be performed on the tilted geometry */ bool m_bViscous; /**< true if the analysis is viscous */ bool m_bWakeRollUp; /**< true if wake roll-up should be taken into account in the analysis */ QColor m_Color; /**< the curve's color for the graphs */ double m_ControlGain[4*MAXCONTROLS]; /**< the scaling factor for each of the control surfaces */ double m_Height; /**< The plane flight altitude, used if ground effect is to be taken into account*/ double m_CoGIxx; /**< The Ixx component of the inertia tensor, w.r.t. the CoG origin */ double m_CoGIxz; /**< The Ixz component of the inertia tensor, w.r.t. the CoG origin */ double m_CoGIyy; /**< The Iyy component of the inertia tensor, w.r.t. the CoG origin */ double m_CoGIzz; /**< The Izz component of the inertia tensor, w.r.t. the CoG origin */ int m_nControls; /**< the number of control surfaces for this wing or plane */ int m_NXWakePanels; /**< the number of wake panels */ double m_QInf; /**< the freestream velocity for type 1 polars */ QString m_PlrName; /**< the polar's name */ int m_PolarFormat; /**< the identification number which references the format used to serialize the data */ int m_RefAreaType; /**< Describes the origin of the refernce area : 1 if planform area, else projected area */ int m_Style; /**< the index of the curve's style for the graphs */ double m_TotalWakeLength; /**< the wake's length */ QString m_UFOName; /**< the name of the parent wing or plane */ double m_Viscosity; /**< The fluid's kinematic viscosity */ double m_WakePanelFactor; /**< the ratio between the length of two wake panels in the x direction */ int m_Width; /**< the curve's width in pixels for the graphs */ QList m_1Cl; /**< 1/Cl, special for Matthieu */ QList m_Alpha; /**< angle of attack */ QList m_Cl32Cd; /**< the power factor */ QList m_ClCd; /**< the glide ratio */ QList m_CL; /**< lift coef. */ QList m_Ctrl; /**< Ctrl variable */ QList m_CY; /**< Side Force */ QList m_DutchRollDamping; /**< the damping of the Dutch roll mode, as a result of stability analysis only */ QList m_DutchRollFrequency; /**< the frequency of the Dutch roll mode, as a result of stability analysis only */ complex m_EigenValue[8][MAXPOLARPOINTS]; /**< until we have a QList> ? */ QList m_FX; /**< the total drag */ QList m_FY; /**< the total side force */ QList m_FZ; /**< the total wing lift */ QList m_Gamma; /**< glide angle = Atan(Cx/Cz), in degrees */ QList m_GCm; /**< Total Pitching Moment coefficient */ QList m_GRm; /**< Total rolling moment */ QList m_GYm; /**< Total yawing moment coefficient */ QList m_ICd; /**< induced drag coef. */ QList m_ICm; /**< Induced Pitching Moment coefficient */ QList m_IYm; /**< induced yawing moment coefficient */ QList m_MaxBending; /**< the max bending moment at the root chord */ QList m_Oswald; /**< Oswald's efficiency factor */ QList m_PCd; /**< profile drag coef. */ QList m_Pm; /**< the total pitching moment */ QList m_PhugoidFrequency; /**< the phugoid's frequency, as a result of stability analysis only */ QList m_PhugoidDamping; /**< the phugoid's damping factor, as a result of stability analysis only */ QList m_QInfinite; /**< the free stream speed - type2 Wpolars */ QList m_RollDamping; /**< the damping of the roll-damping mode, as a result of stability analysis only */ QList m_Rm; /**< the total rolling moment */ QList m_ShortPeriodDamping; /**< the damping of the short period mode, as a result of stability analysis only */ QList m_ShortPeriodFrequency; /**< the frequency of the short period mode, as a result of stability analysis only */ QList m_SM; /**< pseudo Static Margin = (XCP-XCmRef)/m.a.c; */ QList m_SpiralDamping; /**< the damping of the spiral mode, as a result of stability analysis only */ QList m_TCd; /**< total drag coef. */ QList m_VCm; /**< Viscous Pitching Moment coefficient */ QList m_VertPower; /**< the power for steady horizontal flight = m.g.Vz */ QList m_Vx; /**< the horizontal component of the velocity */ QList m_VYm; /**< Profile yawing Moment coefficient */ QList m_Vz; /**< the sink speed = sqrt(2mg/rho/S)/powerfactor */ QList m_XCP; /**< centre of pressure X-position relative to the wing's root LE */ QList m_XNP; /**< the position of the neutral point, as a result of stability analysis only */ QList m_YCP; /**< centre of pressure Y-position relative to the wing's root LE */ QList m_Ym; /**< the total yawing moment */ QList m_ZCP; /**< centre of pressure Z-position relative to the wing's root LE */ public: enumAnalysisMethod m_AnalysisMethod; /**< The method used for the analysis. May be one of the following types : LLTMETHOD, VLMMETHOD, PANELMETHOD */ bool m_bVLM1; /**< true if the analysis is performed with horseshoe vortices, flase if quad rings */ CVector m_CoG; /**< the position of the CoG */ double m_Density; /**< The fluid's density */ double m_Mass; /**< The mass for type 2 and type 7 polars */ double m_WArea; /**< The reference area for the calculation of aero coefficients */ double m_WMAChord; /**< The reference length = the mean aero chord, for the calculation of aero coefficients */ enumPolarType m_WPolarType; /**< The type of analysis. May be one of the following types :FIXEDSPEEDPOLAR, FIXEDLIFTPOLAR, FIXEDAOAPOLAR, STABILITYPOLAR */ double m_WSpan; /**< The reference span for the calculation of aero coefficients */ }; #endif xflr5-6.09-06/src/objects/Body.cpp000644 001750 000144 00000123504 12247174407 020124 0ustar00techwinderusers000000 000000 /**************************************************************************** CBody Class Copyright (C) 2007-2012 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "Body.h" #include "../globals.h" #include "../mainframe.h" #include #include #include void *Body::s_pMainFrame; double Body::s_XPanelPos[300]; /** * The public constructor */ Body::Body() { int i; m_BodyName = QObject::tr("Body Name"); m_BodyColor = QColor(200,228, 216); m_BodyStyle = 0; m_BodyWidth = 1; m_iActiveFrame = 1; m_iHighlight = -1; m_LineType = BODYSPLINETYPE; m_nxPanels = 19; m_nhPanels = 11; m_pBodyPanel = NULL; m_NElements = m_nxPanels * m_nhPanels * 2; m_iRes = 31; // m_BodyLEPosition.Set(0.0,0.0,0.0); m_CoG.Set(0.0,0.0,0.0); m_VolumeMass = m_TotalMass = 0.0; //for inertia calculations m_CoGIxx = m_CoGIyy = m_CoGIzz = m_CoGIxz = 0.0; ClearPointMasses(); m_Bunch = 0.0; eps = 1.0e-06; m_SplineSurface.m_iuDegree = 3; m_SplineSurface.m_ivDegree = 3; #ifdef SAIL7APP m_NSideLines = 4; m_SplineSurface.m_nvLines = m_NSideLines; for(int ifr=0; ifr<4; ifr++) { m_SplineSurface.m_pFrame.append(new CFrame); m_SplineSurface.m_pFrame[ifr]->m_CtrlPoint.clear(); for(int is=0; ism_CtrlPoint.append(CVector(0.0,0.0,0.0)); } } m_SplineSurface.m_nvLines = m_NSideLines; m_SplineSurface.m_pFrame[0]->SetuPosition(-1.0); m_SplineSurface.m_pFrame[1]->SetuPosition( 0.0); m_SplineSurface.m_pFrame[2]->SetuPosition( 3.0); m_SplineSurface.m_pFrame[3]->SetuPosition( 6.0); m_SplineSurface.m_pFrame[0]->m_CtrlPoint[0].Set(-1.0, 0.0, 0.2); m_SplineSurface.m_pFrame[0]->m_CtrlPoint[1].Set(-1.0, 0.0, 0.2); m_SplineSurface.m_pFrame[0]->m_CtrlPoint[2].Set(-1.0, 0.0, 0.2); m_SplineSurface.m_pFrame[0]->m_CtrlPoint[3].Set(-1.0, 0.0, 0.2); m_SplineSurface.m_pFrame[1]->m_CtrlPoint[0].Set(0.0, 0.0, -0.0); m_SplineSurface.m_pFrame[1]->m_CtrlPoint[1].Set(0.0, 2.0, -0.0); m_SplineSurface.m_pFrame[1]->m_CtrlPoint[2].Set(0.0, 0.8, -1.0); m_SplineSurface.m_pFrame[1]->m_CtrlPoint[3].Set(0.0, 0.0, -1.5); m_SplineSurface.m_pFrame[2]->m_CtrlPoint[0].Set(3.0, 0.0, 0.0); m_SplineSurface.m_pFrame[2]->m_CtrlPoint[1].Set(3.0, 1.5, 0.0); m_SplineSurface.m_pFrame[2]->m_CtrlPoint[2].Set(3.0, 0.5,-0.5); m_SplineSurface.m_pFrame[2]->m_CtrlPoint[3].Set(3.0, 0.0,-1.0); m_SplineSurface.m_pFrame[3]->m_CtrlPoint[0].Set(6.0, 0.0, .0); m_SplineSurface.m_pFrame[3]->m_CtrlPoint[1].Set(6.0, 0.0, .0); m_SplineSurface.m_pFrame[3]->m_CtrlPoint[2].Set(6.0, 0.0, .0); m_SplineSurface.m_pFrame[3]->m_CtrlPoint[3].Set(6.0, 0.0, .0); #endif #ifdef XFLR5 // m_NSideLines = 5; // m_SplineSurface.m_nvLines = SideLines(); for(int ifr=0; ifr<7; ifr++) { m_SplineSurface.m_pFrame.append(new Frame); m_SplineSurface.m_pFrame[ifr]->m_CtrlPoint.clear(); for(int is=0; is<5; is++) { m_SplineSurface.m_pFrame[ifr]->m_CtrlPoint.append(CVector(0.0,0.0,0.0)); } } getFrame(0)->SetuPosition(-0.10); getFrame(1)->SetuPosition(-0.0936); getFrame(2)->SetuPosition(-0.0067); getFrame(3)->SetuPosition( 0.0943); getFrame(4)->SetuPosition( 0.242); getFrame(5)->SetuPosition( 0.636); getFrame(6)->SetuPosition( 0.660); getFrame(0)->m_CtrlPoint[0].Set(-0.10, 0.0, -0.0124); getFrame(0)->m_CtrlPoint[1].Set(-0.10, 0.0, -0.0124); getFrame(0)->m_CtrlPoint[2].Set(-0.10, 0.0, -0.0124); getFrame(0)->m_CtrlPoint[3].Set(-0.10, 0.0, -0.0124); getFrame(0)->m_CtrlPoint[4].Set(-0.10, 0.0, -0.0124); getFrame(1)->m_CtrlPoint[0].Set(-0.0936, 0.000, 0.0035); getFrame(1)->m_CtrlPoint[1].Set(-0.0936, 0.011, 0.0003); getFrame(1)->m_CtrlPoint[2].Set(-0.0936, 0.013, -0.0136); getFrame(1)->m_CtrlPoint[3].Set(-0.0936, 0.011, -0.0257); getFrame(1)->m_CtrlPoint[4].Set(-0.0936, 0.000, -0.0266); getFrame(2)->m_CtrlPoint[0].Set(-0.0067, 0.000, 0.0378); getFrame(2)->m_CtrlPoint[1].Set(-0.0067, 0.028, 0.0406); getFrame(2)->m_CtrlPoint[2].Set(-0.0067, 0.037, 0.0016); getFrame(2)->m_CtrlPoint[3].Set(-0.0067, 0.034, -0.0408); getFrame(2)->m_CtrlPoint[4].Set(-0.0067, 0.000, -0.0445); getFrame(3)->m_CtrlPoint[0].Set(0.0943, 0.000, 0.0252); getFrame(3)->m_CtrlPoint[1].Set(0.0943, 0.012, 0.0192); getFrame(3)->m_CtrlPoint[2].Set(0.0943, 0.018, 0.0012); getFrame(3)->m_CtrlPoint[3].Set(0.0943, 0.012, -0.0168); getFrame(3)->m_CtrlPoint[4].Set(0.0943, 0.000, -0.0228); getFrame(4)->m_CtrlPoint[0].Set(0.242, 0.000, 0.0075); getFrame(4)->m_CtrlPoint[1].Set(0.242, 0.006, 0.0090); getFrame(4)->m_CtrlPoint[2].Set(0.242, 0.009, 0.0011); getFrame(4)->m_CtrlPoint[3].Set(0.242, 0.007, -0.0059); getFrame(4)->m_CtrlPoint[4].Set(0.242, 0.000, -0.0051); getFrame(5)->m_CtrlPoint[0].Set(0.636, 0.000, 0.0138); getFrame(5)->m_CtrlPoint[1].Set(0.636, 0.010, 0.0132); getFrame(5)->m_CtrlPoint[2].Set(0.636, 0.012, -0.0001); getFrame(5)->m_CtrlPoint[3].Set(0.636, 0.010, -0.0098); getFrame(5)->m_CtrlPoint[4].Set(0.636, 0.000, -0.0106); getFrame(6)->m_CtrlPoint[0].Set(0.660, 0.00, 0.0); getFrame(6)->m_CtrlPoint[1].Set(0.660, 0.00, 0.0); getFrame(6)->m_CtrlPoint[2].Set(0.660, 0.00, 0.0); getFrame(6)->m_CtrlPoint[3].Set(0.660, 0.00, -0.0); getFrame(6)->m_CtrlPoint[4].Set(0.660, 0.00, -0.0); #endif SetKnots(); // ComputeCenterLine(); for(i=0; im_BodyName; m_BodyColor = pBody->m_BodyColor; m_nxPanels = pBody->m_nxPanels; m_nhPanels = pBody->m_nhPanels; m_LineType = pBody->m_LineType; m_BodyDescription = pBody->m_BodyDescription; m_SplineSurface.ClearFrames(); for(int i=0; iFrameSize(); i++) { m_SplineSurface.m_pFrame.append(new Frame); m_SplineSurface.m_pFrame[i]->CopyFrame(pBody->m_SplineSurface.m_pFrame[i]); m_xPanels[i] = pBody->m_xPanels[i]; } SetKnots(); for(int i=0; im_hPanels[i]; } ClearPointMasses(); for(int im=0; imm_PointMass.size(); im++) { m_PointMass.append(new PointMass(pBody->m_PointMass.at(im))); } m_VolumeMass = pBody->m_VolumeMass; } bool Body::ExportDefinition() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; int i, j; QString strong, FileName; FileName = m_BodyName; FileName.replace("/", " "); FileName = QFileDialog::getSaveFileName(pMainFrame, QObject::tr("Export Body Definition"), MainFrame::s_LastDirName, QObject::tr("Text Format (*.txt)")); if(!FileName.length()) return false; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return false; QTextStream outStream(&XFile); strong = "\n# This file defines a body geometry\n"; outStream << strong; strong = "# The frames are defined from nose to tail\n"; outStream << strong; strong = "# The numer of sidelines is defined by the number of points of the first frame\n"; outStream << strong; strong = "# Each of the next frames should have the same number of points as the first\n"; outStream << strong; strong = QString("# The maximum number of sidelines is %1\n").arg(MAXSIDELINES); outStream << strong; strong = QString("# The maximum number of frames is %1\n").arg(MAXBODYFRAMES); outStream << strong; strong = "# For each frame, the points are defined for the right half of the body, \n"; outStream << strong; strong = "# in the clockwise direction aft looking forward\n\n"; outStream << strong; outStream << (m_BodyName+"\n\n"); outStream << ("BODYTYPE\n"); if(m_LineType==BODYPANELTYPE) outStream << (" 1 # Flat Panels (1) or NURBS (2)\n\n"); if(m_LineType==BODYSPLINETYPE) outStream << (" 2 # Flat Panels (1) or NURBS (2)\n\n"); outStream << ("OFFSET\n"); outStream << ("0.0 0.0 0.0 #Total body offset (Y-coord is ignored)\n\n"); for(i=0; im_Position.x * MainFrame::s_mtoUnit,14,'f',7) .arg(m_SplineSurface.m_pFrame[i]->m_CtrlPoint[j].y * MainFrame::s_mtoUnit,14,'f',7) .arg(m_SplineSurface.m_pFrame[i]->m_CtrlPoint[j].z * MainFrame::s_mtoUnit,14,'f',7); outStream << (strong); } outStream << ("\n"); } return true; } void Body::ExportGeometry(QTextStream &outStream, int type, double mtoUnit, int nx, int nh) { QString strong, LengthUnit,str; int k,l; double u, v; CVector Point; if(type==1) str=""; else str=", "; outStream << (m_BodyName); outStream << ("\n\n"); outStream << (("Right Surface Points\n")); if(type==1) strong = " x("+LengthUnit+") y("+LengthUnit+") z("+LengthUnit+")\n"; else strong = " x("+LengthUnit+"),"+"y("+LengthUnit+"),"+"z("+LengthUnit+")\n"; outStream << (strong); for (k=0; k max) { max = dum; A_pivot_row = pA; pivot_row = i; } if (max <= 0.0) return false; // the matrix A is singular // and if it differs from the current row, interchange the two rows. if (pivot_row != row) { for (i = row; i < n; i++) { dum = *(pa + i); *(pa + i) = *(A_pivot_row + i); *(A_pivot_row + i) = dum; } for(k=0; k<=m; k++){ dum = B[row+k*n]; B[row+k*n] = B[pivot_row+k*n]; B[pivot_row+k*n] = dum; } } // Perform forward substitution for (i = row+1; i= 0; pa -= n, row--) { if ( *(pa + row) == 0.0 ) return false; // matrix is singular dum = 1.0 / *(pa + row); for ( i = row + 1; i < n; i++) *(pa + i) *= dum; for(k=0; k<=m; k++) B[row+k*n] *= dum; for ( i = 0, pA = A; i < row; pA += n, i++) { dum = *(pA + row); for ( j = row + 1; j < n; j++) *(pA + j) -= dum * *(pa + j); for(k=0; k<=m; k++) B[i+k*n] -= dum * B[row+k*n]; } } return true; } double Body::Length() { return qAbs(m_SplineSurface.m_pFrame.last()->m_Position.x - m_SplineSurface.m_pFrame.first()->m_Position.x); } CVector Body::LeadingPoint() { return CVector(m_SplineSurface.m_pFrame[0]->m_Position.x, 0.0, (m_SplineSurface.m_pFrame[0]->m_CtrlPoint.first().z + m_SplineSurface.m_pFrame[0]->m_CtrlPoint.last().z)/2.0 ); } double Body::GetSectionArcLength(double x) { //NURBS only if(m_LineType==BODYPANELTYPE) return 0.0; // aproximate arc length, used for inertia estimations double length = 0.0; double ux = Getu(x); CVector Pt, Pt1; GetPoint(ux, 0.0, true, Pt1); int NPoints = 10;//why not ? for(int i=1; i<=NPoints; i++) { GetPoint(ux, (double)i/(double)NPoints, true, Pt); length += sqrt((Pt.y-Pt1.y)*(Pt.y-Pt1.y) + (Pt.z-Pt1.z)*(Pt.z-Pt1.z)); Pt1.y = Pt.y; Pt1.z = Pt.z; } return length*2.0; //to account for left side. } void Body::GetPoint(double u, double v, bool bRight, CVector &Pt) { m_SplineSurface.GetPoint(u, v, Pt); if(!bRight) Pt.y = -Pt.y; } double Body::Getu(double x) { return m_SplineSurface.Getu(x,0.0); } double Body::Getv(double u, CVector r, bool bRight) { double sine = 10000.0; if(u<=0.0) return 0.0; if(u>=1.0) return 0.0; if(r.VAbs()<1.0e-5) return 0.0; int iter=0; double v, v1, v2; r.Normalize(); v1 = 0.0; v2 = 1.0; while(qAbs(sine)>1.0e-4 && iter<200) { v=(v1+v2)/2.0; GetPoint(u, v, bRight, t_R); t_R.x = 0.0; t_R.Normalize();//t_R is the unit radial vector for u,v sine = (r.y*t_R.z - r.z*t_R.y); if(bRight) { if(sine>0.0) v1 = v; else v2 = v; } else { if(sine>0.0) v2 = v; else v1 = v; } iter++; } return (v1+v2)/2.0; } bool Body::ImportDefinition(QTextStream &inStream, double mtoUnit) { int res, i, j, Line, NSideLines; QString strong; bool bRead, bOK; QByteArray textline; const char *text; double xo,yo,zo; xo = yo = zo = 0.0; Line = 0; bRead = ReadAVLString(inStream, Line, strong); m_BodyName = strong.trimmed(); m_SplineSurface.ClearFrames(); //Header data bRead = true; while (bRead) { bRead = ReadAVLString(inStream, Line, strong); if(!bRead) break; if (strong.indexOf("BODYTYPE") >=0) { bRead = ReadAVLString(inStream, Line, strong); if(!bRead) break; res = strong.toInt(&bOK); if(bOK) { if(res==1) m_LineType = BODYPANELTYPE; else m_LineType = BODYSPLINETYPE; } } else if (strong.indexOf("OFFSET") >=0) { bRead = ReadAVLString(inStream, Line, strong); if(!bRead) break; textline = strong.toLatin1(); text = textline.constData(); res = sscanf(text, "%lf %lf %lf", &xo, &yo, &zo); if(res==3) { xo /= mtoUnit; zo /= mtoUnit; } //y0 is ignored, body is assumed centered along x-z plane } else if (strong.indexOf("FRAME", 0) >=0) { Frame *pNewFrame = new Frame; NSideLines = ReadFrame(inStream, Line, pNewFrame, mtoUnit); if (NSideLines) { m_SplineSurface.InsertFrame(pNewFrame); } } } for(i=1; im_CtrlPoint.size() != m_SplineSurface.m_pFrame[i-1]->m_CtrlPoint.size()) { QString strong = QObject::tr("Error reading ")+m_BodyName+QObject::tr("\nFrames have different number of side points"); // QMessageBox::warning(window(), QObject::tr("Error"),strong); //TODO return false; } } for(i=0; im_Position.x = m_SplineSurface.m_pFrame[i]->m_CtrlPoint[0].x + xo; for(j=0; jm_CtrlPoint[j].z += zo; } } m_SplineSurface.SetKnots(); return true; } void Body::InsertSideLine(int SideLine) { if(SideLine==0) SideLine++; for (int i=0; iInsertPoint(SideLine); } SetKnots(); } int Body::InsertPoint(CVector Real) { //Real is to be inserted in the current frame if(m_iActiveFrame<0) { QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setWindowTitle(QObject::tr("Warning")); msgBox.setText(QObject::tr("Please select a Frame before inserting a point")); msgBox.exec(); return -1; } int i, n; n = (m_SplineSurface.m_pFrame[m_iActiveFrame])->InsertPoint(Real, 3); for (i=0; iInsertPoint(n); } } SetKnots(); return n; } int Body::InsertFrame(CVector Real) { int k, n=0; if(Real.xm_Position.x) { m_SplineSurface.m_pFrame.prepend(new Frame(SideLineCount())); for (k=0; km_CtrlPoint[k].Set(0.0,0.0,Real.z); } m_SplineSurface.m_pFrame.first()->SetuPosition(Real.x); } else if(Real.x>m_SplineSurface.m_pFrame.last()->m_Position.x) { m_SplineSurface.m_pFrame.append(new Frame(SideLineCount())); for (k=0; km_CtrlPoint[k].Set(0.0,0.0,Real.z); } m_SplineSurface.m_pFrame.last()->SetuPosition(Real.x); } else { for (n=0; nm_Position.x<=Real.x && Real.xm_Position.x) { m_SplineSurface.m_pFrame.insert(n+1, new Frame(SideLineCount())); for (k=0; km_CtrlPoint[k].x = (m_SplineSurface.m_pFrame[n]->m_CtrlPoint[k].x + m_SplineSurface.m_pFrame[n+2]->m_CtrlPoint[k].x)/2.0; m_SplineSurface.m_pFrame[n+1]->m_CtrlPoint[k].y = (m_SplineSurface.m_pFrame[n]->m_CtrlPoint[k].y + m_SplineSurface.m_pFrame[n+2]->m_CtrlPoint[k].y)/2.0; m_SplineSurface.m_pFrame[n+1]->m_CtrlPoint[k].z = (m_SplineSurface.m_pFrame[n]->m_CtrlPoint[k].z + m_SplineSurface.m_pFrame[n+2]->m_CtrlPoint[k].z)/2.0; } break; } } if(n+1SetuPosition(Real.x); double trans = Real.z - (m_SplineSurface.m_pFrame[n+1]->m_CtrlPoint[0].z + m_SplineSurface.m_pFrame[n+1]->m_CtrlPoint.last().z)/2.0; for (k=0; km_CtrlPoint[k].z += trans; } } } m_iActiveFrame = n+1; if(n>=FrameSize()) m_iActiveFrame = FrameSize(); if(n<=0) m_iActiveFrame = 0; m_iHighlight = -1; SetKnots(); return n+1; } void Body::InterpolateCurve(CVector *D, CVector *P, double *v, double *knots, int degree, int Size) { int i,j; double Nij[MAXBODYFRAMES* MAXBODYFRAMES];//MAXBODYFRAMES is greater than MAXSIDELINES double RHS[3 * MAXBODYFRAMES];//x, y and z RHS //create the matrix for(i=0; i=0.0) bRight = true; else bRight = false; if(!IsInNURBSBody(M1)) { //consider no intersection (not quite true in special high dihedral cases) I = M1; return false; } I = (M0+M1)/2.0; t=0.5; while(dist>dmax && iterm_Position.x ; LB.y = m_SplineSurface.m_pFrame[i]->m_CtrlPoint[k].y ; LB.z = m_SplineSurface.m_pFrame[i]->m_CtrlPoint[k].z ; TB.x = m_SplineSurface.m_pFrame[i+1]->m_Position.x; TB.y = m_SplineSurface.m_pFrame[i+1]->m_CtrlPoint[k].y; TB.z = m_SplineSurface.m_pFrame[i+1]->m_CtrlPoint[k].z; LA.x = m_SplineSurface.m_pFrame[i]->m_Position.x ; LA.y = m_SplineSurface.m_pFrame[i]->m_CtrlPoint[k+1].y; LA.z = m_SplineSurface.m_pFrame[i]->m_CtrlPoint[k+1].z; TA.x = m_SplineSurface.m_pFrame[i+1]->m_Position.x; TA.y = m_SplineSurface.m_pFrame[i+1]->m_CtrlPoint[k+1].y; TA.z = m_SplineSurface.m_pFrame[i+1]->m_CtrlPoint[k+1].z; //does it intersect the right panel ? C = (LA + LB + TA + TB)/4.0; D1 = LA - TB; D2 = LB - TA; N = D2 * D1; N.Normalize(); r = (C.x-A.x)*N.x + (C.y-A.y)*N.y + (C.z-A.z)*N.z ; s = (U.x*N.x + U.y*N.y + U.z*N.z); if(qAbs(s)>0.0) { t = r/s; P = A + U * t; // P is inside panel if on left side of each panel side W = P - TA; V = TB - TA; t_Prod = V*W; if(t_Prod.VAbs() <1.0e-4 || t_Prod.dot(N)>=0.0) b1 = true; else b1 = false; W = P - TB; V = LB - TB; t_Prod = V*W; if(t_Prod.VAbs() <1.0e-4 || t_Prod.dot(N)>=0.0) b2 = true; else b2 = false; W = P - LB; V = LA - LB; t_Prod = V*W; if(t_Prod.VAbs() <1.0e-4 || t_Prod.dot(N)>=0.0) b3 = true; else b3 = false; W = P - LA; V = TA - LA; t_Prod = V*W; if(t_Prod.VAbs() <1.0e-4 || t_Prod.dot(N)>=0.0) b4 = true; else b4 = false; W = A-P; V = B-P; if(W.dot(V)<=0.0) b5 = true; else b5 = false; if(b1 && b2 && b3 && b4 && b5) { bIntersect = true; break; } } //does it intersect the left panel ? LB.y = -LB.y; LA.y = -LA.y; TB.y = -TB.y; TA.y = -TA.y; C = (LA + LB + TA + TB)/4.0; D1 = LA - TB; D2 = LB - TA; N = D2 * D1; N.Normalize(); r = (C.x-A.x)*N.x + (C.y-A.y)*N.y + (C.z-A.z)*N.z ; s = (U.x*N.x + U.y*N.y + U.z*N.z); if(qAbs(s)>0.0) { t = r/s; P = A + U * t; // P is inside panel if on left side of each panel side W = P - TA; V = TB - TA; t_Prod = V*W; if(t_Prod.VAbs() <1.0e-4 || t_Prod.dot(N)>=0.0) b1 = true; else b1 = false; W = P - TB; V = LB - TB; t_Prod = V*W; if(t_Prod.VAbs() <1.0e-4 || t_Prod.dot(N)>=0.0) b2 = true; else b2 = false; W = P - LB; V = LA - LB; t_Prod = V*W; if(t_Prod.VAbs() <1.0e-4 || t_Prod.dot(N)>=0.0) b3 = true; else b3 = false; W = P - LA; V = TA - LA; t_Prod = V*W; if(t_Prod.VAbs() <1.0e-4 || t_Prod.dot(N)>=0.0) b4 = true; else b4 = false; W = A-P; V = B-P; if(W.dot(V)<=0.0) b5 = true; else b5 = false; if(b1 && b2 && b3 && b4 && b5) { bIntersect = true; break; } } } if(bIntersect) break; } if(bIntersect) I = P; return bIntersect; } int Body::IsFramePos(CVector Real, double ZoomFactor) { int k; for (k=0; km_Position.x) < 0.01 *Length()/ZoomFactor && qAbs(Real.y-m_SplineSurface.m_pFrame[k]->zPos()) < 0.01 *Length()/ZoomFactor) return k; } return -10; } bool Body::IsInNURBSBody(CVector Pt) { double u, v; bool bRight; u = Getu(Pt.x); if (u <= 0.0 || u >= 1.0) return false; t_r.Set(0.0, Pt.y, Pt.z); bRight = (Pt.y>=0.0); v = Getv(u, t_r, bRight); GetPoint(u, v, bRight, t_N); t_N.x = 0.0; if(t_r.VAbs()>t_N.VAbs()) return false; return true; } int Body::ReadFrame(QTextStream &in, int &Line, Frame *pFrame, double const &Unit) { double x,y,z; QString strong; int i, res; i = 0; x=y=z=0.0; bool bRead =true; pFrame->m_CtrlPoint.clear(); while (bRead) { if(!ReadAVLString(in, Line, strong)) bRead = false; ReadValues(strong, res, x,y,z); if(res!=3) { bRead = false; Rewind1Line(in, Line, strong); } else { pFrame->m_CtrlPoint.append(CVector(x/Unit, y/Unit, z/Unit)); i++; } if(i>=MAXSIDELINES) { bRead = false; } } if(pFrame->m_CtrlPoint.size()) pFrame->m_Position.x = pFrame->m_CtrlPoint.first().x; return i; } int Body::RemoveFrame(int n) { m_SplineSurface.m_pFrame.removeAt(n); m_iActiveFrame = qMin(n, m_SplineSurface.m_pFrame.size()); m_iHighlight = -1; SetKnots(); return m_iActiveFrame; } void Body::RemoveActiveFrame() { m_SplineSurface.RemoveFrame(m_iActiveFrame); m_iHighlight = -1; SetKnots(); } void Body::RemoveSideLine(int SideLine) { for (int i=0; iRemovePoint(SideLine); } SetKnots(); } void Body::Scale(double XFactor, double YFactor, double ZFactor, bool bFrameOnly, int FrameID) { int i,j; for (i=0; im_Position.x *= XFactor; for(j=0; jm_CtrlPoint.size(); j++) { m_SplineSurface.m_pFrame[i]->m_CtrlPoint[j].x = m_SplineSurface.m_pFrame[i]->m_Position.x; m_SplineSurface.m_pFrame[i]->m_CtrlPoint[j].y *= YFactor; m_SplineSurface.m_pFrame[i]->m_CtrlPoint[j].z *= ZFactor; } } } // ComputeCenterLine(); } bool Body::SerializeBody(QDataStream &ar, bool bIsStoring) { int ArchiveFormat; int i,k, nStations; float f,g,h; double x,y,z; if(bIsStoring) { ar << 1006; //1006 : added body LEPosition //1005 : added body alpha color + provisions //1004 : QFLRv0.03 : added mass properties for inertia calculations //1003 : QFLR5 v0.02 : added body description field //1002 : Added axial and hoop mesh panel numbers for linetype fuselage //1001 : Added bunching parameter //1000 : first format WriteCString(ar, m_BodyName); WriteCString(ar, m_BodyDescription); WriteCOLORREF(ar, m_BodyColor); if(m_LineType==BODYPANELTYPE) ar << 1; else ar << 2; ar << SideLineCount(); ar << FrameSize(); ar << m_iRes; ar << 3 << 3;// ar << m_nxDegree << m_nhDegree; ar << m_nxPanels << m_nhPanels; ar << (float)m_Bunch; for(k=0; kSerializeFrame(ar, bIsStoring); } ar << 0;//ar << m_NStations; again ? for (k=0; kmass(); for(i=0; iposition().x << (float)m_PointMass[i]->position().y << (float)m_PointMass[i]->position().z; for(i=0; itag()); ar << (float)m_BodyColor.alphaF(); // ar << m_BodyLEPosition.x<< m_BodyLEPosition.y<< m_BodyLEPosition.z; ar << 0.0 << 0.0 << 0.0; ar << 0.0f; } else { int NSideLines; ar >> ArchiveFormat; if(ArchiveFormat<1000 || ArchiveFormat>1100) return false; ReadCString(ar, m_BodyName); if(ArchiveFormat>=1003) ReadCString(ar, m_BodyDescription); ReadCOLORREF(ar, m_BodyColor); ar >> k; if(k==1) m_LineType = BODYPANELTYPE; else m_LineType = BODYSPLINETYPE; ar >> NSideLines; ar >> nStations; ar >> m_iRes; ar >> k >> k; //ar >> m_nxDegree >> m_nhDegree; ar >> m_nxPanels >> m_nhPanels; if(ArchiveFormat>=1001) { ar >> f; m_Bunch = f; } if(ArchiveFormat>=1002) { for(k=0; k> m_xPanels[k]; for(k=0; k> m_hPanels[k]; } ar >> k; // m_bClosedSurface if(k!=0 && k!=1) return false; m_SplineSurface.ClearFrames(); for(k=0; kSerializeFrame(ar, bIsStoring); } //Serialize Bodyline ar >>k;// ar >> m_NStations; again ? for (k=0; k> f; m_SplineSurface.m_pFrame[k]->SetuPosition(f); for(int ic=0; icm_CtrlPoint.size(); ic++) { m_SplineSurface.m_pFrame[k]->m_CtrlPoint[ic].x = f; } ar >> f; //m_FramePosition[k].z =f; } if(ArchiveFormat>=1004) { ar >> f; m_VolumeMass = f; int nMass; ar >> nMass; QVarLengthArray mass; QVarLengthArray position; QVarLengthArray tag; for(int im=0; im> f; mass.append(f); } for(int im=0; im> f >> g >> h; position.append(CVector(f,g,h)); } for(int im=0; im> f; if(ArchiveFormat>=1005) m_BodyColor.setAlphaF(f); if(ArchiveFormat>=1006) { ar >> x >> y >> z; // m_BodyLEPosition.Set(x,y,z); } // else m_BodyLEPosition.Set(0.0,0.0,0.0); ar >> f; SetKnots(); } return true; } void Body::SetPanelPos() { int i; /* for(i=0; i<=m_nxPanels; i++) { s_XPanelPos[i] =(double)i/(double)m_nxPanels; } return;*/ double y, x; double a = (m_Bunch+1.0)*.48 ; a = 1./(1.0-a); double norm = 1/(1+exp(0.5*a)); for(i=0; i<=m_nxPanels; i++) { x = (double)(i)/(double)m_nxPanels; y = 1.0/(1.0+exp((0.5-x)*a)); s_XPanelPos[i] =0.5-((0.5-y)/(0.5-norm))/2.0; } } void Body::Translate(double XTrans, double YTrans, double ZTrans, bool bFrameOnly, int FrameID) { int i,j; for (i=0; im_Position.x += XTrans; // m_SplineSurface.m_pFrame[i]->m_Position.y += YTrans; // m_SplineSurface.m_pFrame[i]->m_Position.z += ZTrans; for(j=0; jm_CtrlPoint.size(); j++) { m_SplineSurface.m_pFrame[i]->m_CtrlPoint[j].x += XTrans; m_SplineSurface.m_pFrame[i]->m_CtrlPoint[j].z += ZTrans; } } } // ComputeCenterLine(); } void Body::Translate(CVector T, bool bFrameOnly, int FrameID) { Translate(T.x, T.y, T.z, bFrameOnly, FrameID); } Frame *Body::getFrame(int k) { if(k>=0 && km_Position.x; } Frame *Body::activeFrame() { if(m_iActiveFrame>=0 && m_iActiveFramemass(); m_CoG += m_PointMass[i]->position() * m_PointMass[i]->mass(); } if(m_TotalMass>0) m_CoG = m_CoG/m_TotalMass; else m_CoG.Set(0.0,0.0,0.0); // The CoG position is now available, so calculate the inertia w.r.t the CoG // using Huyghens theorem //LA is the displacement vector from the centre of mass to the new axis LA = m_CoG-VolumeCoG; m_CoGIxx = Ixx + m_VolumeMass * (LA.y*LA.y + LA.z*LA.z); m_CoGIyy = Iyy + m_VolumeMass * (LA.x*LA.x + LA.z*LA.z); m_CoGIzz = Izz + m_VolumeMass * (LA.x*LA.x + LA.y*LA.y); m_CoGIxz = Ixz + m_VolumeMass * LA.x*LA.z; for(i=0; iposition() - m_CoG; m_CoGIxx += m_PointMass[i]->mass() * (LA.y*LA.y + LA.z*LA.z); m_CoGIyy += m_PointMass[i]->mass() * (LA.x*LA.x + LA.z*LA.z); m_CoGIzz += m_PointMass[i]->mass() * (LA.x*LA.x + LA.y*LA.y); m_CoGIxz -= m_PointMass[i]->mass() * (LA.x*LA.z); } } void Body::ComputeVolumeInertia(CVector &CoG, double &CoGIxx, double &CoGIyy, double &CoGIzz, double &CoGIxz) { // Assume that the mass is distributed homogeneously in the body's skin // Homogeneity is questionable, but is a rather handy assumption // Mass in the body's skin is reasonable, given that the point masses // are added manually //evaluate roughly the Body's wetted area int i,j,k; double ux, rho; double dj, dj1; CVector Pt, LATB, TALB, N, PLA, PTA, PLB, PTB, Top, Bot; double BodyArea = 0.0; double SectionArea; double xpos, dl; CoG.Set(0.0, 0.0, 0.0); CoGIxx = CoGIyy = CoGIzz = CoGIxz = 0.0; if(m_LineType==BODYPANELTYPE) { // we use the panel division //first get the wetted area for (i=0; im_CtrlPoint[k].y ; PLA.z = getFrame(i)->m_CtrlPoint[k].z ; PLB.x = FramePosition(i); PLB.y = getFrame(i)->m_CtrlPoint[k+1].y ; PLB.z = getFrame(i)->m_CtrlPoint[k+1].z ; PTA.x = FramePosition(i+1); PTA.y = getFrame(i+1)->m_CtrlPoint[k].y ; PTA.z = getFrame(i+1)->m_CtrlPoint[k].z ; PTB.x = FramePosition(i+1); PTB.y = getFrame(i+1)->m_CtrlPoint[k+1].y; PTB.z = getFrame(i+1)->m_CtrlPoint[k+1].z; LATB = PTB - PLA; TALB = PLB - PTA; N = TALB * LATB;//panel area x2 BodyArea += N.VAbs() /2.0; } } BodyArea *= 2.0; rho = m_VolumeMass/BodyArea; //First get the CoG position for (i=0; im_CtrlPoint[k].y + dj * getFrame(i+1)->m_CtrlPoint[k].y; PLB.z = (1.0- dj) * getFrame(i)->m_CtrlPoint[k].z + dj * getFrame(i+1)->m_CtrlPoint[k].z; PTB.y = (1.0-dj1) * getFrame(i)->m_CtrlPoint[k].y + dj1 * getFrame(i+1)->m_CtrlPoint[k].y; PTB.z = (1.0-dj1) * getFrame(i)->m_CtrlPoint[k].z + dj1 * getFrame(i+1)->m_CtrlPoint[k].z; PLA.y = (1.0- dj) * getFrame(i)->m_CtrlPoint[k+1].y + dj * getFrame(i+1)->m_CtrlPoint[k+1].y; PLA.z = (1.0- dj) * getFrame(i)->m_CtrlPoint[k+1].z + dj * getFrame(i+1)->m_CtrlPoint[k+1].z; PTA.y = (1.0-dj1) * getFrame(i)->m_CtrlPoint[k+1].y + dj1 * getFrame(i+1)->m_CtrlPoint[k+1].y; PTA.z = (1.0-dj1) * getFrame(i)->m_CtrlPoint[k+1].z + dj1 * getFrame(i+1)->m_CtrlPoint[k+1].z; LATB = PTB - PLA; TALB = PLB - PTA; N = TALB * LATB;//panel area x2 SectionArea += N.VAbs() /2.0; } SectionArea *= 2.0;// to account for right side; // get center point for this section Pt.x = (PLA.x + PTA.x)/2.0; Pt.y = 0.0; Pt.z = ((1.0-dj) * m_SplineSurface.m_pFrame[i]->zPos() + dj * m_SplineSurface.m_pFrame[i+1]->zPos() +(1.0-dj1) * m_SplineSurface.m_pFrame[i]->zPos() + dj1 * m_SplineSurface.m_pFrame[i+1]->zPos())/2.0; CoG.x += SectionArea*rho * Pt.x; CoG.y += SectionArea*rho * Pt.y; CoG.z += SectionArea*rho * Pt.z; } } if(m_VolumeMass>PRECISION) CoG *= 1.0/ m_VolumeMass; else CoG.Set(0.0, 0.0, 0.0); //Then Get Inertias // we could do it one calculation, for CG and inertia, by using Hyghens/steiner theorem for (i=0; im_CtrlPoint[k].y + dj * getFrame(i+1)->m_CtrlPoint[k].y; PLB.z = (1.0- dj) * getFrame(i)->m_CtrlPoint[k].z + dj * getFrame(i+1)->m_CtrlPoint[k].z; PTB.y = (1.0-dj1) * getFrame(i)->m_CtrlPoint[k].y + dj1 * getFrame(i+1)->m_CtrlPoint[k].y; PTB.z = (1.0-dj1) * getFrame(i)->m_CtrlPoint[k].z + dj1 * getFrame(i+1)->m_CtrlPoint[k].z; PLA.y = (1.0- dj) * getFrame(i)->m_CtrlPoint[k+1].y + dj * getFrame(i+1)->m_CtrlPoint[k+1].y; PLA.z = (1.0- dj) * getFrame(i)->m_CtrlPoint[k+1].z + dj * getFrame(i+1)->m_CtrlPoint[k+1].z; PTA.y = (1.0-dj1) * getFrame(i)->m_CtrlPoint[k+1].y + dj1 * getFrame(i+1)->m_CtrlPoint[k+1].y; PTA.z = (1.0-dj1) * getFrame(i)->m_CtrlPoint[k+1].z + dj1 * getFrame(i+1)->m_CtrlPoint[k+1].z; LATB = PTB - PLA; TALB = PLB - PTA; N = TALB * LATB;//panel area x2 SectionArea += N.VAbs() /2.0; } SectionArea *= 2.0;// to account for right side; // get center point for this section Pt.x = (PLA.x + PTA.x)/2.0; Pt.y = 0.0; Pt.z = ((1.0-dj) * m_SplineSurface.m_pFrame[i]->zPos() + dj * m_SplineSurface.m_pFrame[i+1]->zPos() +(1.0-dj1) * m_SplineSurface.m_pFrame[i]->zPos() + dj1 * m_SplineSurface.m_pFrame[i+1]->zPos())/2.0; CoGIxx += SectionArea*rho * ( (Pt.y-CoG.y)*(Pt.y-CoG.y) + (Pt.z-CoG.z)*(Pt.z-CoG.z) ); CoGIyy += SectionArea*rho * ( (Pt.x-CoG.x)*(Pt.x-CoG.x) + (Pt.z-CoG.z)*(Pt.z-CoG.z) ); CoGIzz += SectionArea*rho * ( (Pt.x-CoG.x)*(Pt.x-CoG.x) + (Pt.y-CoG.y)*(Pt.y-CoG.y) ); CoGIxz -= SectionArea*rho * ( (Pt.x-CoG.x)*(Pt.z-CoG.z) ); } } } else if(m_LineType==BODYSPLINETYPE) { int NSections = 20;//why not ? xpos = FramePosition(0); dl = Length()/(double)(NSections-1); for (j=0; jPRECISION) CoG *= 1.0/ m_VolumeMass; else CoG.Set(0.0, 0.0, 0.0); // Next evaluate inertia, assuming each section is a point mass xpos = FramePosition(0); for (j=0; jmass(); return TotalMass; } void Body::SetEdgeWeight(double uw, double vw) { m_SplineSurface.m_EdgeWeightu = uw; m_SplineSurface.m_EdgeWeightv = vw; } /** Destroys the PointMass objects in good order to avoid memory leaks */ void Body::ClearPointMasses() { for(int ipm=m_PointMass.size()-1; ipm>=0; ipm--) { delete m_PointMass.at(ipm); m_PointMass.removeAt(ipm); } } xflr5-6.09-06/src/objects/WingSection.h000644 001750 000144 00000005436 12247174403 021124 0ustar00techwinderusers000000 000000 /**************************************************************************** WingSection Class Copyright (C) 2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** *@file This class defines the wing section object used to define wing geometries. */ #ifndef WINGSECTION_H #define WINGSECTION_H #include /** @enum The different types of panel distribution on the wing */ typedef enum {COSINE, UNIFORM, SINE, INVERSESINE} enumPanelDistribution; /** *@class WingSection *@brief The class which defines the wing section object used to construct wing geometries. */ class WingSection { public: WingSection() { m_NXPanels = 0; m_NYPanels = 0; m_XPanelDist = COSINE; m_YPanelDist = COSINE; m_Chord = 0.0; m_Length = 0.0; m_YPosition = 0.0; m_YProj = 0.0; m_Offset = 0.0; m_Dihedral = 0.0; m_ZPos = 0.0; m_Twist = 0.0; m_RightFoilName.clear(); m_LeftFoilName.clear(); } int m_NXPanels; /**< VLM Panels along chord, for each Wing Panel */ int m_NYPanels; /**< VLM Panels along span, for each Wing Panel */ enumPanelDistribution m_XPanelDist; /**< VLM Panel distribution type, for each Wing Panel */ enumPanelDistribution m_YPanelDist; /**< VLM Panel distribution type, for each Wing Panel */ double m_Chord; /**< Chord length at each panel side */ double m_Length; /**< the length of each panel */ double m_YPosition; /**< b-position of each panel end on developed surface */ double m_YProj; /**< b-position of each panel end projected on tbe xy plane */ double m_Offset; /**< b-position of each panel end */ double m_Dihedral; /**< b-position of each panel end */ double m_ZPos; /**< vertical offset - calculation result only */ double m_Twist; /**< Twist value of each foil (measured to the wing root) */ QString m_LeftFoilName; /**< The name of the foil on the leftt side of the section */ QString m_RightFoilName; /**< The name of the foil on the right side of the section */ }; #endif // WINGSECTION_H xflr5-6.09-06/src/objects/Panel.h000644 001750 000144 00000016220 12247174403 017723 0ustar00techwinderusers000000 000000 /**************************************************************************** Panel Class Copyright (C) 2006-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** *@file * * This file defines the classes for quad panel object used both in VLM and in 3d-panel analysis * */ #ifndef PANEL_H #define PANEL_H #include "Quaternion.h" #include "CVector.h" /** * enumeration used to identify the type of surface on which the panel lies. * May be on a bottom, mid, top, side, or body surface. */ typedef enum {BOTSURFACE, MIDSURFACE, TOPSURFACE, SIDESURFACE, BODYSURFACE} enumPanelPosition; /** *@class Panel *@brief This class defines the quad panel object used both in VLM and in 3d-panel analysis * The class provides member variables which define the geometric properties of the panel, and functions used in the 3D analysis. * * The name of the variables follows closely the naming used in the document NASA Contractor report 4023 "Program VSAERO Theory Document". Refer to this document for detailed explanations on the description of the panel and the meaning of the variables. The nodes are defined in a separate global array. The index of the nodes at the four corners are stored as member variables of this panel. * * For VLM calculations, the position and length vector of the bound vortex at the panel's quarter-chord are stored as member variables. */ class Panel { friend class Surface; friend class Wing; friend class QMiarex; friend class Body; friend class PanelAnalysisDlg; friend class GL3dBodyDlg; friend class GL3dWingDlg; public: Panel(); void RotateBC(CVector const &HA, Quaternion & Qt); void Reset(); void SetFrame(); void SetFrame(CVector const &LA, CVector const &LB, CVector const &TA, CVector const &TB); bool Intersect(CVector const &A, CVector const &U, CVector &I, double &dist); bool Invert33(double *l); CVector GlobalToLocal(CVector const &V); CVector GlobalToLocal(double const &Vx, double const &Vy, double const &Vz); CVector LocalToGlobal(CVector const &V); double Width(); double GetArea(); protected: bool m_bIsInSymPlane; /**< true if the panel lies in the plane's xz plane of symetry at y=0*/ bool m_bIsLeftPanel; /**< true if the panel lies on the left (port) wing */ bool m_bIsWakePanel; /**< true if the panel lies on the wake of a winf */ int m_iElement; /**< panel identification number ; used when the panel array is re-arranged in non sequential order to reduce the matrix size in symetrical calculations */ int m_iSym; /**< reference of the symetric panel, or -1 if none */ int m_iPL; /**< index of the panel which lies left of this panel, or -1 if none */ int m_iPR; /**< index of the panel which lies right of this panel, or -1 if none */ int m_iPU; /**< index of the panel which lies upstream of this panel, or -1 if none */ int m_iPD; /**< index of the panel which lies downstream of this panel, or -1 if none */ int m_iWake; /**< -1 if not followed by a wake panel, else equal to wake panel number */ int m_iWakeColumn; /**< index of the wake column shed by this panel, numbered from left tip to right tip, or -1 if none */ //Local frame of refernce CVector VortexPos; /**< the absolute position of the mid point of the bound vortex at the panel's quarter chord */ CVector Vortex; /**< the bound vortex vector at the panel's quarter chord */ CVector P1; /**< the coordinates of the panel's corners, in local coordinates */ CVector P2; /**< the coordinates of the panel's corners, in local coordinates */ CVector P3; /**< the coordinates of the panel's corners, in local coordinates */ CVector P4; /**< the coordinates of the panel's corners, in local coordinates */ CVector m, l; /**< the unit vectors which lie in the panel's plane. Cf. document NACA 4023 */ double dl; /**< The length of the bound vector */ double Area; /**< The panel's area; */ double Size; /**< = SMP + SMQ and provides an estimation of the panel's size. This is used to determine if the far-field approximation can be used in the evaluation of the source and doublet influent at a distant point */ double SMP; /**< Half panel lenght in the l direction. Cf. document NACA 4023 figure 8.*/ double SMQ; /**< Half panel lenght in the m direction. Cf. document NACA 4023 figure 8. */ double lij[9]; /**< The 3x3 matrix used to transform local coordinates in absolute coordinates */ static CVector *s_pNode; /**< A pointer to the global array of panel nodes */ static CVector smp, smq, MidA, MidB; // temp variables static CVector ILA, ILB, ITA, ITB, T, V, W, P, LATB, TALB; // temp variables static double s_VortexPos; /**< Defines the relative position of the bound vortex in the streamwise direction. Usually the vortex is positioned at the panel's quarter chord i.e. s_VortexPos=0.25 */ static double s_CtrlPos; /**< Defines the relative position of the panel's control point in VLM. Usually the control point is positioned at the panel's 3/4 chord : s_VortexPos=0.75 */ static double det; /**< temporary variable */ static double mat[9]; /**< temporary array */ public: enumPanelPosition m_Pos; /**< defines if the panel is positioned on a top, middle, bottom, side or body surface */ bool m_bIsLeading; /**< true if the panel is positioned on a leading edge */ bool m_bIsTrailing; /**< true if the panel is positioned on a trailing edge */ int m_iLA; /**< index of the leading left node in the node array */ int m_iLB; /**< index of the leading right node in the node array */ int m_iTA; /**< index of the trailing left node in the node array */ int m_iTB; /**< index of the trailing right node in the node array */ CVector Normal; /**< the unit vector normal to the panel */ CVector CtrlPt; /**< the position of the control point for VLM analysis or 3D/Thin panels analysis */ CVector CollPt; /**< the collocation point for 3d panel analysis */ CVector VA; /**< the left end point of the bound quarter-chord vortex on this panel */ CVector VB; /**< the rightt end point of the bound quarter-chord vortex on this panel */ }; #endif xflr5-6.09-06/src/objects/PlaneOpp.h000644 001750 000144 00000007306 12247174403 020407 0ustar00techwinderusers000000 000000 /**************************************************************************** PlaneOpp Class Copyright (C) 2006-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file * * This class defines the operating point object for the 3D analysis of planes * */ #ifndef PLANEOPP_H #define PLANEOPP_H #include "WingOpp.h" #include /** *@brief * This class defines the operating point object which stores the data of plane analysis * Each instance of this class is uniquely associated to an instance of a WPolar, which is itself uniquely associated to a Wing or a Plane object. The results associated to each of the plane's wing is stored in WingOpp objects, declared as member variables. The data is stored in International Standard Units, i.e. meters, seconds, kg, and Newtons. Angular data is stored in degrees. */ class PlaneOpp { friend class QMiarex; friend class MainFrame; friend class WPolar; public: PlaneOpp(int PanelArraySize=0); ~PlaneOpp(); bool SerializePOpp(QDataStream &ar, bool bIsStoring); void AddWingOpp(int iw, int PanelArraySize); void Allocate(int PanelArraySize); void Release(); private: WingOpp *m_pPlaneWOpp[MAXWINGS]; /**< An array of pointers to the four WingOpp objects associated to the four wings */ enumPolarType m_WPolarType; /**< the type of the parent WPolar object */ QString m_PlaneName; /**< the pPane's name to which the PlaneOpp is attached */ QString m_PlrName; /**< the WPolar's name to which the PlaneOpp is attached */ double m_Alpha; /**< the angle of attack*/ double m_QInf; /**< the freestream velocity */ double m_Beta; /**< the sideslip angle */ double m_Bank; /**< the bank angle */ double m_Ctrl; /**< the value of the control variable */ int m_NStation; /**< unused */ // bool m_bWing[MAXWINGS]; /**< true if respectively a main wing, 2nd wing, elevator, fin are part of the parent Plane object */ bool m_bVLM1; /**< true if the PlaneOpp is the result of a horseshoe VLM analysis */ bool m_bOut; /**< true if the interpolation of viscous properties was outside the Foil Polar mesh */ bool m_bIsVisible; /**< true if the PlaneOpp's curve is visible in the active view */ bool m_bShowPoints; /**< true if the PlaneOpp's curve points are visible in the active graphs */ int m_Style; /**< the index of the style with which to draw the PlaneOpp's curve */ int m_Width; /**< the width with which to draw the PlaneOpp's curve */ QColor m_Color; /**< the color with which to draw the PlaneOpp's curve */ public: float *m_G; /**< the VLM vortex strengths, or the panel's doublet's strengths */ float *m_Sigma; /**< the panel's source strengths */ float *m_Cp; /**< the array of Cp coefficients */ int m_NPanels; /**< the number of VLM or 3D-panels */ }; #endif xflr5-6.09-06/src/objects/ArcBall.h000644 001750 000144 00000012501 12247174403 020162 0ustar00techwinderusers000000 000000 /**************************************************************************** CArcBall Class Copyright (C) Bradley Smith, March 24, 2006 Hideously modified in 2008-2009 by Andre Deperrois adeperrois@xflr5.com for miserable selfish purposes This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /* Arcball, written by Bradley Smith, March 24, 2006 * * Using the arcball: * Call arcball_setzoom after setting up the projection matrix. * * The arcball, by default, will act as if a sphere with the given * radius, centred on the origin, can be directly manipulated with * the mouse. Clicking on a point should drag that point to rest under * the current mouse position. eye is the position of the eye relative * to the origin. up is unused. * * Alternatively, pass the value: (-radius/|eye|) * This puts the arcball in a mode where the distance the mouse moves * is equivalent to rotation along the axes. This acts much like a * trackball. (It is for this mode that the up vector is required, * which must be a unit vector.) * * You should call arcball_setzoom after use of gluLookAt. * gluLookAt(eye.x,eye.y,eye.z, ?,?,?, up.x,up.y,up.z); * The arcball derives its transformation information from the * openGL projection and viewport matrices. (modelview is ignored) * * If looking at a point different from the origin, the arcball will still * act as if it centred at (0,0,0). (You can use this to translate * the arcball to some other part of the screen.) * * Call arcball_start with a mouse position, and the arcball will * be ready to manipulate. (Call on mouse button down.) * Call arcball_move with a mouse position, and the arcball will * find the rotation necessary to move the start mouse position to * the current mouse position on the sphere. (Call on mouse move.) * Call arcball_rotate after resetting the modelview matrix in your * drawing code. It will call glRotate with its current rotation. * Call arcball_reset if you wish to reset the arcball rotation. */ /** *@file * This file contains the description of the Arcball class used for the calculation of rotations in 3D display. * Based on the code provided by Bradley Smith http://rainwarrior.ca/dragon/arcball.html * */ #ifndef ARBCALL_H #define ARBCALL_H #include "../objects/CVector.h" #include "../objects/Quaternion.h" #include /** *@class ArcBall *@brief * This class defines the Arcball object used for the calculation of rotations in 3D display. * Based on the code provided by Bradley Smith http://rainwarrior.ca/dragon/arcball.html */ class ArcBall { public: ArcBall(void); void SetQuat(Quaternion Qt); void SetQuat(double r, double qx, double qy, double qz); void SetZoom(double radius, CVector eye, CVector up); void Rotate(); void Reset(); void Start(int mx, int my); void Move(int mx, int my); void GetMatrix(); void SphereCoords(int const &mx, int const &my, CVector &V);// find the intersection with the sphere void PlanarCoords(int const &mx, int const &my, CVector &V);// get intersection with plane for "trackball" style rotation void EdgeCoords(CVector m, CVector &V); // find the intersection with the plane through the visible edge void RotateCrossPoint(); void QuatIdentity(float* q); // reset the rotation matrix void QuatCopy(float* dst, float* src);// copy a rotation matrix void QuattoMatrix(float* q, Quaternion Qt);// convert the quaternion into a rotation matrix void QuatNext(float* dest, float* left, float* right);// multiply two rotation matrices void ClientToGL(int const &x, int const &y, double &glx, double &gly); float ab_quat[16]; float ab_last[16]; float ab_next[16]; float ab_crosspoint[16]; // the distance from the origin to the eye double ab_zoom; double ab_zoom2; // the radius of the arcball double ab_sphere; double ab_sphere2; // the distance from the origin of the plane that intersects // the edge of the visible sphere (tangent to a ray from the eye) double ab_edge; // whether we are using a sphere or plane bool ab_planar; double ab_planedist; void *m_p3dWidget; CVector ab_start; CVector ab_curr; CVector ab_eye; CVector ab_eyedir; CVector ab_up; CVector ab_out; Quaternion Quat; double angle, cosa2, sina2, cosa; double ab_glp[16]; double ab_glm[16]; int ab_glv[4]; // object offset double *m_pOffx, *m_pOffy; double *m_pTransx, *m_pTransy; QRect *m_pRect; //avoid lengthy recurring memory allocations CVector aa, c, m, ec, sc, p, d; double t, ac, c2, q, b, delta, a; double x2, y2, z2, xy, xz, yz, wx, wy, wz; double ax,ay,az; }; #endif xflr5-6.09-06/src/objects/CRectangle.h000644 001750 000144 00000006756 12247174403 020710 0ustar00techwinderusers000000 000000 /**************************************************************************** CRectangle Class Copyright (C) 2008 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef CRECTANGLE_H #define CRECTANGLE_H #include "CVector.h" class CRectangle { public: CRectangle(void) { left = 0; right = 0; top = 0; bottom = 0; }; CRectangle(double const &l, double const &t, double const&r, double const&b) { left = l; right = r; top = t; bottom = b; }; CRectangle(CVector const &TopLeft, CVector const &BottomRight) { left = TopLeft.x; right = BottomRight.x; top = TopLeft.y; bottom = BottomRight.y; }; void CopyRect(CRectangle *pRect) { left = pRect->left; right = pRect->right; top = pRect->top; bottom = pRect->bottom; }; CRectangle(CRectangle const &Rect) { left = Rect.left; right = Rect.right; top = Rect.top; bottom = Rect.bottom; } // ~CRectangle(void); bool IsRectEmpty() { if(bottom==top && right==left) return true; else return false; }; bool PtInRect(CVector const &pt) { if(left right) { tmp = left; left = right; right = tmp; } if(bottom>top) { tmp = bottom; bottom = top; top = tmp; } }; double left; double top; double right; double bottom; }; #endif xflr5-6.09-06/src/objects/WingOpp.cpp000644 001750 000144 00000072176 12247174403 020616 0ustar00techwinderusers000000 000000 /**************************************************************************** WingOpp Class Copyright (C) 2005-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../mainframe.h" #include "WingOpp.h" #include "Plane.h" #include "../globals.h" #include #include /** * The public constructor. */ WingOpp::WingOpp(int PanelArraySize) { m_NVLMPanels = PanelArraySize; m_Cp = m_G = m_Sigma = NULL; Allocate(PanelArraySize); m_bOut = false; m_bVLM1 = true; m_bThinSurface = true; m_bTiltedGeom = false; m_bIsVisible = true; m_bShowPoints = false; m_Color = QColor(255,0,0); m_Style = 0; m_Width = 1; m_nWakeNodes = 0; m_NXWakePanels = 0; m_FirstWakePanel = 0.0; m_WakeFactor = 1.0; m_NStation = 0; m_nFlaps = 0; m_nControls = 0; m_AnalysisMethod = LLTMETHOD; m_Alpha = 0.0; m_Beta = 0.0; m_Phi = 0.0; m_Ctrl = 0.0; m_CL = 0.0; m_CY = 0.0; m_CX = 0.0; m_VCD = 0.0; m_ICD = 0.0; m_GCm = m_VCm = m_ICm = m_GRm = m_GYm = m_VYm = m_IYm = 0.0; m_CP.Set(0.0,0.0,0.0); m_XNP = 0.0; CXu = CZu = Cmu = 0.0; CXa = CLa = Cma = CXq = CLq = Cmq = CYb = CYp = CYr = Clb = Clp = Clr = Cnb = Cnp = Cnr = 0.0; memset(m_ALong, 0, 16*sizeof(double)); memset(m_ALat, 0, 16*sizeof(double)); memset(m_BLat, 0, 4*sizeof(double)); memset(m_BLong, 0, 4*sizeof(double)); CXe = CYe = CZe = CLe = CMe = CNe = 0; memset(m_EigenValue, 0, sizeof(m_EigenValue)); //four longitudinal and four lateral modes memset(m_EigenVector, 0, sizeof(m_EigenVector)); memset(m_Ai,0,sizeof(m_Ai)); memset(m_Twist,0,sizeof(m_Twist)); memset(m_Cl,0,sizeof(m_Cl)); memset(m_PCd,0,sizeof(m_PCd)); memset(m_ICd,0,sizeof(m_ICd)); memset(m_Cm,0,sizeof(m_Cm)); memset(m_CmAirf,0,sizeof(m_CmAirf)); memset(m_XCPSpanRel,0,sizeof(m_XCPSpanRel)); memset(m_XCPSpanAbs,0,sizeof(m_XCPSpanAbs)); memset(m_Chord,0,sizeof(m_Chord)); memset(m_SpanPos,0,sizeof(m_SpanPos)); memset(m_StripArea,0,sizeof(m_StripArea)); memset(m_Re,0,sizeof(m_Re)); memset(m_Twist,0,sizeof(m_Twist)); memset(m_XTrTop,0,sizeof(m_XTrTop)); memset(m_XTrBot,0,sizeof(m_XTrBot)); memset(m_BendingMoment,0,sizeof(m_BendingMoment)); memset(m_Vd,0,sizeof(m_Vd)); memset(m_F,0,sizeof(m_F)); memset(m_FlapMoment,0,sizeof(m_FlapMoment)); } /** * This course of action will lead us to destruction. */ WingOpp::~WingOpp() { ReleasePanelSizeArrays(); } /** Allocate memory to the arrays */ void WingOpp::Allocate(int PanelArraySize) { ReleasePanelSizeArrays(); m_NVLMPanels = PanelArraySize; if(PanelArraySize>0) { m_Cp = new float[PanelArraySize]; m_Sigma = new float[PanelArraySize]; m_G = new float[PanelArraySize]; memset(m_G, 0, PanelArraySize * sizeof(float)); memset(m_Sigma, 0, PanelArraySize * sizeof(float)); memset(m_Cp, 0, PanelArraySize * sizeof(float)); } else { m_Cp = NULL; m_Sigma = NULL; m_G = NULL; } } /** * Releases memory allocated on the heap */ void WingOpp::ReleasePanelSizeArrays() { if(m_Cp) delete[] m_Cp; if(m_Sigma) delete[] m_Sigma; if(m_G) delete[] m_G; m_Cp = NULL; m_Sigma = NULL; m_G = NULL; } /** * Exports the data of the WingOpp to a text file * @param out the instance of output QtextStream * @param FileType TXT if the data is separated by spaces, CSV for a comma separator * @return true if the export was successful, false otherwise. */ bool WingOpp::Export(QTextStream &out, enumTextFileType FileType) { QString Header, strong, Format; int k; if(FileType==TXT) Header = " y-span Chord Ai Cl PCd ICd CmGeom CmAirf XTrtop XTrBot XCP BM\n"; else Header = " y-span,Chord,Ai,Cl,PCd,ICd,CmGeom,CmAirf,XTrtop,XTrBot,XCP,BM\n"; out << Header; int nStart; if(m_AnalysisMethod==LLTMETHOD) nStart = 1; else nStart = 0; if(FileType==TXT) Format = "%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12\n"; else Format = "%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12\n"; for (k=nStart; kmaxlift) { maxlift = m_Cl[i] * m_Chord[i]/m_MAChord; } } return maxlift; } /** * Loads or saves the data of this WingOpp to a binary file * @param ar the QDataStream object from/to which the data should be serialized * @param bIsStoring true if saving the data, false if loading * @return true if the operation was successful, false otherwise */ bool WingOpp::SerializeWingOpp(QDataStream &ar, bool bIsStoring) { int ArchiveFormat; int a,p,k,l,n; float f, f0, f1, f2, f3; if(bIsStoring) { ar << 1023; //1023 : condidional gamma and Cp save on !LLTMethod //1022 : reduced the number of controls to 1 //1021 : added ZCP //1020 : added CXa/CXu/CZu/Cmu + changed the provisions to zero //1019 : added Neutral point position + Provision for more int and float saves //1018 : added non dimensional stability control derivatives //1017 : added non dimensional stability derivatives //1016 : added eigenthings //1015 : added m_CX and m_CY values //1014 : redefined moment coefficients //1013 : added m_bTiltedGeom //1012 : added m_StripArea //1011 : added m_Sigma //1010 : added flap moments, changed lengths to m //1009 : added Vortex strengths //1008 : added wake node number and pos //1007 : added m_XCPSpanAbs //1006 : added SurfaceForce //1005 : added downwash and VLM methods //1004 : added WingType //1003 : added Cl Distribution //1002 : added bending moment //write variables WriteCString(ar, m_WingName); WriteCString(ar, m_PlrName); if(m_bIsVisible) ar << 1; else ar<<0; if(m_bShowPoints) ar << 1; else ar<<0; if(m_bOut) ar << 1; else ar<<0; if(m_AnalysisMethod==LLTMETHOD) ar<<1; else if(m_AnalysisMethod==VLMMETHOD) ar<<2; else if(m_AnalysisMethod==PANELMETHOD) ar<<3; if(m_bVLM1) ar << 1; else ar<<0; if(m_bThinSurface) ar << 1; else ar<<0; if(m_bTiltedGeom) ar << 1; else ar<<0; ar << m_Style << m_Width; WriteCOLORREF(ar,m_Color); if(m_WPolarType==FIXEDSPEEDPOLAR) ar<<1; else if(m_WPolarType==FIXEDLIFTPOLAR) ar<<2; else if(m_WPolarType==FIXEDAOAPOLAR) ar<<4; else if(m_WPolarType==STABILITYPOLAR) ar<<7; else ar << 0; ar << m_NStation; ar << (float)m_Alpha << (float)m_QInf << (float)m_Weight << (float)m_Span << (float)m_MAChord; ar << (float)m_CL << (float)m_VCD << (float)m_ICD ; ar << (float)m_Beta; ar << (float)m_CX << (float)m_CY; ar << (float)m_GCm << (float)m_GRm << (float)m_GYm; ar << 0.0f << (float)m_VYm; ar << (float)m_IYm; ar << (float)m_CP.x << (float)m_CP.y; for (k=0; k> ArchiveFormat; if(ArchiveFormat<1001|| ArchiveFormat>1100) return false; //read variables ReadCString(ar, m_WingName); ReadCString(ar, m_PlrName); ar >> a; if (a!=0 && a!=1) return false; if(a) m_bIsVisible = true; else m_bIsVisible = false; ar >> a; if (a!=0 && a!=1) return false; if(a) m_bShowPoints = true; else m_bShowPoints = false; ar >> a; if (a!=0 && a!=1) return false; if(a) m_bOut = true; else m_bOut = false; ar>>k; if(k==1) m_AnalysisMethod=LLTMETHOD; else if(k==2) m_AnalysisMethod=VLMMETHOD; else if(k==3) m_AnalysisMethod=PANELMETHOD; else if(k==4) m_AnalysisMethod=VLMMETHOD; else return false; if(ArchiveFormat>=1005) { ar >> a; if (a!=0 && a!=1) return false; if(a) m_bVLM1 = true; else m_bVLM1 = false; ar >> a; if (a!=0 && a!=1) return false; if(a) m_bThinSurface = true; else m_bThinSurface = false; } if(ArchiveFormat>=1013) { ar >> a; if (a!=0 && a!=1) return false; if(a) m_bTiltedGeom = true; else m_bTiltedGeom = false; } ar >> m_Style >> m_Width; ReadCOLORREF(ar,m_Color); ar >>k; if(k==1) m_WPolarType = FIXEDSPEEDPOLAR; else if(k==2) m_WPolarType = FIXEDLIFTPOLAR; else if(k==4) m_WPolarType = FIXEDAOAPOLAR; else if(k==6) m_WPolarType = STABILITYPOLAR; //former control polars else if(k==7) m_WPolarType = STABILITYPOLAR; else return false; ar >> m_NStation; ar >> f; m_Alpha =f; ar >> f; m_QInf =f; ar >> f; m_Weight =f; ar >> f; m_Span =f; ar >> f; m_MAChord =f; ar >> f; m_CL =f; ar >> f; m_VCD =f; ar >> f; m_ICD =f; if(ArchiveFormat>=1015) { ar >> f; m_Beta=f; ar >> f; m_CX =f; ar >> f; m_CY =f; } ar >> f; m_GCm =f; ar >> f; m_GRm =f; ar >> f; m_GYm =f; ar >> f; //m_VCm =f; ar >> f; m_VYm =f; ar >> f; m_IYm =f; if(ArchiveFormat<1014 && m_AnalysisMethod>LLTMETHOD) { m_GCm = m_GRm = m_GYm = m_VYm = m_IYm = 0.0; } ar >> f; m_CP.x =f; ar >> f; m_CP.y =f; for (k=0; k> f; m_Re[k] =f; ar >> f; m_Chord[k] =f; ar >> f; m_Twist[k] =f; ar >> f; m_Ai[k] =f; ar >> f; m_Cl[k] =f; ar >> f; m_PCd[k] =f; ar >> f; m_ICd[k] =f; ar >> f; m_Cm[k] =f; ar >> f; m_CmAirf[k] =f; ar >> f; //f=0.0; ar >> f; m_XCPSpanRel[k] =f; if(ArchiveFormat>=1007){ar >> f; m_XCPSpanAbs[k] =f;} ar >> f; m_XTrTop[k] =f; ar >> f; m_XTrBot[k] =f; if(ArchiveFormat>=1002) {ar >> f; m_BendingMoment[k]=f;} else m_BendingMoment[k] = 0.0; if(ArchiveFormat>=1005) { ar >> f; m_Vd[k].x=f; ar >> f; m_Vd[k].y=f; ar >> f; m_Vd[k].z=f; } else { m_Vd[k].x = 0.0; m_Vd[k].y = 0.0; m_Vd[k].z = 0.0; } if(ArchiveFormat>=1006) { ar >> f; m_F[k].x=f; ar >> f; m_F[k].y=f; ar >> f; m_F[k].z=f; } else { m_F[k].x = 0.0; m_F[k].y = 0.0; m_F[k].z = 0.0; } } m_MaxBending = 0.0; for (k=0; k> f1; if(m_AnalysisMethod==LLTMETHOD && ArchiveFormat<=1004) m_SpanPos[k] = -f1; else m_SpanPos[k] = f1; if(ArchiveFormat>=1012) { ar >> f2; m_StripArea[k] = f2; } else m_StripArea[k] = 0.0; } if(ArchiveFormat>=1003) { ar>> m_NVLMPanels; if(m_G) delete m_G; if(m_Sigma) delete m_Sigma; if(m_Cp) delete m_Cp; m_G = new float[m_NVLMPanels]; m_Sigma = new float[m_NVLMPanels]; m_Cp = new float[m_NVLMPanels]; if(ArchiveFormat<1023 || m_AnalysisMethod !=LLTMETHOD) { for (p=0; p> f; m_Cp[p] =f; } } } if(ArchiveFormat>=1009) { if(ArchiveFormat<1023 || m_AnalysisMethod !=LLTMETHOD) { for (p=0; p> f; m_G[p] =f; if(ArchiveFormat<1010) m_G[p] = f/1000.0; } } } if(ArchiveFormat>1010) { if(m_AnalysisMethod==PANELMETHOD) { for (p=0; p> f; m_Sigma[p] = f; } } } if(ArchiveFormat>=1004) { ar>> k; //m_WingType; } if(ArchiveFormat>=1008) { ar >> m_nWakeNodes >> m_NXWakePanels >> m_FirstWakePanel >> m_WakeFactor; } if(ArchiveFormat>=1010) { ar >> m_nFlaps; for(k=0; k>f; m_FlapMoment[k] = f; } } if(ArchiveFormat<1010) { for(k=0; k=1016) { for(k=0; k<8;k++) { ar >> f1 >> f2; m_EigenValue[k] = complex(f1, f2); for(l=0; l<4; l++) { ar >> f1 >> f2; m_EigenVector[k][l] = complex(f1, f2); } } } if(ArchiveFormat>=1020) { // Non dimensional stability derivatives ar>>f; CXa= f; ar>>f; CXq= f; ar>>f; CXu= f; ar>>f; CZu= f; ar>>f; Cmu= f; } if(ArchiveFormat>=1017) { // Non dimensional stability derivatives ar>>f; CLa= f; ar>>f; CLq= f; ar>>f; Cma= f; ar>>f; Cmq= f; ar>>f; CYb= f; ar>>f; CYp= f; ar>>f; CYr= f; ar>>f; Clb= f; ar>>f; Clp= f; ar>>f; Clr= f; ar>>f; Cnb= f; ar>>f; Cnp= f; ar>>f; Cnr= f; } if(ArchiveFormat>=1018) { ar >> m_nControls; if(ArchiveFormat<1022) n = m_nControls; else n =1; for(k=0; k>f; if(k==0) CXe=f; ar >>f; if(k==0) CYe=f; ar >>f; if(k==0) CZe=f; ar >>f; if(k==0) CLe=f; ar >>f; if(k==0) CMe=f; ar >>f; if(k==0) CNe=f; ar >>f0>>f1>>f2>>f3; if(k==0) m_BLat[0]= f0; m_BLat[1]= f1; m_BLat[2] = f2; m_BLat[3] = f3; ar >>f0>>f1>>f2>>f3; m_BLong[0]=f0; m_BLong[1]=f1; m_BLong[2]= f2; m_BLong[3]= f3; } for(k=0; k<4; k++) { ar >>f0>>f1>>f2>>f3; m_ALong[k][0]= f0; m_ALong[k][1]= f1; m_ALong[k][2]= f2; m_ALong[k][3] = f3; ar >>f0>>f1>>f2>>f3; m_ALat[k][0] = f0; m_ALat[k][1] = f1; m_ALat[k][2] = f2; m_ALat[k][3] = f3; } } if(ArchiveFormat>=1019) { ar>>f; m_XNP = f; } else m_XNP = 0.0; if(ArchiveFormat>=1019) { ar>>f; m_Ctrl=f; //provision for(int i=1; i<20; i++) { ar>>f; } for(int i=0; i<20; i++) { ar>>k; } } if(ArchiveFormat>=1021) { ar >> f; m_CP.z=f; } } return true; } /** * Returns a QString object holding the description and value of the WingOpp's parameters * @param &WingOppProperties the reference of the QString object to be filled with the description * @param bData true if the analysis data should be appended to the string */ void WingOpp::GetWingOppProperties(QString &WingOppProperties) { QString strong, strange, lenunit, massunit, speedunit; GetLengthUnit(lenunit, MainFrame::s_LengthUnit); GetWeightUnit(massunit, MainFrame::s_WeightUnit); GetSpeedUnit(speedunit, MainFrame::s_SpeedUnit); WingOppProperties.clear(); if(m_WPolarType==FIXEDSPEEDPOLAR) strong += "Type 1 ("+QObject::tr("Fixed speed") +")\n"; else if(m_WPolarType==FIXEDLIFTPOLAR) strong += "Type 2 ("+QObject::tr("Fixed lift") +")\n"; else if(m_WPolarType==FIXEDAOAPOLAR) strong += "Type 3 ("+QObject::tr("Fixed angle of attack") +")\n"; else if(m_WPolarType==STABILITYPOLAR) strong += "Type 4 ("+QObject::tr("Stability analysis") +")\n"; WingOppProperties += strong; // WOppProperties += QObject::tr("Method")+" = "; if(m_AnalysisMethod==LLTMETHOD) WingOppProperties +=QObject::tr("LLT"); else if(m_AnalysisMethod==PANELMETHOD && !m_bThinSurface) WingOppProperties +=QObject::tr("3D-Panels"); else if(m_AnalysisMethod==PANELMETHOD && m_bVLM1) WingOppProperties +=QObject::tr("3D-Panels/VLM1"); else if(m_AnalysisMethod==PANELMETHOD && !m_bVLM1) WingOppProperties +=QObject::tr("3D-Panels/VLM2"); WingOppProperties +="\n"; if(m_bTiltedGeom) WingOppProperties += QObject::tr("Tilted geometry")+"\n"; if(m_bOut) WingOppProperties += "Point is out of the flight envelope\n"; strong = QString(QObject::tr("VInf")+" =%1 ").arg(m_QInf*MainFrame::s_mstoUnit,7,'f',3); WingOppProperties += "\n"+strong + speedunit+"\n"; strong = QString(QObject::tr("Alpha")+" =%1").arg(m_Alpha,7,'f',2); WingOppProperties += strong +QString::fromUtf8("°")+"\n"; strong = QString(QObject::tr("Mass")+" = %1 ").arg(m_Weight*MainFrame::s_kgtoUnit,7,'f',3); WingOppProperties += strong + massunit + "\n"; if(qAbs(m_Beta)>PRECISION) { strong = QString(QObject::tr("Beta")+" = %1").arg(m_Beta,7,'f',2); WingOppProperties += strong +QString::fromUtf8("°")+"\n\n"; } if(m_WPolarType==STABILITYPOLAR) { strong = QString(QObject::tr("Control value")+" = %1").arg(m_Ctrl,5,'f',2); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("XNP")+" = %1 ").arg(m_XNP*MainFrame::s_mtoUnit,7,'f',3); WingOppProperties += "\n"+strong +lenunit+"\n"; } strong = QString(QObject::tr("XCP")+" = %1 ").arg(m_CP.x*MainFrame::s_mtoUnit,7,'f',3); WingOppProperties += strong +lenunit+"\n"; strong = QString(QObject::tr("YCP")+" = %1 ").arg(m_CP.y*MainFrame::s_mtoUnit,7,'f',3); WingOppProperties += strong +lenunit+"\n"; strong = QString(QObject::tr("ZCP")+" = %1 ").arg(m_CP.z*MainFrame::s_mtoUnit,7,'f',3); WingOppProperties += strong +lenunit+"\n\n"; strong = QString(QObject::tr("CL")+" = %1").arg(m_CL,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("CD")+" = %1").arg(m_ICD+m_VCD,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("VCD")+" = %1").arg(m_VCD,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("ICD")+" = %1").arg(m_ICD,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("CX")+" = %1").arg(m_CX,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("CY")+" = %1").arg(m_CY,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("Cl")+" = %1").arg(m_GRm,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("Cm")+" = %1").arg(m_GCm,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("ICm")+" = %1").arg(m_ICm,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("VCm")+" = %1").arg(m_VCm,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("Cn")+" = %1").arg(m_GYm,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("ICn")+" = %1").arg(m_IYm,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("VCn")+" = %1").arg(m_VYm,9,'f',5); WingOppProperties += strong +"\n"; if(m_nFlaps>0) { WingOppProperties += "\n"; for(int ip=0; ip0) { // (only one) WingOppProperties += QObject::tr("Non-dimensional Control Derivatives:")+"\n"; strong = QString(QObject::tr("CXd")+" = %1").arg(CXe,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("CYd")+" = %1").arg(CYe,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("CZd")+" = %1").arg(CZe,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("Cld")+" = %1").arg(CLe,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("Cmd")+" = %1").arg(CMe,9,'f',5); WingOppProperties += strong +"\n"; strong = QString(QObject::tr("Cnd")+" = %1").arg(CNe,9,'f',5); WingOppProperties += strong +"\n"; } complex c, angle; double OmegaN, Omega1, Dsi, Sigma1, sum, prod, u0, mac, span; u0 = m_QInf; mac = m_MAChord; span = m_Span; WingOppProperties += "\nLongitudinal modes:\n"; for(int im=0; im<4; im++) { c = m_EigenValue[im]; sum = c.real() * 2.0; // is a real number prod = c.real()*c.real() + c.imag()*c.imag(); // is a positive real number OmegaN = qAbs(c.imag()); if(OmegaN>PRECISION) Omega1 = sqrt(prod); else Omega1 = 0.0; Sigma1 = sum /2.0; if(Omega1>PRECISION) Dsi = -Sigma1/Omega1; else Dsi = 0.0; if(c.imag()>=0.0) strange = QString(" Eigenvalue = %1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString(" Eigenvalue = %1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); WingOppProperties += strange +"\n"; strange = QString(" Undamped Natural Frequency = %1 Hz").arg(OmegaN/2.0/PI, 8,'f',3); WingOppProperties += strange +"\n"; strange = QString(" Damped Natural Frequency = %1 Hz").arg(Omega1/2.0/PI, 8,'f',3); WingOppProperties += strange +"\n"; strange = QString(" Damping Ratio = %1 ").arg(Dsi, 8,'f',3); WingOppProperties += strange +"\n"; WingOppProperties += " Normalized Eigenvector:\n"; angle = m_EigenVector[im][3]; c = m_EigenVector[im][0]/u0; if(c.imag()>=0.0) strange = QString(" u/u0 = %1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString(" u/u0 = %1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); WingOppProperties += strange +"\n"; c = m_EigenVector[im][1]/u0; if(c.imag()>=0.0) strange = QString(" w/u0 = %1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString(" w/u0 = %1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); WingOppProperties += strange +"\n"; c = m_EigenVector[im][2]/(2.0*u0/mac); if(c.imag()>=0.0) strange = QString(" q/(2.u0.MAC) = %1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString(" q/(2.u0.MAC) = %1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); WingOppProperties += strange +"\n"; c = m_EigenVector[im][3]/angle; if(c.imag()>=0.0) strange = QString(" theta(rad) = %1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString(" theta(rad) = %1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); WingOppProperties += strange +"\n\n"; } WingOppProperties += "\nLateral modes:\n"; for(int im=4; im<8; im++) { c = m_EigenValue[im]; sum = c.real() * 2.0; // is a real number prod = c.real()*c.real() + c.imag()*c.imag(); // is a positive real number OmegaN = qAbs(c.imag()); if(OmegaN>PRECISION) Omega1 = sqrt(prod); else Omega1 = 0.0; Sigma1 = sum /2.0; if(Omega1>PRECISION) Dsi = -Sigma1/Omega1; else Dsi = 0.0; if(c.imag()>=0.0) strange = QString(" Eigenvalue = %1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString(" Eigenvalue = %1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); WingOppProperties += strange +"\n"; strange = QString(" Undamped Natural Frequency = %1 Hz").arg(OmegaN/2.0/PI, 8,'f',3); WingOppProperties += strange +"\n"; strange = QString(" Damped Natural Frequency = %1 Hz").arg(Omega1/2.0/PI, 8,'f',3); WingOppProperties += strange +"\n"; strange = QString(" Damping Ratio = %1 ").arg(Dsi, 8,'f',3); WingOppProperties += strange +"\n"; WingOppProperties += " Normalized Eigenvector:\n"; angle = m_EigenVector[im][3]; c = m_EigenVector[im][0]/u0; if(c.imag()>=0.0) strange = QString(" v/u0 = %1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString(" v/u0 = %1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); WingOppProperties += strange +"\n"; c = m_EigenVector[im][1]/(2.0*u0/span); if(c.imag()>=0.0) strange = QString(" p/(2.u0.Span) = %1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString(" p/(2.u0.Span) = %1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); WingOppProperties += strange +"\n"; c = m_EigenVector[im][2]/(2.0*u0/span); if(c.imag()>=0.0) strange = QString(" r/(2.u0.Span) = %1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString(" r/(2.u0.Span) = %1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); WingOppProperties += strange +"\n"; c = m_EigenVector[im][3]/angle; if(c.imag()>=0.0) strange = QString(" phi(rad) = %1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString(" phi(rad) = %1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); WingOppProperties += strange +"\n\n"; } } } xflr5-6.09-06/src/objects/NURBSSurface.cpp000644 001750 000144 00000023356 12247174403 021431 0ustar00techwinderusers000000 000000 /**************************************************************************** SplineSurface Class Copyright (C) 2012 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../params.h" #include "../globals.h" #include "NURBSSurface.h" void *NURBSSurface::s_pMainFrame; /** * The public constructor. * @param iAxis defines along which preferred axis the paramater u is directed; v is in the y-direction */ NURBSSurface::NURBSSurface(int iAxis) { m_pFrame.clear(); #if QT_VERSION >= 0x040700 m_pFrame.reserve(10); #endif m_uAxis = iAxis;//directed in x direction, mainly m_vAxis = 2;//directed in y direction, mainly m_iuDegree = 2; m_ivDegree = 2; m_nuKnots = 0; m_nvKnots = 0; m_iRes = 31; m_Bunch = 0.0; m_EdgeWeightu = 1.0; m_EdgeWeightv = 1.0; eps = 1.0e-06; } NURBSSurface::~NURBSSurface() { for(int iFr=m_pFrame.size()-1; iFr>=0; iFr--) { delete m_pFrame.at(iFr); m_pFrame.removeAt(iFr); } } /** * Returns the u-parameter for a given value along the axis and a given v parameter * Proceeds by iteration - time consuming, * @param pos the point coordinate for which the parameter u is requested * @param v the specified value of the v-parameter * @return the value of the u-parameter */ double NURBSSurface::Getu(double pos, double v) { if(pos<=m_pFrame.first()->m_Position[m_uAxis]) return 0.0; if(pos>=m_pFrame.last()->m_Position[m_uAxis]) return 1.0; if(qAbs(m_pFrame.last()->m_Position[m_uAxis] - m_pFrame.first()->m_Position[m_uAxis])<0.0000001) return 0.0; int iter=0; double u2, u1, b, c, u, zz, zh; u1 = 0.0; u2 = 1.0; // v = 0.0;//use top line, but doesn't matter while(qAbs(u2-u1)>1.0e-6 && iter<200) { u=(u1+u2)/2.0; zz = 0.0; for(int iu=0; ium_Position[m_uAxis] * c; } b = SplineBlend(iu, m_iuDegree, u, m_uKnots); zz += zh * b; } if(zz>pos) u2 = u; else u1 = u; iter++; } return (u1+u2)/2.0; } /** * Returns the v-parameter for a given value of u and a geometrical point * Proceeds by iteration - time consuming, * @param u the specified value of the u-parameter * @param r the point for which v is requested * @return the value of the v-parameter */ double NURBSSurface::Getv(double u, CVector r) { double sine = 10000.0; if(u<=0.0) return 0.0; if(u>=1.0) return 0.0; if(r.VAbs()<1.0e-5) return 0.0; int iter=0; double v, v1, v2; r.Normalize(); v1 = 0.0; v2 = 1.0; while(qAbs(sine)>1.0e-4 && iter<200) { v=(v1+v2)/2.0; GetPoint(u, v, t_R); t_R.x = 0.0; t_R.Normalize();//t_R is the unit radial vector for u,v sine = (r.y*t_R.z - r.z*t_R.y); if(sine>0.0) v1 = v; else v2 = v; iter++; } return (v1+v2)/2.0; } /** * Returns the point corresponding to the pair of parameters (u,v) * Assumes that the knots have been set previously * * Scans the u-direction first, then v-direction * @param u the specified u-parameter * @param v the specified v-parameter * @param Pt a reference to the point defined by the pair (u,v) */ void NURBSSurface::GetPoint(double u, double v, CVector &Pt) { CVector V, Vv; double wx, weight; if(u>=1.0) u=0.99999999999; if(v>=1.0) v=0.99999999999; weight = 0.0; for(int iu=0; ium_CtrlPoint[jv].x * cs; Vv.y += m_pFrame[iu]->m_CtrlPoint[jv].y * cs; Vv.z += m_pFrame[iu]->m_CtrlPoint[jv].z * cs; wx += cs; } bs = SplineBlend(iu, m_iuDegree, u, m_uKnots) * Weight(m_EdgeWeightu, iu, FrameSize()); V.x += Vv.x * bs; V.y += Vv.y * bs; V.z += Vv.z * bs; weight += wx * bs; } Pt.x = V.x / weight; Pt.y = V.y / weight; Pt.z = V.z / weight; } /** * Returns the weight of the control point * @param i the index of the point along the edge * @param N the total number of points along the edge * @return the point's weight **/ double NURBSSurface::Weight(double const &d, const int &i, int const &N) { if(qAbs(d-1.0)dmax && iter0.0) m_uKnots[j] = (double)(j-m_iuDegree)/b; else m_uKnots[j] = 1.0; } else m_uKnots[j] = 1.0; } } m_ivDegree = qMin(m_ivDegree, m_pFrame.first()->m_CtrlPoint.size()); m_nvKnots = m_ivDegree + FramePointCount() + 1; b = (double)(m_nvKnots-2*m_ivDegree-1); for (j=0; j0.0) m_vKnots[j] = (double)(j-m_ivDegree)/b; else m_vKnots[j] = 1.0; } else m_vKnots[j] = 1.0; } } } /** * Specifies the degree in the u-direction. * If the degree specified by the input parameter is equal or greater than the Frame count, * then the degree is set to the number of frames minus 1. * @param nvDegree the specified degree * @return the degree which has been set */ int NURBSSurface::SetvDegree(int nvDegree) { if(FramePointCount()>nvDegree) m_ivDegree = nvDegree; else m_ivDegree = FramePointCount()-1; return m_ivDegree; } /** * Specifies the degree in the u-direction. * If the degree specified by the input parameter is equal or greater than the Frame count, * then the degree is set to the number of frames minus 1. * @param nuDegree the specified degree * @return the degree which has been set */ int NURBSSurface::SetuDegree(int nuDegree) { if(FrameSize()>nuDegree) m_iuDegree = nuDegree; else m_iuDegree = FrameSize()-1; return m_iuDegree; } /** * Removes a Frame from the array * @param iFrame the index of the frame to remove */ void NURBSSurface::RemoveFrame(int iFrame) { delete m_pFrame.at(iFrame); m_pFrame.removeAt(iFrame); } /** * Removes all the Frame objects from the array */ void NURBSSurface::ClearFrames() { if(!FrameSize()) return; for(int ifr=FrameSize()-1; ifr>=0; ifr--) { RemoveFrame(ifr); } } /** * Inserts a Frame in the array. The Frame is positioned in crescending position along the u-axis * @param pNewFrame a pointer to the Frame object to insert. */ void NURBSSurface::InsertFrame(Frame *pNewFrame) { for(int ifr=0; ifrm_Position[m_uAxis] < m_pFrame.at(ifr)->m_Position[m_uAxis]) { m_pFrame.insert(ifr, pNewFrame); return; } } m_pFrame.append(pNewFrame); //either the first if none, either the last... } /** * Appends a new Frame at the end of the array * @return a pointer to the Frame which has been created. */ Frame * NURBSSurface::AppendFrame() { m_pFrame.append(new Frame); return m_pFrame.last(); } xflr5-6.09-06/src/objects/Frame.cpp000644 001750 000144 00000017125 12247174403 020256 0ustar00techwinderusers000000 000000 /**************************************************************************** CFrame Class Copyright (C) 2007-2012 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "Frame.h" #include #include "../params.h" /** * The public constructor * @param nCtrlPts the number of points with which the Frame is initialized. */ Frame::Frame(int nCtrlPts) { m_Position.Set(0.0,0.0,0.0); m_CtrlPoint.clear(); for(int ic=0; ic> ArchiveFormat; if(ArchiveFormat<1000 || ArchiveFormat>1100) return false; ar >> n; m_CtrlPoint.clear(); for(k=0; k> fx; ar >> fy; ar >> fz; m_CtrlPoint.append(CVector((double)fx, (double)fy, (double)fz)); } } return true; } /** * Removes a point from the array of control points. *@param n the index of the control point to remove in the array *@return true if the input index is within the array's boundaries, false otherwise */ bool Frame::RemovePoint(int n) { if (n>=0 && n0 && nm_CtrlPoint.first().x) { for(k=0; km_CtrlPoint.first().y) { for(k=0; km_CtrlPoint.last().z) { for(k=0; k=Real.z && Real.z >m_CtrlPoint[k+1].z) { break; } } } else k=-1; } m_CtrlPoint.insert(k+1, Real); m_iSelect = k+1; return k+1; } /** * Returns the Frame's height as the difference of the z-coordinate of the last and first control points. *@return the Frame's height */ double Frame::Height() { return (m_CtrlPoint.last() - m_CtrlPoint.first()).VAbs(); /* double hmin = 10.0; double hmax = -10.0; for(int k=0; khmax) hmax = m_CtrlPoint[k].z; } return qAbs(hmax-hmin);*/ } /** * Returns the Frame's z-position as the highest and lowest z-values in the array of control points. *@return the Frame's z-position */ double Frame::zPos() { double hmin = 10.0; double hmax = -10.0; for(int k=0; khmax) hmax = m_CtrlPoint[k].z; } return (hmax+hmin)/2.0; } /** * Copies the data from an existing Frame * @param pFrame a pointer to the Frame object from which to copy the data */ void Frame::CopyFrame(Frame *pFrame) { m_Position = pFrame->m_Position; CopyPoints(&pFrame->m_CtrlPoint); } /** * Copies the control point data from an existing list of points * @param pPointList a pointer to the list of points */ void Frame::CopyPoints(QList *pPointList) { m_CtrlPoint.clear(); for(int ip=0; ipsize(); ip++) { m_CtrlPoint.append(pPointList->at(ip)); } } /** * Appends a new point at the end of the current array * @param Pt to point to append */ void Frame::AppendPoint(CVector const& Pt) { m_CtrlPoint.append(Pt); } /** * Sets the Frame's absolute position * @param Pos the new position */ void Frame::SetPosition(CVector Pos) { m_Position = Pos; } /** * Set the frame's position on the x-axis *@param u the new x-position */ void Frame::SetuPosition(double u) { m_Position.x = u; } /** * Set the frame's position on the y-axis *@param v the new y-position */ void Frame::SetvPosition(double v) { m_Position.y = v; } /** * Set the frame's position on the z-axis *@param v the new z-position */ void Frame::SetwPosition(double w) { m_Position.z = w; } /** * Rotates the Control points by a specified angle about the Frame's Oy axis *@param Angle the rotation angle in degrees */ void Frame::RotateFrameY(double Angle) { if(!m_CtrlPoint.size()) return; // CVector RotationCenter = m_CtrlPoint.first(); for(int ic=0; ic #include "math.h" ArcBall::ArcBall(void) { m_p3dWidget = NULL; m_pOffx = NULL; m_pOffy = NULL; m_pTransx = NULL; m_pTransy = NULL; m_pRect = NULL; angle = 0.0; Quat.a = 0.0; Quat.qx = Quat.qy = Quat.qz = 0.0; ax = ay = az = 0.0; ab_quat[0] = -0.65987748f; ab_quat[1] = 0.38526487f; ab_quat[2] = -0.64508355f; ab_quat[3] = 0.0f; ab_quat[4] = -0.75137258f; ab_quat[5] = -0.33720365f; ab_quat[6] = 0.56721509f; ab_quat[7] = 0.0f; ab_quat[8] = 0.000f; ab_quat[9] = 0.85899049f; ab_quat[10] = 0.51199043f; ab_quat[11] = 0.0f; ab_quat[12] = 0.0f; ab_quat[13] = 0.0f; ab_quat[14] = 0.0f; ab_quat[15] = 1.0f; memcpy(ab_last, ab_quat, 16*sizeof(float)); memcpy(ab_next, ab_quat, 16*sizeof(float)); // the distance from the origin to the eye ab_zoom = 1.0; ab_zoom2 = 1.0; // the radius of the arcball ab_sphere = 3.0; ab_sphere2 = 9.0; // the distance from the origin of the plane that intersects // the edge of the visible sphere (tangent to a ray from the eye) ab_edge = 1.0; // whether we are using a sphere or plane ab_planar = false; ab_planedist = 0.5; ab_start.Set(0.0,0.0,1.0); ab_curr.Set(0.0,0.0,1.0); ab_eye.Set(0.0,0.0,1.0); ab_eyedir.Set(0.0,0.0,1.0); ab_up.Set(0.0,1.0,0.0); ab_out.Set(1.0,0.0,0.0); ab_glp[0] = 1.0; ab_glp[1] = 0.0; ab_glp[2] = 0.0; ab_glp[3] = 0.0; ab_glp[4] = 0.0; ab_glp[5] = 1.0; ab_glp[6] = 0.0; ab_glp[7] = 0.0; ab_glp[8] = 0.0; ab_glp[9] = 0.0; ab_glp[10] = 1.0; ab_glp[11] = 0.0; ab_glp[12] = 0.0; ab_glp[13] = 0.0; ab_glp[14] = 0.0; ab_glp[15] = 1.0; memcpy(ab_glm, ab_glp, 16*sizeof(double)); ab_glv[0] = 0; ab_glv[1] = 0; ab_glv[2] = 640; ab_glv[3] = 480; sc.Set(0.0,0.0,1.0); ec.Set(0.0,0.0,1.0); memset(ab_crosspoint, 0, 16*sizeof(float)); } void ArcBall::GetMatrix() { glGetDoublev(GL_PROJECTION_MATRIX,ab_glp); glGetIntegerv(GL_VIEWPORT,ab_glv); } /** find the intersection with the plane through the visible edge*/ void ArcBall::EdgeCoords(CVector m, CVector &V) { // find the intersection of the edge plane and the ray t = (ab_edge - ab_zoom) / (ab_eyedir.dot(m)); aa = ab_eye + (m*t); // find the direction of the eye-axis from that point // along the edge plane c = (ab_eyedir * ab_edge) - aa; // find the intersection of the sphere with the ray going from // the plane outside the sphere toward the eye-axis. ac = aa.dot(c); c2 = c.dot(c); q = ( 0.0 - ac - sqrt( ac*ac - c2*(aa.dot(aa)-ab_sphere2 ))) / c2; V = aa+(c*q); V.Normalize(); } /** update current arcball rotation*/ void ArcBall::Move(int mx, int my) { if(ab_planar) { PlanarCoords(mx,my, ab_curr); if(ab_curr == ab_start) return; // d is motion since the last position d = ab_curr - ab_start; angle = d.VAbs(); cosa2 = cos(angle/2.0); sina2 = sin(angle/2.0); // p is perpendicular to d p = (ab_out*d.x)-(ab_up*d.y); p.Normalize(); p *= sina2; Quat.Set(cosa2, p.x, p.y, p.z); QuattoMatrix(ab_next, Quat); QuatNext(ab_quat,ab_last,ab_next); // planar style only ever relates to the last point QuatCopy(ab_last,ab_quat); ab_start = ab_curr; } else { SphereCoords((double)mx,(double)my, ab_curr); if(ab_curr == ab_start) { // avoid potential rare divide by tiny QuatCopy(ab_quat,ab_last); return; } // use a dot product to get the angle between them // use a cross product to get the vector to rotate around cosa = ab_start.dot(ab_curr); sina2 = sqrt((1.0 - cosa)*0.5); cosa2 = sqrt((1.0 + cosa)*0.5); angle = acos(cosa2)*180.0/PI; p = (ab_start*ab_curr); p.Normalize(); p *=sina2; Quat.Set(cosa2, p.x, p.y, p.z); QuattoMatrix(ab_next, Quat); // update the rotation matrix QuatNext(ab_quat,ab_last,ab_next); } } /** reset the rotation matrix*/ void ArcBall::QuatIdentity(float* q) { q[0] =1; q[1] =0; q[2] =0; q[3] =0; q[4] =0; q[5] =1; q[6] =0; q[7] =0; q[8] =0; q[9] =0; q[10]=1; q[11]=0; q[12]=0; q[13]=0; q[14]=0; q[15]=1; } /** copy a rotation matrix*/ void ArcBall::QuatCopy(float* dst, float* src) { dst[0]=src[0]; dst[1]=src[1]; dst[2] =src[2]; dst[4]=src[4]; dst[5]=src[5]; dst[6] =src[6]; dst[8]=src[8]; dst[9]=src[9]; dst[10]=src[10]; } /** convert the quaternion into a rotation matrix*/ void ArcBall::QuattoMatrix(float* q, Quaternion Qt) { x2 = Qt.qx*Qt.qx; y2 = Qt.qy*Qt.qy; z2 = Qt.qz*Qt.qz; xy = Qt.qx*Qt.qy; xz = Qt.qx*Qt.qz; yz = Qt.qy*Qt.qz; wx = Qt.a*Qt.qx; wy = Qt.a*Qt.qy; wz = Qt.a*Qt.qz; q[0] = (float)(1 - 2*y2 - 2*z2); q[1] = (float)(2*xy + 2*wz); q[2] = (float)(2*xz - 2*wy); q[4] = (float)(2*xy - 2*wz); q[5] = (float)(1 - 2*x2 - 2*z2); q[6] = (float)(2*yz + 2*wx); q[8] = (float)(2*xz + 2*wy); q[9] = (float)(2*yz - 2*wx); q[10]= (float)(1 - 2*x2 - 2*y2); } /** multiply two rotation matrices*/ void ArcBall::QuatNext(float* dest, float* left, float* right) { dest[0] = left[0]*right[0] + left[1]*right[4] + left[2] *right[8]; dest[1] = left[0]*right[1] + left[1]*right[5] + left[2] *right[9]; dest[2] = left[0]*right[2] + left[1]*right[6] + left[2] *right[10]; dest[4] = left[4]*right[0] + left[5]*right[4] + left[6] *right[8]; dest[5] = left[4]*right[1] + left[5]*right[5] + left[6] *right[9]; dest[6] = left[4]*right[2] + left[5]*right[6] + left[6] *right[10]; dest[8] = left[8]*right[0] + left[9]*right[4] + left[10]*right[8]; dest[9] = left[8]*right[1] + left[9]*right[5] + left[10]*right[9]; dest[10]= left[8]*right[2] + left[9]*right[6] + left[10]*right[10]; } /** reset the arcball*/ void ArcBall::Reset() { QuatIdentity(ab_quat); QuatIdentity(ab_last); } /** affect the arcball's orientation on openGL*/ void ArcBall::Rotate() { glMultMatrixf(ab_quat); } void ArcBall::RotateCrossPoint() { aa.Set(1.0, 0.0, 0.0); cosa = aa.dot(ab_curr); sina2 = sqrt((1.0 - cosa)*0.5); cosa2 = sqrt((1.0 + cosa)*0.5); angle = 2.0*acos(cosa2)*180.0/PI; p = aa * ab_curr; p.Normalize(); } void ArcBall::SetQuat(Quaternion Qt) { if(qAbs(Qt.a)<=1.0) angle = 2.0*acos(Qt.a) * 180.0/PI; Quat.a = Qt.a; Quat.qx = Qt.qx; Quat.qy = Qt.qy; Quat.qz = Qt.qz; QuattoMatrix(ab_quat, Quat); } void ArcBall::SetQuat(double r, double qx, double qy, double qz) { if(qAbs(r)<=1.0) angle = 2.0*acos(r) * 180.0/PI; Quat.a = r; Quat.qx = qx; Quat.qy = qy; Quat.qz = qz; QuattoMatrix(ab_quat, Quat); } void ArcBall::SetZoom(double radius, CVector eye, CVector up) { ab_eye = eye; // store eye vector ab_zoom2 = ab_eye.dot(ab_eye); ab_zoom = sqrt(ab_zoom2); // store eye distance ab_sphere = radius; // sphere radius ab_sphere2 = ab_sphere * ab_sphere; ab_eyedir = ab_eye * (1.0 / ab_zoom); // distance to eye ab_edge = ab_sphere2 / ab_zoom; // plane of visible edge if(ab_sphere <= 0.0) // trackball mode { ab_planar = true; ab_up = up; ab_out = (ab_eyedir * ab_up); ab_planedist = (0.0 - ab_sphere) * ab_zoom; } else ab_planar = false; } void ArcBall::PlanarCoords(int const &mx, int const &my, CVector &V) { // gluUnProject(mx,my,0,ab_glm,ab_glp,ab_glv,&ax,&ay,&az); ClientToGL(mx, my, ax, ay); m.Set(ax- ab_eye.x, ay- ab_eye.y, az- ab_eye.z); // intersect the point with the trackball plane t = (ab_planedist - ab_zoom)*1.0 / (ab_eyedir.dot(m)); d = ab_eye + m*t; V.Set(d.dot(ab_up),d.dot(ab_out),0.0); } void ArcBall::SphereCoords(int const &mx, int const &my, CVector &V) { // find the intersection with the sphere // gluUnProject(mx, my, 0.0, ab_glm, ab_glp, ab_glv, &ax,&ay); ClientToGL(mx, my, ax, ay); ax -= *m_pOffx ; ay -= *m_pOffy ; if(ab_sphere2>ax*ax+ay*ay) V.Set(ax,ay,sqrt(ab_sphere2-ax*ax-ay*ay)); else V.Set(ax,ay,0.0); // else return EdgeCoords(ax, ay); V.Normalize(); } /** begin arcball rotation*/ void ArcBall::Start(int mx, int my) { // saves a copy of the current rotation for comparison QuatCopy(ab_last,ab_quat); if(ab_planar) PlanarCoords(mx, my, ab_start); else SphereCoords(mx, my, ab_start); ab_curr = ab_start; } /** Convert screen coordinates to GL view coordinates*/ void ArcBall::ClientToGL(int const &x, int const &y, double &glx, double &gly) { double h2, w2; if(!m_p3dWidget) return; ThreeDWidget *p3dWidget = (ThreeDWidget*)m_p3dWidget; h2 = (double)p3dWidget->m_rCltRect.height() /2.0; w2 = (double)p3dWidget->m_rCltRect.width() /2.0; if(w2>h2) { glx = ((double)x - w2) / w2; gly = ((double)y - h2) / w2; } else { glx = ((double)x - w2) / h2; gly = ((double)y - h2) / h2; } } xflr5-6.09-06/src/objects/SplineFoil.cpp000644 001750 000144 00000025005 12247174403 021264 0ustar00techwinderusers000000 000000 /**************************************************************************** Spline Foil Class Copyright (C) 2003-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "math.h" #include "SplineFoil.h" #include "../globals.h" /** * The public costructor. */ SplineFoil::SplineFoil() { m_FoilStyle = 0; m_FoilWidth = 1; m_FoilColor = QColor(119, 183, 83); m_OutPoints = 0; m_bVisible = true; m_bOutPoints = false; m_bModified = false; m_bCenterLine = false; m_Intrados.SetSplineParams(m_FoilStyle, m_FoilWidth, m_FoilColor); m_Extrados.SetSplineParams(m_FoilStyle, m_FoilWidth, m_FoilColor); m_bSymetric = false; } /** * Overloaded constructor. */ SplineFoil::SplineFoil(SplineFoil *pSF) { Copy(pSF); } /** * Sets the display style from the input parameters. * @param style the index of the style. * @param width the curve's width. * @param color te curve's color. */ void SplineFoil::SetCurveParams(int style, int width, QColor color) { m_FoilStyle = style; m_FoilWidth = width; m_FoilColor = color; m_Intrados.SetSplineParams(style, width, color); m_Extrados.SetSplineParams(style, width, color); } /** * Initializes the SplineFoil object with stock data. */ void SplineFoil::InitSplineFoil() { m_bModified = false; m_strFoilName = QObject::tr("Spline Foil"); m_Extrados.SetSplineParams(m_FoilStyle, m_FoilWidth, m_FoilColor); m_Extrados.m_CtrlPoint.clear(); m_Extrados.InsertPoint(0.0 , 0.0); m_Extrados.InsertPoint(0.0 , 0.00774066); m_Extrados.InsertPoint(0.0306026, 0.0343829); m_Extrados.InsertPoint(0.289036 , 0.0504014); m_Extrados.InsertPoint(0.576000, 0.0350933); m_Extrados.InsertPoint(0.736139 , 0.0269428); m_Extrados.InsertPoint(1. , 0.); m_Intrados.SetSplineParams(m_FoilStyle, m_FoilWidth, m_FoilColor); m_Intrados.m_CtrlPoint.clear(); m_Intrados.InsertPoint(0. , 0.); m_Intrados.InsertPoint(0. , -0.00774066); m_Intrados.InsertPoint(0.0306026, -0.0343829); m_Intrados.InsertPoint(0.289036 , -0.0504014); m_Intrados.InsertPoint(0.576000, -0.0350933); m_Intrados.InsertPoint(0.736139 , -0.0269428); m_Intrados.InsertPoint(1. , 0.); CompMidLine(); m_OutPoints = m_Extrados.m_iRes + m_Intrados.m_iRes; } /** * Calculates the SplineFoil's mid-camber line and stores the resutls in the memeber array. * @return */ void SplineFoil::CompMidLine() { double x, yex, yin; m_fThickness = 0.0; m_fCamber = 0.0; m_fxCambMax = 0.0; m_fxThickMax = 0.0; m_rpMid[0].x = 0.0; m_rpMid[0].y = 0.0; double step = 1.0/(double)MIDPOINTCOUNT; for (int k=0; km_fThickness) { m_fThickness = qAbs(yex-yin); m_fxThickMax = x; } if(qAbs(m_rpMid[k].y)>qAbs(m_fCamber)) { m_fCamber = m_rpMid[k].y; m_fxCambMax = x; } } m_rpMid[MIDPOINTCOUNT-1].x = 1.0; m_rpMid[MIDPOINTCOUNT-1].y = 0.0; } /** * Initializes this SplineFoil object with the data from another. * @param pSF a pointer to the source SplineFoil object. */ void SplineFoil::Copy(SplineFoil* pSF) { m_FoilColor = pSF->m_FoilColor; m_FoilStyle = pSF->m_FoilStyle; m_FoilWidth = pSF->m_FoilWidth; m_Extrados.Copy(&pSF->m_Extrados); m_Intrados.Copy(&pSF->m_Intrados); m_OutPoints = pSF->m_OutPoints; m_fCamber = pSF->m_fCamber; m_fThickness = pSF->m_fThickness; m_fxCambMax = pSF->m_fxCambMax; m_fxThickMax = pSF->m_fxThickMax; m_bSymetric = pSF->m_bSymetric; } /** * Exports the current SplineFoil to a Foil object. * @param pFoil a pointer to the existing Foil object to be loaded with the SplineFoil points. */ void SplineFoil::ExportToBuffer(Foil *pFoil) { int i; int j = m_Extrados.m_iRes; int k = m_Intrados.m_iRes; for (i=0; ix[j-i-1] = m_Extrados.m_Output[i].x; pFoil->y[j-i-1] = m_Extrados.m_Output[i].y; } for (i=1; ix[i+j-1] = m_Intrados.m_Output[i].x; pFoil->y[i+j-1] = m_Intrados.m_Output[i].y; } pFoil->n = j+k-1; memcpy(pFoil->xb, pFoil->x, sizeof(pFoil->x)); memcpy(pFoil->yb, pFoil->y, sizeof(pFoil->y)); pFoil->nb = pFoil->n; pFoil->m_FoilName = m_strFoilName; } /** * Exports the SplineFoil's output points to a text file. * @param out the QTextStream to which the output is directed. */ void SplineFoil::ExportToFile(QTextStream &out) { m_Extrados.Export(out, true); m_Intrados.Export(out, false); } /** * Loads or saves the data of this SplineFoil to a binary file * @param ar the QDataStream object from/to which the data should be serialized * @param bIsStoring true if saving the data, false if loading * @return true if the operation was successful, false otherwise */ bool SplineFoil::Serialize(QDataStream &ar, bool bIsStoring) { float f,x,y; int ArchiveFormat,k,n; if(bIsStoring) { ar << 100306; // 100306 : changed to C convention the number of control points WriteCString(ar, m_strFoilName); WriteCOLORREF(ar, m_FoilColor); ar << m_FoilStyle << m_FoilWidth; ar << m_Extrados.m_CtrlPoint.size(); ar << m_Extrados.m_iDegree; for (k=0; k> ArchiveFormat; if(ArchiveFormat < 100000 || ArchiveFormat > 110000) return false; ReadCString(ar, m_strFoilName); m_strFoilName = QObject::tr("Spline Foil"); ReadCOLORREF(ar, m_FoilColor); ar >>m_FoilStyle >> m_FoilWidth; m_Extrados.SetSplineParams(m_FoilStyle, m_FoilWidth, m_FoilColor); m_Intrados.SetSplineParams(m_FoilStyle, m_FoilWidth, m_FoilColor); ar >> n;// m_Extrados.m_iCtrlPoints; m_Extrados.m_CtrlPoint.clear(); ar >> m_Extrados.m_iDegree; for (k=0; k> x; ar >> y; m_Extrados.m_CtrlPoint.append(CVector(x,y,0.0)); } if(ArchiveFormat<100306) { ar >> f; ar >> f; } ar >> n;// m_Intrados.m_iCtrlPoints; m_Intrados.m_CtrlPoint.clear(); ar >> m_Intrados.m_iDegree; for (k=0; k> x; ar >> y; m_Intrados.m_CtrlPoint.append(CVector(x,y,0.0)); } if(ArchiveFormat<100306) { ar >> f; ar >> f; } ar >> m_Extrados.m_iRes >> m_Intrados.m_iRes; ar >> k; if(k!=0 && k!=1) return false; if(k) m_bVisible = true; else m_bVisible = false; ar >> k; if(k!=0 && k!=1) return false; if(k) m_bOutPoints = true; else m_bOutPoints = false; ar >> k; if(k!=0 && k!=1) return false; if(k) m_bCenterLine = true; else m_bCenterLine = false; m_Extrados.SplineKnots(); m_Extrados.SplineCurve(); m_Intrados.SplineKnots(); m_Intrados.SplineCurve(); UpdateSplineFoil(); m_bModified = false; return true; } } /** * Updates the mid camber line and the number of points after a modification. */ void SplineFoil::UpdateSplineFoil() { CompMidLine(); m_OutPoints = m_Extrados.m_iRes + m_Intrados.m_iRes; } /** * Draws the SplineFoil's control points. * @param painter a reference to the QPainter object with which to draw * @param scalex the scale of the view in the x direction * @param scaley the scale of the view in the y direction * @param Offset the postion of the SplineFoil's leading edge point */ void SplineFoil::DrawCtrlPoints(QPainter &painter, double scalex, double scaley, QPoint Offset) { m_Extrados.DrawCtrlPoints(painter, scalex, scaley, Offset); m_Intrados.DrawCtrlPoints(painter, scalex, scaley, Offset); } /** * Draws the SplineFoil's output points. * @param painter a reference to the QPainter object with which to draw * @param scalex the scale of the view in the x direction * @param scaley the scale of the view in the y direction * @param Offset the postion of the SplineFoil's leading edge point */ void SplineFoil::DrawOutPoints(QPainter & painter, double scalex, double scaley, QPoint Offset) { m_Extrados.DrawOutputPoints(painter, scalex, scaley, Offset); m_Intrados.DrawOutputPoints(painter, scalex, scaley, Offset); } /** * Draws the SplineFoil's curves. * @param painter a reference to the QPainter object with which to draw * @param scalex the scale of the view in the x direction * @param scaley the scale of the view in the y direction * @param Offset the postion of the SplineFoil's leading edge point */ void SplineFoil::DrawFoil(QPainter &painter, double scalex, double scaley, QPoint Offset) { m_Extrados.DrawSpline(painter, scalex, scaley, Offset); m_Intrados.DrawSpline(painter, scalex, scaley, Offset); } /** * Draws the SplineFoil's mid camber line. * @param painter a reference to the QPainter object with which to draw * @param scalex the scale of the view in the x direction * @param scaley the scale of the view in the y direction * @param Offset the postion of the SplineFoil's leading edge point */ void SplineFoil::DrawMidLine(QPainter &painter, double scalex, double scaley, QPoint Offset) { painter.save(); int k; QPoint From, To; QPen MidPen(m_FoilColor); MidPen.setStyle(Qt::DashLine); MidPen.setWidth(1); painter.setPen(MidPen); From = QPoint((int)(m_rpMid[0].x*scalex) + Offset.x(), (int)(-m_rpMid[0].y*scaley) + Offset.y()); for (k=1; k /** *@brief * This class defines the polar object for the 2D analysis of foils * The class stores both the analysis parameters and the analysis results. Each instance of this class is uniquely associated to an instance of a Foil object. */ class Polar { friend class MainFrame; friend class QMiarex; friend class QXDirect; friend class BatchDlg; friend class BatchThreadDlg; friend class XFoilTask; friend class XFoilAnalysisDlg; friend class EditPlrDlg; friend class ObjectPropsDlg; friend class XFoil; private: void AddData(OpPoint* pOpPoint); void AddData(void* ptrXFoil); void ExportPolar(QTextStream &out, enumTextFileType FileType, bool bDataOnly=false); void GetPolarProperties(QString &PolarProperties, bool bData=false); void ResetPolar(); Polar(); bool Serialize(QDataStream &ar, bool bIsStoring); void AddPoint(double Alpha, double Cd, double Cdp, double Cl, double Cm, double Xtr1, double Xtr2, double HMom, double Cpmn, double Reynolds, double XCp); void Copy(Polar *pPolar); bool isVisible(){return m_bIsVisible;} bool pointsVisible(){return m_bShowPoints;} static void GetPlrVariableName(int iVar, QString &Name); protected: void Remove(int i); void Insert(int i); double GetCm0(); public: double GetZeroLiftAngle(); void GetAlphaLimits(double &amin, double &amax); void GetClLimits(double &Clmin, double &Clmax); void GetLinearizedCl(double &Alpha0, double &slope); QString m_FoilName; /**< the name of the parent Foil to which this Polar object is attached */ double m_Reynolds; /**< the Reynolds number for a type 4 analysis */ enumPolarType m_PolarType; /**< the Polar type */ QList m_Alpha; /**< the array of aoa values, in degrees */ QList m_Cl; /**< the array of lift coefficients */ QList m_XCp; /**< the array of centre of pressure positions */ QList m_Cd; /**< the array of drag coefficients */ QList m_Cdp; /**< the array of Cdp ? */ QList m_Cm; /**< the array of pitching moment coefficients */ QList m_XTr1; /**< the array of transition points on the top surface */ QList m_XTr2; /**< the array of transition points on the top surface */ QList m_HMom; /**< the array of flap hinge moments */ QList m_Cpmn; /**< the array of Cpmn ? */ QList m_ClCd; /**< the array of glide ratios */ QList m_Cl32Cd; /**< the array of power factors*/ QList m_RtCl; /**< the array of aoa values */ QList m_Re; /**< the array of Re coefficients */ private: QString m_PlrName; /**< the Polar's name, used for references */ int m_ReType; /**< the type of Reynolds number input, cf. XFoil documentation */ int m_MaType; /**< the type of Mach number input, cf. XFoil documentation */ double m_ASpec; /**< the specified aoa in the case of Type 4 polars */ double m_Mach; /**< the Mach number */ double m_ACrit; /**< the transition criterion */ double m_XTop; /**< the point of forced transition on the upper surface */ double m_XBot; /**< the point of forced transition on the lower surface */ bool m_bIsVisible; /**< true if the Polar's curve is visible in the active view */ bool m_bShowPoints; /**< true if the Polar's curve points are visible in the active graphs */ int m_Style; /**< the index of the style with which to draw the Polar's curve */ int m_Width; /**< the width with which to draw the Polar's curve */ QColor m_Color; /**< the color with which to draw the Polar's curve */ }; #endif xflr5-6.09-06/src/objects/PointMass.h000644 001750 000144 00000003614 12247174403 020604 0ustar00techwinderusers000000 000000 /**************************************************************************** PointMass Class Copyright (C) 2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef POINTMASS_H #define POINTMASS_H #include #include "CVector.h" class PointMass { public: /** The public constructor */ PointMass(); /** Overloaded public constructor */ PointMass(PointMass *pPtMass) { m_Mass = pPtMass->m_Mass; m_Position = pPtMass->m_Position; m_Tag = pPtMass->m_Tag; } /** Overloaded public constructor */ PointMass(double const &m, CVector const &p, QString const &tag) { m_Mass = m; m_Position = p; m_Tag = tag; } /** Returns the the value of the mass */ double mass() {return m_Mass;} /** Returns the the position of the mass */ CVector position() {return m_Position;} /** Returns the the tag of the mass */ QString tag() {return m_Tag;} double m_Mass; /**< the value of the point mass, in kg */ CVector m_Position; /**< the absolute position of the point mass */ QString m_Tag; /**< the description of the point mass */ }; #endif // POINTMASS_H xflr5-6.09-06/src/objects/Spline.h000644 001750 000144 00000007642 12247174403 020126 0ustar00techwinderusers000000 000000 /**************************************************************************** Spline Class Copyright (C) 1996 Paul Bourke http://astronomy.swin.edu.au/~pbourke/curves/spline/ Copyright (C) 2003 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** *@file This file implements the spline class used in foil direct and inverse design. */ #ifndef SPLINE_H #define SPLINE_H #include #include #include #include #include "../objects/CVector.h" #include "../params.h" /** *@class Spline *@brief The class which defines the 2D spline object. The spline is used in direct foil design to represent upper and lower surfaces, and in XInverse foil design to define the specification curve. Based on the code provided by Paul Bourke. */ class Spline { // friend class SplineFoil; // friend class QXInverse; // friend class InverseOptionsDlg; public: Spline(); void DrawSpline(QPainter & painter, double const &scalex, double const &scaley, QPoint const &Offset); void DrawCtrlPoints(QPainter & painter, double const &scalex, double const &scaley, QPoint const &Offset); void DrawOutputPoints(QPainter & painter, double const &scalex, double const &scaley, QPoint const &Offset); bool InsertPoint(double const &x, double const &y); bool RemovePoint(int const &k); int IsControlPoint(CVector const &Real); int IsControlPoint(double const &x, double const &y, double const &zx, double const &zy); int IsControlPoint(CVector const &Real, double const &ZoomFactor); double SplineBlend(int const &i, int const &p, double const &t); double GetY(double const &x); void Copy(Spline *pSpline); void CopySymetric(Spline *pSpline); void Export(QTextStream &out, bool bExtrados); void SplineCurve(); void SplineKnots(); void SetStyle(int style); void SetWidth(int width); void SetColor(QColor color); void SetSplineParams(int style, int width, QColor color); QColor color() {return m_Color;} int style() {return m_Style;} int width() {return m_Width;} int m_iHighlight; /**< the index of the currently highlighted control point, i.e. the point over which the mouse hovers, or -1 of none. */ int m_iSelect; /**< the index of the currently selected control point, i.e. the point on which the user has last click, or -1 if none. */ int m_iRes; /**< the number of output points to draw the spline */ int m_iDegree; /**< the spline's degree */ double m_PtWeight; /**< the common weight of all control points. Default is 1. The higher the value, the more the curve will be pulled towards the control points. */ QList m_knot; /**< the array of the values of the spline's knot */ QList m_CtrlPoint; /**< the array of the positions of the spline's control points */ CVector m_Output[IQX2]; /**< the array of output points, size of which is m_iRes @todo use a QVarLengthArray or a QList*/ private: QColor m_Color; /**< the spline's display color */ int m_Style; /**< the index of the spline's style */ int m_Width; /**< the width of the spline */ }; #endif xflr5-6.09-06/src/objects/Wing.cpp000644 001750 000144 00000232752 12247174403 020135 0ustar00techwinderusers000000 000000 /**************************************************************************** Wing Class Copyright (C) 2005-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include "Wing.h" #include "../mainframe.h" #include "../globals.h" #include "../miarex/Miarex.h" #include "../miarex/LLTAnalysisDlg.h" void* Wing::s_pMiarex = NULL; void* Wing::s_p3DPanelDlg = NULL; bool Wing::s_bVLMSymetric; /** * The public constructor. */ Wing::Wing() { memset(m_Ai, 0, sizeof(m_Ai)); memset(m_Twist, 0, sizeof(m_Twist)); memset(m_Cl, 0, sizeof(m_Cl)); memset(m_PCd, 0, sizeof(m_PCd)); memset(m_ICd, 0, sizeof(m_ICd)); memset(m_Cm, 0, sizeof(m_Cm)); memset(m_CmAirf, 0, sizeof(m_CmAirf)); memset(m_XCPSpanAbs, 0, sizeof(m_XCPSpanAbs)); memset(m_XCPSpanRel, 0, sizeof(m_XCPSpanRel)); memset(m_Re, 0, sizeof(m_Re)); memset(m_Chord, 0, sizeof(m_Chord)); memset(m_Offset, 0, sizeof(m_Offset)); memset(m_XTrTop, 0, sizeof(m_XTrTop)); memset(m_XTrBot, 0, sizeof(m_XTrBot)); memset(m_BendingMoment, 0, sizeof(m_BendingMoment)); memset(m_Twist, 0, sizeof(m_Twist)); memset(m_xPanel, 0, MAXCHORDPANELS*sizeof(double)); memset(m_xHinge, 0, MAXCHORDPANELS*sizeof(double)); memset(m_SpanPos, 0, sizeof(m_SpanPos)); memset(m_StripArea, 0, sizeof(m_StripArea)); m_CoG.Set(0.0,0.0,0.0); m_CoGIxx = m_CoGIyy = m_CoGIzz = m_CoGIxz = 0.0; m_VolumeMass = m_TotalMass = 0.0; ClearPointMasses(); m_bIsFin = false; m_bDoubleFin = false; m_bSymFin = false; m_bDoubleSymFin = false; m_bSymetric = true; m_bWingOut = false; s_bVLMSymetric = false; m_WingName = QObject::tr("Wing Name"); m_WingDescription = ""; m_WingColor.setHsv((int)(((double)qrand()/(double)RAND_MAX)*255), 31, 203, 255); m_QInf0 = 0.0; m_pWingPanel = NULL; m_CL = 0.0; m_CDv = 0.0; m_CDi = 0.0; m_GYm = 0.0; m_IYm = 0.0; m_GCm = 0.0; m_GRm = 0.0; m_VCm = 0.0; m_VYm = 0.0; m_CP.Set(0.0, 0.0, 0.0); m_AVLIndex = -(int)(qrand()/10000);//improbable value... m_MatSize = 0; m_NSurfaces = 0; m_AR = 0.0;// Aspect ratio m_TR = 0.0;// Taper ratio m_GChord = 0.0;// mean geometric chord m_MAChord = 0.0;// mean aero chord m_yMac = 0.0; m_ProjectedArea = 0.0; m_ProjectedSpan = 0.0; m_nFlaps = 0; ClearWingSections(); AppendWingSection(.180, .0, 0.0, 1.0, 0.000, 13, 19, COSINE, INVERSESINE, "", ""); AppendWingSection(.110, .0, 1.0, 1.0, 0.070, 13, 5, COSINE, UNIFORM, "", ""); ComputeGeometry(); double length = Length(0); for (int is=0; is=0; iws--) { delete m_WingSection.at(iws); m_WingSection.removeAt(iws); } } /** Destroys the PointMass objects in good order to avoid memory leaks */ void Wing::ClearPointMasses() { for(int ipm=m_PointMass.size()-1; ipm>=0; ipm--) { delete m_PointMass.at(ipm); m_PointMass.removeAt(ipm); } } /** * Imports the wing geometry from a text file. * @param path_to_file the path to the filename as a QString */ void Wing::ImportDefinition(QString path_to_file) { QFile fp(path_to_file); double ypos; double chord; double offset; double dihedral; double twist; int nx; int ny; int px, py; enumPanelDistribution x_pan_dist; enumPanelDistribution y_pan_dist; char right_buff[512]; char left_buff[512]; unsigned counter = 0; try{ if (!fp.open(QIODevice::ReadOnly)) { QMessageBox::warning(0, QObject::tr("Warning"), QObject::tr("Could not open the file for reading")); return; } else { QTextStream infile(&fp); ClearWingSections(); this->m_WingName = infile.readLine(); while (true) { counter++; infile >> ypos >> chord >> offset >> dihedral >> twist >> nx >> ny; infile >> px >> py; if(px ==2) x_pan_dist = INVERSESINE; else if(px == 1) x_pan_dist = COSINE; else if(px == -2) x_pan_dist = SINE; else x_pan_dist = UNIFORM; if(py ==2) y_pan_dist = INVERSESINE; else if(py == 1) y_pan_dist = COSINE; else if(py == -2) y_pan_dist = SINE; else y_pan_dist = UNIFORM; infile >> right_buff >> left_buff; if (infile.atEnd()) { fp.close(); break; } //Append the sections convert from mm to m if (!AppendWingSection(chord, twist, ypos, dihedral, offset, nx, ny, x_pan_dist, y_pan_dist, QString(QString(QLatin1String(right_buff)).replace(QString("/_/"), QString(" "))), QString(QString(QLatin1String(left_buff)).replace(QString("/_/"), QString(" "))) )) { QMessageBox::warning(0,QObject::tr("Warning"),QObject::tr("Total number of wing sections exceeds MAXSPANSECTIONS.\nWing will be truncated.\n")); break; } } } //Build the Geometry ComputeGeometry(); double length = Length(0); for (int is=0; ism_WingName << endl; for (int is=0; is0.0) m_TR = RootChord()/TipChord(); else m_TR = 99999.0; //calculate the number of flaps m_nFlaps = 0; if(QMiarex::s_MinPanelSize>0.0) MinPanelSize = QMiarex::s_MinPanelSize; else MinPanelSize = m_PlanformSpan; for (int is=1; ism_bTEFlap && pFoilB->m_bTEFlap && qAbs(YPosition(is)-YPosition(is-1))>MinPanelSize) m_nFlaps++; } pFoilA = MainFrame::foil(LeftFoil(is-1)); pFoilB = MainFrame::foil(LeftFoil(is)); if(pFoilA && pFoilB) { if(pFoilA->m_bTEFlap && pFoilB->m_bTEFlap && qAbs(YPosition(is)-YPosition(is-1))>MinPanelSize) m_nFlaps++; } } } #define NXSTATIONS 20 #define NYSTATIONS 40 /** * Calculates and returns the inertia properties of the structure based on the object's mass and on the existing geometry * The mass is assumed to have been set previously. * Mass = mass of the structure, excluding point masses * @param &CoG a reference to the CoG point, as a result of the calculation * @param &CoGIxx xx axis component of the inertia tensor, calculated at the CoG * @param &CoGIyy yy axis component of the inertia tensor, calculated at the CoG * @param &CoGIzz zz axis component of the inertia tensor, calculated at the CoG * @param &CoGIxz xz axis component of the inertia tensor, calculated at the CoG */ void Wing::ComputeVolumeInertia(CVector &CoG, double &CoGIxx, double &CoGIyy, double &CoGIzz, double &CoGIxz) { static double ElemVolume[NXSTATIONS*NYSTATIONS*MAXSPANSECTIONS*2]; static CVector PtVolume[NXSTATIONS*NYSTATIONS*MAXSPANSECTIONS*2]; int j,k,l; double rho, LocalSpan, LocalVolume; double LocalChord, LocalArea, tau; double LocalChord1, LocalArea1, tau1; double xrel, xrel1, yrel, ElemArea; CVector ATop, ABot, CTop, CBot, PointNormal, Diag1, Diag2; CVector PtC4, Pt, Pt1; CoG.Set(0.0, 0.0, 0.0); CoGIxx = CoGIyy = CoGIzz = CoGIxz = 0.0; //sanity check // CVector CoGCheck(0.0,0.0,0.0); double CoGIxxCheck, CoGIyyCheck, CoGIzzCheck, CoGIxzCheck; CoGIxxCheck = CoGIyyCheck = CoGIzzCheck = CoGIxzCheck = 0.0; double recalcMass = 0.0; double recalcVolume = 0.0; double checkVolume = 0.0; //use 20 spanwise stations per wing panel to discretize the weight //and 10 stations in the x direction int NYStations = NYSTATIONS; int NXStations = NXSTATIONS; ComputeGeometry(); //the mass density is assumed to be homogeneous //the local weight is proportional to the chord x foil area //the foil's area is interpolated //we consider the whole wing, i.e. all left and right surfaces //note : in avl documentation, each side is considered separately //first get the CoG - necessary for future application of Huygens/Steiner theorem int p = 0; for (j=0; jPRECISION) ElemVolume[p] = ElemArea * LocalSpan; else { //no area, means that the foils have not yet been defined for this surface // so just count a unit volume, temporary ElemVolume[p] = 1.0; } checkVolume += ElemVolume[p]; CoG.x += ElemVolume[p] * PtVolume[p].x; CoG.y += ElemVolume[p] * PtVolume[p].y; CoG.z += ElemVolume[p] * PtVolume[p].z; p++; } } } if(checkVolume>PRECISION) rho = m_VolumeMass/checkVolume; else rho = 0.0; if(checkVolume>0.0) CoG *= 1.0/ checkVolume; else CoG.Set(0.0, 0.0, 0.0); // CoG is the new origin for inertia calculation p=0; for (j=0; jmass(); m_CoG += m_PointMass[im]->position() * m_PointMass[im]->mass(); } if(m_TotalMass>0.0) m_CoG = m_CoG/m_TotalMass; else m_CoG.Set(0.0,0.0,0.0); // The CoG position is now available, so calculate the inertia w.r.t the CoG // using Huygens theorem //LA is the displacement vector from the centre of mass to the new axis LA = m_CoG-VolumeCoG; m_CoGIxx = Ixx + m_VolumeMass * (LA.y*LA.y+ LA.z*LA.z); m_CoGIyy = Iyy + m_VolumeMass * (LA.x*LA.x+ LA.z*LA.z); m_CoGIzz = Izz + m_VolumeMass * (LA.x*LA.x+ LA.y*LA.y); m_CoGIxz = Ixz - m_VolumeMass * LA.x*LA.z; //add the contribution of point masses to total inertia for(int im=0; imposition() - m_CoG; m_CoGIxx += m_PointMass[im]->mass() * (LA.y*LA.y + LA.z*LA.z); m_CoGIyy += m_PointMass[im]->mass() * (LA.x*LA.x + LA.z*LA.z); m_CoGIzz += m_PointMass[im]->mass() * (LA.x*LA.x + LA.y*LA.y); m_CoGIxz -= m_PointMass[im]->mass() * (LA.x*LA.z); } } /** * Constructs the surface objects based on the WingSection data. * The position and orientation are defined in the plane object * The surfaces are constructed from root to tip, and re-ordered from let tip to right tip * One surface object for each of the wing's panels * A is the surface's left side, B is the right side * @param T the translation to be appied to the wing geometry * @param XTilt the rotation in degrees around the x-axis; used in the case of fins * @param YTilt the rotation in degrees arouns the y-axi; used for wing or elevator tilt */ void Wing::CreateSurfaces(CVector const &T, double XTilt, double YTilt) { int j, nSurf; CVector PLA, PTA, PLB, PTB, offset, T1; CVector Trans(T.x, 0.0, T.z); CVector O(0.0,0.0,0.0); CVector VNormal[MAXSPANSECTIONS+1], VNSide[MAXSPANSECTIONS+1]; double MinPanelSize; if(QMiarex::s_MinPanelSize>0.0) MinPanelSize = QMiarex::s_MinPanelSize; else MinPanelSize = 0.0; m_NSurfaces = 0; m_MatSize = 0; //define the normal to each surface nSurf=0; VNormal[0].Set(0.0, 0.0, 1.0); VNSide[0].Set(0.0, 0.0, 1.0); for(int is=0; is MinPanelSize) { VNormal[nSurf].Set(0.0, 0.0, 1.0); VNormal[nSurf].RotateX(O, Dihedral(is)); nSurf++; } } m_NSurfaces = nSurf; //define the normals at panel junctions : average between the normals of the two connecting sufaces for(j=0; j MinPanelSize) { m_Surface[iSurf].m_pFoilA = MainFrame::foil(LeftFoil(jss+1)); m_Surface[iSurf].m_pFoilB = MainFrame::foil(LeftFoil(jss)); m_Surface[iSurf].m_Length = YPosition(jss+1) - YPosition(jss); PLA.x = Offset(jss+1); PLB.x = Offset(jss); PLA.y = -YPosition(jss+1); PLB.y = -YPosition(jss); PLA.z = 0.0; PLB.z = 0.0; PTA.x = PLA.x+Chord(jss+1); PTB.x = PLB.x+Chord(jss); PTA.y = PLA.y; PTB.y = PLB.y; PTA.z = 0.0; PTB.z = 0.0; m_Surface[iSurf].m_LA.Copy(PLA); m_Surface[iSurf].m_TA.Copy(PTA); m_Surface[iSurf].m_LB.Copy(PLB); m_Surface[iSurf].m_TB.Copy(PTB); m_Surface[iSurf].SetNormal(); // is (0,0,1) m_Surface[iSurf].RotateX(m_Surface[iSurf].m_LB, -Dihedral(jss)); m_Surface[iSurf].NormalA.Set(VNSide[nSurf+1].x, -VNSide[nSurf+1].y, VNSide[nSurf+1].z); m_Surface[iSurf].NormalB.Set(VNSide[nSurf].x, -VNSide[nSurf].y, VNSide[nSurf].z); m_Surface[iSurf].m_TwistA = Twist(jss+1); m_Surface[iSurf].m_TwistB = Twist(jss); m_Surface[iSurf].SetTwist1(); if(jss>0) { //translate the surface to the left tip of the previous surface T1 = m_Surface[iSurf+1].m_LA - m_Surface[iSurf].m_LB; m_Surface[iSurf].Translate(0.0,T1.y,T1.z); // m_Surface[is].m_LB = m_Surface[is+1].m_LA; // m_Surface[is].m_TB = m_Surface[is+1].m_TA; } nSurf++; m_Surface[iSurf].m_NXPanels = NXPanels(jss); m_Surface[iSurf].m_NYPanels = NYPanels(jss); //AVL coding + invert sine and -sine for left wing m_Surface[iSurf].m_XDistType = XPanelDist(jss); if(YPanelDist(jss) ==SINE) m_Surface[iSurf].m_YDistType = INVERSESINE; else if(YPanelDist(jss) == COSINE) m_Surface[iSurf].m_YDistType = COSINE; else if(YPanelDist(jss) == INVERSESINE) m_Surface[iSurf].m_YDistType = SINE; else m_Surface[iSurf].m_YDistType = UNIFORM; m_Surface[iSurf].CreateXPoints(); m_Surface[iSurf].SetFlap(); m_Surface[iSurf].Init(); m_Surface[iSurf].m_bIsLeftSurf = true; m_Surface[iSurf].m_bIsInSymPlane = false; --iSurf; } } m_Surface[m_NSurfaces-1].m_bIsCenterSurf = true;//previous left center surface m_Surface[m_NSurfaces].m_bIsCenterSurf = true;//next right center surface // we only need a right wing in the following cases // - if it's an 'ordinary wing' // - if it's a fin, symetrical about the fuselage x-axis // - if it's a symetrical double fin if(!m_bIsFin || (m_bIsFin && m_bSymFin) || (m_bIsFin && m_bDoubleFin)) { iSurf = nSurf; for (int jss=0; jss MinPanelSize) { m_Surface[iSurf].m_pFoilA = MainFrame::foil(RightFoil(jss)); m_Surface[iSurf].m_pFoilB = MainFrame::foil(RightFoil(jss+1)); m_Surface[iSurf].m_Length = YPosition(jss+1) - YPosition(jss); PLA.x = Offset(jss); PLB.x = Offset(jss+1); PLA.y = YPosition(jss); PLB.y = YPosition(jss+1); PLA.z = 0.0; PLB.z = 0.0; PTA.x = PLA.x+Chord(jss); PTB.x = PLB.x+Chord(jss+1); PTA.y = PLA.y; PTB.y = PLB.y; PTA.z = 0.0; PTB.z = 0.0; m_Surface[iSurf].m_LA.Copy(PLA); m_Surface[iSurf].m_TA.Copy(PTA); m_Surface[iSurf].m_LB.Copy(PLB); m_Surface[iSurf].m_TB.Copy(PTB); m_Surface[iSurf].SetNormal(); // is (0,0,1) m_Surface[iSurf].RotateX(m_Surface[iSurf].m_LA, Dihedral(jss)); m_Surface[iSurf].NormalA.Set(VNSide[iSurf-nSurf].x, VNSide[iSurf-nSurf].y, VNSide[iSurf-nSurf].z); m_Surface[iSurf].NormalB.Set(VNSide[iSurf-nSurf+1].x, VNSide[iSurf-nSurf+1].y, VNSide[iSurf-nSurf+1].z); m_Surface[iSurf].m_TwistA = Twist(jss); m_Surface[iSurf].m_TwistB = Twist(jss+1); m_Surface[iSurf].SetTwist1(); if(jss>0) { //translate the surface to the left tip of the previous surface and merge points T1 = m_Surface[iSurf-1].m_LB - m_Surface[iSurf].m_LA ; m_Surface[iSurf].Translate(0.0, T1.y, T1.z); // m_Surface[is].m_LA = m_Surface[is-1].m_LB; // m_Surface[is].m_TA = m_Surface[is-1].m_TB; } m_Surface[iSurf].m_NXPanels = NXPanels(jss); m_Surface[iSurf].m_NYPanels = NYPanels(jss); //AVL coding + invert sine and -sine for left wing m_Surface[iSurf].m_XDistType = XPanelDist(jss); m_Surface[iSurf].m_YDistType = YPanelDist(jss); m_Surface[iSurf].CreateXPoints(); m_Surface[iSurf].SetFlap(); m_Surface[iSurf].Init(); m_Surface[iSurf].m_bIsLeftSurf = false; m_Surface[iSurf].m_bIsRightSurf = true; m_Surface[iSurf].m_bIsInSymPlane = false; iSurf++; } } } CVector Or(0.0,0.0,0.0); if(!m_bIsFin || (m_bIsFin && m_bSymFin)) { m_NSurfaces*=2; for (int jSurf=0; jSurf=1) m_Surface[m_NSurfaces-1].m_bIsTipRight = true; if(m_NSurfaces>1) m_Surface[(int)(m_NSurfaces/2)-1].m_bJoinRight = true; //check for a center gap greater than 1/10mm if(YPosition(0)>0.0001) m_Surface[(int)(m_NSurfaces/2)-1].m_bJoinRight = false; if(m_bIsFin && m_bDoubleFin) m_Surface[(int)(m_NSurfaces/2)-1].m_bJoinRight = false; m_bWingOut = false; } /** * Calculates the chord lengths at each position of the NStation defined by the LLT or the Panel analysis *@param NStation the number of stations required by the analysis */ void Wing::ComputeChords(int NStation) { int j,k,m; double y, yob, tau; double x0,y0,y1,y2; double SpanPosition[MAXSPANSTATIONS]; CVector C; if(NStation !=0) {//LLT based m_NStation = NStation; for (k=0; k<=NStation; k++) { yob = cos(k*PI/NStation); y = qAbs(yob * m_PlanformSpan/2); for (int is=0; ism_NStation; m_PlanformSpan = pWing->m_PlanformSpan; m_ProjectedSpan = pWing->m_ProjectedSpan; m_PlanformArea = pWing->m_PlanformArea; m_ProjectedArea = pWing->m_ProjectedArea; m_AR = pWing->m_AR; m_TR = pWing->m_TR; m_GChord = pWing->m_GChord; m_MAChord = pWing->m_MAChord; m_WingName = pWing->m_WingName; m_bSymetric = pWing->m_bSymetric; m_bIsFin = pWing->m_bIsFin; m_bSymFin = pWing->m_bSymFin; m_bDoubleFin = pWing->m_bDoubleFin; m_bDoubleSymFin = pWing->m_bDoubleSymFin; ClearWingSections(); for (int is=0; ism_WingSection.size(); is++) { AppendWingSection(); Chord(is) = pWing->Chord(is); YPosition(is) = pWing->YPosition(is); Offset(is) = pWing->Offset(is); Length(is) = pWing->Length(is); NXPanels(is) = pWing->NXPanels(is) ; NYPanels(is) = pWing->NYPanels(is); XPanelDist(is) = pWing->XPanelDist(is); YPanelDist(is) = pWing->YPanelDist(is); Twist(is) = pWing->Twist(is); Dihedral(is) = pWing->Dihedral(is); ZPosition(is) = pWing->ZPosition(is); YProj(is) = pWing->YProj(is); RightFoil(is) = pWing->RightFoil(is); LeftFoil(is) = pWing->LeftFoil(is); } m_nFlaps = pWing->m_nFlaps; m_VolumeMass = pWing->m_VolumeMass; m_TotalMass = pWing->m_TotalMass; m_CoG = pWing->m_CoG; m_CoGIxx = pWing->m_CoGIxx; m_CoGIyy = pWing->m_CoGIyy; m_CoGIzz = pWing->m_CoGIzz; m_CoGIxz = pWing->m_CoGIxz; ClearPointMasses(); for(int im=0; imm_PointMass.size();im++) { m_PointMass.append(new PointMass(pWing->m_PointMass[im]->mass(), pWing->m_PointMass[im]->position(), pWing->m_PointMass[im]->tag())); } m_WingDescription = pWing->m_WingDescription; m_WingColor = pWing->m_WingColor; } /** * Export the wing geometry to a text file readable by AVL. * @param out the instance of the QTextStream to which the output will be directed * @param index a reference number used by AVL to idnitfy the wing * @param x the x value of the translation to be applied to the wing's geometry -unused * @param y the y value of the translation to be applied to the wing's geometry * @param z the z value of the translation to be applied to the wing's geometry -unused * @param Thetax the rotation about the x-axis to be applied to the geometry -unused * @param Thetay the rotation about the y-axis to be applied to the geometry * @return true if successful, false otherwise */ bool Wing::ExportAVLWing(QTextStream &out, int index, double x, double y, double z, double Thetax, double Thetay) { int j; QString strong, str; out << ("#=================================================\n"); out << ("SURFACE | (keyword)\n"); out << (m_WingName); out << ("\n"); out << ("#Nchord Cspace [ Nspan Sspace ]\n"); strong = QString("%1 %2\n").arg( NXPanels(0)).arg(1.0,3,'f',1); out << (strong); out << ("\n"); out << ("INDEX | (keyword)\n"); strong = QString("%1 | Lsurf\n").arg(index,3); out << (strong); if(!m_bIsFin) { out << ("\n"); out << ("YDUPLICATE\n"); out << ("0.0\n"); } else if(m_bDoubleFin) { out << ("\n"); out << ("YDUPLICATE\n"); strong = QString("%1\n").arg(y,9,'f',4); out << (strong); } out << ("\n"); out << ("SCALE\n"); out << ("1.0 1.0 1.0\n"); out << ("\n"); out << ("TRANSLATE\n"); out << ("0.0 0.0 0.0\n"); out << ("\n"); out << ("ANGLE\n"); strong = QString("%1 | dAinc\n").arg(Thetay,8,'f',3); out << (strong); out << ("\n\n"); //write only right wing surfaces since we have provided YDUPLICATE Surface ASurface; int iFlap = 1; // int iSurface = 0; int startIndex = (m_bIsFin ? 0 : (int)(m_NSurfaces/2)); for(j=startIndex; jm_FoilName +".dat\n"); out << ("\n"); if(ASurface.m_bTEFlap) { out << ("CONTROL | (keyword)\n"); str = QString("_Flap_%1 ").arg(iFlap); strong = m_WingName; strong.replace(" ", "_"); strong += str; double mean_angle = (ASurface.m_pFoilA->m_TEFlapAngle + ASurface.m_pFoilB->m_TEFlapAngle)/2.0; if(qAbs(mean_angle)>0.0) str = QString("%1 ").arg(1.0/mean_angle,5,'f',2); else str = "1.0 "; strong += str; str = QString("%1 %2 %3 %4 -1.0 ") .arg(ASurface.m_pFoilA->m_TEXHinge/100.0,5,'f',3) .arg(ASurface.m_HingeVector.x,10,'f',4) .arg(ASurface.m_HingeVector.y,10,'f',4) .arg(ASurface.m_HingeVector.z,10,'f',4); strong +=str + "| name, gain, Xhinge, XYZhvec, SgnDup\n"; out << (strong); //write the same flap at the other end /* out << ("\n#______________\nSECTION | (keyword)\n"); strong = QString("%1 %2 %3 %4 %5 %6 %7 | Xle Yle Zle Chord Ainc [ Nspan Sspace ]\n") .arg(ASurface.m_LB.x *MainFrame::m_mtoUnit,9,'f',4) .arg(ASurface.m_LB.y *MainFrame::m_mtoUnit,9,'f',4) .arg(ASurface.m_LB.z *MainFrame::m_mtoUnit,9,'f',4) .arg(ASurface.GetChord(1.0) *MainFrame::m_mtoUnit,9,'f',4) .arg(m_Surface[j].m_TwistB,7,'f',3) .arg(ASurface.NYPanels,3) .arg(ASurface.m_YDistType,3); out << (strong); out << ("\n"); out << ("AFIL 0.0 1.0\n"); out << (ASurface.m_pFoilB->m_FoilName +".dat\n"); out << ("\n"); out << ("CONTROL | (keyword)\n"); str = QString("_Flap_%1 ").arg(iFlap); strong = m_WingName; strong.replace(" ", "_"); strong += str; if(qAbs(mean_angle)>0.0) str = QString("%1 ").arg(1.0/mean_angle,5,'f',2); else str = "1.0 "; strong += str; str = QString("%1 %2 %3 %4 -1.0 ") .arg(ASurface.m_pFoilB->m_TEXHinge/100.0,5,'f',3) .arg(ASurface.m_HingeVector.x,10,'f',4) .arg(ASurface.m_HingeVector.y,10,'f',4) .arg(ASurface.m_HingeVector.z,10,'f',4); strong +=str + "| name, gain, Xhinge, XYZhvec, SgnDup\n\n"; out << (strong); */ iFlap++; } } //write last panel, if no flap before if(!ASurface.m_bTEFlap) { out << ("#______________\nSECTION | (keyword)\n"); strong = QString("%1 %2 %3 %4 %5 %6 %7 | Xle Yle Zle Chord Ainc [ Nspan Sspace ]\n") .arg(ASurface.m_LB.x *MainFrame::s_mtoUnit,9,'f',4) .arg(ASurface.m_LB.y *MainFrame::s_mtoUnit,9,'f',4) .arg(ASurface.m_LB.z *MainFrame::s_mtoUnit,9,'f',4) .arg(ASurface.GetChord(1.0) *MainFrame::s_mtoUnit,9,'f',4) .arg(m_Surface[j-1].m_TwistB,7,'f',3) .arg(ASurface.m_NYPanels,3) .arg(ASurface.m_YDistType,3); out << (strong); out << ("\n"); out << ("AFIL 0.0 1.0\n"); out << (ASurface.m_pFoilB->m_FoilName +".dat\n"); out << ("\n"); } out << ("\n\n"); return true; } /** * Returns the wing's average sweep from root to tip measured at the quarter chord * The sweep is calulated as the arctangent of the root and tip quarter-chord points *@return the value of the average sweep, in degrees */ double Wing::AverageSweep() { double xroot = Chord(0)/4.0; double xtip = TipOffset() + TipChord()/4.0; // double sweep = (atan2(xtip-xroot, m_PlanformSpan/2.0)) * 180.0/PI; return (atan2(xtip-xroot, m_PlanformSpan/2.0)) * 180.0/PI; } /** * Returns the x-position of the quarter-chord point at a given span position, relative to a reference x-value *@param yob the span position where the quarter-chord point will be calculated *@param xRef the reference position *@return the quarter-chord position */ double Wing::C4(double yob, double xRef) { double chord, offset, tau; double C4 = 0.0; double y = qAbs(yob*m_PlanformSpan/2.0); for(int is=0; is=0.0) { //right wing for (int is=0; is=0) return Dihedral(is); else return -Dihedral(is); } } return 0.0; } /** * Returns pointers to the left and right foils of a given span position, and the relative position of the span position between these two foils * @param pFoil0 the pointer to the pointer of the left foil * @param pFoil1 the pointer to the pointer of the right foil * @param y the reference span position * @param t the ratio between the position of the two foils */ void Wing::GetFoils(Foil **pFoil0, Foil **pFoil1, double y, double &t) { if (y>0.0) { //search Right wing for (int is=0; ismass(); return TotalMass; } /** *Returns the wing's absolute positions yv and zv from the relative value xrel and the planform span y *Used for display purposes only *@param xrel the relative position along the chord, in % *@param y the planform (2D) span position where the y and z positions will be calculated *@param &yv the 3D y-position of the point *@param &zv the 3D z-position of the point */ void Wing::GetViewYZPos(double xrel, double y, double &yv, double &zv, int pos) { double tau; double twist, chord; double z0, z1, nx, ny; zv = 0.0; yv = 0.0; double fy = qAbs(y); double sign; if(fy<1.0e-10) sign = 1.0; else sign = y/fy; // if(fy<=0.0) return 0.0; for (int is=0; isGetUpperY(xrel, z0, nx, ny) ; pFoil1->GetUpperY(xrel, z1, nx, ny) ; z0 *= chord; z1 *= chord; zv += z0 + (z1-z0)*tau; } else if(pos==-1) { pFoil0->GetLowerY(xrel, z0, nx, ny); pFoil1->GetLowerY(xrel, z1, nx, ny); z0 *= chord; z1 *= chord; zv += z0 + (z1-z0)*tau; } } } } /** * Returns the relative position in % of a given absolute span position * @param SpanPos the absolute span position * @return the relative position, in % */ double Wing::yrel(double SpanPos) { double y = qAbs(SpanPos); for(int is=0; is0) return (y-YPosition(is))/(YPosition(is+1)-YPosition(is)); else return (y-YPosition(is+1))/(YPosition(is)-YPosition(is+1)); } } return 1.0; } /** * The z-position of a specified absolute span position. * Used for moment evaluations in LLT, where the wing is defined as a 2D planform * @param y the abolute span position * @return the absolute z-position */ double Wing::ZPosition(double y) { double tau; double ZPos =0.0; y= qAbs(y); if(y<=0.0) return 0.0; for (int is=0; ism_bTiltedGeom) { cosa = 1.0; sina = 0.0; } else {*/ cosa = cos(Alpha*PI/180.0); sina = sin(Alpha*PI/180.0); // } // Define wind axis WindNormal.Set( -sina, 0.0, cosa); WindDirection.Set( cosa, 0.0, sina); VInf = WindDirection * QInf; //dynamic pressure, kg/m3 double q = 0.5 * pWPolar->m_Density * QInf * QInf; m_CL = 0.0; WingIDrag = 0.0; IYm = 0.0; int coef = 2; if (pWPolar->m_bThinSurfaces) coef = 1; int NSurfaces = m_NSurfaces; if(s_bVLMSymetric) { if(!m_bIsFin || (m_bIsFin && m_bDoubleFin)) NSurfaces=m_NSurfaces/2; } p=0; m=0; for (j=0; jm_bThinSurfaces) p+=m_Surface[j].m_NXPanels;//tip patch panels for (k=0; km_bThinSurfaces) { // ____________________________ // Downwash calculation // // Since we place the trailing point at the end of the wake panels, it sees only the effect // of the upstream part of the wake because the downstream part isn't modelled. // If we were to model the downstream part, the total induced speed would be twice larger, // so just add a factor 2 to account for this. nw = m_pWingPanel[p].m_iWake; iTA = pWakePanel[nw].m_iTA; iTB = pWakePanel[nw].m_iTB; C = (pWakeNode[iTA] + pWakeNode[iTB])/2.0; pPanelDlg->GetSpeedVector(C, Mu, Sigma, Wg, false); m_Vd[m] = Wg; InducedAngle = atan2(Wg.dot(WindNormal), QInf); m_Ai[m] = InducedAngle*180/PI; // ____________________________ // Lift calculation // // Method 1 : Sum panel pressure forces over the top and bottom strip. // The induced drag is calculated by projection of the strip force on the wind direction // General experience in published literature shows that this isn't such a good idea // Method 2 : Far-field plane integration // This is the method generally recommended GammaStrip[m] = (-Mu[pos+p+coef*m_Surface[j].m_NXPanels-1] + Mu[pos+p]) *4.0*PI; Wg += VInf; StripForce = m_pWingPanel[p].Vortex * Wg; StripForce *= GammaStrip[m] * pWPolar->m_Density / q; // N/q //____________________________ // Project on wind axes m_Cl[m] = StripForce.dot(WindNormal) /m_StripArea[m]; m_ICd[m] = StripForce.dot(WindDirection)/m_StripArea[m]; WingIDrag += StripForce.dot(WindDirection); // N/q } else { pp=p; for(l=0; lm_bVLM1 || m_pWingPanel[pp].m_bIsTrailing) { C = m_pWingPanel[pp].CtrlPt; C.x = m_PlanformSpan * 1000.0; pPanelDlg->GetSpeedVector(C, Mu, Sigma, Wg, false); if(m_pWingPanel[pp].m_bIsTrailing) { m_Vd[m] = Wg; InducedAngle = atan2(Wg.dot(WindNormal), QInf); m_Ai[m] = InducedAngle*180/PI; } Wg += VInf; //total speed vector //induced force dF = Wg * m_pWingPanel[pp].Vortex; dF *= Mu[pp+pos]; // N/rho StripForce += dF; // N/rho } pp++; } StripForce *= 2./QInf/QInf; //N/q //____________________________ // Project on wind axes m_Cl[m] = StripForce.dot(WindNormal) /m_StripArea[m]; m_ICd[m] = StripForce.dot(WindDirection)/m_StripArea[m]/2.; m_CL += StripForce.dot(WindNormal); // N/q WingIDrag += StripForce.dot(WindDirection)/2.; // N/q } p += coef*m_Surface[j].m_NXPanels; // Calculate resulting vector force Force += StripForce; // N/q m_F[m] = StripForce * q; // Newtons // if(pWPolar->m_bTiltedGeom) m_F[m].RotateY(-Alpha); if(s_bVLMSymetric) { if(!m_bIsFin || (m_bIsFin && m_bDoubleFin)) { //construct right side results mm = m_NStation-m-1; m_StripArea[mm] = m_StripArea[m]; m_Ai[mm] = m_Ai[m]; m_Cl[mm] = m_Cl[m]; m_ICd[mm] = m_ICd[m]; m_F[mm].x = m_F[m].x; m_F[mm].y = -m_F[m].y; m_F[mm].z = m_F[m].z; m_Vd[mm].x = m_Vd[m].x; m_Vd[mm].y = -m_Vd[m].y; m_Vd[mm].z = m_Vd[m].z; StripForce.y = -StripForce.y; // add to global force Force += StripForce; m_CL += StripForce.dot(WindNormal); // N/q WingIDrag += StripForce.dot(WindDirection)/(3-coef); // N/q } } m++; } // if(s_bVLMSymetric) p+=m_Surface[j].NXPanels * m_Surface[j].NYPanels; if(m_Surface[j].m_bIsTipRight && !pWPolar->m_bThinSurfaces) p+=m_Surface[j].m_NXPanels;//tip patch panels } m_CDi = WingIDrag; // save this wing's induced drag (unused though...) } /** * Computes the bending moment at each span position based on the results of the panel analysis * Assumes the array of force vectors has been calculated previously * @param bThinSurface true if the calculation has been performed on thin VLM surfaces, false in the case of a 3D-panelanalysis */ void Wing::PanelComputeBending(bool bThinSurface) { double ypos[MAXSPANSTATIONS+1], zpos[MAXSPANSTATIONS+1]; int j,k,jj,coef,p; double bm; CVector Dist(0.0,0.0,0.0); CVector Moment; int m =0; if(bThinSurface) { coef = 1; p = 0; } else { coef = 2; p= m_Surface[0].m_NXPanels; } for (j=0; j0.00001) { //scale each panel's offset double ratio = NewTipOffset/OldTipOffset; for(int is=1; is0.0001) { //scale each panel's twist double ratio = NewTwist/TipTwist(); for(int is=1; ismass(); for(int im=0; imposition().x << (float)m_PointMass[im]->position().y << (float)m_PointMass[im]->position().z; for(int im=0; imtag()); ar << m_WingColor.alpha(); for(int i=0; i<20; i++) ar<<(float)0.0f; for(int i=0; i<20; i++) ar<<0; return true; } else { // loading code float f,g,h; int k; ar >> ArchiveFormat; if (ArchiveFormat <1001 || ArchiveFormat>1100) { m_WingName = ""; return false; } ReadCString(ar,m_WingName); if (m_WingName.length() ==0) return false; if (ArchiveFormat >=1008) { ReadCString(ar, m_WingDescription); } ar >> k; if(k!=0){ m_WingName = ""; return false; } ar >> k; if (k==1) m_bSymetric = true; else if (k==0) m_bSymetric = false; else{ m_WingName = ""; return false; } // m_bVLMSymetric = m_bSymetric; int NPanel; ar >> NPanel; if(NPanel <=0 || NPanel>MAXSPANSECTIONS) { m_WingName = ""; return false; } ClearWingSections(); for(int is=0; is<=NPanel; is++) m_WingSection.append(new WingSection); QString strFoil; for (int is=0; is<=NPanel; is++) { ReadCString(ar, strFoil); RightFoil(is) = strFoil; } for (int is=0; is<=NPanel; is++) { ReadCString(ar, strFoil); LeftFoil(is) = strFoil; } for (int is=0; is<=NPanel; is++) { ar >> f; Chord(is)=f; if (qAbs(Chord(is)) <0.0) { m_WingName = ""; return false; } } for (int is=0; is<=NPanel; is++) { ar >> f; YPosition(is)=f; if (qAbs(YPosition(is)) <0.0) { m_WingName = ""; return false; } } for (int is=0; is<=NPanel; is++) { ar >> f; Offset(is)=f; } if(ArchiveFormat<1007) { //convert mm to m for (int is=0; is<=NPanel; is++) { YPosition(is) /= 1000.0; Chord(is) /= 1000.0; Offset(is) /= 1000.0; } } for (int is=0; is<=NPanel; is++) { ar >> f; Dihedral(is)=f; } for (int is=0; is<=NPanel; is++) { ar >> f; Twist(is)=f; } ar >> f; //m_XCmRef=f; // if(ArchiveFormat<1007) m_XCmRef /= 1000.0; ar >> k; // if (k==1) m_bVLMAutoMesh = true; // else if (k==0) m_bVLMAutoMesh = false; // else{ // m_WingName = ""; // return false; // } for (int is=0; is<=NPanel; is++) { if(ArchiveFormat<=1003) { ar >> f; NXPanels(is) = (int)f; } else ar >> NXPanels(is); // NXPanels[i] = qMax(1,NXPanels[i] ); // NXPanels[i] = qMin(MAXCHORDPANELS, NXPanels[i]); } for (int is=0; is<=NPanel; is++) { if(ArchiveFormat<=1003) { ar >> f; NYPanels(is) = (int)f; } else ar >> NYPanels(is); // NYPanels[i] = qMax(1,NYPanels[i] ); // NYPanels[i] = qMin(100, NYPanels[i]); } int total = 0; for (int is=0; is=MAXSPANSTATIONS) { double ratio = MAXSPANSTATIONS/total/2.0; for (int is=0; is<=NPanel; is++) { NYPanels(is) = (int) (ratio*NYPanels(is)); } } int spanpos = 0; int vlmpanels = 0; for (int is=0; is=1005) { for(int is=0; is<=NPanel; is++) { ar >> k; if(k==1) XPanelDist(is) = COSINE; else if(k==2) XPanelDist(is) = SINE; else if(k==-2) XPanelDist(is) = INVERSESINE; else XPanelDist(is) = UNIFORM; //case 0 } } for (int is=0; is<=NPanel; is++) { ar >> k; if(k==1) YPanelDist(is) = COSINE; else if(k==2) YPanelDist(is) = SINE; else if(k==-2) YPanelDist(is) = INVERSESINE; else YPanelDist(is) = UNIFORM; //case 0 } if(ArchiveFormat>=1006) { ReadCOLORREF(ar, m_WingColor); } if(ArchiveFormat>=1009) { ar >> f; m_VolumeMass = f; int nMass; ar >> nMass; QVarLengthArray mass; QVarLengthArray position; QVarLengthArray tag; for(int im=0; im> f; mass.append(f); } for(int im=0; im> f >> g >> h; position.append(CVector(f,g,h)); } for(int im=0; im=1010) { ar >> k; m_WingColor.setAlpha(k); for(int i=0; i<20; i++) ar>>f; for(int i=0; i<20; i++) ar>>k; } ComputeGeometry(); return true; } } /** * Returns the number of mesh panels defined on this Wing's surfaces.; the number is given for a double-side mesh of the wing * @return the total number of panels */ int Wing::VLMPanelTotal(bool bThinSurface) { double MinPanelSize; if(QMiarex::s_MinPanelSize>0.0) MinPanelSize = QMiarex::s_MinPanelSize; else MinPanelSize = m_PlanformSpan/1000.0; int total = 0; for (int is=0; is MinPanelSize) total += NXPanels(is)*NYPanels(is); } if(!m_bIsFin) total *=2; if(!bThinSurface) { total *= 2; total += 2*NXPanels(0); // assuming a uniform number of chordwise panels over the wing } return total; } /** * Calculates the wing aero coefficients * Uses Cp distribution in input for thick surfaces * Uses Gamma distribution in input for VLM method * * Input data: * Freestream speed Qinf * Angle of attack Alpha * Cp dstribution for thick wings * Mu or Gamma distribution, depending on the analysis type * Type of surface : * - Thin Surface, i.e. VLM type surfaces, with vortex distribution * - Thick Surfaces;, i.e. 3D Panels with source+doublet distribution on panels * Type of analysis : viscous or inviscid * * Output * centre of pressure position (XCP, YCP) * moment coefficients GCm, VCm, ICm, GRm, GYm, VYm, IYm */ void Wing::PanelComputeOnBody(double QInf, double Alpha, double *Cp, double *Gamma, double &XCP, double &YCP, double &ZCP, double &GCm, double &VCm, double &ICm, double &GRm, double &GYm, double &VYm,double &IYm, WPolar *pWPolar, CVector CoG) { int j, k, l, p, m, nFlap, coef; double CPStrip, tau, NForce, cosa, sina; CVector HingeLeverArm, PtC4Strip, PtLEStrip, ForcePt, SurfaceNormal, LeverArmC4CoG, LeverArmPanelC4, LeverArmPanelCoG; CVector Force, PanelForce, StripForce, DragVector, Moment0, HingeMoment, DragMoment, GeomMoment; CVector WindNormal, WindDirection; CVector Origin(0.0,0.0,0.0); //initialize m_GRm =0.0; m_GCm = m_VCm = m_ICm = 0.0; m_GYm = m_VYm = m_IYm = 0.0; // Define the number of panels to consider on each strip if(pWPolar->m_bThinSurfaces) coef = 1; // only mid-surface else coef = 2; // top and bottom surfaces // Define the wind axis cosa = cos(Alpha*PI/180.0); sina = sin(Alpha*PI/180.0); WindNormal.Set( -sina, 0.0, cosa); WindDirection.Set( cosa, 0.0, sina); // Calculate the Reynolds number on each strip for (m=0; m< m_NStation; m++) m_Re[m] = m_Chord[m] * QInf /pWPolar->m_Viscosity; m = p = nFlap = 0; // For each of the wing's surfaces, calculate the coefficients on each strip // and sum them up to get the wing's overall coefficients for (j=0; jm_bThinSurfaces && m_Surface[j].m_bIsTipLeft) p += m_Surface[j].m_NXPanels; if(m_Surface[j].m_bTEFlap) m_FlapMoment[nFlap] = 0.0; SurfaceNormal = m_Surface[j].Normal; // consider each strip in turn for (k=0; km_Beta>0.0) { PtC4Strip.RotateZ(Origin, pWPolar->m_Beta); PtLEStrip.RotateZ(Origin, pWPolar->m_Beta); } LeverArmC4CoG = PtC4Strip - CoG; for (l=0; lm_bVLM1 && !m_pWingPanel[p].m_bIsLeading) { Force = WindDirection * m_pWingPanel[p].Vortex; Force *= 2.0 * Gamma[p+1] /QInf; //Newtons/q PanelForce -= Force; } Cp[p] = PanelForce.dot(m_pWingPanel[p].Normal)/m_pWingPanel[p].Area; // } StripForce += PanelForce; // Newtons/q NForce = PanelForce.dot(SurfaceNormal); // Newtons/q LeverArmPanelC4 = ForcePt - PtC4Strip; // m LeverArmPanelCoG = ForcePt - CoG; // m Moment0 = LeverArmPanelC4 * PanelForce; // N.m/q m_CmAirf[m] += Moment0.y; // N.m/q GeomMoment += LeverArmPanelCoG * PanelForce; // N.m/q XCP += ForcePt.x * PanelForce.dot(WindNormal); //global center of pressure YCP += ForcePt.y * PanelForce.dot(WindNormal); ZCP += ForcePt.z * PanelForce.dot(WindNormal); CPStrip += ForcePt.x * NForce; if(m_Surface[j].m_bTEFlap) { if(m_Surface[j].IsFlapPanel(p)) { //then p is on the flap, so add its contribution HingeLeverArm = ForcePt - m_Surface[j].m_HingePoint; HingeMoment = HingeLeverArm * PanelForce;//N.m/q m_FlapMoment[nFlap] += HingeMoment.dot(m_Surface[j].m_HingeVector)* pWPolar->m_Density * QInf * QInf/2.0; //N.m } } p++; } // calculate center of pressure position NForce = StripForce.dot(SurfaceNormal); m_XCPSpanRel[m] = (CPStrip/NForce - PtLEStrip.x)/m_Chord[m]; m_XCPSpanAbs[m] = CPStrip/NForce ; // add viscous properties, if required if(pWPolar->m_bViscous) DragVector.x = m_PCd[m] * m_StripArea[m];// N/q //TODO : orient along wind direction rather than x-axis else DragVector.x = 0.0; // global moments, in N.m/q DragMoment = LeverArmC4CoG * DragVector; m_GRm += GeomMoment.dot(WindDirection); m_VYm += DragMoment.dot(WindNormal); // m_IYm += -m_ICd[m] * m_StripArea[m] * PtC4Strip.y ; m_IYm += GeomMoment.dot(WindNormal); m_VCm += DragMoment.y; m_ICm += GeomMoment.y; m_CmAirf[m] *= 1.0 /m_Chord[m]/m_StripArea[m]; m_Cm[m] = (GeomMoment.y + DragMoment.y)/m_Chord[m]/m_StripArea[m]; m++; } //do not consider right tip patch if(!pWPolar->m_bThinSurfaces && m_Surface[j].m_bIsTipRight) p += m_Surface[j].m_NXPanels; if(m_Surface[j].m_bTEFlap) nFlap++; } //global plane dimensionless coefficients GCm += m_VCm + m_ICm; VCm += m_VCm; ICm += m_ICm; //sign convention for rolling and yawing is opposite to algebric results GRm -= m_GRm; GYm -= (m_VYm + m_IYm); VYm -= m_VYm; IYm -= m_IYm; } /** * In input, takes the speed QInf and the distribution of lift coefficients m_Cl[] along the span * In output, returns for each span station * - The Reynolds number m_Re[] * - The viscous drag coefficient m_PCd[] * - The top and bottom transition points m_XTrtop[] and m_XTrBot[] */ void Wing::PanelComputeViscous(double QInf, double Alpha, WPolar *pWPolar, double &WingVDrag, bool bViscous, QString &OutString) { QString string, strong, strLength; int m; bool bPointOutRe, bPointOutCl, bOutRe, bError; double tau = 0.0; CVector PtC4; OutString.clear(); WingVDrag = 0.0; bOutRe = bError = bPointOutRe = bPointOutCl = false; GetLengthUnit(strLength, MainFrame::s_LengthUnit); // Calculate the Reynolds number on each strip for (m=0; mm_Viscosity; if(!bViscous) { for(m=0; m m_Offset;} /** Returns the dihedral angle at a span section identified by its index *@param iSection the index of the section *@return the value of the dihedral angle, in degrees */ double & Wing::Dihedral(const int &iSection) {return m_WingSection[iSection]->m_Dihedral;} /** Returns the chord length at a span section identified by its index *@param iSection the index of the section *@return the value of the chord length */ double & Wing::Chord(const int &iSection) {return m_WingSection[iSection]->m_Chord;} /** Returns the twost angle at a span section identified by its index *@param iSection the index of the section *@return the value of the twist angle, in degrees */ double & Wing::Twist(const int &iSection) {return m_WingSection[iSection]->m_Twist;} /** Returns the span position at a span section identified by its index *@param iSection the index of the section *@return the value of the span position */ double & Wing::YPosition(const int &iSection) {return m_WingSection[iSection]->m_YPosition;} /** Returns the length betwee a span section identified by its index and the next spanwise section *@param iSection the index of the section *@return the value of the length of the panel */ double & Wing::Length(const int &iSection) {return m_WingSection[iSection]->m_Length;} /** Returns the span position of a span section identified by its index, projecteed on the x-y plane *@param iSection the index of the section *@return the value of the projected span position */ double & Wing::YProj(const int &iSection) {return m_WingSection[iSection]->m_YProj;} /** Returns the z-position at a span section identified by its index *@param iSection the index of the section *@return the value of the z-position */ double & Wing::ZPosition(const int &iSection) {return m_WingSection[iSection]->m_ZPos;} /** Returns the number of chordwise panels at a span section identified by its index *@param iSection the index of the section *@return the number of chordwise panels */ int & Wing::NXPanels(const int &iSection) {return m_WingSection[iSection]->m_NXPanels;} /** Returns the number of spanwise panels at a span section identified by its index *@param iSection the index of the section *@return the number of spanwise panels */ int & Wing::NYPanels(const int &iSection) {return m_WingSection[iSection]->m_NYPanels;} /** Returns the type of distribution of chordwise panels at a span section identified by its index - always cosine type *@param iSection the index of the section *@return the type of distribution of chordwise panels - always cosine type */ enumPanelDistribution & Wing::XPanelDist(const int &iSection) {return m_WingSection[iSection]->m_XPanelDist;} /** Returns the type of distribution of spanwise panels at a span section identified by its index *@param iSection the index of the section *@return the type of distribution of spanwise panels */ enumPanelDistribution & Wing::YPanelDist(const int &iSection) {return m_WingSection[iSection]->m_YPanelDist;} /** * Returns the name of the foil on the right side of a span section * @param iSection the index of the section * @return the name of the foil on the right side of the section */ QString & Wing::RightFoil(const int &iSection) {return m_WingSection[iSection]->m_RightFoilName;} /** * Returns the name of the foil on the left side of a span section * @param iSection the index of the section * @return the name of the foil on the left side of the section */ QString & Wing::LeftFoil(const int &iSection) {return m_WingSection[iSection]->m_LeftFoilName;} /** * Removes the section in the geometry of the wing identified by its index * @param iSection the index of the section */ void Wing::RemoveWingSection(int const iSection) { if(iSection<0 || iSection>=m_WingSection.size()) return; m_WingSection.removeAt(iSection); } /** * Inserts a section in the geometry of the wing at a postion identified by its index * @param iSection the index of the section */ void Wing::InsertSection(int iSection) { if(iSection==0) m_WingSection.prepend(new WingSection); else if(iSection>=m_WingSection.size()) m_WingSection.append(new WingSection); else m_WingSection.insert(iSection, new WingSection); } /** * Appends a new section at the tip of the wing, with default values *@ */ bool Wing::AppendWingSection() { if(m_WingSection.size()>MAXSPANSECTIONS) return false; m_WingSection.append(new WingSection()); return true; } /** * Appends a new section at the tip of the wing, with values specified as input parameters */ bool Wing::AppendWingSection(double Chord, double Twist, double Pos, double Dihedral, double Offset, int NXPanels, int NYPanels, enumPanelDistribution XPanelDist, enumPanelDistribution YPanelDist, QString RightFoilName, QString LeftFoilName) { if(m_WingSection.size()>MAXSPANSECTIONS) return false; WingSection *pWS = new WingSection(); m_WingSection.append(pWS); pWS->m_Chord = Chord; pWS->m_Twist = Twist; pWS->m_YPosition = Pos ; pWS->m_Dihedral = Dihedral; pWS->m_Offset = Offset ; pWS->m_NXPanels = NXPanels ; pWS->m_NYPanels = NYPanels; pWS->m_XPanelDist = XPanelDist; pWS->m_YPanelDist = YPanelDist; pWS->m_RightFoilName = RightFoilName; pWS->m_LeftFoilName = LeftFoilName; return true; } xflr5-6.09-06/src/objects/OpPoint.h000644 001750 000144 00000012335 12247174403 020257 0ustar00techwinderusers000000 000000 /**************************************************************************** OpPoint Class Copyright (C) 2003 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** *@file * * This class implements the surface object on which the panels are constructed for the VLM and 3d-panel calculations. * */ #ifndef OPPOINT_H #define OPPOINT_H #include "../params.h" #include #include #include #include /** *@class OpPoint *@brief * The class which defines the operating point associated to Foil objects. An OpPoint object stores the results of an XFoil calculation. Each instance of an OpPoint is uniquely attached to a Polar object, which is itself attached uniquely to a Foil object. The identification of the parent Polar and Foil are made using the QString names of the objects. */ class OpPoint { friend class MainFrame; friend class Polar; friend class QXDirect; friend class ObjectPropsDlg; public: OpPoint(); private: bool m_bViscResults; /**< true if viscous results are stored in this OpPoint */ bool m_bBL; /**< true if a boundary layer is stored in this OpPoint */ bool m_bTEFlap; /**< true if the parent foil has a flap on the trailing edge */ bool m_bLEFlap; /**< true if the parent foil has a flap on the leading edge */ int n, nd1, nd2, nd3; double Reynolds; /**< the Re number of the OpPoint */ double Mach; /**< the Mach number of the OpPoint */ double Alpha; /**< the aoa*/ double Cl; /**< the lift coefficient */ double Cm; /**< the pitching moment coefficient */ double Cd; /**< the drag coefficient - viscous only, since we are dealing with 2D analysis */ double Cdp; /**< @todo check significance in XFoil doc */ double Xtr1; /**< the laminar to turbulent transition point on the upper surface */ double Xtr2; /**< the laminar to turbulent transition point on the lower surface */ double ACrit; /**< the NCrit parameter which defines turbulent transition */ double m_XCP; /**< the x-position of the centre of pressure */ // double x[IQX], y[IQX]; /**< the foil coordinates @todo check if still of use */ double Cpv[IQX]; /**< the distribution of Cp on the surfaces for a viscous analysis */ double Cpi[IQX]; /**< the distribution of Cp on the surfaces for an inviscid analysis */ double Qv[IQX]; /**< the distribution of stream velocity on the surfaces for a viscous analysis */ double Qi[IQX]; /**< the distribution of stream velocity on the surfaces for an inviscid analysis */ double xd1[IQX]; /**< x-coordinate of the first part of the boundary layer */ double yd1[IQX]; /**< y-coordinate of the first part of the boundary layer */ double xd2[IWX]; /**< x-coordinate of the second part of the boundary layer */ double yd2[IWX]; /**< y-coordinate of the second part of the boundary layer */ double xd3[IWX]; /**< x-coordinate of the third part of the boundary layer */ double yd3[IWX]; /**< y-coordinate of the third part of the boundary layer */ double m_TEHMom; /**< the moment on the foils trailing edge flap */ double m_LEHMom; /**< the moment on the foils leading edge flap */ double XForce; /**< the y-component of the pressure forces */ double YForce; /**< the y-component of the pressure forces */ double Cpmn; /**< @todo check significance in XFoil doc */ QString m_strFoilName; /**< the name of the parent foil */ QString m_strPlrName; /**< the name of the parent polar */ bool m_bIsVisible; /**< true if the OpPoint's curve is visible in the active view */ bool m_bShowPoints; /**< true if the OpPoint's curve points are visible in the active graphs */ int m_Style; /**< the index of the style with which to draw the OpPoint's curve */ int m_Width; /**< the width with which to draw the OpPoint's curve */ QColor m_Color; /**< the color with which to draw the OpPoint's curve */ private: void ExportOpp(QTextStream &out, QString Version, enumTextFileType FileType, bool bDataOnly=false); bool Serialize(QDataStream &ar, bool bIsStoring, int ArchiveFormat=0); void GetOppProperties(QString &OpPointProperties, bool bData=false); }; #endif xflr5-6.09-06/src/objects/Spline.cpp000644 001750 000144 00000031536 12247174403 020460 0ustar00techwinderusers000000 000000 /**************************************************************************** Spline Class Copyright (C) 1996 Paul Bourke http://astronomy.swin.edu.au/~pbourke/curves/spline/ Copyright (C) 2003-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../globals.h" #include "Spline.h" #include "math.h" /** *The public constructor */ Spline::Spline() { m_Style = 0; m_Width = 1; m_Color = QColor(70, 200, 120); m_CtrlPoint.clear(); #if QT_VERSION >= 0x040700 m_CtrlPoint.reserve(50); #endif m_knot.clear(); #if QT_VERSION >= 0x040700 m_knot.reserve(100); #endif m_iHighlight = -10; m_iSelect = -10; m_iDegree = 3; m_iRes = 79; m_PtWeight = 1.0; memset(m_Output, 0, sizeof(m_Output)); } /** * Copies the data from an existing Spline. * @param pSpline a pointer to an existing Spline object. */ void Spline::Copy(Spline *pSpline) { if(!pSpline) return; m_CtrlPoint.clear(); for(int ic=0; icm_CtrlPoint.size(); ic++) { m_CtrlPoint.append(pSpline->m_CtrlPoint.at(ic)); } m_iDegree = pSpline->m_iDegree; m_iHighlight = pSpline->m_iHighlight; m_iRes = pSpline->m_iRes; m_iSelect = pSpline->m_iSelect; SplineKnots(); SplineCurve(); } /** * Creates a symetric spline w.r.t. the axis y=0, from an existing Spline. * @param pSpline a pointer to an existing Spline object. */ void Spline::CopySymetric(Spline *pSpline) { if(!pSpline) return; m_CtrlPoint.clear(); for(int ic=0; icm_CtrlPoint.size(); ic++) { m_CtrlPoint.append(pSpline->m_CtrlPoint.at(ic)); m_CtrlPoint[ic].y = -m_CtrlPoint[ic].y; } m_iDegree = pSpline->m_iDegree; m_iHighlight = pSpline->m_iHighlight; m_iRes = pSpline->m_iRes; m_iSelect = pSpline->m_iSelect; for(int i=0; im_Output[i].x; m_Output[i].y = -pSpline->m_Output[i].y; m_Output[i].z = pSpline->m_Output[i].z; } m_knot.clear(); for(int i=0; im_knot.size(); i++) { m_knot.append(pSpline->m_knot[i]); } } /** *Draws the control points on a QPainter. @todo separate GUI and object for polymorphism. */ void Spline::DrawCtrlPoints(QPainter &painter, double const &scalex, double const &scaley, QPoint const &Offset) { painter.save(); static QPoint pt; static int i, width; width = 3; static QPen PointPen; static QBrush NoBrush(Qt::NoBrush); PointPen.setWidth(1); painter.setPen(PointPen); painter.setBrush(NoBrush); for (i=0; i=3) { From.rx() = (int)( m_Output[0].x * scalex + Offset.x()); From.ry() = (int)(-m_Output[0].y * scaley + Offset.y()); for(k=1; k=0; k--) { strOut= QString(" %1 %2\n").arg(m_Output[k].x,7,'f',4).arg( m_Output[k].y,7,'f',4); out << strOut; } } else { for (k=1;k=1.0) return 0.0; for (i=0; i=0.0 && x<=1.0) { //No points yet if(m_CtrlPoint.size()==0) { m_CtrlPoint.append(CVector(x,y,0.0)); } else { if(x=m_CtrlPoint.last().x) { // if we're the new maximum point m_CtrlPoint.append(CVector(x,y,0.0)); m_iSelect = m_CtrlPoint.size(); } else { // else if we're in between for (k=0; k=m_CtrlPoint[k].x && x0 && k=m_knot.size()) { // qDebug()<<"Error here"; return 0.0; } if (p == 0) { if ((m_knot[i] <= t) && (t < m_knot[i+1]) ) return 1.0; // else if (qAbs(m_knot[i]-m_knot[i+1])=3) { t = 0; increment = 1.0/(double)(m_iRes - 1); for (j=0;j0.0) m_knot.append(a/b); else m_knot.append(1.0); } else m_knot.append(1.0); } } } xflr5-6.09-06/src/objects/NURBSSurface.h000644 001750 000144 00000007101 12247174403 021064 0ustar00techwinderusers000000 000000 /**************************************************************************** SplineSurface Class Copyright (C) 2012 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** * @file this class implements the NURBSSurface class. */ #ifndef SPLINESURFACE_H #define SPLINESURFACE_H //#include "../params.h" #include "Frame.h" #define MAXVLINES 17 #define MAXULINES 19 /** * @class NURBSSurface * This class implements a 3D NURBSsurface built on an array of Frame objects. * The NURBS surface is described by two parameters u and v with range in [0,1]. * * The NURBS control points are those of the array of Frames objects. * When used to describe a half body, u describes the NURBS in the x direction, and v in the z direction. * */ class NURBSSurface { public: NURBSSurface(int iAxis=0); ~NURBSSurface(); Frame *AppendFrame(); void ClearFrames(); int FrameSize() {return m_pFrame.size();} int FramePointCount() {return m_pFrame.first()->PointCount();} double Getu(double pos, double v); double Getv(double u, CVector r); void GetPoint(double u, double v, CVector &Pt); void InsertFrame(Frame *pNewFrame); bool IntersectNURBS(CVector A, CVector B, CVector &I); void RemoveFrame(int iFrame); void SetKnots(); int SetvDegree(int nvDegree); int SetuDegree(int nuDegree); double Weight(const double &d, int const &i, int const &N); static void* s_pMainFrame; /**< a static pointer to the instance of the MainFrame object */ QList m_pFrame; /**< a pointer to the array of Frame objects */ int m_iuDegree; /**< the degree of the NURBS in the u direction */ int m_ivDegree; /**< the degree of the NURBS in the v direction */ int m_nuKnots; /**< the number of knots in the u direction */ int m_nvKnots; /**< the number of knots in the v direction */ double m_uKnots[MAXVLINES*2]; /**< the array of knots in the u direction */ double m_vKnots[MAXULINES*2]; /**< the array of knots in the v direction */ int m_iRes; /**< the number of output points to draw the NURBS in both directions */ double m_Bunch; /**< a bunch parameter used to modify the output of point density at the end or at the middle of the NURBS */ double m_EdgeWeightu; /**< for a full NURBS. Unused, though, not practical */ double m_EdgeWeightv; /**< for a full NURBS. Unused, though, not practical */ int m_uAxis; /**< used to identify along which axis parameter u is set; 0=x, 1=y, 2=z */ int m_vAxis; /**< used to identify along which axis parameter u is set; 0=x, 1=y, 2=z */ //use temporary variables to avoid lengthy memory allocation times on the stack double value, eps, bs, cs; CVector t_R, t_Prod, t_Q, t_r, t_N; }; #endif // SPLINESURFACE_H xflr5-6.09-06/src/objects/WPolar.cpp000644 001750 000144 00000204105 12247174403 020424 0ustar00techwinderusers000000 000000 /**************************************************************************** WPolar Class Copyright (C) 2005-2012 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "WPolar.h" #include "../globals.h" #include "../mainframe.h" #include "../miarex/Miarex.h" #include #include void *WPolar::s_pMiarex; /** * The public constructor */ WPolar::WPolar() { m_bIsVisible = true; m_bShowPoints = false; m_bVLM1 = true; m_bThinSurfaces = true; m_bWakeRollUp = false; m_bTiltedGeom = false; m_bViscous = true; m_bIgnoreBodyPanels = false; m_bGround = false; m_bDirichlet = true; // m_bAVLControls = false; m_NXWakePanels = 1; m_TotalWakeLength = 100.0; m_WakePanelFactor =1.1; m_AnalysisMethod = LLTMETHOD; m_WPolarType = FIXEDSPEEDPOLAR; m_RefAreaType = 1; m_Style = 0; m_Width = 1; m_Color = 255;//red m_BankAngle = 0.0; m_Beta = 0.0; m_QInf = 10.0; m_Mass = 1.0; // m_XCmRef = 0.0; m_ASpec = 0.0; m_WArea = 0.0; m_WMAChord = 0.0; m_WSpan = 0.0; m_AMem = 0.0; m_Height = 0.0; m_Density = 1.225; m_Viscosity = 1.5e-5;//m2/s m_nControls = 0; // memset(m_MinControl, 0, sizeof(m_MinControl)); memset(m_ControlGain, 0, sizeof(m_ControlGain)); // memset(m_bActiveControl, 0, sizeof(m_bActiveControl)); memset(m_EigenValue, 0, 2*8*MAXPOLARPOINTS*sizeof(double)); m_bAutoInertia = true; m_CoGIxx = m_CoGIyy = m_CoGIzz = m_CoGIxz =0.0; m_CoG.Set(0.0,0.0,0.0); } /** * Adds the data from the instance of the operating point referenced by pPOpp to the polar object. * The index used to insert the data is the aoa, or the velocity, or the control parameter, depending on the polar type. * If a point with identical index exists, the data is replaced. * If not, the data is inserted for this index. * * @param pPOpp the plane operating point from which the data is to be extracted */ void WPolar::AddPoint(PlaneOpp *pPOpp) { bool bInserted = false; int i,j,l; int size = m_Alpha.size(); WingOpp *pWOpp = pPOpp->m_pPlaneWOpp[0]; if(size) { for (i=0; im_Alpha-m_Alpha[i]) < 0.001) { // then erase former result m_Alpha[i] = pWOpp->m_Alpha; m_QInfinite[i] = pWOpp->m_QInf; m_CL[i] = pWOpp->m_CL; m_CY[i] = pWOpp->m_CY; m_ICd[i] = pWOpp->m_ICD; m_PCd[i] = pWOpp->m_VCD; m_TCd[i] = pWOpp->m_ICD + pWOpp->m_VCD; m_GCm[i] = pWOpp->m_GCm; m_VCm[i] = pWOpp->m_VCm; m_ICm[i] = pWOpp->m_ICm; m_GRm[i] = pWOpp->m_GRm; m_GYm[i] = pWOpp->m_GYm; m_VYm[i] = pWOpp->m_VYm; m_IYm[i] = pWOpp->m_IYm; m_XCP[i] = pWOpp->m_CP.x; m_YCP[i] = pWOpp->m_CP.x; m_ZCP[i] = pWOpp->m_CP.z; m_MaxBending[i] = pWOpp->m_MaxBending; m_Ctrl[i] = pWOpp->m_Ctrl; m_XNP[i] = pWOpp->m_XNP; bInserted = true; break; } else if (pPOpp->m_Alpha < m_Alpha[i]) { // sort by crescending alphas m_Alpha.insert(i, pWOpp->m_Alpha); m_QInfinite.insert(i, pWOpp->m_QInf); m_CL.insert(i, pWOpp->m_CL); m_CY.insert(i, pWOpp->m_CY); m_ICd.insert(i, pWOpp->m_ICD); m_PCd.insert(i, pWOpp->m_VCD); m_TCd.insert(i, pWOpp->m_ICD + pWOpp->m_VCD); m_GCm.insert(i, pWOpp->m_GCm); m_VCm.insert(i, pWOpp->m_VCm); m_ICm.insert(i, pWOpp->m_ICm); m_GRm.insert(i, pWOpp->m_GRm); m_GYm.insert(i, pWOpp->m_GYm); m_VYm.insert(i, pWOpp->m_VYm); m_IYm.insert(i, pWOpp->m_IYm); m_XCP.insert(i, pWOpp->m_CP.x); m_YCP.insert(i, pWOpp->m_CP.y); m_ZCP.insert(i, pWOpp->m_CP.z); m_MaxBending.insert(i, pWOpp->m_MaxBending); m_Ctrl.insert(i, pWOpp->m_Ctrl); m_XNP.insert(i, pWOpp->m_XNP); m_ShortPeriodDamping.insert(i,0.0); m_ShortPeriodFrequency.insert(i,0.0); m_PhugoidDamping.insert(i,0.0); m_PhugoidFrequency.insert(i,0.0); m_DutchRollDamping.insert(i,0.0); m_DutchRollFrequency.insert(i,0.0); m_RollDamping.insert(i,0.0); m_SpiralDamping.insert(i,0.0); m_1Cl.insert(i,0.0);//make room for computed values m_ClCd.insert(i,0.0); m_Cl32Cd.insert(i,0.0); m_Vx.insert(i,0.0); m_Vz.insert(i,0.0); m_FZ.insert(i,0.0); m_FY.insert(i,0.0); m_FX.insert(i,0.0); m_Gamma.insert(i,0.0); m_Rm.insert(i, 0.0); m_Pm.insert(i, 0.0); m_Ym.insert(i, 0.0); m_VertPower.insert(i, 0.0); m_Oswald.insert(i, 0.0); m_SM.insert(i, 0.0); bInserted = true; break; } } else if(m_WPolarType==FIXEDAOAPOLAR) { // type 4, sort by speed if (qAbs(pPOpp->m_QInf - m_QInfinite[i]) < 0.001) { // then erase former result m_Alpha[i] = pWOpp->m_Alpha; m_CL[i] = pWOpp->m_CL; m_CY[i] = pWOpp->m_CY; m_ICd[i] = pWOpp->m_ICD; m_PCd[i] = pWOpp->m_VCD; m_TCd[i] = pWOpp->m_ICD + pWOpp->m_VCD; m_GCm[i] = pWOpp->m_GCm; m_VCm[i] = pWOpp->m_VCm; m_ICm[i] = pWOpp->m_ICm; m_GRm[i] = pWOpp->m_GRm; m_GYm[i] = pWOpp->m_GYm; m_VYm[i] = pWOpp->m_VYm; m_IYm[i] = pWOpp->m_IYm; m_QInfinite[i] = pWOpp->m_QInf; m_XCP[i] = pWOpp->m_CP.x; m_YCP[i] = pWOpp->m_CP.y; m_ZCP[i] = pWOpp->m_CP.z; m_MaxBending[i] = pWOpp->m_MaxBending; m_Ctrl[i] = pWOpp->m_Ctrl; m_XNP[i] = pWOpp->m_XNP; bInserted = true; break; } else if (pPOpp->m_QInf < m_QInfinite[i]) { // sort by crescending speed m_Alpha.insert(i, pWOpp->m_Alpha); m_CL.insert(i, pWOpp->m_CL); m_CY.insert(i, pWOpp->m_CY); m_ICd.insert(i, pWOpp->m_ICD); m_PCd.insert(i, pWOpp->m_VCD); m_TCd.insert(i, pWOpp->m_ICD + pWOpp->m_VCD); m_GCm.insert(i, pWOpp->m_GCm); m_VCm.insert(i, pWOpp->m_VCm); m_ICm.insert(i, pWOpp->m_ICm); m_GRm.insert(i, pWOpp->m_GRm); m_GYm.insert(i, pWOpp->m_GYm); m_VYm.insert(i, pWOpp->m_VYm); m_IYm.insert(i, pWOpp->m_IYm); m_QInfinite.insert(i, pWOpp->m_QInf); m_XCP.insert(i, pWOpp->m_CP.x); m_YCP.insert(i, pWOpp->m_CP.y); m_ZCP.insert(i, pWOpp->m_CP.z); m_MaxBending.insert(i, pWOpp->m_MaxBending); m_Ctrl.insert(i, pWOpp->m_Ctrl); m_XNP.insert(i, pWOpp->m_XNP); m_ShortPeriodDamping.insert(i,0.0); m_ShortPeriodFrequency.insert(i,0.0); m_PhugoidDamping.insert(i,0.0); m_PhugoidFrequency.insert(i,0.0); m_DutchRollDamping.insert(i,0.0); m_DutchRollFrequency.insert(i,0.0); m_RollDamping.insert(i,0.0); m_SpiralDamping.insert(i,0.0); m_1Cl.insert(i,0.0);//make room for computed values m_ClCd.insert(i,0.0); m_Cl32Cd.insert(i,0.0); m_Vx.insert(i,0.0); m_Vz.insert(i,0.0); m_FZ.insert(i,0.0); m_FY.insert(i,0.0); m_FX.insert(i,0.0); m_Gamma.insert(i,0.0); m_Rm.insert(i, 0.0); m_Pm.insert(i, 0.0); m_Ym.insert(i, 0.0); m_VertPower.insert(i, 0.0); m_Oswald.insert(i, 0.0); m_SM.insert(i, 0.0); bInserted = true; break; } } else if(m_WPolarType==STABILITYPOLAR) { // Control or stability analysis, sort by control value if (qAbs(pPOpp->m_Alpha - m_Alpha[i])<0.0001) { // then erase former result m_Alpha[i] = pWOpp->m_Alpha; m_CL[i] = pWOpp->m_CL; m_CY[i] = pWOpp->m_CY; m_ICd[i] = pWOpp->m_ICD; m_PCd[i] = pWOpp->m_VCD; m_TCd[i] = pWOpp->m_ICD + pWOpp->m_VCD; m_GCm[i] = pWOpp->m_GCm; m_VCm[i] = pWOpp->m_VCm; m_ICm[i] = pWOpp->m_ICm; m_GRm[i] = pWOpp->m_GRm; m_GYm[i] = pWOpp->m_GYm; m_VYm[i] = pWOpp->m_VYm; m_IYm[i] = pWOpp->m_IYm; m_QInfinite[i] = pWOpp->m_QInf; m_XCP[i] = pWOpp->m_CP.x; m_YCP[i] = pWOpp->m_CP.y; m_ZCP[i] = pWOpp->m_CP.z; m_MaxBending[i] = pWOpp->m_MaxBending; m_Ctrl[i] = pWOpp->m_Ctrl; m_XNP[i] = pWOpp->m_XNP; //store the eigenthings for(l=0; l<8; l++) m_EigenValue[l][i] = pWOpp->m_EigenValue[l]; bInserted = true; break; } else if (pPOpp->m_Ctrl < m_Ctrl[i]) { // sort by crescending control values m_Alpha.insert(i, pWOpp->m_Alpha); m_CL.insert(i, pWOpp->m_CL); m_CY.insert(i, pWOpp->m_CY); m_ICd.insert(i, pWOpp->m_ICD); m_PCd.insert(i, pWOpp->m_VCD); m_TCd.insert(i, pWOpp->m_ICD + pWOpp->m_VCD); m_GCm.insert(i, pWOpp->m_GCm); m_VCm.insert(i, pWOpp->m_VCm); m_ICm.insert(i, pWOpp->m_ICm); m_GRm.insert(i, pWOpp->m_GRm); m_GYm.insert(i, pWOpp->m_GYm); m_VYm.insert(i, pWOpp->m_VYm); m_IYm.insert(i, pWOpp->m_IYm); m_QInfinite.insert(i, pWOpp->m_QInf); m_XCP.insert(i, pWOpp->m_CP.x); m_YCP.insert(i, pWOpp->m_CP.y); m_ZCP.insert(i, pWOpp->m_CP.z); m_MaxBending.insert(i, pWOpp->m_MaxBending); m_Ctrl.insert(i, pWOpp->m_Ctrl); m_XNP.insert(i, pWOpp->m_XNP); m_ShortPeriodDamping.insert(i,0.0); m_ShortPeriodFrequency.insert(i,0.0); m_PhugoidDamping.insert(i,0.0); m_PhugoidFrequency.insert(i,0.0); m_DutchRollDamping.insert(i,0.0); m_DutchRollFrequency.insert(i,0.0); m_RollDamping.insert(i,0.0); m_SpiralDamping.insert(i,0.0); m_1Cl.insert(i,0.0);//make room for computed values m_ClCd.insert(i,0.0); m_Cl32Cd.insert(i,0.0); m_Vx.insert(i,0.0); m_Vz.insert(i,0.0); m_FZ.insert(i,0.0); m_FY.insert(i,0.0); m_FX.insert(i,0.0); m_Gamma.insert(i,0.0); m_Rm.insert(i, 0.0); m_Pm.insert(i, 0.0); m_Ym.insert(i, 0.0); m_VertPower.insert(i, 0.0); m_Oswald.insert(i, 0.0); m_SM.insert(i, 0.0); //make room for(l=0; l<8; l++) for(j=m_Alpha.size(); j>i; j--) { m_EigenValue[l][j] = m_EigenValue[l][j-1]; } //store the eigenthings for(l=0; l<8; l++) m_EigenValue[l][i] = pWOpp->m_EigenValue[l]; bInserted = true; break; } } } } if(bInserted) CalculatePoint(i); else { // data is appended at the end int size = m_Alpha.size(); if(size>=MAXPOLARPOINTS) { QString strong = QObject::tr("The max number of polar points has been reached"); QMessageBox::warning((QMiarex*)s_pMiarex, QObject::tr("Warning"), strong); return; } m_Alpha.append(pWOpp->m_Alpha); m_CL.append(pWOpp->m_CL); m_CY.append(pWOpp->m_CY); m_ICd.append(pWOpp->m_ICD); m_PCd.append(pWOpp->m_VCD); m_TCd.append(pWOpp->m_ICD + pWOpp->m_VCD); m_GCm.append(pWOpp->m_GCm); m_VCm.append(pWOpp->m_VCm); m_ICm.append(pWOpp->m_ICm); m_GRm.append(pWOpp->m_GRm); m_GYm.append(pWOpp->m_GYm); m_VYm.append(pWOpp->m_VYm); m_IYm.append(pWOpp->m_IYm); m_QInfinite.append(pWOpp->m_QInf); m_XCP.append(pWOpp->m_CP.x); m_YCP.append(pWOpp->m_CP.y); m_ZCP.append(pWOpp->m_CP.z); m_MaxBending.append(pWOpp->m_MaxBending); m_Ctrl.append(pWOpp->m_Ctrl); m_XNP.append(pWOpp->m_XNP); m_ShortPeriodDamping.append(0.0); m_ShortPeriodFrequency.append(0.0); m_PhugoidDamping.append(0.0); m_PhugoidFrequency.append(0.0); m_DutchRollDamping.append(0.0); m_DutchRollFrequency.append(0.0); m_RollDamping.append(0.0); m_SpiralDamping.append(0.0); m_1Cl.append(0.0);//make room for computed values m_ClCd.append(0.0); m_Cl32Cd.append(0.0); m_Vx.append(0.0); m_Vz.append(0.0); m_FZ.append(0.0); m_FY.append(0.0); m_FX.append(0.0); m_Gamma.append(0.0); m_Rm.append(0.0); m_Pm.append(0.0); m_Ym.append(0.0); m_VertPower.append(0.0); m_Oswald.append(0.0); m_SM.append(0.0); if(m_WPolarType==STABILITYPOLAR) { //store the eigenthings for (l=0; l<8; l++) m_EigenValue[l][size] = pWOpp->m_EigenValue[l]; } CalculatePoint(size); } } /** * Adds the data from the instnace of the operating point referenced by pWOpp to the polar object. * The index used to insert the data is the aoa, or the velocity, or the control parameter, depending on the polar type. * If a point with identical index exists, the data is replaced. * If not, the data is inserted for this index. * * @param pWOpp the wing operating point from which the data is to be extracted */ void WPolar::AddPoint(WingOpp *pWOpp) { bool bInserted = false; int l; int i=0; int size = m_Alpha.size(); if(size) { for (i=0; im_Alpha - m_Alpha[i]) < 0.001) { // then erase former result m_Alpha[i] = pWOpp->m_Alpha; m_CL[i] = pWOpp->m_CL; m_CY[i] = pWOpp->m_CY; m_ICd[i] = pWOpp->m_ICD; m_PCd[i] = pWOpp->m_VCD; m_TCd[i] = pWOpp->m_ICD + pWOpp->m_VCD; m_GCm[i] = pWOpp->m_GCm; m_VCm[i] = pWOpp->m_VCm; m_ICm[i] = pWOpp->m_ICm; m_GRm[i] = pWOpp->m_GRm; m_GYm[i] = pWOpp->m_GYm; m_VYm[i] = pWOpp->m_VYm; m_IYm[i] = pWOpp->m_IYm; m_QInfinite[i] = pWOpp->m_QInf; m_XCP[i] = pWOpp->m_CP.x; m_YCP[i] = pWOpp->m_CP.y; m_ZCP[i] = pWOpp->m_CP.z; m_MaxBending[i] = pWOpp->m_MaxBending; m_Ctrl[i] = pWOpp->m_Ctrl; m_XNP[i] = pWOpp->m_XNP; bInserted = true; break; } else if (pWOpp->m_Alpha < m_Alpha[i]) { // sort by crescending alphas m_Alpha.insert(i, pWOpp->m_Alpha); m_CL.insert(i, pWOpp->m_CL); m_CY.insert(i, pWOpp->m_CY); m_ICd.insert(i, pWOpp->m_ICD); m_PCd.insert(i, pWOpp->m_VCD); m_TCd.insert(i, pWOpp->m_ICD + pWOpp->m_VCD); m_GCm.insert(i, pWOpp->m_GCm); m_VCm.insert(i, pWOpp->m_VCm); m_ICm.insert(i, pWOpp->m_ICm); m_GRm.insert(i, pWOpp->m_GRm); m_GYm.insert(i, pWOpp->m_GYm); m_VYm.insert(i, pWOpp->m_VYm); m_IYm.insert(i, pWOpp->m_IYm); m_QInfinite.insert(i, pWOpp->m_QInf); m_XCP.insert(i, pWOpp->m_CP.x); m_YCP.insert(i, pWOpp->m_CP.y); m_ZCP.insert(i, pWOpp->m_CP.z); m_MaxBending.insert(i, pWOpp->m_MaxBending); m_Ctrl.insert(i, pWOpp->m_Ctrl); m_XNP.insert(i, pWOpp->m_XNP); m_ShortPeriodDamping.insert(i,0.0); m_ShortPeriodFrequency.insert(i,0.0); m_PhugoidDamping.insert(i,0.0); m_PhugoidFrequency.insert(i,0.0); m_DutchRollDamping.insert(i,0.0); m_DutchRollFrequency.insert(i,0.0); m_RollDamping.insert(i,0.0); m_SpiralDamping.insert(i,0.0); m_1Cl.insert(i,0.0);//make room for computed values m_ClCd.insert(i,0.0); m_Cl32Cd.insert(i,0.0); m_Vx.insert(i,0.0); m_Vz.insert(i,0.0); m_FZ.insert(i,0.0); m_FY.insert(i,0.0); m_FX.insert(i,0.0); m_Gamma.insert(i,0.0); m_Rm.insert(i, 0.0); m_Pm.insert(i, 0.0); m_Ym.insert(i, 0.0); m_VertPower.insert(i, 0.0); m_Oswald.insert(i, 0.0); m_SM.insert(i, 0.0); bInserted = true; break; } } else if (m_WPolarType==FIXEDAOAPOLAR) { // type 4, sort by speed if (qAbs(pWOpp->m_QInf - m_QInfinite[i]) < 0.001) { // then erase former result m_Alpha[i] = pWOpp->m_Alpha; m_CL[i] = pWOpp->m_CL; m_CY[i] = pWOpp->m_CY; m_ICd[i] = pWOpp->m_ICD; m_PCd[i] = pWOpp->m_VCD; m_TCd[i] = pWOpp->m_ICD + pWOpp->m_VCD; m_GCm[i] = pWOpp->m_GCm; m_VCm[i] = pWOpp->m_VCm; m_ICm[i] = pWOpp->m_ICm; m_GRm[i] = pWOpp->m_GRm; m_GYm[i] = pWOpp->m_GYm; m_VYm[i] = pWOpp->m_VYm; m_IYm[i] = pWOpp->m_IYm; m_QInfinite[i] = pWOpp->m_QInf; m_XCP[i] = pWOpp->m_CP.x; m_YCP[i] = pWOpp->m_CP.y; m_ZCP[i] = pWOpp->m_CP.z; m_MaxBending[i] = pWOpp->m_MaxBending; m_Ctrl[i] = pWOpp->m_Ctrl; m_XNP[i] = pWOpp->m_XNP; bInserted = true; break; } else if (pWOpp->m_QInf < m_QInfinite[i]) { // sort by crescending alphas m_Alpha.insert(i, pWOpp->m_Alpha); m_CL.insert(i, pWOpp->m_CL); m_CY.insert(i, pWOpp->m_CY); m_ICd.insert(i, pWOpp->m_ICD); m_PCd.insert(i, pWOpp->m_VCD); m_TCd.insert(i, pWOpp->m_ICD + pWOpp->m_VCD); m_GCm.insert(i, pWOpp->m_GCm); m_VCm.insert(i, pWOpp->m_VCm); m_ICm.insert(i, pWOpp->m_ICm); m_GRm.insert(i, pWOpp->m_GRm); m_GYm.insert(i, pWOpp->m_GYm); m_VYm.insert(i, pWOpp->m_VYm); m_IYm.insert(i, pWOpp->m_IYm); m_QInfinite.insert(i, pWOpp->m_QInf); m_XCP.insert(i, pWOpp->m_CP.x); m_YCP.insert(i, pWOpp->m_CP.y); m_ZCP.insert(i, pWOpp->m_CP.z); m_MaxBending.insert(i, pWOpp->m_MaxBending); m_Ctrl.insert(i, pWOpp->m_Ctrl); m_XNP.insert(i, pWOpp->m_XNP); m_ShortPeriodDamping.insert(i,0.0); m_ShortPeriodFrequency.insert(i,0.0); m_PhugoidDamping.insert(i,0.0); m_PhugoidFrequency.insert(i,0.0); m_DutchRollDamping.insert(i,0.0); m_DutchRollFrequency.insert(i,0.0); m_RollDamping.insert(i,0.0); m_SpiralDamping.insert(i,0.0); m_1Cl.insert(i,0.0);//make room for computed values m_ClCd.insert(i,0.0); m_Cl32Cd.insert(i,0.0); m_Vx.insert(i,0.0); m_Vz.insert(i,0.0); m_FZ.insert(i,0.0); m_FY.insert(i,0.0); m_FX.insert(i,0.0); m_Gamma.insert(i,0.0); m_Rm.insert(i, 0.0); m_Pm.insert(i, 0.0); m_Ym.insert(i, 0.0); m_VertPower.insert(i, 0.0); m_Oswald.insert(i, 0.0); m_SM.insert(i, 0.0); bInserted = true; break; } } else if (m_WPolarType==STABILITYPOLAR) { // Control or Stability Polar, sort by crescending ctrl value if (qAbs(pWOpp->m_Alpha - m_Alpha[i])<0.0001) { // then erase former result m_Alpha[i] = pWOpp->m_Alpha; m_CL[i] = pWOpp->m_CL; m_CY[i] = pWOpp->m_CY; m_ICd[i] = pWOpp->m_ICD; m_PCd[i] = pWOpp->m_VCD; m_TCd[i] = pWOpp->m_ICD + pWOpp->m_VCD; m_GCm[i] = pWOpp->m_GCm; m_VCm[i] = pWOpp->m_VCm; m_ICm[i] = pWOpp->m_ICm; m_GRm[i] = pWOpp->m_GRm; m_GYm[i] = pWOpp->m_GYm; m_VYm[i] = pWOpp->m_VYm; m_IYm[i] = pWOpp->m_IYm; m_QInfinite[i] = pWOpp->m_QInf; m_XCP[i] = pWOpp->m_CP.x; m_YCP[i] = pWOpp->m_CP.y; m_ZCP[i] = pWOpp->m_CP.z; m_MaxBending[i] = pWOpp->m_MaxBending; m_Ctrl[i] = pWOpp->m_Ctrl; m_XNP[i] = pWOpp->m_XNP; //store the eigenthings for(l=0; l<8; l++) { m_EigenValue[l][i] = pWOpp->m_EigenValue[l]; } bInserted = true; break; } else if (pWOpp->m_Ctrl < m_Ctrl[i]) { m_Alpha.insert(i, pWOpp->m_Alpha); m_CL.insert(i, pWOpp->m_CL); m_CY.insert(i, pWOpp->m_CY); m_ICd.insert(i, pWOpp->m_ICD); m_PCd.insert(i, pWOpp->m_VCD); m_TCd.insert(i, pWOpp->m_ICD + pWOpp->m_VCD); m_GCm.insert(i, pWOpp->m_GCm); m_VCm.insert(i, pWOpp->m_VCm); m_ICm.insert(i, pWOpp->m_ICm); m_GRm.insert(i, pWOpp->m_GRm); m_GYm.insert(i, pWOpp->m_GYm); m_VYm.insert(i, pWOpp->m_VYm); m_IYm.insert(i, pWOpp->m_IYm); m_QInfinite.insert(i, pWOpp->m_QInf); m_XCP.insert(i, pWOpp->m_CP.x); m_YCP.insert(i, pWOpp->m_CP.y); m_ZCP.insert(i, pWOpp->m_CP.z); m_MaxBending.insert(i, pWOpp->m_MaxBending); m_Ctrl.insert(i, pWOpp->m_Ctrl); m_XNP.insert(i, pWOpp->m_XNP); m_ShortPeriodDamping.insert(i,0.0); m_ShortPeriodFrequency.insert(i,0.0); m_PhugoidDamping.insert(i,0.0); m_PhugoidFrequency.insert(i,0.0); m_DutchRollDamping.insert(i,0.0); m_DutchRollFrequency.insert(i,0.0); m_RollDamping.insert(i,0.0); m_SpiralDamping.insert(i,0.0); m_1Cl.insert(i,0.0);//make room for computed values m_ClCd.insert(i,0.0); m_Cl32Cd.insert(i,0.0); m_Vx.insert(i,0.0); m_Vz.insert(i,0.0); m_FZ.insert(i,0.0); m_FY.insert(i,0.0); m_FX.insert(i,0.0); m_Gamma.insert(i,0.0); m_Rm.insert(i, 0.0); m_Pm.insert(i, 0.0); m_Ym.insert(i, 0.0); m_VertPower.insert(i, 0.0); m_Oswald.insert(i, 0.0); m_SM.insert(i, 0.0); //make room for(l=0; l<8; l++) for(int j=m_Alpha.size(); j>i; j--) m_EigenValue[l][j] = m_EigenValue[l][j-1]; //store the eigenthings for(l=0; l<8; l++) { m_EigenValue[l][i] = pWOpp->m_EigenValue[l]; } bInserted = true; break; } } } } if(bInserted) CalculatePoint(i); else { // data is appended at the end m_Alpha.append(pWOpp->m_Alpha); m_CL.append(pWOpp->m_CL); m_CY.append(pWOpp->m_CY); m_ICd.append(pWOpp->m_ICD); m_PCd.append(pWOpp->m_VCD); m_TCd.append(pWOpp->m_ICD + pWOpp->m_VCD); m_GCm.append(pWOpp->m_GCm); m_VCm.append(pWOpp->m_VCm); m_ICm.append(pWOpp->m_ICm); m_GRm.append(pWOpp->m_GRm); m_GYm.append(pWOpp->m_GYm); m_VYm.append(pWOpp->m_VYm); m_IYm.append(pWOpp->m_IYm); m_QInfinite.append(pWOpp->m_QInf); m_XCP.append(pWOpp->m_CP.x); m_YCP.append(pWOpp->m_CP.y); m_ZCP.append(pWOpp->m_CP.z); m_MaxBending.append(pWOpp->m_MaxBending); m_Ctrl.append(pWOpp->m_Ctrl); m_XNP.append(pWOpp->m_XNP); m_ShortPeriodDamping.append(0.0); m_ShortPeriodFrequency.append(0.0); m_PhugoidDamping.append(0.0); m_PhugoidFrequency.append(0.0); m_DutchRollDamping.append(0.0); m_DutchRollFrequency.append(0.0); m_RollDamping.append(0.0); m_SpiralDamping.append(0.0); m_1Cl.append(0.0);//make room for computed values m_ClCd.append(0.0); m_Cl32Cd.append(0.0); m_Vx.append(0.0); m_Vz.append(0.0); m_FZ.append(0.0); m_FY.append(0.0); m_FX.append(0.0); m_Gamma.append(0.0); m_Rm.append(0.0); m_Pm.append(0.0); m_Ym.append(0.0); m_VertPower.append(0.0); m_Oswald.append(0.0); m_SM.append(0.0); if(m_WPolarType==STABILITYPOLAR) { int size = m_Alpha.size(); if(size>=MAXPOLARPOINTS) return; //store the eigenthings for(l=0; l<8; l++) { m_EigenValue[l][size-1] = pWOpp->m_EigenValue[l]; } } CalculatePoint(size); } } /** * Adds the data passed in the parameters to the polar object. * The index used to insert the data is the aoa, or the velocity, or the control parameter, depending on the polar type. * If a point with identical index exists, the data is replaced. * If not, the data is inserted for this index. * * @param alpha the aoa * @param CL the lift coefficient * @param ICD the induced drag coefficient * @param PCD the viscous drag coefficient * @param CY the side force coefficient * @param GCm the total pitching moment coefficient * @param VCm the viscous part of the pitching moment coefficient * @param ICm the inviscid part of the pitching moment coefficient * @param GRm the rolling moment coefficient * @param GYm the ywing moment coefficient * @param QInf the freestream velocity * @param XCP the x-positionn of the centre of pressure */ void WPolar::AddPoint(double alpha, double CL, double ICd, double PCd, double CY, double GCm, double VCm, double ICm, double GRm, double GYm, double IYm, double QInf, double XCP) { bool bInserted = false; int i; int size = m_Alpha.size(); if(size) { for (i=0; i0.0) { m_1Cl[i] = (double)(1./sqrt(m_CL[i])); m_Cl32Cd[i] = (double)pow(m_CL[i],1.5)/m_TCd[i]; } else { m_1Cl[i] = -1.0;//will not be plotted m_Cl32Cd[i] = -(double)pow(-m_CL[i],1.5)/m_TCd[i]; } if(qAbs(m_CL[i])>0.) m_Gamma[i] = atan(m_TCd[i]/m_CL[i]) * 180.0/PI; else m_Gamma[i] = 90.0; m_Vz[i] = (double)sqrt(2*m_Mass*9.81/m_Density/m_WArea)/m_Cl32Cd[i]; m_Vx[i] = m_QInfinite[i] * (double)cos(m_Gamma[i]*PI/180.0); //dynamic pressure double q = 0.5 * m_Density * m_QInfinite[i]*m_QInfinite[i]; m_FZ[i] = q * m_CL[i]*m_WArea; m_FY[i] = q * m_CY[i]*m_WArea; m_FX[i] = q * m_TCd[i]*m_WArea; m_Rm[i] = q * m_WArea * m_GRm[i] * m_WSpan;// in N.m m_Ym[i] = q * m_WArea * m_GYm[i] * m_WSpan;// in N.m m_Pm[i] = q * m_WArea * m_GCm[i] * m_WMAChord;// in N.m //power for horizontal flight m_VertPower[i] = m_Mass * 9.81 * m_Vz[i]; double AR = m_WSpan*m_WSpan/m_WArea; if(m_ICd[i]==0.0) m_Oswald[i] = 0.0; else m_Oswald[i] = m_CL[i]*m_CL[i]/PI/m_ICd[i]/AR; m_SM[i] = (m_XCP[i]-m_CoG.x)/m_WMAChord *100.00; complex c; double OmegaN, Omega1, Dsi, Sigma1; double sum, prod; c = m_EigenValue[2][i]; sum = c.real() * 2.0; // is a real number prod = c.real()*c.real() + c.imag()*c.imag(); // is a positive real number OmegaN = qAbs(c.imag()); if(OmegaN>PRECISION) Omega1 = sqrt(prod); else Omega1 = 0.0; Sigma1 = sum /2.0; if(Omega1 > PRECISION) Dsi = -Sigma1/Omega1; else Dsi = 0.0; m_PhugoidDamping[i] = Dsi; m_PhugoidFrequency[i] = qAbs(c.imag()/2.0/PI); c = m_EigenValue[0][i]; sum = c.real() * 2.0; // is a real number prod = c.real()*c.real() + c.imag()*c.imag(); // is a positive real number OmegaN = qAbs(c.imag()); if(OmegaN>PRECISION) Omega1 = sqrt(prod); else Omega1 = 0.0; Sigma1 = sum /2.0; if(Omega1 > PRECISION) Dsi = -Sigma1/Omega1; else Dsi = 0.0; m_ShortPeriodDamping[i] = Dsi; m_ShortPeriodFrequency[i] = qAbs(c.imag()/2.0/PI); c = m_EigenValue[5][i]; sum = c.real() * 2.0; // is a real number prod = c.real()*c.real() + c.imag()*c.imag(); // is a positive real number OmegaN = qAbs(c.imag()); if(OmegaN>PRECISION) Omega1 = sqrt(prod); else Omega1 = 0.0; Sigma1 = sum /2.0; if(Omega1 > PRECISION) Dsi = -Sigma1/Omega1; else Dsi = 0.0; m_DutchRollDamping[i] = Dsi; m_DutchRollFrequency[i] = qAbs(c.imag()/2.0/PI); m_RollDamping[i]= m_EigenValue[4][i].real(); m_SpiralDamping[i]= m_EigenValue[7][i].real(); } /* N = Cn.q.s.b L = Ct.q.s.b M = Cm.q.s.c' */ /** * Copies the polar's analysis parameters from an existing polar * @param pWPolar a pointer to the instance of the reference CWPolar object from which the parameters should be copied */ void WPolar::DuplicateSpec(WPolar *pWPolar) { m_UFOName = pWPolar->m_UFOName; m_PlrName = pWPolar->m_PlrName; m_WPolarType = pWPolar->m_WPolarType; m_QInf = pWPolar->m_QInf; m_ASpec = pWPolar->m_ASpec; m_AMem = pWPolar->m_AMem; m_Beta = pWPolar->m_Beta; m_Style = pWPolar->m_Style; m_Width = pWPolar->m_Width; m_Color = pWPolar->m_Color; // general aerodynamic data - specific to a polar m_Viscosity = pWPolar->m_Viscosity; m_Density = pWPolar->m_Density ; m_Height = pWPolar->m_Height;//for ground effect m_BankAngle = pWPolar->m_BankAngle; m_NXWakePanels = pWPolar->m_NXWakePanels; m_TotalWakeLength = pWPolar->m_TotalWakeLength; m_WakePanelFactor = pWPolar->m_WakePanelFactor; m_bGround = pWPolar->m_bGround; m_bDirichlet = pWPolar->m_bDirichlet; m_bIsVisible = pWPolar->m_bIsVisible; m_bShowPoints = pWPolar->m_bShowPoints; m_bTiltedGeom = pWPolar->m_bTiltedGeom; m_bViscous = pWPolar->m_bViscous; m_bIgnoreBodyPanels = pWPolar->m_bIgnoreBodyPanels; m_bVLM1 = pWPolar->m_bVLM1; m_bWakeRollUp = pWPolar->m_bWakeRollUp; m_AnalysisMethod = pWPolar->m_AnalysisMethod; m_bThinSurfaces = pWPolar->m_bThinSurfaces; m_bVLM1 = pWPolar->m_bVLM1; // m_bAVLControls = pWPolar->m_bAVLControls; // true if the control is defined only by its "gain" AVL-like m_nControls = pWPolar->m_nControls; // memcpy(m_MinControl, pWPolar->m_MinControl, 4*MAXCONTROLS*sizeof(double)); memcpy(m_ControlGain, pWPolar->m_ControlGain, 4*MAXCONTROLS*sizeof(double)); // memcpy(m_bActiveControl, pWPolar->m_bActiveControl, 4*MAXCONTROLS*sizeof(bool)); m_RefAreaType = pWPolar->m_RefAreaType; m_WArea = pWPolar->m_WArea;//for lift and drag calculations m_WMAChord = pWPolar->m_WMAChord;// for moment calculations m_WSpan = pWPolar->m_WSpan;//for moment calculations //Inertia properties m_Mass = pWPolar->m_Mass; m_bAutoInertia = pWPolar->m_bAutoInertia; m_bThinSurfaces = pWPolar->m_bThinSurfaces; m_CoGIxx = pWPolar->m_CoGIxx; m_CoGIyy = pWPolar->m_CoGIyy; m_CoGIzz = pWPolar->m_CoGIzz; m_CoGIxz = pWPolar->m_CoGIxz; m_CoG = pWPolar->m_CoG; } /** * Copies the polar's data from an existing polar * @param pWPolar a pointer to the instance of the reference WPolar object from which the data should be copied */ void WPolar::Copy(WPolar *pWPolar) { int i; DuplicateSpec(pWPolar); int size = m_Alpha.size(); for(i=size-1; i>=0; i--) Remove(i); size = pWPolar->m_Alpha.size(); for(i=0; im_Alpha[i]); m_CL.insert(i, pWPolar-> m_CL[i]); m_CY.insert(i, pWPolar-> m_CY[i]); m_ICd.insert(i, pWPolar-> m_ICd[i]); m_PCd.insert(i, pWPolar-> m_PCd[i]); m_TCd.insert(i, pWPolar-> m_TCd[i]); m_GCm.insert(i, pWPolar-> m_GCm[i]); m_VCm.insert(i, pWPolar-> m_VCm[i]); m_ICm.insert(i, pWPolar-> m_ICm[i]); m_GRm.insert(i, pWPolar-> m_GRm[i]); m_GYm.insert(i, pWPolar-> m_GYm[i]); m_VYm.insert(i, pWPolar-> m_VYm[i]); m_IYm.insert(i, pWPolar-> m_IYm[i]); m_ClCd.insert(i, pWPolar-> m_ClCd[i]); m_1Cl.insert(i, pWPolar-> m_1Cl[i]); m_Cl32Cd.insert(i, pWPolar-> m_Cl32Cd[i]); m_QInfinite.insert(i, pWPolar-> m_QInfinite[i]); m_Gamma.insert(i, pWPolar-> m_Gamma[i]); m_XCP.insert(i, pWPolar-> m_XCP[i]); m_YCP.insert(i, pWPolar-> m_YCP[i]); m_ZCP.insert(i, pWPolar-> m_ZCP[i]); m_MaxBending.insert(i, pWPolar-> m_MaxBending[i]); m_VertPower.insert(i, pWPolar-> m_VertPower[i]); m_Oswald.insert(i, pWPolar-> m_Oswald[i]); m_SM.insert(i, pWPolar-> m_SM[i]); m_Ctrl.insert(i, pWPolar-> m_Ctrl[i]); m_XNP.insert(i, pWPolar->m_XNP[i]); m_ShortPeriodDamping.insert(i, pWPolar->m_ShortPeriodDamping[i]); m_ShortPeriodFrequency.insert(i, pWPolar->m_ShortPeriodFrequency[i]); m_PhugoidDamping.insert(i, pWPolar->m_PhugoidDamping[i]); m_PhugoidFrequency.insert(i, pWPolar->m_PhugoidFrequency[i]); m_DutchRollDamping.insert(i,pWPolar->m_DutchRollDamping[i]); m_DutchRollFrequency.insert(i,pWPolar->m_DutchRollFrequency[i]); m_RollDamping.insert(i,pWPolar->m_RollDamping[i]); m_SpiralDamping.insert(i,pWPolar->m_SpiralDamping[i]); m_FZ.insert(i, pWPolar-> m_FZ[i]); m_FY.insert(i, pWPolar-> m_FY[i]); m_FX.insert(i, pWPolar-> m_FX[i]); m_Vx.insert(i, pWPolar-> m_Vx[i]); m_Vz.insert(i, pWPolar-> m_Vz[i]); m_Pm.insert(i, pWPolar-> m_Pm[i]); m_Ym.insert(i, pWPolar-> m_Ym[i]); m_Rm.insert(i, pWPolar-> m_Rm[i]); //make room for(int l=0; l<8; l++) for(int j=m_Alpha.size(); j>i; j--) { m_EigenValue[l][j] = m_EigenValue[l][j-1]; } for(int l=0; l<8; l++) m_EigenValue[l][i] = pWPolar->m_EigenValue[l][i]; } } /** * Exports the data of the polar to a text file * @param out the instance of output QtextStream * @param FileType TXT if the data is separated by spaces, CSV for a comma separator * @param bDataOnly true if the analysis parameters should not be output */ void WPolar::Export(QTextStream &out, enumTextFileType FileType, bool bDataOnly) { int j; QString Header, strong, str; if (FileType==TXT) { if(!bDataOnly) { strong =MainFrame::versionName() + "\n\n"; out << strong; strong ="Wing name : "+ m_UFOName + "\n"; out << strong; strong ="Wing polar name : "+ m_PlrName + "\n"; out << strong; GetSpeedUnit(str, MainFrame::s_SpeedUnit); str +="\n\n"; if(m_WPolarType==FIXEDSPEEDPOLAR) { strong = QString("Freestream speed : %1 ").arg(m_QInf*MainFrame::s_mstoUnit,7,'f',3); strong +=str + "\n"; } else if(m_WPolarType==FIXEDAOAPOLAR) { strong = QString("Alpha = %1").arg(m_ASpec) + QString::fromUtf8("°") + "\n"; } else strong = "\n"; out << strong; } Header = " alpha CL ICd PCd TCd CY Cm Rm Ym IYm QInf XCP\n"; out << Header; Header = " _________ ________ ________ _________ _________ _________ _________ _________ _________ _________ _________ _________\n"; out << Header; for (j=0; j> m_PolarFormat; if (m_PolarFormat <=1000 || m_PolarFormat>1100) { m_PlrName =""; return false; } ReadCString(ar, m_UFOName); ReadCString(ar, m_PlrName); ar>> f; m_WArea = f; if (m_WArea<0) return false; ar>> f; m_WMAChord = f; if (m_WMAChord<0) return false; ar>> f; m_WSpan = f; if (m_WSpan<0) return false; ar >> m_Style >> m_Width; if (m_Style<0 || m_Style> 10) return false; if (m_Width<0 || m_Width> 10) return false; ReadCOLORREF(ar, m_Color); ar>>k; if(k==1) m_AnalysisMethod=LLTMETHOD; else if(k==2) m_AnalysisMethod=VLMMETHOD; else if(k==3) m_AnalysisMethod=PANELMETHOD; else if(k==4) m_AnalysisMethod=VLMMETHOD; if(m_AnalysisMethod==VLMMETHOD) { m_AnalysisMethod=PANELMETHOD; m_bThinSurfaces = true; } if(m_PolarFormat>=1005) { ar >> n; if (n!=0 && n!=1) return false; if(n) m_bVLM1 =true; else m_bVLM1 = false; ar >> n; if (n!=0 && n!=1) return false; if(n) m_bThinSurfaces =true; else m_bThinSurfaces = false; } if(m_PolarFormat>=1008) { ar >> n; if (n!=0 && n!=1) return false; if(n) m_bTiltedGeom =true; else m_bTiltedGeom = false; } if(m_PolarFormat>=1006) { ar >> n; if (n!=0 && n!=1) return false; if(n) m_bDirichlet = false; else m_bDirichlet = true; } if(m_PolarFormat>=1009) { ar >> n; if (n!=0 && n!=1) return false; if(n) m_bViscous =true; else m_bViscous = false; } /* if(m_PolarFormat>=1024) { ar >> n; if (n!=0 && n!=1) return false; if(n) m_bIgnoreBody =true; else m_bIgnoreBody = false; }*/ if(m_PolarFormat>=1010) { ar >> n; if (n!=0 && n!=1) return false; if(n) m_bGround =true; else m_bGround = false; ar >> f; m_Height = f; } if(m_PolarFormat>=1007) { ar >> m_NXWakePanels; if (m_NXWakePanels<0 || m_NXWakePanels>1000) return false; } if(m_PolarFormat>=1011) { ar >> f; m_TotalWakeLength = f; ar >> f; m_WakePanelFactor = f; } ar >> n; if (n!=0 && n!=1) return false; else { if(n) m_bIsVisible =true; else m_bIsVisible = false; } ar >> n; if (n!=0 && n!=1) return false; else { if(n) m_bShowPoints =true; else m_bShowPoints = false; } ar >>k; if(k==1) m_WPolarType = FIXEDSPEEDPOLAR; else if(k==2) m_WPolarType = FIXEDLIFTPOLAR; else if(k==4) m_WPolarType = FIXEDAOAPOLAR; else if(k==6) m_WPolarType = STABILITYPOLAR; // former control polars else if(k==7) m_WPolarType = STABILITYPOLAR; else return false; ar >> f; m_QInf = f; ar >> f; m_Mass = f; ar >> f; m_ASpec = f; if(m_PolarFormat>=1015) { ar >> f; m_Beta = f; } else m_Beta = 0.0; if(m_PolarFormat<1018 && m_PolarFormat>=1002) { ar >> f; m_CoG.x = f; } else if(m_PolarFormat>=1018) { ar >> f; m_CoG.x = f; ar >> f; m_CoG.y = f; ar >> f; m_CoG.z = f; } // if(m_PolarFormat>=1002) ar >> f; m_XCmRef = f; ar >> f; m_Density=f; ar >> f; m_Viscosity=f; if(m_PolarFormat>=1016) ar >> m_RefAreaType; else m_RefAreaType = 1; ar >> n; if (n<0 || n> 100000) return false; if(m_PolarFormat<1010) { m_WArea /=100.0; m_WMAChord /=1000.0; m_WSpan /=1000.0; m_CoG.x /=1000.0; } float Alpha, Cl, CY, ICd, PCd, GCm, GRm, GYm, VCm, ICm, VYm, IYm, QInfinite, XCP, YCP, ZCP, Ctrl, Cb, XNP; f = Alpha = Cl = CY = ICd = PCd = GCm = GRm = GYm = VCm = ICm = VYm = IYm = QInfinite = XCP = YCP = ZCP = Ctrl = Cb =0.0; // bool bExists; for (i=0; i< n; i++) { ar >> Alpha >> Cl; if(m_PolarFormat>=1015) ar>>CY; ar >> ICd >> PCd; ar >> GCm; if(m_PolarFormat>=1017) ar >> VCm >> ICm; ar >> GRm >> GYm >> f >> VYm >> IYm; if(m_PolarFormat<1012) GCm = GRm = GYm = VCm = VYm = IYm = 0.0; ar >> QInfinite >> XCP >> YCP; if (m_PolarFormat>=1023) ar >> ZCP; if(m_PolarFormat<1010) { XCP /=1000.0; YCP /=1000.0; } if (m_PolarFormat>=1003) ar >> Cb; else Cb = 0.0; if (m_PolarFormat>=1014) ar >> Ctrl; else Ctrl = 0.0; if (m_PolarFormat>=1022) ar >> XNP; else XNP = 0.0; if(m_WPolarType!=FIXEDAOAPOLAR) { for (j=0; j1012) { ar >> m_nControls; if(abs(m_nControls)>1000) m_nControls = 0; for(i=0; i> f; //m_MinControl[i] = f; ar >> f; m_ControlGain[i] = f; } for(i=0; i> n; if (n!=0 && n!=1) return false; else { // if(n) m_bActiveControl[i] =true; else m_bActiveControl[i] = false; } } } if(m_PolarFormat>=1019) { n = m_Alpha.size(); for(i=0; i< n; i++) { ar>>r0>>r1>>r2>>r3; ar>>i0>>i1>>i2>>i3; m_EigenValue[0][i] = complex(r0,i0); m_EigenValue[1][i] = complex(r1,i1); m_EigenValue[2][i] = complex(r2,i2); m_EigenValue[3][i] = complex(r3,i3); ar>>r0>>r1>>r2>>r3; ar>>i0>>i1>>i2>>i3; m_EigenValue[4][i] = complex(r0,i0); m_EigenValue[5][i] = complex(r1,i1); m_EigenValue[6][i] = complex(r2,i2); m_EigenValue[7][i] = complex(r3,i3); CalculatePoint(i); } } if(m_PolarFormat>=1020) { ar >> n; if(n && m_PolarFormat>1020) m_bAutoInertia =true; else m_bAutoInertia = false; ar>>r0>>r1>>r2>>r3; m_CoGIxx = r0; m_CoGIyy = r1; m_CoGIzz = r2; m_CoGIxz = r3; } else { m_bAutoInertia = false; m_CoGIxx = m_CoGIyy = m_CoGIzz = m_CoGIxz = 0.0; } if(m_PolarFormat>=1022) { //float provision for(int i=0; i<20; i++) ar>>f; //int provision ar >> n; if (m_PolarFormat >= 1024) { if (n!=0 && n!=1) return false; if(n) m_bIgnoreBodyPanels = true; else m_bIgnoreBodyPanels = false; } else m_bIgnoreBodyPanels = false; for(int i=1; i<20; i++) ar>>n; } } return true; } /** * Returns a QString object holding the description and value of the polar's parameters * @param &PolarProperties the reference of the QString object to be filled with the description * @param bData true if the analysis data should be appended to the string */ void WPolar::GetPolarProperties(QString &PolarProperties, bool bData) { QMiarex *pMiarex= (QMiarex*)s_pMiarex; QString strong, lenunit, massunit, speedunit; GetLengthUnit(lenunit, MainFrame::s_LengthUnit); GetWeightUnit(massunit, MainFrame::s_WeightUnit); GetSpeedUnit(speedunit, MainFrame::s_SpeedUnit); QString inertiaunit = massunit+"."+lenunit+QString::fromUtf8("²"); Plane *pPlane = pMiarex->GetPlane(m_UFOName); PolarProperties.clear(); if(m_WPolarType==FIXEDSPEEDPOLAR) strong = "Type 1: "+QObject::tr("Fixed speed") +"\n"; else if(m_WPolarType==FIXEDLIFTPOLAR) strong = "Type 2: "+QObject::tr("Fixed lift") +"\n"; else if(m_WPolarType==FIXEDAOAPOLAR) strong = "Type 4: "+QObject::tr("Fixed angle of attack") +"\n"; else if(m_WPolarType==STABILITYPOLAR) strong = "Type 7: "+QObject::tr("Stability analysis") +"\n"; PolarProperties += strong; if(m_WPolarType==FIXEDSPEEDPOLAR) { strong = QString(QObject::tr("VInf =")+"%1 ").arg(m_QInf*MainFrame::s_mstoUnit,10,'g',2); PolarProperties += strong + speedunit+"\n"; } else if(m_WPolarType==FIXEDAOAPOLAR) { strong = QString(QObject::tr("Alpha =")+"%1").arg(m_ASpec,7,'f',2); PolarProperties += strong +QString::fromUtf8("°")+"\n"; } if(qAbs(m_Beta)>PRECISION) { strong = QString(QObject::tr("Beta")+" = %1").arg(m_Beta,7,'f',2); PolarProperties += strong +QString::fromUtf8("°")+"\n"; } // PolarProperties += QObject::tr("Method")+" = "; if(m_AnalysisMethod==LLTMETHOD) PolarProperties +=QObject::tr("LLT"); else if(m_AnalysisMethod==PANELMETHOD && !m_bThinSurfaces) PolarProperties +=QObject::tr("3D-Panels"); else if(m_AnalysisMethod==PANELMETHOD && m_bVLM1) PolarProperties +=QObject::tr("3D-Panels/VLM1"); else if(m_AnalysisMethod==PANELMETHOD && !m_bVLM1) PolarProperties +=QObject::tr("3D-Panels/VLM2"); PolarProperties +="\n"; //Control data if(m_WPolarType==STABILITYPOLAR) { int j; int iCtrl = 0; strong = "AVL type controls\n"; PolarProperties +=strong; if(pPlane) { if(qAbs(m_ControlGain[iCtrl])>PRECISION) { strong = QString(QString::fromUtf8("Wing Tilt: gain=%1°/unit\n")).arg(m_ControlGain[iCtrl],0,'f',2); PolarProperties +=strong; } iCtrl=1; if(pPlane->stab()) { if(qAbs(m_ControlGain[iCtrl])>PRECISION) { strong = QString(QString::fromUtf8("Elev. Tilt: gain=%1°/unit\n")).arg(m_ControlGain[iCtrl],0,'f',2); PolarProperties +=strong; } iCtrl=2; } } Wing *pStab, *pFin, *pWing; pStab = pFin = pWing = NULL; if(pPlane) { pWing = pPlane->wing(); pStab = pPlane->stab(); pFin = pPlane->fin(); } else pWing = pMiarex->GetWing(m_UFOName); // flap controls //wing first int nFlap = 0; if(pWing) { for (j=0; jm_NSurfaces; j++) { if(pWing->m_Surface[j].m_bTEFlap) { if(qAbs(m_ControlGain[iCtrl])>PRECISION) { strong = QString(QString::fromUtf8("Wing Flap %1: g=%2°/unit\n")) .arg(nFlap+1) .arg(m_ControlGain[iCtrl],5,'f',2); PolarProperties +=strong; } nFlap++; iCtrl++; } } } //elevator next nFlap = 0; if(pStab) { for (j=0; jm_NSurfaces; j++) { if(pStab->m_Surface[j].m_bTEFlap) { if(qAbs(m_ControlGain[iCtrl])>PRECISION) { strong = QString(QString::fromUtf8("Elev. Flap %1: gain=%2°/unit\n")) .arg(nFlap+1) .arg(m_ControlGain[iCtrl],5,'f',2); PolarProperties +=strong; } nFlap++; iCtrl++; } } } nFlap = 0; if(pFin) { for (j=0; jm_NSurfaces; j++) { if(pFin->m_Surface[j].m_bTEFlap) { if(qAbs(m_ControlGain[iCtrl])>PRECISION) { strong = QString(QString::fromUtf8("Fin Flap %1: gain=%2°/unit\n")) .arg(nFlap+1) .arg(m_ControlGain[iCtrl],5,'f',2); PolarProperties +=strong; } nFlap++; iCtrl++; } } } } if(m_bAutoInertia) { PolarProperties += "Using plane inertia\n"; } strong = QString(QObject::tr("Mass")+" = %1 ").arg(m_Mass*MainFrame::s_kgtoUnit,10,'f',3); PolarProperties += strong + massunit + "\n"; strong = QString(QObject::tr("CoG.x")+" = %1 ").arg(m_CoG.x*MainFrame::s_mtoUnit,10,'g',4); PolarProperties += strong + lenunit + "\n"; strong = QString(QObject::tr("CoG.z")+" = %1 ").arg(m_CoG.z*MainFrame::s_mtoUnit,10,'g',4); PolarProperties += strong + lenunit + "\n"; if(m_WPolarType==STABILITYPOLAR) { strong = QString("Ixx = %1 ").arg(m_CoGIxx*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit*MainFrame::s_kgtoUnit,10,'g',4); PolarProperties += strong + inertiaunit + "\n"; strong = QString("Iyy = %1 ").arg(m_CoGIyy*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit*MainFrame::s_kgtoUnit,10,'g',4); PolarProperties += strong + inertiaunit + "\n"; strong = QString("Izz = %1 ").arg(m_CoGIzz*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit*MainFrame::s_kgtoUnit,10,'g',4); PolarProperties += strong + inertiaunit + "\n"; strong = QString("Ixz = %1 ").arg(m_CoGIxz*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit*MainFrame::s_kgtoUnit,10,'g',4); PolarProperties += strong + inertiaunit + "\n"; } if(m_AnalysisMethod !=LLTMETHOD) { if(m_bDirichlet) strong = QObject::tr("B.C. = Dirichlet"); else strong = QObject::tr("B.C. = Neumann"); PolarProperties += strong +"\n"; } PolarProperties += QObject::tr("Analysis type")+" = "; if(m_bViscous) PolarProperties += QObject::tr("Viscous")+"\n"; else PolarProperties += QObject::tr("Inviscid")+"\n"; if(pPlane) { PolarProperties += QObject::tr("Body option")+" = "; if(m_bIgnoreBodyPanels) PolarProperties += QObject::tr("Body Panels Ignored")+"\n"; // else PolarProperties += QObject::tr("Body Included")+"\n"; } PolarProperties += QObject::tr("Ref. Area = "); if(m_RefAreaType==1) PolarProperties += QObject::tr("Planform area")+"\n"; else PolarProperties += QObject::tr("Projected area")+"\n"; if(m_bTiltedGeom) PolarProperties += QObject::tr("Tilted geometry")+"\n"; if(m_bGround) { strong = QString(QObject::tr("Ground height")+" = %1").arg(m_Height*MainFrame::s_mtoUnit)+lenunit+"\n"; PolarProperties += strong; } strong = QString(QObject::tr("Density =")+"%1 kg/m3\n").arg(m_Density,12,'g',4); PolarProperties += strong; strong = QString(QObject::tr("Viscosity =")+"%1").arg(m_Viscosity,12,'g',4); strong += "m"+QString::fromUtf8("²")+"/s\n"; PolarProperties += strong; strong = QString(QObject::tr("Data points") +" = %1\n").arg(m_Alpha.size()); PolarProperties += "\n"+strong; if(!bData) return; QTextStream out; strong.clear(); out.setString(&strong); Export(out, MainFrame::s_ExportFileType, true); PolarProperties += "\n"+strong; } /** * Maps the inertia data from the parameter object to the polar's variales * @param ptr a void pointer to the reference wing or plane instance * @param bPlane true if the reference object is a plane, false if it is a wing */ void WPolar::RetrieveInertia(void *ptr, bool bPlane) { Plane *pPlane = NULL; Wing *pWing = NULL; if(bPlane) { pPlane = (Plane*)ptr; m_Mass = pPlane->TotalMass(); m_CoG = pPlane->CoG(); m_CoGIxx = pPlane->m_CoGIxx; m_CoGIyy = pPlane->m_CoGIyy; m_CoGIzz = pPlane->m_CoGIzz; m_CoGIxz = pPlane->m_CoGIxz; } else { pWing = (Wing*)ptr; m_Mass = pWing->TotalMass(); m_CoG = pWing->m_CoG; m_CoGIxx = pWing->m_CoGIxx; m_CoGIyy = pWing->m_CoGIyy; m_CoGIzz = pWing->m_CoGIzz; m_CoGIxz = pWing->m_CoGIxz; } ResetWPlr(); } xflr5-6.09-06/src/objects/Plane.h000644 001750 000144 00000015072 12247174407 017733 0ustar00techwinderusers000000 000000 /**************************************************************************** CPlane Class Copyright (C) 2006-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file * * This file implements the class for the Plane object. */ #ifndef PLANE_H #define PLANE_H /** *@class Plane *@brief * The class which defines the Plane object used in 3D calculations. * - defines the plane object * - provides the methods for the calculation of the plane's geometric properties * The data is stored in International Standard Units, i.e. meters, kg, and seconds * Angular data is stored in degrees */ #include "Wing.h" #include "Body.h" class Plane { friend class PlaneDlg; public: Plane(); ~Plane(); static void SetParents(void *pMainFrame, void*pMiarex); double TotalMass(); double TailVolume(); void Duplicate(Plane *pPlane); bool SerializePlane(QDataStream &ar, bool bIsStoring); void ComputePlane(void); void CreateSurfaces(); void RenameWings(); void SetBody(Body *pBody); void ClearPointMasses(); void ComputeVolumeInertia(double &Mass, CVector &CoG, double &Ixx, double &Iyy, double &Izz, double &Ixz); void ComputeBodyAxisInertia(); void setAutoBodyName(); int VLMPanelTotal(); /** * Returns the translation to be applied to the Body object. * @return the translation to be applied to the Body object. */ CVector BodyPos(){ return m_BodyPos; } /** * Returns the leading edge, root position of a specified Wing. * @param iw the index of the Wing for which the LE position will be returned * @return the LE position of the Wing */ CVector WingLE(int iw){return m_WingLE[iw];} /** * Returns the tilt angle of a specified Wing. * @param iw the index of the Wing for which the tilt angle will be returned * @return the LE position of the Wing */ double WingTiltAngle(int iw){ return m_WingTiltAngle[iw];} /** Returns true if the plane has a secondary main wing, false otherwise.*/ bool BiPlane(){return m_bBiplane;} /** Returns the Plane's name. */ const QString& PlaneName() const {return m_PlaneName;} /** Returns a reference to the QString holding the Plane's name. */ QString& rPlaneName() {return m_PlaneName;} /** Returns the Plane's description. */ const QString& PlaneDescription() const {return m_PlaneDescription;} /** Returns a reference to the QString holding the Plane's description. */ QString& rPlaneDescription() {return m_PlaneDescription;} /** Returns a pointer to the Plane's main wing. Never NULL, a Plane always has a main Wing. */ Wing *wing() {return m_Wing;} /** Returns a pointer to the Plane's secondary wing, or NULL if none. */ Wing *wing2() {if(m_bBiplane) return m_Wing+1; else return NULL;} /** Returns a pointer to the Plane's elevator, or NULL if none. */ Wing *stab() {if(m_bStab) return m_Wing+2; else return NULL;} /** Returns a pointer to the Plane's fin, or NULL if none. */ Wing *fin() {if(m_bFin) return m_Wing+3; else return NULL;} /** Returns a pointer to the Plane's Body, or NULL if none. */ Body *body() {if(m_bBody) return m_pBody; else return NULL;} /** Returns the Plane's CoG position */ CVector CoG() {return m_CoG;} private: static void * s_pMiarex; /**< a void static pointer to the QMiarex object */ static void * s_pMainFrame; /**< a void static pointer to the MainFrame object */ Wing m_Wing[MAXWINGS]; /**< the array of Wing objects used to define this Plane */ Body *m_pBody; /**< a pointer to the Body object, a NULL if none */ bool m_bBody; /**< true if a Body has been selected for this plane */ bool m_bBiplane; /**< true if this Plane is a bi-plane */ bool m_bFin; /**< true if this Plane has a fin*/ bool m_bStab; /**< true if this Plane has an elevator */ double m_VolumeMass; /**< the mass of the Plane's structure, excluding point masses */ double m_TotalMass; /**< the Plane's total mass, i.e. the sum of the volume mass and of the point masses */ QString m_PlaneName; /**< the Plane's name; this name is used to identify the object and as a reference for child WPolar and PlaneOpp objects. */ QString m_PlaneDescription; /**< a free description */ double m_TailVolume; /**< the tail volume, i.e lever_arm_elev x Area_Elev / MAC_wing / Area_wing */ CVector m_CoG; /**< the position of the CoG */ CVector m_WingLE[MAXWINGS]; /**< the array of the leading edge postion of each Wing */ double m_WingTiltAngle[MAXWINGS]; /**< the rotation in degrees of each Wing about the y-axis */ CVector m_BodyPos; /**< the translation vector to apply to the Body */ public: QString m_BodyName; /**< identifies this plane's body */ QList m_PointMass; /**< the array of PointMass objects */ double m_CoGIxx; /**< the Ixx component of the inertia tensor, calculated at the CoG */ double m_CoGIyy; /**< the Ixx component of the inertia tensor, calculated at the CoG */ double m_CoGIzz; /**< the Ixx component of the inertia tensor, calculated at the CoG */ double m_CoGIxz; /**< the Ixx component of the inertia tensor, calculated at the CoG */ bool m_bDoubleFin; /**< true if the plane has a double fin, i.e. left and right */ bool m_bSymFin; /**< true if the plane has a symetric fin, i.e. top and bottom */ bool m_bDoubleSymFin; /**< true if the plane has a double and symetric fin */ }; #endif xflr5-6.09-06/src/objects/Plane.cpp000644 001750 000144 00000047221 12247174407 020267 0ustar00techwinderusers000000 000000 /**************************************************************************** CPlane Class Copyright (C) 2006-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "Plane.h" #include "../miarex/Miarex.h" #include "../globals.h" #include void* Plane::s_pMainFrame; void* Plane::s_pMiarex ; /** The public constructor. */ Plane::Plane() { m_pBody = NULL; m_Wing[0].m_WingName = QObject::tr("Wing"); m_Wing[0].ComputeGeometry(); m_Wing[1].m_WingName = QObject::tr("2nd Wing"); m_Wing[1].ComputeGeometry(); m_Wing[2].m_WingName = QObject::tr("Elevator"); m_Wing[2].m_bIsFin = false; m_Wing[2].Chord(0) = 0.100; m_Wing[2].Chord(1) = 0.080; m_Wing[2].YPosition(0) = 0.0; m_Wing[2].YPosition(1) = 0.150; m_Wing[2].Length(0) = 0.0; m_Wing[2].Length(1) = 0.150; m_Wing[2].Offset(0) = 0.0; m_Wing[2].Offset(1) = 0.020; m_Wing[2].NXPanels(0) = 7; m_Wing[2].NYPanels(0) = 7; m_Wing[2].XPanelDist(0) = SINE; m_Wing[2].YPanelDist(0) = UNIFORM; m_Wing[2].ComputeGeometry(); m_Wing[3].m_WingName = QObject::tr("Fin"); m_Wing[3].m_bIsFin = true; m_Wing[3].Chord(0) = 0.100; m_Wing[3].Chord(1) = 0.060; m_Wing[3].YPosition(0) = 0.000; m_Wing[3].YPosition(1) = 0.120; m_Wing[3].Length(0) = 0.000; m_Wing[3].Length(1) = 0.120; m_Wing[3].Offset(0) = 0.000; m_Wing[3].Offset(1) = 0.040; m_Wing[3].NXPanels(0) = 7; m_Wing[3].NYPanels(0) = 7; m_Wing[3].XPanelDist(0) = UNIFORM; m_Wing[3].YPanelDist(0) = COSINE; m_Wing[3].ComputeGeometry(); m_TailVolume = 0.0; m_WingLE[2].x = 0.600; m_WingLE[2].y = 0.0; m_WingLE[2].z = 0.0; m_WingLE[3].x = 0.650; m_WingLE[3].y = 0.0; m_WingLE[3].z = 0.0; for(int iw=0; iwm_VolumeMass>PRECISION) { //the inertia of the wings are base on the surface geometry; //these surfaces have been translated to the LE position as they were created pWing[iw]->ComputeVolumeInertia(CoGWing[iw], Ixx, Iyy, Izz, Ixz); CoG += CoGWing[iw] * pWing[iw]->m_VolumeMass;// so we do not add again the LE position PlaneMass += pWing[iw]->m_VolumeMass; CoGIxx += Ixx; CoGIyy += Iyy; CoGIzz += Izz; CoGIxz += Ixz; } } if(body()) { if(m_pBody->m_VolumeMass>PRECISION) { m_pBody->ComputeVolumeInertia(CoGBody, Ixx, Iyy, Izz, Ixz); CoG += (CoGBody+m_BodyPos) * m_pBody->m_VolumeMass; PlaneMass += m_pBody->m_VolumeMass; CoGIxx += Ixx; CoGIyy += Iyy; CoGIzz += Izz; CoGIxz += Ixz; } } if(PlaneMass>0.0) CoG *= 1.0/ PlaneMass; else CoG.Set(0.0, 0.0, 0.0); // Deduce inertia tensor in plane CoG from Huyghens/Steiner theorem // we transfer the inertia of each component, defined in its own CG, // to the new origin which is the plane's Volume CoG, excluding point masses for(int iw=0; iw<4; iw++) { if(pWing[iw]) { Pt = CoGWing[iw] - CoG; CoGIxx += pWing[iw]->m_VolumeMass * (Pt.y*Pt.y + Pt.z*Pt.z); CoGIyy += pWing[iw]->m_VolumeMass * (Pt.x*Pt.x + Pt.z*Pt.z); CoGIzz += pWing[iw]->m_VolumeMass * (Pt.x*Pt.x + Pt.y*Pt.y); CoGIxz -= pWing[iw]->m_VolumeMass * Pt.x*Pt.z; } } if(body()) { Pt = CoGBody - CoG; CoGIxx += m_pBody->m_VolumeMass * (Pt.y*Pt.y + Pt.z*Pt.z); CoGIyy += m_pBody->m_VolumeMass * (Pt.x*Pt.x + Pt.z*Pt.z); CoGIzz += m_pBody->m_VolumeMass * (Pt.x*Pt.x + Pt.y*Pt.y); CoGIxz -= m_pBody->m_VolumeMass * Pt.x*Pt.z; } Mass = PlaneMass; } /** * Calculates the inertia tensor in geometrical (body) axis : * - adds the volume inertia AND the inertia of point masses of all components * - the body axis is the frame in which the geometry has been defined * - the origin is the plane's CoG, taking into account all masses */ void Plane::ComputeBodyAxisInertia() { int i, iw; CVector VolumeCoG, MassPos; Wing *pWing[MAXWINGS]; double Ixx, Iyy, Izz, Ixz, VolumeMass; Ixx = Iyy = Izz = Ixz = VolumeMass = 0.0; pWing[0] = m_Wing; if(m_bBiplane) pWing[1] = m_Wing+1; else pWing[1] = NULL; if(m_bStab) pWing[2] = m_Wing+2; else pWing[2] = NULL; if(m_bFin) pWing[3] = m_Wing+3; else pWing[3] = NULL; ComputeVolumeInertia(VolumeMass, VolumeCoG, Ixx, Iyy, Izz, Ixz); m_TotalMass = VolumeMass; m_CoG = VolumeCoG *VolumeMass; // add point masses for(i=0; imass(); m_CoG += m_PointMass[i]->position() * m_PointMass[i]->mass(); } for(iw=0; iwm_PointMass.size(); i++) { m_TotalMass += pWing[iw]->m_PointMass[i]->mass(); m_CoG += (pWing[iw]->m_PointMass[i]->position()+ m_WingLE[iw]) * pWing[iw]->m_PointMass[i]->mass(); } } } if(body()) { for(i=0; im_PointMass.size(); i++) { m_TotalMass += m_pBody->m_PointMass[i]->mass(); m_CoG += (m_pBody->m_PointMass[i]->position()+m_BodyPos) * m_pBody->m_PointMass[i]->mass(); } } if(m_TotalMass>PRECISION) m_CoG = m_CoG/m_TotalMass; else m_CoG.Set(0.0,0.0,0.0); // The CoG position is now available, so calculate the inertia w.r.t the Total CoG, including point masses // The total CoG is the new origin for this calculation, so we transfer the other inertias using Huygens/Steiner theorem // LA is the displacement vector from the centre of mass to the new axis MassPos = m_CoG - VolumeCoG; m_CoGIxx = Ixx + VolumeMass * (MassPos.y*MassPos.y+ MassPos.z*MassPos.z); m_CoGIyy = Iyy + VolumeMass * (MassPos.x*MassPos.x+ MassPos.z*MassPos.z); m_CoGIzz = Izz + VolumeMass * (MassPos.x*MassPos.x+ MassPos.y*MassPos.y); m_CoGIxz = Ixz - VolumeMass * MassPos.x*MassPos.z; for(i=0; iposition(); m_CoGIxx += m_PointMass[i]->mass() * (MassPos.y*MassPos.y + MassPos.z*MassPos.z); m_CoGIyy += m_PointMass[i]->mass() * (MassPos.x*MassPos.x + MassPos.z*MassPos.z); m_CoGIzz += m_PointMass[i]->mass() * (MassPos.x*MassPos.x + MassPos.y*MassPos.y); m_CoGIxz -= m_PointMass[i]->mass() * (MassPos.x*MassPos.z); } for(iw=0; iwm_PointMass.size(); i++) { MassPos = m_CoG - (pWing[iw]->m_PointMass[i]->position() + m_WingLE[iw]); m_CoGIxx += pWing[iw]->m_PointMass[i]->mass() * (MassPos.y*MassPos.y + MassPos.z*MassPos.z); m_CoGIyy += pWing[iw]->m_PointMass[i]->mass() * (MassPos.x*MassPos.x + MassPos.z*MassPos.z); m_CoGIzz += pWing[iw]->m_PointMass[i]->mass() * (MassPos.x*MassPos.x + MassPos.y*MassPos.y); m_CoGIxz -= pWing[iw]->m_PointMass[i]->mass() * (MassPos.x*MassPos.z); } } } if(body()) { Body *pBody = m_pBody; for(i=0; im_PointMass.size(); i++) { MassPos = m_CoG - (pBody->m_PointMass[i]->position() + m_BodyPos); m_CoGIxx += pBody->m_PointMass[i]->mass() * (MassPos.y*MassPos.y + MassPos.z*MassPos.z); m_CoGIyy += pBody->m_PointMass[i]->mass() * (MassPos.x*MassPos.x + MassPos.z*MassPos.z); m_CoGIzz += pBody->m_PointMass[i]->mass() * (MassPos.x*MassPos.x + MassPos.y*MassPos.y); m_CoGIxz -= pBody->m_PointMass[i]->mass() * (MassPos.x*MassPos.z); } } } /** * Calculates the Plane's tail volume = lever_arm_elev x Area_Elev / MAC_Wing / Area_Wing */ void Plane::ComputePlane(void) { int i; if(m_bStab) { double SLA = m_WingLE[2].x + m_Wing[2].Chord(0)/4.0 - m_Wing[0].Chord(0)/4.0; double area = m_Wing[0].m_ProjectedArea; if(m_bBiplane) area += m_Wing[1].m_ProjectedArea; double ProjectedArea = 0.0; for (i=0;im_PlaneName; m_PlaneDescription = pPlane->m_PlaneDescription; RenameWings(); m_bFin = pPlane->m_bFin; m_bSymFin = pPlane->m_bSymFin; m_bDoubleFin = pPlane->m_bDoubleFin; m_bDoubleSymFin = pPlane->m_bDoubleSymFin; m_bStab = pPlane->m_bStab; m_bBiplane = pPlane->m_bBiplane; m_TailVolume = pPlane->m_TailVolume; for(int iw=0; iwm_WingTiltAngle[iw]; m_WingLE[iw] = pPlane->m_WingLE[iw]; m_Wing[iw].Duplicate(pPlane->m_Wing+iw); } m_BodyPos.Copy(pPlane->m_BodyPos); m_TotalMass = pPlane->m_TotalMass; m_CoG = pPlane->m_CoG; m_CoGIxx = pPlane->m_CoGIxx; m_CoGIyy = pPlane->m_CoGIyy; m_CoGIzz = pPlane->m_CoGIzz; m_CoGIxz = pPlane->m_CoGIxz; ClearPointMasses(); for(int i=0; im_PointMass.size();i++) { m_PointMass.append(new PointMass(pPlane->m_PointMass[i])); } m_bBody = pPlane->m_bBody ; if(m_bBody) { m_pBody = new Body(); m_pBody->Duplicate(pPlane->m_pBody); } setAutoBodyName(); } void Plane::setAutoBodyName() { if(!m_pBody) m_BodyName.clear(); else { m_BodyName = m_PlaneName+"_body"; m_pBody->m_BodyName = m_PlaneName+"_body"; } } /** * Returns the plane's tail volume * @return the plane's tail volume */ double Plane::TailVolume() { if(m_bStab) return m_TailVolume; else return 0.0; } /** * Returns the Plane's total mass, i.e. the sum of Volume and Point masses of all its components. * @return the Plane's total mass. */ double Plane::TotalMass() { static double Mass; Mass = m_Wing[0].TotalMass(); if(m_bBiplane) Mass += m_Wing[1].TotalMass(); if(m_bStab) Mass += m_Wing[2].TotalMass(); if(m_bFin) Mass += m_Wing[3].TotalMass(); if(body()) Mass += m_pBody->TotalMass(); for(int i=0; imass(); return Mass; } /** * Loads or Saves the data of this Plane to a binary file. * @param ar the QDataStream object from/to which the data should be serialized * @param bIsStoring true if saving the data, false if loading * @return true if the operation was successful, false otherwise */ bool Plane::SerializePlane(QDataStream &ar, bool bIsStoring) { QMiarex *pMiarex = (QMiarex*)s_pMiarex; int i, nMass; float f,g,h; QString strong = ""; int ArchiveFormat;// identifies the format of the file if (bIsStoring) { // storing code ar << 1013; //1013 : v6.09.06 added pbody serialization //1012 : QFLR5 v0.03 : added mass properties for inertia calculations //1011 : QFLR5 v0.02 : added Plane description field //1010 : added body LE x and z position //1009 : added Main wing LE x and z position //1008 : added body data //1007 : added second wing data, CheckPanel //1006 : Converted lengths to m //1005 : stored double sym fin //1004 : suppressed colors //1003 : Added fin tilt; //1002 : Added doublefin; WriteCString(ar, m_PlaneName); WriteCString(ar, m_PlaneDescription); m_Wing[0].SerializeWing(ar, true); m_Wing[1].SerializeWing(ar, true); m_Wing[2].SerializeWing(ar, true); m_Wing[3].SerializeWing(ar, true); if(m_bStab) ar <<1; else ar <<0; if(m_bFin) ar <<1; else ar <<0; if(m_bDoubleFin) ar <<1; else ar <<0; if(m_bSymFin) ar <<1; else ar <<0; if(m_bDoubleSymFin) ar <<1; else ar <<0; // if(m_bCheckPanels) ar <<1; else ar <<0; ar << 0; if(m_bBiplane) ar <<1; else ar <<0; ar << m_WingLE[1].x << m_WingLE[1].y << m_WingLE[1].z << m_WingTiltAngle[1]; ar << m_WingLE[2].x << m_WingLE[2].y << m_WingLE[2].z; ar << m_WingTiltAngle[0] << m_WingTiltAngle[2] << m_WingTiltAngle[3] ; ar << m_WingLE[3].x << m_WingLE[3].y << m_WingLE[3].z; ar << m_BodyPos.x << m_BodyPos.z; ar << m_WingLE[0].x << m_WingLE[0].z; if(m_bBody && m_pBody) { ar <<1; WriteCString(ar, m_BodyName); } else { ar << 0; WriteCString(ar, strong); } ar << m_PointMass.size(); for(i=0; imass(); for(i=0; iposition().x << (float)m_PointMass[i]->position().y << (float)m_PointMass[i]->position().z; for(i=0; itag()); if(m_bBody) { m_pBody->SerializeBody(ar, true); } return true; } else { // loading code int k; ar >> ArchiveFormat; if (ArchiveFormat <1001 || ArchiveFormat>1100) { m_PlaneName = ""; return false; } ReadCString(ar,m_PlaneName); if (m_PlaneName.length() ==0) return false; if(ArchiveFormat>=1011) ReadCString(ar, m_PlaneDescription); /**@todo remove non active wings from serialization */ m_Wing[0].SerializeWing(ar, false); if(ArchiveFormat>=1007) m_Wing[1].SerializeWing(ar, false); m_Wing[2].SerializeWing(ar, false); m_Wing[3].SerializeWing(ar, false); ar >>k; if(k) m_bStab = true; else m_bStab = false; ar >>k; if(k) m_bFin = true; else m_bFin = false; if(ArchiveFormat>=1002) { ar >>k; if(k) m_bDoubleFin = true; else m_bDoubleFin = false; m_Wing[3].m_bDoubleFin = m_bDoubleFin; ar >>k; if(k) m_bSymFin = true; else m_bSymFin = false; m_Wing[3].m_bSymFin = m_bSymFin; } if(ArchiveFormat>=1005) { ar >>k; if(k) m_bDoubleSymFin = true; else m_bDoubleSymFin = false; m_Wing[3].m_bDoubleSymFin = m_bDoubleSymFin; } if(ArchiveFormat>=1007) { ar >>k; // if(k) m_bCheckPanels = true; else m_bCheckPanels = false; ar >>k; if(k) m_bBiplane = true; else m_bBiplane = false; ar >> m_WingLE[1].x >> m_WingLE[1].y >> m_WingLE[1].z >> m_WingTiltAngle[1]; } ar >> m_WingLE[2].x >> m_WingLE[2].y >> m_WingLE[2].z; ar >> m_WingTiltAngle[0] >> m_WingTiltAngle[2]; if(ArchiveFormat>=1003){ ar >> m_WingTiltAngle[3]; } ar >> m_WingLE[3].x >> m_WingLE[3].y >> m_WingLE[3].z; if(ArchiveFormat>=1010) { ar >> m_BodyPos.x >> m_BodyPos.z; } if(ArchiveFormat>=1009) { ar>> m_WingLE[0].x >> m_WingLE[0].z; } if(ArchiveFormat<1004) { QColor cr; ReadCOLORREF(ar,cr); ReadCOLORREF(ar,cr); ReadCOLORREF(ar,cr); } if(ArchiveFormat<1006) { //convert to m m_WingLE[2].x /= 1000.0; m_WingLE[2].y /= 1000.0; m_WingLE[2].z /= 1000.0; m_WingLE[3].x /= 1000.0; m_WingLE[3].y /= 1000.0; m_WingLE[3].z /= 1000.0; } if(ArchiveFormat>=1008) { ar >> k; if(k) m_bBody=true; else m_bBody=false; ReadCString(ar,strong); m_BodyName = strong; if(m_BodyName.length()) m_pBody = pMiarex->GetBody(strong); else m_pBody = NULL; //redundant } else m_pBody = NULL; if(ArchiveFormat>=1012) { ar >> nMass; double* mass = new double[nMass]; CVector* position = new CVector[nMass]; QStringList tag; for(int im=0; im> f; mass[im] = f; } for(int im=0; im> f >> g >> h; position[im] = CVector(f,g,h); } for(int im=0; im=1013) { if(m_bBody) { m_pBody = new Body; m_pBody->SerializeBody(ar, false); } } ComputePlane(); return true; } } /** Destroys the PointMass objects in good order to avoid memory leaks */ void Plane::ClearPointMasses() { for(int ipm=m_PointMass.size()-1; ipm>=0; ipm--) { delete m_PointMass.at(ipm); m_PointMass.removeAt(ipm); } } /** * Initializes the pointers to the application's widgets. */ void Plane::SetParents(void *pMainFrame, void*pMiarex) { s_pMainFrame = pMainFrame; s_pMiarex = pMiarex; } /** * Renames each of the Plane's Wing objects with an automatic name. */ void Plane::RenameWings() { m_Wing[0].m_WingName = m_PlaneName+"_Wing"; m_Wing[1].m_WingName = m_PlaneName+"_Wing2"; m_Wing[2].m_WingName = m_PlaneName+"_Elev"; m_Wing[3].m_WingName = m_PlaneName+"_Fin"; } /** * Creates the Surface objects associated to each of the Plane's Wing objects. */ void Plane::CreateSurfaces() { m_Wing[0].CreateSurfaces(m_WingLE[0], 0.0, m_WingTiltAngle[0]); m_Wing[1].CreateSurfaces(m_WingLE[1], 0.0, m_WingTiltAngle[1]); m_Wing[2].CreateSurfaces(m_WingLE[2], 0.0, m_WingTiltAngle[2]); m_Wing[3].CreateSurfaces(m_WingLE[3], -90.0, m_WingTiltAngle[3]); } /** * Initiliazes the pointer to an existing Body object * @param pBody the pointer to the existing Body object */ void Plane::SetBody(Body *pBody) { if(!pBody) { m_bBody = false; m_pBody = NULL; m_BodyName.clear(); } else { m_bBody = true; m_pBody = pBody; setAutoBodyName(); } } /** * Returns the number of mesh panels defined on this Plane's surfaces. * @return the number of mesh panels */ int Plane::VLMPanelTotal() { int total = wing()->VLMPanelTotal(true); if(wing2()) total += wing2()->VLMPanelTotal(true); if(stab()) total += stab()->VLMPanelTotal(true); if(fin()) { if(m_bDoubleFin ||m_bSymFin) total += 2*fin()->VLMPanelTotal(true); else total += fin()->VLMPanelTotal(true); } if(body()) total += body()->m_nxPanels * body()->m_nhPanels * 2; return total; } xflr5-6.09-06/src/objects/Wing.h000644 001750 000144 00000034236 12247174403 017577 0ustar00techwinderusers000000 000000 /**************************************************************************** Wing Class Copyright (C) 2005-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** @file This file implements the Wing class. */ #ifndef WING_H #define WING_H #include "WPolar.h" #include "Surface.h" #include "Panel.h" #include "WingSection.h" #include "PointMass.h" /** * @class Wing * @brief This class defines the wing object, provides the methods for the calculation of the wing geometric properties, and provides methods for LLT, VLM and Panel methods. * * A wing is identified and reference by its name, which is used by the parent Plane objects and by child Polar and WingOPpp objects. * * The wing is defined by geometric data at a finite number of span-stations : chord, chord position, foil, dihedral and washout. * * The panel between two span-stations is a WingSection object. The term "panel" is reserved for the mesh panels used to perform a VLM or Panel analysis. * @todo check variable names for consistency with this rule. * * The term stations is reserved for the spanwise points used by the LLT, or by the spanwise position of the panels in a VLM or panel analysis. * During an LLT or a Panel analysis, the value of the aerodynamic parameters of interest are stored in the member variables of this Wing object. * The data is retrieved and stored in an operating point at the end of the analysis. * The choice to include the wing-specific methods used in the analysis in this wing class is arbitrary. It simplifies somewhat the implementation * of the LLTAnalysis and PanelAnalysisDlg classes, but makes this Wing class more complex. * * The data is stored in International Standard Units, i.e. meters, kg, and seconds. Angular data is stored in degrees. */ class Wing { friend class QMiarex; friend class MainFrame; friend class WPolar; friend class PlaneOpp; friend class Plane; friend class Surface; friend class WingDlg; friend class LLTAnalysisDlg; friend class LLTAnalysis; friend class PanelAnalysisDlg; friend class PlaneDlg; friend class ImportWingDlg; friend class WPolarDlg; friend class StabPolarDlg; friend class GL3dWingDlg; friend class ManageUFOsDlg; friend class InertiaDlg; friend class StabViewDlg; public: Wing(); ~Wing(); void ImportDefinition(QString path_to_file); void ExportDefinition(QString path_to_file); void GetViewYZPos(double xrel, double y, double &yv, double &zv, int pos); void CreateSurfaces(CVector const &T, double XTilt, double YTilt);//generic surface, LLT, VLM or Panel int VLMPanelTotal(bool bThinSurface); void VLMSetBending(); void PanelTrefftz(double QInf, double Alpha, double *Mu, double *Sigma, int pos, CVector &Force, double &WingIDrag, WPolar *pWPolar, Panel *pWakePanel, CVector *pWakeNode); void PanelComputeOnBody(double QInf, double Alpha, double *Cp, double *Gamma, double &XCP, double &YCP, double &ZCP, double &GCm, double &VCm, double &ICm, double &GRm, double &GYm, double &VYm,double &IYm, WPolar *pWPolar, CVector CoG); void PanelComputeViscous(double QInf, double Alpha, WPolar *pWPolar, double &WingVDrag, bool bViscous, QString &OutString); void PanelComputeBending(bool bThinSurface); bool IsWingPanel(int nPanel); bool IsWingNode(int nNode); void GetFoils(Foil **pFoil0, Foil **pFoil1, double y, double &t); void Duplicate(Wing *pWing); void ComputeChords(int NStation=0); void ComputeChords(int NStation, double *chord, double *offset, double *twist); void ComputeGeometry(); void ComputeVolumeInertia(CVector &CoG, double &CoGIxx, double &CoGIyy, double &CoGIzz, double &CoGIxz); void ComputeBodyAxisInertia(); void ScaleSweep(double NewSweep); void ScaleTwist(double NewTwist); void ScaleSpan(double NewSpan); void ScaleChord(double NewChord); bool SerializeWing(QDataStream &ar, bool bIsStoring); bool ExportAVLWing(QTextStream &out, int index, double x, double y, double z, double Thetax, double Thetay); bool IsWingOut() {return m_bWingOut;} bool IsFin() {return m_bIsFin;} bool IsDoubleFin() {return m_bDoubleFin;} bool IsSymFin() {return m_bSymFin;} bool IsDoubleSymFin() {return m_bDoubleSymFin;} void InsertSection(int iSection); bool AppendWingSection(); bool AppendWingSection(double Chord, double Twist, double Pos, double Dihedral, double Offset, int NXPanels, int NYPanels, enumPanelDistribution XPanelDist, enumPanelDistribution YPanelDist, QString RightFoilName, QString LeftFoilName); void RemoveWingSection(int const iSection); void ClearWingSections(); void ClearPointMasses(); //access methods int NWingSection() {return m_WingSection.count();} int &NXPanels(const int &iSection); int &NYPanels(const int &iSection); enumPanelDistribution &XPanelDist(const int &iSection); enumPanelDistribution &YPanelDist(const int &iSection); double RootChord() {return m_WingSection.first()->m_Chord;} double TipChord() {return m_WingSection.last()->m_Chord;} double TipTwist() {return m_WingSection.last()->m_Twist;} double TipOffset() {return m_WingSection.last()->m_Offset;} double TipPos() {return m_WingSection.last()->m_YPosition;} double &Chord(const int &iSection); double &Twist(const int &iSection); double &YPosition(const int &iSection); double &Dihedral(const int &iSection); double &Offset(const int &iSection); double &Length(const int &iSection); double &YProj(const int &iSection); double &ZPosition(const int &iSection); double yrel(double SpanPos); double Chord(double yob); double Offset(double yob); double Dihedral(double yob); double Twist(double y); double AverageSweep(); double TotalMass(); double C4(double yob, double xRef); double ZPosition(double y); double Beta(int m, int k); CVector CoG() {return m_CoG;} const QString& WingName() const {return m_WingName;} QString& rWingName() {return m_WingName;} const QString& WingDescription() const {return m_WingDescription;} QString &RightFoil(const int &iSection); QString &LeftFoil(const int &iSection); QString& rWingDescription() {return m_WingDescription;} //__________________________Variables_______________________ private: static void* s_pMiarex; /**< a static pointer to the Miarex Application window */ static void* s_p3DPanelDlg; /**< a static pointer to the instance of the PanelAnalysisDlg class if a calculation is on-going*/ static bool s_bVLMSymetric; /**< true if the vlm calculation is symmetric */ bool m_bWingOut; /**< true if the wing OpPoint is outside the flight envelope of the available Type 1 polar mesh */ bool m_bSymetric; /**< true if the wing's geometry is symetric */ bool m_bIsFin; /**< true if this wing describes a fin */ bool m_bDoubleFin; /**< true if the wing describes a double fin symetric about the y=0 plane */ double m_bSymFin; /**< true if the wing describes a double fin symetric about the z=0 plane */ double m_bDoubleSymFin; /**< true if the fin is both double and symetric */ int m_NStation; /**< the number of stations for wing calculation; either the number of points of LLT, or the number of spanwise panels */ int m_nNodes; /**< the number of nodes of the panel mesh */ int m_AVLIndex; /**< a random identification number needed to export to AVL */ int m_nFlaps; /**< the number of T.E. flaps, numbered from left wing to right wing; for a main wing this number is even*/ double m_FlapMoment[2*MAXSPANSECTIONS]; /**< the flap moments resulting from the panel of VLM analysis */ double m_QInf0; /**< the freestream velocity */ double m_VolumeMass; /**< the mass of the Wing's structure, excluding point masses */ double m_TotalMass; /**< the Wing's total mass, i.e. the sum of the volume mass and of the point masses */ double m_GChord; /**< the mean geometric chord */ double m_yMac; /**< the mean aerodynamic chord span position - @todo meaning and calculation are unclear*/ double m_CDi; /**< the wing's induced drag coefficient for the current calculation */ double m_CDv; /**< the wing's viscous drag coefficient for the current calculation */ double m_CL; /**< the lift coefficient */ double m_Maxa; /**< the convergence crtierion on the difference of induced angle at any span bewteen two LLT iterations*/ double m_ICm; /**< the induced par of the pitching moment coefficient */ double m_GCm; /**< the total pitching moment coefficient */ double m_VCm; /**< the viscous part of the pitching moment coefficient */ double m_GYm; /**< the total yawing moment coefficient */ double m_IYm; /**< the induced part of the yawing moment coefficient */ double m_VYm; /**< the viscous part of the yawing moment coefficient */ double m_GRm; /**< the geometric rolling moment coefficient */ CVector m_CP; /**< the centre of pressure's position */ /**< Span Coefficients resulting from VLM or LLT calculation @todo replace with QVarLenArray*/ double m_Ai[MAXSPANSTATIONS+1]; /**< the induced angles, in degrees */ double m_Cl[MAXSPANSTATIONS+1]; /**< the lift coefficient at stations */ double m_ICd[MAXSPANSTATIONS+1]; /**< the induced drag coefficient at stations */ double m_PCd[MAXSPANSTATIONS+1]; /**< the viscous drag coefficient at stations */ double m_Re[MAXSPANSTATIONS+1]; /**< the Reynolds number at stations */ double m_XTrTop[MAXSPANSTATIONS+1]; /**< the upper transition location at stations */ double m_XTrBot[MAXSPANSTATIONS+1]; /**< the lower transition location at stations */ double m_Cm[MAXSPANSTATIONS+1]; /**< the total pitching moment coefficient at stations */ double m_CmAirf[MAXSPANSTATIONS+1]; /**< the viscous part of the pitching moment coefficient at stations @todo check and rename*/ double m_XCPSpanRel[MAXSPANSTATIONS+1]; /**< the relative position of the strip's center of pressure at stations as a % of the local chord length*/ double m_XCPSpanAbs[MAXSPANSTATIONS+1]; /**< the absolute position of the strip's center of pressure pos at stations */ double m_Chord[MAXSPANSTATIONS+1]; /**< the chord at stations */ double m_Offset[MAXSPANSTATIONS+1]; /**< the offset at LLT stations */ double m_Twist[MAXSPANSTATIONS+1]; /**< the twist at LLT stations */ double m_StripArea[MAXSPANSTATIONS+1]; /**< the area of each chordwise strip */ double m_BendingMoment[MAXSPANSTATIONS+1]; /**< the bending moment at stations */ double m_SpanPos[MAXSPANSTATIONS+1]; /**< the span positions of LLT stations */ double m_xHinge[MAXCHORDPANELS]; /**< the chorwise position of flap hinges */ double m_xPanel[MAXCHORDPANELS]; /**< the chorwise distribution of VLM panels */ CVector m_Vd[MAXSPANSTATIONS]; /**< the downwash vector at span stations */ CVector m_F[MAXSPANSTATIONS]; /**< the lift vector at span stations */ public: QString m_WingName; /**< the wing's name; this name is used to identify the wing and as a reference for child Polar and WingOpp objects. */ QString m_WingDescription; /**< a text field for the description of the wing */ QColor m_WingColor; /**< the Wing's display color */ QList m_WingSection; /**< the array of wing sections. A WingSection extends between a foil and the next. */ QList m_PointMass; /**< the array of PointMass objects associated to this Wing object*/ int m_NSurfaces; /**< the number of Surface objects built on the wing geometry (=2 x number of WingSection) @todo replace with a QList*/ Surface m_Surface[2*MAXSPANSECTIONS]; /**< the array of Surface objects associated to the wing @todo replace with a QList*/ double m_MAChord; /**< the wing's mean aerodynamic chord */ double m_PlanformSpan; /**< the planform span, i.e. if the dihedral was 0 at each junction */ double m_ProjectedSpan; /**< the span projected on the xy plane defined by z=0 */ double m_PlanformArea; /**< the planform wing area, i.e. if the dihedral was 0 at each junction */ double m_ProjectedArea; /**< the wing area projected on the xy plane defined by z=0; */ double m_AR; /**< the wing's aspect ratio */ double m_TR; /**< the wing's taper ratio */ double m_CoGIxx; /**< the Ixx component of the inertia tensor, calculated at the CoG */ double m_CoGIyy; /**< the Ixx component of the inertia tensor, calculated at the CoG */ double m_CoGIzz; /**< the Ixx component of the inertia tensor, calculated at the CoG */ double m_CoGIxz; /**< the Ixx component of the inertia tensor, calculated at the CoG */ CVector m_CoG; /**< the position of the CoG */ int m_MatSize; /**< the number of mesh panels on this Wing; dependant on the polar type */ Panel *m_pWingPanel; /**< a pointer to the first panel of this wing in the array of panels */ }; #endif xflr5-6.09-06/src/objects/Surface.h000644 001750 000144 00000024556 12247174403 020267 0ustar00techwinderusers000000 000000 /**************************************************************************** CSurface Class Copyright (C) 2005-2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /*! @file * * @brief This class defines the surface object on which the panels are constructed for the VLM and 3d-panel calculations. * */ #ifndef SURFACE_H #define SURFACE_H #include "Foil.h" #include "Body.h" #include "CVector.h" #include "WingSection.h" #define VLMHALF 2500 /** *@class Surface *@brief * The class which defines the surface object on which the panels are constructed for the VLM and 3d-panel calculations. * The mesh panels are not constructed using the Wing object, but on this proxy Surface object. * A surface extends from one left Foil to the next right Foil in the spanwise directions. * The Surface's geometry is defined by * - its Leading edge : m_LA, m_LB * - its Trailing edge : m_TA, m_TB * - its left and right twist * - its left and right Foil objects * - its Normal vector * - its left and right normal vectors NormalA and NormalB are * the average of the normals of the two continuous surfaces ; used to define junction between panels * * The points and other geometric data may be requested by calling methods on any of the top, middle, or bottom surfaces. Surfaces are constructed and indexed from left tip to right tip. For a half-wing, there will be one surface less than the number of foils defined by the user. The letter A refers to the Surface's left side, and B refers to the right side. The letter L refers to the Leading upstream side, T refers to the Trailing downstream side A surface is described by its geometric properties inherited from the wing's definition. Surfaces with a span length less than a minimum value are ignored. A surface may only supports trailing edge flaps. A surface may not be flat if different washout angles have been defined at the tips. However the deviation from the flat panel is assumed to be small, and corresponding approximations are made. The process of Surface construction starts by the creation of the array of master points at each end Foil. These points are defined i.a.w. the number of panels and the type of distribution specified by the user. The panel points are interpolated between the left and right Foil points. This implies that a wing is built with a fixed number of chordwise panels all along the span. The panels on the surface are added incrementally to the global array of panels used for the panel analysis. The panels are numbered from left tip to right tip in the span wise direction. Then in the chordwise direction: from T.E. to L.E in the case of VLM from lower surface TE, to leading edge, and to upper surface TE The data is stored in International Standard Units, i.e. meters, seconds, kg, and Newtons. Angular data is stored in degrees. */ class Surface { friend class Wing; friend class QMiarex; friend class MainFrame; friend class GL3dWingDlg; friend class PanelAnalysisDlg; friend class InertiaDlg; friend class WPolar; public: Surface(); void AddFlapPanel(Panel *pPanel); void Copy(Surface const &Surface); void GetC4(int k, CVector &Pt, double &tau); void GetLeadingPt(int k, CVector &C); void GetNormal(double yrel, CVector &N); void GetTrailingPt(int k, CVector &C); void GetPanel(int const &k, int const &l, const enumPanelPosition &pos); void GetSurfacePoint(double const &xArel, double const &xBrel, double const &yrel, CVector &Point, int const &pos=0); void GetSurfacePointNormal(double const &xArel, double const &xBrel, double const &yrel, CVector &Point, CVector &PtNormal, int const &pos=0); void GetSection(double const &tau, double &Chord, double &Area, CVector &PtC4); void GetyDist(int const &k, double &y1, double &y2); void Init(); void ResetFlap(); void RotateX(CVector const &O, double XTilt); void RotateY(CVector const &O, double YTilt); void RotateZ(CVector const &O, double ZTilt); void SetNormal(); void SetFlap(); void SetSidePoints(Body *pBody, double dx, double dz); void SetTwist1(); void SetTwist2(); void Translate(CVector const &T); void Translate(double tx, double ty, double tz); void CreateXZSymetric(Surface const &Surface); void CreateXPoints(); bool IsCenterSurf() {return m_bIsCenterSurf;} bool IsLeftSurf() {return m_bIsLeftSurf;} bool IsRightSurf() {return m_bIsRightSurf;} bool IsTipLeft() {return m_bIsTipLeft;} bool IsTipRight() {return m_bIsTipRight;} bool IsInSymPlane() {return m_bIsInSymPlane;} bool IsFlapPanel(int const &p); bool IsFlapNode(int const &nNode); bool RotateFlap(double const &Angle); // bool RotateFlap(double const &Angle, CPanel *pPanel, CVector *pNode); double GetTwist(int const &k); double GetChord(int const &k); double GetChord(double const &tau); double GetOffset(double const &tau); double GetStripSpanPos(int const &k); double GetFoilArea(double const &tau); double GetStripWidth(int const &k); private : CVector SideA[MAXCHORDPANELS]; /**< the array of points on the left foil's mid-line*/ CVector SideB[MAXCHORDPANELS]; /**< the array of points on the right foil's mid-line*/ CVector SideA_T[MAXCHORDPANELS]; /**< the array of points on the left foil's top-line*/ CVector SideB_T[MAXCHORDPANELS]; /**< the array of points on the right foil's top-line*/ CVector SideA_B[MAXCHORDPANELS]; /**< the array of points on the left foil's bottom-line*/ CVector SideB_B[MAXCHORDPANELS]; /**< the array of points on the right foil's bottom-line*/ static CVector VTemp; static Panel *s_pPanel; /**< a pointer to the array of this Surface's panels, This array is a sub-array of the total array.*/ static CVector *s_pNode; /**< a pointer to the array of this panel nodes.*/ bool m_bIsInSymPlane; /**< true if the Surface is positioned in the symetry xz plane defined by y=0. Case of a single fin. */ bool m_bTEFlap; /**< true if the Surface has a flap on the trailing edge */ bool m_bIsLeftSurf; /**< true if the Surface is built on the left wing */ bool m_bIsRightSurf; /**< true if the Surface is built on the right wing */ bool m_bIsTipLeft; /**< true if the Surface is built on the tip left wing */ bool m_bIsTipRight; /**< true if the Surface is built on the tip right wing */ bool m_bIsCenterSurf; /**< true if the Surface is either a left or right center surface... need to connect to body */ CVector m_LA; /**< the Surface's leading left point */ CVector m_LB; /**< the Surface's leading right point */ CVector m_TA; /**< the Surface's trailing left point */ CVector m_TB; /**< the Surface's trailing right point */ CVector Normal; /**< the Surface's normal vector */ CVector NormalA; /**< the normal at the left tip, defined as the average of this Surface's normal and of the one adjacent on the left side, if any */ CVector NormalB; /**< the normal at the right tip, defined as the average of this Surface's normal and of the one adjacent on the right side, if any */ double m_TwistA; /**< the twist at side A in degrees */ double m_TwistB; /**< the twist at side B in degrees */ double m_Length; /**< the Surface's planform length from A to B*/ double chordA; /**< the chord length at tip A */ double chordB; /**< the chord length at tip B */ double m_posATE, m_posBTE; /**< the relative flap hinge positions at sides A and B */ double m_xPointA[MAXCHORDPANELS]; /**< the chordwise relative position of the VLM panel left corner points at side A */ double m_xPointB[MAXCHORDPANELS]; /**< the chordwise relative position of the VLM panel right corner points at side B */ double y1, y2, xLA, xTA, xLB, xTB; enumPanelDistribution m_XDistType; /**< the type of distribution along the Surface's x axis @todo replace with an enumeration*/ enumPanelDistribution m_YDistType; /**< the type of distribution along the Surface's y axis */ int m_NXLead; /**< the number of panels upstream of the flap, i.e. between the leading edge and the hinge */ int m_NXFlap; /**< the number of panels on the flap, i.e. between the hinge and the trailing edge */ int m_NElements; /**< the number of panel elements constructer on this Surface. */ int m_nFlapNodes; /**< the number of nodes defined on the trailing edge flap */ int m_nFlapPanels; /**< the number of panels defined on the trailing edge flap */ int m_FlapNode[VLMHALF]; /**< the array of flap node indexes, used to avoid defining two nodes at the same location */ int m_FlapPanel[VLMHALF]; /**< the array of flap panel indexes */ CVector m_HingePoint; /**< a point on the trailing flap hinge */ CVector m_HingeVector; /**< a vector which defines the axis of the hinge */ Surface *m_pLeftSurface; /**< a pointer to this Surface's left neighbour, or NULL if none */ Surface *m_pRightSurface; /**< a pointer to this Surface's right neighbour, or NULL if none */ public: bool m_bJoinRight; /**< true if the surface's right side should be connected to the next right surface's right left side - for panel analysis only */ static CVector LA, LB, TA, TB; /**< leading and trailing corners of strip k */ int m_NYPanels; /**< the number of spanwise panels of this surface */ int m_NXPanels; /**< the number of chordwise panels of this surface */ Foil *m_pFoilA; /**< a pointer to the Surface's left Foil object */ Foil *m_pFoilB; /**< a pointer to the Surface's right Foil object */ }; #endif xflr5-6.09-06/src/globals.h000644 001750 000144 00000012213 12247174406 016657 0ustar00techwinderusers000000 000000 /**************************************************************************** Global Functions Copyright (C) 2008-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** * @file * This file contains the declaration of methods used throughout the program and not specific to one application. */ #ifndef GLOBALS_H #define GLOBALS_H #include #include #include #include #include #include "params.h" #include "objects/CVector.h" #include "objects/Foil.h" #include "objects/Polar.h" #include using namespace std; bool IsEven(int n); bool IsBetween(int f, int f1, int f2); bool IsBetween(int f, double f1, double f2); bool Intersect(CVector const &LA, CVector const &LB, CVector const &TA, CVector const &TB, CVector const &Normal, CVector const &A, CVector const &U, CVector &I, double &dist); bool ReadAVLString(QTextStream &in, int &Line, QString &strong); bool Rewind1Line(QTextStream &in, int &Line, QString &strong); void ReadValues(QString line, int &res, double &x, double &y, double &z); void ExpFormat(double &f, int &exp); void ReynoldsFormat(QString &str, double f); bool Gauss(double *A, int n, double *B, int m, bool *pbCancel=NULL); void GetSpeedUnit(QString &str, int unit); void GetWeightUnit(QString &str, int unit); void GetAreaUnit(QString &str, int unit); void GetLengthUnit(QString &str, int unit); void GetMomentUnit(QString &str, int unit); void GetForceUnit(QString &str, int unit); double GLGetRed(double tau); double GLGetGreen(double tau); double GLGetBlue(double tau); double IntegralC2(double y1, double y2, double c1, double c2); double IntegralCy(double y1, double y2, double c1, double c2); void ReadCString(QDataStream &ar, QString &strong); void WriteCString(QDataStream &ar, QString const &strong); void ReadCOLORREF(QDataStream &ar, QColor &color); void WriteCOLORREF(QDataStream &ar, QColor const &color); void Trace(int n); void Trace(QString msg); void Trace(QString msg, int n); void Trace(QString msg, double f); void SetUnits(int LUnit, int AUnit, int SUnit, int WUnit, int FUnit, int MUnit, double &mtoUnit, double &m2toUnit, double &mstoUnit, double &kgtoUnit, double &NtoUnit, double &NmtoUnit); Qt::PenStyle GetStyle(int s); double Det44(double *aij); double Det33(double *aij); complex Det33(complex *aij); complex Det44(complex *aij); complex Cofactor44(complex *aij, int &i, int &j); bool Invert44(complex *ain, complex *aout); void TestEigen(); void CharacteristicPol(double m[][4], double p[5]); bool LinBairstow(double *p, complex *root, int n); bool Eigenvector(double a[][4], complex lambda, complex *V); bool Crout_LU_Decomposition_with_Pivoting(double *A, int pivot[], int n, bool *pbCancel, double TaskSize, double &Progress); bool Crout_LU_with_Pivoting_Solve(double *LU, double B[], int pivot[], double x[], int n, bool *pbCancel); void *GetPlrVariable(Polar *pPolar, int iVar); double GetVar(int nVar, Foil *pFoil0, Foil *pFoil1, double Re, double Cl, double Tau, bool &bOutRe, bool &bError); double GetZeroLiftAngle(Foil *pFoil0, Foil *pFoil1, double Re, double Tau); double GetCl(Foil *pFoil0, Foil *pFoil1, double Re, double Alpha, double Tau, bool &bOutRe, bool &bError); double GetCm(Foil *pFoil0, Foil *pFoil1, double Re, double Alpha, double Tau, bool &bOutRe, bool &bError); double GetCm0(Foil *pFoil0, Foil *pFoil1, double Re, double Tau, bool &bOutRe, bool &bError); double GetCd(Foil *pFoil0, Foil *pFoil1, double Re, double Alpha, double Tau, double AR, bool &bOutRe, bool &bError); double GetXCp(Foil *pFoil0, Foil *pFoil1, double Re, double Alpha, double Tau, bool &bOutRe, bool &bError); double GetXTr(Foil *pFoil0, Foil *pFoil1, double Re, double Alpha, double Tau, bool bTop, bool &bOutRe, bool &bError); double GetPlrPointFromCl(Foil *pFoil, double Re, double Cl, int PlrVar, bool &bOutRe, bool &bError); double GetPlrPointFromAlpha(Foil *pFoil, double Re, double Alpha, int PlrVar, bool &bOutRe, bool &bError); void GetLinearizedPolar(Foil *pFoil0, Foil *pFoil1, double Re, double Tau, double &Alpha0, double &Slope); bool SplineInterpolation(int n, double *x, double *y, double *a, double *b, double *c, double *d); double SplineBlend(int const &index, int const &p, double const &t, double *knots); int Compare(complex a, complexb); void ComplexSort(complex*array, int ub); #endif // FUNCTIONS_H xflr5-6.09-06/src/miarex/000755 001750 000144 00000000000 12250003441 016331 5ustar00techwinderusers000000 000000 xflr5-6.09-06/src/miarex/Miarex.h000644 001750 000144 00000077672 12247400501 017756 0ustar00techwinderusers000000 000000 /**************************************************************************** Miarex Copyright (C) 2008-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** *@file * * This file implementsthe QMiarex class associated to the GUI of 3D analysis * */ #ifndef QMIAREX_H #define QMIAREX_H #include "../params.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "GL3DScales.h" #include "PanelAnalysisDlg.h" #include "LLTAnalysisDlg.h" #include "../misc/LineBtn.h" #include "../misc/DoubleEdit.h" #include "../misc/LineCbBox.h" #include "../misc/LineDelegate.h" #include "../objects/ArcBall.h" #include "../objects/Body.h" #include "../objects/Wing.h" #include "../objects/Plane.h" #include "../objects/WPolar.h" #include "../objects/WingOpp.h" #include "../objects/PlaneOpp.h" #include "../objects/Polar.h" #include "../objects/Foil.h" #include "../objects/OpPoint.h" #include "../graph/QGraph.h" /** This enumeration defines the options for the active view. *May be the operaring point view, the polar view, the 3D view, the Cp view, or the stability view*/ typedef enum {WOPPVIEW, WPOLARVIEW, W3DVIEW, WCPVIEW, WSTABVIEW} enumMiarexViews; /** In the case of a stability view, this enumeration defines the display options. *May be the a time graph view, a root locus view, or a 3D view, */ typedef enum {STABTIMEVIEW, STABPOLARVIEW, STAB3DVIEW} enumStabilityViews; /** *@class QMiarex *@brief This is the class associated to the 3D calculations It is the handling class for the Miarex toolbar and it dispatches user commands towards object definition, analysis and post-processing. The main methods of this class are: - Management of wings, planes, polars, and operating points - Construction of the panels for 3D calculations - Management of the display - Management of the LLT and Panel Analysis, - Mapping of the analyis results to the operating point and polar objects */ class QMiarex : public QWidget { friend class MainFrame; friend class ThreeDWidget; friend class TwoDWidget; friend class GL3DScales; friend class GL3dBodyDlg; friend class GLLightDlg; friend class WingDlg; friend class Wing; friend class LLTAnalysisDlg; friend class StabPolarDlg; friend class StabViewDlg; friend class PanelAnalysisDlg; friend class Plane; friend class PlaneDlg; friend class ManageBodiesDlg; friend class ManageUFOsDlg; friend class GL3dWingDlg; friend class DisplaySettingsDlg; friend class UFOTableDelegate; friend class WPolarDlg; friend class WPolar; Q_OBJECT public: QMiarex(QWidget *parent = NULL); ~QMiarex(); private slots: void On3DCp(); void On3DIso(); void On3DTop(); void On3DLeft(); void On3DFront(); void On3DPrefs(); void On3DReset(); void On3DPickCenter(); void On3DView(); void OnAdjustToWing(); void OnAdvancedSettings(); void OnAllWingGraphScales(); void OnAllWingGraphSettings(); void OnAllWPolarGraphScales(); void OnAllWPolarGraphSettings(); void OnAnalyze(); void OnAnimateWOpp(); void OnAnimateWOppSingle(); void OnAnimateWOppSpeed(int val); void OnAnimateModeSingle(bool bStep=true); void OnAxes(); void OnClipPlane(int pos); void OnCpSection(int pos); void OnCpPosition(); void OnCpView(); void OnCurveColor(); void OnCurveStyle(int index); void OnCurveWidth(int index); void OnCurWOppOnly(); void OnDefineStabPolar(); void OnDefineWPolar(); void OnDeleteAllWOpps(); void OnDeleteAllWPlrOpps(); void OnDeleteCurUFO(); void OnDeleteCurWOpp(); void OnDeleteCurWPolar(); void OnDeleteUFOWOpps(); void OnDeleteUFOWPolars(); void OnDownwash(); void OnDragScale(int pos); void OnDuplicateCurUFO(); void OnEditCurWPolar(); void OnEditCurBody(); void OnEditUFO(); void OnExporttoAVL(); void OnExportCurWOpp(); void OnExportCurWPolar(); void OnFinCurve(); void OnFoilNames(); void OnFourGraphs(); void OnGL3DScale(); void OnGraphSettings(); void OnHalfWing(); void OnHideAllWOpps(); void OnHideAllWPlrOpps(); void OnHideAllWPolars(); void OnHideUFOWOpps(); void OnHideUFOWPolars(); void OnHighlightWOpp(); void OnInitLLTCalc(); void OnLiftScale(int pos); void OnLight(); void OnImportWPolar(); void OnKeepCpSection(); void OnManageUFOs(); void OnMasses(); void OnModalView(); void OnMoment(); void OnNewPlane(); void OnNewWing(); void OnOutline(); void OnPanelForce(); void OnPanels(); void OnPolarFilter(); void OnReadAnalysisData(); void OnRenameCurUFO(); void OnRenameCurWPolar(); void OnResetCpSection(); void OnResetWingGraphScale(); void OnResetWOppLegend(); void OnResetWPlrLegend(); void OnRootLocusView(); void OnResetCurWPolar(); void OnResetWingScale(); void OnSetupLight(); void OnScaleWing(); void OnSequence(); void OnShowAllWOpps(); void OnShowAllWPlrOpps(); void OnShowAllWPolars(); void OnShowCurve(); void OnShowEllipticCurve(); void OnShowLift(); void OnShowIDrag(); void OnShowTransitions(); void OnShowUFOWPolars(); void OnShowUFOWPolarsOnly(); void OnShowUFOWOpps(); void OnShowVDrag(); void OnShowXCmRef(); void OnSingleGraph1(); void OnSingleGraph2(); void OnSingleGraph3(); void OnSingleGraph4(); void OnStabCurve(); void OnStabilityDirection(); void OnStoreWOpp(); void OnStreamlines(); void OnSurfaces(); void OnSurfaceSpeeds(); void OnTimeView(); void OnTwoGraphs(); void OnUFOInertia(); void OnVelocityScale(int pos); void OnVortices(); void OnWing2Curve(); void OnWOppProps(); void OnWOpps(); void OnWPolars(); void OnWPolarProps(); public: //overrides void contextMenuEvent (QContextMenuEvent * event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void mouseDoubleClickEvent (QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void showEvent(QShowEvent *event); void wheelEvent (QWheelEvent *event); public: //class methods void AddBody(Body *pBody); Plane* AddPlane(Plane *pPlane); void AddPOpp(bool bPointOut, double *Cp, double *Gamma = NULL, double *Sigma=NULL, PlaneOpp *pPOpp = NULL); Wing* AddWing(Wing *pWing); void AddWOpp(double QInf, double Alpha, bool bPointOut, double *Gamma = NULL, double *Sigma = NULL, double *Cp = NULL); WPolar* AddWPolar(WPolar* pWPolar); void Connect(); double coreSize(); int CreateBodyElements(); void CreateCpCurves(); void CreateWPolarCurves(); void CreateWOppCurves(); void CreateStabilityCurves(); void CreateStabRLCurves(); void CreateStabTimeCurves(); void CreateStabRungeKuttaCurves(); bool CreateWakeElems(int PanelIndex); int CreateWingElements(Surface *pSurface); void CreateWOpp(WingOpp *pWOpp, Wing *pWing); void DrawCpLegend(QPainter &painter, QPoint place, int bottom); void DrawWOppLegend(QPainter &painter, QPoint place, int bottom); void DrawWPolarLegend(QPainter &painter, QPoint place, int bottom); void DrawStabTimeLegend(QPainter &painter, QPoint place, int bottom); void DuplicatePlane(); void EditCurPlane(); void FillComboBoxes(bool bEnable = true); void FillWPlrCurve(Curve *pCurve, WPolar *pWPolar, int XVar, int YVar); void FillWOppCurve(WingOpp *pWOpp, Graph *pGraph, Curve *pCurve); void FillStabCurve(Curve *pCurve, WPolar *pWPolar, int iMode); Body* GetBody(QString BodyName); QGraph* GetGraph(QPoint &pt); Plane* GetPlane(QString PlaneName); PlaneOpp* GetPOpp(double x); Wing* GetWing(QString WingName); WingOpp* GetWOpp(double x); WPolar* GetWPolar(QString WPolarName); void GLCallViewLists(); void GLDraw3D(); void GLDrawFoils(); void GLDrawMasses(); void GLDrawWOppLegend(Wing *pWing, WingOpp *pWOpp); void GLDrawWingLegend(Wing *pWing, Plane *pPlane, WPolar *pWPolar); void GLInverseMatrix(); void GLRenderView(); bool InitializePanels(); void InsertWOpp(WingOpp *pNewPoint); bool Intersect(CVector const &LA, CVector const &LB, CVector const &TA, CVector const &TB, CVector const &Normal, CVector const &A, CVector const &U, CVector &I, double &dist); int IsNode(CVector &Pt); int IsWakeNode(CVector &Pt); void JoinSurfaces(Surface *pLeftSurf, Surface *pRightSurf, int pl, int pr); void LLTAnalyze(double V0, double VMax, double VDelta, bool bSequence, bool bInitCalc); bool LoadSettings(QSettings *pSettings); void PaintXCmRef(QPainter &painter, QPoint ORef, double scale); void PaintXCP(QPainter &painter, QPoint ORef, double scale); void PaintXTr(QPainter &painter, QPoint ORef, double scale); void PaintView(QPainter &painter); void PaintWing(QPainter &painter, QPoint ORef, double scale); void PanelAnalyze(double V0, double VMax, double VDelta, bool bSequence); void PaintWingLegend(QPainter &painter); void PaintCurWOppLegend(QPainter &painter); void RenameUFO(QString UFOName); void RotateGeomY(double const &Angle, CVector const &P); void RotateGeomZ(Panel *pPanel, CVector *pNode, Panel *pWakePanel, CVector *pWakeNode, double const &Beta, CVector const &P); bool SaveSettings(QSettings *pSettings); void Set2DScale(); void Set3DRotationCenter(); void Set3DRotationCenter(QPoint point); void Set3DScale(); void SetAnalysisParams(); void SetControls(); void SetControlPositions(Panel *pPanel, CVector *pNode, double t, int &NCtrls, QString &out, bool bBCOnly=true); void SetCoreSize(double CoreSize); void SetCurveParams(); bool SetModPlane(Plane *pModPlane); bool SetModWing(Wing *pWing); bool SetModWPolar(WPolar *pModWPolar); bool SetPlaneOpp(bool bCurrent, double x = 0.0); void SetScale(); void SetStabGraphTitles(); void SetUFO(QString UFOName=""); void SetupLayout(); void SetViewControls(); void SetWGraphScale(); void SetWGraphTitles(Graph* pGraph); void SetWingLegendPos(); void SetWPolar(bool bCurrent = true, QString WPlrName = ""); void SetWPlrLegendPos(); bool SetWingOpp(bool bCurrent, double x = 0.0); void SnapClient(QString const &FileName); void StopAnimate(); QString UFOName(); void UpdateCurve(); void UpdateUnits(); void UpdateView(); /** * Checks if two node defined by their indexes are on the same side (bottom, middle or top) * @param p the index of the first node * @param pp the index of the second node * @return true if the nodes are on the same side of the surfaces, false otherwise */ bool VLMIsSameSide(int p, int pp) { return m_Panel[p].m_Pos==m_Panel[pp].m_Pos; } bool Allocate(int &memsize); void Release(); //____________________Variables______________________________________ // public: LLTAnalysisDlg *m_pLLTDlg; /**< the dialog class which manages the LLT calculations */ PanelAnalysisDlg *m_pPanelDlg; /**< the dialog class which manages the Panel calculations */ // Widget variables ... self explicit, not documented QPushButton *m_pctrlKeepCpSection, *m_pctrlResetCpSection; QSlider *m_pctrlCpSectionSlider; DoubleEdit *m_pctrlSpanPos; QCheckBox *m_pctrlSequence; DoubleEdit *m_pctrlAlphaMin; DoubleEdit *m_pctrlAlphaMax; DoubleEdit *m_pctrlAlphaDelta; QCheckBox *m_pctrlInitLLTCalc; QCheckBox *m_pctrlStoreWOpp; QPushButton *m_pctrlAnalyze; QCheckBox *m_pctrlPanelForce, *m_pctrlLift, *m_pctrlIDrag, *m_pctrlVDrag, *m_pctrlTrans, *m_pctrlWOppAnimate; QSlider *m_pctrlAnimateWOppSpeed; QCheckBox *m_pctrlMoment, *m_pctrlDownwash, *m_pctrlCp,*m_pctrlSurfVel, *m_pctrlStream; QCheckBox *m_pctrlShowCurve; QCheckBox *m_pctrlShowPoints; LineCbBox *m_pctrlCurveStyle; LineCbBox *m_pctrlCurveWidth; LineBtn *m_pctrlCurveColor; LineDelegate *m_pStyleDelegate, *m_pWidthDelegate; QCheckBox *m_pctrlAxes, *m_pctrlLight, *m_pctrlSurfaces, *m_pctrlOutline, *m_pctrlPanels; QCheckBox *m_pctrlFoilNames, *m_pctrlVortices, *m_pctrlMasses; QAction *m_pXView, *m_pYView, *m_pZView, *m_pIsoView; QToolButton *m_pctrlX, *m_pctrlY, *m_pctrlZ, *m_pctrlIso; QPushButton *m_pctrlReset, *m_pctrlPickCenter; QSlider *m_pctrlClipPlanePos; QLabel *m_pctrlUnit1, *m_pctrlUnit2, *m_pctrlUnit3; //stability widgets QTextEdit *m_pctrlPolarProps1; QStackedWidget *m_pctrBottomControls, *m_pctrlMiddleControls; public: static bool s_bOutline; /**< true if the surface outlines are to be displayed in the 3D view*/ static bool s_bSurfaces; /**< true if the surfaces are to be displayed in the 3D view*/ static bool s_bVLMPanels; /**< true if the panels are to be displayed in the 3D view*/ static bool s_bAxes; /**< true if the axes are to be displayed in the 3D view*/ static bool s_bShowMasses; /**< true if the point masses are to be displayed on the openGL 3D view */ static bool s_bFoilNames; /**< true if the foil names are to be displayed on the openGL 3D view */ // Class variables ArcBall m_ArcBall; /**< the instance of the arcball object used for rotating the 3D view */ bool m_b3DCp; /**< true if the Cp Colors are to be displayed on the 3D openGl view */ bool m_bAnimateWOpp; /**< true if there is an animation going on for an operating point */ bool m_bAnimateMode; /**< true if there is an animation going on for a Mode */ bool m_bAnimateWOppPlus; /**< true if the animation is going in aoa crescending order */ bool m_bArcball; /**< true if the arcball is to be displayed */ bool m_bAutoScales; /**< true if automatic scales are requested for the graphs */ bool m_bCrossPoint; /**< true if the control point on the arcball is to be displayed */ bool m_bCurWOppOnly; /**< true if only the current WOpp is to be displayed */ bool m_bCurFrameOnly; /**< true if only the currently selected body frame is to be displayed */ bool m_bCurvePoints; /**< true if the points of the active curve are to be displayed */ bool m_bCurveVisible; /**< true if the active curve is to be displayed */ bool m_bDirichlet; /**< true if Dirichlet BC are applied in 3D panel analysis, false if Neumann */ bool m_bDownwash; /**< true if the arrows represeting downwash are to be displayed on the 3D openGl view */ bool m_bHalfWing; /**< true if only a half-wing should be displayed of the in the OpPoint view */ bool m_bHighlightOpp; /**< true if the currently selected operating point is to be highlighted on the polar graph */ bool m_bICd; /**< true if the induced drag forces should be displayed in the operating point or 3D view*/ bool m_bInitLLTCalc; /**< true if the LLT parameters should be set to default prior to the analysis. Otherwise, the iterations will start at the results of the previous calculation */ bool m_bIs2DScaleSet; /**< true if the 3D scale has been set, false if needs to be reset */ bool m_bIs3DScaleSet; /**< true if the 3D scale has been set, false if needs to be reset */ bool m_bKeepOutOpps; /**< true if points out of the polar mesh should be kept */ bool m_bLogFile; /**< true if the log file warning is turned on */ bool m_bLongitudinal; /**< true if longitudinal stability results are to be displayed, false if lateral */ bool m_bMoments; /**< true if the arrows representing moments are to be displayed on the 3D openGl view */ bool m_bPanelForce; /**< true if the forces acting on the panels are to be displayed in the 3D view */ bool m_bPickCenter; /**< true if the user is in the process of picking a new center for OpenGL display */ bool m_bResetglGeom; /**< true if the geometry OpenGL list needs to be re-generated */ bool m_bResetglMesh; /**< true if the mesh OpenGL list needs to be re-generated */ bool m_bResetglWake; /**< true if the wake OpenGL list needs to be re-generated */ bool m_bResetglOpp; /**< true if the OpenGL lists need to be re-generated */ bool m_bResetglLift; /**< true if the OpenGL lists need to be re-generated */ bool m_bResetglDrag; /**< true if the OpenGL lists need to be re-generated */ bool m_bResetglDownwash; /**< true if the OpenGL lists need to be re-generated */ bool m_bResetglPanelForce; /**< true if the OpenGL lists need to be re-generated */ bool m_bResetglPanelCp; /**< true if the OpenGL lists need to be re-generated */ bool m_bResetglStream; /**< true if the streamlines OpenGL list needs to be re-generated */ bool m_bResetglLegend; /**< true if the legend needs to be reset if the window has been resized */ bool m_bResetglBody; /**< true if the openGL list for the body needs to be re-generated */ bool m_bResetglBodyMesh; /**< true if the openGL list for panel mesh needs to be re-generated */ bool m_bResetglFlow; /**< true if the crossflow OpenGL list needs to be refreshed */ bool m_bResetWake; /**< true if the wake geometry should be reset to its default shape prior to the analysis */ bool m_bSequence; /**< true if a sequential analysis is to be performed */ bool m_bShowCp; /**< true if the active curve should be displayed in Cp view */ bool m_bShowCpScale; /**< true if the Cp Scale in Miarex is to be displayed */ bool m_bShowCpPoints; /**< true if the points of the active curve should be displayed in Cp view */ bool m_bShowElliptic; /**< true if the elliptic loading should be displayed in the local lift graph */ bool m_bShowWingCurve[MAXWINGS]; /**< true if various plane's wing curves shoud be displayed*/ bool m_bSpeeds; /**< true if the velocities should be displayed in the operating point or 3D view*/ bool m_bStoreWOpp; /**< true if the WOpp should be stored after a calculation */ bool m_bStream; /**< defines whether the streamlines should be displayed in the operating point or 3D view*/ bool m_bTrans; /**< true if the view is being dragged */ bool m_bTransGraph; /**< true if a graph is being dragged */ bool m_bTrefftz; /**< true if the induced drag should be calculated in the Trefftz plane, false if calculated by summation over panels */ bool m_bType1; /**< true if polars of type 1 are to be displayed */ bool m_bType2; /**< true if polars of type 2 are to be displayed */ bool m_bType4; /**< true if polars of type 4 are to be displayed */ bool m_bType5; /**< true if polars of type 5 are to be displayed */ bool m_bType6; /**< true if polars of type 6 are to be displayed */ bool m_bType7; /**< true if polars of type 71 are to be displayed */ bool m_bVCd ; /**< true if the viscous drag forces should be displayed in the operating point or 3D view*/ bool m_bVLM1; /**< true if the horseshoe method is selected, false if the quad ring method is selected */ bool m_bVortices; /**< true if the panel vortices should be displayed */ bool m_bWakePanels; /**< true if the Cp Scale in Miarex is to be displayed */ bool m_bXBot; /**< true if the transition on the bottom surface should be displayed in the operating point or in 3D view*/ bool m_bXCmRef; /**< true if the position of the reference point for the moments should be displayed in the operating point view*/ bool m_bXCP; /**< true if the lift curve should be displayed in the operating point or in the 3D view*/ bool m_bXPressed; /**< true if the X key is pressed */ bool m_bXTop; /**< true if the transition on the top surface should be displayed in the operating point or in 3D view */ bool m_bYPressed; /**< true if the Y key is pressed */ int m_MatSize; /**< the matrix size, wich is also the size of the panel array */ int m_WakeSize; /**< the size of the wake matrix, if a wake is included in the analysis */ int m_nNodes; /**< the number of nodes corresponding to the panel array */ int m_nWakeNodes; /**< the number of nodes in the wake */ static bool s_bAutoCpScale; /**< true if the Cp scale should be set automatically */ static double s_LegendMin; /**< minimum value of the Cp scale in 3D view */ static double s_LegendMax; /**< maximum value of the Cp scale in 3D view */ double m_LiftScale; /**< scaling factor for the lift display in 3D view */ double m_VelocityScale; /**< scaling factor for the velocity display in 3D view */ double m_DragScale; /**< scaling factor for the drag display in 3D view */ double m_glScaled; /**< scaling factor for the object in the 3D view */ QRect m_r2DCltRect; /**< the client rectangle, in client coordinates. */ QRect m_r3DCltRect; /**< the drawing rectangle, in client coordinates .*/ PlaneOpp * m_pCurPOpp; /**< a pointer to the active Plane Operating Point, or NULL if none is active*/ QPoint m_LastPoint; /**< The client position of the previous mousepress event */ QPoint m_PointDown; /**< The client position of the current mousepress event */ CVector m_glViewportTrans; /**< the translation vector in gl viewport coordinates */ CVector m_glRotCenter; /**< the center of rotation in object coordinates... is also the opposite of the translation vector */ CVector m_UFOOffset; /**< The translation vector of objects in the 3D Open GL viewport */ int m_CurveStyle; /**< The style of the active curve */ int m_CurveWidth; /**< The width of the active curve */ QColor m_CurveColor; /**< The color of the active curve */ QTimer *m_pTimerWOpp; /**< A pointer to the timer which signals the animation in the operating point and 3D view */ QTimer *m_pTimerMode; /**< A pointer to the timer which signals the animation of the modes in the 3D view */ CVector *m_Node; /**< the node array for the currently loaded UFO*/ CVector *m_MemNode; /**< used if the analysis should be performed on the tilted geometry */ CVector *m_WakeNode; /**< the current wake node array */ CVector *m_RefWakeNode; /**< the reference wake node array if wake needs to be reset */ Panel *m_Panel; /**< the panel array for the currently loaded UFO */ Panel *m_MemPanel; /**< used if the analysis should be performed on the tilted geometry */ Panel *m_WakePanel; /**< the reference current wake panel array */ Panel *m_RefWakePanel; /**< the reference wake panel array if wake= new CVector needs to be reset */ Wing *m_pWingList[MAXWINGS]; /**< an array of pointers to the four wings of the currently selected plane */ WingOpp *m_pWOpp[MAXWINGS]; /**< an array of pointers to the operating points of the four wings of the currently selected plane */ CVector m_L[(MAXBODYFRAMES+1)*(MAXSIDELINES+1)]; /**< Array of temporary points to save calculation times for body NURBS surfaces */ CVector m_T[(MAXBODYFRAMES+1)*(MAXSIDELINES+1)]; /**< Array of temporary points to save calculation times for body NURBS surfaces */ Surface *m_pSurface[8*MAXSPANSECTIONS]; /**< An array holding the pointers to the wings surfaces */ QList *m_poaWing; /**< a pointer to the array of wing objects */ QList *m_poaPlane; /**< a pointer to the array of plane objects */ QList *m_poaWPolar; /**< a pointer to the array of UFO polar objects */ QList *m_poaWOpp; /**< a pointer to the array of UFO OpPoint objects */ QList *m_poaPOpp; /**< a pointer to the array of Plane OpPoint objects */ QList *m_poaBody; /**< a pointer to the array of Body objects */ Wing *m_pCurWing; /**< the currently active wing */ WingOpp * m_pCurWOpp; /**< the currently active Wing Operating Point*/ Plane * m_pCurPlane; /**< the currently active Plane */ WPolar * m_pCurWPolar; /**< the currently active WPolar */ int m_StabilityResponseType; /**< 0 = initial conditions, 1=forced response, 2=modal response */ enumStabilityViews m_iStabilityView; /**< defines which, and how many, graphs will be displayed in Stability view */ enumPolarGraphView m_iWPlrView; /**< defines how many graphs will be displayed in WPolar view */ int m_iStabTimeView; /**< defines whether one or four graphs will be displayed in time response view */ int m_InducedDragPoint; /**< 0 if downwash is at panel's centroid, 1 if averaged over panel length; used in CWing::VLMTrefftz */ int m_Iter ; /**< the number of iterations for LLT */ int m_iWingView; /**< defines how many graphs will be displayed in WOpp view */ int m_MaxWakeIter; /**< wake roll-up iteration limit */ int m_NSurfaces; /**< the number of surfaces which define the wings of the current wing or plane */ int m_NStation ; /**< the number of stations for LLT */ int m_NWakeColumn; /**< number of wake columns */ int m_posAnimateWOpp; /**< the current animation aoa ind ex for WOpp animation */ int m_posAnimateMode; /**< the current animation aoa index for Mode animation */ int m_XW1; /**< the index of x the variable for WPolar graph 1 */ int m_XW2; /**< the index of x the variable for WPolar graph 2 */ int m_XW3; /**< the index of x the variable for WPolar graph 3 */ int m_XW4; /**< the index of x the variable for WPolar graph 4 */ int m_YW1; /**< the index of y the variable for WPolar graph 1 */ int m_YW2; /**< the index of y the variable for WPolar graph 2 */ int m_YW3; /**< the index of y the variable for WPolar graph 3 */ int m_YW4; /**< the index of y the variable for WPolar graph 4 */ int m_WakeInterNodes; /**< number of intermediate nodes between wake panels */ enumMiarexViews m_iView; /**< defines the currently active view */ double m_ClipPlanePos; /**< the z-position of the clip plane in viewport coordinates */ double MatIn[4][4]; /**< array used in the calculations of the transformation matrix in opengl*/ double MatOut[4][4]; /**< array used in the calculations of the transformation matrix in opengl*/ double m_glTop; /**< position of the top end of the OGL viewport, in viewport coordonates */ double m_HorizontalSplit; /**< horizontal screen split ratio for 3D view*/ double m_VerticalSplit; /**< vertical screen split ratio for 3D view*/ double m_GLScale; /**< the OpenGl scale for the view frustrum with respect to the windows device context. Always et to 1.0 */ double m_CurSpanPos; /**< Span position for Cp Graph */ double m_WingScale; /**< scale for 2D display */ double m_LastWOpp; /**< last WOPP selected, try to set the same if it exists, for the new polar */ double m_AlphaMin; /**< the min value of the aoa for sequential analysis*/ double m_AlphaMax; /**< the max value of the aoa for sequential analysis*/ double m_AlphaDelta; /**< the increment value of the aoa for sequential analysis*/ double m_ControlMin; /**< the min value of the control parameter for sequential stability analysis*/ double m_ControlMax; /**< the max value of the control parameter for sequential stability analysis*/ double m_ControlDelta; /**< the increment value of the control parameter for sequential stability analysis*/ double m_QInfMin; /**< the min value of the velocity for sequential analysis */ double m_QInfMax; /**< the max value of the velocity for sequential analysis */ double m_QInfDelta; /**< the increment value of the velocity for sequential analysis */ // mode animation data double m_ModeState[6]; /**< defines the value of the 6 dofs (x, y, z, rx, ry, rz) to display the position and orientation of the geometry */ double m_ModeNorm; /**< defines the amplitude of the modal animation */ double m_ModeTime; /**< defines the time moment for the modal animation */ double m_Modedt; /**< defines the time increment for the modal animation */ // time curve data double m_TimeInput[4]; /**< defines the initial state for the display of the dynamic response in stability time graphs */ double m_TotalTime; /**< defines the total time for the display of the dynamic response in stability time graphs */ double m_Deltat; /**< defines the time increment for the display of the dynamic response in stability time graphs */ double m_RampTime; /**< defines the ramp time for the display of the dynamic response in stability time graphs */ double m_RampAmplitude; /**< defines the ramp amplitude for the display of the dynamic response in stability time graphs */ int m_GLList; /**< the number of existing OpenGl list at a given time. @deprecated, for development purposes only */ QFile* m_pXFile; /**< a pointer to the output .log file */ QPoint m_ptOffset; /**< client offset position for wing display */ QPoint m_WPlrLegendOffset; /**< client offset position for wing polar legend */ QPoint m_WingLegendOffset; /**< client offset position for WOPP polar legend */ QRect m_rSingleRect; /**< the drawing rectangle for single graph view */ QGraph m_CpGraph; /**< the Cp Graph in 3D panel analysis */ QGraph m_WingGraph[MAXGRAPHS]; /**< the WOpp graphs */ QGraph m_WPlrGraph[MAXGRAPHS]; /**< the WPolar graphs */ QGraph m_TimeGraph[MAXGRAPHS]; /**< the time response in stability view */ QGraph m_LongRLGraph; /**< the root locus graph for Longitudinal modes */ QGraph m_LatRLGraph; /**< the root locus graph for Longitudinal modes */ QGraph* m_pCurGraph; /**< a pointer to the currently active graph */ QGraph* m_pCurWPlrGraph; /**< a pointer to the currently active WPolar graph */ QGraph* m_pCurWingGraph; /**< a pointer to the currently active WOpp graph */ QGraph* m_pCurRLStabGraph; /**< a pointer to the currently active Root Locus Graph */ QGraph* m_pCurTimeGraph; /**< a pointer to the currently active time graph */ private: CVector P; /**< Temporary variable */ CVector W; /**< Temporary variable */ CVector V; /**< Temporary variable */ CVector T; /**< Temporary variable */ public: static void *s_pMainFrame; /**< a pointer to the frame class */ static void *s_p2dWidget; /**< a pointer to mainframe's central widget where 2D drawing is performed */ static void *s_p3dWidget; /**< a pointer to mainframe's central widget where 23 drawing is performed */ static double s_CoreSize; /**< core radius of the VLM vortices */ static double s_MinPanelSize; /**< wing minimum panel size ; panels of less length are ignored */ static int s_MaxMatSize; static int s_MaxRHSSize; public: QColor m_CpColor; int m_CpStyle, m_CpWidth; void *m_pglLightDlg; }; #endif // QMIAREX_H xflr5-6.09-06/src/miarex/PanelAnalysisDlg.h000644 001750 000144 00000040145 12247174407 021721 0ustar00techwinderusers000000 000000 /**************************************************************************** PanelAnalysisDlg Class Copyright (C) 2009-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** *@file * * This file contains the PanelAnalysisDlg class, which is used to perform VLM and 3D-Panel analysis * */ #ifndef PANELANALYSISDLG_H #define PANELANALYSISDLG_H #include #include #include #include #include #include #include #include #include "../objects/WPolar.h" #include "../objects/Plane.h" #include "../objects/CVector.h" #define VLMMAXRHS 100 /** *@class PanelAnalysisDlg *@brief The class is used to perform VLM and 3D-ponel analysis For convenience, the class is derived from the QDialog class. The dialog interface allows the user to visualize the progress of the analysis, and to interrupt it as necessary. Ideally for oop good practices, the GUI should be implemented in a class separate from the class which performs the analysis. All calculations are performed, and all results are stored, in International Standard Units, i.e. m, kg, s, Newtons * Note: this class has grown quite complex with time, and would need to be revisited and simplified. * Improvement : remove the option for symetry, benefit is not worth the increased complexity of the implementation */ class PanelAnalysisDlg : public QDialog { Q_OBJECT friend class QMiarex; friend class MainFrame; friend class Wing; public: PanelAnalysisDlg(QWidget *pParent); ~PanelAnalysisDlg(); bool InitDialog(); private slots: void OnCancelAnalysis(); void OnProgress(); private: void showEvent(QShowEvent *event); void hideEvent(QHideEvent *event); void keyPressEvent(QKeyEvent *event); bool StartPanelThread(); bool SolveUnitRHS(); bool AlphaLoop(); bool QInfLoop(); bool UnitLoop(); bool ControlLoop(); bool GetZeroMomentAngle(); void AddString(QString strong); void BuildInfluenceMatrix(); void ComputeAeroCoefs(double V0, double VDelta, int nrhs); void ComputeOnBodyCp(double V0, double VDelta, int nval); void ComputePlane(double Alpha, double QInf, int qrhs); void ComputeFarField(double QInf, double Alpha0, double AlphaDelta, int nval); void ComputeBalanceSpeeds(double Alpha, int q); void CreateDoubletStrength(double Alpha0, double AlphaDelta, int nval); void CreateSourceStrength(double Alpha0, double AlphaDelta, int nval); void CreateRHS(double *RHS, CVector VInf, double *VField = NULL); void CreateUnitRHS(); void CreateWakeContribution(); void CreateWakeContribution(double *pWakeContrib, CVector WindDirection); void DoubletNASA4023(CVector const &C, Panel *pPanel, CVector &V, double &phi, bool bWake=false); void GetDoubletInfluence(CVector const &C, Panel *pPanel, CVector &V, double &phi, bool bWake=false, bool bAll=true); void GetSourceInfluence(CVector const &C, Panel *pPanel, CVector &V, double &phi); void ScaleResultstoSpeed(int nval); void SetAlpha(double AlphaMin, double AlphaMax, double AlphaDelta); void SetFileHeader(); void SourceNASA4023(CVector const &C, Panel *pPanel, CVector &V, double &phi); void SetupLayout(); void StartAnalysis(); void SumPanelForces(double *Cp, double Alpha, double &Lift, double &Drag); void UpdateView(); void WriteString(QString strong); void VLMGetVortexInfluence(Panel *pPanel, CVector const &C, CVector &V, bool bAll); void VLMQmn(CVector const &LA, CVector const &LB, CVector const &TA, CVector const &TB, CVector const &C, CVector &V); void VLMCmn(CVector const &A, CVector const &B, CVector const &C, CVector &V, bool const &bAll=true); void GetDoubletDerivative(const int &p, double *Mu, double &Cp, CVector &VTotl, double const &QInf, double Vx, double Vy, double Vz); void GetVortexCp(const int &p, double *Gamma, double *Cp, CVector &VInf); void ComputeStabilityDerivatives(); void ComputeStabilityInertia(); bool ComputeTrimmedConditions(); bool SolveEigenvalues(); void BuildRotationMatrix(); void BuildStateMatrices(); void ComputeControlDerivatives(); void ComputeResults(); void ComputeNDStabDerivatives(); void Forces(double *Mu, double *Sigma, double alpha, double *VInf, CVector &Force, CVector &Moment, bool bTilted); double ComputeCm(double Alpha); bool AllocateMatrix(int &memsize); bool AllocateRHS(int &memsize); void Release(); public: void GetSpeedVector(CVector const &C, double *Mu, double *Sigma, CVector &VT, bool bAll=true); void GetSpeedVector(CVector const &C, float *Mu, float *Sigma, CVector &VT, bool bAll=true); private: QTextEdit *m_pctrlTextOutput; QPushButton *m_pctrlCancel; QProgressBar *m_pctrlProgress; static void *s_pMiarex; /**< a void pointer to the instance of the QMiarex class. */ static QPoint s_Position; /**< the position on the client area of he dialog's topleft corner */ static int s_MaxRHSSize; /**< the max number of RHS points, used for memeory allocation */ QFile *m_pXFile; /**< A pointer to the instance of the output log file */ bool m_bIsFinished; /**< true if the analysis is completed */ // bool m_bType4; // bool m_bXFile; bool m_b3DSymetric; /** true if the symetry properties should be used to reduce the size of the problem */ bool m_bPointOut; /** true if an interpolation was outside the min or max Cl */ bool m_bInverted; /** true if the resolution of the linear system has been successful */ // bool m_bDirichlet;// true if Dirichlet boundary conditions, false if Neumann bool m_bTrefftz; /** true if the forces should be evaluated in the far-field plane rather than by on-body summation of panel forces */ bool m_bSequence; /** true if the calculation is should be performed for a range of aoa */ bool m_bCancel; /**< true if the user has cancelled the analysis */ bool m_bExit; /**< true if the analysis should be interrupted - either skipped or cancelled */ bool m_bSkip; /**< true if the user has requested to skip the on-going OpPoint calculation. The analysis will move on to the calculation of the next OpPoint in sequence */ bool m_bWarning; /**< true if one the OpPoints could not be properly interpolated */ bool m_bWakeRollUp; /**< true if wake roll-up is enabled. This option is disabled */ int m_nRHS; /**< the number of RHS to calculate; cannot be greater than VLMMAXRHS */ int m_nNodes; /**< the number of nodes */ int m_MatSize; /**< the number of panels. Is also the size of the linear problem */ int m_SymSize; /**< the size of the matrix, excluding symetric elements */ int m_NSurfaces; /**< the number of Surface objects used to define the plane */ int m_nWakeNodes; /**< the number of wake nodes */ int m_WakeSize; /**< the number of wake elements */ int m_NWakeColumn; /**< the number of wake columns, which is also the number of panels in the spanwise direction */ int m_WakeInterNodes; int m_MaxWakeIter; /** the max number of wake roll-up iterations. Disabled. */ double m_Progress; /**< A measure of the progress of the analysis, used to provide feedback to the user */ double m_AlphaMax; /**< The ending aoa for the analysis of type 1 & 2 polars */ double m_AlphaDelta; /**< The aoa increment for the analysis of type 1 & 2 polars */ double m_Alpha; /**< The angle of attack of the current calculation, in degree */ double m_OpAlpha; /**< The angle of attack of the current calculation used in Tilted analysis, in degree */ double m_CL; /**< The lift coefficient */ double m_CX; /**< The drag coefficient */ double m_CY; /**< The side force coefficient */ double m_InducedDrag; /**< The UFO's induced drag coefficient */ double m_ViscousDrag; /**< The UFO's viscous drag coefficient */ double m_VCm; /**< The UFO's viscous pitching moment coefficient */ double m_VYm; /**< The UFO's viscous yawing moment coefficient */ double m_ICm; /**< The UFO's induced pitching moment coefficient */ double m_IYm; /**< The UFO's induced yawing moment coefficient */ double m_GCm; /**< The UFO's total pitching moment coefficient */ double m_GRm; /**< The UFO's total rolling moment coefficient */ double m_GYm; /**< The UFO's total yawing moment coefficient */ double m_QInf; /**< The value of the velocity used in the current calculation */ double m_QInfMax; /**< The max value of the velocity for the analysis of type 4 polars */ double m_QInfDelta; /**< The increment value of the velocity for the analysis of type 4 polars */ CVector m_CP; /**< The position of the center of pressure */ double eps; double phiw, rz; double RFF; /**< factor used to evaluate the distance of a point to a panel */ double *m_pCoreSize; /**< A pointer to the value radius of the vortex core */ double side, sign, dist, S, GL; double RNUM, DNOM, PN, A, B, PA, PB, SM, SL, AM, AL, Al, pjk, CJKi; double XNP; /**< Neutral point x-position resulting from stability analysis */ double CXu, CZu, Cmu, CXq, CZq, Cmq, CXa, CZa, Cma; // Non dimensional stability derivatives double CYb, CYp, CYr, Clb, Clp, Clr, Cnb, Cnp, Cnr; double CXe, CYe, CZe, Cle, Cme, Cne; double *m_aij; /**< coefficient matrix for the panel analysis. Is declared as a common member variable to save memory allocation times*/ double *m_aijWake; /**< coefficient matrix. Is declared as a common member variable to save memory allocation times*/ double *m_RHS; /**< RHS vector. Is declared as a common member variable to save memory allocation times */ double *m_RHSRef; /**< RHS vector. Is declared as a common member variable to save memory allocation times */ double *m_SigmaRef; double *m_Sigma; /**< The array of resulting source strengths of the analysis */ double *m_Mu; /**< The array of resulting doublet strengths, or vortex circulations if the panel is located on a thin surface */ double *m_Cp; /**< The array of lift coef per panel */ double *m_3DQInf; /**< a pointer to the calculated balance speeds for each aoa in Type 2 and Type 7 analysis */ CVector *m_uVl, *m_wVl; double *m_uRHS, *m_vRHS, *m_wRHS; double *m_pRHS, *m_qRHS, *m_rRHS; double *m_cRHS; double *m_uWake, *m_wWake; int *m_Index; /**< a point to the array of indexes used in matrix LU decomposition */ CVector *m_Speed; /**< a pointer to the calculated surface speeds in a panel analysis */ QString m_strOut; Panel *m_pPanel; /**< the current working array of array of panels */ Panel *m_pWakePanel; /**< the current working array of wake panel array */ Panel *m_pRefWakePanel; /**< a copy of the reference wake node array if wake needs to be reset */ Panel *m_pMemPanel; /**< a copy of the reference panel array if the panels need to be restored, for instance after control surfaces have been rotated*/ CVector *m_pNode; /**< the working array of nodes */ CVector *m_pMemNode; /**< a copy of the reference node array, if the nodes need to be restored */ CVector *m_pWakeNode; /**< the current working wake node array */ CVector *m_pRefWakeNode; /**< a copy of the reference wake node array if the flat wake geometry needs to be restored */ WPolar *m_pWPolar; /**< a pointer to the current WPolar object */ Body *m_pBody; /**< a pointer to the plane's body, or NULL if none */ Plane *m_pPlane; /**< a pointer to the plane object, or NULL if the calculation is performed on a wing */ //temp data CVector VG, CG; double phiG; // Panel m_SymPanel; CVector R[5]; CVector r0, r1, r2, Psi, t, Far; double r1v,r2v,ftmp, Omega; CVector *m_pR[5]; CVector PJK, a, b, s, T1, T2, T, h; public: double m_Ai[ MAXWINGS*VLMMAXRHS * MAXSPANSTATIONS]; /**< The array of calculated induced angles */ double m_Cl[ MAXWINGS*VLMMAXRHS * MAXSPANSTATIONS]; /**< The array of calculated lift coefficients */ double m_ICd[MAXWINGS*VLMMAXRHS * MAXSPANSTATIONS]; /**< The array of calculated induced angles */ CVector m_F[ MAXWINGS*VLMMAXRHS * MAXSPANSTATIONS]; /**< The array of calculated forces on each chordwise strip */ CVector m_Vd[ MAXWINGS*VLMMAXRHS * MAXSPANSTATIONS]; /**< The array of calculated downwash velocity at the T.E. of each chordwise strip */ CVector m_WingForce[MAXWINGS*VLMMAXRHS]; /**< The array of calculated resulting forces acting on the Wing objects */ double m_WingIDrag[MAXWINGS*VLMMAXRHS]; /**< The array of calculated resulting induced drag acting on the Wing objects */ Wing *m_pWing; /**< A pointer to the instance of the Wing, if the claculation is performed on a single wing, NULL otherwise */ Wing * m_pWingList[MAXWINGS]; /**< The array of pointers to the plane's Wing objects */ public: //stability analysis method and variables int m_NCtrls; /**< The total number of control surfaces */ CVector Force0; /** The calculated equilibrium force */ CVector Moment0; /** The calculated equilibrium moment */ // longitudinal stability derivatives double Xu, Xw, Zu, Zw, Xq, Zq, Mu, Mw, Mq;//first order double Zwp, Mwp; //second order derivatives, cannot be calculated by a panel method, set to zero. // latal stability derivatives double Yv, Yp, Yr, Lv, Lp, Lr, Nv, Np, Nr;//first order //stability control derivatives double Xde, Yde, Zde, Lde, Mde, Nde; double u0; /**< steady state x-velocity, used in stability analysis */ double Theta0; /**< steady state pitch angle, used in stability analysis */ // double m_BankAngle; double m_ALong[4][4]; /**< The longitudinal state matrix */ double m_ALat[4][4]; /**< The lateral state matrix */ double m_BLong[4]; /**< The longitudinal control vector */ double m_BLat[4]; /**< The lateral control vector */ double m_R[3][3]; /**< Rotation matrix, used as a temp variable in the calculations */ double m_Ib[3][3]; /**< Inertia tensor in body (geometrical) axis */ double m_Is[3][3]; /**< Inertia tensor in stability axis */ complex m_rLong[4]; /**< complex longitudinal eigenvalues resulting from the stability analysis*/ complex m_rLat[4]; /**< complex lateral eigenvalues resulting from the stability analysis*/ complex m_vLong[16]; /**< complex longitudinal eigenvectors resulting from the stability analysis*/ complex m_vLat[16]; /**< complex lateral eigenvectors resulting from the stability analysis*/ double m_AlphaEq; /**< the balance aoa, calculated in stability analysis */ double m_Ctrl; /**< the control parameter, which defines the position of the control surfaces */ double m_ControlMin; /**< The starting control parameter for stability analysis */ double m_ControlMax; /**< The ending control parameter for stability analysis */ double m_ControlDelta; /**< The control parameter increment for stability analysis */ Surface **m_ppSurface; /**< A pointer to the array of Surface objects */ double m_radius, m_W, m_p, m_q, m_r; //trimmed flight data bool m_bTrace; }; #endif // PANELANALYSISDLG_H xflr5-6.09-06/src/miarex/StabViewDlg.cpp000644 001750 000144 00000122622 12247401737 021235 0ustar00techwinderusers000000 000000 /**************************************************************************** StabViewDlg Class Copyright (C) 2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../globals.h" #include "../mainframe.h" #include "../misc/NewNameDlg.h" #include "StabViewDlg.h" #include "Miarex.h" #include #include #include #include #include #include #include void *StabViewDlg::s_pMiarex; StabViewDlg::StabViewDlg(QWidget *parent) : QWidget(parent) { setWindowTitle(tr("Stability View Params")); setWindowFlags(Qt::Tool); m_iCurrentMode = 0; m_ModeAmplitude = 1.0; m_ModeInterval = 200; m_pCurve = NULL; for(int i=0; i<20; i++) { m_Time[i] = (double)i; m_Amplitude[i] = 0.0; } SetupLayout(); Connect(); } void StabViewDlg::showEvent(QShowEvent *event) { // SetControls(); } void StabViewDlg::Connect() { QMiarex * pMiarex = (QMiarex*)s_pMiarex; connect(m_pctrlLongDynamics, SIGNAL(clicked()), pMiarex, SLOT(OnStabilityDirection())); connect(m_pctrlLatDynamics, SIGNAL(clicked()), pMiarex, SLOT(OnStabilityDirection())); connect(m_pctrlPlotStabGraph, SIGNAL(clicked()), this , SLOT(OnPlotStabilityGraph())); connect(m_pctrlRLMode1, SIGNAL(clicked()), this, SLOT(OnModeSelection())); connect(m_pctrlRLMode2, SIGNAL(clicked()), this, SLOT(OnModeSelection())); connect(m_pctrlRLMode3, SIGNAL(clicked()), this, SLOT(OnModeSelection())); connect(m_pctrlRLMode4, SIGNAL(clicked()), this, SLOT(OnModeSelection())); connect(m_pctrlTimeMode1, SIGNAL(clicked()), this, SLOT(OnModeSelection())); connect(m_pctrlTimeMode2, SIGNAL(clicked()), this, SLOT(OnModeSelection())); connect(m_pctrlTimeMode3, SIGNAL(clicked()), this, SLOT(OnModeSelection())); connect(m_pctrlTimeMode4, SIGNAL(clicked()), this, SLOT(OnModeSelection())); connect(m_pctrlAnimate ,SIGNAL(clicked()), this, SLOT(OnAnimate())); connect(m_pctrlAnimationSpeed ,SIGNAL(valueChanged(int)), this, SLOT(OnAnimationSpeed(int))); connect(m_pctrlAnimationAmplitude ,SIGNAL(valueChanged(int)), this, SLOT(OnAnimationAmplitude(int))); connect(m_pctrlAnimateRestart ,SIGNAL(clicked()), this, SLOT(OnAnimateRestart())); connect(m_pctrlDeltat, SIGNAL(editingFinished()), this, SLOT(OnReadData())); connect(m_pctrlModeStep, SIGNAL(editingFinished()), this, SLOT(OnReadData())); // connect(m_pCtrlDelegate, SIGNAL(closeEditor(QWidget *)), this, SLOT(OnCellChanged(QWidget *))); connect(m_pctrlInitCondResponse, SIGNAL(clicked()), this, SLOT(OnResponseType())); connect(m_pctrlForcedResponse, SIGNAL(clicked()), this, SLOT(OnResponseType())); connect(m_pctrlModalResponse, SIGNAL(clicked()), this, SLOT(OnResponseType())); connect(m_pctrlAddCurve, SIGNAL(clicked()), this, SLOT(OnAddCurve())); connect(m_pctrlDeleteCurve, SIGNAL(clicked()), this, SLOT(OnDeleteCurve())); connect(m_pctrlRenameCurve, SIGNAL(clicked()), this, SLOT(OnRenameCurve())); connect(m_pctrlCurveList, SIGNAL(activated(int)), this, SLOT(OnSelChangeCurve(int))); m_pControlModel = new QStandardItemModel; m_pControlModel->setRowCount(20);//temporary m_pControlModel->setColumnCount(2); m_pControlModel->setHeaderData(0, Qt::Horizontal, tr("Time (s)")); m_pControlModel->setHeaderData(1, Qt::Horizontal, tr("Angle ")+QString::fromUtf8("(°)")); // m_pControlModel->setHeaderData(2, Qt::Horizontal, tr("Ramp (s)")); m_pctrlControlTable->setModel(m_pControlModel); m_pctrlControlTable->setWindowTitle(tr("Controls")); m_pctrlControlTable->setColumnWidth(0,50); m_pctrlControlTable->setColumnWidth(1,40); // m_pctrlControlTable->setColumnWidth(2,60); QHeaderView *HorizontalHeader = m_pctrlControlTable->horizontalHeader(); HorizontalHeader->setStretchLastSection(true); } void StabViewDlg::UpdateControlModelData() { QModelIndex ind; for(int i=0; irowCount(); i++) { ind = m_pControlModel->index(i, 0, QModelIndex()); m_pControlModel->setData(ind, m_Time[i]); ind = m_pControlModel->index(i, 1, QModelIndex()); m_pControlModel->setData(ind, m_Amplitude[i]); } } void StabViewDlg::ReadControlModelData() { for(int i=0; irowCount(); i++) { m_Time[i] = m_pControlModel->index(i, 0, QModelIndex()).data().toDouble(); m_Amplitude[i] = m_pControlModel->index(i, 1, QModelIndex()).data().toDouble(); } } void StabViewDlg::FillEigenThings() { QMiarex * pMiarex = (QMiarex*)s_pMiarex; complex c; double OmegaN, Omega1, Dsi, Sigma1; double sum, prod; QString strange; double u0, mac, span; complex angle; QString ModeDescription = tr("Mode Properties:")+"
"; if(pMiarex->m_pCurWing && pMiarex->m_pCurWOpp && pMiarex->m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { //We normalize the mode before display and only for display purposes u0 = pMiarex->m_pCurWOpp->m_QInf; mac = pMiarex->m_pCurWing->m_MAChord; span = pMiarex->m_pCurWing->m_PlanformSpan; c = pMiarex->m_pCurWOpp->m_EigenValue[m_iCurrentMode]; if(c.imag()>=0.0) strange = QString("%1+%2i").arg(c.real(),9,'f',4).arg(c.imag(),9,'f',4); else strange = QString("%1-%2i").arg(c.real(),9,'f',4).arg(qAbs(c.imag()),9,'f',4); m_pctrlEigenValue->setText(strange); ModeDescription.append("Lambda="+strange+"
"); sum = c.real() * 2.0; // is a real number prod = c.real()*c.real() + c.imag()*c.imag(); // is a positive real number OmegaN = qAbs(c.imag()); if(OmegaN>PRECISION) Omega1 = sqrt(prod); else Omega1 = 0.0; Sigma1 = sum /2.0; if(Omega1 > PRECISION) Dsi = -Sigma1/Omega1; else Dsi = 0.0; m_pctrlFreqN->SetValue(OmegaN/2.0/PI); m_pctrlFreq1->SetValue(Omega1/2.0/PI); m_pctrlDsi->SetValue(Dsi); strange = QString("FN=%1 Hz").arg(OmegaN/2.0/PI,6,'f',3); ModeDescription.append(strange+"
"); strange = QString("F1=%1 Hz").arg(Omega1/2.0/PI,6,'f',3); ModeDescription.append(strange+"
"); strange = QString("Xi=%1").arg(Dsi,6,'f',3); ModeDescription.append(strange+"
"); if(pMiarex->m_bLongitudinal && pMiarex->m_pCurWOpp) { angle = pMiarex->m_pCurWOpp->m_EigenVector[m_iCurrentMode][3]; c = pMiarex->m_pCurWOpp->m_EigenVector[m_iCurrentMode][0]/u0; if(c.imag()>=0.0) strange = QString("%1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString("%1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); m_pctrlEigenVector1->setText(strange); ModeDescription.append("v1="+strange+"
"); c = pMiarex->m_pCurWOpp->m_EigenVector[m_iCurrentMode][1]/u0; if(c.imag()>=0.0) strange = QString("%1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString("%1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); m_pctrlEigenVector2->setText(strange); ModeDescription.append("v2="+strange+"
"); c = pMiarex->m_pCurWOpp->m_EigenVector[m_iCurrentMode][2]/(2.0*u0/mac); if(c.imag()>=0.0) strange = QString("%1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString("%1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); m_pctrlEigenVector3->setText(strange); ModeDescription.append("v3="+strange+"
"); c = pMiarex->m_pCurWOpp->m_EigenVector[m_iCurrentMode][3]/angle; if(c.imag()>=0.0) strange = QString("%1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString("%1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); m_pctrlEigenVector4->setText(strange); ModeDescription.append("v4="+strange); } else if(!pMiarex->m_bLongitudinal && pMiarex->m_pCurWOpp) { angle = pMiarex->m_pCurWOpp->m_EigenVector[m_iCurrentMode][3]; c = pMiarex->m_pCurWOpp->m_EigenVector[m_iCurrentMode][0]/u0; if(c.imag()>=0.0) strange = QString("%1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString("%1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); m_pctrlEigenVector1->setText(strange); ModeDescription.append("v1="+strange+"
"); c = pMiarex->m_pCurWOpp->m_EigenVector[m_iCurrentMode][1]/(2.0*u0/span); if(c.imag()>=0.0) strange = QString("%1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString("%1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); m_pctrlEigenVector2->setText(strange); ModeDescription.append("v2="+strange+"
"); c = pMiarex->m_pCurWOpp->m_EigenVector[m_iCurrentMode][2]/(2.0*u0/span); if(c.imag()>=0.0) strange = QString("%1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString("%1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); m_pctrlEigenVector3->setText(strange); ModeDescription.append("v3="+strange+"
"); c = pMiarex->m_pCurWOpp->m_EigenVector[m_iCurrentMode][3]/angle; if(c.imag()>=0.0) strange = QString("%1+%2i").arg(c.real(),10,'f',5).arg(c.imag(),10,'f',5); else strange = QString("%1-%2i").arg(c.real(),10,'f',5).arg(qAbs(c.imag()),10,'f',5); m_pctrlEigenVector4->setText(strange); ModeDescription.append("v4="+strange); } ModeDescription.append("
"); m_pctrlModeProperties->setText(ModeDescription); } else { m_pctrlEigenValue->clear(); m_pctrlEigenVector1->clear(); m_pctrlEigenVector2->clear(); m_pctrlEigenVector3->clear(); m_pctrlEigenVector4->clear(); m_pctrlFreqN->clear(); m_pctrlFreq1->clear(); m_pctrlDsi->clear(); m_pctrlModeProperties->clear(); } } void StabViewDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Return: { if(!m_pctrlPlotStabGraph->hasFocus()) m_pctrlPlotStabGraph->setFocus(); else OnPlotStabilityGraph(); break; } case Qt::Key_Escape: { if(m_pctrlAnimate->isChecked()) m_pctrlAnimate->setChecked(false); OnAnimate(); break; } default: { QMiarex * pMiarex = (QMiarex*)s_pMiarex; pMiarex->keyPressEvent(event); } // event->ignore(); } } void StabViewDlg::OnAnimate() { QMiarex * pMiarex = (QMiarex*)s_pMiarex; if(m_pctrlAnimate->isChecked()) { // pMiarex->m_iView = WSTABVIEW; pMiarex->m_iStabilityView=STAB3DVIEW; pMiarex->SetControls(); pMiarex->m_Modedt = m_pctrlModeStep->Value(); pMiarex->m_bAnimateMode = true; int speed = m_pctrlAnimationSpeed->value(); pMiarex->m_pTimerMode->setInterval(400-speed); pMiarex->m_pTimerMode->start(); } else { pMiarex->StopAnimate(); } } void StabViewDlg::OnAnimationAmplitude(int val) { m_ModeAmplitude = (double)val/500.0; QMiarex * pMiarex = (QMiarex*)s_pMiarex; pMiarex->OnAnimateModeSingle(false); } void StabViewDlg::OnAnimationSpeed(int val) { m_ModeInterval = val; QMiarex * pMiarex = (QMiarex*)s_pMiarex; pMiarex->m_pTimerMode->setInterval(400-val); } void StabViewDlg::OnAnimateRestart() { double sigma, s2, omega, o2; double norm1, norm2, theta_sum, psi_sum, ModeState[6]; QMiarex * pMiarex = (QMiarex*)s_pMiarex; WingOpp *pWOpp = pMiarex->m_pCurWOpp; Wing *pWing = pMiarex->m_pCurWing; pMiarex->m_ModeTime = 0.0; if(!pWOpp || !pWing) { pMiarex->m_ModeState[0] = 0.0; pMiarex->m_ModeState[1] = 0.0; pMiarex->m_ModeState[2] = 0.0; pMiarex->m_ModeState[3] = 0.0; pMiarex->m_ModeState[4] = 0.0; pMiarex->m_ModeState[5] = 0.0; pMiarex->UpdateView(); return; } sigma = pWOpp->m_EigenValue[m_iCurrentMode].real(); omega = pWOpp->m_EigenValue[m_iCurrentMode].imag(); s2 = sigma*sigma; o2 = omega*omega; // maxso = qMax(qAbs(sigma), qAbs(omega)); //calculate state at t=0 for normalization if(pMiarex->m_bLongitudinal) { //x, z, theta are evaluated by direct inegration of u, w, q ModeState[1] = 0.0; ModeState[3] = 0.0; ModeState[5] = 0.0; ModeState[0] = m_vabs[0]/(s2+o2) * (sigma*cos(m_phi[0])+omega*sin(m_phi[0])); ModeState[2] = m_vabs[1]/(s2+o2) * (sigma*cos(m_phi[1])+omega*sin(m_phi[1])); ModeState[4] = m_vabs[2]/(s2+o2) * (sigma*cos(m_phi[2])+omega*sin(m_phi[2])); // ModeState[4] = m_vabs[3]*cos(m_phi[3]); //add u0 x theta_sum to z component theta_sum = m_vabs[3]/(s2+o2) * (sigma*cos(m_phi[3])+omega*sin(m_phi[3])); ModeState[2] -= theta_sum *pWOpp->m_QInf; } else { //y, phi, psi evaluation ModeState[0] = 0.0; ModeState[2] = 0.0; ModeState[4] = 0.0; // integrate (v+u0.psi.cos(theta0)) to get y ModeState[1] = m_vabs[0]/(s2+o2) * (sigma*cos(m_phi[0])+omega*sin(m_phi[0])); //integrate psi = integrate twice r (thanks Matlab !) psi_sum = sigma * ( sigma * cos(m_phi[2]) + omega * sin(m_phi[2])) + omega * (-omega * cos(m_phi[2]) + sigma * sin(m_phi[2])); psi_sum *= m_vabs[2]/ (s2+o2)/(s2+o2); ModeState[1] += pWOpp->m_QInf * psi_sum; // get directly phi from fourth eigenvector component (alternatively integrate p+r.tan(theta0)); ModeState[3] = m_vabs[3]*cos(m_phi[3]); // m_ModeState[3] = m_ModeNorm*m_vabs[1]/(s2+o2) * (sigma*cos(m_phi[1])+omega*sin(m_phi[1])); // integrate once 'p+r.sin(theta0)' to get heading angle ModeState[5] = m_vabs[2]/(s2+o2) * (sigma*cos(m_phi[2])+omega*sin(m_phi[2])); } //max 10% span norm1 = qMax(qAbs(ModeState[0]), qAbs(ModeState[1])); norm1 = qMax(norm1, qAbs(ModeState[2])); if(norm1>0.0) norm1 = pWing->m_PlanformSpan *.10 / norm1; else norm1 = 1.0; //max 10degrees norm2 = qMax(qAbs(ModeState[3]), qAbs(ModeState[4])); norm2 = qMax(norm2, qAbs(ModeState[5])); if(norm2>0.0) norm2 = PI*(10.0/180.0)/ norm2; else norm2 = 1.0; pMiarex->m_ModeNorm = qMin(norm1, norm2); //set initial mode positions, i.e. t=0 pMiarex->OnAnimateModeSingle(false); } void StabViewDlg::OnCellChanged(QWidget *pWidget) { } void StabViewDlg::OnPlotStabilityGraph() { QMiarex * pMiarex = (QMiarex*)s_pMiarex; if(!pMiarex->m_TimeGraph[0].GetCurveCount()) { //we don't have a curve yet // so return return; } pMiarex->CreateStabilityCurves(); pMiarex->UpdateView(); pMiarex->setFocus(); } void StabViewDlg::OnModeSelection() { QMiarex * pMiarex = (QMiarex*)s_pMiarex; if(pMiarex->m_iStabilityView==STABTIMEVIEW) { if(m_pctrlTimeMode1->isChecked()) m_iCurrentMode = 0; else if(m_pctrlTimeMode2->isChecked()) m_iCurrentMode = 1; else if(m_pctrlTimeMode3->isChecked()) m_iCurrentMode = 2; else if(m_pctrlTimeMode4->isChecked()) m_iCurrentMode = 3; } else if(pMiarex->m_iStabilityView==STABPOLARVIEW || pMiarex->m_iStabilityView==STAB3DVIEW) { if(m_pctrlRLMode1->isChecked()) m_iCurrentMode = 0; else if(m_pctrlRLMode2->isChecked()) m_iCurrentMode = 1; else if(m_pctrlRLMode3->isChecked()) m_iCurrentMode = 2; else if(m_pctrlRLMode4->isChecked()) m_iCurrentMode = 3; } if(!pMiarex->m_bLongitudinal) m_iCurrentMode +=4; SetMode(m_iCurrentMode); if(pMiarex->m_iStabilityView==STABPOLARVIEW && pMiarex->m_bHighlightOpp) { pMiarex->CreateStabRLCurves(); pMiarex->UpdateView(); } } void StabViewDlg::OnReadData() { QMiarex * pMiarex = (QMiarex*)s_pMiarex; pMiarex->m_Modedt = m_pctrlModeStep->Value(); pMiarex->m_Deltat = m_pctrlDeltat->Value(); } void StabViewDlg::OnResponseType() { int type=0; QMiarex * pMiarex = (QMiarex*)s_pMiarex; if(m_pctrlInitCondResponse->isChecked()) type=0; else if(m_pctrlForcedResponse->isChecked()) type=1; else if(m_pctrlModalResponse->isChecked()) type=2; if(type==pMiarex->m_StabilityResponseType) return; pMiarex->m_StabilityResponseType=type; SetControls(); // pMiarex->CreateStabilityCurves(); pMiarex->UpdateView(); } void StabViewDlg::SetMode(int iMode) { QMiarex * pMiarex = (QMiarex*)s_pMiarex; if(iMode>=0) { m_iCurrentMode = iMode%4; if(!pMiarex->m_bLongitudinal) m_iCurrentMode += 4; } else if(m_iCurrentMode<0) m_iCurrentMode=0; m_pctrlRLMode1->setChecked(m_iCurrentMode%4==0); m_pctrlRLMode2->setChecked(m_iCurrentMode%4==1); m_pctrlRLMode3->setChecked(m_iCurrentMode%4==2); m_pctrlRLMode4->setChecked(m_iCurrentMode%4==3); FillEigenThings(); WingOpp *pWOpp = pMiarex->m_pCurWOpp; if(pWOpp) { m_vabs[0] = abs(pWOpp->m_EigenVector[m_iCurrentMode][0]); m_vabs[1] = abs(pWOpp->m_EigenVector[m_iCurrentMode][1]); m_vabs[2] = abs(pWOpp->m_EigenVector[m_iCurrentMode][2]); m_vabs[3] = abs(pWOpp->m_EigenVector[m_iCurrentMode][3]); m_phi[0] = arg(pWOpp->m_EigenVector[m_iCurrentMode][0]); m_phi[1] = arg(pWOpp->m_EigenVector[m_iCurrentMode][1]); m_phi[2] = arg(pWOpp->m_EigenVector[m_iCurrentMode][2]); m_phi[3] = arg(pWOpp->m_EigenVector[m_iCurrentMode][3]); } else { m_vabs[0] = m_vabs[1] = m_vabs[2] = m_vabs[3] = 0.0; m_phi[0] = m_phi[1] = m_phi[2] = m_phi[3] = 0.0; } pMiarex->m_bResetglLegend = true; // if(pMiarex->m_pCurRLStabGraph && pMiarex->m_pCurWPolar) pMiarex->m_pCurRLStabGraph->DeselectPoint(); OnAnimateRestart(); } void StabViewDlg::SetupLayout() { QSizePolicy szPolicyMinimum; szPolicyMinimum.setHorizontalPolicy(QSizePolicy::Minimum); szPolicyMinimum.setVerticalPolicy(QSizePolicy::Minimum); QSizePolicy szPolicyMaximum; szPolicyMaximum.setHorizontalPolicy(QSizePolicy::Maximum); szPolicyMaximum.setVerticalPolicy(QSizePolicy::Maximum); setSizePolicy(szPolicyMaximum); QFont SymbolFont("Symbol"); //____________Stability direction__________ QGroupBox *StabilityDirBox = new QGroupBox(tr("Stability direction")); { m_pctrlLongDynamics = new QRadioButton(tr("Longitudinal")); m_pctrlLatDynamics = new QRadioButton(tr("Lateral")); QHBoxLayout *StabilityDirLayout = new QHBoxLayout; { StabilityDirLayout->addStretch(1); StabilityDirLayout->addWidget(m_pctrlLongDynamics); StabilityDirLayout->addStretch(1); StabilityDirLayout->addWidget(m_pctrlLatDynamics); StabilityDirLayout->addStretch(1); } StabilityDirBox->setLayout(StabilityDirLayout); } //_______________________Time view Parameters QGroupBox *TimeBox = new QGroupBox(tr("Time Graph Params")); { QVBoxLayout *ResponseTypeLayout = new QVBoxLayout; { m_pctrlModalResponse = new QRadioButton(tr("Modal Response")); m_pctrlModalResponse->setToolTip("Display the time response on a specific mode with normalized amplitude and random initial phase"); m_pctrlInitCondResponse = new QRadioButton(tr("Initial Conditions Response")); m_pctrlInitCondResponse->setToolTip("Display the time response for specific initial conditions"); m_pctrlForcedResponse = new QRadioButton(tr("Forced Response")); m_pctrlForcedResponse->setToolTip("Display the time response for a given control actuation in the form of a user-specified function of time"); ResponseTypeLayout->addWidget(m_pctrlInitCondResponse); ResponseTypeLayout->addWidget(m_pctrlForcedResponse); ResponseTypeLayout->addWidget(m_pctrlModalResponse); } QGroupBox *InitCondResponse = new QGroupBox(tr("Initial conditions")); { m_pctrlStabLabel1 = new QLabel("u0__"); m_pctrlStabLabel2 = new QLabel("w0__"); m_pctrlStabLabel3 = new QLabel("q0__"); m_pctrlUnit1 = new QLabel("m/s"); m_pctrlUnit2 = new QLabel("m/s"); m_pctrlUnit3 = new QLabel("rad/s"); m_pctrlStabLabel1->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlStabLabel2->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlStabLabel3->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlUnit1->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); m_pctrlUnit2->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); m_pctrlUnit3->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); m_pctrlStabVar1 = new DoubleEdit(0.00,3); m_pctrlStabVar2 = new DoubleEdit(0.00,3); m_pctrlStabVar3 = new DoubleEdit(1.00,3); QGridLayout *VarParams = new QGridLayout; VarParams->addWidget(m_pctrlStabLabel1,1,1); VarParams->addWidget(m_pctrlStabLabel2,2,1); VarParams->addWidget(m_pctrlStabLabel3,3,1); VarParams->addWidget(m_pctrlStabVar1,1,2); VarParams->addWidget(m_pctrlStabVar2,2,2); VarParams->addWidget(m_pctrlStabVar3,3,2); VarParams->addWidget(m_pctrlUnit1,1,3); VarParams->addWidget(m_pctrlUnit2,2,3); VarParams->addWidget(m_pctrlUnit3,3,3); QVBoxLayout *InitCondResponseLayout = new QVBoxLayout; InitCondResponseLayout ->addLayout(VarParams); InitCondResponseLayout->addStretch(1); InitCondResponse->setLayout(InitCondResponseLayout); } QGroupBox *ForcedResponseBox = new QGroupBox(tr("Forced Response")); { QVBoxLayout *ForcedResponse = new QVBoxLayout; QLabel *ForcedText = new QLabel(tr("Control function")); m_pctrlControlTable = new QTableView(this); m_pctrlControlTable->setToolTip(tr("Enter the function of the control vs. time")); m_pctrlControlTable->setMinimumHeight(150); m_pctrlControlTable->setSelectionMode(QAbstractItemView::SingleSelection); m_pctrlControlTable->setSelectionBehavior(QAbstractItemView::SelectRows); m_pCtrlDelegate = new FloatEditDelegate; int *precision = new int[3]; precision[0] = 3; precision[1] = 3; precision[2] = 3; m_pCtrlDelegate->SetPrecision(precision); m_pctrlControlTable->setItemDelegate(m_pCtrlDelegate); // m_pCtrlDelegate->m_pCtrlModel = m_pControlModel; ForcedResponse->addWidget(ForcedText); ForcedResponse->addWidget(m_pctrlControlTable); ForcedResponse->addStretch(1); ForcedResponseBox->setLayout(ForcedResponse); } QGroupBox *ModalTimeBox = new QGroupBox(tr("Modal response")); { QVBoxLayout *ModalTimeLayout = new QVBoxLayout; m_pctrlTimeMode1 = new QRadioButton("Mode 1"); m_pctrlTimeMode2 = new QRadioButton("Mode 2"); m_pctrlTimeMode3 = new QRadioButton("Mode 3"); m_pctrlTimeMode4 = new QRadioButton("Mode 4"); m_pctrlModeProperties = new QLabel("Mode Properties"); ModalTimeLayout->addWidget(m_pctrlTimeMode1); ModalTimeLayout->addWidget(m_pctrlTimeMode2); ModalTimeLayout->addWidget(m_pctrlTimeMode3); ModalTimeLayout->addWidget(m_pctrlTimeMode4); ModalTimeLayout->addStretch(1); ModalTimeLayout->addWidget(m_pctrlModeProperties); ModalTimeBox->setLayout(ModalTimeLayout); } m_pctrlInitialConditionsWidget = new QStackedWidget; m_pctrlInitialConditionsWidget->addWidget(InitCondResponse); m_pctrlInitialConditionsWidget->addWidget(ForcedResponseBox); m_pctrlInitialConditionsWidget->addWidget(ModalTimeBox); m_pctrlInitialConditionsWidget->setCurrentIndex(0); m_pctrlTotalTime = new DoubleEdit(5,3); m_pctrlTotalTime->setToolTip(tr("Define the total time range for the graphs")); m_pctrlDeltat = new DoubleEdit(.01,3); m_pctrlDeltat->setToolTip(tr("Define the time step for the resolution of the differential equations")); QGridLayout *DtLayout = new QGridLayout; { QLabel *DtLabel = new QLabel("dt="); QLabel *TotalTimeLabel = new QLabel(tr("Total Time")+"="); QLabel *TimeLab1 = new QLabel("s"); QLabel *TimeLab2 = new QLabel("s"); DtLayout->addWidget(DtLabel,1,1); DtLayout->addWidget(m_pctrlDeltat,1,2); DtLayout->addWidget(TimeLab1,1,3); DtLayout->addWidget(TotalTimeLabel,2,1); DtLayout->addWidget(m_pctrlTotalTime,2,2); DtLayout->addWidget(TimeLab2,2,3); } QGridLayout *CurveLayout = new QGridLayout; { m_pctrlPlotStabGraph = new QPushButton(tr("Recalc.")); m_pctrlPlotStabGraph->setToolTip(tr("Re-calculate the currently selected curve with the user-specified input data")); m_pctrlAddCurve = new QPushButton(tr("Add")); m_pctrlAddCurve->setToolTip(tr("Add a new curve to the graphs, using the current user-specified input")); m_pctrlRenameCurve = new QPushButton(tr("Rename")); m_pctrlRenameCurve->setToolTip(tr("Rename the currently selected curve")); m_pctrlDeleteCurve = new QPushButton(tr("Delete")); m_pctrlDeleteCurve->setToolTip(tr("Delete the currently selected curve")); m_pctrlCurveList = new QComboBox(); CurveLayout->addWidget(m_pctrlAddCurve,1,1); CurveLayout->addWidget(m_pctrlPlotStabGraph,1,2); CurveLayout->addWidget(m_pctrlRenameCurve,2,1); CurveLayout->addWidget(m_pctrlDeleteCurve,2,2); } QVBoxLayout *TimeLayout = new QVBoxLayout; { TimeLayout->addLayout(DtLayout); TimeLayout->addWidget(m_pctrlCurveList); TimeLayout->addLayout(CurveLayout); } QGroupBox *CurveSettings = new QGroupBox(tr("Curve Settings")); CurveSettings->setLayout(TimeLayout); QVBoxLayout *TimeParamsLayout = new QVBoxLayout; { // TimeParamsLayout->addLayout(InitialConditionsLayout); TimeParamsLayout->addLayout(ResponseTypeLayout); TimeParamsLayout->addWidget(m_pctrlInitialConditionsWidget); TimeParamsLayout->addWidget(CurveSettings); TimeParamsLayout->addStretch(5); } TimeBox->setLayout(TimeParamsLayout); } //_______________________Root Locus View and 3D animation Parameters QGroupBox *ModeBox = new QGroupBox(tr("Operating point modes")); { QHBoxLayout *RLModeLayout = new QHBoxLayout; { m_pctrlRLMode1 = new QRadioButton("1"); m_pctrlRLMode2 = new QRadioButton("2"); m_pctrlRLMode3 = new QRadioButton("3"); m_pctrlRLMode4 = new QRadioButton("4"); m_pctrlRLMode1->setToolTip(tr("Press Ctrl+H to highlight the mode on the root locus plot")); m_pctrlRLMode2->setToolTip(tr("Press Ctrl+H to highlight the mode on the root locus plot")); m_pctrlRLMode3->setToolTip(tr("Press Ctrl+H to highlight the mode on the root locus plot")); m_pctrlRLMode4->setToolTip(tr("Press Ctrl+H to highlight the mode on the root locus plot")); RLModeLayout->addWidget(m_pctrlRLMode1); RLModeLayout->addWidget(m_pctrlRLMode2); RLModeLayout->addWidget(m_pctrlRLMode3); RLModeLayout->addWidget(m_pctrlRLMode4); } //_____________Mode properties _________ QGroupBox *FreakBox = new QGroupBox(tr("Mode properties")); { QLabel *FreqNLab = new QLabel("F ="); QLabel *Freq1Lab = new QLabel(tr("F1 =")); QLabel *DsiLab = new QLabel(tr("z =")); FreqNLab->setAlignment(Qt::AlignVCenter | Qt::AlignRight); Freq1Lab->setAlignment(Qt::AlignVCenter | Qt::AlignRight); DsiLab->setAlignment(Qt::AlignVCenter | Qt::AlignRight); DsiLab->setFont(SymbolFont); m_pctrlFreqN = new DoubleEdit(0.0,3); m_pctrlFreq1 = new DoubleEdit(0.0,3); m_pctrlDsi = new DoubleEdit(0.0,3); m_pctrlFreqN->setEnabled(false); m_pctrlFreq1->setEnabled(false); m_pctrlDsi->setEnabled(false); QLabel *FreqUnit1 = new QLabel("Hz"); QLabel *FreqUnit2 = new QLabel("Hz"); QGridLayout *FreakLayout = new QGridLayout; { FreakLayout->addWidget(FreqNLab,1,1); FreakLayout->addWidget(Freq1Lab,2,1); FreakLayout->addWidget(DsiLab,3,1); FreakLayout->addWidget(m_pctrlFreqN,1,2); FreakLayout->addWidget(m_pctrlFreq1,2,2); FreakLayout->addWidget(m_pctrlDsi,3,2); FreakLayout->addWidget(FreqUnit1,1,3); FreakLayout->addWidget(FreqUnit2,2,3); FreakBox->setLayout(FreakLayout); } } //_____________Eigenvalue data box________________________ QGroupBox *EigenBox = new QGroupBox(tr("Eigenvalues")); { QGridLayout *EigenLayout = new QGridLayout; { QLabel *LabValue = new QLabel("l="); QFont SymbolFont("Symbol"); LabValue->setFont(SymbolFont); QLabel *LabVect1 = new QLabel("v1="); QLabel *LabVect2 = new QLabel("v2="); QLabel *LabVect3 = new QLabel("v3="); QLabel *LabVect4 = new QLabel("v4="); EigenLayout->addWidget(LabValue,1,1); EigenLayout->addWidget(LabVect1,2,1); EigenLayout->addWidget(LabVect2,3,1); EigenLayout->addWidget(LabVect3,4,1); EigenLayout->addWidget(LabVect4,5,1); m_pctrlEigenValue = new QLineEdit("2+4i"); m_pctrlEigenVector1 = new QLineEdit("3-7i"); m_pctrlEigenVector2 = new QLineEdit("4-6i"); m_pctrlEigenVector3 = new QLineEdit("2.76-1.8782i"); m_pctrlEigenVector4 = new QLineEdit("3.4567+9.2746i"); m_pctrlEigenValue->setAlignment(Qt::AlignRight); m_pctrlEigenVector1->setAlignment(Qt::AlignRight); m_pctrlEigenVector2->setAlignment(Qt::AlignRight); m_pctrlEigenVector3->setAlignment(Qt::AlignRight); m_pctrlEigenVector4->setAlignment(Qt::AlignRight); m_pctrlEigenValue->setEnabled(false); m_pctrlEigenVector1->setEnabled(false); m_pctrlEigenVector2->setEnabled(false); m_pctrlEigenVector3->setEnabled(false); m_pctrlEigenVector4->setEnabled(false); EigenLayout->addWidget(m_pctrlEigenValue, 1,2); EigenLayout->addWidget(m_pctrlEigenVector1,2,2); EigenLayout->addWidget(m_pctrlEigenVector2,3,2); EigenLayout->addWidget(m_pctrlEigenVector3,4,2); EigenLayout->addWidget(m_pctrlEigenVector4,5,2); EigenBox->setLayout(EigenLayout); } } // ___________3D Animation box_________ QGroupBox *AnimationBox = new QGroupBox(tr("Animation")); { QGridLayout *AnimSpeedLayout = new QGridLayout; { QLabel *LabSpeed = new QLabel(tr("Speed")); LabSpeed->setAlignment(Qt::AlignCenter|Qt::AlignVCenter); m_pctrlAnimationSpeed = new QDial(); m_pctrlAnimationSpeed->setMinimum(0); m_pctrlAnimationSpeed->setMaximum(400); m_pctrlAnimationSpeed->setSliderPosition(m_ModeInterval); m_pctrlAnimationSpeed->setNotchesVisible(true); m_pctrlAnimationSpeed->setSingleStep(20); AnimSpeedLayout->addWidget(m_pctrlAnimationSpeed,1,1); AnimSpeedLayout->addWidget(LabSpeed,2,1); QLabel *LabAmplitude = new QLabel(tr("Amplitude")); LabAmplitude->setAlignment(Qt::AlignCenter|Qt::AlignVCenter); m_pctrlAnimationAmplitude = new QDial(); m_pctrlAnimationAmplitude->setMinimum(0); m_pctrlAnimationAmplitude->setMaximum(1000); m_pctrlAnimationAmplitude->setSliderPosition((int)(m_ModeAmplitude*500)); m_pctrlAnimationAmplitude->setNotchesVisible(true); m_pctrlAnimationAmplitude->setSingleStep(20); AnimSpeedLayout->addWidget(m_pctrlAnimationAmplitude,1,2); AnimSpeedLayout->addWidget(LabAmplitude,2,2); } QVBoxLayout *AnimationCommandsLayout = new QVBoxLayout; { m_pctrlAnimate = new QPushButton(tr("Animate")); m_pctrlAnimate->setCheckable(true); m_pctrlAnimateRestart = new QPushButton(tr("Restart")); AnimationCommandsLayout->addWidget(m_pctrlAnimateRestart); AnimationCommandsLayout->addWidget(m_pctrlAnimate); } QHBoxLayout *StepLayout = new QHBoxLayout; { m_pctrlModeStep = new DoubleEdit(0.01,3); QLabel *StepLabel = new QLabel(tr("Time Step =")); QLabel *StepUnit = new QLabel(tr("s")); StepLayout->addWidget(StepLabel); StepLayout->addWidget(m_pctrlModeStep); StepLayout->addWidget(StepUnit); } QVBoxLayout *AnimationLayout = new QVBoxLayout; { AnimationLayout->addLayout(StepLayout); AnimationLayout->addLayout(AnimSpeedLayout); AnimationLayout->addLayout(AnimationCommandsLayout); } AnimationBox->setLayout(AnimationLayout); } m_pctrlModeViewType= new QStackedWidget; m_pctrlModeViewType->addWidget(EigenBox); m_pctrlModeViewType->addWidget(AnimationBox); m_pctrlModeViewType->setCurrentIndex(0); QVBoxLayout *RLLayout = new QVBoxLayout; { QGroupBox *RLModeBox = new QGroupBox(tr("Mode Selection")); RLModeBox->setLayout(RLModeLayout); RLLayout->addWidget(RLModeBox); RLLayout->addWidget(FreakBox); RLLayout->addWidget(m_pctrlModeViewType); RLLayout->addStretch(1); ModeBox->setLayout(RLLayout); } } //___________________Main Layout____________ m_pctrlStackWidget = new QStackedWidget; m_pctrlStackWidget->addWidget(TimeBox); m_pctrlStackWidget->addWidget(ModeBox); m_pctrlStackWidget->setCurrentIndex(0); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addWidget(StabilityDirBox); MainLayout->addWidget(m_pctrlStackWidget); setLayout(MainLayout); } void StabViewDlg::SetControls() { QMiarex * pMiarex = (QMiarex*)s_pMiarex; QString str, strong; GetSpeedUnit(str, MainFrame::s_SpeedUnit); blockSignals(true); m_pctrlLongDynamics->setChecked(pMiarex->m_bLongitudinal); m_pctrlLatDynamics->setChecked(!pMiarex->m_bLongitudinal); if(pMiarex->m_pCurWPolar && pMiarex->m_pCurWPolar->m_WPolarType!=STABILITYPOLAR) { // m_pControlModel->setRowCount(0); } if(pMiarex->m_iStabilityView==STABTIMEVIEW) { m_pctrlStackWidget->setCurrentIndex(0); m_pctrlInitialConditionsWidget->setCurrentIndex(pMiarex->m_StabilityResponseType); m_pctrlInitCondResponse->setChecked(pMiarex->m_StabilityResponseType==0); m_pctrlForcedResponse->setChecked(pMiarex->m_StabilityResponseType==1); m_pctrlModalResponse->setChecked(pMiarex->m_StabilityResponseType==2); } else if(pMiarex->m_iStabilityView==STABPOLARVIEW) { m_pctrlStackWidget->setCurrentIndex(1); m_pctrlModeViewType->setCurrentIndex(0); } else if(pMiarex->m_iStabilityView==STAB3DVIEW) { m_pctrlStackWidget->setCurrentIndex(1); m_pctrlModeViewType->setCurrentIndex(1); } SetMode(m_iCurrentMode); strong = QString::fromUtf8("°/s"); if(pMiarex->m_bLongitudinal) { m_pctrlStabLabel1->setText(tr("u0=")); m_pctrlStabLabel2->setText(tr("w0=")); m_pctrlStabLabel3->setText(tr("q0=")); m_pctrlUnit1->setText(str); m_pctrlUnit2->setText(str); m_pctrlUnit3->setText(strong); } else { m_pctrlStabLabel1->setText(tr("v0=")); m_pctrlStabLabel2->setText(tr("p0=")); m_pctrlStabLabel3->setText(tr("r0=")); m_pctrlUnit1->setText(str); m_pctrlUnit2->setText(strong); m_pctrlUnit3->setText(strong); } m_pctrlStabVar1->SetValue(pMiarex->m_TimeInput[0]); m_pctrlStabVar2->SetValue(pMiarex->m_TimeInput[1]); m_pctrlStabVar3->SetValue(pMiarex->m_TimeInput[2]); m_pctrlTotalTime->SetValue(pMiarex->m_TotalTime); m_pctrlDeltat->SetValue(pMiarex->m_Deltat); m_pctrlTimeMode1->setChecked(m_iCurrentMode%4==0); m_pctrlTimeMode2->setChecked(m_iCurrentMode%4==1); m_pctrlTimeMode3->setChecked(m_iCurrentMode%4==2); m_pctrlTimeMode4->setChecked(m_iCurrentMode%4==3); m_pctrlRLMode1->setChecked(m_iCurrentMode%4==0); m_pctrlRLMode2->setChecked(m_iCurrentMode%4==1); m_pctrlRLMode3->setChecked(m_iCurrentMode%4==2); m_pctrlRLMode4->setChecked(m_iCurrentMode%4==3); m_pctrlRLMode1->setEnabled(pMiarex->m_iStabilityView>0 && pMiarex->m_pCurWOpp); m_pctrlRLMode2->setEnabled(pMiarex->m_iStabilityView>0 && pMiarex->m_pCurWOpp); m_pctrlRLMode3->setEnabled(pMiarex->m_iStabilityView>0 && pMiarex->m_pCurWOpp); m_pctrlRLMode4->setEnabled(pMiarex->m_iStabilityView>0 && pMiarex->m_pCurWOpp); // Enable the time response controls only if // - the polar's type is 7 // - we have an active wopp // - the StabilityView is0 bool bEnableTimeCtrl = pMiarex->m_pCurWOpp && pMiarex->m_pCurWOpp->m_WPolarType==STABILITYPOLAR && pMiarex->m_iStabilityView==STABTIMEVIEW; m_pctrlAddCurve->setEnabled(bEnableTimeCtrl); m_pctrlRenameCurve->setEnabled(m_pctrlCurveList->count()); m_pctrlPlotStabGraph->setEnabled(m_pctrlCurveList->count()); m_pctrlDeleteCurve->setEnabled(m_pctrlCurveList->count()); m_pctrlCurveList->setEnabled(m_pctrlCurveList->count()); m_pctrlTimeMode1->setEnabled(bEnableTimeCtrl); m_pctrlTimeMode2->setEnabled(bEnableTimeCtrl); m_pctrlTimeMode3->setEnabled(bEnableTimeCtrl); m_pctrlTimeMode4->setEnabled(bEnableTimeCtrl); m_pctrlStabVar1->setEnabled(bEnableTimeCtrl); m_pctrlStabVar2->setEnabled(bEnableTimeCtrl); m_pctrlStabVar3->setEnabled(bEnableTimeCtrl); m_pctrlDeltat->setEnabled(bEnableTimeCtrl); m_pctrlTotalTime->setEnabled(bEnableTimeCtrl); // Enable the 3D mode animation controls only if // - the polar's type is 7 // - we have an active wopp // - the StabilityView is 3 bool bEnable3DAnimation = pMiarex->m_iStabilityView==STAB3DVIEW && pMiarex->m_pCurWOpp && pMiarex->m_pCurWOpp->m_WPolarType==STABILITYPOLAR; m_pctrlAnimate->setEnabled(bEnable3DAnimation); m_pctrlAnimateRestart->setEnabled(bEnable3DAnimation); m_pctrlAnimationAmplitude->setEnabled(bEnable3DAnimation); m_pctrlAnimationSpeed->setEnabled(bEnable3DAnimation); m_pctrlModeStep->SetValue(pMiarex->m_Modedt); FillEigenThings(); blockSignals(false); } void StabViewDlg::SetTimeCurveStyle(QColor const &Color, int const&Style, int const &Width, bool const& bCurve, bool const& bPoints) { if(!m_pCurve) return; QMiarex * pMiarex = (QMiarex*)s_pMiarex; Curve *pCurve; for (int i=0; im_TimeGraph[0].GetCurveCount(); i++) { pCurve = pMiarex->m_TimeGraph[0].GetCurve(i); if(pCurve == m_pCurve) { for(int ig=0; ig<4; ig++) { pCurve = pMiarex->m_TimeGraph[ig].GetCurve(i); pCurve->SetColor(Color); pCurve->SetStyle(Style); pCurve->SetWidth(Width); pCurve->SetVisible(bCurve); pCurve->ShowPoints(bPoints); } return; } } } void StabViewDlg::OnRenameCurve() { QMiarex * pMiarex = (QMiarex*)s_pMiarex; Curve *pCurve; if(!m_pCurve) return; QString NewName = "Test Name"; NewNameDlg dlg(this); dlg.m_OldName = m_pCurve->title(); dlg.InitDialog(); if(dlg.exec() != QDialog::Accepted) return; NewName = dlg.m_NewName; for (int i=0; im_TimeGraph[0].GetCurveCount(); i++) { pCurve = pMiarex->m_TimeGraph[0].GetCurve(i); if(pCurve && (pCurve == m_pCurve)) { for(int ig=0; ig<4; ig++) { pCurve = pMiarex->m_TimeGraph[ig].GetCurve(i); pCurve->SetTitle(NewName); } FillCurveList(); OnPlotStabilityGraph(); return; } } } void StabViewDlg::OnSelChangeCurve(int sel) { QMiarex * pMiarex = (QMiarex*)s_pMiarex; QString strong = m_pctrlCurveList->itemText(sel); m_pCurve = pMiarex->m_TimeGraph[0].GetCurve(strong); m_pCurve->title(strong); pMiarex->SetCurveParams(); } void StabViewDlg::OnAddCurve() { AddCurve(); if(m_pCurve) { int pos =m_pctrlCurveList->findText(m_pCurve->title()); m_pctrlCurveList->setCurrentIndex(pos); } OnPlotStabilityGraph(); } void StabViewDlg::OnDeleteCurve() { QMiarex * pMiarex = (QMiarex*)s_pMiarex; if(!m_pCurve) return; QString CurveTitle = m_pCurve->title(); for(int ig=0; ig<4; ig++) pMiarex->m_TimeGraph[ig].DeleteCurve(CurveTitle); m_pCurve = NULL; FillCurveList(); m_pctrlCurveList->setCurrentIndex(0); m_pctrlPlotStabGraph->setEnabled(pMiarex->m_pCurWOpp && m_pctrlCurveList->count()); m_pctrlRenameCurve->setEnabled(pMiarex->m_pCurWOpp && m_pctrlCurveList->count()); m_pctrlDeleteCurve->setEnabled(pMiarex->m_pCurWOpp && m_pctrlCurveList->count()); m_pctrlCurveList->setEnabled(pMiarex->m_pCurWOpp && m_pctrlCurveList->count()); if(m_pctrlCurveList->count()) m_pCurve = pMiarex->m_TimeGraph[0].GetCurve(m_pctrlCurveList->itemText(0)); else m_pCurve = NULL; pMiarex->SetCurveParams(); pMiarex->CreateStabilityCurves(); pMiarex->UpdateView(); pMiarex->setFocus(); } void StabViewDlg::AddCurve() { QMiarex * pMiarex = (QMiarex*)s_pMiarex; int nCurves = pMiarex->m_TimeGraph[0].GetCurveCount(); QString strong = tr("New curve") + QString(" %1").arg(nCurves); Curve *pCurve; for(int ig=0; ig<4; ig++) { pCurve = pMiarex->m_TimeGraph[ig].AddCurve(); pCurve->SetTitle(strong); if(ig==0) m_pCurve = pCurve; } m_pctrlCurveList->addItem(pCurve->title()); m_pctrlPlotStabGraph->setEnabled(pMiarex->m_pCurWOpp && m_pctrlCurveList->count()); m_pctrlRenameCurve->setEnabled(pMiarex->m_pCurWOpp && m_pctrlCurveList->count()); m_pctrlDeleteCurve->setEnabled(pMiarex->m_pCurWOpp && m_pctrlCurveList->count()); m_pctrlCurveList->setEnabled(pMiarex->m_pCurWOpp && m_pctrlCurveList->count()); pMiarex->SetCurveParams(); } void StabViewDlg::FillCurveList() { QMiarex * pMiarex = (QMiarex*)s_pMiarex; m_pctrlCurveList->clear(); QString strong; for(int i=0; im_TimeGraph[0].GetCurveCount(); i++) { pMiarex->m_TimeGraph[0].GetCurve(i)->title(strong); m_pctrlCurveList->addItem(strong); } if(m_pCurve) { int sel = m_pctrlCurveList->findText(m_pCurve->title()); m_pctrlCurveList->setCurrentIndex(sel); } } double StabViewDlg::GetControlInput(const double &time) { static double t1, t2, in1, in2; t1 = t2 = 0.0; t1 = m_pControlModel->index(0, 0, QModelIndex()).data().toDouble(); for(int i=1; irowCount()-1; i++) { t2 = m_pControlModel->index(i, 0, QModelIndex()).data().toDouble(); if(t1<=time && timeindex(i-1, 1, QModelIndex()).data().toDouble(); in2 = m_pControlModel->index(i, 1, QModelIndex()).data().toDouble(); return (in1 + (time-t1) * (in2-in1)/(t2-t1))*PI/180.0; } t1 = t2; } return 0.0; } xflr5-6.09-06/src/miarex/BodyTableDelegate.cpp000644 001750 000144 00000005470 12247174401 022356 0ustar00techwinderusers000000 000000 /**************************************************************************** BodyTableDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "BodyTableDelegate.h" BodyTableDelegate::BodyTableDelegate(QObject *parent) : QItemDelegate(parent) { m_pNRows = NULL; } QWidget *BodyTableDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex & index ) const { DoubleEdit *editor = new DoubleEdit(parent); editor->setAlignment(Qt::AlignRight); editor->SetPrecision(m_Precision[index.column()]); return editor; } void BodyTableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { double value = index.model()->data(index, Qt::EditRole).toDouble(); DoubleEdit *pDE = static_cast(editor); pDE->SetValue(value); } void BodyTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { DoubleEdit *pDE = static_cast(editor); double value = pDE->Value(); model->setData(index, value, Qt::EditRole); } void BodyTableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QString strong; QStyleOptionViewItem myOption = option; myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; strong = QString("%1").arg(index.model()->data(index, Qt::DisplayRole).toDouble(),0,'f', m_Precision[index.column()]); // if(index.row()> *m_pNRows) strong=" "; drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } void BodyTableDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { editor->setGeometry(option.rect); } void BodyTableDelegate::SetPointers(int *PrecisionTable, int *pNRows) { m_Precision = PrecisionTable; m_pNRows = pNRows; } void BodyTableDelegate::SetPointer(int *PrecisionTable) { m_Precision = PrecisionTable; } xflr5-6.09-06/src/miarex/GL3dWingDlg.cpp000644 001750 000144 00000221222 12247174402 021057 0ustar00techwinderusers000000 000000 /**************************************************************************** GL3dWingDlg Class Copyright (C) 2009-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../mainframe.h" #include "../globals.h" #include "../miarex/GLCreateLists.h" #include "../threedwidget.h" #include "../misc/GLLightDlg.h" #include "Miarex.h" #include "GL3dWingDlg.h" #include "WingScaleDlg.h" #include "InertiaDlg.h" #include "../misc/W3dPrefsDlg.h" #include #include #include #include #include #include #include #include #include #include #define WINGGEOMETRY 1400 #define SECTIONHIGHLIGHT 1402 void* GL3dWingDlg::s_pMiarex; //pointer to the Miarex Application window bool GL3dWingDlg::s_bOutline = true; bool GL3dWingDlg::s_bSurfaces = true; bool GL3dWingDlg::s_bVLMPanels = false; bool GL3dWingDlg::s_bAxes = true; bool GL3dWingDlg::s_bShowMasses = false; bool GL3dWingDlg::s_bFoilNames = false; QList *GL3dWingDlg::s_poaWing; QList *GL3dWingDlg::s_poaFoil; QPoint GL3dWingDlg::s_WindowPos=QPoint(20,20); QSize GL3dWingDlg::s_WindowSize=QSize(900, 700); bool GL3dWingDlg::s_bWindowMaximized=false; GL3dWingDlg::GL3dWingDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Wing Edition")); setWindowFlags(Qt::Window); m_pWing = NULL; m_iSection = -1; m_GLList = 0; m_UFOOffset.Set( 0.0, 0.0, 0.0); m_ClipPlanePos = 5.0; m_glViewportTrans.x = 0.0; m_glViewportTrans.y = 0.0; m_glViewportTrans.z = 0.0; m_glScaled = 1.0; m_bResetglSectionHighlight = true; m_bResetglWing = true; m_bEnableName = true; m_bAcceptName = true; m_bTrans = false; m_bDragPoint = false; m_bArcball = false; m_bCrossPoint = false; m_bPickCenter = false; m_bRightSide = true; m_bChanged = false; m_bDescriptionChanged = false; m_LastPoint.setX(0); m_LastPoint.setY(0); m_PointDown.setX(0); m_PointDown.setY(0); memset(MatIn, 0, 16*sizeof(double)); memset(MatOut, 0, 16*sizeof(double)); m_ArcBall.m_pOffx = &m_UFOOffset.x; m_ArcBall.m_pOffy = &m_UFOOffset.y; m_ArcBall.m_pTransx = &m_glViewportTrans.x; m_ArcBall.m_pTransy = &m_glViewportTrans.y; m_ArcBall.m_pRect = &m_pGLWidget->m_rCltRect; m_pResetScales = new QAction(tr("Reset Scales"), this); m_pInsertBefore = new QAction(tr("Insert Before"), this); m_pInsertAfter = new QAction(tr("Insert after"), this); m_pDeleteSection = new QAction(tr("Delete section"), this); m_pResetSection = new QAction(tr("Reset section"), this); m_pImportWingAct = new QAction(tr("Import Wing from File..."), this); m_pExportWingAct = new QAction(tr("Export Wing to File..."), this); m_pContextMenu = new QMenu(tr("Section"),this); m_pContextMenu->addAction(m_pInsertBefore); m_pContextMenu->addAction(m_pInsertAfter); m_pContextMenu->addAction(m_pDeleteSection); m_pContextMenu->addAction(m_pResetSection); SetupLayout(); Connect(); setMouseTracking(true); } GL3dWingDlg::~GL3dWingDlg() { delete m_pWingModel; delete m_pWingDelegate; } bool GL3dWingDlg::CheckWing() { if(!m_pWing->m_WingName.length()) { QMessageBox::warning(this, tr("Warning"), tr("Please enter a name for the wing")); m_pctrlWingName->setFocus(); return false; } for (int k=1; kNWingSection(); k++) { if(m_pWing->YPosition(k)*1.00001 < m_pWing->YPosition(k-1)) { QMessageBox::warning(this, tr("Warning"), tr("Warning : Panel sequence is inconsistent")); return false; } } int NYPanels = 0; for(int j=0; jNWingSection()-1; j++) { NYPanels += m_pWing->NYPanels(j); } if(NYPanels*2>=MAXSPANSTATIONS) { QString strange = QString(" %1").arg(MAXSPANSTATIONS/2); strange = tr("Too many spanwise panels.\nThe maximum number is")+strange; QMessageBox::warning(this, tr("Warning"), strange); return false; } // if(VLMGetPanelTotal()>VLMMAXMATSIZE/2) // { // QMessageBox::warning(this, tr("Warning"), tr("Too many panels\nReduce the mesh size")); // return false; // } if(m_pWing->m_nFlaps>=20) { QString strong = tr("Only 10 flaps x 2 will be handled"); if (QMessageBox::Ok != QMessageBox::question(window(), tr("Question"), strong, QMessageBox::Ok|QMessageBox::Cancel)) return false; } return true; } void GL3dWingDlg::ComputeGeometry() { // Computes the wing's characteristics from the panel data m_pWing->ComputeGeometry(); m_pWing->CreateSurfaces(CVector(0.0,0.0,0.0), 0.0, 0.0); for (int i=0; im_NSurfaces; i++) m_pWing->m_Surface[i].SetSidePoints(NULL, 0.0, 0.0); } void GL3dWingDlg::contextMenuEvent(QContextMenuEvent *event) { // Display the context menu if(m_pctrlWingTable->geometry().contains(event->pos())) m_pContextMenu->exec(event->globalPos()); } void GL3dWingDlg::Connect() { connect(m_pInsertBefore, SIGNAL(triggered()), this, SLOT(OnInsertBefore())); connect(m_pInsertAfter, SIGNAL(triggered()), this, SLOT(OnInsertAfter())); connect(m_pDeleteSection, SIGNAL(triggered()), this, SLOT(OnDeleteSection())); connect(m_pResetSection, SIGNAL(triggered()), this, SLOT(OnResetSection())); connect(m_pResetScales, SIGNAL(triggered()), this, SLOT(On3DReset())); connect(m_pctrlIso, SIGNAL(clicked()),this, SLOT(On3DIso())); connect(m_pctrlX, SIGNAL(clicked()),this, SLOT(On3DFront())); connect(m_pctrlY, SIGNAL(clicked()),this, SLOT(On3DLeft())); connect(m_pctrlZ, SIGNAL(clicked()),this, SLOT(On3DTop())); connect(m_pctrlReset, SIGNAL(clicked()),this, SLOT(On3DReset())); connect(m_pctrlPickCenter, SIGNAL(clicked()),this, SLOT(On3DPickCenter())); connect(m_pctrlFoilNames, SIGNAL(clicked()),this, SLOT(OnFoilNames())); connect(m_pctrlShowMasses, SIGNAL(clicked()),this, SLOT(OnShowMasses())); connect(m_pctrlClipPlanePos, SIGNAL(sliderMoved(int)), this, SLOT(OnClipPlane(int))); connect(m_pctrlAxes, SIGNAL(clicked()), this, SLOT(OnAxes())); connect(m_pctrlPanels, SIGNAL(clicked()), this, SLOT(OnPanels())); connect(m_pctrlLight, SIGNAL(clicked()), this, SLOT(OnLight())); connect(m_pctrlSurfaces, SIGNAL(clicked()), this, SLOT(OnSurfaces())); connect(m_pctrlOutline, SIGNAL(clicked()), this, SLOT(OnOutline())); connect(m_pctrlInsertBefore, SIGNAL(clicked()), this, SLOT(OnInsertBefore())); connect(m_pctrlInsertAfter, SIGNAL(clicked()), this, SLOT(OnInsertAfter())); connect(m_pctrlDeleteSection, SIGNAL(clicked()), this, SLOT(OnDeleteSection())); connect(m_pctrlResetMesh, SIGNAL(clicked()), this, SLOT(OnResetMesh())); connect(m_pctrlScaleWing, SIGNAL(clicked()), this, SLOT(OnScaleWing())); connect(m_pctrlWingColor, SIGNAL(clicked()), this, SLOT(OnWingColor())); connect(m_pctrlSymetric, SIGNAL(clicked()), this, SLOT(OnSymetric())); connect(m_pctrlRightSide, SIGNAL(clicked()), this, SLOT(OnSide())); connect(m_pctrlLeftSide, SIGNAL(clicked()), this, SLOT(OnSide())); connect(m_pctrlInertiaButton, SIGNAL(clicked()), this, SLOT(OnInertia())); connect(m_pctrlWingDescription, SIGNAL(textChanged()), this, SLOT(OnDescriptionChanged())); connect(m_pImportWingBtn, SIGNAL(clicked()),this, SLOT(OnImportWing())); connect(m_pExportWingBtn, SIGNAL(clicked()),this, SLOT(OnExportWing())); } void GL3dWingDlg::CreateXPoints(int NXPanels, int XDist, Foil *pFoilA, Foil *pFoilB, double *xPointA, double *xPointB, int &NXLead, int &NXFlap) { // the chordwise panel distribution is set i.a.w. with the flap hinges; int l; int NXFlapA, NXFlapB, NXLeadA, NXLeadB; double dl, dl2; double xHingeA, xHingeB; if(pFoilA && pFoilA->m_bTEFlap) xHingeA=pFoilA->m_TEXHinge/100.0; else xHingeA=1.0; if(pFoilB && pFoilB->m_bTEFlap) xHingeB=pFoilB->m_TEXHinge/100.0; else xHingeB=1.0; NXFlapA = (int)((1.0-xHingeA) * NXPanels); NXFlapB = (int)((1.0-xHingeB) * NXPanels); if(pFoilA && pFoilA->m_bTEFlap && NXFlapA==0) NXFlapA++; if(pFoilB && pFoilB->m_bTEFlap && NXFlapB==0) NXFlapB++; NXLeadA = NXPanels - NXFlapA; NXLeadB = NXPanels - NXFlapB; NXFlap = qMax(NXFlapA, NXFlapB); if(NXFlap>NXPanels/2) NXFlap=(int)NXPanels/2; NXLead = NXPanels - NXFlap; for(l=0; lsetRowCount(m_pWing->NWingSection()); for(i=0; iNWingSection(); i++) { FillTableRow(i); } } void GL3dWingDlg::FillTableRow(int row) { QString strong; QModelIndex ind; ind = m_pWingModel->index(row, 0, QModelIndex()); m_pWingModel->setData(ind, m_pWing->YPosition(row) * MainFrame::s_mtoUnit); ind = m_pWingModel->index(row, 1, QModelIndex()); m_pWingModel->setData(ind, m_pWing->Chord(row) * MainFrame::s_mtoUnit); ind = m_pWingModel->index(row, 2, QModelIndex()); m_pWingModel->setData(ind, m_pWing->Offset(row) * MainFrame::s_mtoUnit); ind = m_pWingModel->index(row, 3, QModelIndex()); m_pWingModel->setData(ind, m_pWing->Dihedral(row)); ind = m_pWingModel->index(row, 4, QModelIndex()); m_pWingModel->setData(ind, m_pWing->Twist(row)); ind = m_pWingModel->index(row, 5, QModelIndex()); if(m_bRightSide) m_pWingModel->setData(ind, m_pWing->RightFoil(row)); else m_pWingModel->setData(ind, m_pWing->LeftFoil(row)); if(rowNWingSection()) { ind = m_pWingModel->index(row, 6, QModelIndex()); m_pWingModel->setData(ind, m_pWing->NXPanels(row)); if(m_pWing->XPanelDist(row)==UNIFORM) strong = tr("Uniform"); else if(m_pWing->XPanelDist(row)==COSINE) strong = tr("Cosine"); ind = m_pWingModel->index(row, 7, QModelIndex()); m_pWingModel->setData(ind, strong); ind = m_pWingModel->index(row, 8, QModelIndex()); m_pWingModel->setData(ind, m_pWing->NYPanels(row)); if(m_pWing->YPanelDist(row)==UNIFORM) strong = tr("Uniform"); else if(m_pWing->YPanelDist(row)==COSINE) strong = tr("Cosine"); else if(m_pWing->YPanelDist(row)==SINE) strong = tr("Sine"); else if(m_pWing->YPanelDist(row)== INVERSESINE) strong = tr("-Sine"); ind = m_pWingModel->index(row, 9, QModelIndex()); m_pWingModel->setData(ind, strong); } else { strong = " "; ind = m_pWingModel->index(row, 6, QModelIndex()); m_pWingModel->setData(ind, 0); ind = m_pWingModel->index(row, 7, QModelIndex()); m_pWingModel->setData(ind, " "); ind = m_pWingModel->index(row, 8, QModelIndex()); m_pWingModel->setData(ind, 0); ind = m_pWingModel->index(row, 9, QModelIndex()); m_pWingModel->setData(ind, " "); } } void GL3dWingDlg::GLCreateMesh() { QColor color; int width, j,l,k; CVector A, B, C, D, N, LATB, TALB; glNewList(MESHPANELS,GL_COMPILE); { m_GLList++; glEnable(GL_DEPTH_TEST); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); color = W3dPrefsDlg::s_VLMColor; // style = W3dPrefsDlg::s_VLMStyle; width = W3dPrefsDlg::s_VLMWidth; glLineWidth(width); glColor3d(color.redF(),color.greenF(),color.blueF()); for (j=0; jm_NSurfaces; j++) { for(k=0; km_Surface[j].m_NYPanels; k++) { glBegin(GL_QUAD_STRIP); { for (l=0; lm_Surface[j].m_NXPanels; l++) { m_pWing->m_Surface[j].GetPanel(k,l,TOPSURFACE); LATB = m_pWing->m_Surface[j].TB - m_pWing->m_Surface[j].LA; TALB = m_pWing->m_Surface[j].LB - m_pWing->m_Surface[j].TA; N = LATB *TALB; N. Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(m_pWing->m_Surface[j].TA.x, m_pWing->m_Surface[j].TA.y, m_pWing->m_Surface[j].TA.z); glVertex3d(m_pWing->m_Surface[j].TB.x, m_pWing->m_Surface[j].TB.y, m_pWing->m_Surface[j].TB.z); } for (l=m_pWing->m_Surface[j].m_NXPanels-1; l>=0; l--) { m_pWing->m_Surface[j].GetPanel(k,l,BOTSURFACE); LATB = m_pWing->m_Surface[j].TB - m_pWing->m_Surface[j].LA; TALB = m_pWing->m_Surface[j].LB - m_pWing->m_Surface[j].TA; N = LATB *TALB; N. Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(m_pWing->m_Surface[j].LA.x, m_pWing->m_Surface[j].LA.y, m_pWing->m_Surface[j].LA.z); glVertex3d(m_pWing->m_Surface[j].LB.x, m_pWing->m_Surface[j].LB.y, m_pWing->m_Surface[j].LB.z); } glVertex3d(m_pWing->m_Surface[j].TA.x, m_pWing->m_Surface[j].TA.y, m_pWing->m_Surface[j].TA.z); glVertex3d(m_pWing->m_Surface[j].TB.x, m_pWing->m_Surface[j].TB.y, m_pWing->m_Surface[j].TB.z); } glEnd(); } } //tip patches for (j=0; jm_NSurfaces; j++) { if(m_pWing->m_Surface[j].m_bIsTipLeft) { for (l=0; lm_Surface[j].m_NXPanels; l++) { glBegin(GL_QUADS); { m_pWing->m_Surface[j].GetPanel(0,l,TOPSURFACE); A = m_pWing->m_Surface[j].TA; B = m_pWing->m_Surface[j].LA; m_pWing->m_Surface[j].GetPanel(0,l,BOTSURFACE); C = m_pWing->m_Surface[j].LA; D = m_pWing->m_Surface[j].TA; LATB = A-C; TALB = D-B; N = LATB *TALB; N. Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(A.x,A.y,A.z); glVertex3d(B.x,B.y,B.z); glVertex3d(C.x,C.y,C.z); glVertex3d(D.x,D.y,D.z); } glEnd(); } } if(m_pWing->m_Surface[j].m_bIsTipRight) { for (l=0; lm_Surface[j].m_NXPanels; l++) { glBegin(GL_QUADS); { m_pWing->m_Surface[j].GetPanel(m_pWing->m_Surface[j].m_NYPanels-1,l,TOPSURFACE); A = m_pWing->m_Surface[j].TB; B = m_pWing->m_Surface[j].LB; m_pWing->m_Surface[j].GetPanel(m_pWing->m_Surface[j].m_NYPanels-1,l,BOTSURFACE); C = m_pWing->m_Surface[j].LB; D = m_pWing->m_Surface[j].TB; LATB = A-C; TALB = D-B; N = LATB *TALB; N. Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(A.x,A.y,A.z); glVertex3d(B.x,B.y,B.z); glVertex3d(C.x,C.y,C.z); glVertex3d(D.x,D.y,D.z); } glEnd(); } } } glDisable(GL_DEPTH_TEST); } glEndList(); glNewList(MESHBACK,GL_COMPILE); { m_GLList++; glEnable(GL_DEPTH_TEST); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.0, 1.0); color = MainFrame::s_BackgroundColor; // style = W3dPrefsDlg::s_VLMStyle; width = W3dPrefsDlg::s_VLMWidth; glColor3d(color.redF(),color.greenF(),color.blueF()); glLineWidth(1.0); glDisable (GL_LINE_STIPPLE); for (j=0; jm_NSurfaces; j++) { for(k=0; km_Surface[j].m_NYPanels; k++) { glBegin(GL_QUAD_STRIP); { for (l=0; lm_Surface[j].m_NXPanels; l++) { m_pWing->m_Surface[j].GetPanel(k,l,TOPSURFACE); LATB = m_pWing->m_Surface[j].TB - m_pWing->m_Surface[j].LA; TALB = m_pWing->m_Surface[j].LB - m_pWing->m_Surface[j].TA; N = LATB *TALB; N. Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(m_pWing->m_Surface[j].TA.x, m_pWing->m_Surface[j].TA.y, m_pWing->m_Surface[j].TA.z); glVertex3d(m_pWing->m_Surface[j].TB.x, m_pWing->m_Surface[j].TB.y, m_pWing->m_Surface[j].TB.z); } for (l=m_pWing->m_Surface[j].m_NXPanels-1; l>=0; l--) { m_pWing->m_Surface[j].GetPanel(k,l,BOTSURFACE); LATB = m_pWing->m_Surface[j].TB - m_pWing->m_Surface[j].LA; TALB = m_pWing->m_Surface[j].LB - m_pWing->m_Surface[j].TA; N = LATB *TALB; N. Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(m_pWing->m_Surface[j].LA.x, m_pWing->m_Surface[j].LA.y, m_pWing->m_Surface[j].LA.z); glVertex3d(m_pWing->m_Surface[j].LB.x, m_pWing->m_Surface[j].LB.y, m_pWing->m_Surface[j].LB.z); } glVertex3d(m_pWing->m_Surface[j].TA.x, m_pWing->m_Surface[j].TA.y, m_pWing->m_Surface[j].TA.z); glVertex3d(m_pWing->m_Surface[j].TB.x, m_pWing->m_Surface[j].TB.y, m_pWing->m_Surface[j].TB.z); } glEnd(); } } for (j=0; jm_NSurfaces; j++) { if(m_pWing->m_Surface[j].m_bIsTipLeft) { for (l=0; lm_Surface[j].m_NXPanels; l++) { glBegin(GL_QUADS); { m_pWing->m_Surface[j].GetPanel(0,l,TOPSURFACE); A = m_pWing->m_Surface[j].TA; B = m_pWing->m_Surface[j].LA; m_pWing->m_Surface[j].GetPanel(0,l,BOTSURFACE); C = m_pWing->m_Surface[j].LA; D = m_pWing->m_Surface[j].TA; LATB = A-C; TALB = D-B; N = LATB *TALB; N. Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(A.x,A.y,A.z); glVertex3d(B.x,B.y,B.z); glVertex3d(C.x,C.y,C.z); glVertex3d(D.x,D.y,D.z); } glEnd(); } } if(m_pWing->m_Surface[j].m_bIsTipRight) { for (l=0; lm_Surface[j].m_NXPanels; l++) { glBegin(GL_QUADS); { m_pWing->m_Surface[j].GetPanel(m_pWing->m_Surface[j].m_NYPanels-1,l,TOPSURFACE); A = m_pWing->m_Surface[j].TB; B = m_pWing->m_Surface[j].LB; m_pWing->m_Surface[j].GetPanel(m_pWing->m_Surface[j].m_NYPanels-1,l,BOTSURFACE); C = m_pWing->m_Surface[j].LB; D = m_pWing->m_Surface[j].TB; LATB = A-C; TALB = D-B; N = LATB *TALB; N. Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(A.x,A.y,A.z); glVertex3d(B.x,B.y,B.z); glVertex3d(C.x,C.y,C.z); glVertex3d(D.x,D.y,D.z); } glEnd(); } } } glDisable(GL_DEPTH_TEST); glDisable(GL_POLYGON_OFFSET_FILL); } glEndList(); } void GL3dWingDlg::GLCreateSectionHighlight() { // QMiarex *pMiarex = (QMiarex*)s_pMiarex; int j,l; int section = 0; for(j=0; jNWingSection(); j++) { if(j==m_iSection) break; if(qAbs(m_pWing->YPosition(j+1)-m_pWing->YPosition(j)) > QMiarex::s_MinPanelSize) section++; } glNewList(SECTIONHIGHLIGHT,GL_COMPILE); { m_GLList++; glDisable (GL_LINE_STIPPLE); glColor3d(1.0, 0.0, 0.0); glLineWidth(3); if((m_pWing->m_bSymetric || m_bRightSide) && !m_pWing->m_bIsFin) { if(m_iSectionNWingSection()) { j = m_pWing->m_NSurfaces/2 + section; glBegin(GL_LINE_STRIP); { for (l=0; lm_Surface[j].m_NXPanels; l++) { m_pWing->m_Surface[j].GetPanel(0, l, TOPSURFACE); glVertex3d(m_pWing->m_Surface[j].TA.x, m_pWing->m_Surface[j].TA.y, m_pWing->m_Surface[j].TA.z); } glVertex3d(m_pWing->m_Surface[j].LA.x, m_pWing->m_Surface[j].LA.y, m_pWing->m_Surface[j].LA.z); for (l=m_pWing->m_Surface[j].m_NXPanels-1; l>=0; l--) { m_pWing->m_Surface[j].GetPanel(0, l, BOTSURFACE); glVertex3d(m_pWing->m_Surface[j].TA.x, m_pWing->m_Surface[j].TA.y, m_pWing->m_Surface[j].TA.z); } } glEnd(); } else { j = m_pWing->m_NSurfaces/2 + section -1; glBegin(GL_LINE_STRIP); { for (l=0; lm_Surface[j].m_NXPanels; l++) { m_pWing->m_Surface[j].GetPanel(m_pWing->m_Surface[j].m_NYPanels-1, l, TOPSURFACE); glVertex3d(m_pWing->m_Surface[j].TB.x, m_pWing->m_Surface[j].TB.y, m_pWing->m_Surface[j].TB.z); } glVertex3d(m_pWing->m_Surface[j].LB.x, m_pWing->m_Surface[j].LB.y, m_pWing->m_Surface[j].LB.z); for (l=m_pWing->m_Surface[j].m_NXPanels-1; l>=0; l--) { m_pWing->m_Surface[j].GetPanel(m_pWing->m_Surface[j].m_NYPanels-1, l, BOTSURFACE); glVertex3d(m_pWing->m_Surface[j].TB.x, m_pWing->m_Surface[j].TB.y, m_pWing->m_Surface[j].TB.z); } } glEnd(); } } if(m_pWing->m_bSymetric || !m_bRightSide) { if(m_iSection>0 ) { if(!m_pWing->m_bIsFin) j = m_pWing->m_NSurfaces/2 - section; else j = m_pWing->m_NSurfaces - section; glBegin(GL_LINE_STRIP); { for (l=0; lm_Surface[j].m_NXPanels; l++) { m_pWing->m_Surface[j].GetPanel(0, l, TOPSURFACE); glVertex3d(m_pWing->m_Surface[j].TA.x, m_pWing->m_Surface[j].TA.y, m_pWing->m_Surface[j].TA.z); } glVertex3d(m_pWing->m_Surface[j].LA.x, m_pWing->m_Surface[j].LA.y, m_pWing->m_Surface[j].LA.z); for (l=m_pWing->m_Surface[j].m_NXPanels-1; l>=0; l--) { m_pWing->m_Surface[j].GetPanel(0, l, BOTSURFACE); glVertex3d(m_pWing->m_Surface[j].TA.x, m_pWing->m_Surface[j].TA.y, m_pWing->m_Surface[j].TA.z); } } glEnd(); } else { if(!m_pWing->m_bIsFin) j = m_pWing->m_NSurfaces/2 - 1; else j = m_pWing->m_NSurfaces - 1; glBegin(GL_LINE_STRIP); { for (l=0; lm_Surface[j].m_NXPanels; l++) { m_pWing->m_Surface[j].GetPanel(m_pWing->m_Surface[j].m_NYPanels-1, l, TOPSURFACE); glVertex3d(m_pWing->m_Surface[j].TB.x, m_pWing->m_Surface[j].TB.y, m_pWing->m_Surface[j].TB.z); } glVertex3d(m_pWing->m_Surface[j].LB.x, m_pWing->m_Surface[j].LB.y, m_pWing->m_Surface[j].LB.z); for (l=m_pWing->m_Surface[j].m_NXPanels-1; l>=0; l--) { m_pWing->m_Surface[j].GetPanel(m_pWing->m_Surface[j].m_NYPanels-1, l, BOTSURFACE); glVertex3d(m_pWing->m_Surface[j].TB.x, m_pWing->m_Surface[j].TB.y, m_pWing->m_Surface[j].TB.z); } } glEnd(); } } } glEndList(); } void GL3dWingDlg::GLDraw3D() { glClearColor(MainFrame::s_BackgroundColor.redF(), MainFrame::s_BackgroundColor.greenF(), MainFrame::s_BackgroundColor.blueF(),0.0); if(!glIsList(GLLISTSPHERE)) { m_pGLWidget->GLCreateUnitSphere(); m_GLList++; } if(m_bResetglWing) { m_ArcBall.GetMatrix(); CVector eye(0.0,0.0,1.0); CVector up(0.0,1.0,0.0); m_ArcBall.SetZoom(0.3,eye,up); if(glIsList(ARCBALL)) { glDeleteLists(ARCBALL,2); m_GLList-=2; } m_pGLWidget->CreateArcballList(m_ArcBall, 1.0); m_GLList+=2; } if(m_bResetglSectionHighlight || m_bResetglWing) { if(glIsList(SECTIONHIGHLIGHT)) { glDeleteLists(SECTIONHIGHLIGHT,1); m_GLList-=1; } if(m_iSection>=0) { GLCreateSectionHighlight(); m_bResetglSectionHighlight = false; } } if(m_bResetglWing) { if(glIsList(WINGGEOMETRY)) { glDeleteLists(WINGGEOMETRY,2); m_GLList-=2; } QMiarex *pMiarex = (QMiarex*)s_pMiarex; GLCreateGeom(pMiarex, m_pWing, WINGGEOMETRY); if(glIsList(MESHPANELS)) { glDeleteLists(MESHPANELS,2); m_GLList-=2; } GLCreateMesh(); m_bResetglWing = false; } } void GL3dWingDlg::GLDrawFoils() { int j; Foil *pFoil; glColor3d(MainFrame::s_TextColor.redF(), MainFrame::s_TextColor.greenF(), MainFrame::s_TextColor.blueF()); for(j=0; jm_NSurfaces; j++) { pFoil = m_pWing->m_Surface[j].m_pFoilA; if(pFoil) m_pGLWidget->renderText(m_pWing->m_Surface[j].m_TA.x, m_pWing->m_Surface[j].m_TA.y, m_pWing->m_Surface[j].m_TA.z, pFoil->m_FoilName); } j = m_pWing->m_NSurfaces-1; pFoil = m_pWing->m_Surface[j].m_pFoilB; if(pFoil) m_pGLWidget->renderText(m_pWing->m_Surface[j].m_TB.x, m_pWing->m_Surface[j].m_TB.y, m_pWing->m_Surface[j].m_TB.z, pFoil->m_FoilName); } void GL3dWingDlg::GLInverseMatrix() { //Step 1. Transpose the 3x3 rotation portion of the 4x4 matrix to get the inverse rotation int i,j; for(i=0 ; i<3; i++) { for(j=0; j<3; j++) { MatOut[j][i] = MatIn[i][j]; } } } void GL3dWingDlg::GLRenderView() { QString MassUnit; GetWeightUnit(MassUnit, MainFrame::s_WeightUnit); GLdouble pts[4]; pts[0]= 0.0; pts[1]=0.0; pts[2]=-1.0; pts[3]= m_ClipPlanePos; //x=m_VerticalSplit glClipPlane(GL_CLIP_PLANE1, pts); if(m_ClipPlanePos>4.9999) glDisable(GL_CLIP_PLANE1); else glEnable(GL_CLIP_PLANE1); // Clear the viewport glFlush(); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); { m_pGLWidget->GLSetupLight(m_UFOOffset.y, 1.0); glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glLoadIdentity(); if(m_bCrossPoint && m_bArcball) { glPushMatrix(); { glTranslated(m_UFOOffset.x, m_UFOOffset.y, 0.0); m_ArcBall.RotateCrossPoint(); glRotated(m_ArcBall.angle, m_ArcBall.p.x, m_ArcBall.p.y, m_ArcBall.p.z); glCallList(ARCPOINT); } glPopMatrix(); } if(m_bArcball) { glPushMatrix(); { glTranslated(m_UFOOffset.x, m_UFOOffset.y, 0.0); m_ArcBall.Rotate(); glCallList(ARCBALL); } glPopMatrix(); } glTranslated(m_UFOOffset.x, m_UFOOffset.y, 0.0); m_ArcBall.Rotate(); glScaled(m_glScaled, m_glScaled, m_glScaled); glTranslated(m_glRotCenter.x, m_glRotCenter.y, m_glRotCenter.z); if(s_bAxes) m_pGLWidget->GLDrawAxes(1, W3dPrefsDlg::s_3DAxisColor, W3dPrefsDlg::s_3DAxisStyle, W3dPrefsDlg::s_3DAxisWidth); glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); if(s_bOutline) { glCallList(WINGGEOMETRY+4); } if(m_iSection>=0) { glCallList(SECTIONHIGHLIGHT); } if(GLLightDlg::IsLightOn()) { glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); } else { glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); } if(s_bSurfaces) { glCallList(WINGGEOMETRY); } glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); if(s_bVLMPanels) { if(!s_bSurfaces) glCallList(MESHBACK); glCallList(MESHPANELS); } } if(s_bFoilNames) { GLDrawFoils(); } if(s_bShowMasses) { glColor3d(W3dPrefsDlg::s_MassColor.redF(),W3dPrefsDlg::s_MassColor.greenF(),W3dPrefsDlg::s_MassColor.blueF()); for(int im=0; imm_PointMass.size(); im++) { glPushMatrix(); { glTranslated(m_pWing->m_PointMass[im]->position().x, m_pWing->m_PointMass[im]->position().y, m_pWing->m_PointMass[im]->position().z); glColor3d(W3dPrefsDlg::s_MassColor.redF(), W3dPrefsDlg::s_MassColor.greenF(), W3dPrefsDlg::s_MassColor.blueF()); m_pGLWidget->GLRenderSphere(W3dPrefsDlg::s_MassRadius/m_glScaled); glColor3d(MainFrame::s_TextColor.redF(), MainFrame::s_TextColor.greenF(), MainFrame::s_TextColor.blueF()); m_pGLWidget->renderText( 0.0, 0.0, 0.0 +.02, m_pWing->m_PointMass[im]->tag() +QString(" %1").arg(m_pWing->m_PointMass[im]->mass()*MainFrame::s_kgtoUnit, 7,'g',3) +MassUnit); } glPopMatrix(); } } glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glPopMatrix(); glDisable(GL_CLIP_PLANE1); glFinish(); } bool GL3dWingDlg::InitDialog(Wing *pWing) { QString str; m_iSection = 0; GetAreaUnit(str, MainFrame::s_AreaUnit); m_pctrlAreaUnit1->setText(str); m_pctrlAreaUnit2->setText(str); GetLengthUnit(str, MainFrame::s_LengthUnit); m_pctrlLength1->setText(str); m_pctrlLength2->setText(str); m_pctrlLength3->setText(str); m_pctrlLength4->setText(str); m_pctrlLength5->setText(str); m_pWing = pWing; if(!m_pWing) return false; ComputeGeometry(); m_pctrlWingName->setText(m_pWing->m_WingName); if(m_pWing->m_WingDescription.length()) { m_pctrlWingDescription->setPlainText(m_pWing->m_WingDescription); } else { m_pctrlWingDescription->setPlainText(""); } if(!m_bAcceptName) m_pctrlWingName->setEnabled(false); m_pctrlSymetric->setChecked(m_pWing->m_bSymetric); m_pctrlRightSide->setChecked(m_pWing->m_bSymetric); m_pctrlLeftSide->setEnabled(!m_pWing->m_bSymetric); m_pctrlRightSide->setChecked(m_bRightSide); m_pctrlLeftSide->setChecked(!m_bRightSide); m_pctrlSurfaces->setChecked(s_bSurfaces); m_pctrlOutline->setChecked(s_bOutline); m_pctrlAxes->setChecked(s_bAxes); m_pctrlPanels->setChecked(s_bVLMPanels); m_pctrlLight->setChecked(GLLightDlg::IsLightOn()); m_pctrlFoilNames->setChecked(s_bFoilNames); m_pctrlShowMasses->setChecked(s_bShowMasses); m_pctrlWingColor->SetColor(m_pWing->m_WingColor); m_pWingModel = new QStandardItemModel; m_pWingModel->setRowCount(30);//temporary m_pWingModel->setColumnCount(10); m_pWingModel->setHeaderData(0, Qt::Horizontal, tr("y (")+str+")"); m_pWingModel->setHeaderData(1, Qt::Horizontal, tr("chord (")+str+")"); m_pWingModel->setHeaderData(2, Qt::Horizontal, tr("offset (")+str+")"); m_pWingModel->setHeaderData(3, Qt::Horizontal, QObject::tr("dihedral")); m_pWingModel->setHeaderData(4, Qt::Horizontal, QObject::tr("twist")+QString::fromUtf8("(°)")); m_pWingModel->setHeaderData(5, Qt::Horizontal, QObject::tr("foil")); m_pWingModel->setHeaderData(6, Qt::Horizontal, QObject::tr("X-panels")); m_pWingModel->setHeaderData(7, Qt::Horizontal, QObject::tr("X-dist")); m_pWingModel->setHeaderData(8, Qt::Horizontal, QObject::tr("Y-panels")); m_pWingModel->setHeaderData(9, Qt::Horizontal, QObject::tr("Y-dist")); m_pctrlWingTable->setModel(m_pWingModel); QItemSelectionModel *selectionModel = new QItemSelectionModel(m_pWingModel); m_pctrlWingTable->setSelectionModel(selectionModel); connect(selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnItemClicked(QModelIndex))); m_pWingDelegate = new WingDelegate(this); m_pctrlWingTable->setItemDelegate(m_pWingDelegate); connect(m_pWingDelegate, SIGNAL(closeEditor(QWidget *)), this, SLOT(OnCellChanged(QWidget *))); int *precision = new int[10]; precision[0] = 3; precision[1] = 3; precision[2] = 3; precision[3] = 1; precision[4] = 2; precision[5] = 1; precision[6] = 0; precision[7] = 0; precision[8] = 0; precision[9] = 0; m_pWingDelegate->SetPrecision(precision); m_pWingDelegate->m_pWingSection = &m_pWing->m_WingSection; m_pWingDelegate->m_poaFoil = s_poaFoil; FillDataTable(); SetWingData(); m_pctrlWingTable->selectRow(m_iSection); SetCurrentSection(m_iSection); return true; } void GL3dWingDlg::keyPressEvent(QKeyEvent *event) { // bool bShift = false; // bool bCtrl = false; // if(event->modifiers() & Qt::ShiftModifier) bShift =true; // if(event->modifiers() & Qt::ControlModifier) bCtrl =true; switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus()) OKButton->setFocus(); else accept(); break; } case Qt::Key_Escape: { reject(); return; } case Qt::Key_Delete: { OnDeleteSection(); break; } case Qt::Key_Control: { m_bArcball = true; UpdateView(); break; } default: event->ignore(); } } void GL3dWingDlg::keyReleaseEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Control: { m_bArcball = false; UpdateView(); break; } default: event->ignore(); } } void GL3dWingDlg::MouseDoubleClickEvent(QMouseEvent *event) { QPoint point(event->pos().x(), event->pos().y()); Set3DRotationCenter(point); m_bPickCenter = false; m_pctrlPickCenter->setChecked(false); UpdateView(); } void GL3dWingDlg::MouseMoveEvent(QMouseEvent *event) { QPoint point(event->pos().x(), event->pos().y()); QPoint glPoint(event->pos().x() + m_pGLWidget->geometry().x(), event->pos().y()+m_pGLWidget->geometry().y()); m_MousePos = event->pos(); CVector Real; QPoint Delta(point.x() - m_LastPoint.x(), point.y() - m_LastPoint.y()); m_pGLWidget->ClientToGL(point, Real); // if(!m_pGLWidget->hasFocus()) m_pGLWidget->setFocus(); bool bCtrl = false; if (event->modifiers() & Qt::ControlModifier) bCtrl =true; if (event->buttons() & Qt::LeftButton) { if(bCtrl&& m_pGLWidget->geometry().contains(glPoint)) { //rotate m_ArcBall.Move(point.x(), m_pGLWidget->m_rCltRect.height()-point.y()); UpdateView(); } else if(m_bTrans) { //translate if(m_pGLWidget->geometry().contains(glPoint)) { m_glViewportTrans.x += (GLfloat)(Delta.x()*2.0/m_glScaled/m_pGLWidget->m_rCltRect.width()); m_glViewportTrans.y += (GLfloat)(Delta.y()*2.0/m_glScaled/m_pGLWidget->m_rCltRect.width()); m_glRotCenter.x = MatOut[0][0]*(m_glViewportTrans.x) + MatOut[0][1]*(-m_glViewportTrans.y) + MatOut[0][2]*m_glViewportTrans.z; m_glRotCenter.y = MatOut[1][0]*(m_glViewportTrans.x) + MatOut[1][1]*(-m_glViewportTrans.y) + MatOut[1][2]*m_glViewportTrans.z; m_glRotCenter.z = MatOut[2][0]*(m_glViewportTrans.x) + MatOut[2][1]*(-m_glViewportTrans.y) + MatOut[2][2]*m_glViewportTrans.z; UpdateView(); } } } else if (event->buttons() & Qt::MidButton) { if(m_pWing) { m_ArcBall.Move(point.x(), m_pGLWidget->m_rCltRect.height()-point.y()); UpdateView(); } } m_LastPoint = point; } void GL3dWingDlg::MousePressEvent(QMouseEvent *event) { // the event has been sent by GLWidget, so event is in GL Widget coordinates // but m_3DWingRect is in window client coordinates // the difference is m_pGLWidget->geometry() ! QPoint point(event->pos().x(), event->pos().y()); QPoint glPoint(event->pos().x() + m_pGLWidget->geometry().x(), event->pos().y()+m_pGLWidget->geometry().y()); CVector Real; bool bCtrl = false; if(event->modifiers() & Qt::ControlModifier) bCtrl =true; m_pGLWidget->ClientToGL(point, Real); if(m_pGLWidget->geometry().contains(glPoint)) m_pGLWidget->setFocus(); if (event->buttons() & Qt::MidButton) { m_bArcball = true; m_ArcBall.Start(event->pos().x(), m_pGLWidget->m_rCltRect.height()-event->pos().y()); m_bCrossPoint = true; Set3DRotationCenter(); UpdateView(); } else if (event->buttons() & Qt::LeftButton) { if(m_bPickCenter) { Set3DRotationCenter(point); m_bPickCenter = false; m_pctrlPickCenter->setChecked(false); } else { m_bTrans=true; if(m_pWing && m_pGLWidget->geometry().contains(glPoint)) { m_ArcBall.Start(point.x(), m_pGLWidget->m_rCltRect.height()-point.y()); m_bCrossPoint = true; Set3DRotationCenter(); if (!bCtrl) { m_bTrans = true; m_pGLWidget->setCursor(Qt::ClosedHandCursor); } else { m_bArcball = true; } UpdateView(); } } } m_bPickCenter = false; m_pctrlPickCenter->setChecked(false); m_PointDown = point; m_LastPoint = point; } void GL3dWingDlg::MouseReleaseEvent(QMouseEvent *event) { m_pGLWidget->setCursor(Qt::CrossCursor); m_bTrans = false; m_bDragPoint = false; m_bArcball = false; m_bCrossPoint = false; UpdateView(); // We need to re-calculate the translation vector int i,j; for(i=0; i<4; i++) for(j=0; j<4; j++) MatIn[i][j] = m_ArcBall.ab_quat[i*4+j]; GLInverseMatrix(); m_glViewportTrans.x = (MatOut[0][0]*m_glRotCenter.x + MatOut[0][1]*m_glRotCenter.y + MatOut[0][2]*m_glRotCenter.z); m_glViewportTrans.y = -(MatOut[1][0]*m_glRotCenter.x + MatOut[1][1]*m_glRotCenter.y + MatOut[1][2]*m_glRotCenter.z); m_glViewportTrans.z = (MatOut[2][0]*m_glRotCenter.x + MatOut[2][1]*m_glRotCenter.y + MatOut[2][2]*m_glRotCenter.z); } void GL3dWingDlg::On3DIso() { m_ArcBall.ab_quat[0] = -0.65987748f; m_ArcBall.ab_quat[1] = 0.38526487f; m_ArcBall.ab_quat[2] = -0.64508355f; m_ArcBall.ab_quat[3] = 0.0f; m_ArcBall.ab_quat[4] = -0.75137258f; m_ArcBall.ab_quat[5] = -0.33720365f; m_ArcBall.ab_quat[6] = 0.56721509f; m_ArcBall.ab_quat[7] = 0.0f; m_ArcBall.ab_quat[8] = 0.000f; m_ArcBall.ab_quat[9] = 0.85899049f; m_ArcBall.ab_quat[10] = 0.51199043f; m_ArcBall.ab_quat[11] = 0.0f; m_ArcBall.ab_quat[12] = 0.0f; m_ArcBall.ab_quat[13] = 0.0f; m_ArcBall.ab_quat[14] = 0.0f; m_ArcBall.ab_quat[15] = 1.0f; Set3DRotationCenter(); UpdateView(); } void GL3dWingDlg::On3DTop() { m_ArcBall.SetQuat(sqrt(2.0)/2.0, 0.0, 0.0, -sqrt(2.0)/2.0); Set3DRotationCenter(); UpdateView(); } void GL3dWingDlg::On3DLeft() { m_ArcBall.SetQuat(sqrt(2.0)/2.0, -sqrt(2.0)/2.0, 0.0, 0.0);// rotate by 90� around x Set3DRotationCenter(); UpdateView(); } void GL3dWingDlg::On3DFront() { Quaternion Qt1(sqrt(2.0)/2.0, 0.0, -sqrt(2.0)/2.0, 0.0);// rotate by 90� around y Quaternion Qt2(sqrt(2.0)/2.0, -sqrt(2.0)/2.0, 0.0, 0.0);// rotate by 90� around x m_ArcBall.SetQuat(Qt1 * Qt2); Set3DRotationCenter(); UpdateView(); } void GL3dWingDlg::On3DReset() { m_glViewportTrans.Set(0.0, 0.0, 0.0); m_bPickCenter = false; m_pctrlPickCenter->setChecked(false); SetWingScale(); UpdateView(); } void GL3dWingDlg::On3DPickCenter() { m_bPickCenter = true; m_pctrlPickCenter->setChecked(true); } void GL3dWingDlg::OnAxes() { s_bAxes = m_pctrlAxes->isChecked(); UpdateView(); } void GL3dWingDlg::OnClipPlane(int pos) { double planepos = (double)pos/100.0; m_ClipPlanePos = sinh(planepos) * 0.5; UpdateView(); } void GL3dWingDlg::OnDescriptionChanged() { m_bDescriptionChanged=true; } void GL3dWingDlg::OnCellChanged(QWidget *pWidget) { m_bChanged = true; m_bResetglWing = true; ReadParams(); SetWingData(); UpdateView(); } void GL3dWingDlg::OnDeleteSection() { if(m_iSection <0 || m_iSection>m_pWing->NWingSection()) return; if(m_iSection==0) { QMessageBox::warning(this, tr("Warning"),tr("The first section cannot be deleted")); return; } m_pctrlWingTable->closePersistentEditor(m_pctrlWingTable->currentIndex()); int ny, size; size = m_pWingModel->rowCount(); if(size<=2) return; ny = m_pWing->NYPanels(m_iSection-1) + m_pWing->NYPanels(m_iSection); /* for (k=m_iSection; kTPos(k) = m_pWing->TPos(k+1); m_pWing->TChord(k) = m_pWing->TChord(k+1); m_pWing->TOffset(k) = m_pWing->TOffset(k+1); m_pWing->TTwist(k) = m_pWing->TTwist(k+1); m_pWing->TDihedral(k) = m_pWing->TDihedral(k+1); m_pWing->NXPanels(k) = m_pWing->NXPanels(k+1); m_pWing->NYPanels(k) = m_pWing->NYPanels(k+1); m_pWing->XPanelDist(k) = m_pWing->XPanelDist(k+1); m_pWing->YPanelDist(k) = m_pWing->YPanelDist(k+1); } m_pWing->m_RightFoil.removeAt(m_iSection); m_pWing->m_LeftFoil.removeAt(m_iSection);*/ m_pWing->RemoveWingSection(m_iSection); m_pWing->NYPanels(m_iSection-1) = ny; FillDataTable(); ComputeGeometry(); SetWingData(); m_bChanged = true; m_bResetglWing = true; UpdateView(); } void GL3dWingDlg::OnFoilNames() { s_bFoilNames = m_pctrlFoilNames->isChecked(); UpdateView(); } void GL3dWingDlg::OnShowMasses() { s_bShowMasses = m_pctrlShowMasses->isChecked(); UpdateView(); } void GL3dWingDlg::OnInertia() { InertiaDlg dlg(this); dlg.m_pWing = m_pWing; //save inertia properties QList PtMass; PtMass.clear(); for(int i=0; i< m_pWing->m_PointMass.size(); i++) { PtMass.append(m_pWing->m_PointMass.at(i)); } dlg.InitDialog(); if(dlg.exec() == QDialog::Accepted) { if(dlg.m_bChanged) m_bChanged = true; } else { // restore saved inertia m_pWing->ClearPointMasses(); for(int i=0; i< PtMass.size(); i++) { m_pWing->m_PointMass.append(PtMass.at(i)); } } } void GL3dWingDlg::OnLight() { GLLightDlg::SetLightOn(m_pctrlLight->isChecked()); UpdateView(); } void GL3dWingDlg::OnInsertBefore() { if(m_iSection <0 || m_iSection>m_pWing->NWingSection()) return; if (m_pWing->NWingSection()>=MAXSPANSECTIONS) { QMessageBox::warning(this, tr("Warning"), tr("The maximum number of panels has been reached")); return; } if(m_iSection<=0) { QMessageBox::warning(this, tr("Warning"), tr("No insertion possible before the first section")); return; } int n = m_iSection; m_pWing->InsertSection(m_iSection); m_pWing->YPosition(n) = (m_pWing->YPosition(n+1) + m_pWing->YPosition(n-1)) /2.0; m_pWing->Chord(n) = (m_pWing->Chord(n+1) + m_pWing->Chord(n-1)) /2.0; m_pWing->Offset(n) = (m_pWing->Offset(n+1) + m_pWing->Offset(n-1)) /2.0; m_pWing->Twist(n) = (m_pWing->Twist(n+1) + m_pWing->Twist(n-1)) /2.0; m_pWing->Dihedral(n) = (m_pWing->Dihedral(n+1) + m_pWing->Dihedral(n-1))/2.0; m_pWing->XPanelDist(n) = m_pWing->XPanelDist(n-1); m_pWing->YPanelDist(n) = m_pWing->YPanelDist(n-1); m_pWing->RightFoil(n) = m_pWing->RightFoil(n-1); m_pWing->LeftFoil(n) = m_pWing->LeftFoil(n-1); m_pWing->NXPanels(n) = m_pWing->NXPanels(n-1); int ny = m_pWing->NYPanels(n-1); m_pWing->NYPanels(n) = (int)(ny/2); m_pWing->NYPanels(n-1) = ny-m_pWing->NYPanels(n); if(m_pWing->NYPanels(n)==0) m_pWing->NYPanels(n)++; if(m_pWing->NYPanels(n-1)==0) m_pWing->NYPanels(n-1)++; FillDataTable(); m_pctrlWingTable->closePersistentEditor(m_pctrlWingTable->currentIndex()); ComputeGeometry(); SetWingData(); m_bChanged = true; m_bResetglSectionHighlight = true; m_bResetglWing = true; UpdateView(); } void GL3dWingDlg::OnInsertAfter() { if(m_iSection <0 || m_iSection>=m_pWing->NWingSection()) return; if (m_pWing->NWingSection()>=MAXSPANSECTIONS) { QMessageBox::warning(this, tr("Warning"), tr("The maximum number of panels has been reached")); return; } int n = m_iSection; if(n<0) n=m_pWing->NWingSection(); m_pWing->InsertSection(m_iSection+1); if(nNWingSection()-2) { m_pWing->YPosition(n+1) = (m_pWing->YPosition(n) + m_pWing->YPosition(n+2)) /2.0; m_pWing->Chord(n+1) = (m_pWing->Chord(n) + m_pWing->Chord(n+2)) /2.0; m_pWing->Offset(n+1) = (m_pWing->Offset(n) + m_pWing->Offset(n+2)) /2.0; m_pWing->Twist(n+1) = (m_pWing->Twist(n) + m_pWing->Twist(n+2)) /2.0; } else { m_pWing->YPosition(n+1) = m_pWing->YPosition(n)*1.1; m_pWing->Chord(n+1) = m_pWing->Chord(n)/1.1; m_pWing->Offset(n+1) = m_pWing->Offset(n) + m_pWing->Chord(n) - m_pWing->Chord(n) ; m_pWing->Twist(n+1) = m_pWing->Twist(n); } m_pWing->Dihedral(n+1) = m_pWing->Dihedral(n); m_pWing->NXPanels(n+1) = m_pWing->NXPanels(n); m_pWing->NYPanels(n+1) = m_pWing->NYPanels(n); m_pWing->XPanelDist(n+1) = m_pWing->XPanelDist(n); m_pWing->YPanelDist(n+1) = m_pWing->YPanelDist(n); m_pWing->RightFoil(n+1) = m_pWing->RightFoil(n); m_pWing->LeftFoil(n+1) = m_pWing->LeftFoil(n); int ny = m_pWing->NYPanels(n); m_pWing->NYPanels(n+1) = qMax(1,(int)(ny/2)); m_pWing->NYPanels(n) = qMax(1,ny-m_pWing->NYPanels(n+1)); // m_pWing->m_bVLMAutoMesh = true; FillDataTable(); m_pctrlWingTable->closePersistentEditor(m_pctrlWingTable->currentIndex()); ComputeGeometry(); SetWingData(); m_bChanged = true; m_bResetglWing = true; UpdateView(); } void GL3dWingDlg::OnResetSection() { int n = m_iSection; if((0 < n) && (n < (m_pWing->NWingSection()-1))) { double ratio; ratio = (m_pWing->YPosition(n) - m_pWing->YPosition(n - 1)) / (m_pWing->YPosition(n + 1) - m_pWing->YPosition(n - 1)); m_pWing->Chord (n) = m_pWing->Chord (n-1) + ratio * (m_pWing->Chord (n+1) - m_pWing->Chord (n-1)); m_pWing->Offset (n) = m_pWing->Offset (n-1) + ratio * (m_pWing->Offset (n+1) - m_pWing->Offset (n-1)); m_pWing->Twist (n) = m_pWing->Twist (n-1) + ratio * (m_pWing->Twist (n+1) - m_pWing->Twist (n-1)); // same code here that in OnResetMesh FillDataTable(); SetWingData(); ComputeGeometry(); m_bChanged = true; m_bResetglWing = true; UpdateView(); } } void GL3dWingDlg::OnItemClicked(const QModelIndex &index) { if(index.row()>=m_pWing->NWingSection()) { //the user has filled a cell in the last line if(index.row()setRowCount(m_pWing->NWingSection()+1); FillTableRow(m_pWing->NWingSection()); } } SetCurrentSection(index.row()); UpdateView(); } void GL3dWingDlg::OnOK() { ReadParams(); if(!CheckWing()) return; if(m_pWing->m_bSymetric) { for (int i=0; iNWingSection(); i++) { m_pWing->LeftFoil(i) = m_pWing->RightFoil(i); } } m_pWing->ComputeGeometry(); m_pWing->ComputeBodyAxisInertia(); s_bWindowMaximized= isMaximized(); s_WindowPos = pos(); s_WindowSize = size(); accept(); } void GL3dWingDlg::OnOutline() { s_bOutline = m_pctrlOutline->isChecked(); UpdateView(); } void GL3dWingDlg::OnPanels() { s_bVLMPanels = m_pctrlPanels->isChecked(); UpdateView(); } void GL3dWingDlg::OnResetMesh() { VLMSetAutoMesh(); FillDataTable(); SetWingData(); ComputeGeometry(); m_bChanged = true; m_bResetglWing = true; UpdateView(); } void GL3dWingDlg::OnScaleWing() { WingScaleDlg dlg(this); dlg.InitDialog(m_pWing->m_PlanformSpan, m_pWing->Chord(0), m_pWing->AverageSweep(), m_pWing->Twist(m_pWing->NWingSection()-1)); if(QDialog::Accepted == dlg.exec()) { if (dlg.m_bSpan || dlg.m_bChord || dlg.m_bSweep || dlg.m_bTwist) { if(dlg.m_bSpan) m_pWing->ScaleSpan(dlg.m_NewSpan); if(dlg.m_bChord) m_pWing->ScaleChord(dlg.m_NewChord); if(dlg.m_bSweep) m_pWing->ScaleSweep(dlg.m_NewSweep); if(dlg.m_bTwist) m_pWing->ScaleTwist(dlg.m_NewTwist); } FillDataTable(); m_bChanged = true; m_bResetglWing = true; m_bResetglSectionHighlight = true; ComputeGeometry(); UpdateView(); } } void GL3dWingDlg::OnSide() { m_bRightSide = m_pctrlRightSide->isChecked(); FillDataTable(); m_bChanged = true; m_bResetglSectionHighlight = true; UpdateView(); } void GL3dWingDlg::OnSurfaces() { s_bSurfaces = m_pctrlSurfaces->isChecked(); UpdateView(); } void GL3dWingDlg::OnSymetric() { if(m_pctrlSymetric->isChecked()) { m_pWing->m_bSymetric = true; m_bRightSide = true; m_pctrlLeftSide->setEnabled(false); m_pctrlRightSide->setChecked(true); for(int i=0; iNWingSection(); i++) { m_pWing->LeftFoil(i) = m_pWing->RightFoil(i); } } else { m_pWing->m_bSymetric = false; m_pctrlLeftSide->setEnabled(true); } m_bChanged = true; ComputeGeometry(); m_bResetglWing = true; m_bResetglSectionHighlight = true; UpdateView(); } void GL3dWingDlg::OnWingColor() { if(!m_pWing) return; QColorDialog::ColorDialogOptions dialogOptions = QColorDialog::ShowAlphaChannel; #ifdef Q_WS_MAC #if QT_VERSION >= 0x040700 dialogOptions |= QColorDialog::DontUseNativeDialog; #endif #endif QColor WingColor = QColorDialog::getColor(m_pWing->m_WingColor, this, "Select the wing color", dialogOptions); if(WingColor.isValid()) m_pWing->m_WingColor = WingColor; m_pctrlWingColor->SetColor(m_pWing->m_WingColor); m_bResetglWing = true; UpdateView(); } void GL3dWingDlg::ReadParams() { m_pWing->m_WingName = m_pctrlWingName->text(); QString strange = m_pctrlWingDescription->toPlainText(); if(strange == tr("Wing Description")) strange=""; m_pWing->m_WingDescription = strange; for (int i=0; i< m_pWingModel->rowCount(); i++) { ReadSectionData(i); } //Update Geometry ComputeGeometry(); } void GL3dWingDlg::ReadSectionData(int sel) { if(sel>=m_pWingModel->rowCount()) return; double d; bool bOK; QString strong; QStandardItem *pItem; pItem = m_pWingModel->item(sel,0); strong =pItem->text(); strong.replace(" ",""); d =strong.toDouble(&bOK); if(bOK) m_pWing->YPosition(sel) =d / MainFrame::s_mtoUnit; pItem = m_pWingModel->item(sel,1); strong =pItem->text(); strong.replace(" ",""); d =strong.toDouble(&bOK); if(bOK) m_pWing->Chord(sel) =d / MainFrame::s_mtoUnit; pItem = m_pWingModel->item(sel,2); strong =pItem->text(); strong.replace(" ",""); d =strong.toDouble(&bOK); if(bOK) m_pWing->Offset(sel) =d / MainFrame::s_mtoUnit; pItem = m_pWingModel->item(sel,3); strong =pItem->text(); strong.replace(" ",""); d =strong.toDouble(&bOK); if(bOK) m_pWing->Dihedral(sel) =d; pItem = m_pWingModel->item(sel,4); strong =pItem->text(); strong.replace(" ",""); d =strong.toDouble(&bOK); if(bOK) m_pWing->Twist(sel) =d; pItem = m_pWingModel->item(sel,5); strong =pItem->text(); if(m_pWing->m_bSymetric) { m_pWing->RightFoil(sel) = strong; m_pWing->LeftFoil(sel) = strong; } else { if(m_bRightSide) m_pWing->RightFoil(sel) = strong; else m_pWing->LeftFoil(sel) = strong; } pItem = m_pWingModel->item(sel,6); strong =pItem->text(); strong.replace(" ",""); d =strong.toDouble(&bOK); if(bOK) m_pWing->NXPanels(sel) =(int)qMax(1.0,d); m_pWing->NXPanels(sel) = qMin(m_pWing->NXPanels(sel), MAXCHORDPANELS); pItem = m_pWingModel->item(sel,7); strong =pItem->text(); strong.replace(" ",""); if(strong==tr("Uniform")) m_pWing->XPanelDist(sel) = UNIFORM; else if(strong==tr("Cosine")) m_pWing->XPanelDist(sel) = COSINE; else if(strong==tr("Sine")) m_pWing->XPanelDist(sel) = SINE; else if(strong==tr("-Sine")) m_pWing->XPanelDist(sel) = INVERSESINE; pItem = m_pWingModel->item(sel,8); strong =pItem->text(); strong.replace(" ",""); d =strong.toDouble(&bOK); if(bOK) m_pWing->NYPanels(sel) =(int)qMax(1.0,d); pItem = m_pWingModel->item(sel,9); strong =pItem->text(); strong.replace(" ",""); if(strong==tr("Uniform")) m_pWing->YPanelDist(sel) = UNIFORM; else if(strong==tr("Cosine")) m_pWing->YPanelDist(sel) = COSINE; else if(strong==tr("Sine")) m_pWing->YPanelDist(sel) = SINE; else if(strong==tr("-Sine")) m_pWing->YPanelDist(sel) = INVERSESINE; } void GL3dWingDlg::reject() { if(m_bChanged) { QString strong = tr("Save the changes ?"); int Ans = QMessageBox::question(this, tr("Question"), strong, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel); if (QMessageBox::Yes == Ans) { OnOK(); return; } else if(QMessageBox::Cancel == Ans) return; } s_bWindowMaximized= isMaximized(); s_WindowPos = pos(); s_WindowSize = size(); // reject(); done(QDialog::Rejected); } void GL3dWingDlg::Set3DRotationCenter() { //adjust the new rotation center after a translation or a rotation int i,j; for(i=0; i<4; i++) for(j=0; j<4; j++) MatOut[i][j] = m_ArcBall.ab_quat[i*4+j]; m_glRotCenter.x = MatOut[0][0]*(m_glViewportTrans.x) + MatOut[0][1]*(-m_glViewportTrans.y) + MatOut[0][2]*m_glViewportTrans.z; m_glRotCenter.y = MatOut[1][0]*(m_glViewportTrans.x) + MatOut[1][1]*(-m_glViewportTrans.y) + MatOut[1][2]*m_glViewportTrans.z; m_glRotCenter.z = MatOut[2][0]*(m_glViewportTrans.x) + MatOut[2][1]*(-m_glViewportTrans.y) + MatOut[2][2]*m_glViewportTrans.z; } void GL3dWingDlg::Set3DRotationCenter(QPoint point) { //adjusts the new rotation center after the user has picked a point on the screen //finds the closest panel under the point, //and changes the rotation vector and viewport translation int i, j; CVector N, LA, LB, TA, TB; CVector I, A, B, AA, BB, PP, U; i=-1; m_pGLWidget->ClientToGL(point, B); B.x += -m_UFOOffset.x - m_glViewportTrans.x*m_glScaled; B.y += -m_UFOOffset.y + m_glViewportTrans.y*m_glScaled; B *= 1.0/m_glScaled; A.Set(B.x, B.y, +1.0); B.z = -1.0; for(i=0; i<4; i++) for(j=0; j<4; j++) MatIn[i][j] = m_ArcBall.ab_quat[i*4+j]; //convert screen to model coordinates AA.x = MatIn[0][0]*A.x + MatIn[0][1]*A.y + MatIn[0][2]*A.z; AA.y = MatIn[1][0]*A.x + MatIn[1][1]*A.y + MatIn[1][2]*A.z; AA.z = MatIn[2][0]*A.x + MatIn[2][1]*A.y + MatIn[2][2]*A.z; BB.x = MatIn[0][0]*B.x + MatIn[0][1]*B.y + MatIn[0][2]*B.z; BB.y = MatIn[1][0]*B.x + MatIn[1][1]*B.y + MatIn[1][2]*B.z; BB.z = MatIn[2][0]*B.x + MatIn[2][1]*B.y + MatIn[2][2]*B.z; U.Set(BB.x-AA.x, BB.y-AA.y, BB.z-AA.z); U.Normalize(); bool bIntersect = false; double dist; QMiarex * pMiarex = (QMiarex*)s_pMiarex; for(j=0; jm_NSurfaces; j++) { N = m_pWing->m_Surface[j].Normal; LA = m_pWing->m_Surface[j].m_LA; TA = m_pWing->m_Surface[j].m_TA; LB = m_pWing->m_Surface[j].m_LB; TB = m_pWing->m_Surface[j].m_TB; bIntersect = pMiarex->Intersect(m_pWing->m_Surface[j].m_LA, m_pWing->m_Surface[j].m_LB, m_pWing->m_Surface[j].m_TA, m_pWing->m_Surface[j].m_TB, m_pWing->m_Surface[j].Normal, AA, U, I, dist); if(bIntersect) { PP.Set(I); break; } } if(bIntersect) { // instantaneous visual transition // m_glRotCenter -= PP * m_glScaled; // smooth visual transition GLInverseMatrix(); U.x = (-PP.x -m_glRotCenter.x)/30.0; U.y = (-PP.y -m_glRotCenter.y)/30.0; U.z = (-PP.z -m_glRotCenter.z)/30.0; for(i=0; i<30; i++) { m_glRotCenter +=U; m_glViewportTrans.x = (MatOut[0][0]*m_glRotCenter.x + MatOut[0][1]*m_glRotCenter.y + MatOut[0][2]*m_glRotCenter.z); m_glViewportTrans.y = -(MatOut[1][0]*m_glRotCenter.x + MatOut[1][1]*m_glRotCenter.y + MatOut[1][2]*m_glRotCenter.z); m_glViewportTrans.z= (MatOut[2][0]*m_glRotCenter.x + MatOut[2][1]*m_glRotCenter.y + MatOut[2][2]*m_glRotCenter.z); UpdateView(); } } } void GL3dWingDlg::SetCurrentSection(int section) { m_iSection = section; if(m_iSection <0 || m_iSection>m_pWing->NWingSection()) { m_pctrlInsertAfter->setEnabled(false); m_pctrlInsertBefore->setEnabled(false); m_pctrlDeleteSection->setEnabled(false); } else { m_pctrlInsertAfter->setEnabled(true); m_pctrlInsertBefore->setEnabled(true); m_pctrlDeleteSection->setEnabled(true); QString str; str = tr("Insert after section") +" %1"; str = QString(str).arg(m_iSection+1); m_pctrlInsertAfter->setText(str); str = tr("Insert before section") +" %1"; str = QString(str).arg(m_iSection+1); m_pctrlInsertBefore->setText(str); str = tr("Delete section") +" %1"; str = QString(str).arg(m_iSection+1); m_pctrlDeleteSection->setText(str); } m_bResetglSectionHighlight = true; } void GL3dWingDlg::SetWingScale() { //if(m_bIs3DScaleSet) return; //wing along X axis will take 3/4 of the screen m_glScaled = (GLfloat)(3./4.*2.0/m_pWing->m_PlanformSpan); m_glViewportTrans.x = 0.0; m_glViewportTrans.y = 0.0; m_glViewportTrans.z = 0.0; m_UFOOffset.x = 0.0; m_UFOOffset.y = 0.0; m_ArcBall.GetMatrix(); CVector eye(0.0,0.0,1.0); CVector up(0.0,1.0,0.0); m_ArcBall.SetZoom(0.3,eye,up); Set3DRotationCenter(); } void GL3dWingDlg::SetWingData() { if(!m_pWing) return; //Updates the wing's properties after a change of geometry QString str; str = QString("%1").arg(m_pWing->m_PlanformArea*MainFrame::s_m2toUnit,7,'f',2); m_pctrlWingArea->setText(str); str = QString("%1").arg(m_pWing->m_PlanformSpan*MainFrame::s_mtoUnit,5,'f',2); m_pctrlWingSpan->setText(str); str = QString("%1").arg(m_pWing->m_ProjectedArea*MainFrame::s_m2toUnit,7,'f',2); m_pctrlProjectedArea->setText(str); str = QString("%1").arg(m_pWing->m_ProjectedSpan*MainFrame::s_mtoUnit,5,'f',2); m_pctrlProjectedSpan->setText(str); str = QString("%1").arg(m_pWing->m_GChord*MainFrame::s_mtoUnit,5,'f',2); m_pctrlGeomChord->setText(str); str = QString("%1").arg(m_pWing->m_MAChord*MainFrame::s_mtoUnit,5,'f',2); m_pctrlMAC->setText(str); str = QString("%1").arg(m_pWing->m_yMac*MainFrame::s_mtoUnit,5,'f',2); m_pctrlMACSpanPos->setText(str); str = QString("%1").arg(m_pWing->m_AR,5,'f',2); m_pctrlAspectRatio->setText(str); if(m_pWing->TipChord()>0.0) str = QString("%1").arg(m_pWing->m_TR,0,'f',2); else str = tr("Undefined"); m_pctrlTaperRatio->setText(str); str = QString("%1").arg(m_pWing->AverageSweep(),5,'f',2); m_pctrlSweep->setText(str); str = QString("%1").arg(m_pWing->VLMPanelTotal(true)); m_pctrlVLMPanels->setText(str); str = QString("%1").arg(m_pWing->VLMPanelTotal(false)); m_pctrl3DPanels->setText(str); } void GL3dWingDlg::SetupLayout() { // QDesktopWidget desktop; // QRect r = desktop.screenGeometry(); // setMaximumHeight(r.height()); setMinimumHeight(700); QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::Expanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Expanding); QSizePolicy szPolicyMinimum; szPolicyMinimum.setHorizontalPolicy(QSizePolicy::Minimum); szPolicyMinimum.setVerticalPolicy(QSizePolicy::Minimum); QSizePolicy szPolicyMaximum; szPolicyMaximum.setHorizontalPolicy(QSizePolicy::Maximum); szPolicyMaximum.setVerticalPolicy(QSizePolicy::Maximum); m_pGLWidget = new ThreeDWidget(this); m_pGLWidget->m_iView = GLWINGVIEW; m_ArcBall.m_p3dWidget = m_pGLWidget; /*_____________Start Top Layout Here____________*/ QVBoxLayout *DefLayout = new QVBoxLayout; { QHBoxLayout *SymLayout = new QHBoxLayout; { m_pctrlSymetric = new QCheckBox(tr("Symetric")); m_pctrlRightSide = new QRadioButton(tr("Right Side")); m_pctrlLeftSide = new QRadioButton(tr("Left Side")); m_pctrlInsertBefore = new QPushButton("Insert Before"); m_pctrlInsertAfter = new QPushButton("Insert After"); m_pctrlDeleteSection = new QPushButton("Delete Section"); SymLayout->addWidget(m_pctrlSymetric); SymLayout->addWidget(m_pctrlRightSide); SymLayout->addWidget(m_pctrlLeftSide); SymLayout->addStretch(1); SymLayout->addWidget(m_pctrlInsertBefore); SymLayout->addWidget(m_pctrlInsertAfter); SymLayout->addWidget(m_pctrlDeleteSection); } QHBoxLayout *NameLayout = new QHBoxLayout; { m_pctrlWingName = new QLineEdit(tr("WingName")); m_pctrlWingColor = new ColorButton; NameLayout->addWidget(m_pctrlWingName); NameLayout->addWidget(m_pctrlWingColor); m_pctrlWingTable = new QTableView(this); m_pctrlWingTable->setWindowTitle(QObject::tr("Wing definition")); m_pctrlWingTable->setSelectionMode(QAbstractItemView::SingleSelection); m_pctrlWingTable->setSelectionBehavior(QAbstractItemView::SelectRows); m_pctrlWingTable->setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed | QAbstractItemView::AnyKeyPressed); QHeaderView *HorizontalHeader = m_pctrlWingTable->horizontalHeader(); HorizontalHeader->setStretchLastSection(true); } DefLayout->addLayout(NameLayout); DefLayout->addLayout(SymLayout); DefLayout->addWidget(m_pctrlWingTable,1); } m_pctrlControlsWidget = new QWidget; m_pctrlControlsWidget->setLayout(DefLayout); QVBoxLayout *LeftLayout = new QVBoxLayout; { LeftLayout->addWidget(m_pctrlControlsWidget); LeftLayout->addWidget(m_pGLWidget,1); } QGridLayout *DataLayout = new QGridLayout; { m_pctrlLength1 = new QLabel("mm"); m_pctrlLength2 = new QLabel("mm"); m_pctrlLength3 = new QLabel("mm"); m_pctrlLength4 = new QLabel("mm"); m_pctrlLength5 = new QLabel("mm"); m_pctrlAreaUnit1 = new QLabel("mm2"); m_pctrlAreaUnit2 = new QLabel("mm2"); m_pctrlLength1->setAlignment(Qt::AlignLeft); m_pctrlLength2->setAlignment(Qt::AlignLeft); m_pctrlLength3->setAlignment(Qt::AlignLeft); m_pctrlLength4->setAlignment(Qt::AlignLeft); m_pctrlLength5->setAlignment(Qt::AlignLeft); m_pctrlAreaUnit1->setAlignment(Qt::AlignLeft); m_pctrlAreaUnit2->setAlignment(Qt::AlignLeft); QLabel *lab1 = new QLabel(tr("Wing Span")); QLabel *lab2 = new QLabel(tr("Area")); QLabel *lab3 = new QLabel(tr("Projected Span")); QLabel *lab4 = new QLabel(tr("Projected Area")); QLabel *lab13 = new QLabel(tr("Number of VLM Panels")); QLabel *lab14 = new QLabel(tr("Number of 3D Panels")); lab1->setAlignment(Qt::AlignRight); lab2->setAlignment(Qt::AlignRight); lab3->setAlignment(Qt::AlignRight); lab4->setAlignment(Qt::AlignRight); lab13->setAlignment(Qt::AlignRight); lab14->setAlignment(Qt::AlignRight); DataLayout->addWidget(lab1,1,1); DataLayout->addWidget(lab2,2,1); DataLayout->addWidget(lab3,3,1); DataLayout->addWidget(lab4,4,1); DataLayout->addWidget(lab13,13,1); DataLayout->addWidget(lab14,14,1); m_pctrlWingSpan = new QLabel("2000.00"); m_pctrlWingArea = new QLabel("30.0"); m_pctrlProjectedArea = new QLabel("25.0"); m_pctrlProjectedSpan = new QLabel("1900.0");; m_pctrlVLMPanels = new QLabel("500"); m_pctrl3DPanels = new QLabel("1000"); m_pctrlWingSpan->setAlignment(Qt::AlignRight); m_pctrlWingArea->setAlignment(Qt::AlignRight); m_pctrlProjectedSpan->setAlignment(Qt::AlignRight); m_pctrlProjectedArea->setAlignment(Qt::AlignRight); m_pctrlVLMPanels->setAlignment(Qt::AlignRight); m_pctrl3DPanels->setAlignment(Qt::AlignRight); DataLayout->addWidget(m_pctrlWingSpan, 1,2); DataLayout->addWidget(m_pctrlWingArea, 2,2); DataLayout->addWidget(m_pctrlProjectedSpan, 3,2); DataLayout->addWidget(m_pctrlProjectedArea, 4,2); DataLayout->addWidget(m_pctrlVLMPanels, 13,2); DataLayout->addWidget(m_pctrl3DPanels, 14,2); DataLayout->addWidget(m_pctrlLength1,1,3); DataLayout->addWidget(m_pctrlAreaUnit1,2,3); DataLayout->addWidget(m_pctrlLength2,3,3); DataLayout->addWidget(m_pctrlAreaUnit2,4,3); QLabel *lab20 = new QLabel(tr("Mean Geom. Chord")); QLabel *lab21 = new QLabel(tr("Mean Aero Chord")); QLabel *lab22 = new QLabel(tr("MAC Span Pos")); QLabel *lab23 = new QLabel(tr("Aspect ratio")); QLabel *lab24 = new QLabel(tr("Taper Ratio")); QLabel *lab25 = new QLabel(tr("Root to Tip Sweep")); QLabel *lab26 = new QLabel(tr("Number of Flaps")); lab20->setAlignment(Qt::AlignRight); lab21->setAlignment(Qt::AlignRight); lab22->setAlignment(Qt::AlignRight); lab23->setAlignment(Qt::AlignRight); lab24->setAlignment(Qt::AlignRight); lab25->setAlignment(Qt::AlignRight); lab26->setAlignment(Qt::AlignRight); DataLayout->addWidget(lab20,6,1); DataLayout->addWidget(lab21,7,1); // DataLayout->addWidget(lab22,8,1); DataLayout->addWidget(lab23,9,1); DataLayout->addWidget(lab24,10,1); DataLayout->addWidget(lab25,11,1); DataLayout->addWidget(lab26,12,1); m_pctrlGeomChord = new QLabel("170.0"); m_pctrlMAC = new QLabel("150.0"); m_pctrlMACSpanPos = new QLabel("466.00"); m_pctrlAspectRatio = new QLabel("13.33"); m_pctrlTaperRatio = new QLabel("1.50"); m_pctrlSweep = new QLabel("2.58"); m_pctrlNFlaps = new QLabel("0"); m_pctrlMAC->setAlignment(Qt::AlignRight); m_pctrlGeomChord->setAlignment(Qt::AlignRight); m_pctrlMACSpanPos->setAlignment(Qt::AlignRight); m_pctrlAspectRatio->setAlignment(Qt::AlignRight); m_pctrlTaperRatio->setAlignment(Qt::AlignRight); m_pctrlSweep->setAlignment(Qt::AlignRight); m_pctrlNFlaps->setAlignment(Qt::AlignRight); DataLayout->addWidget(m_pctrlGeomChord, 6,2); DataLayout->addWidget(m_pctrlMAC, 7,2); // DataLayout->addWidget(m_pctrlMACSpanPos, 8,2); DataLayout->addWidget(m_pctrlAspectRatio, 9,2); DataLayout->addWidget(m_pctrlTaperRatio, 10,2); DataLayout->addWidget(m_pctrlSweep, 11,2); DataLayout->addWidget(m_pctrlNFlaps, 12,2); DataLayout->addWidget(m_pctrlLength3, 6, 3); DataLayout->addWidget(m_pctrlLength4, 7, 3); // DataLayout->addWidget(m_pctrlLength5, 8, 3); QLabel *lab30 = new QLabel(QString::fromUtf8("°")); lab30->setAlignment(Qt::AlignLeft); DataLayout->addWidget(lab30, 11, 3); } /*_____________End Top Right Layout Here______________*/ m_pctrlWingDescription = new QTextEdit(); m_pctrlWingDescription->setToolTip(tr("Enter here a short description for the wing")); m_pctrlWingDescription->setSizePolicy(szPolicyMaximum); QLabel *WingDescription = new QLabel(tr("Description:")); /*_____________Start Bottom Right Layout Here_________*/ QVBoxLayout *RightLayout = new QVBoxLayout; { QGridLayout *ThreeDParams = new QGridLayout; { m_pctrlAxes = new QCheckBox(tr("Axes")); m_pctrlLight = new QCheckBox(tr("Light")); m_pctrlSurfaces = new QCheckBox(tr("Surfaces")); m_pctrlOutline = new QCheckBox(tr("Outline")); m_pctrlPanels = new QCheckBox(tr("Panels")); m_pctrlFoilNames = new QCheckBox(tr("Foil Names")); m_pctrlShowMasses = new QCheckBox(tr("Masses")); m_pctrlAxes->setSizePolicy(szPolicyMinimum); m_pctrlLight->setSizePolicy(szPolicyMinimum); m_pctrlSurfaces->setSizePolicy(szPolicyMinimum); m_pctrlOutline->setSizePolicy(szPolicyMinimum); m_pctrlPanels->setSizePolicy(szPolicyMinimum); ThreeDParams->addWidget(m_pctrlAxes, 1,1); ThreeDParams->addWidget(m_pctrlPanels, 1,2); ThreeDParams->addWidget(m_pctrlSurfaces, 2,1); ThreeDParams->addWidget(m_pctrlOutline, 2,2); // ThreeDParams->addWidget(m_pctrlLight, 3,1); ThreeDParams->addWidget(m_pctrlFoilNames, 3,1); ThreeDParams->addWidget(m_pctrlShowMasses, 3,2); } QVBoxLayout *ThreeDView = new QVBoxLayout; { QHBoxLayout *AxisViewLayout = new QHBoxLayout; { m_pctrlX = new QToolButton; m_pctrlY = new QToolButton; m_pctrlZ = new QToolButton; m_pctrlIso = new QToolButton; if(m_pctrlX->iconSize().height()<=48) { m_pctrlX->setIconSize(QSize(32,32)); m_pctrlY->setIconSize(QSize(32,32)); m_pctrlZ->setIconSize(QSize(32,32)); m_pctrlIso->setIconSize(QSize(32,32)); } m_pXView = new QAction(QIcon(":/images/OnXView.png"), tr("X View"), this); m_pYView = new QAction(QIcon(":/images/OnYView.png"), tr("Y View"), this); m_pZView = new QAction(QIcon(":/images/OnZView.png"), tr("Z View"), this); m_pIsoView = new QAction(QIcon(":/images/OnIsoView.png"), tr("Iso View"), this); m_pXView->setCheckable(true); m_pYView->setCheckable(true); m_pZView->setCheckable(true); m_pIsoView->setCheckable(true); m_pctrlX->setDefaultAction(m_pXView); m_pctrlY->setDefaultAction(m_pYView); m_pctrlZ->setDefaultAction(m_pZView); m_pctrlIso->setDefaultAction(m_pIsoView); AxisViewLayout->addWidget(m_pctrlX); AxisViewLayout->addWidget(m_pctrlY); AxisViewLayout->addWidget(m_pctrlZ); AxisViewLayout->addWidget(m_pctrlIso); } QHBoxLayout *ViewResetLayout = new QHBoxLayout; { m_pctrlPickCenter = new QPushButton(tr("Pick Center")); m_pctrlPickCenter->setToolTip(tr("Activate the button, then click on the object to center it in the viewport; alternatively, double click on the object")); m_pctrlReset = new QPushButton(tr("Reset")); m_pctrlPickCenter->setCheckable(true); ViewResetLayout->addWidget(m_pctrlReset); ViewResetLayout->addWidget(m_pctrlPickCenter); } ThreeDView->addLayout(AxisViewLayout); ThreeDView->addLayout(ViewResetLayout); } QHBoxLayout *ThreeDViewControls = new QHBoxLayout; { QLabel *ClipLabel = new QLabel(tr("Clip Plane")); ClipLabel->setSizePolicy(szPolicyMaximum); m_pctrlClipPlanePos = new QSlider(Qt::Horizontal); m_pctrlClipPlanePos->setMinimum(-300); m_pctrlClipPlanePos->setMaximum(300); m_pctrlClipPlanePos->setSliderPosition(0); m_pctrlClipPlanePos->setTickInterval(30); m_pctrlClipPlanePos->setTickPosition(QSlider::TicksBelow); m_pctrlClipPlanePos->setSizePolicy(szPolicyMinimum); ThreeDViewControls->addWidget(ClipLabel); ThreeDViewControls->addWidget(m_pctrlClipPlanePos); } QHBoxLayout *WingModCommands = new QHBoxLayout; { m_pctrlResetMesh = new QPushButton(tr("Reset Mesh")); m_pctrlScaleWing = new QPushButton(tr("Scale Wing")); m_pctrlInertiaButton = new QPushButton(tr("Inertia...")); // m_pctrlSetupLight = new QPushButton("Setup Light"); WingModCommands->addWidget(m_pctrlResetMesh); WingModCommands->addWidget(m_pctrlScaleWing); WingModCommands->addWidget(m_pctrlInertiaButton); // WingModCommands->addWidget(m_pctrlSetupLight); } QHBoxLayout *WingFileCommands = new QHBoxLayout; { m_pImportWingBtn = new QPushButton(tr("Import Wing")); m_pExportWingBtn = new QPushButton(tr("Export Wing")); WingFileCommands->addWidget(m_pImportWingBtn); WingFileCommands->addWidget(m_pExportWingBtn); } QHBoxLayout *CommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("Save and Close")); OKButton->setAutoDefault(true); CancelButton = new QPushButton(tr("Cancel")); CancelButton->setAutoDefault(false); CommandButtons->addWidget(OKButton); CommandButtons->addWidget(CancelButton); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()),this, SLOT(reject())); } QVBoxLayout *All3DControls = new QVBoxLayout; { All3DControls->addStretch(1); All3DControls->addLayout(ThreeDParams); All3DControls->addLayout(ThreeDView); All3DControls->addLayout(ThreeDViewControls); All3DControls->addStretch(1); All3DControls->addLayout(WingModCommands); All3DControls->addLayout(WingFileCommands); All3DControls->addStretch(1); All3DControls->addSpacing(20); All3DControls->addLayout(CommandButtons); } RightLayout->addWidget(WingDescription); RightLayout->addWidget(m_pctrlWingDescription); RightLayout->addStretch(); RightLayout->addLayout(DataLayout); RightLayout->addSpacing(20); RightLayout->addLayout(All3DControls); } QHBoxLayout *MainLayout = new QHBoxLayout; { MainLayout->addLayout(LeftLayout); MainLayout->addLayout(RightLayout); MainLayout->setStretchFactor(LeftLayout, 4); MainLayout->setStretchFactor(RightLayout, 1); } setLayout(MainLayout); } void GL3dWingDlg::showEvent(QShowEvent *event) { move(s_WindowPos); resize(s_WindowSize); if(s_bWindowMaximized) setWindowState(Qt::WindowMaximized); // InitDialog(); // resizeEvent(NULL); m_bChanged = false; m_bResetglWing = true; SetWingScale(); // m_3DWingRect = m_pGLWidget->geometry(); double w = (double)m_pctrlWingTable->width()*.97; int w6 = (int)(w/6.); int w8 = (int)(w/8.); int w12 = (int)(w/12.); m_pctrlWingTable->setColumnWidth(0, w12); m_pctrlWingTable->setColumnWidth(1, w12); m_pctrlWingTable->setColumnWidth(2, w12); m_pctrlWingTable->setColumnWidth(3, w12); m_pctrlWingTable->setColumnWidth(4, w12); m_pctrlWingTable->setColumnWidth(5, w6); m_pctrlWingTable->setColumnWidth(6, w12); m_pctrlWingTable->setColumnWidth(7, w8); m_pctrlWingTable->setColumnWidth(8, w12); m_pctrlWingTable->setColumnWidth(9, w8); UpdateView(); } void GL3dWingDlg::UpdateView() { if(isVisible()) m_pGLWidget->updateGL(); } int GL3dWingDlg::VLMGetPanelTotal() { double MinPanelSize; if(QMiarex::s_MinPanelSize>0.0) MinPanelSize = QMiarex::s_MinPanelSize; else MinPanelSize = m_pWing->m_PlanformSpan/1000.0; int total = 0; for (int i=0; iNWingSection()-1; i++) { //do not create a surface if its length is less than the critical size // if(qAbs(m_pWing->TPos[j]-m_pWing->TPos(j+1))/m_pWing->m_Span >0.001){ if (qAbs(m_pWing->YPosition(i)-m_pWing->YPosition(i+1)) > MinPanelSize) total +=m_pWing->NXPanels(i)*m_pWing->NYPanels(i); } // if(!m_bMiddle) total *=2; if(!m_pWing->m_bIsFin) return total*2; else return total; } bool GL3dWingDlg::VLMSetAutoMesh(int total) { m_bChanged = true; //split (NYTotal) panels on each side proportionnaly to length, and space evenly //Set VLMMATSIZE/NYTotal panels along chord int NYTotal, size; if(!total) { size = (int)(2000/4);//why not ? Too much refinement isn't worthwile NYTotal = 22; } else { size = total; NYTotal = (int)sqrt((float)size); } NYTotal *= 2; // double d1, d2; //spanwise panel densities at i and i+1 for (int i=0; iNWingSection()-1;i++) { // d1 = 5./2./m_pWing->m_Span/m_pWing->m_Span/m_pWing->m_Span *8. * pow(m_pWing->TPos[i], 3) + 0.5; // d2 = 5./2./m_pWing->m_Span/m_pWing->m_Span/m_pWing->m_Span *8. * pow(m_pWing->TPos(i+1),3) + 0.5; // m_pWing->NYPanels(i) = (int) (NYTotal * (0.8*d1+0.2*d2)* (m_pWing->TPos(i+1)-m_pWing->TPos(i))/m_pWing->m_Span); m_pWing->NYPanels(i) = (int)(qAbs(m_pWing->YPosition(i+1) - m_pWing->YPosition(i))* (double)NYTotal/m_pWing->m_PlanformSpan); m_pWing->NXPanels(i) = (int) (size/NYTotal); m_pWing->NXPanels(i) = qMin(m_pWing->NXPanels(i), MAXCHORDPANELS); if(m_pWing->NYPanels(i)==0) m_pWing->NYPanels(i) = 1; if(m_pWing->NXPanels(i)==0) m_pWing->NXPanels(i) = 1; } // if(VLMGetPanelTotal()>VLMMAXMATSIZE/2) // { // QMessageBox::warning(this, tr("Warning"), tr("Too many panels\nReduce the mesh size")); // return false; // } return true; } void GL3dWingDlg::WheelEvent(QWheelEvent *event) { double ZoomFactor; QPoint glPoint(event->pos().x() + m_pGLWidget->geometry().x(), event->pos().y()+m_pGLWidget->geometry().y()); if(m_pGLWidget->geometry().contains(glPoint)) m_pGLWidget->setFocus(); //The mouse button has been wheeled if(!MainFrame::s_bReverseZoom) ZoomFactor = 1./1.06; else ZoomFactor = 1.06; if(m_pGLWidget->geometry().contains(glPoint)) { if(event->delta()>0) m_glScaled *= ZoomFactor; else m_glScaled /= ZoomFactor; } UpdateView(); } void GL3dWingDlg::OnImportWing() { QString path_to_file; path_to_file = QFileDialog::getOpenFileName(0, QString("Open File"), MainFrame::s_LastDirName, QString("XFLR5 Wing file (*.xwimp)")); m_pWing->ImportDefinition(path_to_file); this->InitDialog(m_pWing); this->ReadParams(); this->SetWingData(); m_bChanged = true; m_bResetglWing = true; this->UpdateView(); } void GL3dWingDlg::OnExportWing() { QString path_to_file; path_to_file = QFileDialog::getSaveFileName(0, QString("Save File"), MainFrame::s_LastDirName, QString("XFLR5 Wing file (*.xwimp)")); if (!path_to_file.endsWith(".xwimp")) { path_to_file.append(".xwimp"); } m_pWing->ExportDefinition(path_to_file); } xflr5-6.09-06/src/miarex/LLTAnalysisDlg.h000644 001750 000144 00000013221 12247174407 021310 0ustar00techwinderusers000000 000000 /**************************************************************************** LLTAnalysisDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** *@file * * This file contains the LLTAnalysisDlg class, which is used to perform LLT analysis * */ #ifndef LLTANALYSISDLG_H #define LLTANALYSISDLG_H #include #include #include #include #include #include #include "LLTAnalysis.h" #include "../graph/QGraph.h" #include "../graph/GraphWidget.h" #include "../objects/WPolar.h" #include "../objects/Wing.h" /** *@class LLTAnalysisDlg *@brief The class is used to launch the LLT and to manage the progress of the analysis. It successively : - creates a single instance of the LLTAnalysis object, - initializes the data, - launches the analysis - displays the progress, - stores the results in the OpPoint and Polar objects - updates the display in the Miarex view. The LLTAnalysis class performs the calculation of a signle OpPoint. The loop over a sequence of aoa, Cl, or Re values are performed in the LLAnalysisDlg Class. */ class LLTAnalysisDlg : public QDialog { Q_OBJECT friend class MainFrame; friend class QMiarex; friend class Wing; public: LLTAnalysisDlg(QWidget *pParent); void InitDialog(); void UpdateGraph(int x, double y); private slots: void OnCancelAnalysis(); void OnSkipPoint(); private: void keyPressEvent(QKeyEvent *event); void showEvent(QShowEvent *event); void hideEvent(QHideEvent *event); bool AlphaLoop(); bool QInfLoop(); void ResetCurves(); void SetAlpha(double AlphaMin, double AlphaMax, double AlphaDelta); void SetFileHeader(); void SetupLayout(); void StartAnalysis(); void UpdateView(); void UpdateOutput(QString &strong); void WriteString(QString &strong); static void *s_pMiarex; /**< A static pointer to the unique instance of the QMiarex class. */ static void *s_pMainFrame; /**< A static pointer to the unique instance of the MainFrame class. */ static QPoint s_Position; /**< the position on the client area of he dialog's topleft corner */ double m_AlphaMin; /**< The starting aoa for the analysis of type 1 & 2 polars */ double m_AlphaMax; /**< The ending aoa for the analysis of type 1 & 2 polars */ double m_AlphaDelta; /**< The aoa increment for the analysis of type 1 & 2 polars */ bool m_bCancel; /**< true if the user has cancelled the analysis */ bool m_bError; /**< true if the analysis couldn't converge within the max number of iterations */ bool m_bExit; /**< true if the analysis should be interrupted - either skipped or cancelled */ bool m_bFinished; /**< true if the analysis is completed, false if it is running */ bool m_bInitCalc; /**< true if the data should be initialized prior to the launch of the analysis. If false, the iterations will start with the data from the last calculated point. */ bool m_bSequence; /**< true if the analysis should be performed for a range of input values, false if only a single OpPoint calculation is requested */ bool m_bSkip; /**< true if the user has requested to skip the on-going OpPoint calculation. The analysis will move on to the calculation of the next OpPoint in sequence */ bool m_bWarning; /**< true if one the OpPoints could not be properly interpolated */ int m_Iterations; /**< The number of iterations already performed for the calculation of the current OpPoint */ QGraph m_IterGraph; /**< The instance of the QGraph object where the progress of the iterations are displayed */ int m_IterLim; /**< The maximum number of operations allowed for the calculation of an OpPoint */ QPoint m_LegendPlace; /**< The position where the legend should be diplayed in the output graph */ LLTAnalysis m_LLT; /**< The unique instance of the LLTAnalysis class, called to perform each OpPOint calculation */ Wing *m_pWing; /**< A pointer to the instance of the Wing object for which the analysis is performed */ WPolar *m_pWPolar; /**< A pointer to the instance of the wing WPolar object for which the analysis is performed */ QFile *m_pXFile; /**< A pointer to the instance of the output log file */ double m_ReDelta; /**< The increment value of the velocity for the analysis of type 4 polars */ double m_ReMax; /**< The ending value of the velocity for the analysis of type 4 polars */ double m_ReMin; /**< The starting value of the velocity for the analysis of type 4 polars */ QRect m_ViscRect; /**< The rectangle in the client area where the graph is displayed */ //GUI widget variables QPushButton *m_pctrlCancel, *m_pctrlSkip; GraphWidget * m_pGraphWidget; QTextEdit *m_pctrlTextOutput; }; #endif xflr5-6.09-06/src/miarex/PlaneDlg.h000644 001750 000144 00000010164 12247174407 020213 0ustar00techwinderusers000000 000000 /**************************************************************************** PlaneDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef PLANEDLG_H #define PLANEDLG_H #include #include #include #include #include #include #include #include "../objects/Plane.h" #include "../misc/DoubleEdit.h" /** The class to define and edit planes. SUes */ class PlaneDlg : public QDialog { Q_OBJECT friend class QMiarex; friend class MainFrame; public: PlaneDlg(QWidget *parent); void InitDialog(); private slots: void OnOK(); void OnFin(); void OnStab(); void OnBodyCheck(); void OnDefineWing(); void OnDefineStab(); void OnDefineFin(); void OnDefineBody(); void OnChanged(); void OnDescriptionChanged(); void OnImportWing(); void OnPlaneName(); void OnSymFin(); void OnDoubleFin(); void OnExportWing(); void OnBiplane(); void OnDefineWing2(); void OnImportWing2(); void OnExportWing2(); void OnImportBody(); void OnInertia(); private: void SetupLayout(); void ComputePlane(void); void SetResults(); void ReadParams(); void SetParams(); void keyPressEvent(QKeyEvent *event); void reject(); private: static void * s_pMiarex; /**< A pointer to the QMiarex widget */ static void * s_pMainFrame; /**< A pointer to the mainframe window*/ Plane *m_pPlane; /**< A pointer to the plane which is currently edited in this dialog window */ bool m_bChanged; /**< Set to true whenever the data in the window has been changed */ bool m_bDescriptionChanged; bool m_bAcceptName; private: QLabel *m_pctrlSurf1; QLabel *m_pctrlSurf2; QLabel *m_pctrlSurf3; QLabel *m_pctrlVolume; QLabel *m_pctrlLen1; QLabel *m_pctrlLen2; QLabel *m_pctrlLen3; QLabel *m_pctrlLen4; QLabel *m_pctrlLen5; QLabel *m_pctrlLen6; QLabel *m_pctrlLen7; QLabel *m_pctrlLen8; QLabel *m_pctrlLen9; QLabel *m_pctrlLen10; QLabel *m_pctrlLen11; QLabel *m_pctrlLen12; QLabel *m_pctrlLen13; QLabel *m_pctrlWingSpan; QLabel *m_pctrlWingSurface; QLabel *m_pctrlStabVolume; QLabel *m_pctrlFinSurface; QLabel *m_pctrlStabLeverArm; QLabel *m_pctrlStabSurface; QLabel *m_pctrlPlaneVolume; QLabel *m_pctrlVLMTotalPanels; DoubleEdit *m_pctrlXBody; DoubleEdit *m_pctrlZBody; DoubleEdit *m_pctrlXLEFin; DoubleEdit *m_pctrlYLEFin; DoubleEdit *m_pctrlZLEFin; DoubleEdit *m_pctrlZLEStab; DoubleEdit *m_pctrlXLEStab; DoubleEdit *m_pctrlXLEWing; DoubleEdit *m_pctrlZLEWing; DoubleEdit *m_pctrlXLEWing2; DoubleEdit *m_pctrlZLEWing2; DoubleEdit *m_pctrlStabTilt; DoubleEdit *m_pctrlFinTilt; DoubleEdit *m_pctrlWingTilt; DoubleEdit *m_pctrlWingTilt2; QLineEdit *m_pctrlPlaneName; QTextEdit *m_pctrlPlaneDescription; QCheckBox *m_pctrlBiplane; QCheckBox *m_pctrlBody; QCheckBox *m_pctrlStabCheck; QCheckBox *m_pctrlFinCheck; QCheckBox *m_pctrlDoubleFin; QCheckBox *m_pctrlSymFin; QPushButton *m_pctrlDefineWing; QPushButton *m_pctrlImportWing; QPushButton *m_pctrlExportWing; QPushButton *m_pctrlDefineWing2; QPushButton *m_pctrlImportWing2; QPushButton *m_pctrlExportWing2; QPushButton *m_pctrlDefineFin; QPushButton *m_pctrlVTail; QPushButton *m_pctrlDefineStab; QPushButton *m_pctrlDefineBody; QPushButton *m_pctrlImportBody; QPushButton *m_pctrlPlaneInertia; QPushButton *OKButton; QPushButton *CancelButton; }; #endif // PLANEDLG_H xflr5-6.09-06/src/miarex/GLCreateBodyLists.h000644 001750 000144 00000001032 12247174401 021774 0ustar00techwinderusers000000 000000 /**************************************************************************** GLCreateLists Copyright (C) 2012 Andre Deperrois sail7@xflr5.com All rights reserved *****************************************************************************/ #ifndef GLCREATEBODYLISTS_H #define GLCREATEBODYLISTS_H #include #include "../objects/Body.h" void GLCreateBody3DFlatPanels(int iList, Body *pBody); void GLCreateBody3DSplines(int iList, Body *pBody, int nx, int nh); void GLCreateBodyMesh(int iList, Body *pBody); #endif xflr5-6.09-06/src/miarex/LLTAnalysis.h000644 001750 000144 00000014601 12247174401 020656 0ustar00techwinderusers000000 000000 /**************************************************************************** LLTAnalysis Class Copyright (C) 2011 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** *@file * * This file contains the LLTAnalysisDlg class, which is used to perform LLT analysis * */ // //Class used to perform LLT analysis //GUI-independant // #ifndef LLTANALYSIS_H #define LLTANALYSIS_H #include "../params.h" #include "../globals.h" #include "../objects/Wing.h" #include /** *@class LLTAnalysis *@brief The class is used to perform the LLT analysis of one operating point The analysis is managed from the instance of the LLTAnalysisDlg class. All the data is in International Standard units kg, m, s. */ class LLTAnalysis { friend class MainFrame; friend class QMiarex; friend class LLTAnalysisDlg; public: LLTAnalysis(void *pParent=NULL); private: double AlphaInduced(int k); double Beta(int m, int k); double Eta(int m); void LLTComputeWing(double QInf, double Alpha, QString &ErrorMessage); void LLTInitCl(double &QInf, double const Alpha); void LLTInitialize(double QInf); int LLTIterate(double &QInf, double const Alpha); void LLTSetBending(double QInf); bool LLTSetLinearSolution(double Alpha); double Sigma(int m); void *m_pParent; /**< A void pointer to the instance of the LLTAnalysisDlg class */ Wing * m_pWing; /**< A pointer to the Wing object for which the calculation shall be performed */ WPolar *m_pWPolar; /**< A pointer to the WPolar object for which the calculation shall be performed */ bool m_bCancel; /**< true if the user has cancelled the analysis */ bool m_bConverged; /**< true if the analysis has converged */ bool m_bSkip; /**< true if the user has requested to skip this operating point */ bool m_bWingOut; /**< true if the interpolation of viscous properties falls outside the polar mesh */ double m_Ai[MAXSPANSTATIONS+1]; /**< Induced Angle coefficient at the span stations */ double m_BendingMoment[MAXSPANSTATIONS+1]; /**< bending moment at the span stations */ double m_CDi; /**< The wing's induced drag coefficient */ double m_CDv; /**< The wing's viscous drag coefficient */ double m_Cl[MAXSPANSTATIONS+1]; /**< Local lift coefficient at the span stations */ double m_Chord[MAXSPANSTATIONS+1]; /**< chord at the span stations */ double m_CL; /**< The wing's lift coefficient */ double m_Cm[MAXSPANSTATIONS+1]; /**< Total pitching moment coefficient at the span stations */ double m_CmAirf[MAXSPANSTATIONS+1]; /**< Airfoil part of the pitching moment coefficient at the span stations */ double m_GCm; /**< The wing's total pitching moment */ double m_GRm; /**< The wing's total rolling moment */ double m_GYm; /**< The wing's total yawing moment */ double m_ICd[MAXSPANSTATIONS+1]; /**< Induced Drag coefficient at the span stations */ double m_ICm; /**< The wing's induced pitching moment */ int m_IterLim; /**< Maximum number of iterations in the calculation */ double m_IYm; /**< The wing's induced yawing moment */ QString m_LengthUnit; /**< Name of the user-defined length unit */ double m_Maxa; /**< The max value of the difference of induced angle at any span station between two iterations */ double m_mtoUnit; /**< Conversion factor for the display of results in the user-defined length unit*/ double m_Offset[MAXSPANSTATIONS+1]; /**< offset at the span stations */ double m_PCd[MAXSPANSTATIONS+1]; /**< Viscous Drag coefficient at the span stations */ QList *m_poaPolar; /**< A pointer to the foil polar array */ double m_QInf0; /**< The freestream velocity */ double m_Re[MAXSPANSTATIONS+1]; /**< Reynolds number at the span stations */ double m_SpanPos[MAXSPANSTATIONS+1]; /**< Span position of the span stations */ double m_StripArea[MAXSPANSTATIONS+1]; /** #include #include #include #include #include "UFOTableDelegate.h" #include "../objects/Plane.h" class ManageUFOsDlg : public QDialog { Q_OBJECT friend class QMiarex; friend class MainFrame; public: ManageUFOsDlg(QWidget *pParent); void InitDialog(QString &UFOName); private slots: void OnDelete(); void OnRename(); void OnUFOClicked(QModelIndex index); void OnDoubleClickTable(const QModelIndex &index); void OnDescriptionChanged(); private: void resizeEvent(QResizeEvent *event); void keyPressEvent(QKeyEvent *event); void FillUFOTable(); void FillWingRow(int row); void FillPlaneRow(int row, int n); void SetupLayout(); void SelectUFO(); private: QPushButton *CloseButton; QPushButton *m_pctrlRename, *m_pctrlDelete; QTextEdit *m_pctrlDescription; QTableView *m_pctrlUFOTable; QStandardItemModel *m_pUFOModel; UFOTableDelegate *m_pUFODelegate; Wing *m_pWing; Plane *m_pPlane; static void *s_pMainFrame, *s_pMiarex; }; #endif // MANAGEUFOSDLG_H xflr5-6.09-06/src/miarex/WPolarDlg.cpp000644 001750 000144 00000073203 12247174407 020716 0ustar00techwinderusers000000 000000 /**************************************************************************** WPolarDlg Class Copyright (C) 2009-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../mainframe.h" #include "../globals.h" #include "../objects/WPolar.h" #include "WPolarDlg.h" #include "Miarex.h" #include #include #include #include #include #include void* WPolarDlg::s_pMiarex; WPolar WPolarDlg::s_WPolar; WPolarDlg::WPolarDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Analysis Definition")); m_pPlane = NULL; m_bAutoName = true; m_WingLoad = 0.0; m_UnitType = 1; SetupLayout(); Connect(); } void WPolarDlg::Connect() { connect(m_pctrlWingMethod1, SIGNAL(toggled(bool)), this, SLOT(OnMethod())); connect(m_pctrlWingMethod2, SIGNAL(toggled(bool)), this, SLOT(OnMethod())); connect(m_pctrlWingMethod3, SIGNAL(toggled(bool)), this, SLOT(OnMethod())); connect(m_pctrlUnit1, SIGNAL(toggled(bool)), this, SLOT(OnUnit())); connect(m_pctrlUnit2, SIGNAL(toggled(bool)), this, SLOT(OnUnit())); connect(m_pctrlType1, SIGNAL(toggled(bool)), this, SLOT(OnWPolarType())); connect(m_pctrlType2, SIGNAL(toggled(bool)), this, SLOT(OnWPolarType())); connect(m_pctrlType4, SIGNAL(toggled(bool)), this, SLOT(OnWPolarType())); connect(m_pctrlAutoName, SIGNAL(clicked()), this, SLOT(OnAutoName())); // connect(m_pctrlWakeRollUp, SIGNAL(clicked()), this, SLOT(OnWakeRollUp())); connect(m_pctrlTiltGeom, SIGNAL(clicked()), this, SLOT(OnTiltedGeom())); connect(m_pctrlViscous, SIGNAL(clicked()), this, SLOT(OnViscous())); connect(m_pctrlIgnoreBodyPanels, SIGNAL(clicked()), this, SLOT(OnIgnoreBodyPanels())); connect(m_pctrlGroundEffect, SIGNAL(clicked()), this, SLOT(OnGroundEffect())); connect(m_pctrlPlaneInertia, SIGNAL(clicked()), this, SLOT(OnPlaneInertia())); connect(m_pctrlXCmRef, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlZCmRef, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlDensity, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlViscosity, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlAlpha, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlBeta, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlWeight, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlQInf, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlHeight, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlWPolarName, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlWPolarName, SIGNAL(textEdited ( const QString & )), this, SLOT(OnWPolarName())); connect(m_pctrlArea1, SIGNAL(clicked()),this, SLOT(OnArea())); connect(m_pctrlArea2, SIGNAL(clicked()),this, SLOT(OnArea())); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void WPolarDlg::EnableControls() { switch (s_WPolar.m_WPolarType) { case FIXEDSPEEDPOLAR: { m_pctrlQInf->setEnabled(true); m_pctrlAlpha->setEnabled(false); break; } case FIXEDLIFTPOLAR: { m_pctrlQInf->setEnabled(false); m_pctrlRRe->setText(" "); m_pctrlSRe->setText(" "); m_pctrlAlpha->setEnabled(false); break; } case FIXEDAOAPOLAR: { m_pctrlQInf->setEnabled(false); m_pctrlRRe->setText(" "); m_pctrlSRe->setText(" "); m_pctrlAlpha->setEnabled(true); break; } default: { m_pctrlQInf->setEnabled(true); break; } } m_pctrlViscous->setEnabled(s_WPolar.m_AnalysisMethod==PANELMETHOD); m_pctrlTiltGeom->setEnabled(s_WPolar.m_AnalysisMethod==PANELMETHOD); m_pctrlIgnoreBodyPanels->setEnabled(m_pPlane && m_pPlane->body()); m_pctrlBeta->setEnabled(s_WPolar.m_AnalysisMethod==PANELMETHOD); m_pctrlGroundEffect->setEnabled(s_WPolar.m_AnalysisMethod==PANELMETHOD); m_pctrlHeight->setEnabled(m_pctrlGroundEffect->isChecked() && s_WPolar.m_AnalysisMethod==PANELMETHOD); m_pctrlWeight->setEnabled(!s_WPolar.m_bAutoInertia); m_pctrlXCmRef->setEnabled(!s_WPolar.m_bAutoInertia); m_pctrlZCmRef->setEnabled(!s_WPolar.m_bAutoInertia); } void WPolarDlg::InitDialog(Plane *pPlane, Wing *pWing, WPolar *pWPolar) { QString str, str1; m_pPlane = pPlane; m_pWing = pWing; if(pWPolar) { // m_bAutoName = false; m_pctrlAutoName->setChecked(false); m_pctrlWPolarName->setText(pWPolar->m_PlrName); s_WPolar.DuplicateSpec(pWPolar); } else { // m_bAutoName = true; m_pctrlAutoName->setChecked(true); } if(m_pPlane) { m_pctrlUFOName->setText(m_pPlane->PlaneName()); s_WPolar.m_AnalysisMethod=VLMMETHOD; m_pctrlAnalysisControls->setCurrentIndex(1); s_WPolar.m_UFOName = m_pPlane->PlaneName(); } else if(m_pWing) { m_pctrlUFOName->setText(m_pWing->WingName()); m_pctrlAnalysisControls->setCurrentIndex(0); s_WPolar.m_UFOName = m_pWing->WingName(); } else return; m_pctrlUFOName->setText(s_WPolar.m_UFOName); /* bool bWarning = false; for (i=0; im_NPanel-1; i++) { if(m_pWing->m_NXPanels[i]!= m_pWing->m_NXPanels[i+1]) { QMessageBox::warning(this, tr("Warning"),tr("The number of chordwise VLM-panels across the span is not uniform\n Panel method is disabled")); bWarning = true; break; } }*/ if(m_UnitType==1) m_pctrlUnit1->setChecked(true); else m_pctrlUnit2->setChecked(true); if(s_WPolar.m_WPolarType==FIXEDSPEEDPOLAR) m_pctrlType1->setChecked(true); else if(s_WPolar.m_WPolarType==FIXEDLIFTPOLAR) m_pctrlType2->setChecked(true); else if(s_WPolar.m_WPolarType==FIXEDAOAPOLAR) m_pctrlType4->setChecked(true); OnUnit(); m_pctrlHeight->SetValue(s_WPolar.m_Height*MainFrame::s_mtoUnit); if(s_WPolar.m_bGround) { m_pctrlHeight->setEnabled(true); m_pctrlGroundEffect->setChecked(true); } else { m_pctrlHeight->setEnabled(false); m_pctrlGroundEffect->setChecked(false); } GetSpeedUnit(str, MainFrame::s_SpeedUnit); m_pctrlSpeedUnit->setText(str); SetWingLoad(); GetLengthUnit(str, MainFrame::s_LengthUnit); m_pctrlLengthUnit1->setText(str); m_pctrlLengthUnit2->setText(str); m_pctrlLengthUnit3->setText(str); m_pctrlXCmRef->SetValue(s_WPolar.m_CoG.x*MainFrame::s_mtoUnit); m_pctrlZCmRef->SetValue(s_WPolar.m_CoG.z*MainFrame::s_mtoUnit); GetWeightUnit(str1, MainFrame::s_WeightUnit); m_pctrlWeightUnit->setText(str1); m_pctrlQInf->SetValue(s_WPolar.m_QInf*MainFrame::s_mstoUnit); m_pctrlWeight->SetValue(s_WPolar.m_Mass*MainFrame::s_kgtoUnit); m_pctrlBeta->SetValue(s_WPolar.m_Beta); m_pctrlAlpha->SetValue(s_WPolar.m_ASpec); SetWingLoad(); SetReynolds(); m_pctrlViscous->setChecked(s_WPolar.m_bViscous); m_pctrlTiltGeom->setChecked(s_WPolar.m_bTiltedGeom); m_pctrlIgnoreBodyPanels->setChecked(m_pPlane && m_pPlane->body() && s_WPolar.m_bIgnoreBodyPanels); if(!m_pPlane) s_WPolar.m_bIgnoreBodyPanels=false; // if(s_WPolar.m_bWakeRollUp) m_pctrlWakeRollUp->setChecked(true); OnTiltedGeom(); if(s_WPolar.m_AnalysisMethod==LLTMETHOD) { m_pctrlWingMethod1->setChecked(true); m_pctrlViscous->setChecked(true); m_pctrlViscous->setEnabled(false); } else if(s_WPolar.m_AnalysisMethod==VLMMETHOD) { m_pctrlWingMethod2->setChecked(true); m_pctrlViscous->setEnabled(true); } else if(s_WPolar.m_AnalysisMethod==PANELMETHOD) { if(!m_pPlane) { if(s_WPolar.m_bThinSurfaces) m_pctrlWingMethod2->setChecked(true); else m_pctrlWingMethod3->setChecked(true); } m_pctrlPanelMethod->setChecked(true); m_pctrlViscous->setEnabled(true); } if(m_pPlane) s_WPolar.m_bThinSurfaces = true; m_pctrlPanelMethod->setChecked(m_pPlane); m_pctrlArea1->setChecked(s_WPolar.m_RefAreaType==1); m_pctrlArea2->setChecked(s_WPolar.m_RefAreaType==2); s_WPolar.m_bWakeRollUp = false; SetWPolarName(); EnableControls(); OnMethod(); m_pctrlPlaneInertia->setChecked(s_WPolar.m_bAutoInertia); OnPlaneInertia(); // m_pctrlThinSurfaces->setEnabled(false); // if(s_WPolar.m_bThinSurfaces) m_pctrlThinSurfaces.SetCheck(true); // else m_pctrlThinSurfaces.SetCheck(false); // m_WakeParamsdlg.m_NXWakePanels = m_NXWakePanels; // m_WakeParamsdlg.m_TotalWakeLength = m_TotalWakeLength; // m_WakeParamsdlg.m_WakePanelFactor = m_WakePanelFactor; m_pctrlQInf->setSelection(0,-1); m_pctrlQInf->setFocus(); } void WPolarDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { ReadValues(); SetWPolarName(); OKButton->setFocus(); return; } else { OnOK(); return; } break; } case Qt::Key_Escape: { reject(); } default: event->ignore(); } } void WPolarDlg::OnArea() { if(m_pctrlArea1->isChecked()) { s_WPolar.m_RefAreaType = 1; } else if(m_pctrlArea2->isChecked()) { s_WPolar.m_RefAreaType = 2; } SetWPolarName(); } void WPolarDlg::OnEditingFinished() { ReadValues(); SetReynolds(); SetWPolarName(); } void WPolarDlg::OnAutoName() { m_bAutoName = m_pctrlAutoName->isChecked(); if(m_bAutoName) SetWPolarName(); } void WPolarDlg::OnTiltedGeom() { s_WPolar.m_bTiltedGeom = m_pctrlTiltGeom->isChecked(); SetWPolarName(); EnableControls(); } void WPolarDlg::OnPlaneInertia() { if(m_pctrlPlaneInertia->isChecked()) { if(m_pPlane) { m_pctrlWeight->SetValue(m_pPlane->TotalMass() * MainFrame::s_kgtoUnit); m_pctrlXCmRef->SetValue(m_pPlane->CoG().x * MainFrame::s_mtoUnit); m_pctrlZCmRef->SetValue(m_pPlane->CoG().z * MainFrame::s_mtoUnit); s_WPolar.m_Mass = m_pPlane->TotalMass(); s_WPolar.m_CoG.x = m_pPlane->CoG().x; s_WPolar.m_CoG.z = m_pPlane->CoG().z; } else if(m_pWing) { m_pctrlWeight->SetValue(m_pWing->TotalMass() * MainFrame::s_kgtoUnit); m_pctrlXCmRef->SetValue(m_pWing->m_CoG.x * MainFrame::s_mtoUnit); m_pctrlZCmRef->SetValue(m_pWing->m_CoG.z * MainFrame::s_mtoUnit); s_WPolar.m_Mass = m_pWing->TotalMass(); s_WPolar.m_CoG.x = m_pWing->m_CoG.x; s_WPolar.m_CoG.z = m_pWing->m_CoG.z; } } else { s_WPolar.m_Mass = m_pctrlWeight->Value() / MainFrame::s_kgtoUnit; s_WPolar.m_CoG.x = m_pctrlXCmRef->Value() / MainFrame::s_mtoUnit; s_WPolar.m_CoG.z = m_pctrlZCmRef->Value() / MainFrame::s_mtoUnit; } s_WPolar.m_bAutoInertia = m_pctrlPlaneInertia->isChecked(); SetWPolarName(); EnableControls(); } void WPolarDlg::OnViscous() { s_WPolar.m_bViscous = m_pctrlViscous->isChecked(); SetWPolarName(); EnableControls(); } void WPolarDlg::OnIgnoreBodyPanels() { s_WPolar.m_bIgnoreBodyPanels = m_pctrlIgnoreBodyPanels->isChecked(); SetWPolarName(); EnableControls(); } void WPolarDlg::OnGroundEffect() { s_WPolar.m_bGround = m_pctrlGroundEffect->isChecked(); m_pctrlHeight->setEnabled(s_WPolar.m_bGround); SetWPolarName(); } void WPolarDlg::OnMethod() { if (m_pctrlWingMethod1->isChecked()) { s_WPolar.m_bViscous = true; s_WPolar.m_bThinSurfaces = true; s_WPolar.m_bWakeRollUp = false; s_WPolar.m_bTiltedGeom = false; s_WPolar.m_AnalysisMethod = LLTMETHOD; m_pctrlTiltGeom->setChecked(false); } else if (m_pctrlWingMethod2->isChecked()) { s_WPolar.m_bThinSurfaces = true; s_WPolar.m_AnalysisMethod = PANELMETHOD; } else if (m_pctrlWingMethod3->isChecked()) { s_WPolar.m_bThinSurfaces = false; s_WPolar.m_AnalysisMethod = PANELMETHOD; } EnableControls(); SetWPolarName(); } void WPolarDlg::OnOK() { if(!m_pctrlWPolarName->text().length()) { QMessageBox::warning(this, tr("Warning"),tr("Must enter a name for the polar")); m_pctrlWPolarName->setFocus(); return; } s_WPolar.m_PlrName = m_pctrlWPolarName->text(); if(qAbs(s_WPolar.m_Mass)setFocus(); return; } if(m_pPlane && s_WPolar.m_AnalysisMethod==PANELMETHOD) s_WPolar.m_bThinSurfaces = true; accept(); } void WPolarDlg::OnUnit() { if(m_pctrlUnit1->isChecked()) { m_UnitType = 1; m_pctrlViscosity->SetValue(s_WPolar.m_Viscosity); m_pctrlDensityUnit->setText("kg/m3"); m_pctrlViscosityUnit->setText("m"+QString::fromUtf8("²")+"/s"); } else { m_UnitType = 2; m_pctrlViscosity->SetValue(s_WPolar.m_Viscosity* 10.7182881); m_pctrlDensityUnit->setText("slugs/ft3"); m_pctrlViscosityUnit->setText("ft"+QString::fromUtf8("²")+"/s"); } SetDensity(); } void WPolarDlg::OnWPolarName() { m_bAutoName = false; m_pctrlAutoName->setChecked(false); } void WPolarDlg::OnWPolarType() { if (m_pctrlType1->isChecked()) { s_WPolar.m_WPolarType = FIXEDSPEEDPOLAR; } else if(m_pctrlType2->isChecked()) { s_WPolar.m_WPolarType = FIXEDLIFTPOLAR; } else if(m_pctrlType4->isChecked()) { s_WPolar.m_WPolarType = FIXEDAOAPOLAR; } EnableControls(); SetReynolds(); SetWPolarName(); } void WPolarDlg::ReadValues() { s_WPolar.m_ASpec = m_pctrlAlpha->Value(); s_WPolar.m_Beta = m_pctrlBeta->Value(); s_WPolar.m_Mass = m_pctrlWeight->Value() / MainFrame::s_kgtoUnit; s_WPolar.m_CoG.x = m_pctrlXCmRef->Value() / MainFrame::s_mtoUnit; s_WPolar.m_CoG.z = m_pctrlZCmRef->Value() / MainFrame::s_mtoUnit; s_WPolar.m_QInf = m_pctrlQInf->Value() / MainFrame::s_mstoUnit; s_WPolar.m_Height = m_pctrlHeight->Value() / MainFrame::s_mtoUnit; if(m_pctrlUnit1->isChecked()) { s_WPolar.m_Viscosity = m_pctrlViscosity->Value(); s_WPolar.m_Density = m_pctrlDensity->Value(); } else { s_WPolar.m_Density = m_pctrlDensity->Value() / 0.00194122; s_WPolar.m_Viscosity = m_pctrlViscosity->Value() / 10.7182881; } if(m_pctrlArea1->isChecked()) { s_WPolar.m_RefAreaType = 1; } else if(m_pctrlArea2->isChecked()) { s_WPolar.m_RefAreaType = 2; } SetDensity(); SetWingLoad(); } void WPolarDlg::SetDensity() { int exp, precision; if(m_pctrlUnit1->isChecked()) { exp = (int)log(s_WPolar.m_Density); if(exp>1) precision = 1; else if(exp<-4) precision = 4; else precision = 3-exp; m_pctrlDensity->SetPrecision(precision); m_pctrlDensity->SetValue(s_WPolar.m_Density); } else { exp = (int)log(s_WPolar.m_Density* 0.00194122); if(exp>1) precision = 1; else if(exp<-4) precision = 4; else precision = 3-exp; m_pctrlDensity->SetPrecision(precision); m_pctrlDensity->SetValue(s_WPolar.m_Density* 0.00194122); } } void WPolarDlg::SetupLayout() { QFont SymbolFont("Symbol"); QGroupBox *NameGroup = new QGroupBox(tr("Polar Name")); { QVBoxLayout *NameLayout = new QVBoxLayout; { m_pctrlUFOName = new QLabel(tr("Wing Name")); m_pctrlAutoName = new QCheckBox(tr("Auto Analysis Name")); m_pctrlWPolarName = new QLineEdit(tr("Polar Name")); NameLayout->addWidget(m_pctrlUFOName); NameLayout->addWidget(m_pctrlAutoName); NameLayout->addWidget(m_pctrlWPolarName); } NameGroup->setLayout(NameLayout); } QGroupBox *TypeGroup = new QGroupBox(tr("Polar Type")); { QVBoxLayout *TypeLayout = new QVBoxLayout; { m_pctrlType1 = new QRadioButton(tr("Type 1 (Fixed Speed)")); m_pctrlType2 = new QRadioButton(tr("Type 2 (Fixed Lift)")); m_pctrlType4 = new QRadioButton(tr("Type 4 (Fixed aoa)")); TypeLayout->addWidget(m_pctrlType1); TypeLayout->addWidget(m_pctrlType2); TypeLayout->addWidget(m_pctrlType4); } TypeGroup->setLayout(TypeLayout); } QGroupBox *FlightDataBox = new QGroupBox(tr("Plane and Flight Data")); { QGridLayout *PlaneLayout = new QGridLayout; { QLabel *lab1 = new QLabel(tr("Free Stream Speed =")); QLabel *lab5 = new QLabel("a ="); QLabel *lab6 = new QLabel("b ="); lab5->setFont(SymbolFont); lab6->setFont(SymbolFont); lab1->setAlignment(Qt::AlignRight | Qt::AlignCenter); lab5->setAlignment(Qt::AlignRight | Qt::AlignCenter); lab6->setAlignment(Qt::AlignRight | Qt::AlignCenter); PlaneLayout->addWidget(lab1,1,1); PlaneLayout->addWidget(lab5,2,1); PlaneLayout->addWidget(lab6,3,1); m_pctrlQInf = new DoubleEdit(10.05); m_pctrlQInf->SetMin(0.0); m_pctrlAlpha = new DoubleEdit(1.00,2); m_pctrlBeta = new DoubleEdit(0.00,2); PlaneLayout->addWidget(m_pctrlQInf,1,2); PlaneLayout->addWidget(m_pctrlAlpha,2,2); PlaneLayout->addWidget(m_pctrlBeta,3,2); m_pctrlSpeedUnit = new QLabel("m/s"); QLabel *lab7 = new QLabel(QString::fromUtf8("°")); QLabel *lab8 = new QLabel(QString::fromUtf8("°")); PlaneLayout->addWidget(m_pctrlSpeedUnit ,1,3); PlaneLayout->addWidget(lab7 ,2,3); PlaneLayout->addWidget(lab8 ,3,3); } FlightDataBox->setLayout(PlaneLayout); } QGroupBox *InertiaBox = new QGroupBox(tr("Inertia properties")); { QVBoxLayout *InertiaLayout = new QVBoxLayout; { m_pctrlPlaneInertia = new QCheckBox(tr("Use plane inertia")); m_pctrlPlaneInertia->setToolTip("Activate this checbox for the polar to use dynamically the plane's inertia properties for each analysis"); QGridLayout *InertiaDataLayout = new QGridLayout; { QLabel *lab2 = new QLabel(tr("Plane Mass =")); QLabel *lab3 = new QLabel(tr("X_CoG =")); QLabel *lab4 = new QLabel(tr("Z_CoG =")); lab2->setAlignment(Qt::AlignRight | Qt::AlignCenter); lab3->setAlignment(Qt::AlignRight | Qt::AlignCenter); lab4->setAlignment(Qt::AlignRight | Qt::AlignCenter); InertiaDataLayout->addWidget(lab2,1,1); InertiaDataLayout->addWidget(lab3,2,1); InertiaDataLayout->addWidget(lab4,3,1); m_pctrlWeight = new DoubleEdit(1.234); m_pctrlWeight->SetPrecision(3); m_pctrlWeight->SetMin(0.0); m_pctrlXCmRef = new DoubleEdit(100.00,3); m_pctrlZCmRef = new DoubleEdit(100.00,3); InertiaDataLayout->addWidget(m_pctrlWeight,1,2); InertiaDataLayout->addWidget(m_pctrlXCmRef,2,2); InertiaDataLayout->addWidget(m_pctrlZCmRef,3,2); m_pctrlWeightUnit = new QLabel("kg"); m_pctrlLengthUnit1 = new QLabel("mm"); m_pctrlLengthUnit3 = new QLabel("mm"); InertiaDataLayout->addWidget(m_pctrlWeightUnit ,1,3); InertiaDataLayout->addWidget(m_pctrlLengthUnit1 ,2,3); InertiaDataLayout->addWidget(m_pctrlLengthUnit3 ,3,3); } InertiaLayout->addWidget(m_pctrlPlaneInertia); InertiaLayout->addLayout(InertiaDataLayout); } InertiaBox->setLayout(InertiaLayout); } QGroupBox *FlightGroup = new QGroupBox(tr("Flight Characteristics")); { QVBoxLayout *FlightLayout = new QVBoxLayout; { m_pctrlWingLoad = new QLabel(tr("Wing Loading = 0.033 kg/dm2")); m_pctrlSRe = new QLabel(tr("SRe")); m_pctrlRRe = new QLabel(tr("RRe")); m_pctrlQInfCl = new QLabel(tr("QInfCl")); m_pctrlWingLoad->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlSRe->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlRRe->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlQInfCl->setAlignment(Qt::AlignRight | Qt::AlignCenter); FlightLayout->addWidget(m_pctrlWingLoad); FlightLayout->addWidget(m_pctrlSRe); FlightLayout->addWidget(m_pctrlRRe); FlightLayout->addWidget(m_pctrlQInfCl); } FlightGroup->setLayout(FlightLayout); } //_________________________Main Layout m_pctrlAnalysisControls = new QStackedWidget; { QGroupBox *WingMethodBox = new QGroupBox(tr("Wing analysis methods")); { QVBoxLayout *WingMethodLayout = new QVBoxLayout; { m_pctrlWingMethod1 = new QRadioButton(tr("LLT")); m_pctrlWingMethod2 = new QRadioButton(tr("VLM")); m_pctrlWingMethod3 = new QRadioButton(tr("3D Panels")); WingMethodLayout->addWidget(m_pctrlWingMethod1); WingMethodLayout->addWidget(m_pctrlWingMethod2); WingMethodLayout->addWidget(m_pctrlWingMethod3); } WingMethodBox->setLayout(WingMethodLayout); } m_pctrlPanelMethod = new QRadioButton(tr("Mix 3D Panels/VLM")); QGroupBox *PlaneMethodBox = new QGroupBox("Plane analysis methods"); { QHBoxLayout *PlaneMethodLayout = new QHBoxLayout; { PlaneMethodLayout->addWidget(m_pctrlPanelMethod); PlaneMethodBox->setLayout(PlaneMethodLayout); } } m_pctrlAnalysisControls->addWidget(WingMethodBox); m_pctrlAnalysisControls->addWidget(PlaneMethodBox); } QGroupBox *AeroDataGroupBox = new QGroupBox(tr("Aerodynamic Data")); { QGridLayout *AeroDataLayout = new QGridLayout; { QLabel *lab9 = new QLabel(tr("Unit")); m_pctrlUnit1 = new QRadioButton(tr("International")); m_pctrlUnit2 = new QRadioButton(tr("Imperial")); m_pctrlRho = new QLabel("r ="); m_pctrlDensity = new DoubleEdit(1.225,3); m_pctrlDensityUnit = new QLabel("kg/m3"); m_pctrlNu = new QLabel("n ="); m_pctrlRho->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlNu->setAlignment(Qt::AlignRight | Qt::AlignCenter); m_pctrlViscosity = new DoubleEdit(1.500e-5,3); m_pctrlViscosityUnit = new QLabel("m2/s"); m_pctrlRho->setFont(SymbolFont); m_pctrlNu->setFont(SymbolFont); m_pctrlDensity->SetPrecision(5); m_pctrlViscosity->SetPrecision(3); m_pctrlDensity->SetMin(0.0); m_pctrlViscosity->SetMin(0.0); AeroDataLayout->addWidget(lab9,1,1); AeroDataLayout->addWidget(m_pctrlUnit1,1,2); AeroDataLayout->addWidget(m_pctrlUnit2,1,3); AeroDataLayout->addWidget(m_pctrlRho,2,1); AeroDataLayout->addWidget(m_pctrlDensity,2,2); AeroDataLayout->addWidget(m_pctrlDensityUnit,2,3); AeroDataLayout->addWidget(m_pctrlNu,3,1); AeroDataLayout->addWidget(m_pctrlViscosity,3,2); AeroDataLayout->addWidget(m_pctrlViscosityUnit,3,3); } AeroDataGroupBox->setLayout(AeroDataLayout); } QGroupBox *OptionsGroupBox = new QGroupBox(tr("Options")); { QVBoxLayout *OptionsLayout = new QVBoxLayout; { m_pctrlViscous = new QCheckBox(tr("Viscous")); m_pctrlTiltGeom = new QCheckBox(tr("Tilt. Geom.")); OptionsLayout->addWidget(m_pctrlViscous); OptionsLayout->addWidget(m_pctrlTiltGeom); // OptionsLayout->addWidget(m_pctrlIgnoreBody); m_pctrlIgnoreBodyPanels = new QCheckBox(tr("Ignore Body Panels")); OptionsLayout->addWidget(m_pctrlIgnoreBodyPanels); } OptionsGroupBox->setLayout(OptionsLayout); } QGroupBox *GroundGroupBox = new QGroupBox(tr("Ground Effect")); { QGridLayout * GroundLayout =new QGridLayout; { m_pctrlGroundEffect = new QCheckBox(tr("Ground Effect")); QLabel *lab10 = new QLabel(tr("Height =")); m_pctrlHeight = new DoubleEdit(0.00,2); m_pctrlLengthUnit2 = new QLabel("mm"); GroundLayout->addWidget(m_pctrlGroundEffect,1,1); GroundLayout->addWidget(lab10,2,1); GroundLayout->addWidget(m_pctrlHeight,2,2); GroundLayout->addWidget(m_pctrlLengthUnit2,2,3); } GroundGroupBox->setLayout(GroundLayout); } QGroupBox *AreaBox = new QGroupBox(tr("Reference Area and Span for Aero Coefficients")); { QVBoxLayout *AreaOptions = new QVBoxLayout; { m_pctrlArea1 = new QRadioButton(tr("Wing Planform")); m_pctrlArea2 = new QRadioButton(tr("Wing Planform projected on xy plane")); AreaOptions->addWidget(m_pctrlArea1); AreaOptions->addWidget(m_pctrlArea2); } AreaBox->setLayout(AreaOptions); } QGridLayout *DataLayout = new QGridLayout; { DataLayout->addWidget(NameGroup,1,1); DataLayout->addWidget(FlightDataBox,2,1); DataLayout->addWidget(InertiaBox,3,1); DataLayout->addWidget(m_pctrlAnalysisControls,4,1); DataLayout->addWidget(OptionsGroupBox,5,1); DataLayout->addWidget(TypeGroup, 1,2); DataLayout->addWidget(FlightGroup,2,2); DataLayout->addWidget(AeroDataGroupBox,3,2); DataLayout->addWidget(GroundGroupBox,4,2); DataLayout->addWidget(AreaBox,5,2); } QHBoxLayout *CommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); OKButton->setDefault(true); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); } QVBoxLayout * MainLayout = new QVBoxLayout(this); { MainLayout->addLayout(DataLayout); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); } setLayout(MainLayout); } void WPolarDlg::SetWPolarName() { if(!m_bAutoName) return; QString str, strong; QString WPolarName; QMiarex *pMiarex = (QMiarex*)s_pMiarex; if (s_WPolar.m_WPolarType==FIXEDSPEEDPOLAR) { GetSpeedUnit(str, MainFrame::s_SpeedUnit); WPolarName = QString("T1-%1 ").arg(s_WPolar.m_QInf * MainFrame::s_mstoUnit,0,'f',1); WPolarName += str; } else if(s_WPolar.m_WPolarType==FIXEDLIFTPOLAR) { WPolarName = QString("T2"); } else if(s_WPolar.m_WPolarType==FIXEDAOAPOLAR) { WPolarName = QString(QString::fromUtf8("T4-%1°")).arg(s_WPolar.m_ASpec,0,'f',3); } if(s_WPolar.m_AnalysisMethod==LLTMETHOD) WPolarName += "-LLT"; else if(s_WPolar.m_AnalysisMethod==VLMMETHOD) { if(pMiarex->m_bVLM1) WPolarName += "-VLM1"; else WPolarName += "-VLM2"; } else if(s_WPolar.m_AnalysisMethod==PANELMETHOD) { if(!m_pPlane && !s_WPolar.m_bThinSurfaces) WPolarName += "-Panel"; // if(m_pPlane || !s_WPolar.m_bThinSurfaces) WPolarName += "-Panel"; if(s_WPolar.m_bThinSurfaces) { if(pMiarex->m_bVLM1) WPolarName += "-VLM1"; else WPolarName += "-VLM2"; } } if(!s_WPolar.m_bAutoInertia) { GetWeightUnit(str, MainFrame::s_WeightUnit); strong = QString("-%1").arg(s_WPolar.m_Mass*MainFrame::s_kgtoUnit,0,'f',3); if(s_WPolar.m_WPolarType==FIXEDLIFTPOLAR) WPolarName += strong+str; GetLengthUnit(str, MainFrame::s_LengthUnit); strong = QString("-x%1").arg(s_WPolar.m_CoG.x*MainFrame::s_mtoUnit,0,'f',3); WPolarName += strong + str; if(qAbs(s_WPolar.m_CoG.z)>=.000001) { strong = QString("-z%1").arg(s_WPolar.m_CoG.z*MainFrame::s_mtoUnit,0,'f',3); WPolarName += strong + str; } } // else WPolarName += "-Plane_Inertia"; if(qAbs(s_WPolar.m_Beta) > .001) { strong = QString(QString::fromUtf8("-b%1°")).arg(s_WPolar.m_Beta,0,'f',2); WPolarName += strong; } if(s_WPolar.m_bTiltedGeom) { WPolarName += "-TG"; if(s_WPolar.m_bWakeRollUp) WPolarName += "-W"; } if(!s_WPolar.m_bViscous) { WPolarName += "-Inviscid"; } if(s_WPolar.m_bIgnoreBodyPanels && m_pPlane && m_pPlane->body()) { WPolarName += "-NoBodyPanels"; } if(s_WPolar.m_bGround) { strong = QString("%1").arg(s_WPolar.m_Height,0,'f',2), WPolarName += "-G"+strong; } if(s_WPolar.m_AnalysisMethod!=1 && s_WPolar.m_RefAreaType==PROJECTEDAREA) WPolarName += "-proj_area"; m_pctrlWPolarName->setText(WPolarName); } void WPolarDlg::SetReynolds() { QString strange, str, strUnit; GetSpeedUnit(strUnit, MainFrame::s_SpeedUnit); if(s_WPolar.m_WPolarType ==FIXEDSPEEDPOLAR) { double RRe = m_pWing->Chord(0) * s_WPolar.m_QInf/s_WPolar.m_Viscosity; ReynoldsFormat(str, RRe); strange = tr("Root Re ="); m_pctrlRRe->setText(strange+str); double SRe = m_pWing->TipChord() * s_WPolar.m_QInf/s_WPolar.m_Viscosity; ReynoldsFormat(str, SRe); strange = tr("Tip Re ="); m_pctrlSRe->setText(strange+str); m_pctrlQInfCl->setText(" "); } else if(s_WPolar.m_WPolarType ==FIXEDLIFTPOLAR) { double area; if (s_WPolar.m_RefAreaType==1) area =m_pWing->m_PlanformArea; else area = m_pWing->m_ProjectedArea; double QCl = sqrt(2.* 9.81 /s_WPolar.m_Density* s_WPolar.m_Mass /area) * MainFrame::s_mstoUnit; str = QString("%1").arg(QCl,5,'f',2); str += strUnit; strange = tr("Vinf.sqrt(Cl) ="); m_pctrlQInfCl->setText(strange+str); double RRe = m_pWing->Chord(0) * QCl/s_WPolar.m_Viscosity; ReynoldsFormat(str, RRe); strange = tr("Root Re.sqrt(Cl) ="); m_pctrlRRe->setText(strange+str); double SRe = m_pWing->TipChord() * QCl/s_WPolar.m_Viscosity; ReynoldsFormat(str, SRe); strange = tr("Tip Re.sqrt(Cl) ="); m_pctrlSRe->setText(strange+str); } else if(s_WPolar.m_WPolarType ==FIXEDAOAPOLAR) { m_pctrlQInfCl->setText(" "); m_pctrlRRe->setText(" "); m_pctrlSRe->setText(" "); } } void WPolarDlg::SetWingLoad() { QString str,str1, str2; double area; if (s_WPolar.m_RefAreaType==1) area =m_pWing->m_PlanformArea; else area = m_pWing->m_ProjectedArea; m_WingLoad = s_WPolar.m_Mass/area;//kg/dm2 str = QString("%1").arg(m_WingLoad * MainFrame::s_kgtoUnit / MainFrame::s_m2toUnit,7,'f',3); GetWeightUnit(str1, MainFrame::s_WeightUnit); GetAreaUnit(str2, MainFrame::s_AreaUnit); m_pctrlWingLoad->setText(tr("Wing Loading = ")+str+str1+"/"+str2); } xflr5-6.09-06/src/miarex/LLTAnalysisDlg.cpp000644 001750 000144 00000035326 12247174407 021655 0ustar00techwinderusers000000 000000 /**************************************************************************** LLTAnalysisDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include #include #include #include "LLTAnalysisDlg.h" #include "Miarex.h" #include "../mainframe.h" void *LLTAnalysisDlg::s_pMainFrame; void *LLTAnalysisDlg::s_pMiarex; QPoint LLTAnalysisDlg::s_Position; /** *The public constructor */ LLTAnalysisDlg::LLTAnalysisDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("LLT Analysis")); SetupLayout(); m_IterGraph.SetXTitle(tr("Iterations")); m_IterGraph.SetYTitle(""); m_IterGraph.SetAuto(true); m_IterGraph.SetXMajGrid(true, QColor(120,120,120),2,1); m_IterGraph.SetYMajGrid(true, QColor(120,120,120),2,1); m_IterGraph.SetXMin(0.0); m_IterGraph.SetXMax(50); m_IterGraph.SetYMin(0.0); m_IterGraph.SetYMax(1.0); m_IterGraph.SetType(1); m_IterGraph.SetYTitle("|Da|"); m_IterGraph.SetMargin(10); m_bSkip = false; m_bExit = false; m_bCancel = false; m_bWarning = false; m_bError = false; m_bFinished = false; m_bInitCalc = true; m_bSequence = false; m_Iterations = 0; m_IterLim = 20; m_LegendPlace.rx() = 0; m_LegendPlace.ry() = 0; m_AlphaMin = m_AlphaMax = m_AlphaDelta = 0.; m_ReMin = m_ReMax = m_ReDelta = 0.0; m_pXFile = NULL; m_LLT.m_pParent = this; } /** * Launches a type 1 or 2 analysis. * Loops over the range of specified aoa. * For each successful aoa, stores the data in the WPolar and Operating Point objects. */ bool LLTAnalysisDlg::AlphaLoop() { QString str; QMiarex* pMiarex = (QMiarex*)s_pMiarex; int i,iter; str = tr("Launching analysis....")+"\n\n"; UpdateOutput(str); str = QString(tr("Max iterations = %1")+"\n").arg(m_IterLim); UpdateOutput(str); str = QString(tr("Alpha precision = %1 deg")+"\n").arg(LLTAnalysis::s_CvPrec,0,'f',6); UpdateOutput(str); str = QString(tr("Relaxation factor = %1")+"\n").arg(LLTAnalysis::s_RelaxMax,0,'f',1); UpdateOutput(str); str = QString(tr("Number of stations = %1")+"\n\n").arg(LLTAnalysis::s_NLLTStations); UpdateOutput(str); if(m_AlphaMaxm_QInf); m_IterGraph.ResetLimits(); m_IterGraph.SetXMax((double)m_IterLim); m_IterGraph.SetYMinGrid(false, true, QColor(100,100,100), 2, 1, 4); double Alpha; for (i=0; i<=ia; i++) { Alpha = m_AlphaMin +(double)i * m_AlphaDelta; if(m_bCancel) { str = tr("Analysis cancelled on user request....")+"\n"; UpdateOutput(str); break; } m_IterGraph.SetYMin(0.0); m_IterGraph.SetYMax(0.5); Curve *pCurve = m_IterGraph.GetCurve(0); pCurve->clear(); m_LLT.LLTInitCl(m_pWPolar->m_QInf, Alpha); if(m_bInitCalc) m_LLT.LLTSetLinearSolution(Alpha); str= QString(tr("Calculating Alpha = %1... ")).arg(Alpha,5,'f',2); UpdateOutput(str); iter = m_LLT.LLTIterate(m_pWPolar->m_QInf, Alpha); if (m_bSkip) { if(m_pWPolar->m_WPolarType!=FIXEDAOAPOLAR) str = QString(tr("Alpha = %1, skipped after %2 iterations ")+"\n").arg(Alpha, 6,'f',2).arg(iter); else str = QString(tr("QInf = %1 skipped after %2 iterations ")+"\n" ).arg(m_pWPolar->m_QInf, 8,'f',2).arg(iter); UpdateOutput(str); m_bSkip = false; m_bInitCalc = true; } else if (iter==-1 && !m_bCancel) { str= QString(tr(" ...negative Lift... Aborting")+"\n"); m_bError = true; m_bInitCalc = true; UpdateOutput(str); } else if (iterm_QInf, Alpha, str);// generates wing results, UpdateOutput(str); if (m_LLT.m_bWingOut) m_bWarning = true; pMiarex->AddWOpp(m_pWPolar->m_QInf, Alpha, m_LLT.m_bWingOut);// Adds WOpp point and adds result to polar if(pMiarex->m_iView==WPOLARVIEW) { pMiarex->CreateWPolarCurves(); pMiarex->UpdateView(); } m_bInitCalc = false; } else { if (m_LLT.m_bWingOut) m_bWarning = true; m_bError = true; str= QString(tr(" ...unconverged after %2 iterations")+"\n").arg(iter); UpdateOutput(str); m_bInitCalc = true; } qApp->processEvents(); } return true; } /** * Launches a type 4 analysis. * Loops over the range of specified velocities. * For each successful aoa, stores the data in the WPolar and Operating Point objects. */ bool LLTAnalysisDlg::QInfLoop() { //Alpha stands for QInf... int i,iter; QString str; QMiarex* pMiarex = (QMiarex*)s_pMiarex; Curve *pCurve = m_IterGraph.GetCurve(0); str = tr("Launching analysis....")+"\n\n"; UpdateOutput(str); str = QString(tr("Max iterations = %1")+"\n").arg(m_IterLim); UpdateOutput(str); str = QString(tr("Alpha precision = %1 deg")+"\n").arg(LLTAnalysis::s_CvPrec,0,'f',6); UpdateOutput(str); str = QString(tr("Relaxation factor = %1")+"\n").arg(LLTAnalysis::s_RelaxMax,0,'f',1); UpdateOutput(str); str = QString(tr("Number of stations = %1")+"\n\n").arg(LLTAnalysis::s_NLLTStations); UpdateOutput(str); if(m_AlphaMaxclear(); if(m_bInitCalc) m_LLT.LLTSetLinearSolution(m_pWPolar->m_ASpec); m_LLT.LLTInitCl(QInf, m_pWPolar->m_ASpec); str = QString(tr("Calculating QInf = %1... ")).arg(QInf,6,'f',2); UpdateOutput(str); iter = m_LLT.LLTIterate(QInf, m_pWPolar->m_ASpec); if(iter<0) { //unconverged m_bError = true; m_bWarning = true; str = QString("\n"); UpdateOutput(str); m_bInitCalc = true; } else if (m_bSkip) { if(m_pWPolar->m_WPolarType!=FIXEDAOAPOLAR) str = QString(tr("Alpha = %1, skipped after %2 iterations ")+"\n").arg(m_pWPolar->m_ASpec, 6,'f',2).arg(iter); else str = QString(tr("QInf = %1 skipped after %2 iterations ")+"\n" ).arg(QInf, 8,'f',2).arg(iter); UpdateOutput(str); m_bSkip = false; m_bInitCalc = true; } else if (iterm_ASpec,str);// generates wing results, UpdateOutput(str); if (m_LLT.m_bWingOut) m_bWarning = true; pMiarex->AddWOpp(QInf, m_pWPolar->m_ASpec, m_LLT.m_bWingOut);// Adds WOpp point and adds result to polar if(pMiarex->m_iView==WPOLARVIEW) { pMiarex->CreateWPolarCurves(); pMiarex->UpdateView(); } /* if(m_LLT.m_bWingOut) { str = QString("\n"); UpdateOutput(str); }*/ m_bInitCalc = false; } else { if (m_LLT.m_bWingOut) m_bWarning = true; m_bError = true; str = QString(tr(" ...unconverged after %1 iterations")+"\n").arg(iter); UpdateOutput(str); m_bInitCalc = true; } qApp->processEvents(); } return true; } /** *Initializes the dialog and its associated data. */ void LLTAnalysisDlg::InitDialog() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QString FileName = QDir::tempPath() + "/XFLR5.log"; m_pXFile = new QFile(FileName); if (!m_pXFile->open(QIODevice::WriteOnly | QIODevice::Text)) m_pXFile = NULL; SetFileHeader(); m_Iterations = 0; QString str; m_IterGraph.AddCurve(); m_IterGraph.AddCurve(); str = "|Da|"; m_IterGraph.GetCurve(0)->SetTitle(str); m_IterGraph.SetAutoX(true); m_IterGraph.SetXMin(0.0); m_IterGraph.SetXMax((double)m_IterLim); m_IterGraph.SetX0(0.0); m_IterGraph.SetXUnit((int)(m_IterLim/10.0)); m_IterGraph.SetAutoY(true); m_IterGraph.SetY0(0.0); m_IterGraph.SetYMin(0.0); m_IterGraph.SetYMax(1.0); m_IterGraph.SetMargin(40); if(pMainFrame) m_IterGraph.CopySettings(&pMainFrame->m_RefGraph,false); m_LLT.m_IterLim = m_IterLim; } /** Overrides and handles the keyPressEvent sent by Qt */ void LLTAnalysisDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Escape: { OnCancelAnalysis(); event->accept(); return; } default: event->ignore(); } } /** The user has requested the cancellation of the analysis*/ void LLTAnalysisDlg::OnCancelAnalysis() { if(m_pXFile->isOpen()) m_pXFile->close(); m_bSkip = true; m_bExit = true; m_bCancel = true; if(m_bFinished) done(1); } /** The user has requested that the calculation for the current aoa be skipped. *The analysis will continue for the next aoa if anay. */ void LLTAnalysisDlg::OnSkipPoint() { m_bSkip = true; } /** *Clears the content of the graph's curve prior to the start of the calculation of the next operating point. */ void LLTAnalysisDlg::ResetCurves() { Curve*pCurve; pCurve = m_IterGraph.GetCurve(0); if(pCurve) pCurve->clear(); pCurve = m_IterGraph.GetCurve(1); if(pCurve) pCurve->clear(); } /** * Copies the value of the input parameters to the member variables */ void LLTAnalysisDlg::SetAlpha(double AlphaMin, double AlphaMax, double DeltaAlpha) { m_AlphaMin = AlphaMin; m_AlphaMax = AlphaMax; m_AlphaDelta = DeltaAlpha; } /** * Initializes the header of the log file */ void LLTAnalysisDlg::SetFileHeader() { QMiarex *pMiarex = (QMiarex*)s_pMiarex; QTextStream out(m_pXFile); out << "\n"; out << MainFrame::versionName(); out << "\n"; out << m_pWing->m_WingName; out << "\n"; if(pMiarex && pMiarex->m_pCurWPolar) { // out << pMiarex->m_pCurWPolar->m_WPlrName; // out << "\n"; } QDateTime dt = QDateTime::currentDateTime(); QString str = dt.toString("dd.MM.yyyy hh:mm:ss"); out << str; out << "\n___________________________________\n\n"; } /** * Initializes the interface of the dialog box */ void LLTAnalysisDlg::SetupLayout() { QDesktopWidget desktop; QRect r = desktop.geometry(); // setMinimumHeight(r.height()*2/3); setMinimumWidth(r.width()/3); m_pctrlTextOutput = new QTextEdit; m_pctrlTextOutput->setFontFamily("Courier"); m_pctrlTextOutput->setReadOnly(true); m_pctrlTextOutput->setLineWrapMode(QTextEdit::NoWrap); m_pctrlTextOutput->setWordWrapMode(QTextOption::NoWrap); m_pGraphWidget = new GraphWidget; m_pGraphWidget->setMinimumHeight(r.height()/3); // m_pGraphWidget->setMinimumWidth(r.width()/4); m_pGraphWidget->m_pGraph = &m_IterGraph; m_pctrlSkip = new QPushButton(tr("Skip")); m_pctrlCancel = new QPushButton(tr("Cancel")); connect(m_pctrlSkip, SIGNAL(clicked()), this, SLOT(OnSkipPoint())); connect(m_pctrlCancel, SIGNAL(clicked()), this, SLOT(OnCancelAnalysis())); QHBoxLayout *buttonsLayout = new QHBoxLayout; { buttonsLayout->addStretch(1); buttonsLayout->addWidget(m_pctrlSkip); buttonsLayout->addStretch(1); buttonsLayout->addWidget(m_pctrlCancel); buttonsLayout->addStretch(1); } QVBoxLayout *mainLayout = new QVBoxLayout; { mainLayout->addWidget(m_pctrlTextOutput); mainLayout->addWidget(m_pGraphWidget,2); mainLayout->addLayout(buttonsLayout); } setLayout(mainLayout); } /** * Launches the analysis. * At this stage, the dialogbox has been setup and initialized. * The LLTAnalysis object has been created and the input data has been loaded. * Depending on the type of polar, the method launches either a loop over aoa or velocity values. */ void LLTAnalysisDlg::StartAnalysis() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; //all set to launch the analysis if(!m_pWPolar || !m_pWing) return; m_pctrlCancel->setText(tr("Cancel")); m_bSkip = false; m_bExit = false; m_bCancel = false; m_bWarning = false; m_bError = false; m_bFinished = false; m_pctrlTextOutput->clear(); m_LLT.m_poaPolar = &pMainFrame->s_oaPolar; m_LLT.m_pWing = m_pWing; m_LLT.m_pWPolar = m_pWPolar; m_LLT.LLTInitialize(m_pWPolar->m_QInf); if (m_pWPolar->m_WPolarType!=FIXEDAOAPOLAR) { AlphaLoop() ; } else { QInfLoop(); } m_bFinished = true; QString strange = "\n_________\n"+tr("Analysis completed"); if(m_bWarning) strange += tr(" ...some points are outside the flight envelope"); else if(m_bError) strange += tr(" ...some points are unconverged"); strange+= "\n"; UpdateOutput(strange); m_pctrlCancel->setText(tr("Close")); m_pctrlSkip->setEnabled(false); m_bSkip = false; m_bExit = false; } /** * Updates the graph widget. Called after each iteration of the LLTAnalysis. * Time consuming, but it's necessary to provide the user with visual feedback on the progress of the analysis */ void LLTAnalysisDlg::UpdateView() { m_pGraphWidget->update(); repaint(); } /** * Updates the text output in the dialog box and the log file. *@param strong the text message to append to the output widget and to the log file. */ void LLTAnalysisDlg::UpdateOutput(QString &strong) { m_pctrlTextOutput->insertPlainText(strong); m_pctrlTextOutput->ensureCursorVisible(); WriteString(strong); } /** * Appends a string to the log file *@param strong the text message to append to the log file. */ void LLTAnalysisDlg::WriteString(QString &strong) { if(!m_pXFile) return; if(!m_pXFile->isOpen()) return; QTextStream ds(m_pXFile); ds << strong; } /** * Appends a point to the curve in the graph widget * @param x the x-value of the point to be appended * @param x the y-value of the point to be appended */ void LLTAnalysisDlg::UpdateGraph(int x, double y) { Curve *pCurve = m_IterGraph.GetCurve(0); pCurve->AppendPoint((double)x,y); UpdateView(); } void LLTAnalysisDlg::showEvent(QShowEvent *event) { move(s_Position); } void LLTAnalysisDlg::hideEvent(QHideEvent *event) { s_Position = pos(); } xflr5-6.09-06/src/miarex/WingDelegate.h000644 001750 000144 00000003634 12247174401 021062 0ustar00techwinderusers000000 000000 /**************************************************************************** WingDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef WINGDELEGATE_H #define WINGDELEGATE_H #include #include #include "../misc/DoubleEdit.h" #include "../objects/WingSection.h" class WingDelegate : public QItemDelegate { Q_OBJECT friend class WingDlg; friend class GL3dWingDlg; public: WingDelegate(QObject *parent = 0); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void SetPrecision(int*PrecisionTable); private: void *m_pWingDlg; int *m_Precision; ///table of float precisions for each column QList *m_poaFoil; QList *m_pWingSection; }; #endif // QWingDelegate_H xflr5-6.09-06/src/miarex/ImportObjectDlg.h000644 001750 000144 00000002650 12247174407 021556 0ustar00techwinderusers000000 000000 /**************************************************************************** ImportWingDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef IMPORTWINGDLG_H #define IMPORTWINGDLG_H #include #include #include class ImportObjectDlg : public QDialog { Q_OBJECT friend class PlaneDlg; public: ImportObjectDlg(QWidget *pParent); private slots: void OnOK(); private: void SetupLayout(); void InitDialog(bool bWing=true); void OnSelChangeList(QListWidgetItem *pItem); QLabel *m_pctrlQuestion; QListWidget *m_pctrlNameList; QString m_ObjectName; bool m_bWing; bool m_bBody; }; #endif // IMPORTWINGDLG_H xflr5-6.09-06/src/miarex/WAdvancedDlg.h000644 001750 000144 00000004575 12247261452 021016 0ustar00techwinderusers000000 000000 /**************************************************************************** WAdvancedDlg Class Copyright (C) 2009-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef WADVANCEDDLG_H #define WADVANCEDDLG_H #include #include #include #include #include #include "../misc/DoubleEdit.h" #include "../misc/IntEdit.h" class WAdvancedDlg : public QDialog { Q_OBJECT friend class QMiarex; friend class MainFrame; public: WAdvancedDlg(QWidget *pParent); void InitDialog(); private slots: void OnOK(); void OnResetDefaults(); private: void keyPressEvent(QKeyEvent *event); void ReadParams(); void SetParams(); void SetupLayout(); QLabel *m_pctrlAStat, *m_pctrlLength, *m_pctrlLength2; QPushButton *OKButton, *CancelButton; QCheckBox *m_pctrlLogFile; QCheckBox *m_pctrlResetWake; QCheckBox *m_pctrlKeepOutOpps; QRadioButton *m_pctrlDirichlet, *m_pCtrlNeumann; QRadioButton *m_pctrlVLM1, *m_pctrlVLM2; DoubleEdit *m_pctrlInterNodes; DoubleEdit *m_pctrlRelax; DoubleEdit *m_pctrlAlphaPrec; DoubleEdit *m_pctrlMinPanelSize; IntEdit *m_pctrlNStation; IntEdit *m_pctrlIterMax; DoubleEdit *m_pctrlMaxWakeIter; DoubleEdit *m_pctrlCoreSize; DoubleEdit *m_pctrlVortexPos; DoubleEdit *m_pctrlControlPos; bool m_bLogFile; bool m_bDirichlet; bool m_bTrefftz; bool m_bKeepOutOpps; bool m_bResetWake; bool m_bVLM1; int m_Iter; int m_NStation; int m_WakeInterNodes; int m_MaxWakeIter; int m_InducedDragPoint; double m_ControlPos, m_VortexPos; double m_Relax, m_AlphaPrec; double m_CoreSize; double m_MinPanelSize; }; #endif // WADVANCEDDLG_H xflr5-6.09-06/src/miarex/LLTAnalysis.cpp000644 001750 000144 00000035307 12247174402 021220 0ustar00techwinderusers000000 000000 /**************************************************************************** LLTAnalysis Class Copyright (C) 2011 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include "Miarex.h" #include "../mainframe.h" #include "LLTAnalysis.h" #include "LLTAnalysisDlg.h" #include int LLTAnalysis::s_NLLTStations = 0; double LLTAnalysis::s_RelaxMax = 0.0; double LLTAnalysis::s_CvPrec = 0.0; LLTAnalysis::LLTAnalysis(void *pParent) { m_pParent = pParent; m_pWing = NULL; m_pWPolar = NULL; m_poaPolar = NULL; m_bSkip = false; m_bCancel = false; m_bConverged = false; m_bWingOut = false; m_IterLim = 0; memset(m_Chord, 0, sizeof(m_Chord)); memset(m_Offset, 0, sizeof(m_Offset)); memset(m_Twist, 0, sizeof(m_Twist)); memset(m_SpanPos, 0, sizeof(m_SpanPos)); memset(m_StripArea, 0, sizeof(m_StripArea)); memset(m_Re, 0, sizeof(m_Re)); memset(m_Cl, 0, sizeof(m_Cl)); memset(m_Ai, 0, sizeof(m_Ai)); memset(m_ICd, 0, sizeof(m_ICd)); memset(m_PCd, 0, sizeof(m_PCd)); memset(m_Cm, 0, sizeof(m_Cm)); memset(m_CmAirf, 0, sizeof(m_CmAirf)); memset(m_XCPSpanRel, 0, sizeof(m_XCPSpanRel)); memset(m_XCPSpanAbs, 0, sizeof(m_XCPSpanAbs)); memset(m_BendingMoment, 0, sizeof(m_BendingMoment)); memset(m_XTrTop, 0, sizeof(m_XCPSpanAbs)); memset(m_XTrBot, 0, sizeof(m_BendingMoment)); m_LengthUnit.clear(); m_mtoUnit = 0.0; m_QInf0 = 0.0; m_Maxa = 0.0; m_CL = 0.0; m_CDi = 0.0; m_CDv = 0.0; m_VYm = m_IYm = m_GYm = 0.0; m_VCm = m_ICm = m_GCm = 0.0; m_GRm = 0.0; m_CP.Set(0.0,0.0,0.0); } void LLTAnalysis::LLTInitCl(double &QInf, double const Alpha) { //Initializes the Reynolds numbers and lift coefficients for the initial iteration in LLT Foil *pFoil0 = NULL; Foil *pFoil1 = NULL; double yob, tau; int k; bool bOutRe, bError; for (k=1; kGetFoils(&pFoil0, &pFoil1, yob*m_pWing->m_PlanformSpan/2.0, tau); m_Re[k] = m_Chord[k] * QInf /m_pWPolar->m_Viscosity; m_Cl[k] = GetCl(pFoil0, pFoil1, m_Re[k], Alpha + m_Ai[k] + m_Twist[k], tau, bOutRe, bError); } if(m_pWPolar->m_WPolarType==FIXEDLIFTPOLAR) { double Lift=0.0;// required for Type 2 for (k=1; km_PlanformSpan; } if(Lift<=0.0) return; QInf = m_QInf0 / sqrt(Lift); for (k=1; km_Viscosity; } } } double LLTAnalysis::Eta(int m) { //Auxiliary calculation of the Eta factor in LLT return PI/2.0/(double)m_pWing->m_NStation * sin((double)m*PI/(double)m_pWing->m_NStation) ; } void LLTAnalysis::LLTComputeWing(double QInf, double Alpha, QString &ErrorMessage) { Foil* pFoil0 = NULL; Foil* pFoil1 = NULL; int m; QString strange; double yob, tau, c4, arad, zpos; yob = tau = c4 = arad = zpos = 0.0; double Integral0 = 0.0; double Integral1 = 0.0; double Integral2 = 0.0; double Integral3 = 0.0; double InducedDrag = 0.0; double ViscousDrag = 0.0; double InducedYawingMoment = 0.0; double ViscousYawingMoment = 0.0; double PitchingMoment = 0.0; double VCm = 0.0; double ICm = 0.0; double eta, sigma; double Cm0; double ViscCm[MAXSPANSTATIONS+1], InducedCm[MAXSPANSTATIONS+1]; bool bOutRe, bError; bool bPointOutRe, bPointOutAlpha; m_bWingOut = false; ErrorMessage.clear(); for (m=1; mGetFoils(&pFoil0, &pFoil1, yob*m_pWing->m_PlanformSpan/2.0, tau); m_Cl[m] = GetCl(pFoil0, pFoil1, m_Re[m], Alpha+m_Ai[m]+m_Twist[m], tau, bOutRe, bError); if(bOutRe) bPointOutRe = true; if(bError) bPointOutAlpha = true; m_PCd[m] = GetCd(pFoil0, pFoil1, m_Re[m], Alpha+m_Ai[m]+m_Twist[m], tau, m_pWing->m_AR, bOutRe, bError); if(bOutRe) bPointOutRe = true; if(bError) bPointOutAlpha = true; m_ICd[m] = -m_Cl[m] * (m_Ai[m]* PI/180.0); m_XTrTop[m] = GetXTr(pFoil0, pFoil1, m_Re[m], Alpha+m_Ai[m] + m_Twist[m], tau, true, bOutRe, bError); if(bOutRe) bPointOutRe = true; if(bError) bPointOutAlpha = true; m_XTrBot[m] = GetXTr(pFoil0, pFoil1, m_Re[m], Alpha+m_Ai[m]+m_Twist[m], tau, false, bOutRe, bError); if(bOutRe) bPointOutRe = true; if(bError) bPointOutAlpha = true; m_CmAirf[m] = GetCm(pFoil0, pFoil1, m_Re[m], Alpha+m_Ai[m]+m_Twist[m], tau, bOutRe, bError); if(bOutRe) bPointOutRe = true; if(bError) bPointOutAlpha = true; m_XCPSpanRel[m] = GetXCp(pFoil0, pFoil1, m_Re[m], Alpha+m_Ai[m]+m_Twist[m], tau, bOutRe, bError); if(qAbs(m_XCPSpanRel[m])<0.000001) { //plr mesh was generated prior to v3.15, i.e., without XCp calculations Cm0 = GetCm0(pFoil0, pFoil1, m_Re[m],tau, bOutRe, bError); if(m_Cl[m]!=0.0) m_XCPSpanRel[m] = 0.25 - Cm0/m_Cl[m]; else m_XCPSpanRel[m] = 0.25; } if(bOutRe) bPointOutRe = true; if(bError) bPointOutAlpha = true; arad = (Alpha+m_Ai[m]+m_Twist[m])*PI/180.0; // arad = (s_Alpha-m_Ai[m])*PI/180.0; c4 = m_pWing->C4(yob, m_pWPolar->m_CoG.x)/m_Chord[m]; zpos = m_pWing->ZPosition(yob*m_pWing->m_PlanformSpan/2.0)/m_Chord[m]; m_Cm[m] = m_CmAirf[m]- c4 * (m_Cl[m]*cos(arad) + m_PCd[m]*sin(arad)) - zpos* (m_Cl[m]*sin(arad) - m_PCd[m]*cos(arad)); ViscCm[m] = (-c4 *sin(arad) + zpos*cos(arad))* m_PCd[m]; InducedCm[m] = m_CmAirf[m]- c4 * m_Cl[m]*cos(arad) - zpos* m_Cl[m]*sin(arad); eta = Eta(m); sigma = Sigma(m); Integral0 += eta * m_Cl[m] * m_Chord[m]; Integral1 += sigma * m_Cl[m] * m_Chord[m]; Integral2 += eta * m_Cl[m] * m_Chord[m] * (m_Offset[m]+m_XCPSpanRel[m]*m_Chord[m]); Integral3 += eta * m_Cl[m] * m_Chord[m] * (zpos*m_Chord[m]); // Integral3 += eta * m_Cl[m] * m_Chord[m] * ((m_XCPSpanRel[m]*m_Chord[m]*cos(-m_Twist[m]*PI/180.0)+m_Offset[m]) * sin(-Alpha*PI/180.0) + (zpos*m_Chord[m]+m_XCPSpanRel[m]*m_Chord[m]*sin(-m_Twist[m]*PI/180.0)) * cos(-Alpha*PI/180.0)); InducedDrag += eta * m_Cl[m] * m_Chord[m] * (-m_Ai[m]); ViscousDrag += eta * m_PCd[m] * m_Chord[m]; InducedYawingMoment += sigma * m_Cl[m] * m_Chord[m] * (-m_Ai[m]); ViscousYawingMoment += sigma * m_PCd[m] * m_Chord[m]; PitchingMoment += eta * m_Cm[m] * m_Chord[m] * m_Chord[m]; VCm += eta * ViscCm[m] * m_Chord[m] * m_Chord[m]; ICm += eta * InducedCm[m] * m_Chord[m] * m_Chord[m]; if(bPointOutAlpha) { ErrorMessage = QString(QObject::tr(" Span pos = %1 ")).arg(cos(m*PI/s_NLLTStations)*m_pWing->m_PlanformSpan/2.0*m_mtoUnit,9,'f',2); ErrorMessage += m_LengthUnit; ErrorMessage += ", Re = "; ReynoldsFormat(strange, m_Re[m]); ErrorMessage += strange; strange = QString(QObject::tr(" , A+Ai+Twist = %1 could not be interpolated")+"\n").arg(Alpha+m_Ai[m] + m_Twist[m],6,'f',1); ErrorMessage+=strange; m_bWingOut = true; m_bConverged = false; } else if(bPointOutRe) { ErrorMessage = QString(QObject::tr(" Span pos = %1 ")).arg(cos(m*PI/s_NLLTStations)*m_pWing->m_PlanformSpan/2.0*m_mtoUnit,9,'f',2); ErrorMessage += m_LengthUnit; ErrorMessage += ", Re = "; ReynoldsFormat(strange, m_Re[m]); ErrorMessage += strange; strange = QString(QObject::tr(" , A+Ai+Twist = %1 is outside the flight envelope")+"\n").arg(Alpha+m_Ai[m] + m_Twist[m],6,'f',1); ErrorMessage+=strange; m_bWingOut = true; } } m_CL = Integral0 * m_pWing->m_AR /m_pWing->m_PlanformSpan; m_CDi = InducedDrag * m_pWing->m_AR /m_pWing->m_PlanformSpan * PI / 180.0; m_CDv = ViscousDrag / m_pWing->m_GChord; m_VYm = ViscousYawingMoment /m_pWing->m_GChord; m_IYm = InducedYawingMoment /m_pWing->m_PlanformSpan * PI * m_pWing->m_AR /180.0; m_GYm = m_VYm + m_IYm; // m_GCm = PitchingMoment / m_GChord / m_MAChord; m_VCm = VCm / m_pWing->m_GChord / m_pWing->m_MAChord; m_ICm = ICm / m_pWing->m_GChord / m_pWing->m_MAChord; m_GCm = m_VCm + m_ICm; m_GRm = -Integral1 * m_pWing->m_AR /m_pWing->m_PlanformSpan; if(m_CL !=0.0) { m_CP.x = Integral2 * m_pWing->m_AR /m_pWing->m_PlanformSpan/m_CL; // m_ZCP = Integral3 * m_pWing->m_AR /m_pWing->m_PlanformSpan/m_CL; m_CP.z=0.0;//the ZCP position may make physical sense in 3D panel analysis, but not in LLT } else { m_CP.Set(0.0,0.0,0.0); } if(m_pWing->m_bSymetric) m_CP.y = 0.0; else m_CP.y = m_pWing->m_AR/m_CL * Integral1; LLTSetBending(QInf); } void LLTAnalysis::LLTSetBending(double QInf) { //bending moment int j,jj; //dynamic pressure, kg/m3 double q = 0.5*m_pWPolar->m_Density * QInf * QInf; double bm; double y, yy; for (j=1; j=0) { for (jj=0; jjChord(0); for (i=1; im_PlanformSpan/2.0* fj*snt0/st0; } yob = cos(i*PI/s_NLLTStations); m_pWing->GetFoils(&pFoil0, &pFoil1, yob*m_pWing->m_PlanformSpan/2.0, tau); a0 = GetZeroLiftAngle(pFoil0, pFoil1, m_Re[i], tau); rhs[i] = c/cs * (Alpha-a0+m_Twist[i])/180.0*PI; } bool bCancel = false; if(!Gauss(aij,s_NLLTStations-1, rhs+1,0,&bCancel)) return false; for (i=1; iGetFoils(&pFoil0, &pFoil1, yob*m_pWing->m_PlanformSpan/2.0, tau); GetLinearizedPolar(pFoil0, pFoil1, m_Re[i], tau, a0, slope); a0 = GetZeroLiftAngle(pFoil0, pFoil1, m_Re[i], tau);//better approximation ? m_Cl[i] *= slope*180.0/PI*cs/m_Chord[i]; m_Ai[i] = -(Alpha-a0+m_Twist[i]) + m_Cl[i]/slope; } return true; } double LLTAnalysis::Sigma(int m) { //Auxiliary calculation of the sigma factor in LLT return PI/8.0/(double)m_pWing->m_NStation * sin(2.*(double)m*PI/(double)m_pWing->m_NStation) ; } double LLTAnalysis::Beta(int m, int k) { //Auxiliary calculation of the Beta factor in LLT double b; double fk = (double)k; double fm = (double)m; double fr = (double)m_pWing->m_NStation; if (m==k) b = 180.0*fr/8.0/PI/sin(fk*PI/fr); else if (IsEven(m+k)) b=0.0; else { double c1 = 180.0/4.0/PI/fr/sin(fk*PI/fr); double c2 = 1.0/(1.0-cos((fk+fm)*PI/fr)) - 1.0/(1.0-cos((fk-fm)*PI/fr)); b = c1 * c2; } return b; } double LLTAnalysis::AlphaInduced(int k) { // Calculates the induced angle from the lift coefficient and // from the Beta factor in LLT double ai = 0.0; for (int m=1; mm_NStation; m++) { ai += Beta(m,k) * m_Cl[m] * m_Chord[m]/m_pWing->m_PlanformSpan; } return ai; } int LLTAnalysis::LLTIterate(double &QInf, double Alpha) { int k ; Foil* pFoil0 = NULL; Foil* pFoil1 = NULL; double a, yob, tau, anext; bool bOutRe, bError; int iter = 0; while(iterGetFoils(&pFoil0, &pFoil1, yob*m_pWing->m_PlanformSpan/2.0, tau); m_Cl[k] = GetCl( pFoil0, pFoil1, m_Re[k], Alpha + m_Ai[k]+ m_Twist[k], tau, bOutRe, bError); if (m_pWPolar->m_WPolarType==FIXEDLIFTPOLAR) { Lift += Eta(k) * m_Cl[k] * m_Chord[k]; } } if(m_pWPolar->m_WPolarType==FIXEDLIFTPOLAR) { Lift *= m_pWing->m_AR / m_pWing->m_PlanformSpan; if(Lift<=0.0) return -1; QInf = m_QInf0 / sqrt(Lift); for (k=1; km_Viscosity; yob = cos(k*PI/s_NLLTStations); m_pWing->GetFoils(&pFoil0, &pFoil1, yob*m_pWing->m_PlanformSpan/2.0, tau); m_Cl[k] = GetCl(pFoil0, pFoil1, m_Re[k], Alpha + m_Ai[k]+ m_Twist[k], tau, bOutRe, bError); } } if (m_MaxaUpdateGraph(iter, m_Maxa); iter++; } return iter; } void LLTAnalysis::LLTInitialize(double QInf) { // // Initializes the LLT calculation // double y; int k; m_bWingOut = false; m_bConverged = false; if(m_pWPolar->m_WPolarType==FIXEDLIFTPOLAR) m_QInf0 = sqrt(2.*m_pWPolar->m_Mass* 9.81 /m_pWPolar->m_Density/m_pWing->m_PlanformArea); else m_QInf0 = 0.0; m_bConverged = true; m_bWingOut = false; m_pWing->ComputeChords(s_NLLTStations, m_Chord, m_Offset, m_Twist); for (k=0; k<=s_NLLTStations; k++) { y = cos(k*PI/s_NLLTStations)* m_pWing->m_PlanformSpan/2.0; m_Twist[k] = m_pWing->Twist(y); } for (k=0; k<=s_NLLTStations; k++) { m_SpanPos[k] = m_pWing->m_PlanformSpan/2.0 * cos((double)k*PI/s_NLLTStations); m_Re[k] = m_Chord[k] * QInf/m_pWPolar->m_Viscosity; } double yj, yjm, yjp, dy; for (int j=1; j #include #include #include #include #include WAdvancedDlg::WAdvancedDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Wing Analysis Advanced Settings")); m_NStation = 20; m_AlphaPrec = 0.01; m_Relax = 20.; m_Iter = 100; m_MaxWakeIter = 1; m_CoreSize = 0.0001;// 0.1mm m_WakeInterNodes = 6; m_MinPanelSize = .001; m_InducedDragPoint = 0; m_bResetWake = true; m_bDirichlet = true; m_bLogFile = true; m_bKeepOutOpps = true; m_ControlPos = 0.75; m_VortexPos = 0.25; m_bVLM1 = true; SetupLayout(); } void WAdvancedDlg::SetupLayout() { QSizePolicy szPolicyMaximum; szPolicyMaximum.setHorizontalPolicy(QSizePolicy::Maximum); szPolicyMaximum.setVerticalPolicy(QSizePolicy::Maximum); QSizePolicy szPolicyMinimum; szPolicyMinimum.setHorizontalPolicy(QSizePolicy::Minimum); szPolicyMinimum.setVerticalPolicy(QSizePolicy::Minimum); m_pctrlAStat = new QLabel(""); m_pctrlLength = new QLabel(""); m_pctrlLength2 = new QLabel(""); m_pctrlLogFile = new QCheckBox(tr("View Log File after errors")); m_pctrlResetWake = new QCheckBox(tr("Reset Wake between each angle")); m_pctrlKeepOutOpps = new QCheckBox(tr("Store points outside the polar mesh")); m_pctrlLogFile->setSizePolicy(szPolicyMinimum); m_pctrlResetWake->setSizePolicy(szPolicyMinimum); m_pctrlKeepOutOpps->setSizePolicy(szPolicyMinimum); m_pctrlDirichlet = new QRadioButton("Dirichlet"); m_pCtrlNeumann = new QRadioButton("Neumann"); m_pctrlDirichlet->setSizePolicy(szPolicyMinimum); m_pCtrlNeumann->setSizePolicy(szPolicyMinimum); m_pctrlVLM1 = new QRadioButton(tr("Horseshoe vortex")+" (VLM1)"); m_pctrlVLM2 = new QRadioButton(tr("Ring vortex")+" (VLM2)"); m_pctrlVLM1->setSizePolicy(szPolicyMinimum); m_pctrlVLM2->setSizePolicy(szPolicyMinimum); m_pctrlNStation = new IntEdit(20, this); m_pctrlIterMax = new IntEdit(100, this); m_pctrlInterNodes = new DoubleEdit(); m_pctrlRelax = new DoubleEdit(20,1); m_pctrlAlphaPrec = new DoubleEdit(.01, 4); m_pctrlMinPanelSize = new DoubleEdit(1.00,2); m_pctrlMaxWakeIter = new DoubleEdit(5,0); m_pctrlCoreSize = new DoubleEdit(.0001, 4); m_pctrlVortexPos = new DoubleEdit(25.0, 2); m_pctrlControlPos = new DoubleEdit(75.0, 2); m_pctrlInterNodes->setSizePolicy(szPolicyMaximum); m_pctrlRelax->setSizePolicy(szPolicyMaximum); m_pctrlAlphaPrec->setSizePolicy(szPolicyMaximum); m_pctrlMinPanelSize->setSizePolicy(szPolicyMaximum); m_pctrlNStation->setSizePolicy(szPolicyMaximum); m_pctrlIterMax->setSizePolicy(szPolicyMaximum); m_pctrlMaxWakeIter->setSizePolicy(szPolicyMaximum); m_pctrlCoreSize->setSizePolicy(szPolicyMaximum); m_pctrlVortexPos->setSizePolicy(szPolicyMaximum); m_pctrlControlPos->setSizePolicy(szPolicyMaximum); QGroupBox *AllBox = new QGroupBox(tr("All Analysis")); { QHBoxLayout *AllLayout = new QHBoxLayout; { AllLayout->addWidget(m_pctrlLogFile); AllLayout->addWidget(m_pctrlKeepOutOpps); } AllBox->setLayout(AllLayout); } QGroupBox *VLMPanelBox = new QGroupBox(tr("VLM and Panel Methods")); { QVBoxLayout *VLMPanelLayout = new QVBoxLayout; { QHBoxLayout *WingPanelLayout = new QHBoxLayout; { QLabel *lab5 = new QLabel(tr("Ignore wing panels with span <")); lab5->setAlignment(Qt::AlignRight | Qt::AlignVCenter); WingPanelLayout->addStretch(1); WingPanelLayout->addWidget(lab5); WingPanelLayout->addWidget(m_pctrlMinPanelSize); WingPanelLayout->addWidget(m_pctrlLength); } QHBoxLayout *CoreSizeLayout = new QHBoxLayout; { QLabel *lab10 = new QLabel(tr("Core Size")); lab10->setAlignment(Qt::AlignRight | Qt::AlignVCenter); CoreSizeLayout->addStretch(1); CoreSizeLayout->addWidget(lab10); CoreSizeLayout->addWidget(m_pctrlCoreSize); CoreSizeLayout->addWidget(m_pctrlLength2); } VLMPanelLayout->addLayout(WingPanelLayout); VLMPanelLayout->addLayout(CoreSizeLayout); } VLMPanelBox->setLayout(VLMPanelLayout); } QGroupBox *VLMBox = new QGroupBox(tr("VLM Method")); { QGridLayout *VLMLayout = new QGridLayout; { QLabel *lab6 = new QLabel(tr("Vortex Position")); QLabel *lab7 = new QLabel(tr("Control Point Position")); QLabel *lab8 = new QLabel("%"); QLabel *lab9 = new QLabel("%"); lab6->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab7->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab8->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab9->setAlignment(Qt::AlignRight | Qt::AlignVCenter); VLMLayout->addWidget(lab6,1,1); VLMLayout->addWidget(lab7,2,1); VLMLayout->addWidget(m_pctrlVortexPos,1,2); VLMLayout->addWidget(m_pctrlControlPos,2,2); VLMLayout->addWidget(lab8,1,3); VLMLayout->addWidget(lab9,2,3); QVBoxLayout *VLMMethodLayout = new QVBoxLayout; { VLMMethodLayout->addWidget(m_pctrlVLM1); VLMMethodLayout->addWidget(m_pctrlVLM2); } VLMLayout->addLayout(VLMMethodLayout,4,1,1,2, Qt::AlignLeft); } VLMBox->setLayout(VLMLayout); } QGroupBox *LLTBox = new QGroupBox(tr("Lifting Line Method")); { QGridLayout *LLTLayout = new QGridLayout; { QLabel *lab1 = new QLabel(tr("Relax. factor")); QLabel *lab2 = new QLabel(tr("Alpha Precision")); QLabel *lab3 = new QLabel(tr("Max. Iterations")); QLabel *lab4 = new QLabel(tr("Number of spanwise stations")); lab1->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab2->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab3->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab4->setAlignment(Qt::AlignRight | Qt::AlignVCenter); LLTLayout->addWidget(lab1,1,1); LLTLayout->addWidget(lab2,2,1); LLTLayout->addWidget(lab3,3,1); LLTLayout->addWidget(lab4,4,1); LLTLayout->addWidget(m_pctrlRelax,1,2); LLTLayout->addWidget(m_pctrlAlphaPrec,2,2); LLTLayout->addWidget(m_pctrlIterMax,3,2); LLTLayout->addWidget(m_pctrlNStation,4,2); } LLTBox->setLayout(LLTLayout); } QGroupBox *PanelBCBox = new QGroupBox(tr("3D Panel boundary conditions")); { QVBoxLayout *PanelBCLayout = new QVBoxLayout; { PanelBCLayout->addWidget(m_pctrlDirichlet); PanelBCLayout->addWidget(m_pCtrlNeumann); } PanelBCBox->setLayout((PanelBCLayout)); } QHBoxLayout *CommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); QPushButton *ResetButton = new QPushButton(tr("Reset Defaults")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); CommandButtons->addWidget(ResetButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(ResetButton, SIGNAL(clicked()), this, SLOT(OnResetDefaults())); } QHBoxLayout *BothSides = new QHBoxLayout; { QVBoxLayout *LeftSide = new QVBoxLayout; { LeftSide->addWidget(LLTBox); LeftSide->addStretch(1); LeftSide->addWidget(PanelBCBox); LeftSide->addStretch(1); } QVBoxLayout *RightSide = new QVBoxLayout; { RightSide->addWidget(VLMBox); RightSide->addStretch(1); RightSide->addWidget(VLMPanelBox); RightSide->addStretch(1); } BothSides->addLayout(LeftSide); BothSides->addLayout(RightSide); } QVBoxLayout *MainLayout = new QVBoxLayout; { MainLayout->addLayout(BothSides); MainLayout->addStretch(1); MainLayout->addWidget(AllBox); MainLayout->addStretch(1); MainLayout->addSpacing(30); MainLayout->addLayout(CommandButtons); } setSizePolicy(szPolicyMaximum); setLayout(MainLayout); } void WAdvancedDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Escape: { done(0); return; } case Qt::Key_Return: { if(!OKButton->hasFocus()) { OKButton->setFocus(); return; } break; } default: event->ignore(); break; } } void WAdvancedDlg::InitDialog() { SetParams(); QString len; GetLengthUnit(len,MainFrame::s_LengthUnit); m_pctrlAStat->setText(len); m_pctrlLength->setText(len); m_pctrlLength2->setText(len); m_pctrlVortexPos->setEnabled(false); m_pctrlControlPos->setEnabled(false); m_pctrlDirichlet->setChecked(m_bDirichlet); m_pCtrlNeumann->setChecked(!m_bDirichlet); m_pctrlVLM1->setChecked( m_bVLM1); m_pctrlVLM2->setChecked(!m_bVLM1); } void WAdvancedDlg::OnOK() { ReadParams(); accept(); } void WAdvancedDlg::OnResetDefaults() { m_Relax = 20.0; m_AlphaPrec = 0.01; m_Iter = 100; m_NStation = 20; m_MaxWakeIter = 5; m_CoreSize = 0.0001; m_MinPanelSize = .001; m_WakeInterNodes = 6; m_bLogFile = true; m_VortexPos = 0.25; m_ControlPos = 0.75; m_bDirichlet = true; m_bResetWake = true; m_bTrefftz = true; m_bKeepOutOpps = false; m_bVLM1 = true; SetParams(); } void WAdvancedDlg::ReadParams() { m_Relax = m_pctrlRelax->Value(); m_AlphaPrec = m_pctrlAlphaPrec->Value(); m_MaxWakeIter = m_pctrlMaxWakeIter->Value(); m_CoreSize = m_pctrlCoreSize->Value() / MainFrame::s_mtoUnit; m_MinPanelSize = m_pctrlMinPanelSize->Value() / MainFrame::s_mtoUnit; m_VortexPos = m_pctrlVortexPos->Value()/100.0; m_ControlPos = m_pctrlControlPos->Value()/100.0; m_WakeInterNodes = (int)m_pctrlInterNodes->Value(); m_Iter = (int)m_pctrlIterMax->Value();; m_NStation = (int)m_pctrlNStation->Value(); m_bDirichlet = m_pctrlDirichlet->isChecked(); m_bTrefftz = true; m_bResetWake = m_pctrlResetWake->isChecked(); m_bKeepOutOpps = m_pctrlKeepOutOpps->isChecked(); m_bLogFile = m_pctrlLogFile->isChecked(); m_bVLM1 = m_pctrlVLM1->isChecked(); } void WAdvancedDlg::SetParams() { m_pctrlIterMax->SetValue(m_Iter); m_pctrlRelax->SetValue(m_Relax); m_pctrlAlphaPrec->SetValue(m_AlphaPrec); m_pctrlNStation->SetValue(m_NStation); m_pctrlCoreSize->SetValue(m_CoreSize* MainFrame::s_mtoUnit); m_pctrlMaxWakeIter->SetValue(m_MaxWakeIter); m_pctrlInterNodes->SetValue(m_WakeInterNodes); m_pctrlMinPanelSize->SetValue(m_MinPanelSize * MainFrame::s_mtoUnit); m_pctrlResetWake->setChecked(m_bResetWake); m_pctrlLogFile->setChecked(m_bLogFile); m_pctrlKeepOutOpps->setChecked(m_bKeepOutOpps); m_pctrlControlPos->SetValue(m_ControlPos*100.0); m_pctrlVortexPos->SetValue(m_VortexPos*100.0); m_pctrlVLM1->setChecked(m_bVLM1); } xflr5-6.09-06/src/miarex/GLCreateLists.h000644 001750 000144 00000005051 12247174402 021164 0ustar00techwinderusers000000 000000 /**************************************************************************** GLCreateLists Copyright (C) 2010-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** * @file this file implements the methods used to create the OpenGL lists for the various objects. */ #ifndef GLCREATELISTS_H #define GLCREATELISTS_H #include #include "../objects/Plane.h" #include "../objects/PlaneOpp.h" #include "../objects/WPolar.h" void GLCreateGeom(void *pQMiarex, Wing *pWing, int List, Body *pBody=NULL); void GLCreateCp(void *pQMiarex, CVector *pNode, Panel *pPanel, WingOpp *pWOpp, PlaneOpp *pPOpp); void GLDrawCpLegend(void *pQMiarex); void GLCreateCpLegendClr(void *pQMiarex); void GLCreateDownwash(void *pQMiarex, Wing *pWing, WingOpp *pWOpp, int List); void GLCreateDrag(void *pQMiarex, Wing *pWing, WPolar* pWPolar, WingOpp *pWOpp, int List); void GLCreateMesh(int iList, int size, Panel *pPanel, CVector *pNode, QColor PanelColor, QColor BackColor, bool bBack=true); void GLCreateCtrlPts(void *pQMiarex, Panel *pPanel); void GLCreateLiftStrip(void *pQMiarex, Wing *pWing, WPolar *pWPolar, WingOpp *pWOpp, int List); void GLCreateMoments(void *pQMiarex, Wing *pWing, WPolar *pWPolar, WingOpp *pWOpp); void GLCreateLiftForce(void *pQMiarex, WPolar *pWPolar, WingOpp *pWOpp); void GLCreateStreamLines(void *pQMiarex, Wing *PlaneWing[MAXWINGS], CVector *pNode, WPolar *pWPolar, WingOpp *pWOpp); void GLCreateSurfSpeeds(void *pQMiarex, Panel *pPanel, WPolar *pWPolar, WingOpp *pWOpp); void GLCreateVortices(void *pQMiarex, Panel *pPanel, CVector *pNode, WPolar *pWPolar); void GLCreateTrans(void *pQMiarex, Wing *pWing, WingOpp *pWOpp, int List); void GLCreatePanelForce(void *pQMiarex, WPolar *pWPolar, WingOpp *pWOpp, PlaneOpp *pPOpp); void GLDrawPanelForceLegend(void *pQMiarex, WPolar *pWPolar); #endif // GLCREATELISTS_H xflr5-6.09-06/src/miarex/StabPolarDlg.cpp000644 001750 000144 00000102350 12247174407 021375 0ustar00techwinderusers000000 000000 /**************************************************************************** StabPolarDlg Class Copyright (C) 2010-2012 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../mainframe.h" #include "../globals.h" #include "../objects/WPolar.h" #include "Miarex.h" #include "StabPolarDlg.h" #include #include #include #include #include #include #include void *StabPolarDlg::s_pMiarex; WPolar StabPolarDlg::s_StabPolar; StabPolarDlg::StabPolarDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Stability Polar Definition")); m_bAutoName = true; m_pWingList[0] = NULL; m_pWingList[1] = NULL; m_pWingList[2] = NULL; m_pWingList[3] = NULL; m_pctrlControlTable = NULL; m_pControlModel = NULL; m_pCtrlDelegate = NULL; /* s_StabPolar.m_bAutoInertia = true; s_StabPolar.m_CoG.Set(0.0,0.0,0.0); s_StabPolar.m_CoGIxx = s_StabPolar.m_CoGIyy = s_StabPolar.m_CoGIzz = s_StabPolar.m_CoGIxz = 0.0; s_StabPolar.m_Mass = 0.0; memset(s_StabPolar.m_MinControl, 0, sizeof(s_StabPolar.m_MinControl)); memset(s_StabPolar.m_MaxControl, 0, sizeof(s_StabPolar.m_MaxControl)); memset(s_StabPolar.m_bActiveControl, 0, sizeof(s_StabPolar.m_bActiveControl)); s_StabPolar.m_RefAreaType = 1; m_UnitType = 1; s_StabPolar.m_Density = 1.225; s_StabPolar.m_Viscosity = 1.5e-5; s_StabPolar.m_Beta = 0.0; s_StabPolar.m_BankAngle = 0.0; s_StabPolar.m_nControls = 0; s_StabPolar.m_bViscous = true; s_StabPolar.m_bThinSurfaces = true; s_StabPolar.m_AnalysisMethod = VLMMETHOD; */ s_StabPolar.m_WPolarType = STABILITYPOLAR; SetupLayout(); Connect(); } void StabPolarDlg::Connect() { connect(m_pctrlUnit1, SIGNAL(clicked()), this, SLOT(OnUnit())); connect(m_pctrlUnit2, SIGNAL(clicked()), this, SLOT(OnUnit())); connect(m_pctrlViscous, SIGNAL(clicked()), this, SLOT(OnViscous())); connect(m_pctrlIgnoreBodyPanels, SIGNAL(clicked()), this, SLOT(OnIgnoreBodyPanels())); connect(m_pctrlArea1, SIGNAL(clicked()),this, SLOT(OnArea())); connect(m_pctrlArea2, SIGNAL(clicked()),this, SLOT(OnArea())); connect(m_pctrlWingMethod2, SIGNAL(toggled(bool)), this, SLOT(OnMethod())); connect(m_pctrlWingMethod3, SIGNAL(toggled(bool)), this, SLOT(OnMethod())); connect(m_pctrlDensity, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlViscosity, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlBeta, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlPhi, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlMass, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlCoGx, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlCoGz, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlIxx, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlIyy, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlIzz, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlIxz, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlWPolarName, SIGNAL(editingFinished()), this, SLOT(OnWPolarName())); connect(m_pctrlAutoName, SIGNAL(clicked()), this, SLOT(OnAutoName())); connect(m_pctrlPlaneInertia, SIGNAL(clicked()), this, SLOT(OnAutoInertia())); // connect(m_pctrlAVLControls, SIGNAL(clicked()), this, SLOT(OnAVLControls())); connect(OKButton, SIGNAL(clicked()), this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void StabPolarDlg::FillUFOInertia() { if(m_pPlane) { s_StabPolar.m_Mass = m_pPlane->TotalMass(); s_StabPolar.m_CoG = m_pPlane->CoG(); s_StabPolar.m_CoGIxx = m_pPlane->m_CoGIxx; s_StabPolar.m_CoGIyy = m_pPlane->m_CoGIyy; s_StabPolar.m_CoGIzz = m_pPlane->m_CoGIzz; s_StabPolar.m_CoGIxz = m_pPlane->m_CoGIxz; } else if(m_pWingList[0]) { s_StabPolar.m_Mass = m_pWingList[0]->TotalMass(); s_StabPolar.m_CoG = m_pWingList[0]->CoG(); s_StabPolar.m_CoGIxx = m_pWingList[0]->m_CoGIxx; s_StabPolar.m_CoGIyy = m_pWingList[0]->m_CoGIyy; s_StabPolar.m_CoGIzz = m_pWingList[0]->m_CoGIzz; s_StabPolar.m_CoGIxz = m_pWingList[0]->m_CoGIxz; } m_pctrlMass->SetValue(s_StabPolar.m_Mass*MainFrame::s_kgtoUnit); m_pctrlCoGx->SetValue(s_StabPolar.m_CoG.x*MainFrame::s_mtoUnit); m_pctrlCoGz->SetValue(s_StabPolar.m_CoG.z*MainFrame::s_mtoUnit); m_pctrlIxx->SetValue(s_StabPolar.m_CoGIxx*MainFrame::s_kgtoUnit*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit); m_pctrlIyy->SetValue(s_StabPolar.m_CoGIyy*MainFrame::s_kgtoUnit*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit); m_pctrlIzz->SetValue(s_StabPolar.m_CoGIzz*MainFrame::s_kgtoUnit*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit); m_pctrlIxz->SetValue(s_StabPolar.m_CoGIxz*MainFrame::s_kgtoUnit*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit); } void StabPolarDlg::FillControlList() { m_pControlModel->setRowCount(s_StabPolar.m_nControls);//temporary QString str, strong; QModelIndex ind; int i; GetLengthUnit(str, MainFrame::s_LengthUnit); s_StabPolar.m_nControls = 0; if(m_pPlane) { ind = m_pControlModel->index(s_StabPolar.m_nControls, 0, QModelIndex()); m_pControlModel->setData(ind, tr("Wing Tilt (")+QString::fromUtf8("°")+")"); ind = m_pControlModel->index(s_StabPolar.m_nControls, 1, QModelIndex()); m_pControlModel->setData(ind, s_StabPolar.m_ControlGain[0]); ++s_StabPolar.m_nControls; if(m_pWingList[2]) { ind = m_pControlModel->index(s_StabPolar.m_nControls, 0, QModelIndex()); m_pControlModel->setData(ind, tr("Elevator Tilt ")+QString::fromUtf8("(°)")); ind = m_pControlModel->index(s_StabPolar.m_nControls, 1, QModelIndex()); m_pControlModel->setData(ind, s_StabPolar.m_ControlGain[1]); ++s_StabPolar.m_nControls; } } for(i=0; im_nFlaps; i++) { ind = m_pControlModel->index(i+s_StabPolar.m_nControls, 0, QModelIndex()); strong = QString(tr("Wing Flap angle %1 ")+QString::fromUtf8("(°)")).arg(i+1); m_pControlModel->setData(ind, strong); ind = m_pControlModel->index(i+s_StabPolar.m_nControls, 1, QModelIndex()); m_pControlModel->setData(ind, s_StabPolar.m_ControlGain[i+s_StabPolar.m_nControls]); } s_StabPolar.m_nControls += m_pWingList[0]->m_nFlaps; if(m_pWingList[2]) { for(i=0; im_nFlaps; i++) { ind = m_pControlModel->index(i+s_StabPolar.m_nControls, 0, QModelIndex()); strong = QString(tr("Elevator Flap %1 ")+QString::fromUtf8("(°)")).arg(i+1); m_pControlModel->setData(ind, strong); ind = m_pControlModel->index(s_StabPolar.m_nControls, 1, QModelIndex()); m_pControlModel->setData(ind, s_StabPolar.m_ControlGain[i+s_StabPolar.m_nControls]); } s_StabPolar.m_nControls += m_pWingList[2]->m_nFlaps; } if(m_pWingList[3]) { for(i=0; im_nFlaps; i++) { ind = m_pControlModel->index(i+s_StabPolar.m_nControls, 0, QModelIndex()); strong = QString(tr("Fin Flap %1 ")+QString::fromUtf8("(°)")).arg(i+1); m_pControlModel->setData(ind, strong); ind = m_pControlModel->index(s_StabPolar.m_nControls, 1, QModelIndex()); m_pControlModel->setData(ind, s_StabPolar.m_ControlGain[i+s_StabPolar.m_nControls]); } s_StabPolar.m_nControls += m_pWingList[3]->m_nFlaps; } } void StabPolarDlg::SetViscous() { bool bViscous=true; int nCtrl = 0; if(m_pPlane) nCtrl++; if(m_pPlane && m_pWingList[2]) nCtrl++; for(int i=nCtrl; iPRECISION) { bViscous = false; break; } } if(!bViscous) { m_pctrlViscous->setChecked(false); m_pctrlViscous->setEnabled(false); s_StabPolar.m_bViscous = false; } else { if(s_StabPolar.m_bViscous) m_pctrlViscous->setChecked(true); m_pctrlViscous->setEnabled(true); } } void StabPolarDlg::InitDialog(Plane *pPlane, Wing *pWing, WPolar *pWPolar) { QString strLen, strMass, strInertia; m_pPlane = pPlane; if(m_pPlane) { m_pWingList[0] = pPlane->wing(); m_pWingList[1] = pPlane->wing2(); m_pWingList[2] = pPlane->stab(); m_pWingList[3] = pPlane->fin(); } else { m_pWingList[0] = pWing; m_pWingList[1] = NULL; m_pWingList[2] = NULL; m_pWingList[3] = NULL; } GetLengthUnit(strLen, MainFrame::s_LengthUnit); GetWeightUnit(strMass, MainFrame::s_WeightUnit); strInertia = strMass+"."+strLen+QString::fromUtf8("²"); m_pctrlLab299->setText(strMass); m_pctrlLab300->setText(strLen); m_pctrlLab301->setText(strLen); m_pctrlLab302->setText(strInertia); m_pctrlLab303->setText(strInertia); m_pctrlLab304->setText(strInertia); m_pctrlLab305->setText(strInertia); m_pctrlDensity->SetPrecision(5); m_pctrlViscosity->SetPrecision(3); QString str; GetSpeedUnit(str, MainFrame::s_SpeedUnit); if(m_UnitType==1) m_pctrlUnit1->setChecked(true); else m_pctrlUnit2->setChecked(true); OnUnit(); if(s_StabPolar.m_RefAreaType==1) m_pctrlArea1->setChecked(true); else m_pctrlArea2->setChecked(true); if(pWPolar && pWPolar->m_WPolarType==STABILITYPOLAR) { // m_bAutoName = false; // m_pctrlWPolarName->setText(pWPolar->m_PlrName); s_StabPolar.DuplicateSpec(pWPolar); } else { } m_bAutoName = true; m_pctrlAutoName->setChecked(m_bAutoName); if(m_pPlane) { s_StabPolar.m_AnalysisMethod = PANELMETHOD; s_StabPolar.m_UFOName = m_pPlane->PlaneName(); m_pctrlUFOName->setText(m_pPlane->PlaneName()); m_pctrlAnalysisControls->setCurrentIndex(1); } else if(m_pWingList[0]) { s_StabPolar.m_UFOName = m_pWingList[0]->WingName(); m_pctrlUFOName->setText(m_pWingList[0]->WingName()); m_pctrlAnalysisControls->setCurrentIndex(0); } else return; m_pctrlWPolarName->setText(s_StabPolar.m_PlrName); if(m_pPlane) { m_pctrlAnalysisControls->setCurrentIndex(1); } else m_pctrlAnalysisControls->setCurrentIndex(0); s_StabPolar.m_nControls = 0; s_StabPolar.m_nControls += m_pWingList[0]->m_nFlaps; if(m_pPlane) { s_StabPolar.m_nControls++; // Wing Tilt if(m_pWingList[2]) { s_StabPolar.m_nControls++;//stab tilt s_StabPolar.m_nControls += m_pWingList[2]->m_nFlaps; } if(m_pWingList[3]) s_StabPolar.m_nControls+=m_pWingList[3]->m_nFlaps; } if(m_pPlane) m_pctrlUFOName->setText(m_pPlane->PlaneName()); else m_pctrlUFOName->setText(m_pWingList[0]->WingName()); m_pctrlBeta->SetValue(s_StabPolar.m_Beta); m_pctrlPhi->SetValue(s_StabPolar.m_BankAngle); if(s_StabPolar.m_AnalysisMethod==LLTMETHOD) { s_StabPolar.m_AnalysisMethod = PANELMETHOD; s_StabPolar.m_bThinSurfaces = true; } if(m_pPlane) m_pctrlPanelMethod->setChecked(true); else { m_pctrlPanelMethod->setChecked(false); m_pctrlWingMethod2->setChecked(s_StabPolar.m_AnalysisMethod==VLMMETHOD); m_pctrlWingMethod3->setChecked(s_StabPolar.m_AnalysisMethod==PANELMETHOD); // m_pctrlWingMethod2->setChecked(s_StabPolar.m_bThinSurfaces); // m_pctrlWingMethod3->setChecked(!s_StabPolar.m_bThinSurfaces); } m_pctrlPlaneInertia->setChecked(s_StabPolar.m_bAutoInertia); m_pctrlViscous->setChecked(s_StabPolar.m_bViscous); m_pctrlIgnoreBodyPanels->setEnabled(m_pPlane && m_pPlane->body()); m_pctrlIgnoreBodyPanels->setChecked(m_pPlane && m_pPlane->body() && s_StabPolar.m_bIgnoreBodyPanels); if(!m_pPlane || !m_pPlane->body()) s_StabPolar.m_bIgnoreBodyPanels=false; // m_pctrlAVLControls->setChecked(s_StabPolar.m_bThinSurfaces); OnAutoInertia(); m_pControlModel->setColumnCount(2); m_pControlModel->setHeaderData(0, Qt::Horizontal, tr("Control Name")); m_pControlModel->setHeaderData(1, Qt::Horizontal, tr("Gain")+QString::fromUtf8("(°/unit)")); m_pCtrlDelegate->m_Precision[1] = 2; FillControlList(); SetWPolarName(); m_pctrlControlTable->setFocus(); } void StabPolarDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { ReadCtrlData(); SetWPolarName(); OKButton->setFocus(); return; } else { OnOK(); return; } break; } case Qt::Key_Escape: { reject(); } default: event->ignore(); } } void StabPolarDlg::OnArea() { if(m_pctrlArea1->isChecked()) { s_StabPolar.m_RefAreaType = 1; } else if(m_pctrlArea2->isChecked()) { s_StabPolar.m_RefAreaType = 2; } SetWPolarName(); } void StabPolarDlg::OnAutoName() { m_bAutoName = m_pctrlAutoName->isChecked(); if(m_bAutoName) SetWPolarName(); } void StabPolarDlg::OnCellChanged(QWidget *pWidget) { ReadCtrlData(); SetWPolarName(); } void StabPolarDlg::OnEditingFinished() { ReadParams(); SetWPolarName(); } void StabPolarDlg::OnUnit() { if(m_pctrlUnit1->isChecked()) { m_UnitType = 1; m_pctrlViscosity->SetValue(s_StabPolar.m_Viscosity); m_pctrlDensityUnit->setText("kg/m3"); m_pctrlViscosityUnit->setText("m"+QString::fromUtf8("²")+"/s"); } else { m_UnitType = 2; m_pctrlViscosity->SetValue(s_StabPolar.m_Viscosity* 10.7182881); m_pctrlDensityUnit->setText("slugs/ft3"); m_pctrlViscosityUnit->setText("ft"+QString::fromUtf8("²")+"/s"); } SetDensity(); } void StabPolarDlg::OnOK() { ReadCtrlData(); ReadParams(); if(qAbs(s_StabPolar.m_Mass)setFocus(); return; } if(!m_pctrlWPolarName->text().length()) { QMessageBox::warning(this, tr("Warning"), tr("Must enter a name")); m_pctrlWPolarName->setFocus(); return; } s_StabPolar.m_PlrName = m_pctrlWPolarName->text(); accept(); } void StabPolarDlg::OnViscous() { s_StabPolar.m_bViscous = m_pctrlViscous->isChecked(); SetWPolarName(); } void StabPolarDlg::OnIgnoreBodyPanels() { s_StabPolar.m_bIgnoreBodyPanels = m_pctrlIgnoreBodyPanels->isChecked(); SetWPolarName(); } void StabPolarDlg::OnWPolarName() { m_pctrlAutoName->setChecked(false); m_bAutoName = false; } void StabPolarDlg::ReadCtrlData() { int i; for(i=0; iindex(i, 1, QModelIndex()).data().toInt(); s_StabPolar.m_ControlGain[i] = m_pControlModel->index(i, 1, QModelIndex()).data().toDouble(); //is the gain, AVL-like } for(i=s_StabPolar.m_nControls; i<4*MAXCONTROLS; i++) { // s_StabPolar.m_MinControl[i] = 0.0; s_StabPolar.m_ControlGain[i] = 0.0; // s_StabPolar.m_bActiveControl[i]=false; } SetViscous(); } void StabPolarDlg::ReadParams() { if(m_pctrlUnit1->isChecked()) { s_StabPolar.m_Density = m_pctrlDensity->Value(); s_StabPolar.m_Viscosity = m_pctrlViscosity->Value(); } else { s_StabPolar.m_Density = m_pctrlDensity->Value() / 0.00194122; s_StabPolar.m_Viscosity = m_pctrlViscosity->Value() / 10.7182881; } s_StabPolar.m_Beta = m_pctrlBeta->Value(); s_StabPolar.m_BankAngle = m_pctrlPhi->Value(); SetDensity(); s_StabPolar.m_Mass = m_pctrlMass->Value() / MainFrame::s_kgtoUnit; s_StabPolar.m_CoG.x = m_pctrlCoGx->Value() / MainFrame::s_mtoUnit; s_StabPolar.m_CoG.z = m_pctrlCoGz->Value() / MainFrame::s_mtoUnit; s_StabPolar.m_CoGIxx = m_pctrlIxx->Value() / MainFrame::s_kgtoUnit / MainFrame::s_mtoUnit / MainFrame::s_mtoUnit; s_StabPolar.m_CoGIyy = m_pctrlIyy->Value() / MainFrame::s_kgtoUnit / MainFrame::s_mtoUnit / MainFrame::s_mtoUnit; s_StabPolar.m_CoGIzz = m_pctrlIzz->Value() / MainFrame::s_kgtoUnit / MainFrame::s_mtoUnit / MainFrame::s_mtoUnit; s_StabPolar.m_CoGIxz = m_pctrlIxz->Value() / MainFrame::s_kgtoUnit / MainFrame::s_mtoUnit / MainFrame::s_mtoUnit; s_StabPolar.m_bViscous = m_pctrlViscous->isChecked(); s_StabPolar.m_bIgnoreBodyPanels = m_pctrlIgnoreBodyPanels->isChecked(); } void StabPolarDlg::SetDensity() { int exp, precision; if(m_pctrlUnit1->isChecked()) { exp = (int)log(s_StabPolar.m_Density); if(exp>1) precision = 1; else if(exp<-4) precision = 4; else precision = 3-exp; m_pctrlDensity->SetPrecision(precision); m_pctrlDensity->SetValue(s_StabPolar.m_Density); } else { exp = (int)log(s_StabPolar.m_Density* 0.00194122); if(exp>1) precision = 1; else if(exp<-4) precision = 4; else precision = 3-exp; m_pctrlDensity->SetPrecision(precision); m_pctrlDensity->SetValue(s_StabPolar.m_Density* 0.00194122); } } void StabPolarDlg::SetupLayout() { QGroupBox *pNameGroupBox = new QGroupBox(tr("Polar Name")); { QVBoxLayout *NameLayout = new QVBoxLayout; { QHBoxLayout *MiscLayout = new QHBoxLayout; { m_pctrlUFOName = new QLabel(tr("Wing Name")); MiscLayout->addWidget(m_pctrlUFOName); MiscLayout->addStretch(2); } m_pctrlAutoName = new QCheckBox(tr("Auto Analysis Name")); m_pctrlWPolarName = new QLineEdit(tr("Polar Name")); QHBoxLayout *AutoNameLayout = new QHBoxLayout; { AutoNameLayout->addWidget(m_pctrlAutoName); AutoNameLayout->addWidget(m_pctrlWPolarName); } NameLayout->addLayout(MiscLayout); NameLayout->addLayout(AutoNameLayout); } pNameGroupBox->setLayout(NameLayout); } QGroupBox *pPlaneGroupBox = new QGroupBox(tr("Plane and Flight Data")); { QVBoxLayout *PlaneFlightLayout = new QVBoxLayout; { QGridLayout *PlaneLayout = new QGridLayout; { QLabel *lab2 = new QLabel(tr("b =")); QLabel *lab3 = new QLabel(tr("f =")); lab2->setFont(QFont("Symbol")); lab3->setFont(QFont("Symbol")); lab2->setAlignment(Qt::AlignVCenter|Qt::AlignRight); lab3->setAlignment(Qt::AlignVCenter|Qt::AlignRight); QLabel *lab4 = new QLabel(QString::fromUtf8("°")); QLabel *lab5 = new QLabel(QString::fromUtf8("°")); m_pctrlBeta = new DoubleEdit(0.818,2); m_pctrlPhi = new DoubleEdit(0.414,2); PlaneLayout->addWidget(lab2,1,1); PlaneLayout->addWidget(m_pctrlBeta,1,2); PlaneLayout->addWidget(lab4 ,1,3); PlaneLayout->addWidget(lab3,2,1); PlaneLayout->addWidget(m_pctrlPhi,2,2); PlaneLayout->addWidget(lab5,2,3); } m_pctrlViscous = new QCheckBox(tr("Viscous Analysis")); // PlaneLayout->addWidget(m_pctrlViscous,5,1,1,3); PlaneFlightLayout->addLayout(PlaneLayout); PlaneFlightLayout->addWidget(m_pctrlViscous); QLabel *lab11 = new QLabel(tr("Note : the analysis may be of the viscous type\nonly if all the flap controls are inactive")); PlaneFlightLayout->addWidget(lab11); PlaneFlightLayout->addStretch(1); pPlaneGroupBox->setLayout(PlaneFlightLayout); } } QGroupBox *pAeroDataGroupBox = new QGroupBox(tr("Aerodynamic Data")); { QGridLayout *AeroDataLayout = new QGridLayout; { QLabel *lab9 = new QLabel(tr("Unit")); m_pctrlUnit1 = new QRadioButton(tr("International")); m_pctrlUnit2 = new QRadioButton(tr("Imperial")); m_pctrlRho = new QLabel("r ="); m_pctrlDensity = new DoubleEdit(1.500e-5,3); m_pctrlDensityUnit = new QLabel("kg/m3"); m_pctrlNu = new QLabel("n ="); m_pctrlRho->setFont(QFont("Symbol")); m_pctrlNu->setFont(QFont("Symbol")); m_pctrlViscosity = new DoubleEdit(1.225,3); m_pctrlViscosityUnit = new QLabel("m2/s"); AeroDataLayout->addWidget(lab9,1,1); AeroDataLayout->addWidget(m_pctrlUnit1,1,2); AeroDataLayout->addWidget(m_pctrlUnit2,1,3); AeroDataLayout->addWidget(m_pctrlRho,2,1); AeroDataLayout->addWidget(m_pctrlDensity,2,2); AeroDataLayout->addWidget(m_pctrlDensityUnit,2,3); AeroDataLayout->addWidget(m_pctrlNu,3,1); AeroDataLayout->addWidget(m_pctrlViscosity,3,2); AeroDataLayout->addWidget(m_pctrlViscosityUnit,3,3); } pAeroDataGroupBox->setLayout(AeroDataLayout); } QGroupBox *pAreaBox = new QGroupBox(tr("Reference Area for Aero Coefficients")); { QVBoxLayout *AreaOptions = new QVBoxLayout; { m_pctrlArea1 = new QRadioButton(tr("Wing Planform Area")); m_pctrlArea2 = new QRadioButton(tr("Wing Planform Area projected on xy plane")); AreaOptions->addWidget(m_pctrlArea1); AreaOptions->addWidget(m_pctrlArea2); } pAreaBox->setLayout(AreaOptions); } QVBoxLayout *LeftSideLayout = new QVBoxLayout; { LeftSideLayout->addWidget(pPlaneGroupBox); LeftSideLayout->addWidget(pAeroDataGroupBox); LeftSideLayout->addWidget(pAreaBox); } QGroupBox *InertiaBox = new QGroupBox("Inertia"); { QVBoxLayout *InertiaLayout = new QVBoxLayout; { m_pctrlPlaneInertia = new QCheckBox(tr("Use plane inertia")); m_pctrlPlaneInertia->setToolTip("Activate this checbox for the polar to use dynamically the plane's inertia properties for each analysis"); QGridLayout *InertiaDataLayout = new QGridLayout; { QLabel *Lab099 = new QLabel("Mass="); QLabel *Lab100 = new QLabel("CoG.x="); QLabel *Lab101 = new QLabel("CoG.z="); QLabel *Lab102 = new QLabel("Ixx="); QLabel *Lab103 = new QLabel("Iyy="); QLabel *Lab104 = new QLabel("Izz="); QLabel *Lab105 = new QLabel("Ixz="); Lab099->setAlignment(Qt::AlignVCenter | Qt::AlignRight); Lab100->setAlignment(Qt::AlignVCenter | Qt::AlignRight); Lab101->setAlignment(Qt::AlignVCenter | Qt::AlignRight); Lab102->setAlignment(Qt::AlignVCenter | Qt::AlignRight); Lab103->setAlignment(Qt::AlignVCenter | Qt::AlignRight); Lab104->setAlignment(Qt::AlignVCenter | Qt::AlignRight); Lab105->setAlignment(Qt::AlignVCenter | Qt::AlignRight); m_pctrlLab299 = new QLabel; m_pctrlLab300 = new QLabel; m_pctrlLab301 = new QLabel; m_pctrlLab302 = new QLabel; m_pctrlLab303 = new QLabel; m_pctrlLab304 = new QLabel; m_pctrlLab305 = new QLabel; m_pctrlMass = new DoubleEdit(0.0,3); m_pctrlCoGx = new DoubleEdit(0.0,3); m_pctrlCoGz = new DoubleEdit(0.0,3); m_pctrlIxx = new DoubleEdit(0.0); m_pctrlIyy = new DoubleEdit(0.0); m_pctrlIzz = new DoubleEdit(0.0); m_pctrlIxz = new DoubleEdit(0.0); InertiaDataLayout->addWidget(Lab099,1,1); InertiaDataLayout->addWidget(Lab100,2,1); InertiaDataLayout->addWidget(Lab101,3,1); InertiaDataLayout->addWidget(Lab102,4,1); InertiaDataLayout->addWidget(Lab103,5,1); InertiaDataLayout->addWidget(Lab104,6,1); InertiaDataLayout->addWidget(Lab105,7,1); InertiaDataLayout->addWidget(m_pctrlMass,1,2); InertiaDataLayout->addWidget(m_pctrlCoGx,2,2); InertiaDataLayout->addWidget(m_pctrlCoGz,3,2); InertiaDataLayout->addWidget(m_pctrlIxx, 4,2); InertiaDataLayout->addWidget(m_pctrlIyy, 5,2); InertiaDataLayout->addWidget(m_pctrlIzz, 6,2); InertiaDataLayout->addWidget(m_pctrlIxz, 7,2); InertiaDataLayout->addWidget(m_pctrlLab299,1,3); InertiaDataLayout->addWidget(m_pctrlLab300,2,3); InertiaDataLayout->addWidget(m_pctrlLab301,3,3); InertiaDataLayout->addWidget(m_pctrlLab302,4,3); InertiaDataLayout->addWidget(m_pctrlLab303,5,3); InertiaDataLayout->addWidget(m_pctrlLab304,6,3); InertiaDataLayout->addWidget(m_pctrlLab305,7,3); } InertiaLayout->addWidget(m_pctrlPlaneInertia); // InertiaLayout->addWidget(m_pctrlEstimation); InertiaLayout->addLayout(InertiaDataLayout); InertiaLayout->addStretch(1); } InertiaBox->setLayout(InertiaLayout); } //Analysis method m_pctrlAnalysisControls = new QStackedWidget; { QGroupBox *WingMethodBox = new QGroupBox(tr("Wing analysis methods")); { QVBoxLayout *WingMethodLayout = new QVBoxLayout; { m_pctrlWingMethod2 = new QRadioButton(tr("VLM")); m_pctrlWingMethod3 = new QRadioButton(tr("3D Panels")); WingMethodLayout->addWidget(m_pctrlWingMethod2); WingMethodLayout->addWidget(m_pctrlWingMethod3); WingMethodBox->setLayout(WingMethodLayout); } } QGroupBox *PlaneMethodBox = new QGroupBox(tr("Plane analysis methods")); { QVBoxLayout *PlaneMethodLayout = new QVBoxLayout; { m_pctrlPanelMethod = new QRadioButton(tr("Mix 3D Panels/VLM")); m_pctrlIgnoreBodyPanels = new QCheckBox(tr("Ignore Body Panels")); PlaneMethodLayout->addStretch(); PlaneMethodLayout->addWidget(m_pctrlPanelMethod); PlaneMethodLayout->addStretch(); PlaneMethodLayout->addWidget(m_pctrlIgnoreBodyPanels); PlaneMethodBox->setLayout(PlaneMethodLayout); } } m_pctrlAnalysisControls->addWidget(WingMethodBox); m_pctrlAnalysisControls->addWidget(PlaneMethodBox); } // m_pctrlAVLControls = new QCheckBox(tr("AVL Controls")); QVBoxLayout *RightSideLayout = new QVBoxLayout; { RightSideLayout->addWidget(InertiaBox); RightSideLayout->addWidget(m_pctrlAnalysisControls); // RightSideLayout->addWidget(m_pctrlAVLControls); } QHBoxLayout *DataLayout = new QHBoxLayout; { DataLayout->addLayout(LeftSideLayout); DataLayout->addLayout(RightSideLayout); } m_pctrlControlTable = new QTableView(this); m_pctrlControlTable->setWindowTitle(tr("Controls")); m_pctrlControlTable->setMinimumWidth(400); m_pctrlControlTable->setMinimumHeight(150); m_pctrlControlTable->setSelectionMode(QAbstractItemView::SingleSelection); m_pctrlControlTable->setSelectionBehavior(QAbstractItemView::SelectRows); m_pctrlControlTable->horizontalHeader()->setStretchLastSection(true); m_pControlModel = new QStandardItemModel; m_pControlModel->setRowCount(10);//temporary m_pControlModel->setColumnCount(4);//temporary m_pctrlControlTable->setModel(m_pControlModel); m_pCtrlDelegate = new CtrlTableDelegate; m_pctrlControlTable->setItemDelegate(m_pCtrlDelegate); m_pCtrlDelegate->m_pCtrlModel = m_pControlModel; connect(m_pCtrlDelegate, SIGNAL(closeEditor(QWidget *)), this, SLOT(OnCellChanged(QWidget *))); int *precision = new int[6]; precision[0] = 2; precision[1] = 0; precision[2] = 3; precision[3] = 3; precision[4] = 3; precision[5] = 3; m_pCtrlDelegate->m_Precision = precision; QHBoxLayout *CommandButtons = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); OKButton->setDefault(true); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); } QVBoxLayout * MainLayout = new QVBoxLayout(this); { QLabel* SignLabel = new QLabel(tr("Note: + sign means trailing edge down")); MainLayout->addWidget(pNameGroupBox); MainLayout->addLayout(DataLayout); MainLayout->addWidget(m_pctrlControlTable); MainLayout->addStretch(1); MainLayout->addWidget(SignLabel); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); } setLayout(MainLayout); } void StabPolarDlg::SetWPolarName() { if(!m_bAutoName) return; QString str, strong; int i, nCtrl; QMiarex *pMiarex= (QMiarex*)s_pMiarex; GetSpeedUnit(str, MainFrame::s_SpeedUnit); QString WPolarName = "T7"; if(!m_pPlane && !s_StabPolar.m_bThinSurfaces) WPolarName += "-Panel"; if(s_StabPolar.m_bThinSurfaces) { if(pMiarex->m_bVLM1) WPolarName += "-VLM1"; else WPolarName += "-VLM2"; } nCtrl = 0; if(!s_StabPolar.m_bThinSurfaces) { if(m_pPlane) { if(qAbs(s_StabPolar.m_ControlGain[0])>PRECISION && m_pPlane) { strong = QString(QString::fromUtf8("-Wing(%g1)")) .arg(s_StabPolar.m_ControlGain[0],0,'f',1); WPolarName += strong; } nCtrl++; } if(m_pPlane && m_pWingList[2]) { if(qAbs(s_StabPolar.m_ControlGain[1])>PRECISION) { strong = QString(QString::fromUtf8("-Elev(g%1)")).arg(s_StabPolar.m_ControlGain[1],0,'f',1); WPolarName += strong; } nCtrl++; } for(i=0; im_nFlaps; i++) { if(qAbs(s_StabPolar.m_ControlGain[i+nCtrl])>PRECISION) { strong = QString(QString::fromUtf8("-WF%1(g%2)")) .arg(i+1) .arg(s_StabPolar.m_ControlGain[i+nCtrl],0,'f',1); WPolarName += strong; } } nCtrl += m_pWingList[0]->m_nFlaps; if(m_pPlane && m_pWingList[2]) { for(i=0; im_nFlaps; i++) { if(qAbs(s_StabPolar.m_ControlGain[i+nCtrl])>PRECISION) { strong = QString(QString::fromUtf8("-EF%1(g%2)")) .arg(i+1).arg(s_StabPolar.m_ControlGain[i+nCtrl]); WPolarName += strong; } } nCtrl += m_pWingList[2]->m_nFlaps; } if(m_pPlane && m_pWingList[3]) { for(i=0; im_nFlaps; i++) { if(qAbs(s_StabPolar.m_ControlGain[i+nCtrl])>PRECISION) { strong = QString(QString::fromUtf8("-FF%1(g%2)")) .arg(i+1).arg(s_StabPolar.m_ControlGain[i+nCtrl]); WPolarName += strong; } } } } else { if(m_pPlane) { if(qAbs(s_StabPolar.m_ControlGain[0])>PRECISION) { strong = QString(QString::fromUtf8("-Wing(g%1)")) .arg(s_StabPolar.m_ControlGain[0],0,'f',2); WPolarName += strong; } nCtrl++; } if(m_pPlane && m_pWingList[2]) { if(qAbs(s_StabPolar.m_ControlGain[1])>PRECISION) { strong = QString(QString::fromUtf8("-Elev(g%1)")) .arg(s_StabPolar.m_ControlGain[1],0,'f',2); WPolarName += strong; } nCtrl++; } for(i=0; im_nFlaps; i++) { if(qAbs(s_StabPolar.m_ControlGain[i+nCtrl])>PRECISION) { strong = QString(QString::fromUtf8("-WF%1(g%2)")) .arg(i+1) .arg(s_StabPolar.m_ControlGain[i+nCtrl],0,'f',2); WPolarName += strong; } } nCtrl += m_pWingList[0]->m_nFlaps; if(m_pPlane && m_pWingList[2]) { for(i=0; im_nFlaps; i++) { if(qAbs(s_StabPolar.m_ControlGain[i+nCtrl])>PRECISION) { strong = QString(QString::fromUtf8("-EF%1(g%2)")) .arg(i+1) .arg(s_StabPolar.m_ControlGain[i+nCtrl],0,'f',2); WPolarName += strong; } } nCtrl += m_pWingList[2]->m_nFlaps; } if(m_pPlane && m_pWingList[3]) { for(i=0; im_nFlaps; i++) { if(qAbs(s_StabPolar.m_ControlGain[i+nCtrl])>PRECISION) { strong = QString(QString::fromUtf8("-FF%1(g%2)")) .arg(i+1) .arg(s_StabPolar.m_ControlGain[i+nCtrl],0,'f',2); WPolarName += strong; } } } } if(qAbs(s_StabPolar.m_Beta) > .001) { strong = QString(QString::fromUtf8("-b%1°")).arg(s_StabPolar.m_Beta,0,'f',1); WPolarName += strong; } if(qAbs(s_StabPolar.m_BankAngle) > .001) { strong = QString(QString::fromUtf8("-B%1°")).arg(s_StabPolar.m_BankAngle,0,'f',1); WPolarName += strong; } if(!s_StabPolar.m_bAutoInertia) { GetWeightUnit(str, MainFrame::s_WeightUnit); strong = QString("-%1").arg(s_StabPolar.m_Mass*MainFrame::s_kgtoUnit,0,'f',3); WPolarName += strong+str; GetLengthUnit(str, MainFrame::s_LengthUnit); strong = QString("-x%1").arg(s_StabPolar.m_CoG.x*MainFrame::s_mtoUnit,0,'f',3); WPolarName += strong + str; if(qAbs(s_StabPolar.m_CoG.z)>=.000001) { strong = QString("-z%1").arg(s_StabPolar.m_CoG.z*MainFrame::s_mtoUnit,0,'f',3); WPolarName += strong + str; } } // else m_WPolarName += "-Plane_Inertia"; if(!s_StabPolar.m_bViscous) { WPolarName += "-Inviscid"; } if(s_StabPolar.m_bIgnoreBodyPanels) { WPolarName += "-NoBodyPanels"; } if(s_StabPolar.m_RefAreaType==PROJECTEDAREA) WPolarName += "-proj_area"; m_pctrlWPolarName->setText(WPolarName); } void StabPolarDlg::OnMethod() { if (m_pctrlWingMethod2->isChecked()) { s_StabPolar.m_bThinSurfaces = true; s_StabPolar.m_AnalysisMethod = VLMMETHOD; } else if (m_pctrlWingMethod3->isChecked()) { s_StabPolar.m_bThinSurfaces = false; s_StabPolar.m_AnalysisMethod = PANELMETHOD; } // EnableControls(); SetWPolarName(); } void StabPolarDlg::showEvent(QShowEvent *event) { int w, w2, w3, w6; w = m_pctrlControlTable->width(); w2 = (int)((double)w/2.0); w3 = (int)((double)w/3.0); w6 = (int)((double)w/6.0); if(!s_StabPolar.m_bThinSurfaces) { m_pctrlControlTable->setColumnWidth(0,w3); m_pctrlControlTable->setColumnWidth(1,w6); m_pctrlControlTable->setColumnWidth(2,w6); m_pctrlControlTable->setColumnWidth(3,w6); } else { m_pctrlControlTable->setColumnWidth(0,w2); m_pctrlControlTable->setColumnWidth(1,2*w6); } } void StabPolarDlg::OnAutoInertia() { s_StabPolar.m_bAutoInertia = m_pctrlPlaneInertia->isChecked(); if(s_StabPolar.m_bAutoInertia) { FillUFOInertia(); } else { m_pctrlMass->SetValue(s_StabPolar.m_Mass*MainFrame::s_kgtoUnit); m_pctrlCoGx->SetValue(s_StabPolar.m_CoG.x*MainFrame::s_mtoUnit); m_pctrlCoGz->SetValue(s_StabPolar.m_CoG.z*MainFrame::s_mtoUnit); m_pctrlIxx->SetValue(s_StabPolar.m_CoGIxx*MainFrame::s_kgtoUnit*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit); m_pctrlIyy->SetValue(s_StabPolar.m_CoGIyy*MainFrame::s_kgtoUnit*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit); m_pctrlIzz->SetValue(s_StabPolar.m_CoGIzz*MainFrame::s_kgtoUnit*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit); m_pctrlIxz->SetValue(s_StabPolar.m_CoGIxz*MainFrame::s_kgtoUnit*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit); } m_pctrlMass->setEnabled(!s_StabPolar.m_bAutoInertia); m_pctrlCoGx->setEnabled(!s_StabPolar.m_bAutoInertia); m_pctrlCoGz->setEnabled(!s_StabPolar.m_bAutoInertia); m_pctrlIxx->setEnabled(!s_StabPolar.m_bAutoInertia); m_pctrlIyy->setEnabled(!s_StabPolar.m_bAutoInertia); m_pctrlIzz->setEnabled(!s_StabPolar.m_bAutoInertia); m_pctrlIxz->setEnabled(!s_StabPolar.m_bAutoInertia); SetWPolarName(); } xflr5-6.09-06/src/miarex/UFOTableDelegate.h000644 001750 000144 00000004110 12247174407 021553 0ustar00techwinderusers000000 000000 /**************************************************************************** UFOTableDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef UFOTABLEDELEGATE_H #define UFOTABLEDELEGATE_H #include #include #include #include "../misc/DoubleEdit.h" class UFOTableDelegate : public QItemDelegate { Q_OBJECT friend class QMiarex; friend class ManageUFOsDlg; friend class MainFrame; public: UFOTableDelegate(QObject *parent = 0); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index); private: QStandardItemModel *m_pUFOModel; int *m_Precision; ///table of float precisions for each column static void *s_pMiarex; }; #endif // UFOTABLEDELEGATE_H xflr5-6.09-06/src/miarex/UFOTableDelegate.cpp000644 001750 000144 00000007740 12247174407 022122 0ustar00techwinderusers000000 000000 /**************************************************************************** UFOTableDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "UFOTableDelegate.h" #include "Miarex.h" void *UFOTableDelegate::s_pMiarex; UFOTableDelegate::UFOTableDelegate(QObject *parent) : QItemDelegate(parent) { } QWidget *UFOTableDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex & index ) const { return NULL;//No edition possible - display only if(index.column()==0) { QLineEdit *editor = new QLineEdit(parent); editor->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); return editor; } else { DoubleEdit *editor = new DoubleEdit(parent); editor->setAlignment(Qt::AlignRight | Qt::AlignVCenter); editor->SetPrecision(m_Precision[index.column()]); return editor; } return NULL; } bool UFOTableDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { return false;//don't edit anything! } void UFOTableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QString strong; QStyleOptionViewItem myOption = option; QMiarex *pMiarex = (QMiarex*)s_pMiarex; int NUFOs = pMiarex->m_poaWing->size(); NUFOs += pMiarex->m_poaPlane->size(); if(index.row()> NUFOs) { strong=" "; drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } else if(index.column()==0) { myOption.displayAlignment = Qt::AlignLeft | Qt::AlignVCenter; strong = index.model()->data(index, Qt::DisplayRole).toString(); drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } else { myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; strong = QString("%1").arg(index.model()->data(index, Qt::DisplayRole).toDouble(), 0,'f',m_Precision[index.column()]); drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } } void UFOTableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if(index.column()==0) { QString strong = index.model()->data(index, Qt::EditRole).toString(); QLineEdit *lineEdit = (QLineEdit*)editor; lineEdit->setText(strong); } else { double value = index.model()->data(index, Qt::EditRole).toDouble(); DoubleEdit *pDE = static_cast(editor); pDE->SetValue(value); } } void UFOTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { if(index.column()==0) { QString strong; QLineEdit *pLineEdit = static_cast(editor); strong = pLineEdit->text(); model->setData(index, strong, Qt::EditRole); } else { DoubleEdit *pDE = static_cast(editor); double value = pDE->Value(); model->setData(index, value, Qt::EditRole); } } void UFOTableDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { editor->setGeometry(option.rect); } xflr5-6.09-06/src/miarex/StabViewDlg.h000644 001750 000144 00000007615 12247174407 020707 0ustar00techwinderusers000000 000000 /**************************************************************************** StabViewDlg Class Copyright (C) 200-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef STABVIEWDLG_H #define STABVIEWDLG_H #include #include #include #include #include #include #include #include #include #include #include #include "../misc/DoubleEdit.h" #include "../graph/Curve.h" #include "../misc/FloatEditDelegate.h" class StabViewDlg : public QWidget { Q_OBJECT friend class QMiarex; friend class MainFrame; public: StabViewDlg(QWidget *parent); private slots: void OnAnimate(); void OnAnimateRestart(); void OnAnimationSpeed(int val); void OnAnimationAmplitude(int val); void OnCellChanged(QWidget *pWidget); void OnModeSelection(); void OnPlotStabilityGraph(); void OnReadData(); void OnResponseType(); void OnAddCurve(); void OnDeleteCurve(); void OnRenameCurve(); void OnSelChangeCurve(int sel); private: void keyPressEvent(QKeyEvent *event); void showEvent(QShowEvent *event); void AddCurve(); void Connect(); // void FillControlNames(); void FillEigenThings(); void FillCurveList(); double GetControlInput(const double &time); void SetMode(int iMode=-1); void SetupLayout(); void SetControls(); void SetTimeCurveStyle(QColor const &Color, int const&Style, int const &Width, bool const& bCurve, bool const& bPoints); void ReadControlModelData(); void UpdateControlModelData(); static void *s_pMiarex; QRadioButton *m_pctrlLongDynamics,*m_pctrlLatDynamics; QRadioButton *m_pctrlRLMode1,*m_pctrlRLMode2,*m_pctrlRLMode3,*m_pctrlRLMode4; QRadioButton *m_pctrlTimeMode1,*m_pctrlTimeMode2,*m_pctrlTimeMode3,*m_pctrlTimeMode4; QLineEdit *m_pctrlEigenValue, *m_pctrlEigenVector1, *m_pctrlEigenVector2, *m_pctrlEigenVector3, *m_pctrlEigenVector4; QLabel *m_pctrlModeProperties; // QSlider *m_pctrlAnimationSpeed, *m_pctrlAnimationAmplitude; QDial *m_pctrlAnimationSpeed, *m_pctrlAnimationAmplitude; QPushButton *m_pctrlAnimate, *m_pctrlAnimateRestart; DoubleEdit *m_pctrlModeStep; QLabel *m_pctrlStabLabel1, *m_pctrlStabLabel2, *m_pctrlStabLabel3; DoubleEdit *m_pctrlStabVar1, *m_pctrlStabVar2, *m_pctrlStabVar3; DoubleEdit *m_pctrlTotalTime, *m_pctrlDeltat; QPushButton *m_pctrlPlotStabGraph; QPushButton *m_pctrlAddCurve, *m_pctrlDeleteCurve, *m_pctrlRenameCurve; QComboBox *m_pctrlCurveList; QLabel *m_pctrlUnit1, *m_pctrlUnit2, *m_pctrlUnit3; DoubleEdit *m_pctrlFreqN, *m_pctrlFreq1, *m_pctrlDsi; QStackedWidget *m_pctrlStackWidget, *m_pctrlInitialConditionsWidget, *m_pctrlModeViewType; QRadioButton *m_pctrlModalResponse, *m_pctrlInitCondResponse, *m_pctrlForcedResponse; QTableView *m_pctrlControlTable; QStandardItemModel *m_pControlModel; FloatEditDelegate *m_pCtrlDelegate; int m_ModeInterval; double m_ModeAmplitude; double m_vabs[4], m_phi[4]; public: int m_iCurrentMode; Curve *m_pCurve; double m_Time[20], m_Amplitude[20]; }; #endif // STABVIEWDLG_H xflr5-6.09-06/src/miarex/PlaneDlg.cpp000644 001750 000144 00000102535 12247174407 020552 0ustar00techwinderusers000000 000000 /**************************************************************************** PlaneDlg Class Copyright (C) 2009-2012 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 ****************************************************************************/ #include #include #include #include #include #include #include "../globals.h" #include "../mainframe.h" #include "Miarex.h" #include "PlaneDlg.h" #include "GL3dWingDlg.h" #include "GL3dBodyDlg.h" #include "ImportObjectDlg.h" #include "InertiaDlg.h" void *PlaneDlg::s_pMiarex; void *PlaneDlg::s_pMainFrame; PlaneDlg::PlaneDlg(QWidget *parent) :QDialog(parent) { setWindowTitle(tr("Plane Editor")); m_pPlane = NULL; m_bAcceptName = true; m_bChanged = false; m_bDescriptionChanged = false; SetupLayout(); connect(m_pctrlBiplane, SIGNAL(clicked()), this, SLOT(OnBiplane())); connect(m_pctrlStabCheck, SIGNAL(clicked()), this, SLOT(OnStab())); connect(m_pctrlFinCheck, SIGNAL(clicked()), this, SLOT(OnFin())); connect(m_pctrlSymFin, SIGNAL(clicked()), this, SLOT(OnSymFin())); connect(m_pctrlDoubleFin, SIGNAL(clicked()), this, SLOT(OnDoubleFin())); connect(m_pctrlDefineWing, SIGNAL(clicked()), this, SLOT(OnDefineWing())); connect(m_pctrlImportWing, SIGNAL(clicked()), this, SLOT(OnImportWing())); connect(m_pctrlExportWing, SIGNAL(clicked()), this, SLOT(OnExportWing())); connect(m_pctrlDefineWing2, SIGNAL(clicked()), this, SLOT(OnDefineWing2())); connect(m_pctrlImportWing2, SIGNAL(clicked()), this, SLOT(OnImportWing2())); connect(m_pctrlExportWing2, SIGNAL(clicked()), this, SLOT(OnExportWing2())); connect(m_pctrlDefineStab, SIGNAL(clicked()), this, SLOT(OnDefineStab())); connect(m_pctrlDefineFin, SIGNAL(clicked()), this, SLOT(OnDefineFin())); connect(m_pctrlPlaneInertia, SIGNAL(clicked()), this, SLOT(OnInertia())); connect(OKButton, SIGNAL(clicked()), this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(m_pctrlBody, SIGNAL(clicked()), this, SLOT(OnBodyCheck())); connect(m_pctrlDefineBody, SIGNAL(clicked()), this, SLOT(OnDefineBody())); connect(m_pctrlImportBody, SIGNAL(clicked()), this, SLOT(OnImportBody())); connect(m_pctrlPlaneDescription, SIGNAL(textChanged()), this, SLOT(OnDescriptionChanged())); connect(m_pctrlWingTilt, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlStabTilt, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlFinTilt, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlXLEWing, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlZLEWing, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlXLEWing2, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlZLEWing2, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlXLEStab, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlZLEStab, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlXLEFin, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlZLEFin, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlXBody, SIGNAL(editingFinished()), this, SLOT(OnChanged())); connect(m_pctrlZBody, SIGNAL(editingFinished()), this, SLOT(OnChanged())); } void PlaneDlg::ComputePlane(void) { if(m_pPlane->stab()) { double SLA = m_pPlane->m_WingLE[2].x + m_pPlane->stab()->Chord(0)/4.0 - m_pPlane->m_WingLE[0].x -m_pPlane->wing()->Chord(0)/4.0; double area = m_pPlane->wing()->m_ProjectedArea; if(m_pPlane->wing2()) area += m_pPlane->wing2()->m_ProjectedArea; double ProjectedArea = 0.0; for (int i=0;istab()->NWingSection()-1; i++) { ProjectedArea += m_pPlane->stab()->Length(i+1)*(m_pPlane->stab()->Chord(i)+m_pPlane->stab()->Chord(i+1))/2.0 *cos(m_pPlane->stab()->Dihedral(i)*PI/180.0)*cos(m_pPlane->stab()->Dihedral(i)*PI/180.0); } ProjectedArea *=2.0; m_pPlane->m_TailVolume = ProjectedArea * SLA / area/m_pPlane->wing()->m_MAChord ; } else m_pPlane->m_TailVolume = 0.0; if(m_pPlane->fin()) { m_pPlane->fin()->m_bDoubleFin = m_pPlane->m_bDoubleFin; m_pPlane->fin()->m_bSymFin = m_pPlane->m_bSymFin; } } void PlaneDlg::InitDialog() { QString len, surf; GetLengthUnit(len, MainFrame::s_LengthUnit); GetAreaUnit(surf, MainFrame::s_AreaUnit); m_pctrlLen1->setText(len); m_pctrlLen2->setText(len); m_pctrlLen3->setText(len); m_pctrlLen4->setText(len); m_pctrlLen5->setText(len); m_pctrlLen6->setText(len); m_pctrlLen7->setText(len); m_pctrlLen8->setText(len); m_pctrlLen9->setText(len); m_pctrlLen10->setText(len); m_pctrlLen11->setText(len); m_pctrlLen12->setText(len); m_pctrlLen13->setText(len); m_pctrlSurf1->setText(surf); m_pctrlSurf2->setText(surf); m_pctrlSurf3->setText(surf); m_pctrlPlaneName->setText(m_pPlane->PlaneName()); if(m_pPlane->m_PlaneDescription.length()) m_pctrlPlaneDescription->setPlainText(m_pPlane->m_PlaneDescription); else m_pctrlPlaneDescription->setPlainText(""); SetParams(); SetResults(); if(!m_bAcceptName) m_pctrlPlaneName->setEnabled(false); m_bChanged = false; m_pPlane->m_bDoubleSymFin = true; m_pPlane->m_Wing[0].CreateSurfaces(m_pPlane->m_WingLE[0], 0.0, m_pPlane->m_WingTiltAngle[0]);//necessary for eventual inertia calculations m_pPlane->m_Wing[1].CreateSurfaces(m_pPlane->m_WingLE[1], 0.0, m_pPlane->m_WingTiltAngle[1]);//necessary for eventual inertia calculations m_pPlane->m_Wing[2].CreateSurfaces(m_pPlane->m_WingLE[2], 0.0, m_pPlane->m_WingTiltAngle[2]);//necessary for eventual inertia calculations m_pPlane->m_Wing[3].CreateSurfaces(m_pPlane->m_WingLE[3], -90.0, m_pPlane->m_WingTiltAngle[3]);//necessary for eventual inertia calculations } void PlaneDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OKButton->setFocus(); return; } else { OnOK(); return; } break; } case Qt::Key_Escape: { reject(); return; } default: event->ignore(); } } void PlaneDlg::OnBiplane() { m_bChanged = true; m_pPlane->m_bBiplane = m_pctrlBiplane->isChecked(); if(m_pPlane->wing2()) { m_pctrlDefineWing2->setEnabled(true); m_pctrlImportWing2->setEnabled(true); m_pctrlExportWing2->setEnabled(true); m_pctrlWingTilt2->setEnabled(true); m_pctrlZLEWing2->setEnabled(true); m_pctrlXLEWing2->setEnabled(true); } else { m_pctrlDefineWing2->setEnabled(false); m_pctrlImportWing2->setEnabled(false); m_pctrlExportWing2->setEnabled(false); m_pctrlWingTilt2->setEnabled(false); m_pctrlZLEWing2->setEnabled(false); m_pctrlXLEWing2->setEnabled(false); } } void PlaneDlg::OnBodyCheck() { m_bChanged = true; if(m_pctrlBody->isChecked()) { m_pPlane->m_bBody= true; if(!m_pPlane->body()) { m_pPlane->SetBody(new Body); } } else { m_pPlane->m_bBody= false; } m_pctrlXBody->setEnabled(m_pctrlBody->isChecked()); m_pctrlZBody->setEnabled(m_pctrlBody->isChecked()); m_pctrlDefineBody->setEnabled(m_pctrlBody->isChecked()); m_pctrlImportBody->setEnabled(m_pctrlBody->isChecked()); SetResults(); } void PlaneDlg::OnChanged() { m_bChanged = true; ReadParams(); SetResults(); } void PlaneDlg::OnDescriptionChanged() { m_bDescriptionChanged = true; } void PlaneDlg::OnDefineWing() { Wing *pSaveWing = new Wing(); pSaveWing->Duplicate(m_pPlane->wing()); GL3dWingDlg wingDlg((MainFrame*)s_pMainFrame); wingDlg.m_bAcceptName = false; wingDlg.InitDialog(m_pPlane->wing()); if(wingDlg.exec() ==QDialog::Accepted) { SetResults(); m_bChanged = true; } else m_pPlane->wing()->Duplicate(pSaveWing); m_pPlane->wing()->CreateSurfaces(m_pPlane->m_WingLE[0], 0.0, m_pPlane->m_WingTiltAngle[0]);//necessary for eventual inertia calculations } void PlaneDlg::OnDefineFin() { Wing *pSaveWing = new Wing(); pSaveWing->Duplicate(m_pPlane->fin()); GL3dWingDlg wingDlg((MainFrame*)s_pMainFrame); wingDlg.m_bAcceptName = false; wingDlg.InitDialog(m_pPlane->fin()); if(wingDlg.exec() ==QDialog::Accepted) { SetResults(); m_bChanged = true; } else m_pPlane->fin()->Duplicate(pSaveWing); m_pPlane->fin()->CreateSurfaces(m_pPlane->m_WingLE[3], -90.0, m_pPlane->m_WingTiltAngle[3]);//necessary for eventual inertia calculations } void PlaneDlg::OnDefineStab() { Wing *pSaveWing = new Wing(); pSaveWing->Duplicate(m_pPlane->stab()); GL3dWingDlg wingDlg((MainFrame*)s_pMainFrame); wingDlg.m_bAcceptName = false; wingDlg.InitDialog(m_pPlane->stab()); if(wingDlg.exec() == QDialog::Accepted) { SetResults(); m_bChanged = true; } else m_pPlane->stab()->Duplicate(pSaveWing); m_pPlane->stab()->CreateSurfaces(m_pPlane->m_WingLE[2], 0.0, m_pPlane->m_WingTiltAngle[2]);//necessary for eventual inertia calculations } void PlaneDlg::OnDefineWing2() { Wing *pSaveWing = new Wing(); pSaveWing->Duplicate(m_pPlane->wing2()); GL3dWingDlg wingDlg((MainFrame*)s_pMainFrame); wingDlg.m_bAcceptName = false; wingDlg.InitDialog(m_pPlane->wing2()); if(wingDlg.exec() ==QDialog::Accepted) { SetResults(); m_bChanged = true; } else m_pPlane->wing2()->Duplicate(pSaveWing); m_pPlane->wing2()->CreateSurfaces(m_pPlane->m_WingLE[1], 0.0, m_pPlane->m_WingTiltAngle[1]);//necessary for eventual inertia calculations } void PlaneDlg::OnDoubleFin() { if (m_pctrlDoubleFin->isChecked()) { m_pctrlYLEFin->setEnabled(true); m_pPlane->m_bDoubleFin = true; m_pPlane->m_bSymFin = false; m_pctrlSymFin->setChecked(false); } else { m_pctrlYLEFin->setEnabled(false); m_pPlane->m_bDoubleFin = false; } m_bChanged = true; SetResults(); } void PlaneDlg::OnDefineBody() { if(!m_pPlane->m_pBody) return; QMiarex * pMiarex = (QMiarex*)s_pMiarex; Body memBody; memBody.Duplicate(m_pPlane->m_pBody); GL3dBodyDlg glbDlg((MainFrame*)s_pMainFrame); glbDlg.m_bEnableName = false; glbDlg.InitDialog(m_pPlane->m_pBody); glbDlg.setWindowState(Qt::WindowMaximized); if(glbDlg.exec() == QDialog::Accepted) { pMiarex->m_bResetglBody = true; pMiarex->m_bResetglBodyMesh = true; pMiarex->m_bResetglGeom = true; pMiarex->m_bResetglMesh = true; MainFrame::SetSaveState(false); m_bChanged = true; SetResults(); } else m_pPlane->m_pBody->Duplicate(&memBody); } void PlaneDlg::OnExportWing() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QMiarex * pMiarex = (QMiarex*)s_pMiarex; Wing *pNewWing = new Wing(); pNewWing->Duplicate(m_pPlane->wing()); pNewWing->m_WingName = ""; pMiarex->AddWing(pNewWing); pMainFrame->UpdateUFOs(); pMiarex->UpdateView(); } void PlaneDlg::OnExportWing2() { QMiarex *pMiarex = (QMiarex*)s_pMiarex; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; Wing *pNewWing = new Wing(); pNewWing->Duplicate(m_pPlane->wing2()); pNewWing->m_WingName = ""; pMiarex->AddWing(pNewWing); pMainFrame->UpdateUFOs(); pMiarex->UpdateView(); } void PlaneDlg::OnFin() { m_bChanged = true; if(m_pctrlFinCheck->isChecked()) { m_pctrlSymFin->setEnabled(true); m_pctrlDoubleFin->setEnabled(true); m_pctrlFinTilt->setEnabled(true); m_pctrlXLEFin->setEnabled(true); if (m_pctrlDoubleFin->isChecked()) m_pctrlYLEFin->setEnabled(true); else m_pctrlYLEFin->setEnabled(false); m_pctrlZLEFin->setEnabled(true); m_pctrlDefineFin->setEnabled(true); m_pPlane->m_bFin = true; } else { m_pctrlSymFin->setEnabled(false); m_pctrlDoubleFin->setEnabled(false); m_pctrlFinTilt->setEnabled(false); m_pctrlXLEFin->setEnabled(false); m_pctrlYLEFin->setEnabled(false); m_pctrlZLEFin->setEnabled(false); m_pctrlDefineFin->setEnabled(false); m_pPlane->m_bFin = false; } SetResults(); } void PlaneDlg::OnImportBody() { QMiarex *pMiarex = (QMiarex*)s_pMiarex; ImportObjectDlg dlg(this); if(m_pPlane->m_bBody && m_pPlane->m_pBody) dlg.m_ObjectName = m_pPlane->body()->m_BodyName; else dlg.m_ObjectName.clear(); dlg.InitDialog(false); if(dlg.exec() == QDialog::Accepted) { m_bChanged = true; Body *pOldBody = pMiarex->GetBody(dlg.m_ObjectName); if(pOldBody) { Body *pNewBody = new Body; pNewBody->Duplicate(pOldBody); m_pPlane->SetBody(pNewBody); } } } void PlaneDlg::OnImportWing() { QMiarex *pMiarex = (QMiarex*)s_pMiarex; ImportObjectDlg dlg(this); dlg.m_ObjectName = m_pPlane->wing()->m_WingName; dlg.InitDialog(true); if(dlg.exec() == QDialog::Accepted) { m_bChanged = true; Wing *pWing = pMiarex->GetWing(dlg.m_ObjectName); if(pWing) { m_pPlane->wing()->Duplicate(pWing); m_pPlane->wing()->m_WingColor = pWing->m_WingColor; } } } void PlaneDlg::OnImportWing2() { QMiarex *pMiarex = (QMiarex*)s_pMiarex; ImportObjectDlg dlg(this); dlg.m_ObjectName = m_pPlane->wing()->m_WingName; dlg.InitDialog(true); if(dlg.exec() == QDialog::Accepted) { m_bChanged = true; Wing *pWing = pMiarex->GetWing(dlg.m_ObjectName); if(pWing) { m_pPlane->wing2()->Duplicate(pWing); m_pPlane->wing2()->m_WingColor = pWing->m_WingColor; } } } void PlaneDlg::OnInertia() { if(!m_pPlane) return; ReadParams(); m_pPlane->CreateSurfaces();//necessary for inertia calculations InertiaDlg dlg(this); dlg.m_pBody = NULL; dlg.m_pWing = NULL; dlg.m_pPlane = m_pPlane; //save inertia properties QList memPtMass; memPtMass.clear(); for(int im=0; imm_PointMass.size(); im++) { memPtMass.append(new PointMass(m_pPlane->m_PointMass[im])); } dlg.InitDialog(); if(dlg.exec()==QDialog::Accepted) { if(dlg.m_bChanged) m_bChanged = true; } else { //restore everything m_pPlane->ClearPointMasses(); for(int im=0; imm_PointMass.append(new PointMass(memPtMass[im])); } } } void PlaneDlg::OnPlaneName() { m_pPlane->m_PlaneName = m_pctrlPlaneName->text(); m_pPlane->RenameWings(); } void PlaneDlg::OnOK() { int j; QString strong; ReadParams(); m_pPlane->m_PlaneDescription = m_pctrlPlaneDescription->toPlainText(); ComputePlane(); //check the number of surfaces int nSurfaces = 0; for (j=0; jwing()->NWingSection()-1; j++) { if(qAbs(m_pPlane->wing()->YPosition(j)-m_pPlane->wing()->YPosition(j+1)) > QMiarex::s_MinPanelSize) nSurfaces+=2; } if(m_pPlane->stab()) { for (j=0; jstab()->NWingSection()-1; j++) { if(qAbs(m_pPlane->stab()->YPosition(j)-m_pPlane->stab()->YPosition(j+1)) > QMiarex::s_MinPanelSize) nSurfaces+=2; } } if(m_pPlane->fin()) { for (j=0; jfin()->NWingSection()-1; j++) { if(qAbs(m_pPlane->fin()->YPosition(j)-m_pPlane->fin()->YPosition(j+1)) > QMiarex::s_MinPanelSize) { if((m_pPlane->m_bSymFin) || (m_pPlane->m_bDoubleFin && m_pPlane->m_bDoubleSymFin)) nSurfaces += 2; else nSurfaces += 1; } } } if(nSurfaces >2*MAXSPANSECTIONS) { strong = QString(tr("Total number of wing panels =%1\n Max Number =%2\nA reduction of the number of wing panels is required")) .arg(nSurfaces).arg(MAXSPANSECTIONS); QMessageBox::warning(this, tr("Warning"), strong); return ; } m_pPlane->ComputeBodyAxisInertia(); if(!m_pctrlBody->isChecked()) { delete m_pPlane->m_pBody; m_pPlane->m_pBody = NULL; m_pPlane->m_bBody = false; } accept(); } void PlaneDlg::OnStab() { m_bChanged = true; if(m_pctrlStabCheck->isChecked()) { m_pctrlDefineStab->setEnabled(true); m_pctrlXLEStab->setEnabled(true); m_pctrlZLEStab->setEnabled(true); m_pctrlStabTilt->setEnabled(true); m_pPlane->m_bStab = true; } else { m_pctrlDefineStab->setEnabled(false); m_pctrlXLEStab->setEnabled(false); m_pctrlZLEStab->setEnabled(false); m_pctrlStabTilt->setEnabled(false); m_pPlane->m_bStab = false; } SetResults(); } void PlaneDlg::OnSymFin() { if (m_pctrlSymFin->isChecked()) { m_pctrlYLEFin->setEnabled(false); m_pPlane->m_bSymFin = true; m_pPlane->m_bDoubleFin = false; m_pctrlDoubleFin->setChecked(false); m_pctrlYLEFin->setEnabled(false); } else { // m_pctrlDoubleFin->setEnabled(true); m_pctrlYLEFin->setEnabled(true); m_pPlane->m_bSymFin = false; } m_bChanged = true; SetResults(); } void PlaneDlg::ReadParams() { OnPlaneName(); m_pPlane->m_WingTiltAngle[0] = m_pctrlWingTilt->Value(); m_pPlane->m_WingTiltAngle[1] = m_pctrlWingTilt2->Value(); m_pPlane->m_WingTiltAngle[2] = m_pctrlStabTilt->Value(); m_pPlane->m_WingTiltAngle[3] = m_pctrlFinTilt->Value(); m_pPlane->m_WingLE[0].x = m_pctrlXLEWing->Value() / MainFrame::s_mtoUnit; m_pPlane->m_WingLE[0].z = m_pctrlZLEWing->Value() / MainFrame::s_mtoUnit; m_pPlane->m_WingLE[1].x = m_pctrlXLEWing2->Value() / MainFrame::s_mtoUnit; m_pPlane->m_WingLE[1].z = m_pctrlZLEWing2->Value() / MainFrame::s_mtoUnit; m_pPlane->m_WingLE[2].x = m_pctrlXLEStab->Value() / MainFrame::s_mtoUnit; m_pPlane->m_WingLE[2].z = m_pctrlZLEStab->Value() / MainFrame::s_mtoUnit; m_pPlane->m_WingLE[3].x = m_pctrlXLEFin->Value() / MainFrame::s_mtoUnit; m_pPlane->m_WingLE[3].y = m_pctrlYLEFin->Value() / MainFrame::s_mtoUnit; m_pPlane->m_WingLE[3].z = m_pctrlZLEFin->Value() / MainFrame::s_mtoUnit; m_pPlane->m_BodyPos.x = m_pctrlXBody->Value() / MainFrame::s_mtoUnit; m_pPlane->m_BodyPos.z = m_pctrlZBody->Value() / MainFrame::s_mtoUnit; if(m_pctrlBiplane->isChecked()) m_pPlane->m_bBiplane = true; else m_pPlane->m_bBiplane = false; if(m_pctrlStabCheck->isChecked()) m_pPlane->m_bStab = true; else m_pPlane->m_bStab = false; if(m_pctrlFinCheck->isChecked()) m_pPlane->m_bFin = true; else m_pPlane->m_bFin = false; } void PlaneDlg::reject() { if(m_bChanged) { QString strong = tr("Save the changes ?"); int Ans = QMessageBox::question(this, tr("Question"), strong, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel); if (QMessageBox::Yes == Ans) { OnOK(); return; } else if(QMessageBox::Cancel == Ans) return; } // reject(); done(QDialog::Rejected); } void PlaneDlg::SetParams() { if(m_pPlane->body()) m_pctrlBody->setChecked(true); else m_pctrlBody->setChecked(false); m_pctrlBody->setEnabled(true); m_pctrlXBody->setEnabled(m_pPlane->m_bBody); m_pctrlZBody->setEnabled(m_pPlane->m_bBody); m_pctrlDefineBody->setEnabled(m_pPlane->m_bBody); m_pctrlImportBody->setEnabled(m_pPlane->m_bBody); m_pctrlPlaneName->setText(m_pPlane->PlaneName()); m_pctrlWingTilt->SetValue(m_pPlane->m_WingTiltAngle[0]); m_pctrlWingTilt2->SetValue(m_pPlane->m_WingTiltAngle[1]); m_pctrlStabTilt->SetValue(m_pPlane->m_WingTiltAngle[2]); m_pctrlFinTilt->SetValue(m_pPlane->m_WingTiltAngle[3]); m_pctrlXLEWing->SetValue(m_pPlane->m_WingLE[0].x * MainFrame::s_mtoUnit); m_pctrlZLEWing->SetValue(m_pPlane->m_WingLE[0].z * MainFrame::s_mtoUnit); m_pctrlXLEWing2->SetValue(m_pPlane->m_WingLE[1].x * MainFrame::s_mtoUnit); m_pctrlZLEWing2->SetValue(m_pPlane->m_WingLE[1].z * MainFrame::s_mtoUnit); m_pctrlXLEStab->SetValue(m_pPlane->m_WingLE[2].x * MainFrame::s_mtoUnit); m_pctrlZLEStab->SetValue(m_pPlane->m_WingLE[2].z * MainFrame::s_mtoUnit); m_pctrlXBody->SetValue(m_pPlane->m_BodyPos.x * MainFrame::s_mtoUnit); m_pctrlZBody->SetValue(m_pPlane->m_BodyPos.z * MainFrame::s_mtoUnit); m_pctrlBiplane->setChecked(m_pPlane->wing2()); OnBiplane(); m_pctrlXLEFin->SetValue(m_pPlane->m_WingLE[3].x* MainFrame::s_mtoUnit); m_pctrlYLEFin->SetValue(m_pPlane->m_WingLE[3].y* MainFrame::s_mtoUnit); m_pctrlZLEFin->SetValue(m_pPlane->m_WingLE[3].z* MainFrame::s_mtoUnit); m_pctrlFinCheck->setChecked(m_pPlane->m_bFin); m_pctrlDoubleFin->setChecked(m_pPlane->m_bDoubleFin); m_pctrlSymFin->setChecked(m_pPlane->m_bSymFin); OnFin(); m_pctrlStabCheck->setChecked(m_pPlane->stab()); OnStab(); } void PlaneDlg::SetResults() { QString str; // double area = m_pPlane->Wing()->s_Area; // if(m_pPlane->m_bBiplane) area += m_pPlane->Wing2()->m_Area; str = QString("%1").arg(m_pPlane->wing()->m_PlanformArea*MainFrame::s_m2toUnit,7,'f',2); m_pctrlWingSurface->setText(str); if(m_pPlane->stab()) str = QString("%1").arg(m_pPlane->stab()->m_PlanformArea*MainFrame::s_m2toUnit,7,'f',2); else str = " "; m_pctrlStabSurface->setText(str); if(m_pPlane->fin()) str = QString("%1").arg(m_pPlane->fin()->m_PlanformArea*MainFrame::s_m2toUnit,7,'f',2); else str=" "; m_pctrlFinSurface->setText(str); double span = m_pPlane->wing()->m_PlanformSpan; if(m_pPlane->wing2()) span = qMax(m_pPlane->wing()->m_PlanformSpan, m_pPlane->wing2()->m_PlanformSpan); str = QString("%1").arg(span*MainFrame::s_mtoUnit,5,'f',2); m_pctrlWingSpan->setText(str); ComputePlane(); if(m_pPlane->stab()) { double SLA = m_pPlane->m_WingLE[2].x + m_pPlane->stab()->Chord(0)/4.0 - m_pPlane->wing()->Chord(0)/4.0; str = QString("%1").arg(SLA*MainFrame::s_mtoUnit,5,'f',2); } else str=" "; m_pctrlStabLeverArm->setText(str); if(m_pPlane->stab()) { str = QString("%1").arg(m_pPlane->TailVolume(),5,'f',2); } else str =" "; m_pctrlStabVolume->setText(str); str = QString("%1").arg(m_pPlane->VLMPanelTotal()); m_pctrlVLMTotalPanels->setText(str); } void PlaneDlg::SetupLayout() { QGroupBox *NameBox = new QGroupBox(tr("Plane Description")); { QVBoxLayout *NameLayout = new QVBoxLayout; { m_pctrlPlaneName = new QLineEdit(tr("Plane Name")); // m_pctrlPlaneName->setMinimumWidth(120); m_pctrlPlaneDescription = new QTextEdit(); m_pctrlPlaneDescription->setToolTip(tr("Enter here a short description for the plane")); QLabel *PlaneDescription = new QLabel(tr("Description:")); m_pctrlPlaneInertia = new QPushButton(tr("Plane Inertia")); NameLayout->addWidget(m_pctrlPlaneName); NameLayout->addWidget(PlaneDescription); NameLayout->addWidget(m_pctrlPlaneDescription); NameLayout->addWidget(m_pctrlPlaneInertia); } NameBox->setLayout(NameLayout); } QGroupBox *MainWingBox = new QGroupBox(tr("Main Wing")); { QGridLayout *MainWingLayout = new QGridLayout; { m_pctrlDefineWing = new QPushButton(tr("Define")); m_pctrlImportWing = new QPushButton(tr("Import")); m_pctrlExportWing = new QPushButton(tr("Export")); QLabel *lab1 = new QLabel(tr("x=")); QLabel *lab2 = new QLabel(tr("z=")); QLabel *lab3 = new QLabel(tr("Tilt Angle=")); lab1->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab2->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab3->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlXLEWing = new DoubleEdit(0.00); m_pctrlZLEWing = new DoubleEdit(0.00); m_pctrlWingTilt = new DoubleEdit(0.0,2); m_pctrlLen1 = new QLabel("mm"); m_pctrlLen2 = new QLabel("mm"); QLabel *lab4 = new QLabel(QString::fromUtf8("°")); MainWingLayout->addWidget(m_pctrlDefineWing, 1,1); MainWingLayout->addWidget(m_pctrlImportWing, 2,1); MainWingLayout->addWidget(m_pctrlExportWing, 3,1); MainWingLayout->addWidget(lab1,1,2); MainWingLayout->addWidget(lab2,2,2); MainWingLayout->addWidget(lab3,3,2); MainWingLayout->addWidget(m_pctrlXLEWing,1,3); MainWingLayout->addWidget(m_pctrlZLEWing,2,3); MainWingLayout->addWidget(m_pctrlWingTilt,3,3); MainWingLayout->addWidget(m_pctrlLen1,1,4); MainWingLayout->addWidget(m_pctrlLen2,2,4); MainWingLayout->addWidget(lab4,3,4); } MainWingBox->setLayout(MainWingLayout); } QGroupBox *MainWing2Box = new QGroupBox(tr("Wing 2")); { QGridLayout *MainWing2Layout = new QGridLayout; { m_pctrlBiplane = new QCheckBox(tr("Biplane")); MainWing2Layout->addWidget(m_pctrlBiplane,1,1); m_pctrlDefineWing2 = new QPushButton(tr("Define")); m_pctrlImportWing2 = new QPushButton(tr("Import")); m_pctrlExportWing2 = new QPushButton(tr("Export")); QLabel *lab11 = new QLabel(tr("x=")); QLabel *lab12 = new QLabel(tr("z=")); QLabel *lab13 = new QLabel(tr("Tilt Angle=")); lab11->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab12->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab13->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlXLEWing2 = new DoubleEdit(0.00); m_pctrlZLEWing2 = new DoubleEdit(0.00); m_pctrlWingTilt2 = new DoubleEdit(0.0,2); m_pctrlLen3 = new QLabel("mm"); m_pctrlLen4 = new QLabel("mm"); QLabel *lab14 = new QLabel(QString::fromUtf8("°")); MainWing2Layout->addWidget(m_pctrlDefineWing2, 2,1); MainWing2Layout->addWidget(m_pctrlImportWing2, 3,1); MainWing2Layout->addWidget(m_pctrlExportWing2, 4,1); MainWing2Layout->addWidget(lab11,2,2); MainWing2Layout->addWidget(lab12,3,2); MainWing2Layout->addWidget(lab13,4,2); MainWing2Layout->addWidget(m_pctrlXLEWing2,2,3); MainWing2Layout->addWidget(m_pctrlZLEWing2,3,3); MainWing2Layout->addWidget(m_pctrlWingTilt2,4,3); MainWing2Layout->addWidget(m_pctrlLen3,2,4); MainWing2Layout->addWidget(m_pctrlLen4,3,4); MainWing2Layout->addWidget(lab14,4,4); } MainWing2Box->setLayout(MainWing2Layout); } QGroupBox *StabBox = new QGroupBox(tr("Elevator")); { QGridLayout *StabLayout = new QGridLayout; { m_pctrlStabCheck = new QCheckBox(tr("Elevator")); m_pctrlDefineStab = new QPushButton(tr("Define")); QLabel *lab21 = new QLabel(tr("x=")); QLabel *lab22 = new QLabel(tr("z=")); QLabel *lab23 = new QLabel(tr("Tilt Angle=")); lab21->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab22->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab23->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlXLEStab = new DoubleEdit(550.00); m_pctrlZLEStab = new DoubleEdit(550.00); m_pctrlStabTilt = new DoubleEdit(0.0,2); m_pctrlLen5 = new QLabel("mm"); m_pctrlLen6 = new QLabel("mm"); QLabel *lab24 = new QLabel(QString::fromUtf8("°")); StabLayout->addWidget(m_pctrlStabCheck,1,1); StabLayout->addWidget(m_pctrlDefineStab, 2,1); StabLayout->addWidget(lab21,2,2); StabLayout->addWidget(lab22,4,2); StabLayout->addWidget(lab23,5,2); StabLayout->addWidget(m_pctrlXLEStab,2,3); StabLayout->addWidget(m_pctrlZLEStab,4,3); StabLayout->addWidget(m_pctrlStabTilt,5,3); StabLayout->addWidget(m_pctrlLen5,2,4); StabLayout->addWidget(m_pctrlLen6,4,4); StabLayout->addWidget(lab24,5,4); } StabBox->setLayout(StabLayout); } QGroupBox *FinBox = new QGroupBox(tr("Fin")); { QGridLayout *FinLayout = new QGridLayout; { m_pctrlFinCheck = new QCheckBox(tr("Fin")); m_pctrlDefineFin = new QPushButton(tr("Define")); m_pctrlDoubleFin = new QCheckBox(tr("Double Fin")); m_pctrlSymFin = new QCheckBox(tr("Two-sided Fin")); QLabel *lab31 = new QLabel(tr("x=")); QLabel *lab32 = new QLabel(tr("y=")); QLabel *lab33 = new QLabel(tr("z=")); QLabel *lab34 = new QLabel(tr("Tilt Angle=")); lab31->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab32->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab33->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab34->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlXLEFin = new DoubleEdit(600.00); m_pctrlYLEFin = new DoubleEdit(0.00); m_pctrlZLEFin = new DoubleEdit(50.00); m_pctrlFinTilt = new DoubleEdit(0.0,2); m_pctrlLen7= new QLabel("mm"); m_pctrlLen8 = new QLabel("mm"); m_pctrlLen9 = new QLabel("mm"); QLabel *lab35 = new QLabel(QString::fromUtf8("°")); FinLayout->addWidget(m_pctrlFinCheck,1,1); FinLayout->addWidget(m_pctrlDefineFin, 2,1); FinLayout->addWidget(m_pctrlSymFin, 3,1); FinLayout->addWidget(m_pctrlDoubleFin, 4,1); FinLayout->addWidget(lab31,2,2); FinLayout->addWidget(lab32,3,2); FinLayout->addWidget(lab33,4,2); FinLayout->addWidget(lab34,5,2); FinLayout->addWidget(m_pctrlXLEFin,2,3); FinLayout->addWidget(m_pctrlYLEFin,3,3); FinLayout->addWidget(m_pctrlZLEFin,4,3); FinLayout->addWidget(m_pctrlFinTilt,5,3); FinLayout->addWidget(m_pctrlLen7,2,4); FinLayout->addWidget(m_pctrlLen8,3,4); FinLayout->addWidget(m_pctrlLen9,4,4); FinLayout->addWidget(lab35,5,4); } FinBox->setLayout(FinLayout); } QGroupBox *BodyBox = new QGroupBox(tr("Body")); { QHBoxLayout *BodyName = new QHBoxLayout; { m_pctrlBody = new QCheckBox(tr("Body")); m_pctrlDefineBody = new QPushButton(tr("Define")); m_pctrlImportBody = new QPushButton(tr("Import")); BodyName->addWidget(m_pctrlBody); BodyName->addWidget(m_pctrlDefineBody); BodyName->addWidget(m_pctrlImportBody); // m_pctrlBodyList->setMinimumWidth(250); BodyName->addStretch(1); } QGridLayout *BodyPos = new QGridLayout; { BodyPos->setColumnStretch(0,3); BodyPos->setColumnStretch(1,0); BodyPos->setColumnStretch(2,0); m_pctrlXBody = new DoubleEdit(0.00); m_pctrlZBody = new DoubleEdit(0.00); QLabel *lab41 = new QLabel(tr("x=")); QLabel *lab42 = new QLabel(tr("z=")); m_pctrlLen10 = new QLabel("mm"); m_pctrlLen11 = new QLabel("mm"); BodyPos->addWidget(lab41,1,1); BodyPos->addWidget(m_pctrlXBody,1,2); BodyPos->addWidget(m_pctrlLen10,1,3); BodyPos->addWidget(lab42,2,1); BodyPos->addWidget(m_pctrlZBody,2,2); BodyPos->addWidget(m_pctrlLen11,2,3); } QVBoxLayout *BodyLayout = new QVBoxLayout; { QLabel *BodyWarning = new QLabel(tr("Warning:\nIncluding the body in the analysis is not recommended.\nCheck the guidelines for explanations.")); BodyLayout->addWidget(BodyWarning); BodyLayout->addLayout(BodyName); BodyLayout->addLayout(BodyPos); } BodyBox->setLayout(BodyLayout); } QGridLayout *Data1Layout = new QGridLayout; { QLabel *lab101 = new QLabel(tr("Wing Area = ")); QLabel *lab102 = new QLabel(tr("Wing Span = ")); QLabel *lab103 = new QLabel(tr("Elev. Area = ")); QLabel *lab104 = new QLabel(tr("Elev. Lever Arm = ")); lab101->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab102->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab103->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab104->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlWingSurface = new QLabel("1.00"); m_pctrlStabSurface = new QLabel("2.00"); m_pctrlWingSpan = new QLabel("3.00"); m_pctrlStabLeverArm = new QLabel("4.00"); m_pctrlFinSurface = new QLabel("5.00"); m_pctrlStabVolume = new QLabel("6.00"); m_pctrlVLMTotalPanels = new QLabel("1234"); m_pctrlWingSurface->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlStabSurface->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlWingSpan->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlStabLeverArm->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlSurf1 = new QLabel("dm2"); m_pctrlSurf2 = new QLabel("dm2"); m_pctrlSurf3 = new QLabel("dm2"); m_pctrlLen12 = new QLabel("mm"); m_pctrlLen13 = new QLabel("mm"); m_pctrlVolume = new QLabel("mm3"); Data1Layout->addWidget(lab101, 1, 1); Data1Layout->addWidget(m_pctrlWingSurface,1,2); Data1Layout->addWidget(m_pctrlSurf1, 1, 3); Data1Layout->addWidget(lab102, 2, 1); Data1Layout->addWidget(m_pctrlWingSpan, 2, 2); Data1Layout->addWidget(m_pctrlLen12, 2, 3); Data1Layout->addWidget(lab103, 3, 1); Data1Layout->addWidget(m_pctrlStabSurface, 3, 2); Data1Layout->addWidget(m_pctrlSurf2, 3, 3); Data1Layout->addWidget(lab104, 4, 1); Data1Layout->addWidget(m_pctrlStabLeverArm, 4, 2); Data1Layout->addWidget(m_pctrlLen13, 4, 3); } QGridLayout *Data2Layout = new QGridLayout; { QLabel *lab105 = new QLabel(tr("Fin Area = ")); QLabel *lab106 = new QLabel(tr("TailVolume = ")); QLabel *lab108 = new QLabel(tr("Total Panels = ")); lab105->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab106->setAlignment(Qt::AlignRight | Qt::AlignVCenter); lab108->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlFinSurface->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlStabVolume->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlVLMTotalPanels->setAlignment(Qt::AlignRight | Qt::AlignVCenter); Data2Layout->addWidget(lab105, 1, 1); Data2Layout->addWidget(m_pctrlFinSurface, 1, 2); Data2Layout->addWidget(m_pctrlSurf3, 1, 3); Data2Layout->addWidget(lab106, 2, 1); Data2Layout->addWidget(m_pctrlStabVolume, 2, 2); Data2Layout->addWidget(lab108, 3, 1); Data2Layout->addWidget(m_pctrlVLMTotalPanels, 3, 2); } QHBoxLayout *CommandButtonsLayout = new QHBoxLayout; { OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(OKButton); CommandButtonsLayout->addStretch(1); CommandButtonsLayout->addWidget(CancelButton); CommandButtonsLayout->addStretch(1); } QGridLayout *GeomLayout = new QGridLayout; { GeomLayout->addWidget(NameBox,1,1); GeomLayout->addWidget(BodyBox,1,2); GeomLayout->addWidget(MainWingBox,2,1); GeomLayout->addWidget(MainWing2Box,2,2); GeomLayout->addWidget(StabBox,3,1); GeomLayout->addWidget(FinBox,3,2); GeomLayout->addLayout(Data1Layout,4,1); GeomLayout->addLayout(Data2Layout,4,2); } QVBoxLayout *MainLayout = new QVBoxLayout; { MainLayout->addStretch(1); MainLayout->addLayout(GeomLayout); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtonsLayout); MainLayout->addStretch(1); } setLayout(MainLayout); } xflr5-6.09-06/src/miarex/BodyScaleDlg.h000644 001750 000144 00000003511 12247174401 021011 0ustar00techwinderusers000000 000000 /**************************************************************************** BodyScaleDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef BODYSCALEDLG_H #define BODYSCALEDLG_H #include #include #include #include #include #include "../misc/DoubleEdit.h" class BodyScaleDlg : public QDialog { Q_OBJECT friend class GL3dBodyDlg; friend class Body; friend class MainFrame; public: BodyScaleDlg(QWidget *pParent); private slots: void OnOK(); void OnRadio(); void OnEditingFinished(); private: void SetupLayout(); void InitDialog(); void EnableControls(); void keyPressEvent(QKeyEvent *event); private: static void *s_pMainFrame; QPushButton *OKButton, *CancelButton; QRadioButton *m_pctrlBody, *m_pctrlFrame; DoubleEdit *m_pctrlXScaleFactor; DoubleEdit *m_pctrlYScaleFactor; DoubleEdit *m_pctrlZScaleFactor; DoubleEdit *m_pctrlFrameID; private: void *m_pBodyDlg; double m_XFactor, m_YFactor, m_ZFactor; bool m_bFrameOnly; int m_FrameID; }; #endif // BODYGRIDDLG_H xflr5-6.09-06/src/miarex/InertiaDlg.h000644 001750 000144 00000006350 12247174402 020544 0ustar00techwinderusers000000 000000 /**************************************************************************** InertiaDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef INERTIADLG_H #define INERTIADLG_H #include #include #include #include #include #include #include #include "../params.h" #include "../misc/FloatEditDelegate.h" #include "../misc/DoubleEdit.h" #include "../objects/CVector.h" #include "../objects/Plane.h" class InertiaDlg : public QDialog { Q_OBJECT friend class GL3dWingDlg; friend class GL3dBodyDlg; friend class PlaneDlg; friend class QMiarex; friend class MainFrame; public: InertiaDlg(QWidget *pParent); ~InertiaDlg(); void InitDialog(); private slots: void OnOK(); void OnBodyInertia(); void OnWingInertia(); void OnWing2Inertia(); void OnStabInertia(); void OnFinInertia(); void OnCellChanged(QWidget *pWidget=NULL); void OnExportToAVL(); void OnInsertMassRow(); void OnDeleteMassRow(); private: void contextMenuEvent(QContextMenuEvent *event); void keyPressEvent(QKeyEvent *event); void resizeEvent(QResizeEvent *event); void showEvent(QShowEvent *event); void FillMassModel(); void ClearPointMasses(); void ComputeInertia(); void ComputeBodyAxisInertia(); void SetupLayout(); void ReadData(); //layout widget variables QStackedWidget *m_pctrlTopStack; QPushButton *m_pctrlWingInertia, *m_pctrlWing2Inertia, *m_pctrlStabInertia, *m_pctrlFinInertia, *m_pctrlBodyInertia; QPushButton *OKButton; QLabel *m_pctrlMassUnit, *m_pctrlMassUnit2, *m_pctrlLengthUnit, *m_pctrlLengthUnit2; QLabel *m_pctrlVolumeMassLabel, *m_pctrlTotalMassLabel; QLabel *m_pctrlInertiaUnit1, *m_pctrlInertiaUnit2; QTableView *m_pctrlMassTable; QStandardItemModel *m_pMassModel; FloatEditDelegate *m_pFloatDelegate; DoubleEdit *m_pctrlCoGIxx, *m_pctrlCoGIyy, *m_pctrlCoGIzz, *m_pctrlCoGIxz; DoubleEdit *m_pctrlXCoG,*m_pctrlYCoG,*m_pctrlZCoG; DoubleEdit *m_pctrlVolumeMass; DoubleEdit *m_pctrlTotalIxx, *m_pctrlTotalIyy, *m_pctrlTotalIzz, *m_pctrlTotalIxz; DoubleEdit *m_pctrlXTotalCoG,*m_pctrlYTotalCoG,*m_pctrlZTotalCoG; DoubleEdit *m_pctrlTotalMass; QMenu *m_pContextMenu; QAction *m_pInsertMassRow, *m_pDeleteMassRow; //member variables Body *m_pBody; Wing *m_pWing; Plane *m_pPlane; double m_VolumeMass; CVector m_VolumeCoG; double m_CoGIxx, m_CoGIyy, m_CoGIzz, m_CoGIxz; QList m_PointMass; bool m_bChanged; }; #endif // INERTIADLG_H xflr5-6.09-06/src/miarex/InertiaDlg.cpp000644 001750 000144 00000116751 12247174402 021106 0ustar00techwinderusers000000 000000 /**************************************************************************** InertiaDlg Class Copyright (C) 2009-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ //performs an automatic evaluation of the object's CoG an inertia properties #include #include #include #include #include #include #include #include #include "../mainframe.h" #include "../globals.h" #include "InertiaDlg.h" InertiaDlg::InertiaDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Inertia Properties")); m_pPlane = NULL; m_pWing = NULL; m_pBody = NULL; m_CoGIxx = m_CoGIyy = m_CoGIzz = m_CoGIxz = 0.0; m_VolumeMass = 0.0; ClearPointMasses(); m_bChanged = false; m_pInsertMassRow = new QAction(tr("Insert Before"), this); m_pDeleteMassRow = new QAction(tr("Delete"), this); m_pContextMenu = new QMenu(tr("Point Mass"),this); m_pContextMenu->addAction(m_pInsertMassRow); m_pContextMenu->addAction(m_pDeleteMassRow); SetupLayout(); } InertiaDlg::~InertiaDlg() { ClearPointMasses(); delete m_pMassModel; } /** Destroys the PointMass objects in good order to avoid memory leaks */ void InertiaDlg::ClearPointMasses() { for(int ipm=m_PointMass.size()-1; ipm>=0; ipm--) { delete m_PointMass.at(ipm); m_PointMass.removeAt(ipm); } } void InertiaDlg::ComputeBodyAxisInertia() { if(m_pPlane) m_pPlane->ComputeBodyAxisInertia(); else if(m_pWing) m_pWing->ComputeBodyAxisInertia(); else if(m_pBody) m_pBody->ComputeBodyAxisInertia(); } /** * Computes the inertia in the frame of reference with origin at the CoG. * * Assumes that the data has been read. */ void InertiaDlg::ComputeInertia() { int i, iw; double TotalMass, TotalIxx, TotalIyy, TotalIzz, TotalIxz; double Unit = MainFrame::s_mtoUnit * MainFrame::s_mtoUnit * MainFrame::s_kgtoUnit; CVector TotalCoG, MassPos; m_CoGIxx = m_CoGIyy = m_CoGIzz = m_CoGIxz = 0.0; m_VolumeCoG.Set(0.0, 0.0, 0.0); Wing *pWing[MAXWINGS]; pWing[0] = pWing[1] = pWing[2] = pWing[3] = NULL; if(m_pPlane) { pWing[0] = m_pPlane->wing(); if(m_pPlane->BiPlane()) pWing[1] = m_pPlane->wing2(); if(m_pPlane->stab()) pWing[2] = m_pPlane->stab(); if(m_pPlane->fin()) pWing[3] = m_pPlane->fin(); } else if(m_pWing) { pWing[0] = m_pWing; } // First evaluate the object's volume inertia, i.e. without point masses, // in the frame of reference with origin at the object's self CoG if(m_pWing) { m_pWing->m_VolumeMass = m_VolumeMass; if(m_pWing->m_VolumeMass>PRECISION) m_pWing->ComputeVolumeInertia(m_VolumeCoG, m_CoGIxx, m_CoGIyy, m_CoGIzz, m_CoGIxz); } else if(m_pBody) { m_pBody->m_VolumeMass = m_VolumeMass; if(m_pBody->m_VolumeMass>PRECISION) m_pBody->ComputeVolumeInertia(m_VolumeCoG, m_CoGIxx, m_CoGIyy, m_CoGIzz, m_CoGIxz); } else if(m_pPlane) { m_pPlane->ComputeVolumeInertia(m_VolumeMass, m_VolumeCoG, m_CoGIxx, m_CoGIyy, m_CoGIzz, m_CoGIxz); } // and display the results m_pctrlXCoG->SetValue(m_VolumeCoG.x*MainFrame::s_mtoUnit); m_pctrlYCoG->SetValue(m_VolumeCoG.y*MainFrame::s_mtoUnit); m_pctrlZCoG->SetValue(m_VolumeCoG.z*MainFrame::s_mtoUnit); m_pctrlCoGIxx->SetValue(m_CoGIxx*Unit); m_pctrlCoGIyy->SetValue(m_CoGIyy*Unit); m_pctrlCoGIzz->SetValue(m_CoGIzz*Unit); m_pctrlCoGIxz->SetValue(m_CoGIxz*Unit); // take into account all point masses to calculate the total CoG and total mass TotalCoG.Set(m_VolumeMass*m_VolumeCoG.x, m_VolumeMass*m_VolumeCoG.y, m_VolumeMass*m_VolumeCoG.z); TotalMass = m_VolumeMass; TotalIxx = TotalIyy = TotalIzz = TotalIxz = 0.0; for(i=0; imass(); TotalCoG += m_PointMass[i]->position() * m_PointMass[i]->mass(); } if(m_pPlane) { for(iw=0; iwm_PointMass.size(); i++) { TotalMass += pWing[iw]->m_PointMass[i]->mass(); TotalCoG += (pWing[iw]->m_PointMass[i]->position() + m_pPlane->WingLE(iw)) * pWing[iw]->m_PointMass[i]->mass(); } } } } if(m_pPlane && m_pPlane->body()) { for(i=0; ibody()->m_PointMass.size(); i++) { TotalMass += m_pPlane->body()->m_PointMass[i]->mass(); TotalCoG += (m_pPlane->body()->m_PointMass[i]->position()+m_pPlane->BodyPos()) * m_pPlane->body()->m_PointMass[i]->mass(); } } if(TotalMass>PRECISION) TotalCoG *= 1.0/TotalMass; else TotalCoG.Set(0.0,0.0,0.0); //Total inertia in CoG referential //Apply Huyghens theorem to convert the object's inertia to the new frame CVector LA = TotalCoG - m_VolumeCoG; TotalIxx = m_CoGIxx + m_VolumeMass * (LA.y*LA.y+ LA.z*LA.z); TotalIyy = m_CoGIyy + m_VolumeMass * (LA.x*LA.x+ LA.z*LA.z); TotalIzz = m_CoGIzz + m_VolumeMass * (LA.x*LA.x+ LA.y*LA.y); TotalIxz = m_CoGIxz - m_VolumeMass * LA.x*LA.z; //add the inertia contribution of all point masses in the Total CoG frame of reference for(i=0; imass()>PRECISION) { MassPos = TotalCoG - m_PointMass[i]->position(); TotalIxx += m_PointMass[i]->mass() * (MassPos.y*MassPos.y + MassPos.z*MassPos.z); TotalIyy += m_PointMass[i]->mass() * (MassPos.x*MassPos.x + MassPos.z*MassPos.z); TotalIzz += m_PointMass[i]->mass() * (MassPos.x*MassPos.x + MassPos.y*MassPos.y); TotalIxz -= m_PointMass[i]->mass() * (MassPos.x*MassPos.z); } } if(m_pPlane || m_pWing) { for(iw=0; iwm_PointMass.size(); i++) { MassPos = TotalCoG - (pWing[iw]->m_PointMass[i]->position() + (m_pPlane != NULL ? m_pPlane->WingLE(iw) : CVector(0.0, 0.0, 0.0))); TotalIxx += pWing[iw]->m_PointMass[i]->mass() * (MassPos.y*MassPos.y + MassPos.z*MassPos.z); TotalIyy += pWing[iw]->m_PointMass[i]->mass() * (MassPos.x*MassPos.x + MassPos.z*MassPos.z); TotalIzz += pWing[iw]->m_PointMass[i]->mass() * (MassPos.x*MassPos.x + MassPos.y*MassPos.y); TotalIxz -= pWing[iw]->m_PointMass[i]->mass() * (MassPos.x*MassPos.z); } } } if(m_pPlane && m_pPlane->body()) { for(i=0; ibody()->m_PointMass.size(); i++) { MassPos = TotalCoG - (m_pPlane->BodyPos() + m_pPlane->body()->m_PointMass[i]->position()); TotalIxx += m_pPlane->body()->m_PointMass[i]->mass() * (MassPos.y*MassPos.y + MassPos.z*MassPos.z); TotalIyy += m_pPlane->body()->m_PointMass[i]->mass() * (MassPos.x*MassPos.x + MassPos.z*MassPos.z); TotalIzz += m_pPlane->body()->m_PointMass[i]->mass() * (MassPos.x*MassPos.x + MassPos.y*MassPos.y); TotalIxz -= m_pPlane->body()->m_PointMass[i]->mass() * (MassPos.x*MassPos.z); } } } //display the results m_pctrlTotalMass->SetValue(TotalMass*MainFrame::s_kgtoUnit); m_pctrlXTotalCoG->SetValue(TotalCoG.x*MainFrame::s_mtoUnit); m_pctrlYTotalCoG->SetValue(TotalCoG.y*MainFrame::s_mtoUnit); m_pctrlZTotalCoG->SetValue(TotalCoG.z*MainFrame::s_mtoUnit); m_pctrlTotalIxx->SetValue(TotalIxx*Unit); m_pctrlTotalIyy->SetValue(TotalIyy*Unit); m_pctrlTotalIzz->SetValue(TotalIzz*Unit); m_pctrlTotalIxz->SetValue(TotalIxz*Unit); } void InertiaDlg::contextMenuEvent(QContextMenuEvent *event) { // Display the context menu if(m_pctrlMassTable->geometry().contains(event->pos())) m_pContextMenu->exec(event->globalPos()); } /** * Fills the table with the object's point masses. */ void InertiaDlg::FillMassModel() { QModelIndex index; m_pMassModel->setRowCount(m_PointMass.size()+1); int i; for(i=0; imass()>PRECISION || m_PointMass[i]->tag().length()) { index = m_pMassModel->index(i, 0, QModelIndex()); m_pMassModel->setData(index, m_PointMass[i]->mass()*MainFrame::s_kgtoUnit); index = m_pMassModel->index(i, 1, QModelIndex()); m_pMassModel->setData(index, m_PointMass[i]->position().x*MainFrame::s_mtoUnit); index = m_pMassModel->index(i, 2, QModelIndex()); m_pMassModel->setData(index, m_PointMass[i]->position().y*MainFrame::s_mtoUnit); index = m_pMassModel->index(i, 3, QModelIndex()); m_pMassModel->setData(index, m_PointMass[i]->position().z*MainFrame::s_mtoUnit); index = m_pMassModel->index(i, 4, QModelIndex()); m_pMassModel->setData(index, m_PointMass[i]->tag()); } } //add an extra empty line for a new mass index = m_pMassModel->index(i, 0, QModelIndex()); m_pMassModel->setData(index, 0.0); index = m_pMassModel->index(i, 1, QModelIndex()); m_pMassModel->setData(index, 0.0); index = m_pMassModel->index(i, 2, QModelIndex()); m_pMassModel->setData(index, 0.0); index = m_pMassModel->index(i, 3, QModelIndex()); m_pMassModel->setData(index, 0.0); index = m_pMassModel->index(i, 4, QModelIndex()); m_pMassModel->setData(index, ""); } void InertiaDlg::InitDialog() { QString strong, strMass, strLength; GetWeightUnit(strMass, MainFrame::s_WeightUnit); GetLengthUnit(strLength, MainFrame::s_LengthUnit); m_pctrlMassUnit->setText(strMass); m_pctrlMassUnit2->setText(strMass); m_pctrlLengthUnit->setText(strLength); m_pctrlLengthUnit2->setText(strLength); strong = strMass+"."+strLength+QString::fromUtf8("²"); m_pctrlInertiaUnit1->setText(strong); m_pctrlInertiaUnit2->setText(strong); m_pMassModel->setHeaderData(0, Qt::Horizontal, tr("Mass") +" ("+strMass+")"); m_pMassModel->setHeaderData(1, Qt::Horizontal, tr("x") +" ("+strLength+")"); m_pMassModel->setHeaderData(2, Qt::Horizontal, tr("y")+" ("+strLength+")"); m_pMassModel->setHeaderData(3, Qt::Horizontal, tr("z")+" ("+strLength+")"); m_pMassModel->setHeaderData(4, Qt::Horizontal, tr("Description")); m_pctrlWingInertia->setEnabled(false); m_pctrlWing2Inertia->setEnabled(false); m_pctrlStabInertia->setEnabled(false); m_pctrlFinInertia->setEnabled(false); m_pctrlBodyInertia->setEnabled(false); int rc = m_pMassModel->rowCount(); m_pMassModel->removeRows(0, rc); ClearPointMasses(); if(m_pWing) { m_VolumeMass = m_pWing->m_VolumeMass; for(int i=0; im_PointMass.size(); i++) { m_PointMass.append(new PointMass(m_pWing->m_PointMass[i])); } m_pctrlVolumeMass->SetValue(m_pWing->m_VolumeMass * MainFrame::s_kgtoUnit); //we only display half a wing, AVL way m_pctrlVolumeMassLabel->setText(tr("Wing Mass:")); m_pctrlWingInertia->setEnabled(true); setWindowTitle(tr("Inertia properties for ")+m_pWing->m_WingName); } else if (m_pBody) { m_VolumeMass = m_pBody->m_VolumeMass; for(int i=0; im_PointMass.size(); i++) { m_PointMass.append(new PointMass(m_pBody->m_PointMass[i]->mass(), m_pBody->m_PointMass[i]->position(), m_pBody->m_PointMass[i]->tag())); } m_pctrlVolumeMass->SetValue(m_pBody->m_VolumeMass * MainFrame::s_kgtoUnit); m_pctrlVolumeMassLabel->setText(tr("Body Mass:")); m_pctrlBodyInertia->setEnabled(true); setWindowTitle(tr("Inertia properties for ")+m_pBody->m_BodyName); } else if (m_pPlane) { m_VolumeMass = m_pPlane->wing()->m_VolumeMass; if(m_pPlane->BiPlane()) m_VolumeMass += m_pPlane->wing2()->m_VolumeMass; if(m_pPlane->stab()) m_VolumeMass += m_pPlane->stab()->m_VolumeMass; if(m_pPlane->fin()) m_VolumeMass += m_pPlane->fin()->m_VolumeMass; if(m_pPlane->body()) m_VolumeMass += m_pPlane->body()->m_VolumeMass; for(int i=0; im_PointMass.size(); i++) { m_PointMass.append(new PointMass(m_pPlane->m_PointMass[i])); } m_pctrlVolumeMass->SetValue(m_VolumeMass * MainFrame::s_kgtoUnit); m_pctrlVolumeMassLabel->setText(tr("Volume Mass:")); m_pctrlVolumeMass->setEnabled(false); m_pctrlWingInertia->setEnabled(true); if(m_pPlane->BiPlane()) m_pctrlWing2Inertia->setEnabled(true); if(m_pPlane->stab()) m_pctrlStabInertia->setEnabled(true); if(m_pPlane->fin()) m_pctrlFinInertia->setEnabled(true); if(m_pPlane->body()) m_pctrlBodyInertia->setEnabled(true); setWindowTitle(tr("Inertia properties for ")+m_pPlane->PlaneName()); } if(m_pPlane) m_pctrlTopStack->setCurrentIndex(1); else m_pctrlTopStack->setCurrentIndex(0); FillMassModel(); ComputeInertia(); setFocus(); } void InertiaDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus()) OKButton->setFocus(); else accept(); break; } case Qt::Key_Escape: { reject(); return; } default: event->ignore(); } } void InertiaDlg::OnCellChanged(QWidget *pWidget) { ReadData(); ComputeInertia(); m_bChanged = true; FillMassModel();//to add an empty line } /** * Exports the mass and inertia data to AVL format */ void InertiaDlg::OnExportToAVL() { if (!m_pWing && !m_pBody && !m_pPlane) return; QString filter =".mass"; QString FileName, strong; double CoGIxx, CoGIyy, CoGIzz, CoGIxz; CVector CoG; Wing *pWing[MAXWINGS]; pWing[0] = pWing[1] = pWing[2] = pWing[3] = NULL; if(m_pPlane) { pWing[0] = m_pPlane->wing(); if(m_pPlane->BiPlane()) pWing[1] = m_pPlane->wing2(); if(m_pPlane->stab()) pWing[2] = m_pPlane->stab(); if(m_pPlane->fin()) pWing[3] = m_pPlane->fin(); } else { pWing[0] = m_pWing; } if(m_pPlane) FileName = m_pPlane->PlaneName(); else if(m_pWing) FileName = m_pWing->m_WingName; else if(m_pBody) FileName = m_pBody->m_BodyName; FileName.replace("/", " "); FileName += ".mass"; FileName = QFileDialog::getSaveFileName(this, tr("Export Mass Properties"),MainFrame::s_LastDirName + "/"+FileName, tr("AVL Mass File (*.mass)"), &filter); if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); pos = FileName.lastIndexOf("."); if(pos<0) FileName += ".mass"; QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&XFile); out.setCodec("UTF-8"); double Lunit = 1./MainFrame::s_mtoUnit; double Munit = 1./MainFrame::s_kgtoUnit; double Iunit = Munit * Lunit * Lunit; out << "#-------------------------------------------------\n"; out << "#\n"; if(m_pPlane) out << "# "+m_pPlane->PlaneName()+"\n"; else if(m_pWing) out << "# "+m_pWing->m_WingName+"\n"; else if(m_pBody) out << "# "+m_pBody->m_BodyName+"\n"; out << "#\n"; out << "# Dimensional unit and parameter data.\n"; out << "# Mass & Inertia breakdown.\n"; out << "#-------------------------------------------------\n"; out << "# Names and scalings for units to be used for trim and eigenmode calculations.\n"; out << "# The Lunit and Munit values scale the mass, xyz, and inertia table data below.\n"; out << "# Lunit value will also scale all lengths and areas in the AVL input file.\n"; out << "#\n"; strong = QString("Lunit = %1 m").arg(Lunit,10,'f',4); out << strong+"\n"; strong = QString("Munit = %1 kg").arg(Munit,10,'f',4); out << strong+"\n"; out << "Tunit = 1.0 s\n"; out << "#-------------------------\n"; out << "# Gravity and density to be used as default values in trim setup (saves runtime typing).\n"; out << "# Must be in the unit names given above (i.e. m,kg,s).\n"; out << "g = 9.81\n"; out << "rho = 1.225\n"; out << "#-------------------------\n"; out << "# Mass & Inertia breakdown.\n"; out << "# x y z is location of item's own CG.\n"; out << "# Ixx... are item's inertias about item's own CG.\n"; out << "#\n"; out << "# x,y,z system here must be exactly the same one used in the .avl input file\n"; out << "# (same orientation, same origin location, same length units)\n"; out << "#\n"; out << "# mass x y z Ixx Iyy Izz Ixy Ixz Iyz \n"; if(m_pWing) { // in accordance with AVL input format, // we need to convert the inertia in the wing's CoG system // by applying Huyghen/Steiner's theorem strong = QString(tr("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10! Inertia of both left and right wings")) .arg(m_VolumeMass /Munit, 10, 'g', 3) .arg(m_VolumeCoG.x/Lunit, 10, 'g', 3) .arg(m_VolumeCoG.y/Lunit, 10, 'g', 3) //should be zero .arg(m_VolumeCoG.z/Lunit, 10, 'g', 3) .arg(m_CoGIxx/Iunit, 10, 'g', 3) .arg(m_CoGIyy/Iunit, 10, 'g', 3) .arg(m_CoGIzz/Iunit, 10, 'g', 3) .arg(0.0, 10, 'g', 3).arg(m_CoGIxz/Iunit, 10, 'g', 3).arg(0.0, 10, 'g', 3); out << strong+"\n"; } else if (m_pBody) { strong = QString(tr("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Body inertia")) .arg(m_VolumeMass /Munit, 10, 'g', 3) .arg(m_VolumeCoG.x/Lunit, 10, 'g', 3) .arg(m_VolumeCoG.y/Lunit, 10, 'g', 3) .arg(m_VolumeCoG.z/Lunit, 10, 'g', 3) .arg(m_CoGIxx/Iunit, 10, 'g', 3) .arg(m_CoGIyy/Iunit, 10, 'g', 3) .arg(m_CoGIzz/Iunit, 10, 'g', 3) .arg(0.0,10, 'g', 3) .arg(m_CoGIxz/Iunit,10, 'g', 3) .arg(0.0,10, 'g', 3); out << strong+"\n"; } else if (m_pPlane) { // we write out each object contribution individually for(int iw=0; iwComputeVolumeInertia(CoG, CoGIxx, CoGIyy, CoGIzz, CoGIxz); strong = QString(tr("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! ")) .arg(pWing[iw]->m_VolumeMass /Munit, 10, 'g', 3) .arg(CoG.x/Lunit, 10, 'g', 3) .arg(CoG.y/Lunit, 10, 'g', 3) .arg(CoG.z/Lunit, 10, 'g', 3) .arg(CoGIxx/Iunit,10, 'g', 3) .arg(CoGIyy/Iunit,10, 'g', 3) .arg(CoGIzz/Iunit,10, 'g', 3) .arg(0.0,10, 'g', 3) .arg(CoGIxz/Iunit,10, 'g', 3) .arg(0.0,10, 'g', 3); strong += pWing[iw]->m_WingName; out << strong+"\n"; } } if(m_pPlane->body()) { m_pPlane->body()->ComputeVolumeInertia(CoG, CoGIxx, CoGIyy, CoGIzz, CoGIxz); strong = QString(tr("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 ! Body's inertia")) .arg(m_pPlane->body()->m_VolumeMass /Munit, 10, 'g', 3) .arg(CoG.x/Lunit, 10, 'g', 3) .arg(CoG.y/Lunit, 10, 'g', 3) .arg(CoG.z/Lunit, 10, 'g', 3) .arg(CoGIxx/Iunit,10, 'g', 3) .arg(CoGIyy/Iunit,10, 'g', 3) .arg(CoGIzz/Iunit,10, 'g', 3) .arg(0.0,10, 'g', 3) .arg(CoGIxz/Iunit,10, 'g', 3) .arg(0.0,10, 'g', 3); /* .arg(m_pPlane->Body()->m_VolumeMass /Munit, 10, 'g', 3) .arg(m_pPlane->Body()->m_VolumeCoG.x/Lunit, 10, 'g', 3) .arg(m_pPlane->Body()->m_VolumeCoG.y/Lunit, 10, 'g', 3) .arg(m_pPlane->Body()->m_VolumeCoG.z/Lunit, 10, 'g', 3) .arg(m_pPlane->Body()->m_CoGIxx/Iunit,10, 'g', 3) .arg(m_pPlane->Body()->m_CoGIyy/Iunit,10, 'g', 3) .arg(m_pPlane->Body()->m_CoGIzz/Iunit,10, 'g', 3) .arg(0.0,10, 'g', 3) .arg(m_pPlane->Body()->m_CoGIxz/Iunit,10, 'g', 3) .arg(0.0,10, 'g', 3); */ out << strong+"\n"; } } for (int i=0; imass()>0.0) { strong = QString("%1 %2 %3 %4 0.000 0.000 0.000") .arg(m_PointMass[i]->mass() / Munit, 10, 'g', 3) .arg(m_PointMass[i]->position().x/Lunit, 10, 'g', 3) .arg(m_PointMass[i]->position().y/Lunit, 10, 'g', 3) .arg(m_PointMass[i]->position().z/Lunit, 10, 'g', 3); strong += " ! " + m_PointMass[i]->tag(); out << strong+"\n"; } } if(m_pPlane) { // need to write the point masses for the objects //Main Wing for(int iw=0; iwm_PointMass.size(); i++) { if(m_pPlane->wing()->m_PointMass[i]->mass()>0.0) { strong = QString("%1 %2 %3 %4 0.000 0.000 0.000") .arg(pWing[iw]->m_PointMass[i]->mass() / Munit, 10, 'g', 3) .arg((pWing[iw]->m_PointMass[i]->position().x+m_pPlane->WingLE(iw).x)/Lunit, 10, 'g', 3) .arg((pWing[iw]->m_PointMass[i]->position().y+m_pPlane->WingLE(iw).y)/Lunit, 10, 'g', 3) .arg((pWing[iw]->m_PointMass[i]->position().z+m_pPlane->WingLE(iw).z)/Lunit, 10, 'g', 3); strong += " ! " + pWing[iw]->m_PointMass[i]->tag(); out << strong+"\n"; } } } } if(m_pPlane->body()) { //fin for (int i=0; ibody()->m_PointMass.size(); i++) { if(m_pPlane->body()->m_PointMass[i]->mass()>0.0) { strong = QString("%1 %2 %3 %4 0.000 0.000 0.000") .arg(m_pPlane->body()->m_PointMass[i]->mass() / Munit, 10, 'g', 3) .arg(m_pPlane->body()->m_PointMass[i]->position().x/Lunit, 10, 'g', 3) .arg(m_pPlane->body()->m_PointMass[i]->position().y/Lunit, 10, 'g', 3) .arg(m_pPlane->body()->m_PointMass[i]->position().z/Lunit, 10, 'g', 3); strong += " ! " + m_pPlane->body()->m_PointMass[i]->tag(); out << strong+"\n"; } } } } XFile.close(); } void InertiaDlg::OnInsertMassRow() { int sel; sel = m_pctrlMassTable->currentIndex().row(); m_PointMass.insert(sel, new PointMass(0.0, CVector(0.0,0.0,0.0), "")); FillMassModel(); m_pctrlMassTable->closePersistentEditor(m_pctrlMassTable->currentIndex()); QModelIndex index = m_pMassModel->index(sel, 0, QModelIndex()); m_pctrlMassTable->setCurrentIndex(index); // m_pctrlMassTable->openPersistentEditor(index); } void InertiaDlg::OnDeleteMassRow() { int sel; m_pctrlMassTable->closePersistentEditor(m_pctrlMassTable->currentIndex()); sel = m_pctrlMassTable->currentIndex().row(); m_PointMass.removeAt(sel); FillMassModel(); } void InertiaDlg::OnOK() { int i; ReadData(); if(m_pWing) { m_pWing->m_VolumeMass = m_VolumeMass; m_pWing->ClearPointMasses(); for(i=0; imass()>PRECISION) { m_pWing->m_PointMass.append(new PointMass(m_PointMass[i]->mass(), m_PointMass[i]->position(), m_PointMass[i]->tag())); } } } else if(m_pBody) { m_pBody->m_VolumeMass = m_VolumeMass; m_pBody->ClearPointMasses(); for(i=0; i< m_PointMass.size(); i++) { if(m_PointMass[i]->mass()>PRECISION) { m_pBody->m_PointMass.append(new PointMass(m_PointMass[i]->mass(), m_PointMass[i]->position(), m_PointMass[i]->tag())); } } } else if(m_pPlane) { m_pPlane->ClearPointMasses(); for(i=0; imass()>PRECISION) { m_pPlane->m_PointMass.append(new PointMass(m_PointMass[i]->mass(), m_PointMass[i]->position(), m_PointMass[i]->tag())); } } } ComputeBodyAxisInertia(); accept(); } void InertiaDlg::ReadData() { QModelIndex index; bool bOK; double mass, x,y,z; int i; QString tag; ClearPointMasses(); for (i=0; irowCount(); i++) { index = m_pMassModel->index(i, 0, QModelIndex()); mass = index.data().toDouble(&bOK); index = m_pMassModel->index(i, 1, QModelIndex()); x = index.data().toDouble(&bOK); index = m_pMassModel->index(i, 2, QModelIndex()); y = index.data().toDouble(&bOK); index = m_pMassModel->index(i, 3, QModelIndex()); z = index.data().toDouble(&bOK); index = m_pMassModel->index(i, 4, QModelIndex()); tag = index.data().toString(); if(qAbs(mass)>PRECISION || qAbs(x)>PRECISION || qAbs(y)>PRECISION || qAbs(z)>PRECISION || tag.length()) { m_PointMass.append(new PointMass(mass/MainFrame::s_kgtoUnit, CVector(x/MainFrame::s_mtoUnit, y/MainFrame::s_mtoUnit, z/MainFrame::s_mtoUnit), tag)); } } m_VolumeMass = m_pctrlVolumeMass->Value() / MainFrame::s_kgtoUnit; } void InertiaDlg::resizeEvent(QResizeEvent *event) { /* double w = (double)m_pctrlMassView->width()*.97; int w6 = (int)(w/6.); m_pctrlMassView->setColumnWidth(0, w6); m_pctrlMassView->setColumnWidth(1, w6); m_pctrlMassView->setColumnWidth(2, w6); m_pctrlMassView->setColumnWidth(3, w6); m_pctrlMassView->setColumnWidth(4, w-4*w6);*/ } void InertiaDlg::SetupLayout() { QString strMass, strLength; GetWeightUnit(strMass, MainFrame::s_WeightUnit); GetLengthUnit(strLength, MainFrame::s_LengthUnit); QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::Expanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Expanding); QSizePolicy szPolicyMinimum; szPolicyMinimum.setHorizontalPolicy(QSizePolicy::Minimum); szPolicyMinimum.setVerticalPolicy(QSizePolicy::Minimum); QSizePolicy szPolicyMaximum; szPolicyMaximum.setHorizontalPolicy(QSizePolicy::Maximum); szPolicyMaximum.setVerticalPolicy(QSizePolicy::Maximum); QVBoxLayout *MessageLayout = new QVBoxLayout; QLabel *Label1 = new QLabel(tr("This is a calculation form for a rough order of magnitude for the inertia tensor.")); QLabel *Label2 = new QLabel(tr("Refer to the Guidelines for explanations.")); MessageLayout->addWidget(Label1); MessageLayout->addWidget(Label2); //___________Volume Mass, Center of gravity, and inertias__________ m_pctrlTopStack = new QStackedWidget; QGroupBox *ObjectMassBox = new QGroupBox(tr("Object Mass - Volume only, excluding point masses")); { QHBoxLayout *ObjectMassLayout = new QHBoxLayout; m_pctrlVolumeMassLabel = new QLabel(tr("Wing Mass=")); m_pctrlMassUnit = new QLabel("kg"); m_pctrlVolumeMass = new DoubleEdit(1.00,3); QGroupBox *CoGBox = new QGroupBox(tr("Center of gravity")); { QGridLayout *CoGLayout = new QGridLayout; QLabel *CoGLabel = new QLabel(tr("Center of gravity")); CoGLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); QLabel *XCoGLab = new QLabel("X_CoG="); QLabel *YCoGLab = new QLabel("Y_CoG="); QLabel *ZCoGLab = new QLabel("Z_CoG="); m_pctrlXCoG = new DoubleEdit(0.00,3); m_pctrlYCoG = new DoubleEdit(0.00,3); m_pctrlZCoG = new DoubleEdit(0.00,3); m_pctrlXCoG->setEnabled(false); m_pctrlYCoG->setEnabled(false); m_pctrlZCoG->setEnabled(false); m_pctrlLengthUnit = new QLabel("m"); m_pctrlVolumeMassLabel->setAlignment(Qt::AlignRight|Qt::AlignVCenter); XCoGLab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); YCoGLab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); ZCoGLab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); m_pctrlXCoG->setAlignment(Qt::AlignRight|Qt::AlignVCenter); m_pctrlYCoG->setAlignment(Qt::AlignRight|Qt::AlignVCenter); m_pctrlZCoG->setAlignment(Qt::AlignRight|Qt::AlignVCenter); CoGLayout->addWidget(m_pctrlVolumeMassLabel,1,1); CoGLayout->addWidget(m_pctrlVolumeMass,1,2); CoGLayout->addWidget(m_pctrlMassUnit,1,3); CoGLayout->addWidget(XCoGLab,2,1); CoGLayout->addWidget(YCoGLab,3,1); CoGLayout->addWidget(ZCoGLab,4,1); // CoGLayout->addWidget(CoGLabel,2,1); CoGLayout->addWidget(m_pctrlXCoG,2,2); CoGLayout->addWidget(m_pctrlYCoG,3,2); CoGLayout->addWidget(m_pctrlZCoG,4,2); CoGLayout->addWidget(m_pctrlLengthUnit,2,3); CoGLayout->setColumnStretch(1,1); CoGLayout->setColumnStretch(2,2); CoGLayout->setColumnStretch(3,1); CoGBox->setLayout(CoGLayout); } QGroupBox *ResultsBox = new QGroupBox(tr("Inertia in CoG Frame")); { QGridLayout *ResultsLayout = new QGridLayout; m_pctrlCoGIxx = new DoubleEdit(1.0,3); m_pctrlCoGIyy = new DoubleEdit(1.2,3); m_pctrlCoGIzz = new DoubleEdit(-1.5,3); m_pctrlCoGIxz = new DoubleEdit(4.2,3); m_pctrlCoGIxx->setEnabled(false); m_pctrlCoGIyy->setEnabled(false); m_pctrlCoGIzz->setEnabled(false); m_pctrlCoGIxz->setEnabled(false); QLabel *LabIxx = new QLabel("Ixx="); QLabel *LabIyy = new QLabel("Iyy="); QLabel *LabIzz = new QLabel("Izz="); QLabel *LabIxz = new QLabel("Ixz="); LabIxx->setAlignment(Qt::AlignRight | Qt::AlignVCenter); LabIyy->setAlignment(Qt::AlignRight | Qt::AlignVCenter); LabIzz->setAlignment(Qt::AlignRight | Qt::AlignVCenter); LabIxz->setAlignment(Qt::AlignRight | Qt::AlignVCenter); QLabel *LabInertiaObject = new QLabel(tr("Inertia in CoG Frame")); LabInertiaObject->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlInertiaUnit1 = new QLabel("kg.m2"); ResultsLayout->addWidget(LabIxx,1,1); ResultsLayout->addWidget(LabIyy,2,1); ResultsLayout->addWidget(LabIzz,3,1); ResultsLayout->addWidget(LabIxz,4,1); ResultsLayout->addWidget(m_pctrlCoGIxx,1,2); ResultsLayout->addWidget(m_pctrlCoGIyy,2,2); ResultsLayout->addWidget(m_pctrlCoGIzz,3,2); ResultsLayout->addWidget(m_pctrlCoGIxz,4,2); // ResultsLayout->addWidget(LabInertiaObject,2,1); ResultsLayout->addWidget(m_pctrlInertiaUnit1,1,3); ResultsLayout->setColumnStretch(1,1); ResultsLayout->setColumnStretch(2,2); ResultsLayout->setColumnStretch(3,1); ResultsBox->setLayout(ResultsLayout); } ObjectMassLayout->addWidget(CoGBox); ObjectMassLayout->addWidget(ResultsBox); ObjectMassBox->setLayout(ObjectMassLayout); } QGroupBox *ObjectSelectionBox = new QGroupBox(tr("Component inertias")); { QVBoxLayout *ObjectLayout = new QVBoxLayout; m_pctrlWingInertia = new QPushButton(tr("Main Wing")); m_pctrlWing2Inertia = new QPushButton(tr("Second Wing")); m_pctrlStabInertia = new QPushButton(tr("Elevator")); m_pctrlFinInertia = new QPushButton(tr("Fin")); m_pctrlBodyInertia = new QPushButton(tr("Body")); QHBoxLayout *WingInertiasLayout = new QHBoxLayout; WingInertiasLayout->addStretch(1); WingInertiasLayout->addWidget(m_pctrlWingInertia); WingInertiasLayout->addStretch(2); WingInertiasLayout->addWidget(m_pctrlWing2Inertia); WingInertiasLayout->addStretch(3); QHBoxLayout *TailInertiasLayout = new QHBoxLayout; TailInertiasLayout->addStretch(3); TailInertiasLayout->addWidget(m_pctrlStabInertia); TailInertiasLayout->addStretch(2); TailInertiasLayout->addWidget(m_pctrlFinInertia); TailInertiasLayout->addStretch(1); QHBoxLayout *BodyInertiaLayout = new QHBoxLayout; BodyInertiaLayout->addStretch(1); BodyInertiaLayout->addWidget(m_pctrlBodyInertia); BodyInertiaLayout->addStretch(2); ObjectLayout->addLayout(WingInertiasLayout); ObjectLayout->addStretch(1); ObjectLayout->addLayout(TailInertiasLayout); ObjectLayout->addStretch(1); ObjectLayout->addLayout(BodyInertiaLayout); ObjectLayout->addStretch(1); ObjectSelectionBox->setLayout(ObjectLayout); } m_pctrlTopStack->addWidget(ObjectMassBox); m_pctrlTopStack->addWidget(ObjectSelectionBox); //___________________Point Masses__________________________ QLabel *PointMasses = new QLabel(tr("Additional Point Masses")); m_pctrlMassTable = new QTableView(this); m_pctrlMassTable->setMinimumHeight(150); m_pctrlMassTable->horizontalHeader()->setStretchLastSection(true); m_pctrlMassTable->setSelectionMode(QAbstractItemView::SingleSelection); m_pctrlMassTable->setSelectionBehavior(QAbstractItemView::SelectRows); m_pctrlMassTable->setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed | QAbstractItemView::AnyKeyPressed); m_pMassModel = new QStandardItemModel; m_pMassModel->setRowCount(10);//temporary m_pMassModel->setColumnCount(5); m_pctrlMassTable->setModel(m_pMassModel); m_pctrlMassTable->setColumnWidth(0,70); m_pctrlMassTable->setColumnWidth(1,55); m_pctrlMassTable->setColumnWidth(2,55); m_pctrlMassTable->setColumnWidth(3,55); m_pctrlMassTable->setColumnWidth(4,70); m_pFloatDelegate = new FloatEditDelegate; m_pctrlMassTable->setItemDelegate(m_pFloatDelegate); int *precision = new int[5]; precision[0] = 3; precision[1] = 3; precision[2] = 3; precision[3] = 3; precision[4] = -1;// Not a number, will be detected as such by FloatEditDelegate m_pFloatDelegate->SetPrecision(precision); connect(m_pFloatDelegate, SIGNAL(closeEditor(QWidget *)), this, SLOT(OnCellChanged(QWidget *))); //________________Total Mass, Center of gravity, and inertias__________ QGroupBox *TotalMassBox = new QGroupBox(tr("Total Mass = Volume + point masses")); { QHBoxLayout *TotalMassLayout = new QHBoxLayout; m_pctrlTotalMassLabel = new QLabel(tr("Total Mass=")); m_pctrlMassUnit2 = new QLabel("kg"); m_pctrlTotalMass = new DoubleEdit(1.00,3); m_pctrlTotalMass->setEnabled(false); QGroupBox *TotalCoGBox = new QGroupBox(tr("Center of gravity")); { QGridLayout *TotalCoGLayout = new QGridLayout; QLabel *TotalLabel = new QLabel(tr("Center of gravity")); TotalLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); QLabel *XTotalLab = new QLabel("X_CoG="); QLabel *YTotalLab = new QLabel("Y_CoG="); QLabel *ZTotalLab = new QLabel("Z_CoG="); m_pctrlXTotalCoG = new DoubleEdit(0.00,3); m_pctrlYTotalCoG = new DoubleEdit(0.00,3); m_pctrlZTotalCoG = new DoubleEdit(0.00,3); m_pctrlXTotalCoG->setEnabled(false); m_pctrlYTotalCoG->setEnabled(false); m_pctrlZTotalCoG->setEnabled(false); m_pctrlLengthUnit2 = new QLabel("m"); m_pctrlTotalMassLabel->setAlignment(Qt::AlignRight|Qt::AlignVCenter); XTotalLab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); YTotalLab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); ZTotalLab->setAlignment(Qt::AlignRight|Qt::AlignVCenter); m_pctrlXTotalCoG->setAlignment(Qt::AlignRight|Qt::AlignVCenter); m_pctrlYTotalCoG->setAlignment(Qt::AlignRight|Qt::AlignVCenter); m_pctrlZTotalCoG->setAlignment(Qt::AlignRight|Qt::AlignVCenter); TotalCoGLayout->addWidget(m_pctrlTotalMassLabel,1,1); TotalCoGLayout->addWidget(m_pctrlTotalMass,1,2); TotalCoGLayout->addWidget(m_pctrlMassUnit2,1,3); TotalCoGLayout->addWidget(XTotalLab,2,1); TotalCoGLayout->addWidget(YTotalLab,3,1); TotalCoGLayout->addWidget(ZTotalLab,4,1); // TotalCoGLayout->addWidget(TotalLabel,2,1); TotalCoGLayout->addWidget(m_pctrlXTotalCoG,2,2); TotalCoGLayout->addWidget(m_pctrlYTotalCoG,3,2); TotalCoGLayout->addWidget(m_pctrlZTotalCoG,4,2); TotalCoGLayout->addWidget(m_pctrlLengthUnit2,2,3); TotalCoGLayout->setColumnStretch(1,1); TotalCoGLayout->setColumnStretch(2,2); TotalCoGLayout->setColumnStretch(3,1); TotalCoGBox->setLayout(TotalCoGLayout); } QGroupBox *TotalInertiaBox = new QGroupBox(tr("Inertia in CoG Frame")); { QGridLayout *TotalInertiaLayout = new QGridLayout; m_pctrlTotalIxx = new DoubleEdit(1.0,3); m_pctrlTotalIyy = new DoubleEdit(1.2,3); m_pctrlTotalIzz = new DoubleEdit(-1.5,3); m_pctrlTotalIxz = new DoubleEdit(4.2,3); m_pctrlTotalIxx->setEnabled(false); m_pctrlTotalIyy->setEnabled(false); m_pctrlTotalIzz->setEnabled(false); m_pctrlTotalIxz->setEnabled(false); QLabel *LabTotIxx = new QLabel("Ixx="); QLabel *LabTotIyy = new QLabel("Iyy="); QLabel *LabTotIzz = new QLabel("Izz="); QLabel *LabTotIxz = new QLabel("Ixz="); LabTotIxx->setAlignment(Qt::AlignRight | Qt::AlignVCenter); LabTotIyy->setAlignment(Qt::AlignRight | Qt::AlignVCenter); LabTotIzz->setAlignment(Qt::AlignRight | Qt::AlignVCenter); LabTotIxz->setAlignment(Qt::AlignRight | Qt::AlignVCenter); QLabel *LabInertiaTotal = new QLabel(tr("Inertia in CoG Frame")); LabInertiaTotal->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlInertiaUnit2 = new QLabel("kg.m2"); TotalInertiaLayout->addWidget(LabTotIxx,1,1); TotalInertiaLayout->addWidget(LabTotIyy,2,1); TotalInertiaLayout->addWidget(LabTotIzz,3,1); TotalInertiaLayout->addWidget(LabTotIxz,4,1); TotalInertiaLayout->addWidget(m_pctrlTotalIxx,1,2); TotalInertiaLayout->addWidget(m_pctrlTotalIyy,2,2); TotalInertiaLayout->addWidget(m_pctrlTotalIzz,3,2); TotalInertiaLayout->addWidget(m_pctrlTotalIxz,4,2); // TotalInertiaLayout->addWidget(LabInertiaObject,2,1); TotalInertiaLayout->addWidget(m_pctrlInertiaUnit2,1,3); TotalInertiaLayout->setColumnStretch(1,1); TotalInertiaLayout->setColumnStretch(2,2); TotalInertiaLayout->setColumnStretch(3,1); TotalInertiaBox->setLayout(TotalInertiaLayout); } TotalMassLayout->addWidget(TotalCoGBox); TotalMassLayout->addWidget(TotalInertiaBox); TotalMassBox->setLayout(TotalMassLayout); } //__________________Control buttons___________________ QHBoxLayout *CommandButtons = new QHBoxLayout; QPushButton *ExportAVLButton = new QPushButton(tr("Export to AVL")); OKButton = new QPushButton(tr("OK")); QPushButton *CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(ExportAVLButton); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); QVBoxLayout * MainLayout = new QVBoxLayout(this); MainLayout->addStretch(1); MainLayout->addLayout(MessageLayout); MainLayout->addStretch(1); MainLayout->addWidget(m_pctrlTopStack); MainLayout->addStretch(1); // MainLayout->addWidget(PointMassBox); MainLayout->addWidget(PointMasses); MainLayout->addWidget(m_pctrlMassTable); MainLayout->addStretch(1); MainLayout->addWidget(TotalMassBox); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); setLayout(MainLayout); connect(m_pctrlWingInertia, SIGNAL(clicked()), this, SLOT(OnWingInertia())); connect(m_pctrlWing2Inertia, SIGNAL(clicked()), this, SLOT(OnWing2Inertia())); connect(m_pctrlStabInertia, SIGNAL(clicked()), this, SLOT(OnStabInertia())); connect(m_pctrlFinInertia, SIGNAL(clicked()), this, SLOT(OnFinInertia())); connect(m_pctrlBodyInertia, SIGNAL(clicked()), this, SLOT(OnBodyInertia())); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(ExportAVLButton, SIGNAL(clicked()), this, SLOT(OnExportToAVL())); connect(m_pctrlVolumeMass, SIGNAL(editingFinished()), SLOT(OnCellChanged())); connect(m_pInsertMassRow, SIGNAL(triggered()), SLOT(OnInsertMassRow())); connect(m_pDeleteMassRow, SIGNAL(triggered()), SLOT(OnDeleteMassRow())); } void InertiaDlg::showEvent(QShowEvent *event) { resizeEvent(NULL); } void InertiaDlg::OnWingInertia() { InertiaDlg dlg(this); if(!m_pPlane->wing()) return; dlg.m_pWing = m_pPlane->wing(); dlg.m_pPlane = NULL; dlg.m_pBody = NULL; dlg.InitDialog(); dlg.move(pos().x()+25, pos().y()+25); if(dlg.exec()==QDialog::Accepted) m_bChanged=true; ComputeInertia(); } void InertiaDlg::OnWing2Inertia() { if(!m_pPlane->BiPlane()) return; InertiaDlg dlg(this); dlg.m_pWing = m_pPlane->wing2(); dlg.m_pPlane = NULL; dlg.m_pBody = NULL; dlg.InitDialog(); dlg.move(pos().x()+25, pos().y()+25); if(dlg.exec()==QDialog::Accepted) m_bChanged=true; ComputeInertia(); } void InertiaDlg::OnStabInertia() { if(!m_pPlane->stab()) return; InertiaDlg dlg(this); dlg.m_pWing = m_pPlane->stab(); dlg.m_pPlane = NULL; dlg.m_pBody = NULL; dlg.InitDialog(); dlg.move(pos().x()+25, pos().y()+25); if(dlg.exec()==QDialog::Accepted) m_bChanged=true; ComputeInertia(); } void InertiaDlg::OnFinInertia() { if(!m_pPlane->fin()) return; InertiaDlg dlg(this); dlg.m_pWing = m_pPlane->fin(); dlg.m_pPlane = NULL; dlg.m_pBody = NULL; dlg.InitDialog(); dlg.move(pos().x()+25, pos().y()+25); if(dlg.exec()==QDialog::Accepted) m_bChanged=true; ComputeInertia(); } void InertiaDlg::OnBodyInertia() { if(!m_pPlane->body()) return; InertiaDlg dlg(this); dlg.m_pBody = m_pPlane->body(); dlg.m_pPlane = NULL; dlg.m_pWing = NULL; dlg.InitDialog(); dlg.move(pos().x()+25, pos().y()+25); if(dlg.exec()==QDialog::Accepted) m_bChanged=true; ComputeInertia(); } xflr5-6.09-06/src/miarex/WingDelegate.cpp000644 001750 000144 00000011264 12247174407 021421 0ustar00techwinderusers000000 000000 /**************************************************************************** WingDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../objects/Foil.h" #include "WingDelegate.h" #include "GL3dWingDlg.h" WingDelegate::WingDelegate(QObject *parent) : QItemDelegate(parent) { m_pWingDlg = parent; } QWidget *WingDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex & index ) const { if(index.column()!=5 && index.column()!=7 && index.column()!=9) { DoubleEdit *editor = new DoubleEdit(parent); editor->setAlignment(Qt::AlignRight); editor->SetPrecision(m_Precision[index.column()]); if(index.column()==6) { editor->SetMin(1); editor->SetMax(MAXCHORDPANELS-1); } if(index.column()==8) { editor->SetMin(1); editor->SetMax(MAXSPANSTATIONS-1); } return editor; } else { QString strong; QComboBox *editor = new QComboBox(parent); editor->setSizeAdjustPolicy(QComboBox::AdjustToContents); //fill comboboxes here if(index.column()==5) { for(int i=0; i< m_poaFoil->size(); i++) { Foil *pFoil = (Foil*)m_poaFoil->at(i); pFoil->foilName(strong); editor->addItem(strong); } } else if(index.column()==7) { editor->addItem(tr("Uniform")); editor->addItem(tr("Cosine")); } else if(index.column()==9) { editor->addItem(tr("Uniform")); editor->addItem(tr("Cosine")); editor->addItem(tr("Sine")); editor->addItem(tr("-Sine")); } return editor; } return NULL; } void WingDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if(index.column()!=5 && index.column()!=7 && index.column()!=9) { double value = index.model()->data(index, Qt::EditRole).toDouble(); DoubleEdit *pDE = static_cast(editor); pDE->SetValue(value); } else { QString strong = index.model()->data(index, Qt::EditRole).toString(); QComboBox *pCbBox = static_cast(editor); int pos = pCbBox->findText(strong); if (pos>=0) pCbBox->setCurrentIndex(pos); else pCbBox->setCurrentIndex(0); } } void WingDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { if(index.column()!=5 && index.column()!=7 && index.column()!=9) { DoubleEdit *pDE = static_cast(editor); double value = pDE->Value(); model->setData(index, value, Qt::EditRole); } else { QString strong; QComboBox *pCbBox = static_cast(editor); int sel = pCbBox->currentIndex(); if (sel >=0) strong = pCbBox->itemText(sel); model->setData(index, strong, Qt::EditRole); } } void WingDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QString strong; QStyleOptionViewItem myOption = option; if(index.column()!=5 && index.column()!=7 && index.column()!=9) { myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; strong = QString("%1").arg(index.model()->data(index, Qt::DisplayRole).toDouble(),0,'f', m_Precision[index.column()]); } else { myOption.displayAlignment = Qt::AlignLeft | Qt::AlignVCenter; strong = index.model()->data(index, Qt::DisplayRole).toString(); } if(index.row()> m_pWingSection->count()) strong=" "; if(index.row()== m_pWingSection->count()-1) { if(index.column()==3 ||index.column()>=6) strong = " "; } drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } void WingDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { editor->setGeometry(option.rect); } void WingDelegate::SetPrecision(int *PrecisionTable) { m_Precision = PrecisionTable; } xflr5-6.09-06/src/miarex/BodyScaleDlg.cpp000644 001750 000144 00000013204 12247174402 021345 0ustar00techwinderusers000000 000000 /**************************************************************************** BodyScaleDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include #include #include "../mainframe.h" #include "../globals.h" #include "../misc/LinePickerDlg.h" #include "BodyScaleDlg.h" #include "./GL3dBodyDlg.h" BodyScaleDlg::BodyScaleDlg(QWidget *pParent ): QDialog(pParent) { setWindowTitle(tr("Body Scale Dialog")); m_pBodyDlg = pParent; m_XFactor = 1.0; m_YFactor = 1.0; m_ZFactor = 1.0; m_bFrameOnly = false; m_FrameID = 0; SetupLayout(); } void BodyScaleDlg::InitDialog() { m_pctrlXScaleFactor->SetValue(m_XFactor); m_pctrlYScaleFactor->SetValue(m_YFactor); m_pctrlZScaleFactor->SetValue(m_ZFactor); m_pctrlXScaleFactor->setFocus(); m_pctrlFrameID->setEnabled(false); m_pctrlFrameID->SetValue(m_FrameID+1); if(!m_bFrameOnly) { m_pctrlBody->setChecked(true); m_pctrlFrame->setChecked(false); } else { m_pctrlBody->setChecked(false); m_pctrlFrame->setChecked(true); m_pctrlXScaleFactor->setEnabled(false); } EnableControls(); } void BodyScaleDlg::SetupLayout() { setWindowTitle("Scale Body"); // QDesktopWidget desktop; // QRect r = desktop.geometry(); // setMinimumHeight(r.height()/3); // move(r.width()/3, r.height()/6); QGridLayout *TopLayout = new QGridLayout; m_pctrlBody = new QRadioButton(tr("Whole Body")); m_pctrlFrame = new QRadioButton(tr("Frame Only")); m_pctrlFrameID = new DoubleEdit(10); m_pctrlFrameID->SetPrecision(0); TopLayout->addWidget(m_pctrlBody,1,1); TopLayout->addWidget(m_pctrlFrame,2,1); TopLayout->addWidget(m_pctrlFrameID,2,2); QGridLayout *ScaleLayout = new QGridLayout; m_pctrlXScaleFactor = new DoubleEdit(1.0); m_pctrlYScaleFactor = new DoubleEdit(2.000); m_pctrlZScaleFactor = new DoubleEdit(3.); m_pctrlXScaleFactor->SetPrecision(3); m_pctrlYScaleFactor->SetPrecision(3); m_pctrlZScaleFactor->SetPrecision(3); QLabel *lab0 = new QLabel(tr("Scale Factor")); QLabel *lab1 = new QLabel(tr("X Scale")); QLabel *lab2 = new QLabel(tr("Y Scale")); QLabel *lab3 = new QLabel(tr("Z Scale")); ScaleLayout->addWidget(lab0,1,2); ScaleLayout->addWidget(lab1,2,1); ScaleLayout->addWidget(lab2,3,1); ScaleLayout->addWidget(lab3,4,1); ScaleLayout->addWidget(m_pctrlXScaleFactor,2,2); ScaleLayout->addWidget(m_pctrlYScaleFactor,3,2); ScaleLayout->addWidget(m_pctrlZScaleFactor,4,2); QHBoxLayout *CommandButtons = new QHBoxLayout; OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addStretch(1); MainLayout->addLayout(TopLayout); MainLayout->addStretch(1); MainLayout->addLayout(ScaleLayout); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); setLayout(MainLayout); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(m_pctrlBody, SIGNAL(clicked()), this, SLOT(OnRadio())); connect(m_pctrlFrame, SIGNAL(clicked()), this, SLOT(OnRadio())); connect(m_pctrlXScaleFactor, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlYScaleFactor, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlZScaleFactor, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlFrameID, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); } void BodyScaleDlg::EnableControls() { } void BodyScaleDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OKButton->setFocus(); return; } else { OnOK(); return; } break; } case Qt::Key_Escape: { reject(); break; } default: event->ignore(); } } void BodyScaleDlg::OnRadio() { if(m_pctrlBody->isChecked()) { m_pctrlFrameID->setEnabled(false); m_pctrlXScaleFactor->setEnabled(true); m_bFrameOnly = false; } else { m_pctrlFrameID->setEnabled(true); m_pctrlXScaleFactor->setEnabled(false); m_bFrameOnly = true; } } void BodyScaleDlg::OnOK() { m_FrameID = m_pctrlFrameID->Value()-1; m_XFactor = m_pctrlXScaleFactor->Value(); m_YFactor = m_pctrlYScaleFactor->Value(); m_ZFactor = m_pctrlZScaleFactor->Value(); QDialog::accept(); } void BodyScaleDlg::OnEditingFinished() { GL3dBodyDlg *pBodyDlg = (GL3dBodyDlg*)m_pBodyDlg; m_FrameID = m_pctrlFrameID->Value()-1; pBodyDlg->m_pBody->m_iActiveFrame = m_FrameID; pBodyDlg->m_pFrame = pBodyDlg->m_pBody->activeFrame(); pBodyDlg->m_bResetglBody2D = true; pBodyDlg->UpdateView(); } xflr5-6.09-06/src/miarex/BodyTableDelegate.h000644 001750 000144 00000003661 12247174402 022024 0ustar00techwinderusers000000 000000 /**************************************************************************** BodyTableDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef BODYTABLEDELEGATE_H #define BODYTABLEDELEGATE_H #include #include #include "../misc/DoubleEdit.h" class BodyTableDelegate : public QItemDelegate { Q_OBJECT friend class GL3dBodyDlg; public: BodyTableDelegate(QObject *parent = 0); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void SetPointers(int *PrecisionTable, int *pNRows); void SetPointer(int *PrecisionTable); private: int *m_pNRows; int *m_Precision; ///table of float precisions for each column }; #endif // BODYTABLEDELEGATE_H xflr5-6.09-06/src/miarex/BodyGridDlg.cpp000644 001750 000144 00000025654 12247174402 021217 0ustar00techwinderusers000000 000000 /**************************************************************************** BodyGridDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include #include #include #include "../mainframe.h" #include "../globals.h" #include "../misc/LinePickerDlg.h" #include "BodyGridDlg.h" bool BodyGridDlg::s_bScale = false; bool BodyGridDlg::s_bGrid = false; int BodyGridDlg::s_Style = 1; int BodyGridDlg::s_Width =1; QColor BodyGridDlg::s_Color = QColor(150,150,150); double BodyGridDlg::s_Unit = 0.2; bool BodyGridDlg::s_bMinGrid = false; int BodyGridDlg::s_MinStyle=2; int BodyGridDlg::s_MinWidth =1; QColor BodyGridDlg::s_MinColor=QColor(75,75,75); double BodyGridDlg::s_MinorUnit=0.05; bool BodyGridDlg::s_bGrid2 = false; int BodyGridDlg::s_Style2 = 1; int BodyGridDlg::s_Width2 =1; QColor BodyGridDlg::s_Color2 = QColor(150,150,150); double BodyGridDlg::s_Unit2 = 0.01; bool BodyGridDlg::s_bMinGrid2 = false; int BodyGridDlg::s_MinStyle2=2; int BodyGridDlg::s_MinWidth2 =1; QColor BodyGridDlg::s_MinColor2=QColor(75,75,75); double BodyGridDlg::s_MinorUnit2=0.002; BodyGridDlg::BodyGridDlg(QWidget *pParent):QDialog(pParent) { setWindowTitle(tr("Body Grid Dialog")); SetupLayout(); } void BodyGridDlg::InitDialog() { QString length; GetLengthUnit(length, MainFrame::s_LengthUnit); m_pctrlLength1->setText(length); m_pctrlLength2->setText(length); m_pctrlLength3->setText(length); m_pctrlLength4->setText(length); m_pctrlScales->setChecked(s_bScale); m_pctrlGrid->setChecked(s_bGrid); m_pctrlLine->SetStyle(s_Style); m_pctrlLine->SetWidth(s_Width); m_pctrlLine->SetColor(s_Color); m_pctrlMinGrid->setChecked(s_bMinGrid); m_pctrlMinLine->SetStyle(s_MinStyle); m_pctrlMinLine->SetWidth(s_MinWidth); m_pctrlMinLine->SetColor(s_MinColor); m_pctrlUnit->SetValue(s_Unit); m_pctrlMinUnit->SetValue(s_MinorUnit); m_pctrlGrid2->setChecked(s_bGrid2); m_pctrlLine2->SetStyle(s_Style2); m_pctrlLine2->SetWidth(s_Width2); m_pctrlLine2->SetColor(s_Color2); m_pctrlMinGrid2->setChecked(s_bMinGrid2); m_pctrlMinLine2->SetStyle(s_MinStyle2); m_pctrlMinLine2->SetWidth(s_MinWidth2); m_pctrlMinLine2->SetColor(s_MinColor2); m_pctrlUnit2->SetValue(s_Unit2); m_pctrlMinUnit2->SetValue(s_MinorUnit2); EnableControls(); } void BodyGridDlg::SetupLayout() { setWindowTitle(tr("Grid Parameters")); m_pctrlScales = new QCheckBox(tr("Show Scales")); m_pctrlGrid = new QCheckBox(tr("Main Grid")); m_pctrlGrid2 = new QCheckBox(tr("Main Grid")); m_pctrlMinGrid = new QCheckBox(tr("Minor Grid")); m_pctrlMinGrid2 = new QCheckBox(tr("Minor Grid")); m_pctrlLine = new LineBtn(this); m_pctrlLine2 = new LineBtn(this); m_pctrlMinLine = new LineBtn(this); m_pctrlMinLine2 = new LineBtn(this); m_pctrlUnit = new DoubleEdit(100.00); m_pctrlUnit2 = new DoubleEdit(101.00); m_pctrlMinUnit = new DoubleEdit(102.00); m_pctrlMinUnit2 = new DoubleEdit(103.00); m_pctrlUnit->SetPrecision(3); m_pctrlUnit2->SetPrecision(3); m_pctrlMinUnit->SetPrecision(3); m_pctrlMinUnit2->SetPrecision(3); m_pctrlLength1 = new QLabel("mm"); m_pctrlLength2 = new QLabel("mm"); m_pctrlLength3 = new QLabel("mm"); m_pctrlLength4 = new QLabel("mm"); QGroupBox *BodyBox = new QGroupBox(tr("Body Grid")); { QGridLayout *BodyLayout = new QGridLayout; { BodyLayout->addWidget(m_pctrlGrid,1,1); BodyLayout->addWidget(m_pctrlLine,1,2); BodyLayout->addWidget(m_pctrlUnit,1,3); BodyLayout->addWidget(m_pctrlLength1, 1,4); BodyLayout->addWidget(m_pctrlMinGrid,2,1); BodyLayout->addWidget(m_pctrlMinLine,2,2); BodyLayout->addWidget(m_pctrlMinUnit,2,3); BodyLayout->addWidget(m_pctrlLength2, 2,4); } BodyBox->setLayout(BodyLayout); } QGroupBox *FrameBox = new QGroupBox(tr("Frame Grid")); { QGridLayout *FrameLayout = new QGridLayout; { FrameLayout->addWidget(m_pctrlGrid2,1,1); FrameLayout->addWidget(m_pctrlLine2,1,2); FrameLayout->addWidget(m_pctrlUnit2,1,3); FrameLayout->addWidget(m_pctrlLength3, 1,4); FrameLayout->addWidget(m_pctrlMinGrid2,2,1); FrameLayout->addWidget(m_pctrlMinLine2,2,2); FrameLayout->addWidget(m_pctrlMinUnit2,2,3); FrameLayout->addWidget(m_pctrlLength4, 2,4); } FrameBox->setLayout(FrameLayout); } QHBoxLayout *CommandButtons = new QHBoxLayout; { QPushButton *OKButton = new QPushButton(tr("OK")); QPushButton *Cancel = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(Cancel); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(Cancel, SIGNAL(clicked()), this, SLOT(reject())); } QVBoxLayout *MainLayout = new QVBoxLayout; { MainLayout->addWidget(m_pctrlScales); MainLayout->addStretch(1); MainLayout->addWidget(BodyBox); MainLayout->addStretch(1); MainLayout->addWidget(FrameBox); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); } setLayout(MainLayout); connect(m_pctrlGrid, SIGNAL(clicked()), this, SLOT(OnGrid())); connect(m_pctrlMinGrid, SIGNAL(clicked()), this, SLOT(OnMinGrid())); connect(m_pctrlGrid2, SIGNAL(clicked()), this, SLOT(OnGrid2())); connect(m_pctrlMinGrid2, SIGNAL(clicked()), this, SLOT(OnMinGrid2())); connect(m_pctrlLine, SIGNAL(clickedLB()), this, SLOT(OnLineStyle())); connect(m_pctrlLine2, SIGNAL(clickedLB()), this, SLOT(OnLine2Style())); connect(m_pctrlMinLine, SIGNAL(clickedLB()), this, SLOT(OnMinLineStyle())); connect(m_pctrlMinLine2, SIGNAL(clickedLB()), this, SLOT(OnMinLine2Style())); } void BodyGridDlg::EnableControls() { m_pctrlLine->setEnabled(s_bGrid); m_pctrlUnit->setEnabled(s_bGrid); m_pctrlMinLine->setEnabled(s_bMinGrid); m_pctrlMinUnit->setEnabled(s_bMinGrid); m_pctrlLine2->setEnabled(s_bGrid2); m_pctrlUnit2->setEnabled(s_bGrid2); m_pctrlMinLine2->setEnabled(s_bMinGrid2); m_pctrlMinUnit2->setEnabled(s_bMinGrid2); } void BodyGridDlg::OnOK() { s_bScale = m_pctrlScales->isChecked(); accept(); } void BodyGridDlg::OnGrid() { s_bGrid = m_pctrlGrid->isChecked(); EnableControls(); } void BodyGridDlg::OnGrid2() { s_bGrid2 = m_pctrlGrid2->isChecked(); EnableControls(); } void BodyGridDlg::OnMinGrid() { s_bMinGrid = m_pctrlMinGrid->isChecked(); EnableControls(); } void BodyGridDlg::OnMinGrid2() { s_bMinGrid2 = m_pctrlMinGrid2->isChecked(); EnableControls(); } void BodyGridDlg::OnLineStyle() { LinePickerDlg dlg(this); dlg.InitDialog(s_Style, s_Width, s_Color); if(QDialog::Accepted==dlg.exec()) { s_Style = dlg.GetStyle(); s_Width = dlg.GetWidth(); s_Color = dlg.GetColor(); m_pctrlLine->SetStyle(s_Style); m_pctrlLine->SetWidth(s_Width); m_pctrlLine->SetColor(s_Color); } } void BodyGridDlg::OnLine2Style() { LinePickerDlg dlg(this); dlg.InitDialog(s_Style2, s_Width2, s_Color2); if(QDialog::Accepted==dlg.exec()) { s_Style2 = dlg.GetStyle(); s_Width2 = dlg.GetWidth(); s_Color2 = dlg.GetColor(); m_pctrlLine2->SetStyle(s_Style2); m_pctrlLine2->SetWidth(s_Width2); m_pctrlLine2->SetColor(s_Color2); } } void BodyGridDlg::OnMinLineStyle() { LinePickerDlg dlg(this); dlg.InitDialog(s_MinStyle, s_MinWidth, s_MinColor); if(QDialog::Accepted==dlg.exec()) { s_MinStyle = dlg.GetStyle(); s_MinWidth = dlg.GetWidth(); s_MinColor = dlg.GetColor(); m_pctrlMinLine->SetStyle(s_MinStyle); m_pctrlMinLine->SetWidth(s_MinWidth); m_pctrlMinLine->SetColor(s_MinColor); } } void BodyGridDlg::OnMinLine2Style() { LinePickerDlg dlg(this); dlg.InitDialog(s_MinStyle2, s_MinWidth2, s_MinColor2); if(QDialog::Accepted==dlg.exec()) { s_MinStyle2 = dlg.GetStyle(); s_MinWidth2 = dlg.GetWidth(); s_MinColor2 = dlg.GetColor(); m_pctrlMinLine2->SetStyle(s_MinStyle2); m_pctrlMinLine2->SetWidth(s_MinWidth2); m_pctrlMinLine2->SetColor(s_MinColor2); } } void BodyGridDlg::LoadSettings (QSettings *pSettings) { pSettings->beginGroup("GL3dBodyGrid"); { s_bGrid = pSettings->value("Grid").toBool(); s_bMinGrid = pSettings->value("MinGrid").toBool(); s_bGrid2 = pSettings->value("Grid2").toBool(); s_bMinGrid2 = pSettings->value("MinGrid2").toBool(); s_Style = pSettings->value("Style").toInt(); s_MinStyle = pSettings->value("MinStyle").toInt(); s_Style2 = pSettings->value("Style2").toInt(); s_MinStyle2 = pSettings->value("MinStyle2").toInt(); s_Width = pSettings->value("Width").toInt(); s_MinWidth = pSettings->value("MinWidth").toInt(); s_Width2 = pSettings->value("Width2").toInt(); s_MinWidth2 = pSettings->value("MinWidth2").toInt(); s_Color = pSettings->value("Color").value(); s_MinColor = pSettings->value("MinColor").value(); s_Color2 = pSettings->value("Color2").value(); s_MinColor2 = pSettings->value("MinColor2").value(); s_Unit = pSettings->value("Unit").toDouble(); s_MinorUnit = pSettings->value("MinorUnit").toDouble(); s_Unit2 = pSettings->value("Unit2").toDouble(); s_MinorUnit2 = pSettings->value("MinorUnit2").toDouble(); s_bScale = pSettings->value("bScale").toBool(); } pSettings->endGroup(); } void BodyGridDlg::SaveSettings (QSettings *pSettings) { pSettings->beginGroup("GL3dBodyGrid"); { pSettings->setValue("Grid", s_bGrid); pSettings->setValue("MinGrid", s_bMinGrid); pSettings->setValue("Grid2", s_bGrid2); pSettings->setValue("MinGrid2", s_bMinGrid2); pSettings->setValue("Style", s_Style); pSettings->setValue("MinStyle", s_MinStyle); pSettings->setValue("Style2", s_Style2); pSettings->setValue("MinStyle2", s_MinStyle2); pSettings->setValue("Width", s_Width); pSettings->setValue("MinWidth", s_MinWidth); pSettings->setValue("Width2", s_Width2); pSettings->setValue("MinWidth2", s_MinWidth2); pSettings->setValue("Color", s_Color); pSettings->setValue("MinColor", s_MinColor); pSettings->setValue("Color2", s_Color2); pSettings->setValue("MinColor2", s_MinColor2); pSettings->setValue("Unit", s_Unit); pSettings->setValue("MinorUnit", s_MinorUnit); pSettings->setValue("Unit2", s_Unit2); pSettings->setValue("MinorUnit2", s_MinorUnit2); pSettings->setValue("bScale", s_bScale); } pSettings->endGroup(); } xflr5-6.09-06/src/miarex/GL3DScales.cpp000644 001750 000144 00000032451 12247174401 020701 0ustar00techwinderusers000000 000000 /**************************************************************************** GL3DScales Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "Miarex.h" #include "../mainframe.h" #include "../globals.h" #include "GL3DScales.h" #include #include #include int GL3DScales::s_pos = 1; int GL3DScales::s_NX = 30; double GL3DScales::s_DeltaL = 0.01; double GL3DScales::s_XFactor = 1.10; double GL3DScales::s_XOffset = 0.0; double GL3DScales::s_ZOffset = 0.0; GL3DScales::GL3DScales(QWidget *parent) { setWindowTitle(tr("3D Scales Settings")); m_pMainFrame = NULL; m_pMiarex = NULL; s_pos = 1; s_NX = 30; s_XFactor = 1.10; s_DeltaL = 0.01; s_XOffset = 0.0; s_ZOffset = 0.0; SetupLayout(); connect(ApplyButton, SIGNAL(clicked()),this, SLOT(OnApply())); connect(m_pctrlAutoCpScale, SIGNAL(clicked()), this, SLOT(OnCpScale())); connect(m_pctrlLegendMin, SIGNAL(editingFinished()), this, SLOT(OnCpScale())); connect(m_pctrlLegendMax, SIGNAL(editingFinished()), this, SLOT(OnCpScale())); connect(m_pctrlLiftScaleSlider, SIGNAL(sliderMoved(int)), this, SLOT(OnLiftScale(int))); connect(m_pctrlDragScaleSlider, SIGNAL(sliderMoved(int)), this, SLOT(OnDragScale(int))); connect(m_pctrlVelocityScaleSlider, SIGNAL(sliderMoved(int)), this, SLOT(OnVelocityScale(int))); } void GL3DScales::SetupLayout() { QSizePolicy szPolicyMinimum; szPolicyMinimum.setHorizontalPolicy(QSizePolicy::Minimum); szPolicyMinimum.setVerticalPolicy(QSizePolicy::Minimum); setSizePolicy(szPolicyMinimum); QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::Expanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Expanding); QGroupBox *CpScaleBox = new QGroupBox(tr("Cp Scale")); { QGridLayout *CpScaleLayout = new QGridLayout; { m_pctrlAutoCpScale = new QCheckBox(tr("Auto Scales")); m_pctrlLegendMin = new DoubleEdit(-1.0); m_pctrlLegendMax = new DoubleEdit(1.0); m_pctrlLegendMin->SetPrecision(2); m_pctrlLegendMax->SetPrecision(2); QLabel *lab0 = new QLabel(tr("Min")); QLabel *lab1 = new QLabel(tr("Max")); lab0->setAlignment(Qt::AlignVCenter |Qt::AlignRight); lab1->setAlignment(Qt::AlignVCenter |Qt::AlignRight); CpScaleLayout->addWidget(m_pctrlAutoCpScale,1,2); CpScaleLayout->addWidget(lab1,2,1); CpScaleLayout->addWidget(m_pctrlLegendMax,2,2); CpScaleLayout->addWidget(lab0,3,1); CpScaleLayout->addWidget(m_pctrlLegendMin,3,2); } CpScaleBox->setLayout(CpScaleLayout); } //_______________________3D Scales QGroupBox *ScaleBox = new QGroupBox(tr("Vector Scales")); { QHBoxLayout *ScaleLayout = new QHBoxLayout; { QVBoxLayout *SliderLayout = new QVBoxLayout; { m_pctrlLiftScaleSlider = new QSlider(Qt::Horizontal); m_pctrlLiftScaleSlider->setMinimum(0); m_pctrlLiftScaleSlider->setMaximum(100); m_pctrlLiftScaleSlider->setSliderPosition(50); m_pctrlLiftScaleSlider->setTickInterval(5); m_pctrlLiftScaleSlider->setTickPosition(QSlider::TicksBelow); m_pctrlDragScaleSlider = new QSlider(Qt::Horizontal); m_pctrlDragScaleSlider->setMinimum(0); m_pctrlDragScaleSlider->setMaximum(100); m_pctrlDragScaleSlider->setSliderPosition(50); m_pctrlDragScaleSlider->setTickInterval(5); m_pctrlDragScaleSlider->setTickPosition(QSlider::TicksBelow); m_pctrlVelocityScaleSlider = new QSlider(Qt::Horizontal); m_pctrlVelocityScaleSlider->setMinimum(0); m_pctrlVelocityScaleSlider->setMaximum(100); m_pctrlVelocityScaleSlider->setSliderPosition(50); m_pctrlVelocityScaleSlider->setTickInterval(5); m_pctrlVelocityScaleSlider->setTickPosition(QSlider::TicksBelow); SliderLayout->addWidget(m_pctrlLiftScaleSlider); SliderLayout->addWidget(m_pctrlDragScaleSlider); SliderLayout->addWidget(m_pctrlVelocityScaleSlider); } QVBoxLayout *LabelLayout = new QVBoxLayout; { QLabel *lab2 = new QLabel(tr("Lift ")); QLabel *lab3 = new QLabel(tr("Drag ")); QLabel *lab4 = new QLabel(tr("Velocity ")); LabelLayout->addWidget(lab2); LabelLayout->addWidget(lab3); LabelLayout->addWidget(lab4); } ScaleLayout->addLayout(LabelLayout); ScaleLayout->addLayout(SliderLayout); } ScaleBox->setLayout(ScaleLayout); } //__________________________________ Streamlines QGroupBox *LengthBox = new QGroupBox(tr("Streamline length")); { m_pctrlNXPoint = new DoubleEdit(33,0); m_pctrlNXPoint->SetPrecision(0); m_pctrlDeltaL = new DoubleEdit(12.34,2); m_pctrlXFactor = new DoubleEdit(1.23,2); m_pctrlLengthUnit1 = new QLabel("miles"); QLabel *lab5 = new QLabel(tr("X-axis points")); QLabel *lab6 = new QLabel(tr("1st segment")); QLabel *lab7 = new QLabel(tr("X factor")); lab5->setAlignment(Qt::AlignVCenter |Qt::AlignRight); lab6->setAlignment(Qt::AlignVCenter |Qt::AlignRight); lab7->setAlignment(Qt::AlignVCenter |Qt::AlignRight); QGridLayout *LengthLayout = new QGridLayout; { LengthLayout->addWidget(lab5, 1, 1); LengthLayout->addWidget(m_pctrlNXPoint , 1, 2); LengthLayout->addWidget(lab6, 2, 1); LengthLayout->addWidget(m_pctrlDeltaL, 2, 2); LengthLayout->addWidget(m_pctrlLengthUnit1, 2, 3); LengthLayout->addWidget(lab7, 3, 1); LengthLayout->addWidget(m_pctrlXFactor, 3, 2); } LengthBox->setLayout(LengthLayout); } QGroupBox *StartBox = new QGroupBox(tr("Start Streamline at")); { QVBoxLayout *StartLayout = new QVBoxLayout; { m_pctrlXOffset = new DoubleEdit(4.56,3); m_pctrlZOffset = new DoubleEdit(7.89,3); m_pctrlLengthUnit2 = new QLabel("km"); m_pctrlLengthUnit3 = new QLabel("m"); m_pctrlLE = new QRadioButton(tr("L.E.")); m_pctrlTE = new QRadioButton(tr("T.E.")); m_pctrlLine = new QRadioButton(tr("Y-Line")); QLabel *lab8 = new QLabel(tr("X-Offset")); QLabel *lab9 = new QLabel(tr("Z-Offset")); lab8->setAlignment(Qt::AlignVCenter |Qt::AlignRight); lab9->setAlignment(Qt::AlignVCenter |Qt::AlignRight); QHBoxLayout *LineLayout = new QHBoxLayout; { LineLayout->addWidget(m_pctrlLE); LineLayout->addWidget(m_pctrlTE); LineLayout->addWidget(m_pctrlLine); } QGridLayout *OffsetLayout = new QGridLayout; { OffsetLayout->addWidget(lab8,1,1); OffsetLayout->addWidget(m_pctrlXOffset,1,2); OffsetLayout->addWidget(m_pctrlLengthUnit2,1,3); OffsetLayout->addWidget(lab9,2,1); OffsetLayout->addWidget(m_pctrlZOffset,2,2); OffsetLayout->addWidget(m_pctrlLengthUnit3,2,3); } StartLayout->addLayout(LineLayout); StartLayout->addLayout(OffsetLayout); } StartBox->setLayout(StartLayout); } QGroupBox *StreamBox = new QGroupBox(tr("Streamlines")); { ApplyButton = new QPushButton(tr("Apply")); QVBoxLayout *StreamLayout = new QVBoxLayout; StreamLayout->addWidget(LengthBox); StreamLayout->addWidget(StartBox); StreamLayout->addStretch(1); StreamLayout->addWidget(ApplyButton); StreamLayout->addStretch(1); StreamBox->setLayout(StreamLayout); } QVBoxLayout *MainLayout = new QVBoxLayout; { MainLayout->addStretch(1); MainLayout->addWidget(ScaleBox); MainLayout->addSpacing(15); MainLayout->addStretch(1); MainLayout->addWidget(CpScaleBox); MainLayout->addSpacing(15); MainLayout->addStretch(1); MainLayout->addWidget(StreamBox); MainLayout->addStretch(1); } setLayout(MainLayout); } void GL3DScales::InitDialog() { if(!m_pMainFrame) return; QMiarex *pMiarex = (QMiarex*)m_pMiarex; QString str; GetLengthUnit(str, MainFrame::s_LengthUnit); m_pctrlLengthUnit1->setText(str); m_pctrlLengthUnit2->setText(str); m_pctrlLengthUnit3->setText(str); m_pctrlAutoCpScale->setChecked(pMiarex->s_bAutoCpScale); m_pctrlLegendMin->SetValue(QMiarex::s_LegendMin); m_pctrlLegendMax->SetValue(QMiarex::s_LegendMax); m_pctrlLegendMin->setEnabled(!pMiarex->s_bAutoCpScale); m_pctrlLegendMax->setEnabled(!pMiarex->s_bAutoCpScale); double pos; pos = -pMiarex->m_LiftScale*pMiarex->m_LiftScale + pMiarex->m_LiftScale*sqrt(pMiarex->m_LiftScale*pMiarex->m_LiftScale+4.0*1.01); pos = pos/2.0/1.01; m_pctrlLiftScaleSlider->setSliderPosition((int)(pos*100.0)); pos = -pMiarex->m_DragScale*pMiarex->m_DragScale + pMiarex->m_DragScale*sqrt(pMiarex->m_DragScale*pMiarex->m_DragScale+4.0*1.01); pos = pos/2.0/1.01; m_pctrlDragScaleSlider->setSliderPosition((int)(pos*100.0)); pos = -pMiarex->m_VelocityScale*pMiarex->m_VelocityScale + pMiarex->m_VelocityScale*sqrt(pMiarex->m_VelocityScale*pMiarex->m_VelocityScale+4.0*1.01); pos = pos/2.0/1.01; m_pctrlVelocityScaleSlider->setSliderPosition((int)(pos*100.0)); if(s_pos==0) m_pctrlLE->setChecked(true); else if(s_pos==1) m_pctrlTE->setChecked(true); else if(s_pos==2) m_pctrlLine->setChecked(true); m_pctrlDeltaL->SetValue(s_DeltaL* MainFrame::s_mtoUnit); m_pctrlXOffset->SetValue(s_XOffset* MainFrame::s_mtoUnit); m_pctrlZOffset->SetValue(s_ZOffset* MainFrame::s_mtoUnit); m_pctrlXFactor->SetValue(s_XFactor); m_pctrlNXPoint->SetValue(s_NX); } void GL3DScales::OnCpScale() { QMiarex * pMiarex = (QMiarex*)m_pMiarex; pMiarex->s_bAutoCpScale = m_pctrlAutoCpScale->isChecked(); pMiarex->s_LegendMax = m_pctrlLegendMax->Value(); pMiarex->s_LegendMin = m_pctrlLegendMin->Value(); m_pctrlLegendMin->setEnabled(!pMiarex->s_bAutoCpScale); m_pctrlLegendMax->setEnabled(!pMiarex->s_bAutoCpScale); pMiarex->m_bResetglPanelCp = true; pMiarex->m_bResetglLegend = true; pMiarex->UpdateView(); } void GL3DScales::OnApply() { QMiarex * pMiarex = (QMiarex*)m_pMiarex; pMiarex->s_LegendMax = m_pctrlLegendMax->Value(); pMiarex->s_LegendMin = m_pctrlLegendMin->Value(); pMiarex->s_bAutoCpScale = m_pctrlAutoCpScale->isChecked(); ReadStreamParams(); pMiarex->m_bResetglStream = true; pMiarex->UpdateView(); } void GL3DScales::OnLiftScale(int pos) { QMiarex * pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_LiftScale = pos/100.0/sqrt(1.01-pos/100.0); pMiarex->m_bResetglLift = true; pMiarex->m_bResetglPanelForce = true; pMiarex->UpdateView(); } void GL3DScales::OnDragScale(int pos) { QMiarex * pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_DragScale = pos/100.0/sqrt(1.01-pos/100.0); pMiarex->m_bResetglDrag = true; pMiarex->UpdateView(); } void GL3DScales::OnVelocityScale(int pos) { QMiarex * pMiarex = (QMiarex*)m_pMiarex; pMiarex->m_VelocityScale = pos/100.0/sqrt(1.01-pos/100.0); pMiarex->m_bResetglDownwash = true; pMiarex->UpdateView(); } void GL3DScales::showEvent(QShowEvent *event) { InitDialog(); } void GL3DScales::ReadStreamParams() { s_NX = m_pctrlNXPoint->Value(); s_XOffset = m_pctrlXOffset->Value() / MainFrame::s_mtoUnit; s_ZOffset = m_pctrlZOffset->Value() / MainFrame::s_mtoUnit; s_DeltaL = m_pctrlDeltaL->Value() / MainFrame::s_mtoUnit; s_XFactor = m_pctrlXFactor->Value(); if(m_pctrlLE->isChecked()) s_pos=0; else if(m_pctrlTE->isChecked()) s_pos=1; else if(m_pctrlLine->isChecked()) s_pos=2; } bool GL3DScales::LoadSettings(QSettings *pSettings) { pSettings->beginGroup("GL3DScales"); { QMiarex::s_bAutoCpScale = pSettings->value("AutoCpScale").toBool(); QMiarex::s_LegendMin = pSettings->value("LegendMin").toDouble(); QMiarex::s_LegendMax = pSettings->value("LegendMax").toDouble(); s_pos = pSettings->value("Position").toInt(); s_NX = pSettings->value("NX").toInt(); s_DeltaL = pSettings->value("DeltaL").toDouble(); s_XFactor = pSettings->value("XFactor").toDouble(); s_XOffset = pSettings->value("XOffset").toDouble(); s_ZOffset = pSettings->value("ZOffset").toDouble(); } pSettings->endGroup(); return true; } bool GL3DScales::SaveSettings(QSettings *pSettings) { pSettings->beginGroup("GL3DScales"); { pSettings->setValue("AutoCpScale", QMiarex::s_bAutoCpScale); pSettings->setValue("LegendMin", QMiarex::s_LegendMin); pSettings->setValue("LegendMax", QMiarex::s_LegendMax); pSettings->setValue("Position", s_pos); pSettings->setValue("NX", s_NX); pSettings->setValue("DeltaL", s_DeltaL); pSettings->setValue("XFactor", s_XFactor); pSettings->setValue("XOffset", s_XOffset); pSettings->setValue("ZOffset", s_ZOffset); } pSettings->endGroup(); return true; } void GL3DScales::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Escape: { MainFrame* pMainFrame = (MainFrame*)m_pMainFrame; pMainFrame->m_pctrl3DScalesWidget->hide(); return; } default: event->ignore(); } } xflr5-6.09-06/src/miarex/WingScaleDlg.h000644 001750 000144 00000004104 12247174407 021025 0ustar00techwinderusers000000 000000 /**************************************************************************** WingScaleDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef WINGSCALEDLG_H #define WINGSCALEDLG_H #include #include #include #include "../misc/DoubleEdit.h" class WingScaleDlg : public QDialog { Q_OBJECT friend class QMiarex; friend class MainFrame; public: WingScaleDlg(QWidget *pParent); void InitDialog(double const &RefSpan, double const &RefChord, double const &RefSweep, double const &RefTwist); private: void SetupLayout(); void ReadData(); void SetResults(); void EnableControls(); private slots: void OnOK(); void OnClickedCheckBox(); void OnEditingFinished(); public: QCheckBox *m_pctrlSpan, *m_pctrlChord, *m_pctrlSweep, *m_pctrlTwist; DoubleEdit *m_pctrlNewSpan, *m_pctrlNewChord, *m_pctrlNewSweep, *m_pctrlNewTwist; QLabel *m_pctrlRefSpan, *m_pctrlRefChord, *m_pctrlRefSweep, *m_pctrlRefTwist; QLabel *m_pctrlSpanRatio, *m_pctrlChordRatio, *m_pctrlSweepRatio, *m_pctrlTwistRatio; QLabel *m_pctrlUnit20, *m_pctrlUnit21; bool m_bSweep, m_bSpan, m_bChord, m_bTwist; double m_NewSweep, m_NewChord, m_NewTwist, m_NewSpan; double m_RefSweep, m_RefChord, m_RefTwist, m_RefSpan; }; #endif // WINGSCALEDLG_H xflr5-6.09-06/src/miarex/CtrlTableDelegate.cpp000644 001750 000144 00000013365 12247174402 022370 0ustar00techwinderusers000000 000000 /**************************************************************************** CtrlTableDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "CtrlTableDelegate.h" #include CtrlTableDelegate::CtrlTableDelegate(QObject *parent) : QItemDelegate(parent) { } QWidget *CtrlTableDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex & index ) const { if(index.column()==0) { QLineEdit *editor = new QLineEdit(parent); editor->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); return editor; } else { DoubleEdit *editor = new DoubleEdit(parent); editor->setAlignment(Qt::AlignRight | Qt::AlignVCenter); editor->SetPrecision(m_Precision[index.column()]); return editor; } return NULL; } void CtrlTableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if(index.column()==0) { QString strong = index.model()->data(index, Qt::EditRole).toString(); QLineEdit *lineEdit = (QLineEdit*)editor; lineEdit->setText(strong); } else { double value = index.model()->data(index, Qt::EditRole).toDouble(); DoubleEdit *pDE = static_cast(editor); pDE->SetValue(value); } } void CtrlTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { if(index.column()==0) { QString strong; QLineEdit *pLineEdit = static_cast(editor); strong = pLineEdit->text(); model->setData(index, strong, Qt::EditRole); } else { DoubleEdit *pDE = static_cast(editor); double value = pDE->Value(); model->setData(index, value, Qt::EditRole); } } void CtrlTableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QString strong; // int NCtrls = 2; QStyleOptionViewItem myOption = option; // QMiarex *pMiarex = (QMiarex*)s_pMiarex; // NCtrls = pMiarex->m_poaCtrl->size(); /* if(index.row()> NCtrls) { strong=" "; drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } else */ if(index.column()==0) { myOption.displayAlignment = Qt::AlignLeft | Qt::AlignVCenter; strong = index.model()->data(index, Qt::DisplayRole).toString(); drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } /* else if(index.column()==1) { myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; strong = QString("%1").arg(index.model()->data(index, Qt::DisplayRole).toInt()); drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); }*/ else { myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; strong = QString("%1").arg(index.model()->data(index, Qt::DisplayRole).toDouble(), 0,'f',m_Precision[index.column()]); drawDisplay(painter, myOption, myOption.rect, strong); drawFocus(painter, myOption, myOption.rect); } } void CtrlTableDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { editor->setGeometry(option.rect); } void CtrlTableDelegate::drawCheck(QPainter *painter, const QStyleOptionViewItem &option, const QRect &, Qt::CheckState state) const { const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; QRect checkRect = QStyle::alignedRect(option.direction, Qt::AlignCenter, option.rect.size(), QRect(option.rect.x() + textMargin, option.rect.y(), option.rect.width() - (textMargin * 2), option.rect.height())); QItemDelegate::drawCheck(painter, option, checkRect, state); } bool CtrlTableDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { // make sure that the item is checkable Qt::ItemFlags flags = model->flags(index); if (!(flags & Qt::ItemIsUserCheckable) || !(flags & Qt::ItemIsEnabled)) return false; // make sure that we have a check state QVariant value = index.data(Qt::CheckStateRole); if (!value.isValid()) return false; // make sure that we have the right event type if (event->type() == QEvent::MouseButtonRelease) { const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; QRect checkRect = QStyle::alignedRect(option.direction, Qt::AlignCenter, option.rect.size(), QRect(option.rect.x() + textMargin, option.rect.y(), option.rect.width() - (2 * textMargin), option.rect.height())); if (!checkRect.contains(static_cast(event)->pos())) return false; } else if (event->type() == QEvent::KeyPress) { if ( static_cast(event)->key() != Qt::Key_Space && static_cast(event)->key() != Qt::Key_Select) return false; } else { return false; } Qt::CheckState state = (static_cast(value.toInt()) == Qt::Checked ? Qt::Unchecked : Qt::Checked); return model->setData(index, state, Qt::CheckStateRole); } xflr5-6.09-06/src/miarex/Miarex.cpp000755 001750 000144 00001524027 12250570143 020310 0ustar00techwinderusers000000 000000 /**************************************************************************** Miarex Copyright (C) 2008-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include "Miarex.h" #include "./GLCreateLists.h" #include "./GLCreateBodyLists.h" #include "../mainframe.h" #include "../twodwidget.h" #include "../globals.h" #include #include "NURBSDomDoc.h" #include "PlaneDlg.h" #include "GL3dWingDlg.h" #include "GL3dBodyDlg.h" #include "StabPolarDlg.h" #include "ManageUFOsDlg.h" #include "InertiaDlg.h" #include "WingScaleDlg.h" #include "WAdvancedDlg.h" #include "WPolarDlg.h" #include "StabPolarDlg.h" #include "StabViewDlg.h" #include "../graph/GraphDlg.h" #include "../misc/ProgressDlg.h" #include "../misc/ModDlg.h" #include "../misc/RenameDlg.h" #include "../misc/PolarFilterDlg.h" #include "../misc/ObjectPropsDlg.h" #include "../misc/UnitsDlg.h" #include "../misc/W3dPrefsDlg.h" #include "../misc/GLLightDlg.h" void *QMiarex::s_pMainFrame; void *QMiarex::s_p2dWidget; void *QMiarex::s_p3dWidget; double QMiarex::s_CoreSize = 0.000001; double QMiarex::s_MinPanelSize = 0.0001; bool QMiarex::s_bAxes = true; bool QMiarex::s_bOutline = true; bool QMiarex::s_bSurfaces = true; bool QMiarex::s_bShowMasses = false; bool QMiarex::s_bFoilNames = false; bool QMiarex::s_bVLMPanels = false; bool QMiarex::s_bAutoCpScale = true; double QMiarex::s_LegendMin = -1.0; double QMiarex::s_LegendMax = 1.0; #define VLMMAXMATSIZE 5000 /**< The max number of VLM panels for the whole plane. Sets the size of the influence matrix and its RHS.*/ #define VLMHALF 2500 /**< Half the value of VLMMAXMATSIZE. */ #define VLMMAXRHS 100 /**< The max number of points which may be calculated in a single sequence. Has an impact on the memory reserved at program launch the size of the */ int QMiarex::s_MaxMatSize = VLMMAXMATSIZE; int QMiarex::s_MaxRHSSize = VLMMAXRHS; /** * The public constructor. * * @param parent: a pointer to the parent window */ QMiarex::QMiarex(QWidget *parent) : QWidget(parent) { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; //construct and initialize everything m_pLLTDlg = new LLTAnalysisDlg(pMainFrame); m_pPanelDlg = new PanelAnalysisDlg (pMainFrame); Wing::s_p3DPanelDlg = m_pPanelDlg; //pointer to the 3DPanel analysis dialog class m_pPanelDlg->m_pCoreSize = &s_CoreSize; m_pglLightDlg = new GLLightDlg(pMainFrame); m_Node = m_MemNode = m_WakeNode = m_RefWakeNode = NULL; m_Panel = m_MemPanel = m_WakePanel = m_RefWakePanel = NULL; int memsize=0; if(!Allocate(memsize)) { QMessageBox::warning(pMainFrame,tr("Warning"),"This computer does not have enough memory resources to run XFLR5\n"); } QString strange = QString("Initial memory allocation for PanelAnalysis is %1 MB").arg((double)memsize/1024./1024., 7, 'f', 2); Trace(strange); m_pXFile = NULL; m_pCurPlane = NULL; m_pCurWing = NULL; m_pCurPOpp = NULL; m_pCurWPolar = NULL; m_pCurWOpp = NULL; m_pCurGraph = m_WingGraph; for(int iw=0; iwsize(); ip++) { Plane *pPlane = (Plane*)m_poaPlane->at(ip); if(pPlane->m_BodyName==pBody->m_BodyName) { // duplicate the body - create one for each plane // no more bodies associated to multiple plane Body *planeBody = new Body(); planeBody->Duplicate(pBody); //attach it and rename it pPlane->SetBody(planeBody); } } /* for(int ib=0; ibsize(); ib++) { Body *pOldBody = (Body*)m_poaBody->at(ib); if(pOldBody==pBody) { m_poaBody->removeAt(ib); delete pBody; //discarded } } */ } /** * Inserts a plane in the array of plane objects * @param pPlane: the plane to be inserted * @return a pointer to the input CPlane object, or NULL if the CPlane could not be inserted */ Plane* QMiarex::AddPlane(Plane *pPlane) { int i,j; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; Plane *pOldPlane; bool bExists = false; bool bInserted = false; for (i=0; isize(); i++) { pOldPlane = (Plane*)m_poaPlane->at(i); if (pOldPlane->PlaneName() == pPlane->PlaneName()) { bExists = true; break; } } while(!bInserted) { if(!bExists) { for (j=0; jsize(); j++) { pOldPlane = (Plane*)m_poaPlane->at(j); if (pPlane->PlaneName() < pOldPlane->PlaneName()) { m_poaPlane->insert(j, pPlane); bInserted = true; break; } } if(!bInserted) { m_poaPlane->append(pPlane); bInserted = true; } return pPlane; } else { //overwrite it all for (int l=0; lsize(); l++) { pOldPlane = (Plane*)m_poaPlane->at(l); if (pOldPlane->PlaneName() == pPlane->PlaneName()) { pMainFrame->DeletePlane(pOldPlane, false); } } bExists = false; } } return NULL; } /** * Creates the plane's operating point, * fills it with the input resulting from the VLM or 3D-panel analysis, * and inserts it in the array of plane operating points * * In output, fills the pPOpp object and returns the pointer *@param bPointOut: if true, part of the oppoint viscous properties could not be interpolated *@param Cp: the array of Cp value for each panel *@param Gamma: the array of circulation or doublet strengths Gamma for each panel *@param Sigma: the array of source strengths for a panel analysis *@param pPOpp: A point to the CPOpp object to be inserted */ void QMiarex::AddPOpp(bool bPointOut, double *Cp, double *Gamma, double *Sigma, PlaneOpp *pPOpp) { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; PlaneOpp *pOldPOpp = NULL; WingOpp *pWOpp=NULL; int i,l,p; double Cb = 0.0; if(!pPOpp) { // loads PAnalysis results in the POpPoint // else we're adding from serialization if(!m_bKeepOutOpps && bPointOut) return; pPOpp = new PlaneOpp(m_MatSize); if(pPOpp==NULL) return; pPOpp->m_Color = pMainFrame->GetColor(6); for(int iw=0; iwAddWingOpp(iw, m_pWingList[iw]->m_MatSize); CreateWOpp(pPOpp->m_pPlaneWOpp[iw], m_pWingList[iw]); } } pWOpp = pPOpp->m_pPlaneWOpp[0]; pPOpp->m_PlaneName = m_pCurPlane->PlaneName(); pPOpp->m_bVLM1 = m_pCurWPolar->m_bVLM1; pPOpp->m_PlrName = m_pCurWPolar->m_PlrName; pWOpp->m_WPolarType = m_pCurWPolar->m_WPolarType; pPOpp->m_WPolarType = m_pCurWPolar->m_WPolarType; pPOpp->m_NStation = m_pCurWing->m_NStation; pWOpp->m_nFlaps = m_pCurWing->m_nFlaps; for (i=0; im_nFlaps; i++) { pWOpp->m_FlapMoment[i] = m_pCurWing->m_FlapMoment[i]; } for (l=0; lm_NStation; l++) { if(qAbs(m_pCurWing->m_BendingMoment[l])>qAbs(Cb)) Cb = m_pCurWing->m_BendingMoment[l]; } pWOpp->m_MaxBending = (float)Cb; if(m_pCurWPolar->m_AnalysisMethod==VLMMETHOD) { QMessageBox::warning(pMainFrame,tr("Warning"),"OldVLM polar\n"); } else if(m_pCurWPolar->m_AnalysisMethod==PANELMETHOD && m_pPanelDlg) { //get the data from the PanelAnalysis dialog, and from the plane object pPOpp->m_NPanels = m_pPanelDlg->m_MatSize; pPOpp->m_Alpha = m_pPanelDlg->m_OpAlpha; pPOpp->m_QInf = m_pPanelDlg->m_QInf; pWOpp->m_Alpha = m_pPanelDlg->m_OpAlpha; pWOpp->m_QInf = m_pPanelDlg->m_QInf; pWOpp->m_CL = m_pPanelDlg->m_CL; pWOpp->m_CX = m_pPanelDlg->m_CX; pWOpp->m_CY = m_pPanelDlg->m_CY; pWOpp->m_ICD = m_pPanelDlg->m_InducedDrag; pWOpp->m_VCD = m_pPanelDlg->m_ViscousDrag; pWOpp->m_GCm = m_pPanelDlg->m_GCm; pWOpp->m_VCm = m_pPanelDlg->m_VCm; pWOpp->m_ICm = m_pPanelDlg->m_ICm; pWOpp->m_GRm = m_pPanelDlg->m_GRm; pWOpp->m_GYm = m_pPanelDlg->m_GYm; pWOpp->m_VYm = m_pPanelDlg->m_VYm; pWOpp->m_IYm = m_pPanelDlg->m_IYm; pWOpp->m_CP = m_pPanelDlg->m_CP; pPOpp->m_Beta = m_pCurWPolar->m_Beta; pWOpp->m_Beta = m_pCurWPolar->m_Beta; if(m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { pPOpp->m_Alpha = m_pPanelDlg->m_AlphaEq; pPOpp->m_QInf = m_pPanelDlg->u0; pPOpp->m_Ctrl = m_pPanelDlg->m_Ctrl; pWOpp->m_Ctrl = m_pPanelDlg->m_Ctrl; pWOpp->m_QInf = m_pPanelDlg->u0; pWOpp->m_Alpha = m_pPanelDlg->m_AlphaEq; for(i=0; i<4; i++) { pWOpp->m_EigenValue[i] = m_pPanelDlg->m_rLong[i]; pWOpp->m_EigenValue[i+4] = m_pPanelDlg->m_rLat[i]; for(l=0;l<4; l++) { pWOpp->m_EigenVector[i][l] = m_pPanelDlg->m_vLong[4*i+l]; pWOpp->m_EigenVector[i+4][l] = m_pPanelDlg->m_vLat[4*i+l]; } } pPOpp->m_pPlaneWOpp[0]->m_XNP = m_pPanelDlg->XNP; pPOpp->m_pPlaneWOpp[0]->CXu = m_pPanelDlg->CXu; pPOpp->m_pPlaneWOpp[0]->CZu = m_pPanelDlg->CZu; pPOpp->m_pPlaneWOpp[0]->Cmu = m_pPanelDlg->Cmu; pPOpp->m_pPlaneWOpp[0]->CXa = m_pPanelDlg->CXa; pPOpp->m_pPlaneWOpp[0]->CLa = -m_pPanelDlg->CZa; pPOpp->m_pPlaneWOpp[0]->Cma = m_pPanelDlg->Cma; pPOpp->m_pPlaneWOpp[0]->CXq = m_pPanelDlg->CXq; pPOpp->m_pPlaneWOpp[0]->CLq = -m_pPanelDlg->CZq; pPOpp->m_pPlaneWOpp[0]->Cmq = m_pPanelDlg->Cmq; pPOpp->m_pPlaneWOpp[0]->CYb = m_pPanelDlg->CYb; pPOpp->m_pPlaneWOpp[0]->Clb = m_pPanelDlg->Clb; pPOpp->m_pPlaneWOpp[0]->Cnb = m_pPanelDlg->Cnb; pPOpp->m_pPlaneWOpp[0]->CYp = m_pPanelDlg->CYp; pPOpp->m_pPlaneWOpp[0]->Clp = m_pPanelDlg->Clp; pPOpp->m_pPlaneWOpp[0]->Cnp = m_pPanelDlg->Cnp; pPOpp->m_pPlaneWOpp[0]->CYr = m_pPanelDlg->CYr; pPOpp->m_pPlaneWOpp[0]->Clr = m_pPanelDlg->Clr; pPOpp->m_pPlaneWOpp[0]->Cnr = m_pPanelDlg->Cnr; //Only one control derivative for all the controls of the polar pPOpp->m_pPlaneWOpp[0]->m_nControls = 1; pPOpp->m_pPlaneWOpp[0]->CXe = m_pPanelDlg->CXe; pPOpp->m_pPlaneWOpp[0]->CYe = m_pPanelDlg->CYe; pPOpp->m_pPlaneWOpp[0]->CZe = m_pPanelDlg->CZe; pPOpp->m_pPlaneWOpp[0]->CLe = m_pPanelDlg->Cle; pPOpp->m_pPlaneWOpp[0]->CMe = m_pPanelDlg->Cme; pPOpp->m_pPlaneWOpp[0]->CNe = m_pPanelDlg->Cne; memcpy(pWOpp->m_ALong, m_pPanelDlg->m_ALong, 16*sizeof(double)); memcpy(pWOpp->m_ALat, m_pPanelDlg->m_ALat, 16*sizeof(double)); memcpy(pWOpp->m_BLong, m_pPanelDlg->m_BLong, 4*sizeof(double)); memcpy(pWOpp->m_BLat, m_pPanelDlg->m_BLat, 4*sizeof(double)); } else { pPOpp->m_Ctrl = 0.0; pWOpp->m_Ctrl = 0.0; memset(pWOpp->m_EigenValue, 0, sizeof(pWOpp->m_EigenValue)); memset(pWOpp->m_EigenVector, 0, sizeof(pWOpp->m_EigenVector)); memset(pWOpp->m_ALong, 0, 16*sizeof(double)); memset(pWOpp->m_ALat, 0, 16*sizeof(double)); } } for(int iw=0;iwm_pPlaneWOpp[iw]) { pPOpp->m_pPlaneWOpp[iw]->m_Alpha = pPOpp->m_Alpha; pPOpp->m_pPlaneWOpp[iw]->m_QInf = pPOpp->m_QInf; } } for(int ip=0; ipm_NPanels; ip++) { pPOpp->m_Cp[ip] = (float)Cp[ip]; if(Gamma) pPOpp->m_G[ip] = (float)Gamma[ip]; if(Sigma) pPOpp->m_Sigma[ip] = (float)Sigma[ip]; } p = 0; for(int iw=0; iwm_PlaneWOpp[iw].m_Cp, pPOpp->m_Cp+p, m_pWingList[iw]->m_MatSize*sizeof(float)); for(int ip=0; ipm_MatSize;ip++) { if(pPOpp->m_pPlaneWOpp[iw]) { pPOpp->m_pPlaneWOpp[iw]->m_Cp[ip] = (float)Cp[ip+p]; pPOpp->m_pPlaneWOpp[iw]->m_G[ip] = (float)Gamma[ip+p]; pPOpp->m_pPlaneWOpp[iw]->m_Sigma[ip] = (float)Sigma[ip+p]; } } p+=m_pWingList[iw]->m_MatSize; } } //add the data to the polar object m_pCurWPolar->AddPoint(pPOpp); } MainFrame::SetSaveState(false); bool bIsInserted = false; // add the POpPoint to the POpPoint Array for the current PlaneName if(m_bStoreWOpp) { for (i=0; isize(); i++) { pOldPOpp = (PlaneOpp*)m_poaPOpp->at(i); if (pPOpp->m_PlaneName == pOldPOpp->m_PlaneName) { if (pPOpp->m_PlrName == pOldPOpp->m_PlrName) { if(pPOpp->m_WPolarTypem_Alpha - pOldPOpp->m_Alpha)<0.005) { //replace existing point pPOpp->m_Color = pOldPOpp->m_Color; pPOpp->m_Style = pOldPOpp->m_Style; pPOpp->m_Width = pOldPOpp->m_Width; pPOpp->m_bIsVisible = pOldPOpp->m_bIsVisible; pPOpp->m_bShowPoints = pOldPOpp->m_bShowPoints; if (m_pCurPOpp == pOldPOpp) { m_pCurPOpp = NULL; m_pCurWOpp = NULL; } m_poaPOpp->removeAt(i); delete pOldPOpp; m_poaPOpp->insert(i, pPOpp); bIsInserted = true; i = m_poaPOpp->size();// to break } else if (pPOpp->m_Alpha > pOldPOpp->m_Alpha) { //insert point m_poaPOpp->insert(i, pPOpp); bIsInserted = true; i = m_poaPOpp->size();// to break } } else if (pPOpp->m_WPolarType==FIXEDAOAPOLAR) { if(qAbs(pPOpp->m_QInf - pOldPOpp->m_QInf)<0.1) { //replace existing point pPOpp->m_Color = pOldPOpp->m_Color; pPOpp->m_Style = pOldPOpp->m_Style; pPOpp->m_Width = pOldPOpp->m_Width; pPOpp->m_bIsVisible = pOldPOpp->m_bIsVisible; pPOpp->m_bShowPoints = pOldPOpp->m_bShowPoints; if (m_pCurPOpp == pOldPOpp) { m_pCurPOpp = NULL; m_pCurWOpp = NULL; } m_poaPOpp->removeAt(i); delete pOldPOpp; m_poaPOpp->insert(i, pPOpp); bIsInserted = true; i = m_poaPOpp->size();// to break } else if (pPOpp->m_QInf > pOldPOpp->m_QInf) { //insert point m_poaPOpp->insert(i, pPOpp); bIsInserted = true; i = m_poaPOpp->size();// to break } } else if(pPOpp->m_WPolarType==STABILITYPOLAR) { if(qAbs(pPOpp->m_Ctrl - pOldPOpp->m_Ctrl)<0.005) { //replace existing point pPOpp->m_Color = pOldPOpp->m_Color; pPOpp->m_Style = pOldPOpp->m_Style; pPOpp->m_Width = pOldPOpp->m_Width; pPOpp->m_bIsVisible = pOldPOpp->m_bIsVisible; pPOpp->m_bShowPoints = pOldPOpp->m_bShowPoints; if (m_pCurPOpp == pOldPOpp) { m_pCurPOpp = NULL; m_pCurWOpp = NULL; } m_poaPOpp->removeAt(i); delete pOldPOpp; m_poaPOpp->insert(i, pPOpp); bIsInserted = true; i = m_poaPOpp->size();// to break } else if (pPOpp->m_Ctrl > pOldPOpp->m_Ctrl) { //insert point m_poaPOpp->insert(i, pPOpp); bIsInserted = true; i = m_poaPOpp->size();// to break } } } } } if (!bIsInserted) m_poaPOpp->append(pPOpp); for(int iw=0; iwm_pPlaneWOpp[iw]) { pPOpp->m_pPlaneWOpp[iw]->m_Color = pPOpp->m_Color; pPOpp->m_pPlaneWOpp[iw]->m_Style = pPOpp->m_Style; pPOpp->m_pPlaneWOpp[iw]->m_Width = pPOpp->m_Width; } } } else { delete pPOpp; m_pCurPOpp = NULL; m_pCurWOpp = NULL; } } /** * Adds the wing pointed by pWing to the array of wing objects * places it in alphabetical order *@param pWing a pointer to the instand of the wing to be inserted in the array *@return the pointer to the wing which was inserted, or NULL if the insertion failed */ Wing* QMiarex::AddWing(Wing *pWing) { int i,j; bool bExists = false; bool bInserted = false; Wing *pOldWing; // MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(pWing->m_WingName.length()) { for (i=0; isize(); i++) { pOldWing = (Wing*)m_poaWing->at(i); if (pOldWing->m_WingName == pWing->m_WingName) { bExists = true; break; } } } else bExists = true; while(!bInserted) { if(!bExists) { for (j=0; jsize(); j++) { pOldWing = (Wing*)m_poaWing->at(j); if (pWing->m_WingName.compare(pOldWing->m_WingName, Qt::CaseInsensitive)<0) { m_poaWing->insert(j, pWing); bInserted = true; break; } } if(!bInserted) { m_poaWing->append(pWing); bInserted = true; } return pWing; } else { //Ask for user intentions if(SetModWing(pWing)) { m_poaWing->append(pWing); return pWing; } else { delete pWing; return NULL; } bExists = false; } } return NULL; } /** * Creates the operating point for the active wing, fills it with the data passed in input, and inserts it in the array of wing operating points * *@param QInf the operating point's velocity *@param Alpha the operating point's aoa *@param bPointOut true if the inerpolation of viscous properties was unsuccessfull *@param Gamma a pointer to the array of doublet or circulation strengths *@param Sigma a pointer to the array of source strengths *@param Cp a pointer to the array of Cp Coeffcients * */ void QMiarex::AddWOpp(double QInf, double Alpha, bool bPointOut, double *Gamma, double *Sigma, double *Cp) { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; int i,l; if(!m_bKeepOutOpps && bPointOut) return; MainFrame::SetSaveState(false); WingOpp *pWOpp; WingOpp * pNewPoint; pNewPoint = new WingOpp(m_MatSize); if(pNewPoint == NULL) { QMessageBox::warning(pMainFrame,tr("Warning"),tr("Not enough memory to store the OpPoint\n")); return; } else { //load WOpp with data pNewPoint->m_Color = pMainFrame->GetColor(5); pNewPoint->m_WingName = m_pCurWing->WingName(); pNewPoint->m_Span = m_pCurWPolar->m_WSpan; pNewPoint->m_MAChord = m_pCurWing->m_MAChord; pNewPoint->m_NStation = m_pCurWing->m_NStation; pNewPoint->m_PlrName = m_pCurWPolar->m_PlrName; pNewPoint->m_AnalysisMethod = m_pCurWPolar->m_AnalysisMethod; pNewPoint->m_bVLM1 = m_pCurWPolar->m_bVLM1; pNewPoint->m_bThinSurface = m_pCurWPolar->m_bThinSurfaces; pNewPoint->m_bTiltedGeom = m_pCurWPolar->m_bTiltedGeom; pNewPoint->m_WPolarType = m_pCurWPolar->m_WPolarType; pNewPoint->m_Weight = m_pCurWPolar->m_Mass; double Cb =0.0; if(m_pCurWPolar->m_AnalysisMethod==LLTMETHOD) { //get the data from the LLTAnalysis dialog, and from the wing object pNewPoint->m_Alpha = Alpha; pNewPoint->m_QInf = QInf; pNewPoint->m_NVLMPanels = m_pCurWing->m_MatSize; pNewPoint->m_bOut = m_pLLTDlg->m_LLT.m_bWingOut; pNewPoint->m_CL = m_pLLTDlg->m_LLT.m_CL; // pNewPoint->m_CY = m_pCurWing->m_CY; // pNewPoint->m_CX = m_pCurWing->m_CX; pNewPoint->m_ICD = m_pLLTDlg->m_LLT.m_CDi; pNewPoint->m_GCm = m_pLLTDlg->m_LLT.m_GCm; pNewPoint->m_VCm = m_pLLTDlg->m_LLT.m_VCm; pNewPoint->m_ICm = m_pLLTDlg->m_LLT.m_ICm; pNewPoint->m_GRm = m_pLLTDlg->m_LLT.m_GRm; pNewPoint->m_GYm = m_pLLTDlg->m_LLT.m_GYm; pNewPoint->m_VYm = m_pLLTDlg->m_LLT.m_VYm; pNewPoint->m_IYm = m_pLLTDlg->m_LLT.m_IYm; pNewPoint->m_CP = m_pLLTDlg->m_LLT.m_CP; pNewPoint->m_VCD = m_pLLTDlg->m_LLT.m_CDv; pNewPoint->ReleasePanelSizeArrays(); for (l=1; lm_NStation; l++) { pNewPoint->m_SpanPos[l] = -(float)m_pLLTDlg->m_LLT.m_SpanPos[l]; pNewPoint->m_StripArea[l] = (float)m_pLLTDlg->m_LLT.m_StripArea[l]; pNewPoint->m_Ai[l] = (float)m_pLLTDlg->m_LLT.m_Ai[m_NStation-l]; pNewPoint->m_Cl[l] = (float)m_pLLTDlg->m_LLT.m_Cl[m_NStation-l]; pNewPoint->m_PCd[l] = (float)m_pLLTDlg->m_LLT.m_PCd[m_NStation-l]; pNewPoint->m_ICd[l] = (float)m_pLLTDlg->m_LLT.m_ICd[m_NStation-l]; pNewPoint->m_Cm[l] = (float)m_pLLTDlg->m_LLT.m_Cm[m_NStation-l]; pNewPoint->m_CmAirf[l] = (float)m_pLLTDlg->m_LLT.m_CmAirf[m_NStation-l]; pNewPoint->m_XCPSpanRel[l] = (float)m_pLLTDlg->m_LLT.m_XCPSpanRel[m_NStation-l]; pNewPoint->m_XCPSpanAbs[l] = (float)m_pLLTDlg->m_LLT.m_XCPSpanAbs[m_NStation-l]; pNewPoint->m_Re[l] = (float)m_pLLTDlg->m_LLT.m_Re[m_NStation-l]; pNewPoint->m_Chord[l] = (float)m_pLLTDlg->m_LLT.m_Chord[m_NStation-l]; pNewPoint->m_Twist[l] = (float)m_pLLTDlg->m_LLT.m_Twist[m_NStation-l]; pNewPoint->m_XTrTop[l] = (float)m_pLLTDlg->m_LLT.m_XTrTop[m_NStation-l]; pNewPoint->m_XTrBot[l] = (float)m_pLLTDlg->m_LLT.m_XTrBot[m_NStation-l]; pNewPoint->m_BendingMoment[l] = (float)m_pLLTDlg->m_LLT.m_BendingMoment[m_NStation-l]; if(qAbs(m_pLLTDlg->m_LLT.m_BendingMoment[l])>qAbs(Cb)) Cb = m_pLLTDlg->m_LLT.m_BendingMoment[l]; } } else if(m_pCurWPolar->m_AnalysisMethod==VLMMETHOD) { //obsolete QMessageBox::warning(pMainFrame,tr("Warning"),"OldVLM Polar\n"); } else if(m_pCurWPolar->m_AnalysisMethod==PANELMETHOD && m_pPanelDlg) { //get the data from the PanelAnalysis dialog, and from the wing object pNewPoint->m_Alpha = m_pPanelDlg->m_OpAlpha; pNewPoint->m_QInf = m_pPanelDlg->m_QInf; pNewPoint->m_Ctrl = m_pPanelDlg->m_Ctrl; pNewPoint->m_NVLMPanels = m_pPanelDlg->m_MatSize; pNewPoint->m_bOut = m_pPanelDlg->m_bPointOut; pNewPoint->m_CL = m_pPanelDlg->m_CL; pNewPoint->m_CY = m_pPanelDlg->m_CY; pNewPoint->m_CX = m_pPanelDlg->m_CX; pNewPoint->m_ICD = m_pPanelDlg->m_InducedDrag; pNewPoint->m_VCD = m_pPanelDlg->m_ViscousDrag; pNewPoint->m_GCm = m_pPanelDlg->m_GCm; pNewPoint->m_VCm = m_pPanelDlg->m_VCm; pNewPoint->m_ICm = m_pPanelDlg->m_ICm; pNewPoint->m_GRm = m_pPanelDlg->m_GRm; pNewPoint->m_GYm = m_pPanelDlg->m_GYm; pNewPoint->m_VYm = m_pPanelDlg->m_VYm; pNewPoint->m_IYm = m_pPanelDlg->m_IYm; pNewPoint->m_CP = m_pPanelDlg->m_CP; pNewPoint->m_Beta = m_pCurWPolar->m_Beta; for (l=0; lm_NStation; l++) { pNewPoint->m_Ai[l] = (float)m_pCurWing->m_Ai[l]; pNewPoint->m_SpanPos[l] = (float)m_pCurWing->m_SpanPos[l]; pNewPoint->m_StripArea[l] = (float)m_pCurWing->m_StripArea[l]; pNewPoint->m_Re[l] = (float)m_pCurWing->m_Re[l]; pNewPoint->m_Cl[l] = (float)m_pCurWing->m_Cl[l]; pNewPoint->m_ICd[l] = (float)m_pCurWing->m_ICd[l]; pNewPoint->m_PCd[l] = (float)m_pCurWing->m_PCd[l]; pNewPoint->m_Cm[l] = (float)m_pCurWing->m_Cm[l]; pNewPoint->m_CmAirf[l] = (float)m_pCurWing->m_CmAirf[l]; pNewPoint->m_XCPSpanRel[l] = (float)m_pCurWing->m_XCPSpanRel[l]; pNewPoint->m_XCPSpanAbs[l] = (float)m_pCurWing->m_XCPSpanAbs[l]; pNewPoint->m_Chord[l] = (float)m_pCurWing->m_Chord[l]; pNewPoint->m_Twist[l] = (float)m_pCurWing->m_Twist[l]; pNewPoint->m_XTrTop[l] = (float)m_pCurWing->m_XTrTop[l]; pNewPoint->m_XTrBot[l] = (float)m_pCurWing->m_XTrBot[l]; pNewPoint->m_BendingMoment[l] = (float)m_pCurWing->m_BendingMoment[l]; if(qAbs(m_pCurWing->m_BendingMoment[l])>qAbs(Cb)) Cb = m_pCurWing->m_BendingMoment[l]; } memcpy(pNewPoint->m_Vd, m_pCurWing->m_Vd, sizeof(pNewPoint->m_Vd)); memcpy(pNewPoint->m_F, m_pCurWing->m_F, sizeof(pNewPoint->m_F)); for(int ip=0; ipm_MatSize; ip++) { pNewPoint->m_Cp[ip] = (float)Cp[ip]; pNewPoint->m_G[ip] = (float)Gamma[ip]; pNewPoint->m_Sigma[ip] = (float)Sigma[ip]; } if(m_pCurWPolar->m_bWakeRollUp) { pNewPoint->m_nWakeNodes = m_nWakeNodes; pNewPoint->m_NXWakePanels = m_pCurWPolar->m_NXWakePanels; pNewPoint->m_FirstWakePanel = m_pCurWPolar->m_TotalWakeLength; pNewPoint->m_WakeFactor = m_pCurWPolar->m_WakePanelFactor; } else { pNewPoint->m_nWakeNodes = 0; pNewPoint->m_NXWakePanels = 1; pNewPoint->m_FirstWakePanel = m_pCurWPolar->m_WSpan; pNewPoint->m_WakeFactor = 1.0; } for (i=0; im_nFlaps; i++) pNewPoint->m_FlapMoment[i] = m_pCurWing->m_FlapMoment[i]; pNewPoint->m_nFlaps = m_pCurWing->m_nFlaps; for(i=0; i<4; i++) { pNewPoint->m_EigenValue[i] = m_pPanelDlg->m_rLong[i]; pNewPoint->m_EigenValue[i+4] = m_pPanelDlg->m_rLat[i]; for(l=0;l<4; l++) { pNewPoint->m_EigenVector[i][l] = m_pPanelDlg->m_vLong[4*i+l]; pNewPoint->m_EigenVector[i+4][l] = m_pPanelDlg->m_vLat[4*i+l]; } } pNewPoint->m_XNP = m_pPanelDlg->XNP; pNewPoint->CXu = m_pPanelDlg->CXu; pNewPoint->CZu = m_pPanelDlg->CZu; pNewPoint->Cmu = m_pPanelDlg->Cmu; pNewPoint->CXa = m_pPanelDlg->CXa; pNewPoint->CLa = -m_pPanelDlg->CZa; pNewPoint->Cma = m_pPanelDlg->Cma; pNewPoint->CXq = m_pPanelDlg->CXq; pNewPoint->CLq = -m_pPanelDlg->CZq; pNewPoint->Cmq = m_pPanelDlg->Cmq; pNewPoint->CYb = m_pPanelDlg->CYb; pNewPoint->Clb = m_pPanelDlg->Clb; pNewPoint->Cnb = m_pPanelDlg->Cnb; pNewPoint->CYp = m_pPanelDlg->CYp; pNewPoint->Clp = m_pPanelDlg->Clp; pNewPoint->Cnp = m_pPanelDlg->Cnp; pNewPoint->CYr = m_pPanelDlg->CYr; pNewPoint->Clr = m_pPanelDlg->Clr; pNewPoint->Cnr = m_pPanelDlg->Cnr; //Only one control derivative for all the controls of the polar pNewPoint->m_nControls = 1; pNewPoint->CXe = m_pPanelDlg->CXe; pNewPoint->CYe = m_pPanelDlg->CYe; pNewPoint->CZe = m_pPanelDlg->CZe; pNewPoint->CLe = m_pPanelDlg->Cle; pNewPoint->CMe = m_pPanelDlg->Cme; pNewPoint->CNe = m_pPanelDlg->Cne; memcpy(pNewPoint->m_ALong, m_pPanelDlg->m_ALong, 16*sizeof(double)); memcpy(pNewPoint->m_ALat, m_pPanelDlg->m_ALat, 16*sizeof(double)); memcpy(pNewPoint->m_BLong, m_pPanelDlg->m_BLong, 4*sizeof(double)); memcpy(pNewPoint->m_BLat , m_pPanelDlg->m_BLat, 4*sizeof(double)); } pNewPoint->m_MaxBending = (float)Cb; } //add the data to the polar object m_pCurWPolar->AddPoint(pNewPoint); bool bIsInserted = false; // add the WOpPoint to the WOpPoint Array for the current WingName if(m_bStoreWOpp) { for (i=0; isize(); i++) { pWOpp = (WingOpp*)m_poaWOpp->at(i); if (pNewPoint->m_WingName == pWOpp->m_WingName) { if (pNewPoint->m_PlrName == pWOpp->m_PlrName) { if(pNewPoint->m_WPolarTypem_Alpha - pWOpp->m_Alpha)<0.005) { //replace existing point pNewPoint->m_Color = pWOpp->m_Color; pNewPoint->m_Style = pWOpp->m_Style; pNewPoint->m_Width = pWOpp->m_Width; pNewPoint->m_bIsVisible = pWOpp->m_bIsVisible; pNewPoint->m_bShowPoints = pWOpp->m_bShowPoints; if (m_pCurWOpp == pWOpp) m_pCurWOpp = NULL; m_poaWOpp->removeAt(i); delete pWOpp; m_poaWOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaWOpp->size();// to break } else if (pNewPoint->m_Alpha > pWOpp->m_Alpha) { //insert point m_poaWOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaWOpp->size();// to break } } else if(pNewPoint->m_WPolarType==FIXEDAOAPOLAR) { if(qAbs(pNewPoint->m_QInf - pWOpp->m_QInf)<0.1) { //replace existing point pNewPoint->m_Color = pWOpp->m_Color; pNewPoint->m_Style = pWOpp->m_Style; pNewPoint->m_Width = pWOpp->m_Width; pNewPoint->m_bIsVisible = pWOpp->m_bIsVisible; pNewPoint->m_bShowPoints = pWOpp->m_bShowPoints; if (m_pCurWOpp == pWOpp) m_pCurWOpp = NULL; m_poaWOpp->removeAt(i); delete pWOpp; m_poaWOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaWOpp->size();// to break } else if (pNewPoint->m_QInf > pWOpp->m_QInf) { //insert point m_poaWOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaWOpp->size();// to break } } else if(pNewPoint->m_WPolarType==STABILITYPOLAR) { if(qAbs(pNewPoint->m_Ctrl - pWOpp->m_Ctrl)<0.001) { //replace existing point pNewPoint->m_Color = pWOpp->m_Color; pNewPoint->m_Style = pWOpp->m_Style; pNewPoint->m_Width = pWOpp->m_Width; pNewPoint->m_bIsVisible = pWOpp->m_bIsVisible; pNewPoint->m_bShowPoints = pWOpp->m_bShowPoints; if (m_pCurWOpp == pWOpp) m_pCurWOpp = NULL; m_poaWOpp->removeAt(i); delete pWOpp; m_poaWOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaWOpp->size();// to break } else if (pNewPoint->m_Ctrl > pWOpp->m_Ctrl) { //insert point m_poaWOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaWOpp->size();// to break } } } } } if (!bIsInserted) m_poaWOpp->append(pNewPoint); // m_pCurWOpp = pNewPoint; } else { delete pNewPoint; pNewPoint = NULL; } } /** * Adds the WPolar pointed by pWPolar to the m_oaWPolar array. * Inserts it in alphabetical order using the UFO Name and the polar name *@param pWPolar a pointer to the instance of the CWPolar object to be inserted *@return a pointer to the instance of the CWPolar object which has been inserted, or NULL if the operation failed */ WPolar* QMiarex::AddWPolar(WPolar *pWPolar) { int i,j,k,l,p; bool bExists = false; bool bInserted = false; WPolar *pOldWPlr; WPolar *pOld2WPlr; QString strong; for (i=0; isize(); i++) { pOldWPlr = (WPolar*)m_poaWPolar->at(i); if (pOldWPlr->m_PlrName == pWPolar->m_PlrName && pOldWPlr->m_UFOName == pWPolar->m_UFOName) { bExists = true; break; } } while(!bInserted) { if(!bExists) { //if it doesn't exist, find its place in alphabetical order and insert it for (j=0; jsize(); j++) { pOldWPlr = (WPolar*)m_poaWPolar->at(j); if(pWPolar->m_UFOName.compare(pOldWPlr->m_UFOName, Qt::CaseInsensitive)<0) { m_poaWPolar->insert(j, pWPolar); bInserted = true; break; } else if (pWPolar->m_UFOName == pOldWPlr->m_UFOName) { //first sort by Type if(pWPolar->m_PlrName.compare(pOldWPlr->m_PlrName, Qt::CaseInsensitive)<0) { m_poaWPolar->insert(j, pWPolar); bInserted = true; break; } } } if(!bInserted) { m_poaWPolar->append(pWPolar); bInserted = true; } return pWPolar; } else { // if it exists, append an index to the WPolar, change the existence flag, and re-enter the loop for (l=0; lsize(); l++) { pOldWPlr = (WPolar*)m_poaWPolar->at(l); if (pOldWPlr->m_UFOName == pWPolar->m_UFOName && pOldWPlr->m_PlrName == pWPolar->m_PlrName) { p = 2; bool bFound = true; while(bFound) { strong=QString(" (%1)").arg( p); strong = pWPolar->m_PlrName + strong; for (k=0; ksize(); k++) { bFound = false; pOld2WPlr = (WPolar*)m_poaWPolar->at(k); if (pOld2WPlr->m_UFOName == pWPolar->m_UFOName && pOld2WPlr->m_PlrName == strong) { p++; bFound = true; break; } } } pWPolar->m_PlrName = strong; } } bExists = false; } } return NULL; } /** * Checks and enables all buttons and actions * depending on the currently active objects */ void QMiarex::SetControls() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; QString str_translation; blockSignals(true); if(m_pCurPlane) str_translation=tr("Current Plane"); else if(m_pCurWing) str_translation=tr("Current Wing"); else str_translation=tr("Current Object"); pMainFrame->currentUFOMenu->setTitle(str_translation); if(m_iView==W3DVIEW) m_pctrBottomControls->setCurrentIndex(1); else if(m_iView==WSTABVIEW) { if(m_iStabilityView == STAB3DVIEW) m_pctrBottomControls->setCurrentIndex(1); else m_pctrBottomControls->setCurrentIndex(0); } else m_pctrBottomControls->setCurrentIndex(0); if(m_iView==WPOLARVIEW) m_pctrlMiddleControls->setCurrentIndex(1); else if(m_iView==WCPVIEW) m_pctrlMiddleControls->setCurrentIndex(2); else if(m_iView==WSTABVIEW) m_pctrlMiddleControls->setCurrentIndex(1); else m_pctrlMiddleControls->setCurrentIndex(0); if (m_iView==WSTABVIEW || (m_iView==W3DVIEW && m_pCurWPolar && m_pCurWPolar->m_WPolarType==STABILITYPOLAR)) pMainFrame->m_pctrlStabViewWidget->show(); else pMainFrame->m_pctrlStabViewWidget->hide(); // pMainFrame->StabTimeAct->setEnabled(m_pCurWPolar && m_pCurWPolar->m_WPolarType==STABILITYPOLAR); // pMainFrame->RootLocusAct->setEnabled(m_pCurWPolar && m_pCurWPolar->m_WPolarType==STABILITYPOLAR); if(m_pCurWPolar) { QString PolarProps; m_pCurWPolar->GetPolarProperties(PolarProps); m_pctrlPolarProps1->setText(PolarProps); } else { m_pctrlPolarProps1->clear(); } m_pctrlInitLLTCalc->setEnabled(m_pCurWPolar && m_pCurWPolar->m_AnalysisMethod==LLTMETHOD); pMainFrame->WOppAct->setChecked(m_iView==WOPPVIEW); pMainFrame->WPolarAct->setChecked(m_iView==WPOLARVIEW); pMainFrame->W3DAct->setChecked(m_iView==W3DVIEW); pMainFrame->CpViewAct->setChecked(m_iView==WCPVIEW); pMainFrame->WOppAct->setChecked(m_iView==WOPPVIEW); pMainFrame->WPolarAct->setChecked(m_iView==WPOLARVIEW); pMainFrame->W3DAct->setChecked(m_iView==W3DVIEW || (m_iView==WSTABVIEW && m_iStabilityView==STAB3DVIEW)); pMainFrame->CpViewAct->setChecked(m_iView==WCPVIEW); pMainFrame->StabTimeAct->setChecked(m_iView==WSTABVIEW && m_iStabilityView==STABTIMEVIEW); pMainFrame->RootLocusAct->setChecked(m_iView==WSTABVIEW && m_iStabilityView==STABPOLARVIEW); pMainFrame->halfWingAct->setChecked(m_bHalfWing); pMainFrame->showEllipticCurve->setChecked(m_bShowElliptic); pMainFrame->showXCmRefLocation->setChecked(m_bXCmRef); pMainFrame->showWing2Curve->setChecked(m_bShowWingCurve[1]); pMainFrame->showStabCurve->setChecked(m_bShowWingCurve[2]); pMainFrame->showFinCurve->setChecked(m_bShowWingCurve[3]); pMainFrame->showCurWOppOnly->setChecked(m_bCurWOppOnly); if(m_iView==WOPPVIEW) { pMainFrame->Graph1->setChecked(m_iWingView==1 && (m_pCurWingGraph == m_WingGraph)); pMainFrame->Graph2->setChecked(m_iWingView==1 && (m_pCurWingGraph == m_WingGraph+1)); pMainFrame->Graph3->setChecked(m_iWingView==1 && (m_pCurWingGraph == m_WingGraph+2)); pMainFrame->Graph4->setChecked(m_iWingView==1 && (m_pCurWingGraph == m_WingGraph+3)); pMainFrame->twoGraphs->setChecked(m_iWingView==2); pMainFrame->fourGraphs->setChecked(m_iWingView==4); } else if(m_iView==WSTABVIEW) { pMainFrame->Graph1->setChecked(m_iStabTimeView==1 && (m_pCurTimeGraph== m_TimeGraph)); pMainFrame->Graph2->setChecked(m_iStabTimeView==1 && (m_pCurTimeGraph == (m_TimeGraph+1))); pMainFrame->Graph3->setChecked(m_iStabTimeView==1 && (m_pCurTimeGraph == (m_TimeGraph+2))); pMainFrame->Graph4->setChecked(m_iStabTimeView==1 && (m_pCurTimeGraph == (m_TimeGraph+3))); pMainFrame->twoGraphs->setChecked(m_iStabTimeView==2); pMainFrame->fourGraphs->setChecked(m_iStabTimeView==4); } else if(m_iView==WPOLARVIEW) { pMainFrame->Graph1->setChecked(m_iWPlrView==ONEPOLARGRAPH && (m_pCurWPlrGraph == m_WPlrGraph)); pMainFrame->Graph2->setChecked(m_iWPlrView==ONEPOLARGRAPH && (m_pCurWPlrGraph == m_WPlrGraph+1)); pMainFrame->Graph3->setChecked(m_iWPlrView==ONEPOLARGRAPH && (m_pCurWPlrGraph == m_WPlrGraph+2)); pMainFrame->Graph4->setChecked(m_iWPlrView==ONEPOLARGRAPH && (m_pCurWPlrGraph == m_WPlrGraph+3)); pMainFrame->twoGraphs->setChecked(m_iWPlrView==TWOPOLARGRAPHS); pMainFrame->fourGraphs->setChecked(m_iWPlrView==ALLPOLARGRAPHS); } pMainFrame->WPlrGraphMenu->setEnabled(m_iView==WPOLARVIEW || m_iView==WSTABVIEW); pMainFrame->hideAllWPlrs->setEnabled(m_iView==WPOLARVIEW || m_iView==WSTABVIEW); pMainFrame->showAllWPlrs->setEnabled(m_iView==WPOLARVIEW || m_iView==WSTABVIEW); m_pctrlAnalyze->setEnabled(m_pCurWPolar); m_pctrlAlphaMin->setEnabled(m_pCurWPolar); m_pctrlAlphaMax->setEnabled(m_pCurWPolar && m_bSequence); m_pctrlAlphaDelta->setEnabled(m_pCurWPolar && m_bSequence); m_pctrlSequence->setEnabled(m_pCurWPolar); m_pctrlStoreWOpp->setEnabled(m_pCurWPolar); pMainFrame->showCurWOppOnly->setEnabled(m_iView==WOPPVIEW); pMainFrame->showAllWOpps->setEnabled(m_iView==WOPPVIEW); pMainFrame->hideAllWOpps->setEnabled(m_iView==WOPPVIEW); pMainFrame->showEllipticCurve->setEnabled(m_iView==WOPPVIEW); pMainFrame->showXCmRefLocation->setEnabled(m_iView==WOPPVIEW); pMainFrame->showWing2Curve->setEnabled(m_pWingList[1] && (m_iView==WOPPVIEW || m_iView==WCPVIEW)); pMainFrame->showStabCurve->setEnabled( m_pWingList[2] && (m_iView==WOPPVIEW || m_iView==WCPVIEW)); pMainFrame->showFinCurve->setEnabled( m_pWingList[3] && (m_iView==WOPPVIEW || m_iView==WCPVIEW)); pMainFrame->showAllWPlrOpps->setEnabled(m_iView==WOPPVIEW); pMainFrame->hideAllWPlrOpps->setEnabled(m_iView==WOPPVIEW); pMainFrame->WOppGraphMenu->setEnabled( m_iView==WOPPVIEW || m_iView==WSTABVIEW); pMainFrame->WOppCurGraphMenu->setEnabled(m_iView==WOPPVIEW || m_iView==WCPVIEW || m_iView==WSTABVIEW); m_pctrlLift->setEnabled((m_iView==WOPPVIEW||m_iView==W3DVIEW) && m_pCurWOpp); m_pctrlTrans->setEnabled((m_iView==WOPPVIEW||m_iView==W3DVIEW) && m_pCurWOpp); m_pctrlWOppAnimate->setEnabled((m_iView==WOPPVIEW||m_iView==W3DVIEW) && m_pCurWOpp && m_pCurWPolar->m_WPolarType!=STABILITYPOLAR); m_pctrlAnimateWOppSpeed->setEnabled((m_iView==WOPPVIEW||m_iView==W3DVIEW) && m_pCurWOpp); m_pctrlIDrag->setEnabled(m_iView==W3DVIEW && m_pCurWOpp); m_pctrlVDrag->setEnabled(m_iView==W3DVIEW && m_pCurWOpp); m_pctrlDownwash->setEnabled(m_iView==W3DVIEW && m_pCurWOpp); m_pctrlVortices->setEnabled(m_iView==W3DVIEW && m_pCurWOpp); m_pctrlMoment->setEnabled(m_iView==W3DVIEW && m_pCurWOpp); m_pctrlPanelForce->setEnabled(m_iView==W3DVIEW && m_pCurWOpp && m_pCurWOpp->m_AnalysisMethod!=LLTMETHOD); m_pctrlCp->setEnabled(m_iView==W3DVIEW && m_pCurWOpp && m_pCurWOpp->m_AnalysisMethod!=LLTMETHOD); m_pctrlStream->setEnabled(m_iView==W3DVIEW && m_pCurWOpp && m_pCurWOpp->m_AnalysisMethod!=LLTMETHOD); m_pctrlSurfVel->setEnabled(m_iView==W3DVIEW && m_pCurWOpp && m_pCurWOpp->m_AnalysisMethod!=LLTMETHOD); m_pctrlFoilNames->setChecked(s_bFoilNames); m_pctrlMasses->setChecked(s_bShowMasses); pMainFrame->highlightWOppAct->setChecked(m_bHighlightOpp); pMainFrame->defineWPolar->setEnabled(m_pCurWing); pMainFrame->defineStabPolar->setEnabled(m_pCurWing); pMainFrame->currentUFOMenu->setEnabled(m_pCurWing); pMainFrame->curWPlrMenu->setEnabled(m_pCurWPolar); pMainFrame->curWOppMenu->setEnabled(m_pCurWOpp); // pMainFrame->CurBodyMenu->setVisible(m_pCurPlane!=NULL); pMainFrame->editCurBodyAct->setEnabled(m_pCurPlane && m_pCurPlane->body()); StabViewDlg *pStabView = (StabViewDlg*)pMainFrame->m_pStabView; if(m_iView==WSTABVIEW) pStabView->SetControls(); m_pctrlSpanPos->SetValue(m_CurSpanPos); m_pctrlCpSectionSlider->setValue((int)(m_CurSpanPos*100.0)); pMainFrame->W3DScalesAct->setChecked(pMainFrame->m_pctrl3DScalesWidget->isVisible()); m_pctrlOutline->setChecked(s_bOutline); m_pctrlPanels->setChecked(s_bVLMPanels); m_pctrlAxes->setChecked(s_bAxes); m_pctrlCp->setChecked(m_b3DCp); m_pctrlPanelForce->setChecked(m_bPanelForce); m_pctrlDownwash->setChecked(m_bDownwash); m_pctrlMoment->setChecked(m_bMoments); m_pctrlTrans->setChecked(m_bXTop); m_pctrlLift->setChecked(m_bXCP); m_pctrlIDrag->setChecked(m_bICd); m_pctrlVDrag->setChecked(m_bVCd); m_pctrlAxes->setChecked(s_bAxes); m_pctrlLight->setChecked(GLLightDlg::IsLightOn()); m_pctrlSurfaces->setChecked(s_bSurfaces); m_pctrlOutline->setChecked(s_bOutline); m_pctrlStream->setChecked(m_bStream); m_pctrlClipPlanePos->setValue((int)(m_ClipPlanePos*100.0)); SetCurveParams(); blockSignals(false); } /** * Sets the checkboxes of the x, y and z view to their default false value */ void QMiarex::SetViewControls() { m_pctrlX->setChecked(false); m_pctrlY->setChecked(false); m_pctrlZ->setChecked(false); m_pctrlIso->setChecked(false); } /** * Creates the curves of the Cp graph at the selected span positions */ void QMiarex::CreateCpCurves() { int p,pp,i; bool bFound; double SpanPos, SpanInc; CVector N; Curve *pCurve = NULL; QString str1, str2, str3; for (i=0; i<4; i++) { // the first four curves are necessarily the current opPoint's main wing, second wing, elevator and fin // the next are those the user has chosen to keep for display --> don't reset them pCurve = m_CpGraph.GetCurve(i); if(pCurve) pCurve->clear(); } if(!m_pCurWOpp || !m_bShowCp) { return; } int coef = 2; if(m_pCurWPolar->m_bThinSurfaces) coef = 1; m_CurSpanPos = qMax(-1.0, m_CurSpanPos); m_CurSpanPos = qMin( 1.0, m_CurSpanPos); SpanPos = m_CurSpanPos*m_pCurWOpp->m_Span/2.000001; str1 = m_pCurWing->WingName(); str2 = QString(" a=%1").arg(m_pCurWOpp->m_Alpha, 5, 'f', 2); str3 = QString(" y/b=%1").arg(m_CurSpanPos, 5, 'f', 2); // if(m_bCurWOppOnly) { p=0; bFound = false; if(m_pCurWPolar->m_bThinSurfaces) p+=m_pCurWing->m_Surface[0].m_NXPanels; SpanInc = -m_pCurWing->m_PlanformSpan/2.0; for (p=0; pm_MatSize; p++) { if(m_pCurWing->m_pWingPanel[p].m_bIsTrailing && m_pCurWing->m_pWingPanel[p].m_Pos<=MIDSURFACE) { SpanInc += m_pCurWing->m_pWingPanel[p].Width(); if(SpanPos<=SpanInc || qAbs(SpanPos-SpanInc)/m_pCurWing->m_PlanformSpan<0.001) { bFound = true; break; } } } for (int iw=0; iwm_bThinSurfaces) p+=m_pWingList[iw]->m_Surface[0].m_NXPanels; SpanInc = -m_pWingList[iw]->m_PlanformSpan/2.0; for (p=0; pm_MatSize; p++) { if(m_pWingList[iw]->m_pWingPanel[p].m_bIsTrailing && m_pWingList[iw]->m_pWingPanel[p].m_Pos<=MIDSURFACE) { SpanInc += m_pWingList[iw]->m_pWingPanel[p].Width(); if(SpanPos<=SpanInc || qAbs(SpanPos-SpanInc)/m_pWingList[iw]->m_PlanformSpan<0.001) { bFound = true; break; } } } if(bFound) { pCurve = m_CpGraph.GetCurve(iw); pCurve->SetColor(m_CpColor); pCurve->SetStyle(m_CpStyle); pCurve->SetWidth(m_CpWidth); pCurve->ShowPoints(m_bShowCpPoints); pCurve->SetTitle(m_pWingList[iw]->m_WingName+str2+str3); for (pp=p; ppm_Surface[0].m_NXPanels; pp++) { pCurve->AppendPoint(m_Panel[pp].CollPt.x, m_pWOpp[iw]->m_Cp[pp]); } } } } } } /** * Creates the body panels for the active CBody object * The panels are created in the following order * - for the port side first, then for the starboard side * - from bottom to top * - from tip to tail * The panels are appended to the existing array of panels * @return the number of panels which have been created and appended */ int QMiarex::CreateBodyElements() { if(!m_pCurPlane) return 0; if(!m_pCurPlane->body()) return 0; Body *pCurBody = m_pCurPlane->body(); int i,j,k,l; double uk, uk1, v, dj, dj1, dl1; double dpx, dpz; CVector LATB, TALB; CVector LA, LB, TA, TB; CVector PLA, PTA, PLB, PTB; int n0, n1, n2, n3, lnx, lnh; int nx = pCurBody->m_nxPanels; int nh = pCurBody->m_nhPanels; int p = 0; int InitialSize = m_MatSize; int FullSize =0; lnx = 0; if(m_pCurPlane && m_pCurPlane->body()) { dpx = m_pCurPlane->BodyPos().x; dpz = m_pCurPlane->BodyPos().z; } else dpx=dpz=0.0; if(pCurBody->m_LineType==BODYPANELTYPE) { nx = 0; for(i=0; iFrameSize()-1; i++) nx+=pCurBody->m_xPanels[i]; nh = 0; for(i=0; iSideLineCount()-1; i++) nh+=pCurBody->m_hPanels[i]; FullSize = nx*nh*2; pCurBody->m_nxPanels = nx; pCurBody->m_nhPanels = nh; for (i=0; iFrameSize()-1; i++) { for (j=0; jm_xPanels[i]; j++) { dj = (double) j /(double)(pCurBody->m_xPanels[i]); dj1 = (double)(j+1)/(double)(pCurBody->m_xPanels[i]); //body left side lnh = 0; for (k=0; kSideLineCount()-1; k++) { //build the four corner points of the strips PLB.x = (1.0- dj) * pCurBody->FramePosition(i) + dj * pCurBody->FramePosition(i+1) +dpx; PLB.y = -(1.0- dj) * pCurBody->getFrame(i)->m_CtrlPoint[k].y - dj * pCurBody->getFrame(i+1)->m_CtrlPoint[k].y; PLB.z = (1.0- dj) * pCurBody->getFrame(i)->m_CtrlPoint[k].z + dj * pCurBody->getFrame(i+1)->m_CtrlPoint[k].z +dpz; PTB.x = (1.0-dj1) * pCurBody->FramePosition(i) + dj1 * pCurBody->FramePosition(i+1) +dpx; PTB.y = -(1.0-dj1) * pCurBody->getFrame(i)->m_CtrlPoint[k].y - dj1 * pCurBody->getFrame(i+1)->m_CtrlPoint[k].y; PTB.z = (1.0-dj1) * pCurBody->getFrame(i)->m_CtrlPoint[k].z + dj1 * pCurBody->getFrame(i+1)->m_CtrlPoint[k].z +dpz; PLA.x = (1.0- dj) * pCurBody->FramePosition(i) + dj * pCurBody->FramePosition(i+1) +dpx; PLA.y = -(1.0- dj) * pCurBody->getFrame(i)->m_CtrlPoint[k+1].y - dj * pCurBody->getFrame(i+1)->m_CtrlPoint[k+1].y; PLA.z = (1.0- dj) * pCurBody->getFrame(i)->m_CtrlPoint[k+1].z + dj * pCurBody->getFrame(i+1)->m_CtrlPoint[k+1].z +dpz; PTA.x = (1.0-dj1) * pCurBody->FramePosition(i) + dj1 * pCurBody->FramePosition(i+1) +dpx; PTA.y = -(1.0-dj1) * pCurBody->getFrame(i)->m_CtrlPoint[k+1].y - dj1 * pCurBody->getFrame(i+1)->m_CtrlPoint[k+1].y; PTA.z = (1.0-dj1) * pCurBody->getFrame(i)->m_CtrlPoint[k+1].z + dj1 * pCurBody->getFrame(i+1)->m_CtrlPoint[k+1].z +dpz; LB = PLB; TB = PTB; for (l=0; lm_hPanels[k]; l++) { dl1 = (double)(l+1) / (double)(pCurBody->m_hPanels[k]); LA = PLB * (1.0- dl1) + PLA * dl1; TA = PTB * (1.0- dl1) + PTA * dl1; n0 = IsNode(LA); n1 = IsNode(TA); n2 = IsNode(LB); n3 = IsNode(TB); if(n0>=0) { m_Panel[m_MatSize].m_iLA = n0; } else { m_Panel[m_MatSize].m_iLA = m_nNodes; m_Node[m_nNodes].Copy(LA); m_nNodes++; } if(n1>=0) { m_Panel[m_MatSize].m_iTA = n1; } else { m_Panel[m_MatSize].m_iTA = m_nNodes; m_Node[m_nNodes].Copy(TA); m_nNodes++; } if(n2>=0) { m_Panel[m_MatSize].m_iLB = n2; } else { m_Panel[m_MatSize].m_iLB = m_nNodes; m_Node[m_nNodes].Copy(LB); m_nNodes++; } if(n3 >=0) { m_Panel[m_MatSize].m_iTB = n3; } else { m_Panel[m_MatSize].m_iTB = m_nNodes; m_Node[m_nNodes].Copy(TB); m_nNodes++; } LATB = TB - LA; TALB = LB - TA; m_Panel[m_MatSize].Normal = LATB * TALB; m_Panel[m_MatSize].Area = m_Panel[m_MatSize].Normal.VAbs()/2.0; m_Panel[m_MatSize].Normal.Normalize(); m_Panel[m_MatSize].m_bIsInSymPlane = false; m_Panel[m_MatSize].m_bIsLeading = false; m_Panel[m_MatSize].m_bIsTrailing = false; m_Panel[m_MatSize].m_Pos = BODYSURFACE; m_Panel[m_MatSize].m_iElement = m_MatSize; m_Panel[m_MatSize].m_iSym = -1; m_Panel[m_MatSize].m_bIsLeftPanel = true; m_Panel[m_MatSize].SetFrame(LA, LB, TA, TB); // set neighbour panels m_Panel[m_MatSize].m_iPD = m_MatSize + nh; m_Panel[m_MatSize].m_iPU = m_MatSize - nh; if(lnx==0) m_Panel[m_MatSize].m_iPU = -1;// no panel downstream if(lnx==nx-1) m_Panel[m_MatSize].m_iPD = -1;// no panel upstream m_Panel[m_MatSize].m_iPL = m_MatSize + 1; m_Panel[m_MatSize].m_iPR = m_MatSize - 1; if(lnh==0) m_Panel[m_MatSize].m_iPR = InitialSize + FullSize - p - 1; if(lnh==nh-1) m_Panel[m_MatSize].m_iPL = InitialSize + FullSize - p - 1; m_MatSize++; p++; LB = LA; TB = TA; lnh++; } } lnx++; } } } else if(pCurBody->m_LineType==BODYSPLINETYPE) { FullSize = 2*nx*nh; //start with left side... same as for wings for (k=0; ks_XPanelPos[k]; uk1 = pCurBody->s_XPanelPos[k+1]; pCurBody->GetPoint(uk, 0, false, LB); pCurBody->GetPoint(uk1, 0, false, TB); LB.x += dpx; LB.z += dpz; TB.x += dpx; TB.z += dpz; for (l=0; lGetPoint(uk, v, false, LA); pCurBody->GetPoint(uk1, v, false, TA); LA.x += dpx; LA.z += dpz; TA.x += dpx; TA.z += dpz; n0 = IsNode(LA); n1 = IsNode(TA); n2 = IsNode(LB); n3 = IsNode(TB); if(n0>=0) { m_Panel[m_MatSize].m_iLA = n0; } else { m_Panel[m_MatSize].m_iLA = m_nNodes; m_Node[m_nNodes].Copy(LA); m_nNodes++; } if(n1>=0) { m_Panel[m_MatSize].m_iTA = n1; } else { m_Panel[m_MatSize].m_iTA = m_nNodes; m_Node[m_nNodes].Copy(TA); m_nNodes++; } if(n2>=0) { m_Panel[m_MatSize].m_iLB = n2; } else { m_Panel[m_MatSize].m_iLB = m_nNodes; m_Node[m_nNodes].Copy(LB); m_nNodes++; } if(n3 >=0) { m_Panel[m_MatSize].m_iTB = n3; } else { m_Panel[m_MatSize].m_iTB = m_nNodes; m_Node[m_nNodes].Copy(TB); m_nNodes++; } LATB = TB - LA; TALB = LB - TA; m_Panel[m_MatSize].Normal = LATB * TALB; m_Panel[m_MatSize].Area = m_Panel[m_MatSize].Normal.VAbs()/2.0; m_Panel[m_MatSize].Normal.Normalize(); m_Panel[m_MatSize].m_bIsInSymPlane = false; m_Panel[m_MatSize].m_bIsLeading = false; m_Panel[m_MatSize].m_bIsTrailing = false; m_Panel[m_MatSize].m_Pos = BODYSURFACE; m_Panel[m_MatSize].m_iElement = m_MatSize; m_Panel[m_MatSize].m_iSym = -1; m_Panel[m_MatSize].m_bIsLeftPanel = true; m_Panel[m_MatSize].SetFrame(LA, LB, TA, TB); // set neighbour panels m_Panel[m_MatSize].m_iPD = m_MatSize + nh; m_Panel[m_MatSize].m_iPU = m_MatSize - nh; if(k==0) m_Panel[m_MatSize].m_iPU = -1;// no panel downstream if(k==nx-1) m_Panel[m_MatSize].m_iPD = -1;// no panel upstream m_Panel[m_MatSize].m_iPL = m_MatSize + 1; m_Panel[m_MatSize].m_iPR = m_MatSize - 1; if(l==0) m_Panel[m_MatSize].m_iPR = InitialSize + FullSize - p - 1; if(l==nh-1) m_Panel[m_MatSize].m_iPL = InitialSize + FullSize - p - 1; m_MatSize++; p++; LB = LA; TB = TA; } } } //right side next i = m_MatSize; //right side next for (k=nx-1; k>=0; k--) { for (l=nh-1; l>=0; l--) { i--; LA = m_Node[m_Panel[i].m_iLB]; TA = m_Node[m_Panel[i].m_iTB]; LB = m_Node[m_Panel[i].m_iLA]; TB = m_Node[m_Panel[i].m_iTA]; LA.y = -LA.y; LB.y = -LB.y; TA.y = -TA.y; TB.y = -TB.y; n0 = IsNode(LA); n1 = IsNode(TA); n2 = IsNode(LB); n3 = IsNode(TB); if(n0>=0) { m_Panel[m_MatSize].m_iLA = n0; } else { m_Panel[m_MatSize].m_iLA = m_nNodes; m_Node[m_nNodes].Copy(LA); m_nNodes++; } if(n1>=0) { m_Panel[m_MatSize].m_iTA = n1; } else { m_Panel[m_MatSize].m_iTA = m_nNodes; m_Node[m_nNodes].Copy(TA); m_nNodes++; } if(n2>=0) { m_Panel[m_MatSize].m_iLB = n2; } else { m_Panel[m_MatSize].m_iLB = m_nNodes; m_Node[m_nNodes].Copy(LB); m_nNodes++; } if(n3 >=0) { m_Panel[m_MatSize].m_iTB = n3; } else { m_Panel[m_MatSize].m_iTB = m_nNodes; m_Node[m_nNodes].Copy(TB); m_nNodes++; } LATB = TB - LA; TALB = LB - TA; m_Panel[m_MatSize].Normal = LATB * TALB; m_Panel[m_MatSize].Area = m_Panel[m_MatSize].Normal.VAbs()/2.0; m_Panel[m_MatSize].Normal.Normalize(); m_Panel[m_MatSize].m_bIsInSymPlane = false; m_Panel[m_MatSize].m_bIsLeading = false; m_Panel[m_MatSize].m_bIsTrailing = false; m_Panel[m_MatSize].m_Pos = BODYSURFACE; m_Panel[m_MatSize].m_iElement = m_MatSize; m_Panel[m_MatSize].m_iSym = -1; m_Panel[i].m_iSym = m_MatSize; m_Panel[m_MatSize].m_bIsLeftPanel = false; m_Panel[m_MatSize].SetFrame(LA, LB, TA, TB); // set neighbour panels // valid only for Panel Analysis m_Panel[m_MatSize].m_iPD = m_MatSize - nh; m_Panel[m_MatSize].m_iPU = m_MatSize + nh; if(k==0) m_Panel[m_MatSize].m_iPU = -1;// no panel downstream if(k==nx-1) m_Panel[m_MatSize].m_iPD = -1;// no panel upstream m_Panel[m_MatSize].m_iPL = m_MatSize + 1; m_Panel[m_MatSize].m_iPR = m_MatSize - 1; if(l==0) m_Panel[m_MatSize].m_iPL = InitialSize + FullSize - p - 1; if(l==nh-1) m_Panel[m_MatSize].m_iPR = InitialSize + FullSize - p - 1; m_MatSize++; p++; LB = LA; TB = TA; } } pCurBody->m_NElements = m_MatSize-InitialSize; return pCurBody->m_NElements; } /** * Creates the panel elements for the active surface. * The panels are appended at the end of the existing array of panel * The panels are created from left to right on a surface * The panels are created depending on the current WPolar: * No WPolar --> panel elements on top & bottom surfaces, just for cosmetics * VLM --> panel elements on mid camber line from T.E. to L.E. * 3D Panels --> panel elements on left tip surface * panel elements on each strip, starting on the bottom T.E. to the L.E back to the opt T.E * panel elements on right tip surface * *@param a pointer to the surface for which the panels will be created *@return the number of panels which have been created and appended */ int QMiarex::CreateWingElements(Surface *pSurface) { //TODO : for a gap at the wing's center, need to separate m_iPL and m_iPR at the tips; bool bNoJoinFlap; int k,l; int n0, n1, n2, n3; int InitialSize = m_MatSize; enumPanelPosition side; CVector LA, LB, TA, TB; bool bThickSurfaces = true; if(m_pCurPlane) bThickSurfaces= false; if(m_pCurWPolar) { if(m_pCurWPolar->m_AnalysisMethod == LLTMETHOD) bThickSurfaces = false; if(m_pCurWPolar->m_AnalysisMethod == VLMMETHOD) bThickSurfaces = false; if(m_pCurWPolar->m_bThinSurfaces) bThickSurfaces = false; } if (bThickSurfaces && m_pCurWPolar && pSurface->m_bIsTipLeft) { //then left tip surface, add side panels for (l=0; l< pSurface->m_NXPanels; l++) { m_Panel[m_MatSize].m_bIsLeading = false; m_Panel[m_MatSize].m_bIsTrailing = false; m_Panel[m_MatSize].m_bIsWakePanel = false; m_Panel[m_MatSize].m_bIsInSymPlane = false; //even if part of a fin pSurface->GetPanel(0, l, BOTSURFACE); LA.Copy(pSurface->LA); TA.Copy(pSurface->TA); pSurface->GetPanel(0, l, TOPSURFACE); LB.Copy(pSurface->LA); TB.Copy(pSurface->TA); n0 = IsNode(LA); if(n0>=0) m_Panel[m_MatSize].m_iLA = n0; else { m_Panel[m_MatSize].m_iLA = m_nNodes; m_Node[m_nNodes].Copy(LA); m_nNodes++; } n1 = IsNode(TA); if(n1>=0) m_Panel[m_MatSize].m_iTA = n1; else { m_Panel[m_MatSize].m_iTA = m_nNodes; m_Node[m_nNodes].Copy(TA); m_nNodes++; } n2 = IsNode(LB); if(n2>=0) m_Panel[m_MatSize].m_iLB = n2; else { m_Panel[m_MatSize].m_iLB = m_nNodes; m_Node[m_nNodes].Copy(LB); m_nNodes++; } n3 = IsNode(TB); if(n3>=0) m_Panel[m_MatSize].m_iTB = n3; else { m_Panel[m_MatSize].m_iTB = m_nNodes; m_Node[m_nNodes].Copy(TB); m_nNodes++; } m_Panel[m_MatSize].m_Pos = SIDESURFACE; m_Panel[m_MatSize].m_iElement = m_MatSize; m_Panel[m_MatSize].m_iSym = -1; m_Panel[m_MatSize].m_bIsLeftPanel = pSurface->m_bIsLeftSurf; m_Panel[m_MatSize].SetFrame(LA, LB, TA, TB); m_Panel[m_MatSize].m_iWake = -1; m_Panel[m_MatSize].m_iPD = m_MatSize-1; m_Panel[m_MatSize].m_iPU = m_MatSize+1; if(l==0) m_Panel[m_MatSize].m_iPD = -1;// no panel downstream if(l==pSurface->m_NXPanels-1) m_Panel[m_MatSize].m_iPU = -1;// no panel upstream m_Panel[m_MatSize].m_iPL = -1; m_Panel[m_MatSize].m_iPR = -1; m_MatSize++; } } for (k=0; km_NYPanels; k++) { //add "horizontal" panels, mid side, or following a strip from bot to top if 3D Panel if(bThickSurfaces) side = BOTSURFACE; //start with lower surf, as recommended by K&P else side = MIDSURFACE; //from T.E. to L.E. for (l=0; lm_NXPanels; l++) { pSurface->GetPanel(k,l,side); n0 = IsNode(pSurface->LA); n1 = IsNode(pSurface->TA); n2 = IsNode(pSurface->LB); n3 = IsNode(pSurface->TB); if(l==0) m_Panel[m_MatSize].m_bIsTrailing = true; if(l==pSurface->m_NXPanels-1) m_Panel[m_MatSize].m_bIsLeading = true; m_Panel[m_MatSize].m_bIsWakePanel = false; m_Panel[m_MatSize].m_bIsInSymPlane = pSurface->m_bIsInSymPlane; bNoJoinFlap = side==0 && lm_NXFlap && k==0; if(n0>=0 && !bNoJoinFlap) // do not merge nodes if we are at a flap's side in VLM { m_Panel[m_MatSize].m_iLA = n0; } else { m_Panel[m_MatSize].m_iLA = m_nNodes; m_Node[m_nNodes].Copy(pSurface->LA); m_nNodes++; } if(n1>=0 && !bNoJoinFlap) // do not merge nodes if we are at a flap's side in VLM { m_Panel[m_MatSize].m_iTA = n1; } else { m_Panel[m_MatSize].m_iTA = m_nNodes; m_Node[m_nNodes].Copy(pSurface->TA); m_nNodes++; } bNoJoinFlap = side==0 && lm_NXFlap && k==pSurface->m_NYPanels-1; if(n2>=0 && !bNoJoinFlap) // do not merge nodes if we are at a flap's side in VLM { m_Panel[m_MatSize].m_iLB = n2; } else { m_Panel[m_MatSize].m_iLB = m_nNodes; m_Node[m_nNodes].Copy(pSurface->LB); m_nNodes++; } if(n3>=0 && !bNoJoinFlap) // do not merge nodes if we are at a flap's side in VLM { m_Panel[m_MatSize].m_iTB = n3; } else { m_Panel[m_MatSize].m_iTB = m_nNodes; m_Node[m_nNodes].Copy(pSurface->TB); m_nNodes++; } m_Panel[m_MatSize].m_Pos = side; m_Panel[m_MatSize].m_iElement = m_MatSize; m_Panel[m_MatSize].m_iSym = -1; m_Panel[m_MatSize].m_bIsLeftPanel = pSurface->m_bIsLeftSurf; if(side==MIDSURFACE) m_Panel[m_MatSize].SetFrame(pSurface->LA, pSurface->LB, pSurface->TA, pSurface->TB); else if (side==BOTSURFACE) m_Panel[m_MatSize].SetFrame(pSurface->LB, pSurface->LA, pSurface->TB, pSurface->TA); // set neighbour panels // valid only for Panel 2-sided Analysis // we are on the bottom or middle surface m_Panel[m_MatSize].m_iPD = m_MatSize-1; m_Panel[m_MatSize].m_iPU = m_MatSize+1; if(l==0) m_Panel[m_MatSize].m_iPD = -1;// no panel downstream if(l==pSurface->m_NXPanels-1 && side==MIDSURFACE) m_Panel[m_MatSize].m_iPU = -1;// no panel upstream if(side!=MIDSURFACE) { //wings are modelled as thick surfaces m_Panel[m_MatSize].m_iPL = m_MatSize + 2*pSurface->m_NXPanels; m_Panel[m_MatSize].m_iPR = m_MatSize - 2*pSurface->m_NXPanels; //todo : do not link to right wing if there is a gap in between if(k==0 && pSurface->m_bIsTipLeft) m_Panel[m_MatSize].m_iPR = -1; if(k==pSurface->m_NYPanels-1 && pSurface->m_bIsTipRight) m_Panel[m_MatSize].m_iPL = -1; } else { //wings are modelled as thin surfaces m_Panel[m_MatSize].m_iPR = m_MatSize + pSurface->m_NXPanels; m_Panel[m_MatSize].m_iPL = m_MatSize - pSurface->m_NXPanels; if(k==0 && pSurface->m_bIsTipLeft) m_Panel[m_MatSize].m_iPL = -1; if(k==pSurface->m_NYPanels-1 && pSurface->m_bIsTipRight) m_Panel[m_MatSize].m_iPR = -1; } //do not link to next surfaces... will be done in JoinSurfaces() if surfaces are continuous if(k==0) m_Panel[m_MatSize].m_iPR = -1; if(k==pSurface->m_NYPanels-1) m_Panel[m_MatSize].m_iPL = -1; if(m_pCurWPolar && m_Panel[m_MatSize].m_bIsTrailing && m_pCurWPolar->m_AnalysisMethod==PANELMETHOD) { m_Panel[m_MatSize].m_iWake = m_WakeSize;//next wake element m_Panel[m_MatSize].m_iWakeColumn = m_NWakeColumn; if(m_pCurWPolar->m_bThinSurfaces) { CreateWakeElems(m_MatSize); m_NWakeColumn++; } } if(lm_NXFlap) pSurface->AddFlapPanel(m_Panel+m_MatSize); m_MatSize++; } if (bThickSurfaces) { //add top side if 3D Panels side = TOPSURFACE; //next upper surf, as recommended by K&P //from L.E. to T.E. for (l=pSurface->m_NXPanels-1;l>=0; l--) { pSurface->GetPanel(k,l,side); n0 = IsNode(pSurface->LA); n1 = IsNode(pSurface->TA); n2 = IsNode(pSurface->LB); n3 = IsNode(pSurface->TB); if(l==0) m_Panel[m_MatSize].m_bIsTrailing = true; if(l==pSurface->m_NXPanels-1) m_Panel[m_MatSize].m_bIsLeading = true; m_Panel[m_MatSize].m_bIsWakePanel = false; m_Panel[m_MatSize].m_bIsInSymPlane = pSurface->m_bIsInSymPlane; if(n0>=0) m_Panel[m_MatSize].m_iLA = n0; else { m_Panel[m_MatSize].m_iLA = m_nNodes; m_Node[m_nNodes].Copy(pSurface->LA); m_nNodes++; } if(n1>=0) m_Panel[m_MatSize].m_iTA = n1; else { m_Panel[m_MatSize].m_iTA = m_nNodes; m_Node[m_nNodes].Copy(pSurface->TA); m_nNodes++; } if(n2>=0) m_Panel[m_MatSize].m_iLB = n2; else { m_Panel[m_MatSize].m_iLB = m_nNodes; m_Node[m_nNodes].Copy(pSurface->LB); m_nNodes++; } if(n3 >=0) m_Panel[m_MatSize].m_iTB = n3; else { m_Panel[m_MatSize].m_iTB = m_nNodes; m_Node[m_nNodes].Copy(pSurface->TB); m_nNodes++; } m_Panel[m_MatSize].m_Pos = side; m_Panel[m_MatSize].m_iElement = m_MatSize; m_Panel[m_MatSize].m_iSym = -1; m_Panel[m_MatSize].m_bIsLeftPanel = pSurface->m_bIsLeftSurf; m_Panel[m_MatSize].SetFrame(pSurface->LA, pSurface->LB, pSurface->TA, pSurface->TB); // set neighbour panels // valid only for Panel 2-sided Analysis // we are on the top surface m_Panel[m_MatSize].m_iPD = m_MatSize+1; m_Panel[m_MatSize].m_iPU = m_MatSize-1; if(l==0) m_Panel[m_MatSize].m_iPD = -1;// no panel downstream // if(l==pSurface->m_NXPanels-1) m_Panel[m_MatSize].m_iPU = -1;// no panel upstream m_Panel[m_MatSize].m_iPL = m_MatSize - 2*pSurface->m_NXPanels;//assuming all wing panels have same chordwise distribution m_Panel[m_MatSize].m_iPR = m_MatSize + 2*pSurface->m_NXPanels;//assuming all wing panels have same chordwise distribution if(k==0 && pSurface->m_bIsTipLeft) m_Panel[m_MatSize].m_iPL = -1; if(k==pSurface->m_NYPanels-1 && pSurface->m_bIsTipRight) m_Panel[m_MatSize].m_iPR = -1; //do not link to next surfaces... will be done in JoinSurfaces() if surfaces are continuous if(k==0) m_Panel[m_MatSize].m_iPL = -1; if(k==pSurface->m_NYPanels-1) m_Panel[m_MatSize].m_iPR = -1; if(m_pCurWPolar && m_Panel[m_MatSize].m_bIsTrailing && m_pCurWPolar->m_AnalysisMethod==PANELMETHOD) { m_Panel[m_MatSize].m_iWake = m_WakeSize;//next wake element m_Panel[m_MatSize].m_iWakeColumn = m_NWakeColumn; CreateWakeElems(m_MatSize); } if(lm_NXFlap) pSurface->AddFlapPanel(m_Panel+m_MatSize); m_MatSize++; } m_NWakeColumn++; } } if (bThickSurfaces && m_pCurWPolar && pSurface->m_bIsTipRight) { //right tip surface k = pSurface->m_NYPanels-1; for (l=0; l< pSurface->m_NXPanels; l++) { m_Panel[m_MatSize].m_bIsTrailing = false; m_Panel[m_MatSize].m_bIsLeading = false; m_Panel[m_MatSize].m_bIsWakePanel = false; m_Panel[m_MatSize].m_bIsInSymPlane = false;//even if part of a fin pSurface->GetPanel(k,l,TOPSURFACE); LA.Copy(pSurface->LB); TA.Copy(pSurface->TB); pSurface->GetPanel(k,l,BOTSURFACE); LB.Copy(pSurface->LB); TB.Copy(pSurface->TB); n0 = IsNode(LA);//answer should be yes if(n0>=0) m_Panel[m_MatSize].m_iLA = n0; else { m_Panel[m_MatSize].m_iLA = m_nNodes; m_Node[m_nNodes].Copy(LA); m_nNodes++; } n1 = IsNode(TA);//answer should be yes if(n1>=0) m_Panel[m_MatSize].m_iTA = n1; else { m_Panel[m_MatSize].m_iTA = m_nNodes; m_Node[m_nNodes].Copy(TA); m_nNodes++; } n2 = IsNode(LB);//answer should be yes if(n2>=0) m_Panel[m_MatSize].m_iLB = n2; else { m_Panel[m_MatSize].m_iLB = m_nNodes; m_Node[m_nNodes].Copy(LB); m_nNodes++; } n3 = IsNode(TB);//answer should be yes if(n3>=0) m_Panel[m_MatSize].m_iTB = n3; else { m_Panel[m_MatSize].m_iTB = m_nNodes; m_Node[m_nNodes].Copy(TB); m_nNodes++; } m_Panel[m_MatSize].m_iPD = m_MatSize-1; m_Panel[m_MatSize].m_iPU = m_MatSize+1; if(l==0) m_Panel[m_MatSize].m_iPD = -1;// no panel downstream if(l==pSurface->m_NXPanels-1) m_Panel[m_MatSize].m_iPU = -1;// no panel upstream m_Panel[m_MatSize].m_iPL = -1; m_Panel[m_MatSize].m_iPR = -1; m_Panel[m_MatSize].m_Pos = SIDESURFACE; m_Panel[m_MatSize].m_iElement = m_MatSize; m_Panel[m_MatSize].m_iSym = -1; m_Panel[m_MatSize].m_bIsLeftPanel = pSurface->m_bIsLeftSurf; m_Panel[m_MatSize].SetFrame(LA, LB, TA, TB); m_Panel[m_MatSize].m_iWake = -1; m_MatSize++; } } pSurface->m_NElements = m_MatSize-InitialSize; return pSurface->m_NElements; } /** * Creates a column of wake elements shed from a panel at the trailing edge of the wing's surface * @param PanelIndex the index of the panel on the trailing edge of the surface which will shed the column of wake panels */ bool QMiarex::CreateWakeElems(int PanelIndex) { if(!m_pCurWPolar) return false; if(!m_Panel[PanelIndex].m_bIsTrailing) return false; //creates elements trailing panel p int l, n0, n1,n2, n3; double dxA, dxB; int mw = m_WakeSize;// number of wake panels CVector LATB, TALB; CVector LA, LB, TA,TB;//wake panel's corner points int NXWakePanels; double WakePanelFactor; double TotalWakeLength; // double slope = m_pSurface[0]->m_pFoilA->GetCamberSlope(1.0); // CVector TE(1.0,0.0,slope); // TE.Normalize(); NXWakePanels = m_pCurWPolar->m_NXWakePanels; WakePanelFactor = m_pCurWPolar->m_WakePanelFactor; TotalWakeLength = m_pCurWPolar->m_TotalWakeLength; TA = m_Node[m_Panel[PanelIndex].m_iTA]; TB = m_Node[m_Panel[PanelIndex].m_iTB]; dxA = TotalWakeLength*m_pCurWing->m_MAChord - m_Node[m_Panel[PanelIndex].m_iTA].x; dxB = TotalWakeLength*m_pCurWing->m_MAChord - m_Node[m_Panel[PanelIndex].m_iTB].x; if(WakePanelFactor==1.0) { dxA /= NXWakePanels; dxB /= NXWakePanels; } else { dxA *= (1.0-WakePanelFactor)/(1.0-pow(WakePanelFactor, NXWakePanels)); dxB *= (1.0-WakePanelFactor)/(1.0-pow(WakePanelFactor, NXWakePanels)); } for (l=0; l=0) { m_WakePanel[mw].m_iLA = n0; } else { m_WakePanel[mw].m_iLA = m_nWakeNodes; m_WakeNode[m_nWakeNodes].Copy(LA); m_nWakeNodes++; } if(n1>=0) { m_WakePanel[mw].m_iTA = n1; } else { m_WakePanel[mw].m_iTA = m_nWakeNodes; m_WakeNode[m_nWakeNodes].Copy(TA); m_nWakeNodes++; } if(n2>=0) { m_WakePanel[mw].m_iLB = n2; } else { m_WakePanel[mw].m_iLB = m_nWakeNodes; m_WakeNode[m_nWakeNodes].Copy(LB); m_nWakeNodes++; } if(n3 >=0) { m_WakePanel[mw].m_iTB = n3; } else { m_WakePanel[mw].m_iTB = m_nWakeNodes; m_WakeNode[m_nWakeNodes].Copy(TB); m_nWakeNodes++; } LATB = TB - LA; TALB = LB - TA; m_WakePanel[mw].Normal = LATB * TALB; m_WakePanel[mw].m_Pos = MIDSURFACE; m_WakePanel[mw].m_bIsWakePanel = true; m_WakePanel[mw].Area = m_WakePanel[mw].Normal.VAbs()/2.0; m_WakePanel[mw].Normal.Normalize(); m_WakePanel[mw].SetFrame(LA,LB, TA, TB); m_WakePanel[mw].m_iSym = -1; m_WakePanel[mw].m_bIsLeftPanel = false; if(l==0) m_WakePanel[mw].m_iPD = -1;// no panel downstream else if(l==NXWakePanels) m_WakePanel[mw].m_iPU = -1;// no panel upstream else m_WakePanel[mw].m_iPD = mw+1; m_WakePanel[mw].m_iPL = -1; m_WakePanel[mw].m_iPR = -1; mw++; } m_WakeSize = mw; return true; } /** * Creates the operating point associated to a plane's wing pointed by pWing * Uses the wing's geometric data and the current instance of the LLT, VLM or Panel analysis dialog box * Returns the pointer pWOpp to the operating point which has been created *@param pWOpp a pointer to the CWOpp object which is to be filled with the results of the analysis which has been completed *@param to the wing object for which the CWOpp will be created */ void QMiarex::CreateWOpp(WingOpp *pWOpp, Wing *pWing) { pWOpp->m_WingName = pWing->m_WingName; pWOpp->m_NStation = pWing->m_NStation; pWOpp->m_PlrName = m_pCurWPolar->m_PlrName; pWOpp->m_WPolarType = m_pCurWPolar->m_WPolarType; pWOpp->m_bVLM1 = m_pCurWPolar->m_bVLM1; pWOpp->m_bThinSurface = m_pCurWPolar->m_bThinSurfaces; pWOpp->m_bTiltedGeom = m_pCurWPolar->m_bTiltedGeom; pWOpp->m_AnalysisMethod = m_pCurWPolar->m_AnalysisMethod; pWOpp->m_Beta = m_pCurWPolar->m_Beta; pWOpp->m_Phi = m_pCurWPolar->m_BankAngle; pWOpp->m_Weight = m_pCurWPolar->m_Mass; pWOpp->m_Span = m_pCurWPolar->m_WSpan; if(m_pCurWPolar->m_AnalysisMethod==PANELMETHOD && m_pPanelDlg) { pWOpp->m_bOut = m_pPanelDlg->m_bPointOut; pWOpp->m_Alpha = m_pPanelDlg->m_Alpha; pWOpp->m_QInf = m_pPanelDlg->m_QInf; } pWOpp->m_MAChord = pWing->m_MAChord; pWOpp->m_CL = pWing->m_CL; pWOpp->m_ICD = pWing->m_CDi; pWOpp->m_VCD = pWing->m_CDv; pWOpp->m_GCm = pWing->m_GCm; pWOpp->m_VCm = pWing->m_VCm; pWOpp->m_ICm = pWing->m_ICm; pWOpp->m_GRm = pWing->m_GRm; pWOpp->m_GYm = pWing->m_GYm; pWOpp->m_VYm = pWing->m_VYm; pWOpp->m_IYm = pWing->m_IYm; /**< @todo check if m_CP !=0 */ pWOpp->m_CP = pWing->m_CP; double Cb =0.0; for(int l=0; lm_NStation; l++) { pWOpp->m_Ai[l] = (float)pWing->m_Ai[l]; pWOpp->m_Cl[l] = (float)pWing->m_Cl[l]; pWOpp->m_PCd[l] = (float)pWing->m_PCd[l]; pWOpp->m_ICd[l] = (float)pWing->m_ICd[l]; pWOpp->m_Cm[l] = (float)pWing->m_Cm[l]; pWOpp->m_CmAirf[l] = (float)pWing->m_CmAirf[l]; pWOpp->m_XCPSpanRel[l] = (float)pWing->m_XCPSpanRel[l]; pWOpp->m_XCPSpanAbs[l] = (float)pWing->m_XCPSpanAbs[l]; pWOpp->m_Re[l] = (float)pWing->m_Re[l]; pWOpp->m_Chord[l] = (float)pWing->m_Chord[l]; pWOpp->m_Twist[l] = (float)pWing->m_Twist[l]; pWOpp->m_XTrTop[l] = (float)pWing->m_XTrTop[l]; pWOpp->m_XTrBot[l] = (float)pWing->m_XTrBot[l]; pWOpp->m_BendingMoment[l] = (float)pWing->m_BendingMoment[l]; pWOpp->m_Vd[l] = pWing->m_Vd[l]; pWOpp->m_F[l] = pWing->m_F[l]; pWOpp->m_SpanPos[l] = pWing->m_SpanPos[l]; pWOpp->m_StripArea[l] = pWing->m_StripArea[l]; Cb = qMax(Cb, pWing->m_BendingMoment[l]); } pWOpp->m_MaxBending = (float)Cb; } /** * Creates the curves for the graphs in the operating point view */ void QMiarex::CreateWOppCurves() { WingOpp *pWOpp = NULL;; PlaneOpp *pPOpp = NULL; Curve *pWingCurve[MAXWINGS][MAXGRAPHS]; QString str; int i,k; for(int ig=0; igsize(); k++) { pWOpp = (WingOpp*)m_poaWOpp->at(k); if (pWOpp->m_bIsVisible && (!m_bCurWOppOnly || (m_pCurWOpp==pWOpp))) { str = QString("Q=%1 - Alpha=%2").arg(pWOpp->m_QInf,5,'f',2).arg(pWOpp->m_Alpha,5,'f',2); for(int ic=0; icShowPoints(pWOpp->m_bShowPoints); pWingCurve[0][ic]->SetStyle(pWOpp->m_Style); pWingCurve[0][ic]->SetColor(pWOpp->m_Color); pWingCurve[0][ic]->SetWidth(pWOpp->m_Width); pWingCurve[0][ic]->SetTitle(str); FillWOppCurve(pWOpp, m_WingGraph+ic, pWingCurve[0][ic]); } } } // Browse through the array of plane operating points // add a curve for those selected, and fill them with data for (k=0; ksize(); k++) { pPOpp = (PlaneOpp*)m_poaPOpp->at(k); if (pPOpp->m_bIsVisible && (!m_bCurWOppOnly || (m_pCurPOpp==pPOpp))) { for(int iw=0; iwm_pPlaneWOpp[iw]) { for(int ic=0; icShowPoints(pPOpp->m_bShowPoints); pWingCurve[iw][ic]->SetStyle(pPOpp->m_Style); pWingCurve[iw][ic]->SetColor(pPOpp->m_Color); pWingCurve[iw][ic]->SetWidth(pPOpp->m_Width); pWingCurve[iw][ic]->SetTitle(str); FillWOppCurve(pPOpp->m_pPlaneWOpp[iw], m_WingGraph+ic, pWingCurve[iw][ic]); } } } } } //if the optimal elliptic curve is requested, and if the graph variable is local lift, then add the curve if(m_bShowElliptic && m_pCurWOpp) { double maxlift, x, y; maxlift = m_pCurWOpp->GetMaxLift(); int nStart; if(m_pCurWOpp->m_AnalysisMethod==LLTMETHOD) nStart = 1; else nStart = 0; for(int ig=0; igSetStyle(1); pCurve->SetColor(QColor(150, 150, 150)); for (i=nStart; im_NStation; i++) { x = m_pCurWOpp->m_SpanPos[i]; y = maxlift*sqrt(1.0-x*x/m_pCurWOpp->m_Span/m_pCurWOpp->m_Span*4.0); pCurve->AppendPoint(x*MainFrame::s_mtoUnit,y); } } } } } /** * Resets and fills the polar graphs curves with the data from the CWPolar objects */ void QMiarex::CreateWPolarCurves() { WPolar *pWPolar; Curve *pCurve[4]; for(int ig=0; ig<4; ig++) m_WPlrGraph[ig].DeleteCurves(); for (int k=0; ksize(); k++) { pWPolar = (WPolar*)m_poaWPolar->at(k); if (pWPolar->m_bIsVisible && pWPolar->m_Alpha.size()>0 && ((m_bType1 && pWPolar->m_WPolarType==FIXEDSPEEDPOLAR) || (m_bType2 && pWPolar->m_WPolarType==FIXEDLIFTPOLAR) || (m_bType4 && pWPolar->m_WPolarType==FIXEDAOAPOLAR) || (m_bType7 && pWPolar->m_WPolarType==STABILITYPOLAR))) { for(int ig=0; ig<4; ig++) { pCurve[ig] = m_WPlrGraph[ig].AddCurve(); pCurve[ig]->ShowPoints(pWPolar->m_bShowPoints); pCurve[ig]->SetStyle(pWPolar->m_Style); pCurve[ig]->SetColor(pWPolar->m_Color); pCurve[ig]->SetWidth(pWPolar->m_Width); FillWPlrCurve(pCurve[ig], pWPolar, m_WPlrGraph[ig].GetXVariable(), m_WPlrGraph[ig].GetYVariable()); pCurve[ig]->SetTitle(pWPolar->m_PlrName); } } } } /** * Resets and fills the stability graphs curves with the data from the CWPolar objects */ void QMiarex::CreateStabilityCurves() { if(m_iStabilityView==STABTIMEVIEW) { if(m_StabilityResponseType==1) CreateStabRungeKuttaCurves(); else CreateStabTimeCurves(); } else { CreateStabRLCurves(); } } /** * Builds the initial condition response due to perturbations from steady state * The time response is calculated analytically based on the knowledge of the eigenvalues and eigenvectors */ void QMiarex::CreateStabTimeCurves() { complex M[16];// the modal matrix complex InvM[16];// the inverse of the modal matrix complex q[4],q0[4],y[4];//the part of each mode in the solution int i,j,k; double t, dt, TotalPoints; // the input load complex in[4]; Curve *pCurve0, *pCurve1, *pCurve2, *pCurve3; QString strong, CurveTitle; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; CurveTitle = pStabView->m_pctrlCurveList->currentText(); pCurve0 = m_TimeGraph[0].GetCurve(CurveTitle); if(pCurve0) pCurve0->clear(); else return; pCurve1 = m_TimeGraph[1].GetCurve(CurveTitle); if(pCurve1) pCurve1->clear(); else return; pCurve2 = m_TimeGraph[2].GetCurve(CurveTitle); if(pCurve2) pCurve2->clear(); else return; pCurve3 = m_TimeGraph[3].GetCurve(CurveTitle); if(pCurve3) pCurve3->clear(); else return; if(!m_pCurWOpp || !m_pCurWOpp->m_bIsVisible) return; strong = pStabView->m_pctrlCurveList->currentText(); m_Deltat = pStabView->m_pctrlDeltat->Value(); m_TotalTime = pStabView->m_pctrlTotalTime->Value(); dt = m_TotalTime/1000.; if(dtm_pctrlStabVar1->Value(); m_TimeInput[1] = pStabView->m_pctrlStabVar2->Value(); m_TimeInput[2] = pStabView->m_pctrlStabVar3->Value(); m_TimeInput[3] = 0.0;//we start with an initial 0.0 value for pitch or bank angles if(m_StabilityResponseType==0) { //start with the user input initial conditions in[0] = complex(m_TimeInput[0]*PI/180.0, 0.0); in[1] = complex(m_TimeInput[1]*PI/180.0, 0.0); in[2] = complex(m_TimeInput[2]*PI/180.0, 0.0); in[3] = complex(m_TimeInput[3]*PI/180.0, 0.0); } else if(m_StabilityResponseType==2) { //start with the initial conditions which will excite only the requested mode in[0] = m_pCurWOpp->m_EigenVector[pStabView->m_iCurrentMode][0]; in[1] = m_pCurWOpp->m_EigenVector[pStabView->m_iCurrentMode][1]; in[2] = m_pCurWOpp->m_EigenVector[pStabView->m_iCurrentMode][2]; in[3] = m_pCurWOpp->m_EigenVector[pStabView->m_iCurrentMode][3]; } //fill the modal matrix if(m_bLongitudinal) k=0; else k=1; for (i=0; i<4; i++) { for(j=0;j<4;j++) { *(M+4*j+i) = m_pCurWOpp->m_EigenVector[k*4+i][j]; } } //Invert the matrix if(!Invert44(M, InvM)) { } else { //calculate the modal coefficients at t=0 q0[0] = InvM[0] * in[0] + InvM[1] * in[1] + InvM[2] * in[2] + InvM[3] * in[3]; q0[1] = InvM[4] * in[0] + InvM[5] * in[1] + InvM[6] * in[2] + InvM[7] * in[3]; q0[2] = InvM[8] * in[0] + InvM[9] * in[1] + InvM[10]* in[2] + InvM[11]* in[3]; q0[3] = InvM[12]* in[0] + InvM[13]* in[1] + InvM[14]* in[2] + InvM[15]* in[3]; for(i=0; im_EigenValue[0+k*4]*t); q[1] = q0[1] * exp(m_pCurWOpp->m_EigenValue[1+k*4]*t); q[2] = q0[2] * exp(m_pCurWOpp->m_EigenValue[2+k*4]*t); q[3] = q0[3] * exp(m_pCurWOpp->m_EigenValue[3+k*4]*t); y[0] = *(M+4*0+0) * q[0] +*(M+4*0+1) * q[1] +*(M+4*0+2) * q[2] +*(M+4*0+3) * q[3]; y[1] = *(M+4*1+0) * q[0] +*(M+4*1+1) * q[1] +*(M+4*1+2) * q[2] +*(M+4*1+3) * q[3]; y[2] = *(M+4*2+0) * q[0] +*(M+4*2+1) * q[1] +*(M+4*2+2) * q[2] +*(M+4*2+3) * q[3]; y[3] = *(M+4*3+0) * q[0] +*(M+4*3+1) * q[1] +*(M+4*3+2) * q[2] +*(M+4*3+3) * q[3]; if(abs(q[0])>1.e10 || abs(q[1])>1.e10 || abs(q[2])>1.e10 || abs(q[3])>1.e10 ) break; pCurve0->AppendPoint(t, y[0].real()); if(m_bLongitudinal) pCurve1->AppendPoint(t, y[1].real()); else pCurve1->AppendPoint(t, y[1].real()*180.0/PI); pCurve2->AppendPoint(t, y[2].real()*180.0/PI); pCurve3->AppendPoint(t, y[3].real()*180.0/PI); } } } /** * Builds the forced response from the state matrix and the forced input matrix * using a Runge-Kutta integration scheme. * The forced input is interpolated in the control history defined in the input table. */ void QMiarex::CreateStabRungeKuttaCurves() { static int i, j, TotalPoints, PlotInterval; static double t, dt, ctrl_t; static Curve *pCurve0, *pCurve1, *pCurve2, *pCurve3; static double A[4][4], B[MAXCONTROLS][4]; static double m[5][4]; static double y[4], yp[4]; QString CurveTitle; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; CurveTitle = pStabView->m_pctrlCurveList->currentText(); pCurve0 = m_TimeGraph[0].GetCurve(CurveTitle); if(pCurve0) pCurve0->clear(); else return; pCurve1 = m_TimeGraph[1].GetCurve(CurveTitle); if(pCurve1) pCurve1->clear(); else return; pCurve2 = m_TimeGraph[2].GetCurve(CurveTitle); if(pCurve2) pCurve2->clear(); else return; pCurve3 = m_TimeGraph[3].GetCurve(CurveTitle); if(pCurve3) pCurve3->clear(); else return; //We need a WOpp if(!m_pCurWOpp) return;//nothing to plot //Check that the current polar is of the stability type if(!m_pCurWPolar || m_pCurWPolar->m_WPolarType!=STABILITYPOLAR) return; if(m_bLongitudinal) { memcpy(A, m_pCurWOpp->m_ALong, 4*4*sizeof(double)); memcpy(B, m_pCurWOpp->m_BLong, MAXCONTROLS*4*sizeof(double)); } else { memcpy(A, m_pCurWOpp->m_ALat, 4*4*sizeof(double)); memcpy(B, m_pCurWOpp->m_BLat, MAXCONTROLS*4*sizeof(double)); } // Rebuild the Forced Response matrix //read the initial step condition // pStabView->ReadForcedInput(time,input); // RampAmp = m_RampAmplitude*PI/180.0; // RampTime = m_RampTime; //s m_Deltat = pStabView->m_pctrlDeltat->Value(); m_TotalTime = pStabView->m_pctrlTotalTime->Value(); dt = m_TotalTime/1000.; if(dtAppendPoint(0.0, y[0]); pCurve1->AppendPoint(0.0, y[1]); pCurve2->AppendPoint(0.0, y[2]); pCurve3->AppendPoint(0.0, y[3]); //Runge-Kutta method for(i=0; iGetControlInput(t); m[0][0] += B[j][0] * ctrl_t; m[0][1] += B[j][1] * ctrl_t; m[0][2] += B[j][2] * ctrl_t; m[0][3] += B[j][3] * ctrl_t; //middle point m2 yp[0] = y[0] + dt/2.0 * m[0][0]; yp[1] = y[1] + dt/2.0 * m[0][1]; yp[2] = y[2] + dt/2.0 * m[0][2]; yp[3] = y[3] + dt/2.0 * m[0][3]; m[1][0] = A[0][0]*yp[0] + A[0][1]*yp[1] + A[0][2]*yp[2] + A[0][3]*yp[3]; m[1][1] = A[1][0]*yp[0] + A[1][1]*yp[1] + A[1][2]*yp[2] + A[1][3]*yp[3]; m[1][2] = A[2][0]*yp[0] + A[2][1]*yp[1] + A[2][2]*yp[2] + A[2][3]*yp[3]; m[1][3] = A[3][0]*yp[0] + A[3][1]*yp[1] + A[3][2]*yp[2] + A[3][3]*yp[3]; ctrl_t = pStabView->GetControlInput(t+dt/2.0); m[1][0] += B[j][0] * ctrl_t; m[1][1] += B[j][1] * ctrl_t; m[1][2] += B[j][2] * ctrl_t; m[1][3] += B[j][3] * ctrl_t; //second point m3 yp[0] = y[0] + dt/2.0 * m[1][0]; yp[1] = y[1] + dt/2.0 * m[1][1]; yp[2] = y[2] + dt/2.0 * m[1][2]; yp[3] = y[3] + dt/2.0 * m[1][3]; m[2][0] = A[0][0]*yp[0] + A[0][1]*yp[1] + A[0][2]*yp[2] + A[0][3]*yp[3]; m[2][1] = A[1][0]*yp[0] + A[1][1]*yp[1] + A[1][2]*yp[2] + A[1][3]*yp[3]; m[2][2] = A[2][0]*yp[0] + A[2][1]*yp[1] + A[2][2]*yp[2] + A[2][3]*yp[3]; m[2][3] = A[3][0]*yp[0] + A[3][1]*yp[1] + A[3][2]*yp[2] + A[3][3]*yp[3]; ctrl_t = pStabView->GetControlInput(t+dt/2.0); m[2][0] += B[j][0] * ctrl_t; m[2][1] += B[j][1] * ctrl_t; m[2][2] += B[j][2] * ctrl_t; m[2][3] += B[j][3] * ctrl_t; //third point m4 yp[0] = y[0] + dt * m[2][0]; yp[1] = y[1] + dt * m[2][1]; yp[2] = y[2] + dt * m[2][2]; yp[3] = y[3] + dt * m[2][3]; m[3][0] = A[0][0]*yp[0] + A[0][1]*yp[1] + A[0][2]*yp[2] + A[0][3]*yp[3]; m[3][1] = A[1][0]*yp[0] + A[1][1]*yp[1] + A[1][2]*yp[2] + A[1][3]*yp[3]; m[3][2] = A[2][0]*yp[0] + A[2][1]*yp[1] + A[2][2]*yp[2] + A[2][3]*yp[3]; m[3][3] = A[3][0]*yp[0] + A[3][1]*yp[1] + A[3][2]*yp[2] + A[3][3]*yp[3]; ctrl_t = pStabView->GetControlInput(t+dt); m[3][0] += B[j][0] * ctrl_t; m[3][1] += B[j][1] * ctrl_t; m[3][2] += B[j][2] * ctrl_t; m[3][3] += B[j][3] * ctrl_t; //final slope m5 m[4][0] = 1./6. * (m[0][0] + 2.0*m[1][0] + 2.0*m[2][0] + m[3][0]); m[4][1] = 1./6. * (m[0][1] + 2.0*m[1][1] + 2.0*m[2][1] + m[3][1]); m[4][2] = 1./6. * (m[0][2] + 2.0*m[1][2] + 2.0*m[2][2] + m[3][2]); m[4][3] = 1./6. * (m[0][3] + 2.0*m[1][3] + 2.0*m[2][3] + m[3][3]); y[0] += m[4][0] * dt; y[1] += m[4][1] * dt; y[2] += m[4][2] * dt; y[3] += m[4][3] * dt; t +=dt; if(qAbs(y[0])>1.e10 || qAbs(y[1])>1.e10 || qAbs(y[2])>1.e10 || qAbs(y[3])>1.e10 ) break; if(i%PlotInterval==0) { if(m_bLongitudinal) { pCurve0->AppendPoint(t, y[0]*MainFrame::s_mstoUnit); pCurve1->AppendPoint(t, y[1]*MainFrame::s_mstoUnit); pCurve2->AppendPoint(t, y[2]*180.0/PI);//deg/s pCurve3->AppendPoint(t, y[3]*180.0/PI);//deg } else { pCurve0->AppendPoint(t, y[0]*MainFrame::s_mstoUnit); pCurve1->AppendPoint(t, y[1]*180.0/PI);//deg/s pCurve2->AppendPoint(t, y[2]*180.0/PI);//deg/s pCurve3->AppendPoint(t, y[3]*180.0/PI);//deg } } } pCurve0->SetVisible(true); pCurve1->SetVisible(true); pCurve2->SetVisible(true); pCurve3->SetVisible(true); } /** * Resets and fills the curves of the root locus graph with the data from the CWPolar objects */ void QMiarex::CreateStabRLCurves() { WPolar *pWPolar; // we have eight modes, 4 longitudinal and 4 lateral // declare a curve for each static Curve *pLongCurve1,*pLongCurve2,*pLongCurve3,*pLongCurve4; static Curve *pLatCurve1,*pLatCurve2,*pLatCurve3,*pLatCurve4;//do it later m_LongRLGraph.DeleteCurves(); m_LatRLGraph.DeleteCurves(); for (int k=0; ksize(); k++) { pWPolar = (WPolar*)m_poaWPolar->at(k); if ((pWPolar->m_bIsVisible||pWPolar->m_bShowPoints) && pWPolar->m_Alpha.size()>0 && (m_bType7 && pWPolar->m_WPolarType==STABILITYPOLAR)) { pLongCurve1 = m_LongRLGraph.AddCurve(); pLongCurve2 = m_LongRLGraph.AddCurve(); pLongCurve3 = m_LongRLGraph.AddCurve(); pLongCurve4 = m_LongRLGraph.AddCurve(); pLongCurve1->SetVisible(pWPolar->m_bIsVisible); pLongCurve2->SetVisible(pWPolar->m_bIsVisible); pLongCurve3->SetVisible(pWPolar->m_bIsVisible); pLongCurve4->SetVisible(pWPolar->m_bIsVisible); pLongCurve1->ShowPoints(pWPolar->m_bShowPoints); pLongCurve2->ShowPoints(pWPolar->m_bShowPoints); pLongCurve3->ShowPoints(pWPolar->m_bShowPoints); pLongCurve4->ShowPoints(pWPolar->m_bShowPoints); pLongCurve1->SetStyle(pWPolar->m_Style); pLongCurve1->SetColor(pWPolar->m_Color); pLongCurve1->SetWidth(pWPolar->m_Width); pLongCurve2->SetStyle(pWPolar->m_Style); pLongCurve2->SetColor(pWPolar->m_Color); pLongCurve2->SetWidth(pWPolar->m_Width); pLongCurve3->SetStyle(pWPolar->m_Style); pLongCurve3->SetColor(pWPolar->m_Color); pLongCurve3->SetWidth(pWPolar->m_Width); pLongCurve4->SetStyle(pWPolar->m_Style); pLongCurve4->SetColor(pWPolar->m_Color); pLongCurve4->SetWidth(pWPolar->m_Width); FillStabCurve(pLongCurve1, pWPolar, 0); FillStabCurve(pLongCurve2, pWPolar, 1); FillStabCurve(pLongCurve3, pWPolar, 2); FillStabCurve(pLongCurve4, pWPolar, 3); pLongCurve1->SetTitle(pWPolar->m_PlrName+"_Mode_1"); pLongCurve2->SetTitle(pWPolar->m_PlrName+"_Mode_2"); pLongCurve3->SetTitle(pWPolar->m_PlrName+"_Mode_3"); pLongCurve4->SetTitle(pWPolar->m_PlrName+"_Mode_4"); //Lateral modes pLatCurve1 = m_LatRLGraph.AddCurve(); pLatCurve2 = m_LatRLGraph.AddCurve(); pLatCurve3 = m_LatRLGraph.AddCurve(); pLatCurve4 = m_LatRLGraph.AddCurve(); pLatCurve1->SetVisible(pWPolar->m_bIsVisible); pLatCurve2->SetVisible(pWPolar->m_bIsVisible); pLatCurve3->SetVisible(pWPolar->m_bIsVisible); pLatCurve4->SetVisible(pWPolar->m_bIsVisible); pLatCurve1->ShowPoints(pWPolar->m_bShowPoints); pLatCurve2->ShowPoints(pWPolar->m_bShowPoints); pLatCurve3->ShowPoints(pWPolar->m_bShowPoints); pLatCurve4->ShowPoints(pWPolar->m_bShowPoints); pLatCurve1->SetStyle(pWPolar->m_Style); pLatCurve1->SetColor(pWPolar->m_Color); pLatCurve1->SetWidth(pWPolar->m_Width); pLatCurve2->SetStyle(pWPolar->m_Style); pLatCurve2->SetColor(pWPolar->m_Color); pLatCurve2->SetWidth(pWPolar->m_Width); pLatCurve3->SetStyle(pWPolar->m_Style); pLatCurve3->SetColor(pWPolar->m_Color); pLatCurve3->SetWidth(pWPolar->m_Width); pLatCurve4->SetStyle(pWPolar->m_Style); pLatCurve4->SetColor(pWPolar->m_Color); pLatCurve4->SetWidth(pWPolar->m_Width); FillStabCurve(pLatCurve1, pWPolar, 4); FillStabCurve(pLatCurve2, pWPolar, 5); FillStabCurve(pLatCurve3, pWPolar, 6); FillStabCurve(pLatCurve4, pWPolar, 7); pLatCurve1->SetTitle(pWPolar->m_PlrName+"_Mode_1"); pLatCurve2->SetTitle(pWPolar->m_PlrName+"_Mode_2"); pLatCurve3->SetTitle(pWPolar->m_PlrName+"_Mode_3"); pLatCurve4->SetTitle(pWPolar->m_PlrName+"_Mode_4"); } } } /** * Draws the legend of the Cp graph *@param painter the instance of the QPainter object associated to the active view *@param the top left postition where the legend is to be drawn *@param the y coordinate of the bottom of the drawing rectangle */ void QMiarex::DrawCpLegend(QPainter &painter, QPoint place, int bottom) { painter.save(); int LegendSize, LegendWidth, dny, x1, i, ny; Curve *pCurve=NULL; QString strong; LegendSize = 30; LegendWidth = 350; dny = 14; bottom -= 15;//margin QPen CurvePen; QPen TextPen(MainFrame::s_TextColor); ny=-1; for (i=0; isize()) { ny++; if(abs(bottom)color()); CurvePen.setStyle(GetStyle(pCurve->style())); CurvePen.setWidth(pCurve->width()); painter.setPen(CurvePen); painter.drawLine(place.x() + (int)(1.5*LegendSize), place.y() + (int)(1.*dny*ny), place.x() + (int)(2.5*LegendSize), place.y() + (int)(1.*dny*ny)); if(pCurve->PointsVisible()) { x1 = place.x() + (int)(2.0*LegendSize); painter.drawRect(x1-2, place.y() + (int)(1.*dny*ny)-2,4,4); } pCurve->title(strong); painter.setPen(TextPen); painter.drawText(place.x() + (int)(3*LegendSize),place.y() + (int)(1.*dny*ny), strong); } } painter.restore(); } /** * Draws the legend for the time response graph- 4 curves *@param painter the instance of the QPainter object associated to the active view *@param the top left postition where the legend is to be drawn *@param the y coordinate of the bottom of the drawing rectangle */ void QMiarex::DrawStabTimeLegend(QPainter &painter, QPoint place, int bottom) { painter.save(); int LegendSize, LegendWidth, dny, x1, i, ny; Curve *pCurve=NULL; QString strong; LegendSize = 30; LegendWidth = 350; dny = 14; bottom -= 15;//margin QPen CurvePen; QPen TextPen(MainFrame::s_TextColor); ny=0; for (i=0; isize() && pCurve->IsVisible()) { ny++; if(abs(bottom)color()); CurvePen.setStyle(GetStyle(pCurve->style())); CurvePen.setWidth(pCurve->width()); painter.setPen(CurvePen); painter.drawLine(place.x() + (int)(1.5*LegendSize), place.y() + (int)(1.*dny*ny), place.x() + (int)(2.5*LegendSize), place.y() + (int)(1.*dny*ny)); if(pCurve->PointsVisible()) { x1 = place.x() + (int)(2.0*LegendSize); painter.drawRect(x1-2, place.y() + (int)(1.*dny*ny)-2,4,4); } pCurve->title(strong); painter.setPen(TextPen); painter.drawText(place.x() + (int)(3*LegendSize), place.y() + (int)(1.*dny*ny)+(int)(dny/3), strong); } } painter.restore(); } /** * Draws the legend for the WOpp graph *@param painter the instance of the QPainter object associated to the active view *@param the top left postition where the legend is to be drawn *@param the y coordinate of the bottom of the drawing rectangle */ void QMiarex::DrawWOppLegend(QPainter &painter, QPoint place, int bottom) { painter.save(); int LegendSize, LegendWidth, ypos; int i, j, k,l, x1, nc, ny; ny=0; QString str1, str2, str3, str4, str5, str6; LegendSize = 30; LegendWidth = 300; QStringList str; // we need to make an inventory of wings bool bFound; WingOpp * pWOpp = NULL; PlaneOpp *pPOpp = NULL; for (i=0; isize(); i++) { bFound = false; pWOpp = (WingOpp*)m_poaWOpp->at(i); for (j=0; jm_WingName == str.at(j)) bFound = true; } if (!bFound) { str.append(pWOpp->m_WingName); } } for (i=0; isize(); i++) { bFound = false; pPOpp = (PlaneOpp*)m_poaPOpp->at(i); for (j=0; jm_PlaneName == str.at(j)) bFound = true; } if (!bFound) { str.append(pPOpp->m_PlaneName); } } painter.setBackgroundMode(Qt::TransparentMode); painter.setFont(MainFrame::s_TextFont); QFontMetrics fm(((MainFrame*)s_pMainFrame)->s_TextFont); ypos = fm.height(); QPen TextPen(MainFrame::s_TextColor); painter.setPen(TextPen); TextPen.setWidth(1); QBrush LegendBrush(MainFrame::s_BackgroundColor); painter.setBrush(LegendBrush); QPen LegendPen; LegendPen.setWidth(1); if(m_bCurWOppOnly) { if(!m_pCurWOpp || !m_pCurWOpp->m_bIsVisible) { painter.restore(); return; } ny++ ; painter.setPen(TextPen); painter.drawText(place.x() + (int)(1*LegendSize), place.y() + ypos*ny-(int)(ypos/2), m_pCurWing->WingName()); LegendPen.setColor(m_pCurWOpp->m_Color); LegendPen.setStyle(GetStyle(m_pCurWOpp->m_Style)); LegendPen.setWidth(m_pCurWOpp->m_Width); painter.setPen(LegendPen); painter.drawLine(place.x() + (int)(1.5*LegendSize), place.y() + (int)(1.*ypos*ny), place.x() + (int)(2.5*LegendSize), place.y() + (int)(1.*ypos*ny)); if(m_pCurWOpp->m_bShowPoints) { x1 = place.x() + (int)(2.0*LegendSize); painter.drawRect(x1-2, place.y() + (int)(1.*ypos*ny)-2, 4, 4); } str1 = QString("V=%1").arg(m_pCurWOpp->m_QInf*MainFrame::s_mstoUnit,5,'f',2); GetSpeedUnit(str2, MainFrame::s_SpeedUnit); str3 = QString("_a=%1").arg(m_pCurWOpp->m_Alpha,5,'f',2); if(qAbs(m_pCurWOpp->m_Beta)>0.0) str4 = QString("_b=%1").arg(m_pCurWOpp->m_Beta,5,'f',2); else str4 =""; if(m_pCurWOpp->m_WPolarType==STABILITYPOLAR) str5 = QString("_Ctrl=%1").arg(m_pCurWOpp->m_Ctrl,5,'f',2); else str5 =""; if(m_pCurWOpp->m_AnalysisMethod==LLTMETHOD) str6="_LLT"; else if(m_pCurWPolar->m_bThinSurfaces) { if(m_pCurWOpp->m_bVLM1) str6="_VLM1"; else str6="_VLM2"; } else if(m_pCurWOpp->m_AnalysisMethod==PANELMETHOD) { str6="_Panel"; if(m_pCurWOpp->m_bThinSurface) str6 += "_Thin"; } if(m_pCurWOpp->m_bTiltedGeom) str6 += "_TG"; if(m_pCurWOpp->m_bOut) str6+=" (Out)"; painter.setPen(TextPen); painter.drawText(place.x() + (int)(3*LegendSize), place.y() + (int)(1.*ypos*ny)+(int)(ypos/3), str1+str2+str3+str4+str5+str6); } else { bool bStarted = false; for (k = 0; ksize(); l++) { pWOpp = (WingOpp*)m_poaWOpp->at(l); if (pWOpp->m_bIsVisible && pWOpp->m_WingName == str.at(k)) UFOPts++; } for (l=0; l < m_poaPOpp->size(); l++) { pPOpp = (PlaneOpp*)m_poaPOpp->at(l); if (pPOpp->m_bIsVisible && pPOpp->m_PlaneName == str.at(k)) UFOPts++; } if (UFOPts) { int YPos = place.y() + (ny+UFOPts+2) * ypos;// bottom line of this foil's legend painter.setPen(TextPen); if (!bStarted || (abs(bottom) > abs(YPos))) { ny++; painter.drawText(place.x() + (int)(1*LegendSize), place.y() + ypos*ny-(int)(ypos/2), str.at(k)); } else { // move rigth if outside screen place.rx() += LegendWidth; ny=1; painter.drawText(place.x() + (int)(1*LegendSize), place.y() + ypos*ny-(int)(ypos/2), str.at(k)); } bStarted = true; for (nc=0; nc < m_poaWOpp->size(); nc++) { pWOpp = (WingOpp*)m_poaWOpp->at(nc); if(str.at(k) == pWOpp->m_WingName && pWOpp->m_bIsVisible) { if(abs(bottom)m_Color); LegendPen.setStyle(GetStyle(pWOpp->m_Style)); LegendPen.setWidth(pWOpp->m_Width); painter.setPen(LegendPen); painter.drawLine(place.x() + (int)(1.5*LegendSize), place.y() + (int)(1.*ypos*ny), place.x() + (int)(2.5*LegendSize), place.y() + (int)(1.*ypos*ny)); if(pWOpp->m_bShowPoints) { x1 = place.x() + (int)(2.0*LegendSize); painter.drawRect(x1-2, place.y() + (int)(1.*ypos*ny)-2, 4,4); } str1 = QString("V=%1").arg(pWOpp->m_QInf*MainFrame::s_mstoUnit,5,'f',2); GetSpeedUnit(str2, MainFrame::s_SpeedUnit); str3 = QString("_a=%1").arg(pWOpp->m_Alpha,5,'f',2); if(qAbs(pWOpp->m_Beta)>0.0) str4 = QString("_b=%1").arg(pWOpp->m_Beta,5,'f',2); else str4 =""; if(pWOpp->m_WPolarType==STABILITYPOLAR) str5 = QString("_Ctrl=%1").arg(pWOpp->m_Ctrl,5,'f',2); else str5 =""; if(pWOpp->m_AnalysisMethod==LLTMETHOD) str6 ="_LLT"; else if(pWOpp->m_AnalysisMethod==VLMMETHOD) { if(pWOpp->m_bVLM1) str6 ="_VLM1"; else str6 ="_VLM2"; } else if(pWOpp->m_AnalysisMethod==PANELMETHOD) { str6="_Panel"; if(pWOpp->m_bThinSurface) str6 += "_Thin"; } if(pWOpp->m_bTiltedGeom) str6 += "_TG"; if(pWOpp->m_bOut) str6+=" (Out)"; painter.setPen(TextPen); painter.drawText(place.x() + (int)(3*LegendSize), place.y() + (int)(1.*ypos*ny)+(int)(ypos/3), str1+str2+str3+str4+str5+str6); ny++ ; } } for (nc=0; nc < m_poaPOpp->size(); nc++) { pPOpp = (PlaneOpp*)m_poaPOpp->at(nc); if(str.at(k) == pPOpp->m_PlaneName && pPOpp->m_bIsVisible) { if(abs(bottom)m_Color); LegendPen.setStyle(GetStyle(pPOpp->m_Style)); LegendPen.setWidth(pPOpp->m_Width); painter.setPen(LegendPen); painter.drawLine(place.x() + (int)(1.5*LegendSize), place.y() + (int)(1.*ypos*ny), place.x() + (int)(2.5*LegendSize), place.y() + (int)(1.*ypos*ny)); if(pPOpp->m_bShowPoints) { x1 = place.x() + (int)(2.0*LegendSize); painter.drawRect(x1-2, place.y() + (int)(1.*ypos*ny)-2, 4, 4); } str1 = QString("V=%1").arg(pPOpp->m_QInf*MainFrame::s_mstoUnit,5,'f',2); GetSpeedUnit(str2, MainFrame::s_SpeedUnit); str3 = QString("_a=%1").arg(pPOpp->m_Alpha,5,'f',2); if(qAbs(pPOpp->m_Beta)>0.0) str4 = QString("_b=%1").arg(pPOpp->m_Beta,5,'f',2); else str4 =""; if(pPOpp->m_WPolarType==STABILITYPOLAR) str5 = QString("_Ctrl=%1").arg(pPOpp->m_Ctrl,5,'f',2); else str5 =""; if(pPOpp->m_pPlaneWOpp[0]->m_AnalysisMethod==VLMMETHOD) { if(pPOpp->m_bVLM1) str6 ="_VLM1"; else str6 ="_VLM2"; } else if(pPOpp->m_pPlaneWOpp[0]->m_AnalysisMethod==PANELMETHOD) { str6="_Panel"; if(pPOpp->m_pPlaneWOpp[0]->m_bThinSurface) str4 += "_Thin"; } if(pPOpp->m_pPlaneWOpp[0]->m_bTiltedGeom) str6+= "_TG"; if(pPOpp->m_pPlaneWOpp[0]->m_bOut) str6+=" (Out)"; painter.setPen(TextPen); painter.drawText(place.x() + (int)(3*LegendSize), place.y() + (int)(1.*ypos*ny)+(int)(ypos/3), str1+str2+str3+str4+str5+str6); ny++ ; } } if (UFOPts) ny++; } } } painter.restore(); } /** * Draws the legend of the polar graphs *@param painter the instance of the QPainter object associated to the active view *@param the top left postition where the legend is to be drawn *@param the y coordinate of the bottom of the drawing rectangle */ void QMiarex::DrawWPolarLegend(QPainter &painter, QPoint place, int bottom) { painter.save(); int LegendSize, LegendWidth, ypos; int i,j,k,l, ny, x1; LegendSize = 30; LegendWidth = 280; QFontMetrics fm(((MainFrame*)s_pMainFrame)->s_TextFont); ypos = fm.height(); painter.setFont(MainFrame::s_TextFont); QPen TextPen(MainFrame::s_TextColor); painter.setPen(TextPen); TextPen.setWidth(1); QStringList strUFOList; // we need to make an inventory of wings WPolar * pWPolar; Wing *pWing; Plane *pPlane; for (j=0; jsize(); j++) { pWing = (Wing*)m_poaWing->at(j); for (i=0; isize(); i++) { pWPolar = (WPolar*)m_poaWPolar->at(i); if (pWPolar->UFOName()==pWing->WingName() && (pWPolar->visible() || (pWPolar->pointsVisible()&&m_iView==WSTABVIEW))) { strUFOList.append(pWing->WingName()); break; } }// finished inventory } for (j=0; jsize(); j++) { pPlane = (Plane*)m_poaPlane->at(j); for (i=0; isize(); i++) { pWPolar = (WPolar*)m_poaWPolar->at(i); if (pWPolar->UFOName()==pPlane->PlaneName()&& (pWPolar->visible() || (pWPolar->pointsVisible()&&m_iView==WSTABVIEW))) { strUFOList.append(pPlane->PlaneName()); break; } }// finished inventory } int nUFOs = strUFOList.size(); painter.setBackgroundMode(Qt::TransparentMode); QBrush LegendBrush(MainFrame::s_BackgroundColor); painter.setBrush(LegendBrush); QPen LegendPen; LegendPen.setWidth(1); ny =0; for (k=0; ksize(); l++) { pWPolar = (WPolar*)m_poaWPolar->at(l); if ( pWPolar->m_Alpha.size() && (pWPolar->visible() || (pWPolar->pointsVisible() && pWPolar->m_WPolarType==STABILITYPOLAR)) && ((pWPolar->m_WPolarType==STABILITYPOLAR && m_iView==WSTABVIEW) || m_iView!=WSTABVIEW) && pWPolar->UFOName() == strUFOList.at(k) && ((pWPolar->m_WPolarType==FIXEDSPEEDPOLAR && m_bType1) || (pWPolar->m_WPolarType==FIXEDLIFTPOLAR && m_bType2) || (pWPolar->m_WPolarType==FIXEDAOAPOLAR && m_bType4) || (pWPolar->m_WPolarType==STABILITYPOLAR && m_bType7))) { UFOPlrs++; } } if (UFOPlrs) { int YPos = place.y() + (ny+UFOPlrs+2) * ypos;// bottom line of this UFO's legend if(abs(bottom) > abs(YPos)) { ny++; painter.drawText(place.x(), place.y() + ypos*ny-(int)(ypos/2), strUFOList.at(k)); } else { // move rigth if outside screen place.rx() += LegendWidth; ny=1; painter.setPen(TextPen); painter.drawText(place.x() , place.y() + ypos*ny-(int)(ypos/2), strUFOList.at(k)); } for (int nc=0; ncsize(); nc++) { pWPolar = (WPolar*)m_poaWPolar->at(nc); if(strUFOList.at(k) == pWPolar->UFOName()) { if(!pWPolar->m_Alpha.size()) { } else if(m_iView==WPOLARVIEW && !pWPolar->visible()) { } else if(m_iView==WSTABVIEW && (!pWPolar->visible() && !pWPolar->pointsVisible())) { } else if(m_iView==WSTABVIEW && pWPolar->m_WPolarType!=STABILITYPOLAR) { } else if((pWPolar->m_WPolarType==FIXEDSPEEDPOLAR && !m_bType1) || (pWPolar->m_WPolarType==FIXEDLIFTPOLAR && !m_bType2) || (pWPolar->m_WPolarType==FIXEDAOAPOLAR && !m_bType4) || (pWPolar->m_WPolarType==STABILITYPOLAR && !m_bType7)) { } else { LegendPen.setColor(pWPolar->m_Color); LegendPen.setStyle(GetStyle(pWPolar->m_Style)); LegendPen.setWidth(pWPolar->m_Width); painter.setPen(LegendPen); painter.drawLine(place.x() + (int)(0.5*LegendSize), place.y() + (int)(1.*ypos*ny), place.x() + (int)(1.5*LegendSize), place.y() + (int)(1.*ypos*ny)); if(pWPolar->m_bShowPoints) { x1 = place.x() + (int)(1.0*LegendSize); painter.drawRect(x1-2, place.y()-2 + (int)(1.*ypos*ny), 4, 4); } painter.setPen(TextPen); painter.drawText(place.x() + (int)(2.0*LegendSize), place.y() + (int)(1.*ypos*ny)+(int)(ypos/3), pWPolar->m_PlrName); ny++ ; } } } if(UFOPlrs) ny++; } } painter.restore(); } /** * Duplicates the currently selected plane, if any and opens it for edition */ void QMiarex::DuplicatePlane() { if(!m_pCurPlane) return; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; Plane* pNewPlane= new Plane; pNewPlane->Duplicate(m_pCurPlane); if(!SetModPlane(pNewPlane)) { delete pNewPlane; SetUFO(); pMainFrame->UpdateUFOs(); UpdateView(); } else { m_pCurPlane = AddPlane(pNewPlane); SetUFO(); pMainFrame->UpdateUFOs(); UpdateView(); EditCurPlane(); } } /** * Opens the edition dialog box for the currently selected plane */ void QMiarex::EditCurPlane() { int i; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(!m_pCurPlane) return; WPolar *pWPolar; PlaneOpp* pPOpp; bool bHasResults = false; for (i=0; i< m_poaWPolar->size(); i++) { pWPolar = (WPolar*)m_poaWPolar->at(i); if(pWPolar->m_Alpha.size() && pWPolar->m_UFOName == m_pCurPlane->PlaneName()) { bHasResults = true; break; } } for (i=0; i< m_poaPOpp->size(); i++) { pPOpp = (PlaneOpp*)m_poaPOpp->at(i); if(pPOpp->m_PlaneName == m_pCurPlane->PlaneName()) { bHasResults = true; break; } } Plane* pModPlane= new Plane; pModPlane->Duplicate(m_pCurPlane); PlaneDlg plDlg(pMainFrame); plDlg.m_pPlane = pModPlane; plDlg.m_bAcceptName = false; plDlg.InitDialog(); ModDlg mdDlg(pMainFrame); if(QDialog::Accepted == plDlg.exec()) { if(plDlg.m_bDescriptionChanged) { MainFrame::SetSaveState(false); m_pCurPlane->rPlaneDescription() = pModPlane->PlaneDescription(); } if(plDlg.m_bChanged) { if(bHasResults) { mdDlg.m_Question = tr("The modification will erase all results associated to this Plane.\nContinue ?"); mdDlg.InitDialog(); int Ans = mdDlg.exec(); if (Ans == QDialog::Rejected) { //restore geometry delete pModPlane; // clean up return; } else if(Ans==20) { //save mods to a new plane object if(!SetModPlane(pModPlane)) { delete pModPlane; } else { m_pCurPlane = AddPlane(pModPlane); } SetUFO(); pMainFrame->UpdateUFOs(); UpdateView(); return; } } //then modifications are automatically recorded m_pCurPlane->Duplicate(pModPlane); pMainFrame->DeletePlane(m_pCurPlane, true);// will also set new surface and Aerochord in WPolars m_bResetglGeom = true; m_bResetglMesh = true; // m_bResetglOpp = true; if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); else if(m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); } SetUFO(); pMainFrame->UpdateUFOs(); m_bIs2DScaleSet = false; SetScale(); OnAdjustToWing(); SetControls(); UpdateView(); } else { // restore original // m_pCurPlane->Duplicate(pSavePlane); delete pModPlane; // clean up return ; } delete pModPlane; // clean up } /** * Initializes the style combo box for the graph curves * Selects the styles of the active curve */ void QMiarex::FillComboBoxes(bool bEnable) { if(!bEnable) { m_pctrlCurveColor->setEnabled(false); m_pctrlCurveStyle->setEnabled(false); m_pctrlCurveWidth->setEnabled(false); m_pctrlShowCurve->setEnabled(false); m_pctrlShowPoints->setEnabled(false); } else { m_pctrlCurveColor->setEnabled(true); m_pctrlCurveStyle->setEnabled(true); m_pctrlCurveWidth->setEnabled(true); m_pctrlShowCurve->setEnabled(true); m_pctrlShowPoints->setEnabled(true); } int LineWidth[5]; for (int i=0; i<5;i++) LineWidth[i] = m_CurveWidth; m_pStyleDelegate->SetLineWidth(LineWidth); // the same selected width for all styles m_pStyleDelegate->SetLineColor(m_CurveColor); int LineStyle[5]; for (int i=0; i<5;i++) LineStyle[i] = m_CurveStyle; m_pWidthDelegate->SetLineStyle(LineStyle); //the same selected style for all widths m_pWidthDelegate->SetLineColor(m_CurveColor); m_pctrlCurveStyle->SetLine(m_CurveStyle, m_CurveWidth, m_CurveColor); m_pctrlCurveWidth->SetLine(m_CurveStyle, m_CurveWidth, m_CurveColor); m_pctrlCurveColor->SetColor(m_CurveColor); m_pctrlCurveColor->SetStyle(m_CurveStyle); m_pctrlCurveColor->SetWidth(m_CurveWidth); m_pctrlCurveStyle->update(); m_pctrlCurveWidth->update(); m_pctrlCurveColor->update(); m_pctrlCurveStyle->setCurrentIndex(m_CurveStyle); m_pctrlCurveWidth->setCurrentIndex((int)m_CurveWidth-1); } /** * Fills the existing active curve with the WOpp data *@param pWOpp a pointer to the instance of the CWOpp object from which the data is to be extracted *@param pGraph a pointer to the instance of the Graph object to which the curve belongs *@param pCurve a pointer to the instance of the CCurve object to be filled with the data from the CWOpp object */ void QMiarex::FillWOppCurve(WingOpp *pWOpp, Graph *pGraph, Curve *pCurve) { if(!pCurve) return; int Var = pGraph->GetYVariable(); int nStart, i; if(pWOpp->m_AnalysisMethod==LLTMETHOD) nStart = 1; else nStart = 0; switch(Var) { case 0: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_Ai[i]); } pGraph->SetYTitle(tr("Induced Angle")); break; } case 1: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_Alpha + pWOpp->m_Ai[i] + pWOpp->m_Twist[i]); } pGraph->SetYTitle(tr("Total Angle")); break; } case 2: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_Cl[i]); } pGraph->SetYTitle(tr("Cl")); break; } case 3: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_Cl[i] * pWOpp->m_Chord[i]/pWOpp->m_MAChord); } pGraph->SetYTitle(tr("Local lift")); break; } case 4: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_PCd[i]); } pGraph->SetYTitle(tr("Airfoil drag")); break; } case 5: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_ICd[i]); } pGraph->SetYTitle(tr("Induced drag")); break; } case 6: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_PCd[i]+ pWOpp->m_ICd[i]); } pGraph->SetYTitle(tr("Total drag")); break; } case 7: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, (pWOpp->m_PCd[i]+ pWOpp->m_ICd[i])* pWOpp->m_Chord[i]/pWOpp->m_MAChord); } pGraph->SetYTitle(tr("Local drag")); break; } case 8: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_CmAirf[i]); } pGraph->SetYTitle(tr("Cm Airfoil")); break; } case 9: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_Cm[i]); } pGraph->SetYTitle(tr("Cm total")); break; } case 10: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_Re[i]); } pGraph->SetYTitle(tr("Re")); break; } case 11: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_XTrTop[i]); } pGraph->SetYTitle(tr("Top Trans x-Pos %")); break; } case 12: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_XTrBot[i]); } pGraph->SetYTitle(tr("Bot Trans x-Pos %")); break; } case 13: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_XCPSpanRel[i]*100.0); } pGraph->SetYTitle(tr("CP x-Pos %")); break; } case 14: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_BendingMoment[i] * MainFrame::s_NmtoUnit); } QString str; GetMomentUnit(str, MainFrame::s_MomentUnit); pGraph->SetYTitle(tr("BM (") + str + ")"); break; } default: { for (i=nStart; im_NStation; i++) { pCurve->AppendPoint(pWOpp->m_SpanPos[i]*MainFrame::s_mtoUnit, pWOpp->m_Ai[i]); } pGraph->SetYTitle(tr("Induced Angle")); } } } /** * Fills the curve of the stability graph with the data from the pWPolar oject for the seleted mode *@param pCurve a pointer to the instance of the CCurve object to be filled with the data from the CWPolar object *@param pWPolar a pointer to the instance of the CWPolar object from which the data is to be extracted *@param iMode the index of the mode for which the curve is to be created */ void QMiarex::FillStabCurve(Curve *pCurve, WPolar *pWPolar, int iMode) { static int i; static double x,y; static QString UFOName; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; if(m_pCurPlane) UFOName=m_pCurPlane->PlaneName(); else if(m_pCurWing) UFOName=m_pCurWing->WingName(); pCurve->SetSelected(-1); for (i=0; im_Ctrl.size(); i++) { x = pWPolar->m_EigenValue[iMode][i].real(); y = pWPolar->m_EigenValue[iMode][i].imag()/2./PI; pCurve->AppendPoint(x, y); if(m_pCurWOpp && m_bHighlightOpp) { if(qAbs(pWPolar->m_Ctrl[i]-m_pCurWOpp->m_Ctrl)<0.0001) { if(m_pCurPOpp && m_pCurPlane && (pWPolar->m_UFOName==m_pCurPlane->PlaneName()) && (m_pCurPOpp->m_PlrName==pWPolar->m_PlrName)) { if(iMode==pStabView->m_iCurrentMode) pCurve->SetSelected(i); } else if(m_pCurWOpp && m_pCurWing && (pWPolar->m_UFOName==m_pCurWing->WingName()) && (m_pCurWOpp->m_PlrName ==pWPolar->m_PlrName)) { if(iMode==pStabView->m_iCurrentMode) pCurve->SetSelected(i); } } } } } /** * Fills the polar curve object which has been created with the variable data specified by XVar and YVar. *@param pCurve a pointer to the curve to fill with the data *@param pWPolar a pointer to the instance of the CWPolar object from which the data will be extracted *@param XVar the index of the variable to appear on the x-axis *@param YVar the index of the variable to appear on the y-axis */ void QMiarex::FillWPlrCurve(Curve *pCurve, WPolar *pWPolar, int XVar, int YVar) { bool bAdd; int i; double x,y; QString UFOName; if(m_pCurPlane) UFOName=m_pCurPlane->PlaneName(); else if(m_pCurWing) UFOName=m_pCurWing->WingName(); static QList *pX; static QList *pY; pX = (QList *) pWPolar->GetUFOPlrVariable(XVar); pY = (QList *) pWPolar->GetUFOPlrVariable(YVar); pCurve->SetSelected(-1); for (i=0; im_Alpha.size(); i++) { bAdd = true; x = (*pX)[i]; y = (*pY)[i]; if((XVar==14 || XVar==17 || XVar==18) && x<0) bAdd = false; if((YVar==14 || YVar==17 || YVar==18) && y<0) bAdd = false; //Set user units if(XVar==15 || XVar==16 || XVar==17) x *= MainFrame::s_NtoUnit; //force if(YVar==15 || YVar==16 || YVar==17) y *= MainFrame::s_NtoUnit; //force if(XVar==18 || XVar==19 || XVar==20) x *= MainFrame::s_mstoUnit;//speed if(YVar==18 || YVar==19 || YVar==20) y *= MainFrame::s_mstoUnit;//speed if(XVar==22 || XVar==23 || XVar==24) x *= MainFrame::s_NmtoUnit;//moment if(YVar==22 || YVar==23 || YVar==24) y *= MainFrame::s_NmtoUnit;//moment if(XVar==25 || XVar==26 || XVar==27 ) x *= MainFrame::s_mtoUnit;//force if(YVar==25 || YVar==26 || YVar==27 ) y *= MainFrame::s_mtoUnit;//force if(XVar==28) x *= MainFrame::s_NmtoUnit;//moment if(YVar==28) y *= MainFrame::s_NmtoUnit;//moment if(XVar==34) x *= MainFrame::s_mtoUnit;//length if(YVar==34) y *= MainFrame::s_mtoUnit;//length if(bAdd) { pCurve->AppendPoint(x,y); if(m_pCurWOpp && m_bHighlightOpp) { if(qAbs(pWPolar->m_Alpha[i]-m_pCurWOpp->m_Alpha)<0.0001) { if(m_pCurPOpp && m_pCurPlane && pWPolar->m_UFOName==m_pCurPlane->PlaneName() && m_pCurPOpp->m_PlrName ==pWPolar->m_PlrName) { pCurve->SetSelected(i); } else if(m_pCurWOpp && m_pCurWing && pWPolar->m_UFOName==m_pCurWing->WingName() && m_pCurWOpp->m_PlrName ==pWPolar->m_PlrName) pCurve->SetSelected(i); } } } } } /** * Returns a pointer to the body with the name BodyName *@param BodyName the QString holding the name of the body *@return a pointer to the body with the requested body name, or NULL if none has been found */ Body * QMiarex::GetBody(QString BodyName) { Body* pBody; for (int ib=0; ibsize(); ib++) { pBody = (Body*)m_poaBody->at(ib); if (pBody->m_BodyName == BodyName) return pBody; } Plane *pPlane; for(int ip=0; ipsize(); ip++) { pPlane = (Plane*)m_poaPlane->at(ip); if(pPlane->body()) { if((pPlane->PlaneName()+"/Body") == BodyName) return pPlane->body(); } } return NULL; } /** * Returns a pointer to the OpPoint with the name of the current plane and current WPolar, and which matches the input parameter * @param x the aoa, of velocity, or control parameter for which the CPOpp object is requested * @return a pointer to the instance of the CPOpp object, or NULL if non has been found */ PlaneOpp * QMiarex::GetPOpp(double x) { int i; if(!m_pCurPlane || !m_pCurWPolar) return NULL; PlaneOpp* pPOpp; for (i=0; isize(); i++) { pPOpp = (PlaneOpp*)m_poaPOpp->at(i); if ((pPOpp->m_PlaneName == m_pCurPlane->PlaneName()) && (pPOpp->m_PlrName == m_pCurWPolar->m_PlrName)) { if (m_pCurWPolar->m_WPolarType< FIXEDAOAPOLAR && qAbs(pPOpp->m_Alpha - x)<0.005) return pPOpp; else if(m_pCurWPolar->m_WPolarType==FIXEDAOAPOLAR && qAbs(pPOpp->m_QInf - x)<0.005) return pPOpp; else if(m_pCurWPolar->m_WPolarType==STABILITYPOLAR && qAbs(pPOpp->m_Ctrl - x)<0.005) return pPOpp; } } return NULL; } /** * Returns a pointer to the polar with the name of the input parameter * @param WPolarName the name of the CWPolar object * @return a pointer to the instance of the CWPolar object, or NULL if non has been found */ WPolar* QMiarex::GetWPolar(QString WPolarName) { // // returns a pointer to the WPolar with name WPolarName // or returns NULL if non with that name for the current UFO // WPolar *pWPolar; QString UFOName; int i; if(m_pCurPlane) UFOName = m_pCurPlane->PlaneName(); else if(m_pCurWing) UFOName = m_pCurWing->WingName(); else return NULL; for (i=0; isize(); i++) { pWPolar = (WPolar*) m_poaWPolar->at(i); if (pWPolar->m_UFOName == UFOName && pWPolar->m_PlrName == WPolarName) return pWPolar; } return NULL; } /** * Returns a pointer to the OpPoint with the name of the current wing and current WPolar, and which matches the input parameter * @param x the aoa, of velocity, or control parameter for which the CWOpp object is requested * @return a pointer to the instance of the CWOpp object, or NULL if non has been found */ WingOpp* QMiarex::GetWOpp(double x) { if(!m_pCurWing || !m_pCurWPolar) return NULL; int i; WingOpp* pWOpp; for (i=0; isize(); i++) { pWOpp = (WingOpp*)m_poaWOpp->at(i); if ((pWOpp->m_WingName==m_pCurWing->WingName()) &&(pWOpp->m_PlrName==m_pCurWPolar->m_PlrName)) { if(m_pCurWPolar->m_WPolarTypem_Alpha - x)<0.005) return pWOpp; else if(m_pCurWPolar->m_WPolarType==FIXEDAOAPOLAR && qAbs(pWOpp->m_QInf - x)<0.005) return pWOpp; else if(m_pCurWPolar->m_WPolarType==STABILITYPOLAR && qAbs(pWOpp->m_Ctrl - x)<0.005) return pWOpp; } } return NULL; } /** * Returns a pointer to the graph in which the point pt lies *@param a reference to the QPoint object which holds the mouse input in client coordinates *@param a pointer to the instance of the QGraph which contains the client point */ QGraph* QMiarex::GetGraph(QPoint &pt) { if(m_iView==WOPPVIEW) { if(m_iWingView==1) { if(m_pCurWingGraph->IsInDrawRect(pt)) return m_pCurWingGraph; else return NULL; } else if (m_iWingView==2) { if(m_WingGraph[0].IsInDrawRect(pt)){return m_WingGraph;} if(m_WingGraph[1].IsInDrawRect(pt)){return m_WingGraph+1;} return NULL; } else { for(int ig=0; ig<4; ig++) { if(m_WingGraph[ig].IsInDrawRect(pt)){return m_WingGraph+ig;} } return NULL; } } else if(m_iView==WPOLARVIEW) { if(m_iWPlrView==ONEPOLARGRAPH) { return m_pCurWPlrGraph; } else if (m_iWPlrView==TWOPOLARGRAPHS) { if(m_WPlrGraph[0].IsInDrawRect(pt)){return m_WPlrGraph;} if(m_WPlrGraph[1].IsInDrawRect(pt)){return m_WPlrGraph+1;} return NULL; } else { for(int ig=0; ig<4; ig++) if(m_WPlrGraph[ig].IsInDrawRect(pt)) {return m_WPlrGraph+ig;} } } else if(m_iView==WSTABVIEW) { if(m_iStabilityView==STABTIMEVIEW) { if(m_iStabTimeView==1) { return m_pCurTimeGraph; } else { for(int ig=0; ig<4; ig++) if(m_TimeGraph[ig].IsInDrawRect(pt)) return m_TimeGraph+ig; } return NULL; } else if(m_iStabilityView==STABPOLARVIEW) { if(m_pCurRLStabGraph && m_pCurRLStabGraph->IsInDrawRect(pt)) return m_pCurRLStabGraph; return NULL; } } else if(m_iView==WCPVIEW) { m_pCurGraph = &m_CpGraph; return m_pCurGraph; } return NULL; } /** * Returns a pointer to the plane with the name PlaneName *@param PlaneName a QString object with the name of the requested CPlane object *@return a pointer to the instance of the CPlane object, or NULL if non has been found */ Plane * QMiarex::GetPlane(QString PlaneName) { int i; Plane* pPlane; for (i=0; isize(); i++) { pPlane = (Plane*)m_poaPlane->at(i); if (pPlane->PlaneName() == PlaneName) return pPlane; } return NULL; } /** * Returns a pointer to the wing with the name WingName *@param WingName a QString object with the name of the requested CWing object *@return a pointer to the instance of the CWing object, or NULL if non has been found */ Wing * QMiarex::GetWing(QString WingName) { if(!WingName.length()) return NULL; int i; Wing* pWing; for (i=0; isize(); i++) { pWing = (Wing*)m_poaWing->at(i); if (pWing->m_WingName == WingName) return pWing; } return NULL; } /** * Calls the existing OpenGL lists for display in the 3D view. * The list have been created previously by a call to GLDraw3D */ void QMiarex::GLCallViewLists() { glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); if (m_pCurWPolar && m_pCurWPolar->m_AnalysisMethod==PANELMETHOD && m_pCurWPolar->m_bTiltedGeom && m_bWakePanels) glCallList(WINGWAKEPANELS); if(m_bMoments && m_pCurWOpp) glCallList(VLMMOMENTS); if (m_pCurWOpp && m_bStream && m_pCurWOpp->m_AnalysisMethod>=VLMMETHOD && !m_bResetglStream && glIsList(VLMSTREAMLINES) ) glCallList(VLMSTREAMLINES);//streamlines are not rotated if(m_pCurWOpp && m_bSpeeds && m_pCurWOpp->m_AnalysisMethod>=VLMMETHOD && !m_bResetglFlow) glCallList(SURFACESPEEDS); if (m_pCurWOpp) glRotated(m_pCurWOpp->m_Alpha, 0.0, 1.0, 0.0); if(s_bVLMPanels && m_pCurWing) { if(!(m_b3DCp&&m_pCurWOpp) && !s_bSurfaces) glCallList(MESHBACK); glCallList(MESHPANELS); } if(m_bVortices && m_pCurWing) { glCallList(VLMCTRLPTS); glCallList(VLMVORTICES); } if(m_b3DCp && m_pCurWOpp && m_pCurWOpp->m_AnalysisMethod>=VLMMETHOD) { glCallList(PANELCP); } if(m_bPanelForce && m_pCurWOpp && m_pCurWOpp->m_AnalysisMethod>=VLMMETHOD) { glCallList(PANELFORCEARROWS); } if (m_pCurWPolar && qAbs(m_pCurWPolar->m_Beta)>0.001) glRotated(-m_pCurWPolar->m_Beta, 0.0, 0.0, 1.0); if(m_bXCP && m_pCurWOpp) { for(int iw=0; iwbody()) { glTranslated((m_pCurPlane)->BodyPos().x, 0.0, (m_pCurPlane)->BodyPos().z); glCallList(BODYGEOMBASE+MAXBODIES); glTranslated(-(m_pCurPlane)->BodyPos().x, 0.0, -(m_pCurPlane)->BodyPos().z); } } if(GLLightDlg::IsLightOn()) { glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); } else { glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); } if(s_bSurfaces) { for(int iw=0; iwbody()) { if(m_pCurPlane) glTranslated((m_pCurPlane)->BodyPos().x, 0.0, (m_pCurPlane)->BodyPos().z); glCallList(BODYGEOMBASE); if(m_pCurPlane) glTranslated(-(m_pCurPlane)->BodyPos().x, 0.0, -(m_pCurPlane)->BodyPos().z); } } glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); if((m_bICd || m_bVCd) && m_pCurWOpp ) { for (int iw=0; iwbody(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; glClearColor(MainFrame::s_BackgroundColor.redF(), MainFrame::s_BackgroundColor.greenF(), MainFrame::s_BackgroundColor.blueF(),0.0); if(!glIsList(ARCBALL)) { p3dWidget->CreateArcballList(m_ArcBall, m_GLScale); m_GLList++; } if(!glIsList(GLLISTSPHERE)) { p3dWidget->GLCreateUnitSphere(); m_GLList++; } if(m_bResetglBody && pCurBody) { if(glIsList(BODYGEOMBASE)) { glDeleteLists(BODYGEOMBASE,1); glDeleteLists(BODYGEOMBASE+MAXBODIES,1); m_GLList -=2; } if(pCurBody->m_LineType==BODYPANELTYPE) GLCreateBody3DFlatPanels(BODYGEOMBASE, pCurBody); else if(pCurBody->m_LineType==BODYSPLINETYPE) GLCreateBody3DSplines(BODYGEOMBASE, pCurBody, GL3dBodyDlg::s_NXPoints, GL3dBodyDlg::s_NHoopPoints); m_bResetglBody = false; } if(m_bResetglGeom && (m_iView==W3DVIEW || m_iView==WSTABVIEW)) { Body TranslatedBody; if(pCurBody && m_pCurPlane) { TranslatedBody.Duplicate(pCurBody); TranslatedBody.Translate(m_pCurPlane->BodyPos()); } for(int iw=0; iwm_AnalysisMethod==PANELMETHOD) { // GLCreateMesh(WINGWAKEPANELS, m_WakeSize, m_WakePanel, m_WakeNode, m_WakeColor, pMainFrame->m_BackgroundColor, false); } m_bResetglWake = false; } if(m_bResetglMesh && s_bVLMPanels && (m_iView==W3DVIEW || m_iView==WSTABVIEW)) { if(glIsList(MESHPANELS)) { glDeleteLists(MESHPANELS,2); m_GLList-=2; } GLCreateMesh(MESHPANELS, m_MatSize, m_Panel, m_Node, W3dPrefsDlg::s_VLMColor, MainFrame::s_BackgroundColor); m_GLList+=2; if(glIsList(VLMCTRLPTS)) { glDeleteLists(VLMCTRLPTS,2); m_GLList-=2; } GLCreateCtrlPts(this, m_Panel); GLCreateVortices(this, m_Panel, m_Node, m_pCurWPolar); m_bResetglMesh = false; } if((m_bResetglLift || m_bResetglOpp) && m_iView==W3DVIEW) { if(glIsList(LIFTFORCE)) { glDeleteLists(LIFTFORCE,1); m_GLList -=1; } if(glIsList(VLMMOMENTS)) { glDeleteLists(VLMMOMENTS,1); m_GLList -=1; } for(int iw=0; iwm_AnalysisMethod!=LLTMETHOD) { if(glIsList(PANELFORCEARROWS)) { glDeleteLists(PANELFORCEARROWS,1); m_GLList -=1; } if (m_pCurWing && m_pCurWOpp) { GLCreatePanelForce(this, m_pCurWPolar,m_pCurWOpp, m_pCurPOpp); } m_bResetglPanelForce = false; } if((m_bResetglPanelCp || m_bResetglOpp) && m_iView==W3DVIEW && m_pCurWPolar && m_pCurWPolar->m_AnalysisMethod!=LLTMETHOD) { if(glIsList(PANELCP)) { glDeleteLists(PANELCP,1); m_GLList-=1; } if (m_pCurWing && m_pCurWOpp) { GLCreateCp(this, m_Node, m_Panel, m_pCurWOpp, m_pCurPOpp); } m_bResetglPanelCp = false; } if((m_bResetglLegend || m_bResetglOpp || m_bResetglGeom) && (m_iView==W3DVIEW || m_iView==WSTABVIEW)) { if(glIsList(WOPPCPLEGENDCLR)) { glDeleteLists(WOPPCPLEGENDCLR,1); m_GLList -= 1; } if(m_pCurWOpp) { GLCreateCpLegendClr(this); } m_bResetglLegend = false; } if((m_bResetglStream) && m_iView==W3DVIEW) { if(glIsList(VLMSTREAMLINES)) { glDeleteLists(VLMSTREAMLINES,1); m_GLList -=1; } if(m_bStream) { m_bStream = false; //Disable temporarily during calculation //no need to recalculate if not showing if(m_pCurWing && m_pCurWOpp && m_pCurWOpp->m_AnalysisMethod>=VLMMETHOD) { m_bResetglStream = false; GLCreateStreamLines(this, m_pWingList, m_Node, m_pCurWPolar, m_pCurWOpp); m_bStream = true; } } } if((m_bResetglFlow || m_bResetglOpp) && m_iView==W3DVIEW) { if(glIsList(SURFACESPEEDS)) { glDeleteLists(SURFACESPEEDS,1); m_GLList -=1; } if(m_bSpeeds) { if(m_pCurWing && m_pCurWOpp && m_pCurWOpp->m_AnalysisMethod>=VLMMETHOD) { GLCreateSurfSpeeds(this, m_Panel, m_pCurWPolar, m_pCurWOpp); m_bResetglFlow = false; } } } m_bResetglOpp = false; QApplication::restoreOverrideCursor(); } /** * Draws the point masses, the object masses, and the CG position in the OpenGL viewport */ void QMiarex::GLDrawMasses() { ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; QString MassUnit; GetWeightUnit(MassUnit, MainFrame::s_WeightUnit); glColor3d(W3dPrefsDlg::s_MassColor.redF(), W3dPrefsDlg::s_MassColor.greenF(), W3dPrefsDlg::s_MassColor.blueF()); double zdist = 25.0/(double)m_r3DCltRect.width(); for(int iw=0; iwWingLE(iw).x, m_pCurPlane->WingLE(iw).y, m_pCurPlane->WingLE(iw).z); if(m_pWingList[iw]->m_bIsFin) glTranslated(0.0,0.0, m_pWingList[iw]->m_ProjectedSpan/4.0); else glTranslated(0.0, m_pWingList[iw]->m_ProjectedSpan/4.0,0.0); glColor3d(0.5, 1.0, 0.5); p3dWidget->renderText(0.0, 0.0, zdist, m_pWingList[iw]->m_WingName+ QString(" %1").arg(m_pWingList[iw]->m_VolumeMass*MainFrame::s_kgtoUnit, 7,'g',3)+ MassUnit); } } glPopMatrix(); for(int im=0; imm_PointMass.size(); im++) { glPushMatrix(); { if(m_pCurPlane) { glTranslated(m_pCurPlane->WingLE(iw).x, m_pCurPlane->WingLE(iw).y, m_pCurPlane->WingLE(iw).z); } glTranslated(m_pWingList[iw]->m_PointMass[im]->position().x, m_pWingList[iw]->m_PointMass[im]->position().y, m_pWingList[iw]->m_PointMass[im]->position().z); glColor3d(W3dPrefsDlg::s_MassColor.redF(), W3dPrefsDlg::s_MassColor.greenF(), W3dPrefsDlg::s_MassColor.blueF()); p3dWidget->GLRenderSphere(W3dPrefsDlg::s_MassRadius/m_glScaled); glColor3d(MainFrame::s_TextColor.redF(), MainFrame::s_TextColor.greenF(), MainFrame::s_TextColor.blueF()); p3dWidget->renderText(0.0, 0.0, 0.0 +.02, m_pWingList[iw]->m_PointMass[im]->tag() +QString(" %1").arg(m_pWingList[iw]->m_PointMass[im]->mass()*MainFrame::s_kgtoUnit, 7,'g',3) +MassUnit); } glPopMatrix(); } } } if(m_pCurPlane) { glColor3d(W3dPrefsDlg::s_MassColor.redF(), W3dPrefsDlg::s_MassColor.greenF(), W3dPrefsDlg::s_MassColor.blueF()); for(int im=0; imm_PointMass.size(); im++) { glPushMatrix(); { glTranslated(m_pCurPlane->m_PointMass[im]->position().x, m_pCurPlane->m_PointMass[im]->position().y, m_pCurPlane->m_PointMass[im]->position().z); glColor3d(W3dPrefsDlg::s_MassColor.redF(), W3dPrefsDlg::s_MassColor.greenF(), W3dPrefsDlg::s_MassColor.blueF()); p3dWidget->GLRenderSphere(W3dPrefsDlg::s_MassRadius/m_glScaled); glColor3d(MainFrame::s_TextColor.redF(), MainFrame::s_TextColor.greenF(), MainFrame::s_TextColor.blueF()); p3dWidget->renderText(0.0,0.0,0.0+.02, m_pCurPlane->m_PointMass[im]->tag() +QString(" %1").arg(m_pCurPlane->m_PointMass[im]->mass()*MainFrame::s_kgtoUnit, 7,'g',3) +MassUnit); } glPopMatrix(); } } if(m_pCurPlane && m_pCurPlane->body()) { Body *pCurBody = m_pCurPlane->body(); // glColor3d(W3dPrefsDlg::s_MassColor.redF()*.75, W3dPrefsDlg::s_MassColor.greenF()*.75, W3dPrefsDlg::s_MassColor.blueF()*.75); glColor3d(0.0, 0.0, 0.7); glPushMatrix(); { if(m_pCurPlane) { glTranslated(m_pCurPlane->BodyPos().x, m_pCurPlane->BodyPos().y, m_pCurPlane->BodyPos().z); glColor3d(0.5, 1.0, 0.5); p3dWidget->renderText(0.0, 0.0, zdist, pCurBody->m_BodyName+ QString(" %1").arg(pCurBody->m_VolumeMass*MainFrame::s_kgtoUnit, 7,'g',3)+ MassUnit); } } glPopMatrix(); glColor3d(W3dPrefsDlg::s_MassColor.redF(), W3dPrefsDlg::s_MassColor.greenF(), W3dPrefsDlg::s_MassColor.blueF()); for(int im=0; imm_PointMass.size(); im++) { glPushMatrix(); { glTranslated(pCurBody->m_PointMass[im]->position().x,pCurBody->m_PointMass[im]->position().y,pCurBody->m_PointMass[im]->position().z); if(m_pCurPlane) { glTranslated(m_pCurPlane->BodyPos().x, m_pCurPlane->BodyPos().y, m_pCurPlane->BodyPos().z); } glColor3d(W3dPrefsDlg::s_MassColor.redF(), W3dPrefsDlg::s_MassColor.greenF(), W3dPrefsDlg::s_MassColor.blueF()); p3dWidget->GLRenderSphere(W3dPrefsDlg::s_MassRadius/m_glScaled); glColor3d(MainFrame::s_TextColor.redF(), MainFrame::s_TextColor.greenF(), MainFrame::s_TextColor.blueF()); p3dWidget->renderText(0.0, 0.0, 0.0+.02, pCurBody->m_PointMass[im]->tag() +QString(" %1").arg(pCurBody->m_PointMass[im]->mass()*MainFrame::s_kgtoUnit, 7,'g',3) +MassUnit); } glPopMatrix(); } } //plot CG if(m_pCurPlane || m_pCurWing) { CVector CoG; double Mass=0.0; if(m_pCurPlane) { CoG = m_pCurPlane->CoG(); Mass = m_pCurPlane->TotalMass(); } else if(m_pCurWing) { CoG = m_pCurWing->m_CoG; Mass = m_pCurWing->m_TotalMass; } glPushMatrix(); { glTranslated(CoG.x,CoG.y,CoG.z); glColor3d(1.0, 0.5, 0.5); p3dWidget->GLRenderSphere(W3dPrefsDlg::s_MassRadius*2.0/m_glScaled); glColor3d(MainFrame::s_TextColor.redF(), MainFrame::s_TextColor.greenF(), MainFrame::s_TextColor.blueF()); p3dWidget->renderText(0.0, 0.0, 0.0+.02, "CoG "+QString("%1").arg(Mass*MainFrame::s_kgtoUnit, 7,'g',3) +MassUnit); } glPopMatrix(); } } /** * Prints the foil names on the OpenGl viewport */ void QMiarex::GLDrawFoils() { ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; int j; Foil *pFoil; double zdist = 25.0/(double)m_r3DCltRect.width(); glColor3d(MainFrame::s_TextColor.redF(), MainFrame::s_TextColor.greenF(), MainFrame::s_TextColor.blueF()); for(int iw=0; iwm_NSurfaces; j++) { pFoil = m_pWingList[iw]->m_Surface[j].m_pFoilA; if(pFoil) { glPushMatrix(); { glTranslated(m_pWingList[iw]->m_Surface[j].m_TA.x, m_pWingList[iw]->m_Surface[j].m_TA.y, m_pWingList[iw]->m_Surface[j].m_TA.z); p3dWidget->renderText(0.0, 0.0, zdist, pFoil->m_FoilName, MainFrame::s_TextFont); } glPopMatrix(); } } j = m_pWingList[iw]->m_NSurfaces-1; pFoil = m_pWingList[iw]->m_Surface[j].m_pFoilB; if(pFoil) { glPushMatrix(); { glTranslated(m_pWingList[iw]->m_Surface[j].m_TB.x, m_pWingList[iw]->m_Surface[j].m_TB.y, m_pWingList[iw]->m_Surface[j].m_TB.z); p3dWidget->renderText(0.0, 0.0, zdist, pFoil->m_FoilName, MainFrame::s_TextFont); } glPopMatrix(); } } } } /** * Writes the Wing or the Plane's main properties on the bottom left of the OpenGl viewport. * The attempt to define this as an OpenGL list has lead to issues and has been abandoned. * @param pQMiarex a void pointer to the QMiarex object * @param pWing a pointer to the Wing object, or NULL if the selected object is a Plane * @param pPlane a pointer to the Plane object, or NULL if the selected object is a Wing * @param pWPolar a pointer to the active WPolar, or NULL if none */ void QMiarex::GLDrawWingLegend(Wing *pWing, Plane *pPlane, WPolar *pWPolar) { ThreeDWidget *pGLWidget = (ThreeDWidget*)s_p3dWidget; static int dD, ZPos, LeftPos, total; static double Mass; QString Result, str, strong, str1; QString length, surface; QString UFOName; QFontMetrics fm(MainFrame::s_TextFont); dD = fm.height();//pixels total = 13; if(pWPolar) total +=2; if(pPlane && pPlane->stab()) total ++; ZPos = m_r3DCltRect.bottom()- total * dD ; LeftPos = m_r3DCltRect.left() +15; int a,b,c,d; a=8; b=3; c=7; d=2; //glNewList(WINGLEGEND,GL_COMPILE); { //m_GLList++; glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glColor3d(MainFrame::s_TextColor.redF(),MainFrame::s_TextColor.greenF(),MainFrame::s_TextColor.blueF()); if(pWing) { GetLengthUnit(length,MainFrame::s_LengthUnit); GetAreaUnit(surface,MainFrame::s_AreaUnit); if(pPlane) UFOName = pPlane->PlaneName(); else if(pWing) UFOName = pWing->m_WingName; pGLWidget->renderText(LeftPos, ZPos, UFOName, MainFrame::s_TextFont); ZPos +=dD; str1 = QString(QObject::tr("Wing Span = %1 ")).arg(pWing->m_PlanformSpan*MainFrame::s_mtoUnit, a,'f',b); strong = str1 + length; pGLWidget->renderText(LeftPos, ZPos, QString(strong), MainFrame::s_TextFont); ZPos +=dD; str1 = QString(QObject::tr("XYProj. Span = %1 ")).arg(pWing->m_ProjectedSpan*MainFrame::s_mtoUnit,a,'f',b); str1 += length; pGLWidget->renderText(LeftPos, ZPos, str1, MainFrame::s_TextFont); ZPos +=dD; Result = QString(QObject::tr("Root Chord = %1 ")).arg(pWing->Chord(0)*MainFrame::s_mtoUnit, a,'f',b); pGLWidget->renderText(LeftPos, ZPos, Result+length, MainFrame::s_TextFont); ZPos +=dD; Result = QString(QObject::tr("M.A.C. = %1 ")).arg(pWing->m_MAChord*MainFrame::s_mtoUnit, a,'f',b); pGLWidget->renderText(LeftPos, ZPos, Result+length, MainFrame::s_TextFont); ZPos +=dD; double xcog; if(pWPolar) xcog = pWPolar->m_CoG.x; else if(pPlane) xcog = pPlane->CoG().x; else if(pWing) xcog = pWing->m_CoG.x; Result = QString(QObject::tr("X_CG = %1 ")).arg(xcog*MainFrame::s_mtoUnit, a,'f',b); pGLWidget->renderText(LeftPos, ZPos, Result+length, MainFrame::s_TextFont); ZPos +=dD; double Area = pWing->m_PlanformArea; if(pPlane && pPlane->BiPlane()) Area+=pPlane->wing2()->m_PlanformArea; str1 = QString(QObject::tr("Wing Area = %1 ")).arg(Area * MainFrame::s_m2toUnit, a,'f',b); str1 +=surface; pGLWidget->renderText(LeftPos, ZPos, str1, MainFrame::s_TextFont); ZPos +=dD; str1 = QString(QObject::tr("XYProj. Area = %1 ")).arg(pWing->m_ProjectedArea * MainFrame::s_m2toUnit,a,'f',b); strong = str1+surface; pGLWidget->renderText(LeftPos, ZPos, strong, MainFrame::s_TextFont); ZPos +=dD; if(pWPolar) { if(pWPolar->m_WPolarType!=STABILITYPOLAR) Mass = pWPolar->m_Mass; else { if(pPlane) Mass = pPlane->TotalMass(); else if(pWing) Mass = pWing->TotalMass(); } GetWeightUnit(str, MainFrame::s_WeightUnit); str1 = QString(QObject::tr("Plane Mass = %1 ")).arg(Mass*MainFrame::s_kgtoUnit,c,'f',d); Result = str1 + str; pGLWidget->renderText(LeftPos, ZPos, Result, MainFrame::s_TextFont); ZPos +=dD; GetAreaUnit(strong, MainFrame::s_AreaUnit); str1 = QString(QObject::tr("Wing Load = %1 ")).arg(Mass*MainFrame::s_kgtoUnit/Area/MainFrame::s_m2toUnit, a,'f',b); Result = str1 + str+"/" + strong; pGLWidget->renderText(LeftPos, ZPos, Result, MainFrame::s_TextFont); ZPos +=dD; } if(pPlane && pPlane->stab()) { Result = QString(QObject::tr("Tail Volume = %1")).arg(pPlane->TailVolume(),c,'f',d); pGLWidget->renderText(LeftPos, ZPos, Result, MainFrame::s_TextFont); ZPos +=dD; } Result = QString(QObject::tr("Tip Twist = %1")).arg(pWing->Twist(pWing->NWingSection()-1),c,'f',d); pGLWidget->renderText(LeftPos, ZPos, Result, MainFrame::s_TextFont); ZPos +=dD; Result = QString(QObject::tr("Aspect Ratio = %1")).arg(pWing->m_AR,c,'f',d); pGLWidget->renderText(LeftPos, ZPos, Result, MainFrame::s_TextFont); ZPos +=dD; Result = QString(QObject::tr("Taper Ratio = %1")).arg(pWing->m_TR,c,'f',d); pGLWidget->renderText(LeftPos, ZPos, Result, MainFrame::s_TextFont); ZPos +=dD; Result = QString(QObject::tr("Root-Tip Sweep = %1")).arg(pWing->AverageSweep(),c,'f',d); pGLWidget->renderText(LeftPos, ZPos, Result, MainFrame::s_TextFont); ZPos +=dD; if(pPlane) Result = QString("%1 ").arg(pPlane->VLMPanelTotal()) + QObject::tr("mesh panels"); else if(pWing) { if(!pWPolar || !pWPolar->thinSurfaces()) Result = QString("%1 ").arg(pWing->VLMPanelTotal(false)) + QObject::tr("mesh panels"); else Result = QString("%1 ").arg(pWing->VLMPanelTotal(true)) + QObject::tr("mesh panels"); } else Result.clear(); pGLWidget->renderText(LeftPos, ZPos, Result, MainFrame::s_TextFont); } glEnable(GL_DEPTH_TEST); } //glEndList(); } /** * Writes the operating point's main properties on the bottom right of the OpenGl viewport. * The attempt to define this as an OpenGL list has lead to issues and has been abandoned. * @param pQMiarex a void pointer to the QMiarex object * @param pWing a pointer to the Wing object, or NULL if the selected object is a Plane * @param pWOpp a pointer to the active WingOpp, or NULL if none */ void QMiarex::GLDrawWOppLegend(Wing *pWing, WingOpp *pWOpp) { if(!pWing || !pWOpp) return; ThreeDWidget *pGLWidget = (ThreeDWidget*)s_p3dWidget; int dD, YPos, XPos; QString Result, str; int l; QFontMetrics fm(MainFrame::s_TextFont); dD = fm.height();//pixels YPos = m_r3DCltRect.bottom()- 14 * dD; XPos = m_r3DCltRect.right() - 10 ; if(pWOpp->m_WPolarType==STABILITYPOLAR) YPos -= dD; //glNewList(WOPPLEGEND,GL_COMPILE); { //m_GLList++; glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glColor3d(MainFrame::s_TextColor.redF(),MainFrame::s_TextColor.greenF(),MainFrame::s_TextColor.blueF()); if(pWOpp) { if(pWOpp->m_bOut) { YPos -=dD; Result = QObject::tr("Point is out of the flight envelope"); pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); } GetSpeedUnit(str, MainFrame::s_SpeedUnit); l = str.length(); if (l==2) Result = QString(QObject::tr("V = %1 ")).arg(pWOpp->m_QInf*MainFrame::s_mstoUnit,7,'f',2); else if(l==3) Result = QString(QObject::tr("V = %1 ")).arg(pWOpp->m_QInf*MainFrame::s_mstoUnit,6,'f',1); else if(l==4) Result = QString(QObject::tr("V = %1 ")).arg(pWOpp->m_QInf*MainFrame::s_mstoUnit,5,'f',1); Result += str; YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); Result = QString(QObject::tr("Alpha = %1")).arg(pWOpp->m_Alpha,9,'f',4); Result += QString::fromUtf8("°"); YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); Result = QString(QObject::tr("Sideslip = %1")).arg(pWOpp->m_Beta, 9,'f',4); Result += QString::fromUtf8("°"); YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); Result = QString(QObject::tr("Bank = %1")).arg(pWOpp->m_Phi, 9,'f',4); Result += QString::fromUtf8("°"); YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); Result = QString(QObject::tr("Control pos. = %1 ")).arg(pWOpp->m_Ctrl, 9,'f',4); YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); Result = QString(QObject::tr("CL = %1 ")).arg(pWOpp->m_CL, 9,'f',4); YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); Result = QString(QObject::tr("CD = %1 ")).arg(pWOpp->m_VCD+pWOpp->m_ICD,9,'f',4); YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); double cxielli=pWOpp->m_CL*pWOpp->m_CL/PI/pWing->m_AR; Result = QString(QObject::tr("Efficiency = %1 ")).arg(cxielli/pWOpp->m_ICD,9,'f',4); YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); Result = QString(QObject::tr("CL/CD = %1 ")).arg(pWOpp->m_CL/(pWOpp->m_ICD+pWOpp->m_VCD),9,'f',4); YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); Result = QString(QObject::tr("Cl = %1 ")).arg(pWOpp->m_GRm, 9,'f',4); YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); Result = QString(QObject::tr("Cm = %1 ")).arg(pWOpp->m_GCm,9,'f',4); YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); Result = QString(QObject::tr("Cn = %1 ")).arg(pWOpp->m_GYm, 9,'f',4); YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); GetLengthUnit(str, MainFrame::s_LengthUnit); l = str.length(); int c, d; if(l==1) {c=8, d=3;} else if(l==2) {c=7, d=3;} else {c=6, d=3;} if(pWOpp->m_WPolarType==STABILITYPOLAR) { Result = QString(QObject::tr("X_NP = %1 ")).arg(pWOpp->m_XNP*MainFrame::s_mtoUnit, c,'f',d); Result += str; YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); } Result = QString(QObject::tr("X_CP = %1 ")).arg(pWOpp->m_CP.x*MainFrame::s_mtoUnit, c, 'f', d); Result += str; YPos += dD; pGLWidget->renderText(XPos-fm.width(Result), YPos, Result, MainFrame::s_TextFont); } } //glEndList(); } /** * Inverses by transposition the 3x3 rotation matrix used in the 3D display */ void QMiarex::GLInverseMatrix() { int i,j; for(i=0 ; i<3; i++) { for(j=0; j<3; j++) { MatOut[j][i] = MatIn[i][j]; } } } /** * Renders the OpenGl 3D view */ void QMiarex::GLRenderView() { ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; GLLightDlg *pgllDlg = (GLLightDlg*)m_pglLightDlg; double LightFactor = qMin(1.0, m_glScaled); static GLdouble pts[4]; pts[0]= 0.0; pts[1]=0.0; pts[2]=-1.0; pts[3]= m_ClipPlanePos; //x=m_VerticalSplit glClipPlane(GL_CLIP_PLANE1, pts); if(m_ClipPlanePos>4.9999) glDisable(GL_CLIP_PLANE1); else glEnable(GL_CLIP_PLANE1); // Clear the viewport glFlush(); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); { if(m_ClipPlanePos>4.9999) glDisable(GL_CLIP_PLANE1); else glEnable(GL_CLIP_PLANE1); p3dWidget->GLSetupLight(m_UFOOffset.y, LightFactor); glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); if(m_pCurWOpp && m_pCurWOpp->m_WPolarType==STABILITYPOLAR) { QString strong = QString(tr("Time =")+"%1s").arg(m_ModeTime,6,'f',3); p3dWidget->renderText(15, 15, strong, MainFrame::s_TextFont); } if(pgllDlg->isVisible()) { glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glPushMatrix(); { glTranslated(( pgllDlg->s_XLight+ m_UFOOffset.x)*m_GLScale, ( pgllDlg->s_YLight+ m_UFOOffset.y)*m_GLScale, pgllDlg->s_ZLight*m_GLScale); double radius = (pgllDlg->s_ZLight+2.0)/40.0*m_GLScale; glColor3d(pgllDlg->s_Red, pgllDlg->s_Green, pgllDlg->s_Blue); p3dWidget->GLRenderSphere(radius/m_glScaled); } glPopMatrix(); } glLoadIdentity(); if(m_bCrossPoint && m_bArcball) { glPushMatrix(); { glTranslated(m_UFOOffset.x, m_UFOOffset.y, 0.0); m_ArcBall.RotateCrossPoint(); glRotated(m_ArcBall.angle, m_ArcBall.p.x, m_ArcBall.p.y, m_ArcBall.p.z); glCallList(ARCPOINT); } glPopMatrix(); } if(m_bArcball) { glPushMatrix(); { glTranslated(m_UFOOffset.x, m_UFOOffset.y, 0.0); m_ArcBall.Rotate(); glCallList(ARCBALL); } glPopMatrix(); } glTranslated(m_UFOOffset.x, m_UFOOffset.y, 0.0); m_ArcBall.Rotate(); glScaled(m_glScaled, m_glScaled, m_glScaled); glTranslated(m_glRotCenter.x, m_glRotCenter.y, m_glRotCenter.z); if(s_bAxes) p3dWidget->GLDrawAxes(1.0/m_glScaled, W3dPrefsDlg::s_3DAxisColor, W3dPrefsDlg::s_3DAxisStyle, W3dPrefsDlg::s_3DAxisWidth); if(m_pCurWPolar && m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { glTranslated(m_ModeState[0], m_ModeState[1], m_ModeState[2]); glRotated(m_ModeState[3]*180.0/PI, 1.0, 0.0 ,0.0); glRotated(m_ModeState[4]*180.0/PI, 0.0, 1.0 ,0.0); glRotated(m_ModeState[5]*180.0/PI, 0.0, 0.0 ,1.0); if(qAbs(m_pCurWPolar->m_Beta)>0.001) glRotated(-m_pCurWPolar->m_Beta, 0.0, 0.0, 1.0); } GLCallViewLists(); if(s_bFoilNames) GLDrawFoils(); if(s_bShowMasses) GLDrawMasses(); glLoadIdentity(); glDisable(GL_CLIP_PLANE1); glPushMatrix(); { if(m_pCurWing) GLDrawWingLegend(m_pCurWing, m_pCurPlane, m_pCurWPolar); //glCallList(WINGLEGEND); if(m_pCurWOpp) GLDrawWOppLegend(m_pCurWing, m_pCurWOpp); // glCallList(WOPPLEGEND); } glPopMatrix(); if (m_b3DCp && m_pCurWOpp && m_pCurWOpp->m_AnalysisMethod>=VLMMETHOD) { GLDrawCpLegend(this); glCallList(WOPPCPLEGENDCLR); } else if (m_bPanelForce && m_pCurWOpp && m_pCurWOpp->m_AnalysisMethod>=VLMMETHOD) { GLDrawPanelForceLegend(this, m_pCurWPolar); glCallList(WOPPCPLEGENDCLR); } } glPopMatrix(); glDisable(GL_CLIP_PLANE1); } /** * Following the selection of a wing or a plane, this subroutine creates the panels * associated to all of the surface objects. * * m_Panel is the array of panels in the following order * main wing left side, main wing right side * elevator * fin * body * Each panel gets the index of its symmetric, if any, else this index is set to -1 * * A copy of the panels is saved to the MemPanel and MemNode arrays *@return true if successful, false if the panels could not be properly created ot if no object is active */ bool QMiarex::InitializePanels() { if(!m_pCurWing) return false; int j, k, l, Nel, p, pp, HalfSize, nx, nh; // first check that the total number of panels that will be created does not exceed // the currently allocated memory size for the influence atrix. int PanelArraySize = 0; //Count the wing panels for (j=0; jm_NXPanels * m_pSurface[j]->m_NYPanels ; } if(!m_pCurPlane && (!m_pCurWPolar || !m_pCurWPolar->m_bThinSurfaces)) { PanelArraySize *= 2; for (j=0; jm_bIsTipLeft || m_pSurface[j]->m_bIsTipRight) PanelArraySize += m_pSurface[j]->m_NXPanels;//tip patches } } // add the number of body panels //create the body elements only if there is a body, and the analysis is not of the VLM Type bool bBodyEl = false; if(m_pCurPlane && m_pCurPlane->body()) { Body *pCurBody = m_pCurPlane->body(); if(!m_pCurWPolar) bBodyEl = true;//no risk... else if(m_pCurWPolar->m_AnalysisMethod==PANELMETHOD && !m_pCurWPolar->m_bIgnoreBodyPanels) { bBodyEl = true; if(pCurBody->m_LineType==BODYPANELTYPE) { nx = 0; for(int i=0; iFrameSize()-1; i++) nx+=pCurBody->m_xPanels[i]; nh = 0; for(int i=0; iSideLineCount()-1; i++) nh+=pCurBody->m_hPanels[i]; PanelArraySize += nx*nh*2; } else PanelArraySize += 2 * pCurBody->m_nxPanels * pCurBody->m_nhPanels; } else bBodyEl = false; } if(PanelArraySize>s_MaxMatSize) { QApplication::restoreOverrideCursor(); Trace(QString("Requesting additional memory for %1 panels").arg(PanelArraySize)); // allocate 10% more than needed to avoid repeating the operation if the user requirement increases sightly again. s_MaxMatSize = (int)((double)PanelArraySize *1.1); Release(); int memsize = 0; if(!Allocate(memsize)) { s_MaxMatSize = 0; return false; } QString strange = QString("Total memory allocation for PanelAnalysis is %1 MB\n").arg((double)memsize/1024./1024., 7, 'f', 2); Trace(strange); } // all set to create the panels m_MatSize = 0; m_nNodes = 0; m_NWakeColumn = 0; m_nWakeNodes = 0; m_WakeSize = 0; memset(m_Panel, 0, s_MaxMatSize * sizeof(Panel)); memset(m_Node, 0, 2 * s_MaxMatSize * sizeof(CVector)); Panel *ptr = m_Panel; // dlg.setValue(5); // int NXWakePanels; // if(m_pCurWPolar) NXWakePanels = m_pCurWPolar->m_NXWakePanels; // else NXWakePanels = 1; int coef = 1; if(m_pCurWPolar) { if(m_pCurWPolar->m_bThinSurfaces) coef = 1; else coef = 2; } for(int iw=0; iwm_MatSize = 0; for(j=0; jm_NSurfaces;j++) { m_pWingList[iw]->m_Surface[j].ResetFlap(); Nel = CreateWingElements(m_pWingList[iw]->m_Surface+j); m_pWingList[iw]->m_MatSize += Nel; } m_pWingList[iw]->m_pWingPanel = ptr; ptr += m_pWingList[iw]->m_MatSize; //create symetry properties between panels if((m_pWingList[iw]->m_bIsFin && !m_pWingList[iw]->m_bDoubleFin) || !m_pWingList[iw]->m_bSymetric) { for(p=0; pm_MatSize; p++) m_pWingList[iw]->m_pWingPanel[p].m_iSym=-1; } HalfSize = m_pWingList[iw]->m_MatSize/2; p = HalfSize-1; pp = HalfSize; for(j=0; jm_NSurfaces; j++) { if(m_pWingList[iw]->m_Surface[j].m_bIsRightSurf) { for(k=0; km_Surface[j].m_NYPanels; k++) { for(l=0; lm_Surface[j].m_NXPanels*coef; l++) { m_pWingList[iw]->m_pWingPanel[p].m_iSym = m_pWingList[iw]->m_pWingPanel[pp+m_pWingList[iw]->m_Surface[j].m_NXPanels*coef-l-1].m_iElement; p--; } pp += m_pWingList[iw]->m_Surface[j].m_NXPanels*coef; } if(m_pWingList[iw]->m_Surface[j].m_bIsTipRight && (m_pCurWPolar && !m_pCurWPolar->m_bThinSurfaces)) { for(l=0; lm_Surface[j].m_NXPanels; l++) { m_pWingList[iw]->m_pWingPanel[p].m_iSym = m_pWingList[iw]->m_pWingPanel[pp+m_pWingList[iw]->m_Surface[j].m_NXPanels-l-1].m_iElement; p--; } } } } } } if(bBodyEl) { Nel = CreateBodyElements(); if(m_pCurPlane && m_pCurPlane->body()) m_pCurPlane->body()->m_pBodyPanel = ptr; /* HalfSize = pCurBody->m_NElements/2; p = HalfSize-1; pp = HalfSize; for(k=0; km_nxPanels; k++) { for(l=0; lm_nhPanels; l++) { pCurBody->m_pPanel[p].m_iSym = pCurBody->m_pPanel[pp+pCurBody->m_nhPanels-l-1].m_iElement; p--; } pp += pCurBody->m_nhPanels; }*/ } //back-up the current geometry memcpy(m_MemPanel, m_Panel, m_MatSize* sizeof(Panel)); memcpy(m_MemNode, m_Node, m_nNodes * sizeof(CVector)); memcpy(m_RefWakePanel, m_WakePanel, m_WakeSize* sizeof(Panel)); memcpy(m_RefWakeNode, m_WakeNode, m_nWakeNodes * sizeof(CVector)); // dlg.setValue(100); return true; } /** * Adds a new CWOpp to the existing array * @param pNewPoint a pointer to the instance of the CWOpp object to be inserted in the array */ void QMiarex::InsertWOpp(WingOpp *pNewPoint) { int i; bool bIsInserted = false; WingOpp* pWOpp; // add the WOpPoint to the WOpPoint Array for the current WingName for (i=0; isize(); i++) { pWOpp = (WingOpp*)m_poaWOpp->at(i); if (pNewPoint->m_WingName == pWOpp->m_WingName) { if (pNewPoint->m_PlrName == pWOpp->m_PlrName) { if(pNewPoint->m_WPolarType!=FIXEDAOAPOLAR) { if(qAbs(pNewPoint->m_Alpha - pWOpp->m_Alpha)<0.005) { //replace existing point if (m_pCurWOpp == pWOpp) m_pCurWOpp = NULL; m_poaWOpp->removeAt(i); delete pWOpp; m_poaWOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaWOpp->size();// to break } else if (pNewPoint->m_Alpha > pWOpp->m_Alpha) { //insert point m_poaWOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaWOpp->size();// to break } } else { if(qAbs(pNewPoint->m_QInf - pWOpp->m_QInf)<0.005) { //replace existing point if (m_pCurWOpp == pWOpp) m_pCurWOpp = NULL; m_poaWOpp->removeAt(i); delete pWOpp; m_poaWOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaWOpp->size();// to break } else if (pNewPoint->m_QInf > pWOpp->m_QInf) { //insert point m_poaWOpp->insert(i, pNewPoint); bIsInserted = true; i = m_poaWOpp->size();// to break } } } } } if (!bIsInserted) m_poaWOpp->append(pNewPoint); // return pNewPoint; } /** * Returns the intersection of a ray with the object's panels * The ray is defined by a mouse click and is perpendicular to the viewport *@param A is the ray's origin, *@param U is the ray's direction *@param LA, LB, TA, TB define a quadrangle in 3D space. *@param N is the normal to the quadrangle *@param &I is the resulting intersection point of the ray and the quadrangle, if inside the quadrangle *@param &dist = |AI| *@return true if the intersection is inside the quadrangle, false otherwise */ bool QMiarex::Intersect(CVector const &LA, CVector const &LB, CVector const &TA, CVector const &TB, CVector const &Normal, CVector const &A, CVector const &U, CVector &I, double &dist) { bool b1, b2, b3, b4; double r,s; r = (LA.x-A.x)*Normal.x + (LA.y-A.y)*Normal.y + (LA.z-A.z)*Normal.z ; s = U.x*Normal.x + U.y*Normal.y + U.z*Normal.z; dist = 10000.0; if(qAbs(s)>0.0) { dist = r/s; //inline operations to save time P.x = A.x + U.x * dist; P.y = A.y + U.y * dist; P.z = A.z + U.z * dist; // P is inside the panel if on left side of each panel side W.x = P.x - TA.x; W.y = P.y - TA.y; W.z = P.z - TA.z; V.x = TB.x - TA.x; V.y = TB.y - TA.y; V.z = TB.z - TA.z; T.x = V.y * W.z - V.z * W.y; T.y = -V.x * W.z + V.z * W.x; T.z = V.x * W.y - V.y * W.x; if(T.x*T.x+T.y*T.y+T.z*T.z <1.0e-10 || T.x*Normal.x+T.y*Normal.y+T.z*Normal.z>=0.0) b1 = true; else b1 = false; W.x = P.x - TB.x; W.y = P.y - TB.y; W.z = P.z - TB.z; V.x = LB.x - TB.x; V.y = LB.y - TB.y; V.z = LB.z - TB.z; T.x = V.y * W.z - V.z * W.y; T.y = -V.x * W.z + V.z * W.x; T.z = V.x * W.y - V.y * W.x; if(T.x*T.x+T.y*T.y+T.z*T.z <1.0e-10 || T.x*Normal.x+T.y*Normal.y+T.z*Normal.z>=0.0) b2 = true; else b2 = false; W.x = P.x - LB.x; W.y = P.y - LB.y; W.z = P.z - LB.z; V.x = LA.x - LB.x; V.y = LA.y - LB.y; V.z = LA.z - LB.z; T.x = V.y * W.z - V.z * W.y; T.y = -V.x * W.z + V.z * W.x; T.z = V.x * W.y - V.y * W.x; if(T.x*T.x+T.y*T.y+T.z*T.z <1.0e-10 || T.x*Normal.x+T.y*Normal.y+T.z*Normal.z>=0.0) b3 = true; else b3 = false; W.x = P.x - LA.x; W.y = P.y - LA.y; W.z = P.z - LA.z; V.x = TA.x - LA.x; V.y = TA.y - LA.y; V.z = TA.z - LA.z; T.x = V.y * W.z - V.z * W.y; T.y = -V.x * W.z + V.z * W.x; T.z = V.x * W.y - V.y * W.x; if(T.x*T.x+T.y*T.y+T.z*T.z <1.0e-10 || T.x*Normal.x+T.y*Normal.y+T.z*Normal.z>=0.0) b4 = true; else b4 = false; if(b1 && b2 && b3 && b4) { I.Set(P.x, P.y, P.z); return true; } } return false; } /** * Checks if the input point is close to a wake node within the tolerances set in the CVector class * Returns the index of a node if found, else returns -1 *@param Pt : the point to identify *@return the index of the node with coordinates equal to the input Pt */ int QMiarex::IsWakeNode(CVector &Pt) { // // returns the index of a wake node if found, else returns NULL // int in; for (in=0; in=0; in--) { if(Pt.IsSame(m_Node[in])) return in; } return -1; } /** * At panels on the side of the surfaces, connects the element to the next surface * * In the case where the number of chordwise panels is different between two adjacent surfaces, * We need to correct the ideal connection that was set in the CreateElements() method. * This is the case for instance for a flap. * The algorithm below is artisanal and not robust... ideally the connections should be set manually * * Uses VSAERO method * */ void QMiarex::JoinSurfaces(Surface *pLeftSurf, Surface *pRightSurf, int pl, int pr) { if(!m_pCurWPolar || m_pCurWPolar->m_AnalysisMethod!=PANELMETHOD) return;//panel analysis only //pl and pr are respectively the left surface's and the right surface's first panel index int ls, lr, lclose, ppl, ppr; double dist, x,y,z, mindist; lclose=0; CVector MidNormal = pLeftSurf->Normal + pRightSurf->Normal; MidNormal.Normalize(); int coef = 1; if(m_pCurWPolar && m_pCurWPolar->m_AnalysisMethod==PANELMETHOD && !m_pCurWPolar->m_bThinSurfaces) coef = 2; //left surface's right side ppl = pl; ppr = pr; if(pLeftSurf->m_bIsTipLeft && !m_pCurWPolar->m_bThinSurfaces) ppl+= pLeftSurf->m_NXPanels;//left tip patch ppl += (pLeftSurf->m_NYPanels-1) * coef*pLeftSurf->m_NXPanels; //ppl is now set at left surface's first bottom panel of tip right strip //Process left bottom side first for (ls=0; lsm_NXPanels; ls++) { if(ls>=pLeftSurf->m_NXFlap) //flaps are not connected { mindist = 1.0e100; for (lr=0; lrm_NXPanels; lr++) { //get distance from panel's normal plane as per NASA 4023 VSAERO fig.10 x = m_Panel[ppr+lr].CollPt.x - m_Panel[ppl+ls].CollPt.x; y = m_Panel[ppr+lr].CollPt.y - m_Panel[ppl+ls].CollPt.y; z = m_Panel[ppr+lr].CollPt.z - m_Panel[ppl+ls].CollPt.z; dist = qAbs(x*m_Panel[ppl+ls].l.x + y*m_Panel[ppl+ls].l.y + z*m_Panel[ppl+ls].l.z); if(dist=pRightSurf->m_NXFlap) { m_Panel[ppl+ls].m_iPL = ppr+lclose; } else m_Panel[ppl+ls].m_iPL = -1; } else m_Panel[ppl+ls].m_iPL = -1;//flap is not connected } //Process left top side next for (ls=pLeftSurf->m_NXPanels;lsm_NXPanels; ls++) { if(ls < coef*pLeftSurf->m_NXPanels-pLeftSurf->m_NXFlap) { mindist = 1.0e100; for (lr=pRightSurf->m_NXPanels; lrm_NXPanels; lr++) { //get distance from panel's normal plane as per NASA 4023 VSAERO fig.10 x = m_Panel[ppr+lr].CollPt.x - m_Panel[ppl+ls].CollPt.x; y = m_Panel[ppr+lr].CollPt.y - m_Panel[ppl+ls].CollPt.y; z = m_Panel[ppr+lr].CollPt.z - m_Panel[ppl+ls].CollPt.z; dist = qAbs(x*m_Panel[ppl+ls].l.x + y*m_Panel[ppl+ls].l.y + z*m_Panel[ppl+ls].l.z); if(distm_NXPanels-pRightSurf->m_NXFlap) { m_Panel[ppl+ls].m_iPR = ppr+lclose; } else m_Panel[ppl+ls].m_iPR = -1; } else m_Panel[ppl+ls].m_iPR = -1; } //Move on to right surface's left connections //ppr is set at right surface's first bottom panel of tip left strip ppl = pl; if(pLeftSurf->m_bIsTipLeft && !m_pCurWPolar->m_bThinSurfaces) ppl+= pLeftSurf->m_NXPanels;//left tip patch ppl += (pLeftSurf->m_NYPanels-1) * coef*pLeftSurf->m_NXPanels; //Process right bottom side for (lr=0;lrm_NXPanels; lr++) { if(lr>=pRightSurf->m_NXFlap) { mindist = 1.0e100; for (ls=0; lsm_NXPanels; ls++) { //get distance from panel's normal plane as per NASA 4023 VSAERO fig.10 x = m_Panel[ppl+ls].CollPt.x - m_Panel[ppr+lr].CollPt.x; y = m_Panel[ppl+ls].CollPt.y - m_Panel[ppr+lr].CollPt.y; z = m_Panel[ppl+ls].CollPt.z - m_Panel[ppr+lr].CollPt.z; dist = qAbs(x*m_Panel[ppr+lr].l.x + y*m_Panel[ppr+lr].l.y + z*m_Panel[ppr+lr].l.z); if(dist=pLeftSurf->m_NXFlap) { m_Panel[ppr+lr].m_iPR = ppl+lclose; } else m_Panel[ppr+lr].m_iPR = -1; } else m_Panel[ppr+lr].m_iPR = -1; } //Process right top side for (lr=pRightSurf->m_NXPanels;lrm_NXPanels; lr++) { if(lr < 2*pRightSurf->m_NXPanels-pRightSurf->m_NXFlap) { mindist = 1.0e100; for (ls=pLeftSurf->m_NXPanels; ls<2*pLeftSurf->m_NXPanels; ls++) { //get distance from panel's normal plane as per NASA 4023 VSAERO fig.10 x = m_Panel[ppl+ls].CollPt.x - m_Panel[ppr+lr].CollPt.x; y = m_Panel[ppl+ls].CollPt.y - m_Panel[ppr+lr].CollPt.y; z = m_Panel[ppl+ls].CollPt.z - m_Panel[ppr+lr].CollPt.z; dist = qAbs(x*m_Panel[ppr+lr].l.x + y*m_Panel[ppr+lr].l.y + z*m_Panel[ppr+lr].l.z); if(distm_NXPanels-pLeftSurf->m_NXFlap) { m_Panel[ppr+lr].m_iPL = ppl+lclose; } else m_Panel[ppr+lr].m_iPL = -1; } else m_Panel[ppr+lr].m_iPL = -1; } } /** * Overrides the QWidget's keyPressEvent method. * Dispatches the key press event * @param event the QKeyEvent */ void QMiarex::keyPressEvent(QKeyEvent *event) { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(event->key()==Qt::Key_0 || event->text()=="0") { if(m_iView==WSTABVIEW) { m_iStabilityView = STABTIMEVIEW; // m_pCurGraph = &m_TimeGraph1; // m_pCurTimeGraph= m_pCurGraph; SetWPlrLegendPos(); UpdateView(); } return; } else if(event->key()==Qt::Key_1 || event->text()=="1") { if(m_iView==WPOLARVIEW) { m_iWPlrView = ONEPOLARGRAPH; m_pCurGraph = m_WPlrGraph; m_pCurWPlrGraph = m_pCurGraph; SetWPlrLegendPos(); } else if(m_iView==WOPPVIEW) { m_iWingView =1; m_pCurGraph = m_WingGraph; m_pCurWingGraph = m_pCurGraph; SetWingLegendPos(); } else if(m_iView==WSTABVIEW) { if(m_iStabilityView==STABTIMEVIEW) { m_iStabTimeView =1; m_pCurGraph = m_TimeGraph; m_pCurTimeGraph = m_pCurGraph; SetWingLegendPos(); } } UpdateView(); return; } else if(event->key()==Qt::Key_2 || event->text()=="2") { if(m_iView==WPOLARVIEW) { m_iWPlrView = ONEPOLARGRAPH; m_pCurGraph = m_WPlrGraph+1; m_pCurWPlrGraph = m_pCurGraph; SetWPlrLegendPos(); } else if(m_iView==WOPPVIEW) { m_iWingView =1; m_pCurGraph = m_WingGraph+1; m_pCurWingGraph = m_pCurGraph; SetWingLegendPos(); } else if(m_iView==WSTABVIEW) { if(m_iStabilityView==STABTIMEVIEW) { m_iStabTimeView =1; m_pCurGraph = m_TimeGraph+1; m_pCurTimeGraph = m_pCurGraph; SetWingLegendPos(); } } UpdateView(); return; } else if(event->key()==Qt::Key_3 || event->text()=="3") { if(m_iView==WPOLARVIEW) { m_iWPlrView = ONEPOLARGRAPH; m_pCurGraph = m_WPlrGraph+2; m_pCurWPlrGraph = m_pCurGraph; SetWPlrLegendPos(); } else if(m_iView==WOPPVIEW) { m_iWingView =1; m_pCurGraph = m_WingGraph+2; m_pCurWingGraph = m_pCurGraph; SetWingLegendPos(); } else if(m_iView==WSTABVIEW) { if(m_iStabilityView==STABTIMEVIEW) { m_iStabTimeView =1; m_pCurGraph = m_TimeGraph+2; m_pCurTimeGraph = m_pCurGraph; SetWingLegendPos(); } } UpdateView(); return; } else if(event->key()==Qt::Key_4 || event->text()=="4") { if(m_iView==WPOLARVIEW) { m_iWPlrView = ONEPOLARGRAPH; m_pCurGraph = m_WPlrGraph+3; m_pCurWPlrGraph = m_pCurGraph; SetWPlrLegendPos(); } else if(m_iView==WOPPVIEW) { m_iWingView =1; m_pCurGraph = m_WingGraph+3; m_pCurWingGraph = m_pCurGraph; SetWingLegendPos(); } else if(m_iView==WSTABVIEW) { if(m_iStabilityView==STABTIMEVIEW) { m_iStabTimeView =1; m_pCurGraph = m_TimeGraph+3; m_pCurTimeGraph = m_pCurGraph; SetWingLegendPos(); } } UpdateView(); return; } switch (event->key()) { case Qt::Key_Return: { if (event->modifiers().testFlag(Qt::AltModifier)) { OnWPolarProps(); break; } if(!m_pctrlAnalyze->hasFocus()) { activateWindow(); m_pctrlAnalyze->setFocus(); } else { OnAnalyze(); } event->accept(); break; } case Qt::Key_Escape: { StopAnimate(); if(m_pCurGraph) m_pCurGraph->DeselectPoint(); if(pMainFrame->m_pctrl3DScalesWidget->isVisible()) pMainFrame->m_pctrl3DScalesWidget->hide(); UpdateView(); break; } case Qt::Key_L: { pMainFrame->OnLogFile(); break; } case Qt::Key_T: { if(m_iView==WPOLARVIEW) { m_iWPlrView = TWOPOLARGRAPHS; SetWPlrLegendPos(); } else if(m_iView==WOPPVIEW) { m_iWingView =2; SetWingLegendPos(); } else if(m_iView==WSTABVIEW) { m_iStabTimeView =2; SetWingLegendPos(); } SetControls(); UpdateView(); break; } case Qt::Key_A: { if(m_iView==WPOLARVIEW) { m_iWPlrView = ALLPOLARGRAPHS; SetWPlrLegendPos(); } else if(m_iView==WOPPVIEW) { m_iWingView =4; SetWingLegendPos(); } else if(m_iView==WSTABVIEW) { if(m_iStabilityView==STABTIMEVIEW) { m_iStabTimeView = 4; SetWingLegendPos(); } } UpdateView(); break; } case Qt::Key_V: { if (event->modifiers().testFlag(Qt::ControlModifier) & event->modifiers().testFlag(Qt::ShiftModifier)) { m_bVortices = !m_bVortices; if(m_bVortices) m_bResetglMesh = true; UpdateView(); break; } else if(m_pCurGraph) { GraphDlg::s_ActivePage=0; OnGraphSettings(); } break; } case Qt::Key_X: m_bXPressed = true; break; case Qt::Key_Y: m_bYPressed = true; break; case Qt::Key_G: { if(m_pCurGraph) { OnGraphSettings(); } break; } case Qt::Key_H: { if((m_iView==WPOLARVIEW ||(m_iView==WSTABVIEW&&m_iStabilityView==STABPOLARVIEW)) && event->modifiers().testFlag(Qt::ControlModifier)) { OnHighlightWOpp(); } break; } case Qt::Key_R: { if(m_pCurGraph) { m_pCurGraph->SetAuto(true); UpdateView(); } else if(m_iView==WOPPVIEW) OnResetWingScale(); else if(m_iView==WPOLARVIEW) OnResetWPlrLegend(); else if(m_iView==WSTABVIEW) OnResetWPlrLegend(); else if(m_iView==W3DVIEW) On3DReset(); break; } case Qt::Key_F12: { OnUFOInertia(); break; } case Qt::Key_F2: { OnRenameCurUFO(); break; } case Qt::Key_F3: { if (event->modifiers().testFlag(Qt::ShiftModifier)) OnEditUFO(); else if (event->modifiers().testFlag(Qt::ControlModifier)) OnNewPlane(); else OnNewWing(); break; } case Qt::Key_F4: { On3DView(); break; } case Qt::Key_F5: { OnWOpps(); break; } case Qt::Key_F6: { if (event->modifiers().testFlag(Qt::ShiftModifier)) OnDefineStabPolar(); else if (event->modifiers().testFlag(Qt::ControlModifier)) OnEditCurWPolar(); else OnDefineWPolar(); break; } case Qt::Key_F8: { if (event->modifiers().testFlag(Qt::ShiftModifier)) OnRootLocusView(); else if (event->modifiers().testFlag(Qt::ControlModifier)) OnTimeView(); else OnWPolars(); break; } case Qt::Key_F9: { OnCpView(); break; } case Qt::Key_Control: { m_bArcball = true; UpdateView(); break; } default: // QWidget::keyPressEvent(event); event->ignore(); } } /** * Dispatches the key release event * @param event the QKeyEvent sent by Qt */ void QMiarex::keyReleaseEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Control: { m_bArcball = false; UpdateView(); break; } case Qt::Key_X: if(!event->isAutoRepeat()) m_bXPressed = false; break; case Qt::Key_Y: if(!event->isAutoRepeat()) m_bYPressed = false; break; default: event->ignore(); } } /** * Launches the LLT analysis and updates the display after the analysis *@param V0 : the start angle *@param VMax : the maximal angle *@param VDelta : the increment angle *@param bSequence : if true, the analysis will be run for the whole range between V0 and VMax; * if not, the analysis will be run for V0 only *@param bInitCalc : if true, the starting point for convergence iterations will be reset to the default * if not, the iterations will start at the last calculated point * */ void QMiarex::LLTAnalyze(double V0, double VMax, double VDelta, bool bSequence, bool bInitCalc) { if(!m_pCurWing || !m_pCurWPolar) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; m_pLLTDlg->m_bInitCalc = bInitCalc; m_pLLTDlg->m_pWing = m_pCurWing; m_pLLTDlg->m_pWPolar = m_pCurWPolar; m_pLLTDlg->m_bSequence = bSequence; m_pLLTDlg->m_AlphaMin = V0; m_pLLTDlg->m_AlphaMax = VMax; m_pLLTDlg->m_AlphaDelta = VDelta; m_pLLTDlg->m_IterLim = m_Iter; m_pLLTDlg->InitDialog(); m_pLLTDlg->show(); m_pLLTDlg->StartAnalysis(); if(!m_bLogFile || !(m_pLLTDlg->m_bError || m_pLLTDlg->m_bWarning)) m_pLLTDlg->hide(); pMainFrame->UpdateWOpps(); SetWingOpp(false, V0); } /** * Loads the user's saved settings from the configuration file and maps the data. *@param a pointer to the QSettings object loaded in the MainFrame class *@return true if the settings have been loaded successfully */ bool QMiarex::LoadSettings(QSettings *pSettings) { int r,g,b; QString strong; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; pSettings->beginGroup("Miarex"); { m_bXTop = pSettings->value("bXTop", false).toBool(); m_bXBot = pSettings->value("bXBot", false).toBool(); m_bXCP = pSettings->value("bXCP", false).toBool(); m_bPanelForce = pSettings->value("bPanelForce", false).toBool(); m_bXCmRef = pSettings->value("bXCmRef").toBool(); m_bICd = pSettings->value("bICd", true).toBool(); m_bVCd = pSettings->value("bVCd", true).toBool(); m_bWakePanels = pSettings->value("bWakePanels").toBool(); s_bSurfaces = pSettings->value("bSurfaces").toBool(); s_bOutline = pSettings->value("bOutline").toBool(); s_bVLMPanels = pSettings->value("bVLMPanels").toBool(); s_bAxes = pSettings->value("bAxes").toBool(); m_b3DCp = pSettings->value("b3DCp").toBool(); m_bDownwash = pSettings->value("bDownwash").toBool(); m_bMoments = pSettings->value("bMoments").toBool(); s_bAutoCpScale = pSettings->value("bAutoCpScale").toBool(); m_bShowCpScale = pSettings->value("bShowCpScale").toBool(); m_bCurWOppOnly = pSettings->value("CurWOppOnly").toBool(); m_bShowElliptic = pSettings->value("bShowElliptic").toBool(); m_bLogFile = pSettings->value("LogFile").toBool(); m_bDirichlet = pSettings->value("Dirichlet").toBool(); m_bVLM1 = pSettings->value("bVLM1").toBool(); m_bTrefftz = pSettings->value("Trefftz").toBool(); m_bKeepOutOpps = pSettings->value("KeepOutOpps").toBool(); m_bResetWake = pSettings->value("ResetWake").toBool(); m_bShowWingCurve[0] = pSettings->value("ShowWing").toBool(); m_bShowWingCurve[1] = pSettings->value("ShowWing2").toBool(); m_bShowWingCurve[2] = pSettings->value("ShowStab").toBool(); m_bShowWingCurve[3] = pSettings->value("ShowFin").toBool(); m_bShowWingCurve[0] = true; m_bStoreWOpp = pSettings->value("StoreWOpp").toBool(); m_bSequence = pSettings->value("Sequence").toBool(); m_bHighlightOpp = pSettings->value("HighlightOpp").toBool(); // m_bHighlightOpp = false; m_AlphaMin = pSettings->value("AlphaMin").toDouble(); m_AlphaMax = pSettings->value("AlphaMax").toDouble(); m_AlphaDelta = pSettings->value("AlphaDelta").toDouble(); m_QInfMin = pSettings->value("QInfMin").toDouble(); m_QInfMax = pSettings->value("QInfMax").toDouble(); m_QInfDelta = pSettings->value("QInfDelta").toDouble(); m_ControlMin = pSettings->value("ControlMin").toDouble(); m_ControlMax = pSettings->value("ControlMax").toDouble(); m_ControlDelta = pSettings->value("ControlDelta").toDouble(); WPolarDlg::s_WPolar.m_bAutoInertia = pSettings->value("bAutoInertia", false).toBool(); m_CpStyle = pSettings->value("CpStyle").toInt(); m_CpWidth = pSettings->value("CpWidth").toInt(); r = pSettings->value("CpColorRed").toInt(); g = pSettings->value("CpColorGreen").toInt(); b = pSettings->value("CpColorBlue").toInt(); m_CpColor = QColor(r,g,b); W3dPrefsDlg::s_MassColor = pSettings->value("MassColor", QColor(100, 100, 200)).value(); LLTAnalysis::s_CvPrec = pSettings->value("CvPrec").toDouble(); LLTAnalysis::s_RelaxMax = pSettings->value("RelaxMax").toDouble(); LLTAnalysis::s_NLLTStations = pSettings->value("NLLTStations").toInt(); int k = pSettings->value("iView").toInt(); if(k==0) m_iView = WOPPVIEW; else if(k==1) m_iView = WPOLARVIEW; else if(k==2) m_iView = W3DVIEW; else if(k==3) m_iView = WCPVIEW; else if(k==4) m_iView = WSTABVIEW; m_iWingView = pSettings->value("iWingView").toInt(); k = pSettings->value("iWPlrView").toInt(); if(k==0) m_iWPlrView = ALLPOLARGRAPHS; else if(k==1) m_iWPlrView = ONEPOLARGRAPH; else if(k==2) m_iWPlrView = TWOPOLARGRAPHS; k = pSettings->value("iWStabView").toInt(); if(k==0) m_iStabilityView = STABTIMEVIEW; else if(k==1) m_iStabilityView = STABPOLARVIEW; else if(k==2) m_iStabilityView = STAB3DVIEW; k = pSettings->value("CurrentWingGraph").toInt(); m_pCurWingGraph = m_WingGraph+k-1; k = pSettings->value("CurWPlrGraph").toInt(); m_pCurWPlrGraph = m_WPlrGraph+k-1; k = pSettings->value("CurRLStabGraph").toInt(); if (k==1) m_pCurRLStabGraph = &m_LongRLGraph; else if(k==2) m_pCurRLStabGraph = &m_LatRLGraph; if(m_iView==WOPPVIEW) m_pCurGraph=m_pCurWingGraph; else if(m_iView==WPOLARVIEW) m_pCurGraph=m_pCurWPlrGraph; else if(m_iView==WSTABVIEW) m_pCurGraph=m_pCurRLStabGraph; m_Iter = pSettings->value("Iter").toInt(); m_NStation = pSettings->value("NStation").toInt(); GL3dBodyDlg::s_NHoopPoints = pSettings->value("NHoopPoints").toInt(); GL3dBodyDlg::s_NXPoints = pSettings->value("NXPoints").toInt(); m_InducedDragPoint = pSettings->value("InducedDragPoint").toInt(); m_LiftScale = pSettings->value("LiftScale").toDouble(); m_DragScale = pSettings->value("DragScale").toDouble(); m_VelocityScale = pSettings->value("VelocityScale").toDouble(); m_WakeInterNodes = pSettings->value("WakeInterNodes").toInt(); m_MaxWakeIter = pSettings->value("MaxWakeIter").toInt(); Panel::s_CtrlPos = pSettings->value("CtrlPos").toDouble(); Panel::s_VortexPos = pSettings->value("VortexPos").toDouble(); s_CoreSize = pSettings->value("CoreSize").toDouble(); s_MinPanelSize = pSettings->value("MinPanelSize").toDouble(); m_RampTime = pSettings->value("RampTime", 0.1).toDouble(); m_RampAmplitude = pSettings->value("RampAmplitude", 1.0).toDouble(); m_TotalTime = pSettings->value("TotalTime",10.0).toDouble(); m_Deltat = pSettings->value("Delta_t",0.01).toDouble(); m_TimeInput[0] = pSettings->value("TimeIn0",0.0).toDouble(); m_TimeInput[1] = pSettings->value("TimeIn1",0.0).toDouble(); m_TimeInput[2] = pSettings->value("TimeIn2",0.0).toDouble(); m_TimeInput[3] = pSettings->value("TimeIn3",0.0).toDouble(); // m_bForcedResponse = pSettings->value("ForcedResponse").toBool(); m_bLongitudinal = pSettings->value("DynamicsMode").toBool(); m_iStabTimeView = pSettings->value("StabTimeView",4).toInt(); m_StabilityResponseType = pSettings->value("StabCurveType",0).toInt(); k = pSettings->value("TimeGraph").toInt(); m_pCurTimeGraph = m_TimeGraph+k-1; // StabPolarDlg::s_StabPolar.m_bAVLControls = pSettings->value("AVLControls", true).toBool(); for(int i=0; i<20; i++) { strong = QString("ForcedTime%1").arg(i); pStabView->m_Time[i] = pSettings->value(strong, (double)i).toDouble(); } for(int i=0; i<20; i++) { strong = QString("ForcedAmplitude%1").arg(i); pStabView->m_Amplitude[i] = pSettings->value(strong, 0.0).toDouble(); } pStabView->UpdateControlModelData(); StabPolarDlg::s_StabPolar.m_bAutoInertia = pSettings->value("StabPolarAutoInertia", true).toBool(); StabPolarDlg::s_StabPolar.m_Mass = pSettings->value("StabPolarMass", 0.0).toDouble(); StabPolarDlg::s_StabPolar.m_CoG.x = pSettings->value("StabPolarCoGx", 0.0).toDouble(); StabPolarDlg::s_StabPolar.m_CoG.y = pSettings->value("StabPolarCoGy", 0.0).toDouble(); StabPolarDlg::s_StabPolar.m_CoG.z = pSettings->value("StabPolarCoGz", 0.0).toDouble(); StabPolarDlg::s_StabPolar.m_CoGIxx = pSettings->value("StabPolarCoGIxx", 0.0).toDouble(); StabPolarDlg::s_StabPolar.m_CoGIyy = pSettings->value("StabPolarCoGIyy", 0.0).toDouble(); StabPolarDlg::s_StabPolar.m_CoGIzz = pSettings->value("StabPolarCoGIzz", 0.0).toDouble(); StabPolarDlg::s_StabPolar.m_CoGIxz = pSettings->value("StabPolarCoGIxz", 0.0).toDouble(); } pSettings->endGroup(); GL3dBodyDlg::LoadSettings(pSettings); GLLightDlg::LoadSettings(pSettings); m_CpGraph.LoadSettings(pSettings); for(int ig=0; igpos(); ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; CVector Real; p3dWidget->ClientToGL(point, Real); if(m_r3DCltRect.contains(point)) p3dWidget->setFocus(); Set3DRotationCenter(point); m_bPickCenter = false; m_pctrlPickCenter->setChecked(false); UpdateView(); } else if(m_pCurGraph) { Curve *pCloseCurve = NULL; int n=-1; pCloseCurve = m_pCurGraph->GetCurvePoint(event->pos().x(),event->pos().y(), n); if(pCloseCurve) { QString CurveName; pCloseCurve->title(CurveName); if(m_iView==WPOLARVIEW) { } else if(m_iView==WSTABVIEW && m_iStabilityView==STABPOLARVIEW) { if(m_pCurWPolar) { if(m_pCurWPolar->m_PlrName==CurveName.left(CurveName.length()-7)) { //then we select and highlight the mode int iMode = CurveName.right(1).toInt(); MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; pStabView->SetMode(iMode-1); } } } } else OnGraphSettings(); } } /** * Dispatches the mouse move event * @param event a point to the QMouseEvent sent by Qt */ void QMiarex::mouseMoveEvent(QMouseEvent *event) { if(!hasFocus()) setFocus(); static CVector Real; static bool bCtrl; static QPoint Delta, point; static double xu, yu, x1, y1, xmin, xmax, ymin, ymax; ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; Delta.setX(event->pos().x() - m_LastPoint.x()); Delta.setY(event->pos().y() - m_LastPoint.y()); point = event->pos(); m_pCurGraph = GetGraph(point); bCtrl = false; if(event->modifiers() & Qt::ControlModifier) bCtrl =true; if(m_iView==W3DVIEW || (m_iView==WSTABVIEW && m_iStabilityView==STAB3DVIEW)) { p3dWidget->ClientToGL(point, Real); if (event->buttons() & Qt::LeftButton) { if(bCtrl)//rotate { SetViewControls(); m_ArcBall.Move(point.x(), m_r3DCltRect.height()-point.y()); UpdateView(); } else if(m_bTrans) { //translate m_glViewportTrans.x += (GLfloat)(Delta.x()*2.0*m_GLScale/m_glScaled/m_r3DCltRect.width()); m_glViewportTrans.y += (GLfloat)(Delta.y()*2.0*m_GLScale/m_glScaled/m_r3DCltRect.width()); m_glRotCenter.x = MatOut[0][0]*m_glViewportTrans.x + MatOut[0][1]*(-m_glViewportTrans.y) + MatOut[0][2]*m_glViewportTrans.z; m_glRotCenter.y = MatOut[1][0]*m_glViewportTrans.x + MatOut[1][1]*(-m_glViewportTrans.y) + MatOut[1][2]*m_glViewportTrans.z; m_glRotCenter.z = MatOut[2][0]*m_glViewportTrans.x + MatOut[2][1]*(-m_glViewportTrans.y) + MatOut[2][2]*m_glViewportTrans.z; UpdateView(); } } else if ((event->buttons() & Qt::MidButton) && !bCtrl) { SetViewControls(); m_ArcBall.Move(point.x(), m_r3DCltRect.height()-point.y()); UpdateView(); } } else { if ((event->buttons() & Qt::LeftButton) && m_bTrans && (m_iView==WOPPVIEW || m_iView==WPOLARVIEW || m_iView==WCPVIEW || m_iView==WSTABVIEW)) { if(m_pCurGraph && m_bTransGraph) { // we translate the curves inside the graph m_pCurGraph->SetAuto(false); x1 = m_pCurGraph->ClientTox(m_LastPoint.x()) ; y1 = m_pCurGraph->ClientToy(m_LastPoint.y()) ; xu = m_pCurGraph->ClientTox(point.x()); yu = m_pCurGraph->ClientToy(point.y()); xmin = m_pCurGraph->GetXMin() - xu+x1; xmax = m_pCurGraph->GetXMax() - xu+x1; ymin = m_pCurGraph->GetYMin() - yu+y1; ymax = m_pCurGraph->GetYMax() - yu+y1; m_pCurGraph->SetWindow(xmin, xmax, ymin, ymax); UpdateView(); } else if (m_pCurWing && ((m_iView==WOPPVIEW && m_iWingView ==1))) { // we translate the UFO m_ptOffset.rx() += Delta.x(); m_ptOffset.ry() += Delta.y(); UpdateView(); } else if (m_pCurWing && m_iView==WOPPVIEW && m_iWingView !=1) { // we translate the legend //horizontally only m_WingLegendOffset.rx() += Delta.x(); m_WingLegendOffset.ry() += Delta.y(); UpdateView(); } else if (m_iView==WPOLARVIEW) { // we translate the legend if(m_iWPlrView==ONEPOLARGRAPH || m_iWPlrView==ALLPOLARGRAPHS) { m_WPlrLegendOffset.rx() += Delta.x(); m_WPlrLegendOffset.ry() += Delta.y(); UpdateView(); } else if(m_iWPlrView==TWOPOLARGRAPHS) { m_WPlrLegendOffset.rx() += Delta.x(); m_WPlrLegendOffset.ry() += Delta.y(); UpdateView(); } } else if (m_iView==WSTABVIEW) { // we translate the legend if(m_iStabilityView==STABTIMEVIEW) { m_WingLegendOffset.rx() += Delta.x(); m_WingLegendOffset.ry() += Delta.y(); UpdateView(); } else if(m_iStabilityView==STABPOLARVIEW) { m_WPlrLegendOffset.rx() += Delta.x(); m_WPlrLegendOffset.ry() += Delta.y(); UpdateView(); } } } else if ((event->buttons() & Qt::MidButton) && !bCtrl) //scaling { // we zoom the graph or the wing if(m_iView ==WOPPVIEW ||m_iView==WPOLARVIEW || m_iView==WCPVIEW || m_iView==WSTABVIEW) { if(m_pCurGraph && m_pCurGraph->IsInDrawRect(point)) { //zoom graph m_pCurGraph->SetAuto(false); if(point.y()-m_LastPoint.y()<0) m_pCurGraph->Scale(1.02); else m_pCurGraph->Scale(1.0/1.02); UpdateView(); } else if(m_pCurWing && m_iView==WOPPVIEW) { //zoom wing if(point.y()-m_LastPoint.y()<0) m_WingScale /= 1.02; else m_WingScale *= 1.02; UpdateView(); } } } else if(m_pCurGraph && m_pCurGraph->IsInDrawRect(point)) { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->statusBar()->showMessage(QString("X =%1, Y = %2").arg(m_pCurGraph->ClientTox(event->x())).arg(m_pCurGraph->ClientToy(event->y()))); } } m_LastPoint = point; } /** * Dispatches the mouse press event * @param event a point to the QMouseEvent sent by Qt */ void QMiarex::mousePressEvent(QMouseEvent *event) { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; static complex eigenvalue; static int i,j,k, isel, jsel,xval, yval; static double diff, dmax; QString str,suffix; if (event->buttons() & Qt::MidButton) { m_bArcball = true; m_ArcBall.Start(event->pos().x(), m_r3DCltRect.height()-event->pos().y()); m_bCrossPoint = true; Set3DRotationCenter(); UpdateView(); } else if (event->buttons() & Qt::RightButton) { QPoint point = event->pos(); m_pCurGraph = GetGraph(point); } else if (event->buttons() & Qt::LeftButton) { QPoint point = event->pos(); if(m_iView==W3DVIEW || (m_iView==WSTABVIEW && m_iStabilityView==STAB3DVIEW)) { // point is in client coordinates CVector Real; bool bCtrl = false; if(event->modifiers() & Qt::ControlModifier) { m_bArcball = true; bCtrl =true; } p3dWidget->ClientToGL(point, Real); if(m_r3DCltRect.contains(point)) p3dWidget->setFocus(); if(m_bPickCenter) { Set3DRotationCenter(point); m_bPickCenter = false; m_pctrlPickCenter->setChecked(false); } else { m_ArcBall.Start(point.x(), m_r3DCltRect.height()-point.y()); m_bCrossPoint = true; Set3DRotationCenter(); if (!bCtrl) { m_bTrans = true; p3dWidget->setCursor(Qt::ClosedHandCursor); } } UpdateView(); m_bPickCenter = false; } else { TwoDWidget *p2dWidget = (TwoDWidget*)s_p2dWidget; m_pCurGraph = GetGraph(point); if(m_r2DCltRect.contains(point)) p2dWidget->setFocus(); if(m_pCurGraph && m_iView==WSTABVIEW && (m_iStabilityView==STABPOLARVIEW) && m_pCurWPolar && m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { //first we try to see if the user intended to select a mode; //if not, then we initiate the graph translation isel = jsel = -1; dmax = 1.0e40; eigenvalue = complex(m_pCurGraph->ClientTox(event->x()), m_pCurGraph->ClientToy(event->y())); for(i=0; i<4; i++) { if(m_bLongitudinal) { for(j=0; jm_Alpha.size(); j++) { diff = abs(eigenvalue-m_pCurWPolar->m_EigenValue[i][j])/abs(eigenvalue); if(diffxToClient(m_pCurWPolar->m_EigenValue[i][j].real()); yval = m_pCurGraph->yToClient(m_pCurWPolar->m_EigenValue[i][j].imag()); } } } else { for(j=0; jm_Alpha.size(); j++) { diff = abs(eigenvalue-m_pCurWPolar->m_EigenValue[i+4][j])/abs(eigenvalue); if(diffxToClient(m_pCurWPolar->m_EigenValue[i+4][j].real()); yval = m_pCurGraph->yToClient(m_pCurWPolar->m_EigenValue[i+4][j].imag()); } } } } //is this mode close enough ? let's say less than 10 pixels away ? if((xval-event->x())+(xval-event->x()) + (yval-event->y())*(yval-event->y())<20.0) { //select the mode pStabView->SetMode(isel); //highlight the point suffix = QString("_Mode_%1").arg(isel+1); m_pCurRLStabGraph->DeselectPoint(); for(k=0;kGetCurveCount(); k++) { m_pCurRLStabGraph->GetCurve(k)->title(str); if(str==m_pCurWPolar->m_PlrName+suffix) { m_pCurRLStabGraph->GetCurve(k)->SetSelected(jsel); break; } } } } if (m_pCurWing || (m_pCurGraph && m_pCurGraph->IsInDrawRect(point))) { m_LastPoint.rx() = point.x(); m_LastPoint.ry() = point.y(); m_bTrans = true; m_bTransGraph = true; if(m_pCurGraph && m_pCurGraph->IsInDrawRect(point)) m_bTransGraph = true; else m_bTransGraph = false; if(m_bTrans || m_bTransGraph) p2dWidget->setCursor(Qt::ClosedHandCursor); } } m_PointDown = point; m_LastPoint = point; } } /** * Dispatches the mouse release event * @param event a point to the QMouseEvent sent by Qt */ void QMiarex::mouseReleaseEvent(QMouseEvent *event) { if(m_iView==W3DVIEW || (m_iView==WSTABVIEW && m_iStabilityView==STAB3DVIEW)) { QGLWidget* p3dWidget = (QGLWidget*)s_p3dWidget; p3dWidget->setCursor(Qt::CrossCursor); m_bArcball = false; m_bCrossPoint = false; UpdateView(); // We need to re-calculate the translation vector int i,j; for(i=0; i<4; i++) for(j=0; j<4; j++) MatIn[i][j] = m_ArcBall.ab_quat[i*4+j]; GLInverseMatrix(); m_glViewportTrans.x = (MatOut[0][0]*m_glRotCenter.x + MatOut[0][1]*m_glRotCenter.y + MatOut[0][2]*m_glRotCenter.z); m_glViewportTrans.y = -(MatOut[1][0]*m_glRotCenter.x + MatOut[1][1]*m_glRotCenter.y + MatOut[1][2]*m_glRotCenter.z); m_glViewportTrans.z = (MatOut[2][0]*m_glRotCenter.x + MatOut[2][1]*m_glRotCenter.y + MatOut[2][2]*m_glRotCenter.z); } else { TwoDWidget *p2dWidget = (TwoDWidget*)s_p2dWidget; p2dWidget->setCursor(Qt::CrossCursor); } m_bTrans = false; } /** * Updates the display after the user has requested a switch to the OpenGL 3D view */ void QMiarex::On3DView() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; m_bArcball = false; m_iStabilityView = STAB3DVIEW; if(m_iView==W3DVIEW) { SetControls(); UpdateView(); if(m_pCurWPolar && m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { pMainFrame->m_pctrlStabViewWidget->show(); } return; } m_bIs3DScaleSet = false; m_iView =W3DVIEW; SetControls(); pMainFrame->SetCentralWidget(); if(m_pCurWPolar && m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { pMainFrame->m_pctrlStabViewWidget->show(); } UpdateView(); return; } /** * Updates the display after the user has toggled the switch for the display of Cp coefficients */ void QMiarex::On3DCp() { m_b3DCp = m_pctrlCp->isChecked(); if(m_b3DCp) { s_bSurfaces = false; m_pctrlSurfaces->setChecked(false); m_bPanelForce = false; m_pctrlPanelForce->setChecked(false); } UpdateView(); } /** * Updates the display after the user has requested a perspective view in the 3D display */ void QMiarex::On3DIso() { SetViewControls(); m_pctrlIso->setChecked(true); m_ArcBall.ab_quat[0] = -0.65987748f; m_ArcBall.ab_quat[1] = 0.38526487f; m_ArcBall.ab_quat[2] = -0.64508355f; m_ArcBall.ab_quat[3] = 0.0f; m_ArcBall.ab_quat[4] = -0.75137258f; m_ArcBall.ab_quat[5] = -0.33720365f; m_ArcBall.ab_quat[6] = 0.56721509f; m_ArcBall.ab_quat[7] = 0.0f; m_ArcBall.ab_quat[8] = 0.000f; m_ArcBall.ab_quat[9] = 0.85899049f; m_ArcBall.ab_quat[10] = 0.51199043f; m_ArcBall.ab_quat[11] = 0.0f; m_ArcBall.ab_quat[12] = 0.0f; m_ArcBall.ab_quat[13] = 0.0f; m_ArcBall.ab_quat[14] = 0.0f; m_ArcBall.ab_quat[15] = 1.0f; Set3DRotationCenter(); UpdateView(); } /** * Updates the display after the user has requested a top view in the 3D display */ void QMiarex::On3DTop() { SetViewControls(); m_pctrlZ->setChecked(true); m_ArcBall.SetQuat(sqrt(2.0)/2.0, 0.0, 0.0, -sqrt(2.0)/2.0); Set3DRotationCenter(); UpdateView(); } /** * Updates the display after the user has requested a left view in the 3D display */ void QMiarex::On3DLeft() { SetViewControls(); m_pctrlY->setChecked(true); m_ArcBall.SetQuat(sqrt(2.0)/2.0, -sqrt(2.0)/2.0, 0.0, 0.0);// rotate by 90 deg around x Set3DRotationCenter(); UpdateView(); } /** * Updates the display after the user has requested a front view in the 3D display */ void QMiarex::On3DFront() { SetViewControls(); m_pctrlX->setChecked(true); Quaternion Qt1(sqrt(2.0)/2.0, 0.0, -sqrt(2.0)/2.0, 0.0);// rotate by 90 deg around y Quaternion Qt2(sqrt(2.0)/2.0, -sqrt(2.0)/2.0, 0.0, 0.0);// rotate by 90 deg around x m_ArcBall.SetQuat(Qt1 * Qt2); Set3DRotationCenter(); UpdateView(); } /** * Updates the display after the user has requested a reset of the scales in the 3D view */ void QMiarex::On3DReset() { m_glViewportTrans.Set(0.0, 0.0, 0.0); m_bPickCenter = false; m_bIs3DScaleSet = false; Set3DScale(); Set3DRotationCenter(); UpdateView(); } /** * The user has requested a modification of the styles for the 3D view * Launhes the dialog box, reads the data, and updates the view */ void QMiarex::On3DPrefs() { W3dPrefsDlg w3dDlg((MainFrame*)s_pMainFrame); w3dDlg.InitDialog(); w3dDlg.exec(); m_bResetglWake = true; m_bResetglBody = true; m_bResetglGeom = true; m_bResetglMesh = true; m_bResetglOpp = true; m_bResetglStream = true; UpdateView(); } /** * The user has pressed the button which initiates a pick of the rotation center in 3D view * Sets the internal flag to true * The action will be processed in the ::mousePressEvent() function */ void QMiarex::On3DPickCenter() { m_bPickCenter = m_pctrlPickCenter->isChecked(); } /** * Updates the display after the user has requested a reset of the scale of all WOpp graphs */ void QMiarex::OnAllWingGraphScales() { if(m_iView == WOPPVIEW) { double halfspan = m_pCurWing->m_PlanformSpan/2.0; for(int ig=0; ig<4; ig++) { m_WingGraph[ig].SetAuto(true); m_WingGraph[ig].ResetXLimits(); m_WingGraph[ig].ResetYLimits(); m_WingGraph[ig].SetAutoX(false); if(m_bHalfWing) m_WingGraph[ig].SetXMin(0.0); else m_WingGraph[ig].SetXMin(-halfspan*MainFrame::s_mtoUnit); m_WingGraph[ig].SetXMax( halfspan*MainFrame::s_mtoUnit); } } else if(m_iView==WSTABVIEW && m_iStabilityView==STABTIMEVIEW) { for(int ig=0; ig<4; ig++) { m_TimeGraph[ig].SetAuto(true); m_TimeGraph[ig].ResetXLimits(); m_TimeGraph[ig].ResetYLimits(); } } UpdateView(); } /** * Updates the display after the user has requested a reset of the scale of all WPolar graphs */ void QMiarex::OnAllWPolarGraphScales() { if(m_iView==WPOLARVIEW) { for(int ig=0; ig<4; ig++) { m_WPlrGraph[ig].SetAuto(true); m_WPlrGraph[ig].ResetXLimits(); m_WPlrGraph[ig].ResetYLimits(); } } else if(m_iView==WOPPVIEW) { SetWGraphScale(); } else if(m_iView==WCPVIEW) { m_CpGraph.SetAuto(true); m_CpGraph.ResetXLimits(); m_CpGraph.ResetYLimits(); m_CpGraph.SetInverted(true); } else if(m_iView==WSTABVIEW) { for(int ig=0; ig<4; ig++) { m_TimeGraph[ig].SetAuto(true); m_TimeGraph[ig].ResetXLimits(); m_TimeGraph[ig].ResetYLimits(); } } UpdateView(); } /** * The user has requested an edition of the settings for all WOpp graphs * Launches the dialog box and updates the graphs */ void QMiarex::OnAllWingGraphSettings() { QGraph graph; graph.CopySettings(m_WingGraph); GraphDlg grDlg((MainFrame*)s_pMainFrame); grDlg.m_pMemGraph = &graph; grDlg.m_pGraph = m_WingGraph; grDlg.m_GraphArray[0] = m_WingGraph; grDlg.m_GraphArray[1] = m_WingGraph+1; grDlg.m_GraphArray[2] = m_WingGraph+2; grDlg.m_GraphArray[3] = m_WingGraph+3; grDlg.m_NGraph = 4; grDlg.SetParams(); if(grDlg.exec() == QDialog::Accepted) { } else { for(int ig=0; ig<4; ig++) m_WingGraph[ig].CopySettings(&graph); } UpdateView(); } /** * The user has requested an edition of the settings for all WPolar graphs * Launches the dialog box and updates the graphs */ void QMiarex::OnAllWPolarGraphSettings() { QGraph graph; graph.CopySettings(m_WPlrGraph); GraphDlg grDlg((MainFrame*)s_pMainFrame); grDlg.m_pMemGraph = &graph; grDlg.m_pGraph = m_WPlrGraph; grDlg.m_GraphArray[0] = m_WPlrGraph; grDlg.m_GraphArray[1] = m_WPlrGraph+1; grDlg.m_GraphArray[2] = m_WPlrGraph+2; grDlg.m_GraphArray[3] = m_WPlrGraph+3; grDlg.m_NGraph = 4; grDlg.SetParams(); if(grDlg.exec() == QDialog::Accepted) { } else { for(int ig=0; ig<4; ig++) m_WPlrGraph[ig].CopySettings(&graph); } UpdateView(); } /** * Updates the display following a user toggl of the axis the display in the 3D view */ void QMiarex::OnAxes() { s_bAxes = m_pctrlAxes->isChecked(); UpdateView(); } /** * The user has requested a launch of the analysis * Reads a last time the intput parameters from th control box * Checks the foils * Launches the analysis * Updates the active view */ void QMiarex::OnAnalyze() { int l; double V0, VMax, VDelta; bool bHigh = m_bHighlightOpp; m_bHighlightOpp = false; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(!m_pCurWing) { QMessageBox::warning(pMainFrame, tr("Warning"), tr("Please define a wing or a plane object before running a calculation")); return; } if(!m_pCurWPolar) { QMessageBox::warning(pMainFrame, tr("Warning"), tr("Please define an analysis/polar before running a calculation")); return; } //prevent an automatic and lengthy redraw of the streamlines after the calculation m_bStream = m_bSpeeds = false; m_pctrlStream->setChecked(false); m_pctrlSurfVel->setChecked(false); // make sure that the latest parameters are loaded OnReadAnalysisData(); if(m_pCurWPolar->m_WPolarType==FIXEDAOAPOLAR) { V0 = m_QInfMin; VMax = m_QInfMax; VDelta = m_QInfDelta; } else if(m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { V0 = m_ControlMin; VMax = m_ControlMax; VDelta = m_ControlDelta; } else if(m_pCurWPolar->m_WPolarType NWingSection(); l++) { if (!MainFrame::foil(m_pWingList[iw]->RightFoil(l))) { QString strong; strong = m_pWingList[iw]->m_WingName + ": "+tr("Could not find the wing's foil ")+ m_pWingList[iw]->RightFoil(l) +tr("...\nAborting Calculation"); QMessageBox::warning(pMainFrame, tr("Warning"), strong); return; } if (!MainFrame::foil(m_pWingList[iw]->LeftFoil(l))) { QString strong; strong = m_pWingList[iw]->m_WingName + ": "+tr("Could not find the wing's foil ")+ m_pWingList[iw]->LeftFoil(l) +tr("...\nAborting Calculation"); QMessageBox::warning(pMainFrame, tr("Warning"), strong); return; } } } } m_pctrlAnalyze->setEnabled(false); pMainFrame->m_pctrlUFO->setEnabled(false); pMainFrame->m_pctrlWPolar->setEnabled(false); pMainFrame->m_pctrlWOpp->setEnabled(false); if(m_pCurWPolar->m_AnalysisMethod==LLTMETHOD) { LLTAnalyze(V0, VMax, VDelta, m_bSequence, m_bInitLLTCalc); } else if(m_pCurWPolar->m_AnalysisMethod==PANELMETHOD) { if(m_MatSize>0 && m_Panel && m_Node) { if(m_pCurWPolar->m_WPolarType>STABILITYPOLAR) { QString strong; strong = tr("Control polars are not supported in XFLR5 v6.\nPlease use stability polars instead."); QMessageBox::warning(pMainFrame, tr("Warning"), strong+"\n"); return; } PanelAnalyze(V0, VMax, VDelta, m_bSequence); } } else if(m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { if(m_MatSize>0 && m_Panel && m_Node) { PanelAnalyze(V0, VMax, VDelta, m_bSequence); } } m_pctrlAnalyze->setEnabled(true); pMainFrame->m_pctrlUFO->setEnabled(true); pMainFrame->m_pctrlWPolar->setEnabled(true); pMainFrame->m_pctrlWOpp->setEnabled(true); //restore things as they were m_bHighlightOpp = bHigh; //refresh the view if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); UpdateView(); SetControls(); pMainFrame->setFocus(); } /** * Launches the animation of the WOpp display * Will display all the available WOpps for this WPolar in sequence */ void QMiarex::OnAnimateWOpp() { if(!m_pCurWing || !m_pCurWPolar || m_iView==WPOLARVIEW) { m_bAnimateWOpp = false; return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); WingOpp* pWOpp; PlaneOpp*pPOpp; int l; if(m_pctrlWOppAnimate->isChecked()) { if(m_pCurPlane) { for (l=0; l< m_poaPOpp->size(); l++) { pPOpp = (PlaneOpp*)m_poaPOpp->at(l); if (pPOpp && pPOpp->m_PlrName == m_pCurWPolar->m_PlrName && pPOpp->m_PlaneName == m_pCurPlane->PlaneName()) { if(m_pCurPOpp->m_Alpha - pPOpp->m_Alpha<0.0001) m_posAnimateWOpp = l; } } } else if(m_pCurWing) { for (l=0; l< m_poaWOpp->size(); l++) { pWOpp = (WingOpp*)m_poaWOpp->at(l); if (pWOpp && pWOpp->m_PlrName == m_pCurWPolar->m_PlrName && pWOpp->m_WingName == m_pCurWing->WingName()) { if(m_pCurWOpp->m_Alpha - pWOpp->m_Alpha<0.0001) m_posAnimateWOpp = l; } } } m_bAnimateWOpp = true; int speed = m_pctrlAnimateWOppSpeed->value(); m_pTimerWOpp->setInterval(800-speed); m_pTimerWOpp->start(); } else { StopAnimate(); } QApplication::restoreOverrideCursor(); } /** * A signal has been received from the timer to update the 3D mode display * So calculates the state corresponding to the time m_ModeTime and displays it *@param if true, the time position of the modal response will be incremented after the display */ void QMiarex::OnAnimateModeSingle(bool bStep) { static double t, sigma, s2, omega, o2, theta_sum, psi_sum, norm; double *vabs, *phi; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; if(m_iView!=WSTABVIEW && m_iView!=W3DVIEW) { m_pTimerMode->stop(); return; //nothing to animate } if(!m_pCurWing || !m_pCurWPolar || m_pCurWPolar->m_WPolarType!=STABILITYPOLAR || !m_pCurWOpp) { m_pTimerMode->stop(); return; //nothing to animate } //read the data, since the user may have been playing with it norm = m_ModeNorm * pStabView->m_ModeAmplitude; vabs = pStabView->m_vabs; phi = pStabView->m_phi; // calculate the new state sigma = m_pCurWOpp->m_EigenValue[pStabView->m_iCurrentMode].real(); omega = m_pCurWOpp->m_EigenValue[pStabView->m_iCurrentMode].imag(); s2 = sigma*sigma; o2 = omega*omega; t=m_ModeTime; if(t>=100) StopAnimate(); if(m_bLongitudinal) { //x, z, theta are evaluated by direct integration of u, w, q m_ModeState[1] = 0.0; m_ModeState[3] = 0.0; m_ModeState[5] = 0.0; m_ModeState[0] = norm*vabs[0]*exp(sigma*t)/(s2+o2) * (sigma*cos(omega*t+phi[0])+omega*sin(omega*t+phi[0])); m_ModeState[2] = norm*vabs[1]*exp(sigma*t)/(s2+o2) * (sigma*cos(omega*t+phi[1])+omega*sin(omega*t+phi[1])); m_ModeState[4] = norm*vabs[2]*exp(sigma*t)/(s2+o2) * (sigma*cos(omega*t+phi[2])+omega*sin(omega*t+phi[2])); // m_ModeState[4] = norm*vabs[3]*exp(sigma*t)*cos(omega*t+phi[3]); //add u0 x theta_sum to z component theta_sum = norm*vabs[3]*exp(sigma*t)/(s2+o2) * (sigma*cos(omega*t+phi[3])+omega*sin(omega*t+phi[3])); m_ModeState[2] -= theta_sum *m_pCurWOpp->m_QInf; } else { //y, phi, psi evaluation m_ModeState[0] = 0.0; m_ModeState[2] = 0.0; m_ModeState[4] = 0.0; // integrate (v+u0.psi.cos(theta0)) to get y m_ModeState[1] = norm*vabs[0]*exp(sigma*t)/(s2+o2) * (sigma*cos(omega*t+phi[0])+omega*sin(omega*t+phi[0])); //integrate psi = integrate twice r (thanks Matlab !) psi_sum = sigma * ( sigma * cos(omega*t+phi[2]) + omega * sin(omega*t+phi[2])) + omega * (-omega * cos(omega*t+phi[2]) + sigma * sin(omega*t+phi[2])); psi_sum *= vabs[2] * exp(sigma*t)/(s2+o2)/(s2+o2); m_ModeState[1] += norm * m_pCurWOpp->m_QInf * psi_sum; // get directly phi from fourth eigenvector component (alternatively integrate p+r.tan(theta0)); m_ModeState[3] = norm*vabs[3]*exp(sigma*t)*cos(omega*t+phi[3]); // m_ModeState[3] = norm*vabs[1]*exp(sigma*t)/(s2+o2) * (sigma*cos(omega*t+phi[1])+omega*sin(omega*t+phi[1])); // integrate once 'p+r.sin(theta0)' to get heading angle m_ModeState[5] = norm*vabs[2]*exp(sigma*t)/(s2+o2) * (sigma*cos(omega*t+phi[2])+omega*sin(omega*t+phi[2])); } //increase the time for the next update if(bStep) m_ModeTime += m_Modedt; UpdateView(); } /** * A signal has been received from the timer to update the WOPP display * So displays the next WOpp in the sequence. */ void QMiarex::OnAnimateWOppSingle() { static bool bIsValid, bSkipOne; static int size; static PlaneOpp *pPOpp; static WingOpp *pWOpp; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; //KickIdle if(m_iView!=W3DVIEW && m_iView !=WOPPVIEW) return; //nothing to animate if(!m_pCurWing || !m_pCurWPolar) return; if(m_pCurPlane) size = m_poaPOpp->size(); else size = m_poaWOpp->size(); if(size<=1) return; bIsValid = false; bSkipOne = false; while(!bIsValid) { pPOpp = NULL; pWOpp = NULL; //Find the current position to display if(m_pCurPlane) { pPOpp = (PlaneOpp*)m_poaPOpp->at(m_posAnimateWOpp); if(!pPOpp) return; } else { pWOpp = (WingOpp*)m_poaWOpp->at(m_posAnimateWOpp); if(!pWOpp) return; } if(m_pCurPlane) bIsValid =(pPOpp->m_PlrName==m_pCurWPolar->m_PlrName && pPOpp->m_PlaneName==m_pCurPlane->PlaneName()); else bIsValid =(pWOpp->m_PlrName==m_pCurWPolar->m_PlrName && pWOpp->m_WingName==m_pCurWing->WingName()); if (bIsValid && !bSkipOne) { if(m_pCurPlane) { m_pCurPOpp = pPOpp; m_pCurWOpp = pPOpp->m_pPlaneWOpp[0]; for(int iw=0; iwm_pPlaneWOpp[iw]) m_pWOpp[iw] = m_pCurPOpp->m_pPlaneWOpp[iw]; else m_pWOpp[iw] = NULL; } } else { m_pCurPOpp = NULL; m_pCurWOpp = pWOpp; m_pWOpp[0] = m_pCurWOpp; m_pWOpp[1] = m_pWOpp[2] = m_pWOpp[3] = NULL; } m_pCurPOpp = pPOpp; m_bCurWOppOnly = true; if (m_iView==WOPPVIEW) { CreateWOppCurves(); UpdateView(); } else if (m_iView==W3DVIEW) { m_bResetglOpp = true; m_bResetglDownwash = true; m_bResetglLift = true; m_bResetglDrag = true; m_bResetglWake = true; m_bResetglLegend = true; UpdateView(); } else if(m_iView==WCPVIEW) { CreateCpCurves(); UpdateView(); } //select the PlanePOpp in the top listbox pMainFrame->SelectWOpp(m_pCurWOpp); } else if(bIsValid) bSkipOne = false; if(m_bAnimateWOppPlus) { m_posAnimateWOpp++; if (m_posAnimateWOpp >= size) { m_posAnimateWOpp = size-1; m_bAnimateWOppPlus = false; bSkipOne = true; } } else { m_posAnimateWOpp--; if (m_posAnimateWOpp <0) { m_posAnimateWOpp = 0; m_bAnimateWOppPlus = true; bSkipOne = true; } } if(m_posAnimateWOpp<0 || m_posAnimateWOpp>=size) return; } } /** * Modfies the animation after the user has changed the animation speed for the WOpp display */ void QMiarex::OnAnimateWOppSpeed(int val) { if(m_pTimerWOpp->isActive()) { m_pTimerWOpp->setInterval(800-val); } } /** * In the pperating point view, adjusts the graph's scale to the wing's span */ void QMiarex::OnAdjustToWing() { if(!m_pCurWing) return; double halfspan = m_pCurWing->m_PlanformSpan/2.0; double xmin = -halfspan*MainFrame::s_mtoUnit; if(m_bHalfWing) xmin = 0.0; for(int ig=0; ig<4; ig++) { m_WingGraph[ig].SetAutoX(false); m_WingGraph[ig].SetXMax( halfspan*MainFrame::s_mtoUnit); m_WingGraph[ig].SetXMin(xmin); } } /** * The user has requested an edition of the advanced settings * Launches the dialog box and maps the returned data */ void QMiarex::OnAdvancedSettings() { WAdvancedDlg waDlg((MainFrame*)s_pMainFrame); waDlg.m_AlphaPrec = LLTAnalysis::s_CvPrec; waDlg.m_Relax = LLTAnalysis::s_RelaxMax; waDlg.m_NStation = LLTAnalysis::s_NLLTStations; waDlg.m_Iter = m_Iter; waDlg.m_MaxWakeIter = m_MaxWakeIter; waDlg.m_CoreSize = s_CoreSize; waDlg.m_bResetWake = m_bResetWake; waDlg.m_bDirichlet = m_bDirichlet; waDlg.m_bTrefftz = m_bTrefftz; waDlg.m_bKeepOutOpps = m_bKeepOutOpps; waDlg.m_bLogFile = m_bLogFile; waDlg.m_MinPanelSize = s_MinPanelSize; waDlg.m_ControlPos = Panel::s_CtrlPos; waDlg.m_VortexPos = Panel::s_VortexPos; waDlg.m_WakeInterNodes = m_WakeInterNodes; waDlg.m_bVLM1 = m_bVLM1; waDlg.InitDialog(); if(waDlg.exec() == QDialog::Accepted) { LLTAnalysis::s_CvPrec = waDlg.m_AlphaPrec; LLTAnalysis::s_RelaxMax = waDlg.m_Relax; LLTAnalysis::s_NLLTStations = waDlg.m_NStation; m_Iter = waDlg.m_Iter; m_MaxWakeIter = waDlg.m_MaxWakeIter; s_CoreSize = waDlg.m_CoreSize; m_bResetWake = waDlg.m_bResetWake; m_bDirichlet = waDlg.m_bDirichlet; m_bTrefftz = waDlg.m_bTrefftz; m_bKeepOutOpps = waDlg.m_bKeepOutOpps; m_WakeInterNodes = waDlg.m_WakeInterNodes; s_MinPanelSize = waDlg.m_MinPanelSize; m_bVLM1 = waDlg.m_bVLM1; m_InducedDragPoint = waDlg.m_InducedDragPoint; Panel::s_CtrlPos = waDlg.m_ControlPos; Panel::s_VortexPos = waDlg.m_VortexPos; if(waDlg.m_bLogFile) m_bLogFile = true; else m_bLogFile = false; m_bResetglWake = true; UpdateView(); } } /** * The user has modified the position of the clip plane in the 3D view *@param pos the new z position in viewport coordinates of the clipping plane */ void QMiarex::OnClipPlane(int pos) { double planepos = (double)pos/100.0; m_ClipPlanePos = sinh(planepos) * 0.5; UpdateView(); } /** * The user has modified the position span section to display in the Cp view */ void QMiarex::OnCpSection(int pos) { m_CurSpanPos = (double)pos/100.0; m_pctrlSpanPos->SetValue(m_CurSpanPos); CreateCpCurves(); UpdateView(); } /** * The user has modified the position span section to display in the Cp view */ void QMiarex::OnCpPosition() { m_CurSpanPos = m_pctrlSpanPos->Value(); m_pctrlCpSectionSlider->setValue((int)(m_CurSpanPos*100.0)); CreateCpCurves(); UpdateView(); } /** * The user has switched to the Cp view */ void QMiarex::OnCpView() { if (m_bAnimateWOpp) StopAnimate(); if(m_iView==WCPVIEW) { SetControls(); UpdateView(); return; } m_iView=WCPVIEW; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->SetCentralWidget(); // SetWPlrLegendPos(); m_pCurGraph = &m_CpGraph; CreateCpCurves(); SetCurveParams(); SetControls(); UpdateView(); } /** * The user has requested a display only of the current operating point */ void QMiarex::OnCurWOppOnly() { m_bCurWOppOnly = !m_bCurWOppOnly; if(m_iView==WOPPVIEW) { CreateWOppCurves(); UpdateView(); } else if(m_iView==WSTABVIEW && m_iStabilityView==STABTIMEVIEW) { CreateStabilityCurves(); UpdateView(); } SetControls(); } /** * The user has requested a change to the color of the active curve. * The curve may be for a polar curve or for an oppoint. * Changes the style and modifies the content of the comboboxes */ void QMiarex::OnCurveColor() { QColor Color = QColorDialog::getColor(m_CurveColor); if(Color.isValid()) m_CurveColor = Color; FillComboBoxes(); UpdateCurve(); } /** * The user has requested a change to the style of the active curve. * The curve may be for a polar curve or for an oppoint. * Changes the style and modifies the content of the comboboxes */ void QMiarex::OnCurveStyle(int index) { m_CurveStyle = index; FillComboBoxes(); UpdateCurve(); } /** * The user has requested a change to the width of the active curve. * The curve may be for a polar curve or for an oppoint. * Changes the style and modifies the content of the comboboxes */ void QMiarex::OnCurveWidth(int index) { m_CurveWidth = index+1; FillComboBoxes(); UpdateCurve(); } /** * The user has requested the creation of a new stability polar */ void QMiarex::OnDefineStabPolar() { StopAnimate(); m_bArcball = false; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StabPolarDlg::s_StabPolar.m_Viscosity = WPolarDlg::s_WPolar.m_Viscosity; StabPolarDlg::s_StabPolar.m_Density = WPolarDlg::s_WPolar.m_Density; StabPolarDlg::s_StabPolar.m_RefAreaType = WPolarDlg::s_WPolar.m_RefAreaType; StabPolarDlg::s_StabPolar.m_bThinSurfaces = WPolarDlg::s_WPolar.m_bThinSurfaces; StabPolarDlg spDlg(pMainFrame); spDlg.InitDialog(m_pCurPlane, m_pCurWing); int res = spDlg.exec(); if(res == QDialog::Accepted) { MainFrame::SetSaveState(false); WPolar* pNewStabPolar = new WPolar; if (m_pCurPlane) pNewStabPolar->m_UFOName = m_pCurPlane->PlaneName(); else pNewStabPolar->m_UFOName = m_pCurWing->WingName(); pNewStabPolar->m_WMAChord = m_pCurWing->m_MAChord; pNewStabPolar->DuplicateSpec(&StabPolarDlg::s_StabPolar); pNewStabPolar->m_UFOName = UFOName(); // pNewStabPolar->m_PlrName = dlg.m_WPolarName; if(pNewStabPolar->m_PlrName.length()>60) { pNewStabPolar->m_PlrName = pNewStabPolar->m_PlrName.left(60)+"..."+QString("(%1)").arg(m_poaWPolar->size()); } if(pNewStabPolar->m_RefAreaType==PLANFORMAREA) { pNewStabPolar->m_WArea = m_pCurWing->m_PlanformArea; if(m_pCurPlane && m_pCurPlane->BiPlane()) pNewStabPolar->m_WArea += m_pCurPlane->wing2()->m_PlanformArea; pNewStabPolar->m_WSpan = m_pCurWing->m_PlanformSpan; } else { pNewStabPolar->m_WArea = m_pCurWing->m_ProjectedArea; if(m_pCurPlane && m_pCurPlane->BiPlane()) pNewStabPolar->m_WArea += m_pCurPlane->wing2()->m_ProjectedArea; pNewStabPolar->m_WSpan = m_pCurWing->m_ProjectedSpan; } pNewStabPolar->m_bVLM1 = m_bVLM1; pNewStabPolar->m_bDirichlet = m_bDirichlet; pNewStabPolar->m_bTiltedGeom = false; pNewStabPolar->m_bWakeRollUp = false; pNewStabPolar->m_AnalysisMethod = PANELMETHOD; pNewStabPolar->m_bGround = false; pNewStabPolar->m_ASpec = 0.0; pNewStabPolar->m_Height = 0.0; /* for(int i=StabPolarDlg::s_StabPolar.m_nControls; i<4*MAXCONTROLS; i++) { pNewStabPolar->m_bActiveControl[i] = false; }*/ pNewStabPolar->m_Color = pMainFrame->GetColor(4); pNewStabPolar->m_Width = 2; pNewStabPolar->m_bShowPoints = true; pNewStabPolar->m_bIsVisible = true; pNewStabPolar->m_bShowPoints = true; SetModWPolar(pNewStabPolar); m_bResetglGeom = true; m_bResetglOpp = true; m_bResetglMesh = true; m_bResetglWake = true; SetWPolar(); pMainFrame->UpdateWPolars(); UpdateView(); } SetControls(); } /** * The user has requested the creation of a new performance polar. * A new WPolar object is created and is attached to the owning plane or wing. */ void QMiarex::OnDefineWPolar() { if(!m_pCurWing) return; StopAnimate(); MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; WPolar* pNewWPolar = new WPolar; WPolarDlg wpDlg(pMainFrame); wpDlg.InitDialog(m_pCurPlane, m_pCurWing); int res = wpDlg.exec(); if (res == QDialog::Accepted) { //Then add WPolar to array MainFrame::SetSaveState(false); pNewWPolar->DuplicateSpec(&WPolarDlg::s_WPolar); pNewWPolar->m_UFOName = UFOName(); pNewWPolar->m_PlrName = wpDlg.s_WPolar.m_PlrName; pNewWPolar->m_WMAChord = m_pCurWing->m_MAChord; if(pNewWPolar->m_RefAreaType==PLANFORMAREA) { pNewWPolar->m_WSpan = m_pCurWing->m_PlanformSpan; pNewWPolar->m_WArea = m_pCurWing->m_PlanformArea; if(m_pCurPlane && m_pCurPlane->BiPlane()) pNewWPolar->m_WArea += m_pCurPlane->wing2()->m_PlanformArea; } else { pNewWPolar->m_WSpan = m_pCurWing->m_ProjectedSpan; pNewWPolar->m_WArea = m_pCurWing->m_ProjectedArea; if(m_pCurPlane && m_pCurPlane->BiPlane()) pNewWPolar->m_WArea += m_pCurPlane->wing2()->m_ProjectedArea; } pNewWPolar->m_bVLM1 = m_bVLM1; pNewWPolar->m_bDirichlet = m_bDirichlet; // pNewWPolar->m_bAVLControls = false; pNewWPolar->m_Color = pMainFrame->GetColor(4); pNewWPolar->m_bIsVisible = true; SetModWPolar(pNewWPolar); m_bResetglGeom = true; m_bResetglMesh = true; m_bResetglOpp = true; m_bResetglWake = true; SetWPolar(); pMainFrame->UpdateWPolars(); UpdateView(); m_pctrlAnalyze->setFocus(); } else { delete pNewWPolar; } SetControls(); } /** * The user wants to edit the analysis parameters of the currently selected polar. * A new WPolar object is created. The user may choose to overwrite or not the existing WPolar. */ void QMiarex::OnEditCurWPolar() { StopAnimate(); if(!m_pCurWing || !m_pCurWPolar) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; QString WPolarName; int res; WPolar *pNewWPolar = new WPolar; if(m_pCurWPolar->m_WPolarType!=STABILITYPOLAR) { WPolarDlg dlg(this); dlg.InitDialog(m_pCurPlane, m_pCurWing, m_pCurWPolar); res = dlg.exec(); pNewWPolar->DuplicateSpec(&dlg.s_WPolar); WPolarName=dlg.s_WPolar.m_PlrName; } else { StabPolarDlg dlg(this); dlg.InitDialog(m_pCurPlane, m_pCurWing, m_pCurWPolar); res = dlg.exec(); pNewWPolar->DuplicateSpec(&dlg.s_StabPolar); WPolarName=dlg.s_StabPolar.m_PlrName; } if (res == QDialog::Accepted) { MainFrame::SetSaveState(false); pNewWPolar->m_UFOName = UFOName(); pNewWPolar->m_PlrName = WPolarName; if(pNewWPolar->m_RefAreaType==PLANFORMAREA) { pNewWPolar->m_WSpan = m_pCurWing->m_PlanformSpan; pNewWPolar->m_WArea = m_pCurWing->m_PlanformArea; if(m_pCurPlane && m_pCurPlane->BiPlane()) pNewWPolar->m_WArea += m_pCurPlane->wing2()->m_PlanformArea; } else { pNewWPolar->m_WSpan = m_pCurWing->m_ProjectedSpan; pNewWPolar->m_WArea = m_pCurWing->m_ProjectedArea; if(m_pCurPlane && m_pCurPlane->BiPlane()) pNewWPolar->m_WArea += m_pCurPlane->wing2()->m_ProjectedArea; } pNewWPolar->m_bVLM1 = m_bVLM1; pNewWPolar->m_bDirichlet = m_bDirichlet; // pNewWPolar->m_bAVLControls = false; pNewWPolar->m_Color = pMainFrame->GetColor(4); pNewWPolar->m_bIsVisible = true; SetModWPolar(pNewWPolar); m_bResetglGeom = true; m_bResetglMesh = true; m_bResetglOpp = true; m_bResetglWake = true; SetWPolar(); pMainFrame->UpdateWPolars(); UpdateView(); m_pctrlAnalyze->setFocus(); } else { delete pNewWPolar; } SetControls(); } /** * The user has requested a deletion of all the WOpps or POpps associated to the active WPolar. */ void QMiarex::OnDeleteAllWPlrOpps() { if(!m_pCurWPolar) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; MainFrame::SetSaveState(false); WingOpp* pWOpp; PlaneOpp* pPOpp; int i; if(m_pCurPlane) { for (i = m_poaPOpp->size()-1; i>=0; i--) { pPOpp = (PlaneOpp*) m_poaPOpp->at(i); if(pPOpp->m_PlrName == m_pCurWPolar->m_PlrName && pPOpp->m_PlaneName == m_pCurPlane->PlaneName()) { m_poaPOpp->removeAt(i); delete pPOpp; } } } else if(m_pCurWing) { for (i = m_poaWOpp->size()-1; i>=0; i--) { pWOpp = (WingOpp*) m_poaWOpp->at(i); if(pWOpp->m_PlrName == m_pCurWPolar->m_PlrName&& pWOpp->m_WingName == m_pCurWing->WingName()) { m_poaWOpp->removeAt(i); delete pWOpp; } } } m_pCurWOpp = NULL; m_pCurPOpp = NULL; m_bResetglMesh = true; pMainFrame->UpdateWOpps(); SetWingOpp(true); if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); SetControls(); UpdateView(); } /** * The user has requested a deletion of all the WOpps or POpps */ void QMiarex::OnDeleteAllWOpps() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; MainFrame::SetSaveState(false); WingOpp* pWOpp; PlaneOpp* pPOpp; int i; for (i = m_poaPOpp->size()-1; i>=0; i--) { pPOpp = (PlaneOpp*) m_poaPOpp->at(i); m_poaPOpp->removeAt(i); delete pPOpp; } for (i = m_poaWOpp->size()-1; i>=0; i--) { pWOpp = (WingOpp*) m_poaWOpp->at(i); m_poaWOpp->removeAt(i); delete pWOpp; } m_pCurWOpp = NULL; m_pCurPOpp = NULL; pMainFrame->UpdateWOpps(); SetWingOpp(true); if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); SetControls(); UpdateView(); } /** * The user has requested a deletion of the current wing of plane */ void QMiarex::OnDeleteCurUFO() { if(!m_pCurWing) return; m_bAnimateWOpp = false; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QString strong; if(m_pCurPlane) strong = tr("Are you sure you want to delete the plane :\n") + m_pCurPlane->PlaneName() +"?\n"; else strong = tr("Are you sure you want to delete the wing :\n") + m_pCurWing->WingName() +"?\n"; if (QMessageBox::Yes != QMessageBox::question(pMainFrame, tr("Question"), strong, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel)) return; if(m_pCurPlane) pMainFrame->DeletePlane(m_pCurPlane); else pMainFrame->DeleteWing(m_pCurWing); SetUFO(); pMainFrame->UpdateUFOs(); if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); else if(m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); SetControls(); UpdateView(); } /** * The user has requested a deletion of the current operating point */ void QMiarex::OnDeleteCurWOpp() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; int i; double alpha=-9999999; if(m_pCurPOpp) { alpha = m_pCurPOpp->m_Alpha; PlaneOpp* pPOpp; for (i = m_poaPOpp->size()-1; i>=0; i--) { pPOpp = (PlaneOpp*)m_poaPOpp->at(i); if(pPOpp == m_pCurPOpp) { m_poaPOpp->removeAt(i); delete pPOpp; break; } } m_pCurPOpp = NULL; m_pCurWOpp = NULL; pMainFrame->UpdateWOpps(); SetWingOpp(true); MainFrame::SetSaveState(false); if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); UpdateView(); } else if(m_pCurWOpp) { alpha = m_pCurWOpp->m_Alpha; WingOpp* pWOpp; for (i = m_poaWOpp->size()-1; i>=0; i--) { pWOpp = (WingOpp*)m_poaWOpp->at(i); if(pWOpp == m_pCurWOpp) { m_poaWOpp->removeAt(i); delete pWOpp; m_pCurWOpp = NULL; break; } } pMainFrame->UpdateWOpps(); SetWingOpp(true); if(pMainFrame->m_pctrlWOpp->count()) { QString strong; double x; pMainFrame->blockSignals(true); pMainFrame->m_pctrlWOpp->setCurrentIndex(0); pMainFrame->blockSignals(false); strong = pMainFrame->m_pctrlWOpp->itemText(0); bool bRes; x = strong.toDouble(&bRes); if(bRes) { m_pCurWOpp = GetWOpp(x); } else m_pCurWOpp = NULL; } else { m_pCurWOpp = NULL; } MainFrame::SetSaveState(false); if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); UpdateView(); } if(m_pCurWPolar) { m_pCurWPolar->Remove(alpha); } SetControls(); } /** * The user has requested a deletion of all operating point associated to the wing or plane */ void QMiarex::OnDeleteUFOWOpps() { PlaneOpp *pPOpp; WingOpp *pWOpp; int i; if(m_pCurPlane) { for (i=m_poaPOpp->size()-1; i>=0; i--) { pPOpp = (PlaneOpp*)m_poaPOpp->at(i); if (pPOpp->m_PlaneName == m_pCurPlane->PlaneName()) { m_poaPOpp->removeAt(i); delete pPOpp; } } } else if(m_pCurWing) { for (i=m_poaWOpp->size()-1; i>=0; i--) { pWOpp = (WingOpp*)m_poaWOpp->at(i); if (pWOpp->m_WingName == m_pCurWing->WingName()) { m_poaWOpp->removeAt(i); delete pWOpp; } } } m_pCurWOpp = NULL; m_pCurPOpp = NULL; if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; MainFrame::SetSaveState(false); pMainFrame->UpdateWOpps(); SetControls(); UpdateView(); } /** * The user has requested a deletion of all WPolars associated to the wing or plane */ void QMiarex::OnDeleteUFOWPolars() { if(!m_pCurWing) return; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; WPolar *pWPolar; QString UFOName, strong; if(m_pCurPlane) UFOName = m_pCurPlane->PlaneName(); else UFOName = m_pCurWing->WingName(); strong = tr("Are you sure you want to delete the polars associated to :\n") + UFOName +"?\n"; if (QMessageBox::Yes != QMessageBox::question(pMainFrame, tr("Question"), strong, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel)) return; for(int j=m_poaWPolar->size()-1; j>=0; j--) { pWPolar = (WPolar *)m_poaWPolar->at(j); if(pWPolar && pWPolar->m_UFOName==UFOName) { //first remove all WOpps and POpps associated to the Wing Polar WingOpp * pWOpp; for (int i=m_poaWOpp->size()-1; i>=0; i--) { pWOpp = (WingOpp*)m_poaWOpp->at(i); if (pWOpp->m_PlrName == pWPolar->m_PlrName && pWOpp->m_WingName == UFOName) { m_poaWOpp->removeAt(i); delete pWOpp; } } PlaneOpp * pPOpp; for (int i=m_poaPOpp->size()-1; i>=0; i--) { pPOpp = (PlaneOpp*)m_poaPOpp->at(i); if (pPOpp->m_PlrName == pWPolar->m_PlrName && pPOpp->m_PlaneName== UFOName) { m_poaPOpp->removeAt(i); delete pPOpp; } } //then remove the polar m_poaWPolar->removeAt(j); delete pWPolar; } } m_pCurWPolar = NULL; SetWPolar(); pMainFrame->UpdateWPolars(); MainFrame::SetSaveState(false); SetControls(); UpdateView(); } /** * The user has requested a deletion of the current WPolar object */ void QMiarex::OnDeleteCurWPolar() { if(!m_pCurWPolar) return; m_bAnimateWOpp = false; int i; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QString strong, UFOName; if(m_pCurPlane) UFOName = m_pCurPlane->PlaneName(); else if(m_pCurWing) UFOName = m_pCurWing->WingName(); else return; strong = tr("Are you sure you want to delete the polar :\n") + m_pCurWPolar->m_PlrName +"?\n"; if (QMessageBox::Yes != QMessageBox::question(pMainFrame, tr("Question"), strong, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel)) return; //first remove all WOpps associated to the Wing Polar WingOpp * pWOpp; for (i=m_poaWOpp->size()-1; i>=0; i--) { pWOpp = (WingOpp*)m_poaWOpp->at(i); if (pWOpp->m_PlrName == m_pCurWPolar->m_PlrName && pWOpp->m_WingName == UFOName) { m_poaWOpp->removeAt(i); delete pWOpp; } } //next remove all the POpps associated to the Wing Polar PlaneOpp * pPOpp; for (i=m_poaPOpp->size()-1; i>=0; i--) { pPOpp = (PlaneOpp*)m_poaPOpp->at(i); if (pPOpp->m_PlrName == m_pCurWPolar->m_PlrName && pPOpp->m_PlaneName == UFOName) { m_poaPOpp->removeAt(i); delete pPOpp; } } //next remove the WPolar WPolar* pWPolar; for (i=m_poaWPolar->size()-1;i>=0; i--) { pWPolar = (WPolar*)m_poaWPolar->at(i); if (pWPolar == m_pCurWPolar) { m_poaWPolar->removeAt(i); delete pWPolar; break; } } m_pCurPOpp = NULL; m_pCurWOpp = NULL; m_pCurWPolar = NULL; MainFrame::SetSaveState(false); SetWPolar(); pMainFrame->UpdateWPolars(); SetControls(); UpdateView(); } /** * The user has toggled the checkbox for the display of the downwash */ void QMiarex::OnDownwash() { m_bDownwash = m_pctrlDownwash->isChecked(); UpdateView(); } /** * The user hase changed the position of the slider for the drag display * @param pos the slider's new position */ void QMiarex::OnDragScale(int pos) { m_DragScale = pos/100.0/sqrt(1.01-pos/100.0); m_bResetglDrag = true; UpdateView(); } /** * The user has requested a duplication of the currently selected wing or plane */ void QMiarex::OnDuplicateCurUFO() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(!m_pCurWing) return; if(m_pCurPlane) { DuplicatePlane(); return; } QString UFOName; if(m_pCurPlane) UFOName = m_pCurPlane->PlaneName(); else if(m_pCurWing) UFOName = m_pCurWing->WingName(); else return; Wing* pNewWing= new Wing; pNewWing->Duplicate(m_pCurWing); if(!SetModWing(pNewWing)) { delete pNewWing; UpdateView(); } else { m_pCurWing = AddWing(pNewWing); SetUFO(); pMainFrame->UpdateUFOs(); OnEditUFO(); } } /** * The user has requested an edition of the current body * Launch the edition interface, and on return, insert the body i.a.w. user instructions */ void QMiarex::OnEditCurBody() { if(!m_pCurPlane || !m_pCurPlane->body()) return; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; Body *pCurBody = m_pCurPlane->body(); bool bUsed = false; int i; Plane *pPlane; WPolar *pWPolar; for (i=0; i< m_poaPlane->size(); i++) { pPlane = (Plane*)m_poaPlane->at(i); if(pPlane->body() && pPlane->body()==pCurBody) { // Does this plane have results for(int j=0; jsize(); j++) { pWPolar = (WPolar*)m_poaWPolar->at(j); if(pWPolar->m_UFOName==pPlane->PlaneName() && pWPolar->m_Alpha.size()) { bUsed = true; break; } } if(bUsed) break; } } Plane *pModPlane = new Plane(); pModPlane->Duplicate(m_pCurPlane); GL3dBodyDlg glbDlg(pMainFrame); glbDlg.m_bEnableName = false; glbDlg.InitDialog(pModPlane->body()); glbDlg.move(GL3dBodyDlg::s_WindowPos); glbDlg.resize(GL3dBodyDlg::s_WindowSize); if(GL3dBodyDlg::s_bWindowMaximized) glbDlg.setWindowState(Qt::WindowMaximized); if(glbDlg.exec()!=QDialog::Accepted) return; ModDlg mdDlg(pMainFrame); if(bUsed) { mdDlg.m_Question = tr("The modification will erase all results associated to this Plane.\nContinue ?"); mdDlg.InitDialog(); int Ans = mdDlg.exec(); if (Ans == QDialog::Rejected) { //restore geometry delete pModPlane; // clean up return; } else if(Ans==20) { //save mods to a new plane object if(!SetModPlane(pModPlane)) { delete pModPlane; } else { m_pCurPlane = AddPlane(pModPlane); } SetUFO(); pMainFrame->UpdateUFOs(); UpdateView(); return; } } //then modifications are automatically recorded m_pCurPlane->Duplicate(pModPlane); pMainFrame->DeletePlane(m_pCurPlane, true);// will also set new surface and Aerochord in WPolars SetUFO(); if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); else if(m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); } /** * The user has requested an edition of the current wing or plane * Launches the dialog box, and maps the data depending on whether the user wants to overwrite, create a new object, or has cancelled the request. */ void QMiarex::OnEditUFO() { if(!m_pCurWing) return; if(m_pCurPlane) { EditCurPlane(); return; } int i; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; WPolar *pWPolar; WingOpp* pWOpp; bool bHasResults = false; for (i=0; i< m_poaWPolar->size(); i++) { pWPolar = (WPolar*)m_poaWPolar->at(i); if (pWPolar->m_Alpha.size() && pWPolar->m_UFOName == m_pCurWing->WingName()) { bHasResults = true; break; } } for (i=0; i< m_poaWOpp->size(); i++) { pWOpp = (WingOpp*)m_poaWOpp->at(i); if(pWOpp->m_WingName == m_pCurWing->WingName()) { bHasResults = true; break; } } Wing* pModWing= new Wing; pModWing->Duplicate(m_pCurWing); GL3dWingDlg wingDlg(pMainFrame); wingDlg.m_bAcceptName= false; wingDlg.InitDialog(pModWing); ModDlg mdDlg(pMainFrame); if(QDialog::Accepted == wingDlg.exec()) { if(wingDlg.m_bDescriptionChanged) { MainFrame::SetSaveState(false); m_pCurWing->rWingDescription() = pModWing->WingDescription(); } if(wingDlg.m_bChanged) { if(bHasResults) { mdDlg.m_Question = tr("The modification will erase all results associated to this Wing.\nContinue ?"); mdDlg.InitDialog(); int Ans = mdDlg.exec(); if (Ans == QDialog::Rejected) { delete pModWing; // clean up return; } else if(Ans==20) { //user wants to save as a new wing if(!SetModWing(pModWing)) { delete pModWing; } else { m_pCurWing = AddWing(pModWing); } SetUFO(); pMainFrame->UpdateUFOs(); UpdateView(); return; } else { //user wants to overwrite pMainFrame->DeleteWing(m_pCurWing,true); m_pCurWing->Duplicate(pModWing); } } else { //No results, record the changes without prompting the user m_pCurWing->Duplicate(pModWing); } if(m_iView==W3DVIEW) { m_bResetglGeom = true; m_bResetglMesh = true; // m_bResetglOpp = true; } else { if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); else if(m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); } } m_pCurWing->m_WingColor = pModWing->m_WingColor; SetUFO(); pMainFrame->UpdateUFOs(); m_bResetglStream = true; m_bIs2DScaleSet = false; SetScale(); SetWGraphScale(); OnAdjustToWing(); SetControls(); UpdateView(); } else { delete pModWing; // clean up } } /** * Exports the data from the active WOpp to the text file */ void QMiarex::OnExportCurWOpp() { if(!m_pCurWOpp)return ;// is there anything to export ? int iStrip,j,k,l,p, coef; enumTextFileType exporttype; QString filter; if(MainFrame::s_ExportFileType==TXT) filter = "Text File (*.txt)"; else filter = "Comma Separated Values (*.csv)"; QString FileName, sep, str, strong, Format; strong = QString("a=%1_v=%2").arg(m_pCurWOpp->m_Alpha, 5,'f',2).arg(m_pCurWOpp->m_QInf*MainFrame::s_mstoUnit,6,'f',2); GetSpeedUnit(str, MainFrame::s_SpeedUnit); strong = m_pCurWOpp->m_WingName+"_"+strong+str; strong.replace(" ",""); strong.replace("/", ""); FileName = QFileDialog::getSaveFileName(this, tr("Export Wing OpPoint"), MainFrame::s_LastDirName +'/'+strong, tr("Text File (*.txt);;Comma Separated Values (*.csv)"), &filter); if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); pos = FileName.lastIndexOf(".csv"); if (pos>0) MainFrame::s_ExportFileType = CSV; else MainFrame::s_ExportFileType = TXT; exporttype = MainFrame::s_ExportFileType; QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&XFile); if(exporttype==TXT) sep = ""; else sep=","; out << MainFrame::versionName(); out << "\n\n"; if(m_pCurPOpp) out << m_pCurPOpp->m_PlaneName<< "\n"; else if(m_pCurWOpp) out << m_pCurWOpp->m_WingName<< "\n"; strong = m_pCurWOpp->m_PlrName + "\n"; out << strong; strong = QString("QInf ="+sep+" %1 "+sep).arg(m_pCurWOpp->m_QInf*MainFrame::s_mstoUnit,11, 'f', 6); GetSpeedUnit(str, MainFrame::s_SpeedUnit); strong+=str+"\n"; out << strong; strong = QString("Alpha = "+sep+"%1\n").arg(m_pCurWOpp->m_Alpha,11, 'f', 6); out << strong; strong = QString("Beta = "+sep+"%1").arg(m_pCurWOpp->m_Beta, 8,'f',3); strong += QString::fromUtf8("°\n"); out << strong; strong = QString("Phi = "+sep+"%1").arg(m_pCurWOpp->m_Phi, 8,'f',3); strong += QString::fromUtf8("°\n"); out << strong; strong = QString("Ctrl = "+sep+"%1\n").arg(m_pCurWOpp->m_Ctrl, 8,'f',3); out << strong; strong = QString("CL = "+sep+"%1\n").arg(m_pCurWOpp->m_CL,11, 'f', 6); out << strong; strong = QString("Cy = "+sep+"%1\n").arg(m_pCurWOpp->m_CY,11, 'f', 6); out << strong; if(exporttype==TXT) strong = QString(tr("Cd = %1 ICd = %2 PCd = %3\n")) .arg(m_pCurWOpp->m_ICD+m_pCurWOpp->m_VCD,11, 'f', 6) .arg(m_pCurWOpp->m_ICD,11, 'f', 6) .arg(m_pCurWOpp->m_VCD,11, 'f', 6); else strong = QString(tr("Cd=,%1,ICd=, %2,PCd=, %3\n")) .arg(m_pCurWOpp->m_ICD+m_pCurWOpp->m_VCD,11, 'f', 6) .arg(m_pCurWOpp->m_ICD,11, 'f', 6) .arg(m_pCurWOpp->m_VCD,11, 'f', 6); out << strong; strong = QString(tr("Cl = ")+sep+"%1\n").arg(m_pCurWOpp->m_GRm, 11,'g',6); out << strong; strong = QString(tr("Cm =")+sep+" %1\n").arg(m_pCurWOpp->m_GCm, 11,'g',6); out << strong; if(exporttype==TXT) strong = QString(tr("ICn = %1 PCn = %2 \n")).arg(m_pCurWOpp->m_IYm, 11, 'f', 6).arg(m_pCurWOpp->m_GYm, 11, 'f', 6); else strong = QString(tr("ICn=, %1,PCn=, %2\n")).arg(m_pCurWOpp->m_IYm, 11, 'f', 6).arg(m_pCurWOpp->m_GYm, 11, 'f', 6); out << strong; if(exporttype==TXT) strong = QString("XCP = %1 YCP = %2 ZCP = %3 \n").arg(m_pCurWOpp->m_CP.x, 11, 'f', 6).arg(m_pCurWOpp->m_CP.y, 11, 'f', 6).arg(m_pCurWOpp->m_CP.z, 11, 'f', 6); else strong = QString("XCP=, %1, YCP=, %2, ZCP=, %3 \n").arg(m_pCurWOpp->m_CP.x, 11, 'f', 6).arg(m_pCurWOpp->m_CP.y, 11, 'f', 6).arg(m_pCurWOpp->m_CP.z, 11, 'f', 6); out << strong; if(exporttype==TXT) strong = QString("XNP = %1\n").arg(m_pCurWOpp->m_XNP, 11, 'f', 6); else strong = QString("XNP=, %1\n").arg(m_pCurWOpp->m_XNP, 11, 'f', 6); out << strong; strong = QString(tr("Bend. =")+sep+" %1\n\n").arg(m_pCurWOpp->m_MaxBending, 11, 'f', 6); out << strong; if(m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { //export non dimensional stability derivatives if(exporttype==TXT) { // complex c, angle; double u0 = m_pCurWOpp->m_QInf; double mac = m_pCurWPolar->m_WArea; double b = m_pCurWPolar->m_WSpan; strong = "\n\n ___Longitudinal modes____\n\n"; out << strong; strong = QString(" Eigenvalue: %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_pCurWOpp->m_EigenValue[0].real(),9, 'g', 4).arg(m_pCurWOpp->m_EigenValue[0].imag(),9, 'g', 4) .arg(m_pCurWOpp->m_EigenValue[1].real(),9, 'g', 4).arg(m_pCurWOpp->m_EigenValue[1].imag(),9, 'g', 4) .arg(m_pCurWOpp->m_EigenValue[2].real(),9, 'g', 4).arg(m_pCurWOpp->m_EigenValue[2].imag(),9, 'g', 4) .arg(m_pCurWOpp->m_EigenValue[3].real(),9, 'g', 4).arg(m_pCurWOpp->m_EigenValue[3].imag(),9, 'g', 4); out << strong; strong=(" _____________________________________________________________________________________________________\n"); out << strong; strong = QString(" u/u0: %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_pCurWOpp->m_EigenVector[0][0].real()/u0, 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[0][0].imag()/u0, 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[1][0].real()/u0, 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[1][0].imag()/u0, 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[2][0].real()/u0, 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[2][0].imag()/u0, 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[3][0].real()/u0, 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[3][0].imag()/u0, 9, 'g', 4); out << strong; strong = QString(" w/u0: %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_pCurWOpp->m_EigenVector[0][1].real()/u0, 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[0][1].imag()/u0, 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[1][1].real()/u0, 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[1][1].imag()/u0, 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[2][1].real()/u0, 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[2][1].imag()/u0, 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[3][1].real()/u0, 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[3][1].imag()/u0, 9, 'g', 4); out << strong; strong = QString(" q/(2.u0/MAC): %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_pCurWOpp->m_EigenVector[0][2].real()/(2.*u0/mac), 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[0][2].imag()/(2.*u0/mac), 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[1][2].real()/(2.*u0/mac), 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[1][2].imag()/(2.*u0/mac), 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[2][2].real()/(2.*u0/mac), 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[2][2].imag()/(2.*u0/mac), 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[3][2].real()/(2.*u0/mac), 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[3][2].imag()/(2.*u0/mac), 9, 'g', 4); out << strong; strong = QString(" theta(rad): %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(1.0, 9, 'g', 4).arg(0.0, 9, 'g', 4) .arg(1.0, 9, 'g', 4).arg(0.0, 9, 'g', 4) .arg(1.0, 9, 'g', 4).arg(0.0, 9, 'g', 4) .arg(1.0, 9, 'g', 4).arg(0.0, 9, 'g', 4); out << strong; strong = "\n"; out << strong; strong = "\n\n ___Lateral modes____\n\n"; out << strong; strong = QString(" Eigenvalue: %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_pCurWOpp->m_EigenValue[4].real(),9, 'g', 4).arg(m_pCurWOpp->m_EigenValue[4].imag(),9, 'g', 4) .arg(m_pCurWOpp->m_EigenValue[5].real(),9, 'g', 4).arg(m_pCurWOpp->m_EigenValue[5].imag(),9, 'g', 4) .arg(m_pCurWOpp->m_EigenValue[6].real(),9, 'g', 4).arg(m_pCurWOpp->m_EigenValue[6].imag(),9, 'g', 4) .arg(m_pCurWOpp->m_EigenValue[7].real(),9, 'g', 4).arg(m_pCurWOpp->m_EigenValue[7].imag(),9, 'g', 4); out << strong; strong=(" _____________________________________________________________________________________________________\n"); out << strong; strong = QString(" v/u0 : %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_pCurWOpp->m_EigenVector[4][0].real()/u0, 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[4][0].imag()/u0, 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[5][0].real()/u0, 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[5][0].imag()/u0, 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[6][0].real()/u0, 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[6][0].imag()/u0, 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[7][0].real()/u0, 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[7][0].imag()/u0, 9, 'g', 4); out << strong; strong = QString(" p/(2.u0/Span): %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_pCurWOpp->m_EigenVector[4][1].real()/(2.0*u0/b), 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[4][1].imag()/(2.0*u0/b), 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[5][1].real()/(2.0*u0/b), 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[5][1].imag()/(2.0*u0/b), 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[6][1].real()/(2.0*u0/b), 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[6][1].imag()/(2.0*u0/b), 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[7][1].real()/(2.0*u0/b), 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[7][1].imag()/(2.0*u0/b), 9, 'g', 4); out << strong; strong = QString(" r/(2.u0/Span): %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_pCurWOpp->m_EigenVector[4][2].real()/(2.0*u0/b), 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[4][2].imag()/(2.0*u0/b), 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[5][2].real()/(2.0*u0/b), 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[5][2].imag()/(2.0*u0/b), 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[6][2].real()/(2.0*u0/b), 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[6][2].imag()/(2.0*u0/b), 9, 'g', 4) .arg(m_pCurWOpp->m_EigenVector[7][2].real()/(2.0*u0/b), 9, 'g', 4).arg(m_pCurWOpp->m_EigenVector[7][2].imag()/(2.0*u0/b), 9, 'g', 4); out << strong; strong = QString(" phi(rad): %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(1.0, 9, 'g', 4).arg(0.0, 9, 'g', 4) .arg(1.0, 9, 'g', 4).arg(0.0, 9, 'g', 4) .arg(1.0, 9, 'g', 4).arg(0.0, 9, 'g', 4) .arg(1.0, 9, 'g', 4).arg(0.0, 9, 'g', 4); out << strong; strong = "\n"; out << strong; strong = QString("CLa = %1\n").arg(m_pCurWOpp->CLa, 11, 'f', 6); out << strong; strong = QString("CLq = %1\n").arg(m_pCurWOpp->CLq, 11, 'f', 6); out << strong; strong = QString("Cma = %1\n").arg(m_pCurWOpp->Cma, 11, 'f', 6); out << strong; strong = QString("Cmq = %1\n").arg(m_pCurWOpp->Cmq, 11, 'f', 6); out << strong; strong = QString("CYb = %1\n").arg(m_pCurWOpp->CYb, 11, 'f', 6); out << strong; strong = QString("CYp = %1\n").arg(m_pCurWOpp->CYp, 11, 'f', 6); out << strong; strong = QString("CYr = %1\n").arg(m_pCurWOpp->CYr, 11, 'f', 6); out << strong; strong = QString("Clb = %1\n").arg(m_pCurWOpp->Clb, 11, 'f', 6); out << strong; strong = QString("Clp = %1\n").arg(m_pCurWOpp->Clp, 11, 'f', 6); out << strong; strong = QString("Clr = %1\n").arg(m_pCurWOpp->Clr, 11, 'f', 6); out << strong; strong = QString("Cnb = %1\n").arg(m_pCurWOpp->Cnb, 11, 'f', 6); out << strong; strong = QString("Cnp = %1\n").arg(m_pCurWOpp->Cnp, 11, 'f', 6); out << strong; strong = QString("Cnr = %1\n").arg(m_pCurWOpp->Cnr, 11, 'f', 6); out << strong; if(m_pCurWOpp->m_nControls>0) { strong = QString("CXe = %1\n").arg(m_pCurWOpp->CXe, 11, 'f', 6); out << strong; strong = QString("CYe = %1\n").arg(m_pCurWOpp->CYe, 11, 'f', 6); out << strong; strong = QString("CZe = %1\n").arg(m_pCurWOpp->CZe, 11, 'f', 6); out << strong; strong = QString("CLe = %1\n").arg(m_pCurWOpp->CLe, 11, 'f', 6); out << strong; strong = QString("CMe = %1\n").arg(m_pCurWOpp->CMe, 11, 'f', 6); out << strong; strong = QString("CNe = %1\n").arg(m_pCurWOpp->CNe, 11, 'f', 6); out << strong; } } else { strong = QString("CLa =,%1\n").arg(m_pCurWOpp->CLa, 11, 'f', 6); out << strong; strong = QString("CLq =,%1\n").arg(m_pCurWOpp->CLq, 11, 'f', 6); out << strong; strong = QString("Cma =,%1\n").arg(m_pCurWOpp->Cma, 11, 'f', 6); out << strong; strong = QString("Cmq =,%1\n").arg(m_pCurWOpp->Cmq, 11, 'f', 6); out << strong; strong = QString("CYb =,%1\n").arg(m_pCurWOpp->CYb, 11, 'f', 6); out << strong; strong = QString("CYp =,%1\n").arg(m_pCurWOpp->CYp, 11, 'f', 6); out << strong; strong = QString("CYr =,%1\n").arg(m_pCurWOpp->CYr, 11, 'f', 6); out << strong; strong = QString("Clb =,%1\n").arg(m_pCurWOpp->Clb, 11, 'f', 6); out << strong; strong = QString("Clp =,%1\n").arg(m_pCurWOpp->Clp, 11, 'f', 6); out << strong; strong = QString("Clr =,%1\n").arg(m_pCurWOpp->Clr, 11, 'f', 6); out << strong; strong = QString("Cnb =,%1\n").arg(m_pCurWOpp->Cnb, 11, 'f', 6); out << strong; strong = QString("Cnp =,%1\n").arg(m_pCurWOpp->Cnp, 11, 'f', 6); out << strong; strong = QString("Cnr =,%1\n").arg(m_pCurWOpp->Cnr, 11, 'f', 6); out << strong; if(m_pCurWOpp->m_nControls>0) { strong = QString("CXe =, %1\n").arg(m_pCurWOpp->CXe, 11, 'f', 6); out << strong; strong = QString("CYe =, %1\n").arg(m_pCurWOpp->CYe, 11, 'f', 6); out << strong; strong = QString("CZe =, %1\n").arg(m_pCurWOpp->CZe, 11, 'f', 6); out << strong; strong = QString("CLe =, %1\n").arg(m_pCurWOpp->CLe, 11, 'f', 6); out << strong; strong = QString("CMe =, %1\n").arg(m_pCurWOpp->CMe, 11, 'f', 6); out << strong; strong = QString("CNe =, %1\n").arg(m_pCurWOpp->CNe, 11, 'f', 6); out << strong; } } out << "\n\n"; } for(int iw=0; iwm_WingName; for (l=0; lm_nFlaps; l++) { strong = QString(tr("Flap ")+sep+"%1"+sep+" moment = "+sep+"%2 ").arg(l+1,4).arg(m_pWOpp[iw]->m_FlapMoment[l]*MainFrame::s_NmtoUnit, 9,'f',4); GetMomentUnit(str, MainFrame::s_MomentUnit); strong += str +"\n"; out << strong; } out << ("\n"); m_pWOpp[iw]->Export(out, exporttype); } } if(m_pCurWOpp->m_AnalysisMethod>=VLMMETHOD) { if(m_pCurPOpp) out << tr("Main Wing Cp Coefficients\n"); else out << tr("Wing Cp Coefficients\n"); coef = 1; if(!m_pCurWPolar->m_bThinSurfaces) { coef = 2; } if(exporttype==1) out << tr(" Panel CtrlPt.x CtrlPt.y CtrlPt.z Cp\n"); else out << tr("Panel,CtrlPt.x,CtrlPt.y,CtrlPt.z,Cp\n"); if(exporttype==1) Format = "%1 %2 %3 %4 %5\n"; else Format = "%1,%2,%3,%4,%5\n"; for(int iw=0; iwm_WingName+ tr("Cp Coefficients")+"\n"; p=0; iStrip = 0; for (j=0; jm_NSurfaces; j++) { if(m_pWingList[iw]->m_Surface[j].m_bIsTipLeft && !m_pCurWOpp->m_bThinSurface) p+= m_pWingList[iw]->m_Surface[j].m_NXPanels; for(k=0; km_Surface[j].m_NYPanels; k++) { iStrip++; strong = QString(tr("Strip %1\n")).arg(iStrip); out << strong; for(l=0; lm_Surface[j].m_NXPanels * coef; l++) { if(m_pWingList[iw]->m_pWingPanel[p].m_Pos==MIDSURFACE) { strong = QString(Format).arg(p,4).arg(m_pWingList[iw]->m_pWingPanel[p].CtrlPt.x,11,'e',3).arg(m_pWingList[iw]->m_pWingPanel[p].CtrlPt.y,11,'e',3).arg(m_pWingList[iw]->m_pWingPanel[p].CtrlPt.z,11,'e',3).arg(m_pWOpp[iw]->m_Cp[p],11,'f',4); } else { strong = QString(Format).arg(p,4).arg(m_pWingList[iw]->m_pWingPanel[p].CollPt.x,11,'e',3).arg(m_pWingList[iw]->m_pWingPanel[p].CollPt.y,11,'e',3).arg(m_pWingList[iw]->m_pWingPanel[p].CollPt.z,11,'e',3).arg(m_pWOpp[iw]->m_Cp[p],11,'f',4); } out << strong; p++; } } } } out << ("\n\n"); } } out << ("\n\n"); XFile.close(); } /** * Exports the data from the active polar to a text file */ void QMiarex::OnExportCurWPolar() { if (!m_pCurWPolar) return; QString FileName, filter; if(MainFrame::s_ExportFileType==TXT) filter = "Text File (*.txt)"; else filter = "Comma Separated Values (*.csv)"; FileName = m_pCurWPolar->m_PlrName; FileName.replace("/", " "); FileName = QFileDialog::getSaveFileName(this, tr("Export Polar"), MainFrame::s_LastDirName + "/"+FileName, tr("Text File (*.txt);;Comma Separated Values (*.csv)"), &filter); if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); pos = FileName.lastIndexOf(".csv"); if (pos>0) MainFrame::s_ExportFileType = CSV; else MainFrame::s_ExportFileType = TXT; QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&XFile); m_pCurWPolar->Export(out, MainFrame::s_ExportFileType); XFile.close(); UpdateView(); } /** * Exports the geometrical data of the acitve wing or plane to a text file readable by AVL *@todo AVL expects consistency of the units, need to check all lines and cases */ void QMiarex::OnExporttoAVL() { if (!m_pCurWing) return; QString filter =".avl"; QString FileName, strong; if(m_pCurPlane) FileName = m_pCurPlane->PlaneName(); else FileName = m_pCurWing->WingName(); FileName.replace("/", " "); FileName = QFileDialog::getSaveFileName(this, tr("Export UFO"), MainFrame::s_LastDirName + "/"+FileName, tr("AVL Text File (*.avl)"), &filter); if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&XFile); strong = MainFrame::s_ProjectName; int len = strong.length(); if (strong.right(1) == "*") strong = strong.left(len-1); if(!strong.length()) out << tr("Project"); else out << strong; out << "\n"; out << "0.0 | Mach\n"; if(m_pCurWing->m_bSymetric) out << ("0 0 0.0 | iYsym iZsym Zsym\n"); else out << ("0 0 0.0 | iYsym iZsym Zsym\n"); out << ("\n"); strong = QString("%1 %2 %3 | Sref Cref Bref\n") .arg(m_pCurWing->m_PlanformArea*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit, 8, 'f', 3) .arg(m_pCurWing->m_MAChord*MainFrame::s_mtoUnit, 8, 'f', 3) .arg(m_pCurWing->m_PlanformSpan*MainFrame::s_mtoUnit, 8, 'f', 3); out << strong; out << "# Note : check consistency of area unit above with length units of the file\n"; if(m_pCurPlane) strong = QString("%1 %2 %3 | Xref Yref Zref\n") .arg(m_pCurPlane->CoG().x*MainFrame::s_mtoUnit,8,'f',3) .arg(m_pCurPlane->CoG().y*MainFrame::s_mtoUnit,8,'f',3) .arg(m_pCurPlane->CoG().z*MainFrame::s_mtoUnit,8,'f',3); else if(m_pCurWing) strong = QString("%1 %2 %3 | Xref Yref Zref\n") .arg(m_pCurWing->m_CoG.x*MainFrame::s_mtoUnit,8,'f',3) .arg(m_pCurWing->m_CoG.y*MainFrame::s_mtoUnit,8,'f',3) .arg(m_pCurWing->m_CoG.z*MainFrame::s_mtoUnit,8,'f',3); out << strong; out << (" 0.00 | CDp (optional)\n"); out << ("\n\n\n"); int index = rand(); if(m_pCurPlane) m_pCurWing->ExportAVLWing(out, index, 0.0, 0.0, 0.0, 0.0, m_pCurPlane->WingTiltAngle(0)); else m_pCurWing->ExportAVLWing(out, index, 0.0, 0.0, 0.0, 0.0, 0.0); for(int iw=1; iwExportAVLWing(out, index+iw, 0.0, 0.0, 0.0, 0.0, m_pCurPlane->WingTiltAngle(iw)); } XFile.close(); } /** * The user has toggled the display switch for the fin curve in the OpPoint view */ void QMiarex::OnFinCurve() { m_bShowWingCurve[3] = !m_bShowWingCurve[3]; // CheckMenus(); if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); UpdateView(); } /** * The user has toggled the display switch for the elevator curve in the OpPoint view */ void QMiarex::OnStabCurve() { m_bShowWingCurve[2] = !m_bShowWingCurve[2]; // CheckMenus(); if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); UpdateView(); } /** * The user has toggled the display of the foil names in the 3D view */ void QMiarex::OnFoilNames() { s_bFoilNames = m_pctrlFoilNames->isChecked(); UpdateView(); } /** * The user has toggled the display of the masses in the 3D view */ void QMiarex::OnMasses() { s_bShowMasses = m_pctrlMasses->isChecked(); UpdateView(); } /** * The user has changed one of the scale in the GL3DScale widget */ void QMiarex::OnGL3DScale() { if(m_iView != W3DVIEW) { // m_pctrl3DSettings->setChecked(false); return; } MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(pMainFrame->m_pctrl3DScalesWidget->isVisible()) pMainFrame->m_pctrl3DScalesWidget->hide(); else pMainFrame->m_pctrl3DScalesWidget->show(); pMainFrame->W3DScalesAct->setChecked(pMainFrame->m_pctrl3DScalesWidget->isVisible()); // if(m_pctrl3DSettings->isChecked()) pMainFrame->m_pctrl3DScalesWidget->show(); // else pMainFrame->m_pctrl3DScalesWidget->hide(); } /** * The user has requested an edition of the settings of the active graph */ void QMiarex::OnGraphSettings() { QGraph *pGraph = NULL; GraphDlg grDlg((MainFrame*)s_pMainFrame); pGraph = m_pCurGraph; if(!pGraph) return; if(m_iView==WOPPVIEW) { grDlg.m_iGraphType = 61; } else if(m_iView==WPOLARVIEW) { grDlg.m_iGraphType = 62; } else if(m_iView==WCPVIEW) grDlg.m_iGraphType = 64; if(!pGraph) return; QGraph graph; graph.CopySettings(pGraph); grDlg.m_pMemGraph = &graph; grDlg.m_pGraph = pGraph; grDlg.SetParams(); if(grDlg.exec() == QDialog::Accepted) { if(m_iView==WOPPVIEW) { if(grDlg.m_bVariableChanged) { m_pCurGraph->SetAutoY(true); m_pCurGraph->SetAutoYMinUnit(true); } CreateWOppCurves(); } else if(m_iView==WPOLARVIEW) { if(pGraph == m_WPlrGraph) SetWGraphTitles(m_WPlrGraph); else if(pGraph == m_WPlrGraph+1) SetWGraphTitles(m_WPlrGraph+1); else if(pGraph == m_WPlrGraph+2) SetWGraphTitles(m_WPlrGraph+2); else if(pGraph == m_WPlrGraph+3) SetWGraphTitles(m_WPlrGraph+3); if(grDlg.m_bVariableChanged) { m_pCurGraph->SetAuto(true); m_pCurGraph->SetAutoYMinUnit(true); } CreateWPolarCurves(); } else if(m_iView==WSTABVIEW) { CreateStabilityCurves(); SetStabGraphTitles(); } } else { pGraph->CopySettings(&graph); } UpdateView(); } /** * The user has toggled the display of the half-wing in the OpPoint view */ void QMiarex::OnHalfWing() { m_bHalfWing = !m_bHalfWing; if(m_iView==WOPPVIEW) { m_bIs2DScaleSet = false; SetWGraphScale(); Set2DScale(); OnAdjustToWing(); UpdateView(); } SetControls(); } /** * The user has requested that all polars curves be hidden */ void QMiarex::OnHideAllWPolars() { int i; WPolar *pWPolar; for (i=0; isize(); i++) { pWPolar = (WPolar*)m_poaWPolar->at(i); pWPolar->m_bIsVisible = false; if(pWPolar->m_WPolarType==STABILITYPOLAR) pWPolar->m_bShowPoints = false; } if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); MainFrame::SetSaveState(false); SetCurveParams(); UpdateView(); } /** * The user has requested that all curves of the oppoints associated to the active polar be hidden */ void QMiarex::OnHideAllWPlrOpps() { int i; m_bCurWOppOnly = false; PlaneOpp *pPOpp; WingOpp *pWOpp; if(m_pCurPlane) { for (i=0; i< m_poaPOpp->size(); i++) { pPOpp = (PlaneOpp*)m_poaPOpp->at(i); if (pPOpp->m_PlaneName == m_pCurWPolar->m_UFOName && pPOpp->m_PlrName == m_pCurWPolar->m_PlrName) { pPOpp->m_bIsVisible = false; } } } else if (m_pCurWing) { for (i=0; i< m_poaWOpp->size(); i++) { pWOpp = (WingOpp*)m_poaWOpp->at(i); if (pWOpp->m_WingName == m_pCurWPolar->m_UFOName && pWOpp->m_PlrName == m_pCurWPolar->m_PlrName) { pWOpp->m_bIsVisible = false; } } } MainFrame::SetSaveState(false); SetCurveParams(); if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); UpdateView(); } /** * The user has requested that all oppoint curves be hidden */ void QMiarex::OnHideAllWOpps() { int i; m_bCurWOppOnly = false; PlaneOpp *pPOpp; WingOpp *pWOpp; for (i=0; i< m_poaWOpp->size(); i++) { pWOpp = (WingOpp*)m_poaWOpp->at(i); pWOpp->m_bIsVisible = false; } for (i=0; i< m_poaPOpp->size(); i++) { pPOpp = (PlaneOpp*)m_poaPOpp->at(i); pPOpp->m_bIsVisible = false; } MainFrame::SetSaveState(false); SetCurveParams(); if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); UpdateView(); } /** * The user has requested that all curves of the oppoints associated to the active wing or plane be hidden */ void QMiarex::OnHideUFOWOpps() { PlaneOpp *pPOpp; WingOpp *pWOpp; int i; for (i=0; i< m_poaWOpp->size(); i++) { pWOpp = (WingOpp*)m_poaWOpp->at(i); if (pWOpp->m_WingName == m_pCurWPolar->m_UFOName) { pWOpp->m_bIsVisible = false; } } for (i=0; i< m_poaPOpp->size(); i++) { pPOpp = (PlaneOpp*)m_poaPOpp->at(i); if (pPOpp->m_PlaneName == m_pCurWPolar->m_UFOName) { pPOpp->m_bIsVisible = false; } } if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); MainFrame::SetSaveState(false); SetCurveParams(); UpdateView(); } /** * The user has requested that all curves of the oppoints associated to the active polar be hidden */ void QMiarex::OnHideUFOWPolars() { if(!m_pCurWing) return; int i; QString UFOName; if(m_pCurPlane) UFOName = m_pCurPlane->PlaneName(); else if(m_pCurWing) UFOName = m_pCurWing->WingName(); else return; WPolar *pWPolar; for (i=0; isize(); i++) { pWPolar = (WPolar*)m_poaWPolar->at(i); if (pWPolar->m_UFOName == UFOName) { pWPolar->m_bIsVisible = false; if(pWPolar->m_WPolarType==STABILITYPOLAR) pWPolar->m_bShowPoints = false; } } if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); SetCurveParams(); MainFrame::SetSaveState(false); UpdateView(); } /** * The user has requested that the current point be highlighted in the selected graph *@todo not quite robust - check and improve */ void QMiarex::OnHighlightWOpp() { if(m_iView!=WPOLARVIEW && !(m_iView==WSTABVIEW && m_iStabilityView==STABPOLARVIEW)) return; m_bHighlightOpp = !m_bHighlightOpp; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->highlightWOppAct->setChecked(m_bHighlightOpp); for(int ig=0; ig<4; ig++) m_WPlrGraph[ig].m_bHighlightPoint = m_bHighlightOpp; if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); UpdateView(); } /** * The user has requested the import of a polar definition from a text file. * Createss a new CWPolar object, fills it with the data from the text file, and adds it to the array *@todo not used often, nor thouroughly tested */ void QMiarex::OnImportWPolar() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; WPolar *pWPolar = new WPolar; bool bOK; QString PolarName, UFOName; QString strong, str; QString PathName; QByteArray textline; const char *text; PathName = QFileDialog::getOpenFileName(pMainFrame, tr("Open File"), MainFrame::s_LastDirName, tr("UFO Polar Format (*.*)")); if(!PathName.length()) return ; int pos = PathName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = PathName.left(pos); QFile XFile(PathName); if (!XFile.open(QIODevice::ReadOnly)) { QString strange = tr("Could not read the file\n")+PathName; QMessageBox::warning(pMainFrame, tr("Warning"), strange); return; } QTextStream in(&XFile); int res, Line; Line = 0; bool bRead; bRead = ReadAVLString(in, Line, strong);// XFoil or XFLR5 version bRead = ReadAVLString(in, Line, strong);// UFO Name UFOName = strong.right(strong.length()-19); UFOName = UFOName.trimmed(); Plane *pPlane = GetPlane(UFOName); Wing *pWing = GetWing(UFOName); if(!pWing && !pPlane) { str = tr("No UFO with the name ")+UFOName; str+= tr("\ncould be found. The polar(s) will not be stored"); delete pWPolar; QMessageBox::warning(pMainFrame, tr("Warning"), str); return; } pWPolar->m_UFOName = UFOName; bRead = ReadAVLString(in, Line, strong);// Polar Name PolarName = strong.right(strong.length()-19); pWPolar->m_PlrName = PolarName; bRead = ReadAVLString(in, Line, strong);// Freestream speed pWPolar->m_QInf = strong.toDouble(&bOK)/MainFrame::s_mstoUnit; bRead = ReadAVLString(in, Line, strong);// " alpha CL ICd ..." bRead = ReadAVLString(in, Line, strong);// " _________ ________ ________ ..." double alpha, CL, ICd, PCd, TCd, CY, GCm, GRm, GYm, IYm, QInf, XCP; while( bRead) { bRead = ReadAVLString(in, Line, strong);// polar data if(bRead) { if(strong.length()) { textline = strong.toLatin1(); text = textline.constData(); res = sscanf(text, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", &alpha, &CL, &ICd, &PCd, &TCd, &CY, &GCm, &GRm, &GYm, &IYm, &QInf, &XCP); if (res >0) { pWPolar->AddPoint(alpha, CL, ICd, PCd, CY, GCm, 0.0, 0.0, GRm, GYm, IYm, QInf, XCP); } else { bRead = false; } } } } pWPolar->m_Color = pMainFrame->GetColor(4); m_pCurWPolar = AddWPolar(pWPolar); m_pCurWOpp = NULL; SetWPolar(pWPolar); pMainFrame->UpdateWPolars(); UpdateView(); MainFrame::SetSaveState(false); } /** * Toggles the flag which requests the initialization of the start parameters at the launch of an LLT analysis */ void QMiarex::OnInitLLTCalc() { m_bInitLLTCalc = m_pctrlInitLLTCalc->isChecked(); } /** * The user has requested to store the active curve in the Cp graph display * Duplicates the curve and adds it to the graph */ void QMiarex::OnKeepCpSection() { Curve *pCurve, *pNewCurve; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; pCurve = m_CpGraph.GetCurve(0); pNewCurve = m_CpGraph.AddCurve(); pNewCurve->CopyData(pCurve); pNewCurve->SetTitle(pCurve->title()); m_CpColor = pMainFrame->m_ColorList[(m_CpGraph.GetCurveCount())%24]; pCurve->SetColor(m_CpColor); m_CpStyle = 0; m_CpWidth = 1; m_bShowCpPoints = false; SetCurveParams(); CreateCpCurves(); UpdateView(); } /** * The user has modified the scale of the lift display */ void QMiarex::OnLiftScale(int pos) { m_LiftScale = pos/100.0/sqrt(1.01-pos/100.0); m_bResetglLift = true; UpdateView(); } /** * The user has toggled the switch of the light - much like in real life ? */ void QMiarex::OnLight() { GLLightDlg::s_bLight = m_pctrlLight->isChecked(); // m_bResetglGeom = true; UpdateView(); } /** * The user has requested the launch of the dialog box used to manage the array of planes */ void QMiarex::OnManageUFOs() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QString UFOName = ""; if(m_pCurPlane) UFOName = m_pCurPlane->PlaneName(); else if(m_pCurWing) UFOName = m_pCurWing->WingName(); ManageUFOsDlg uDlg(pMainFrame); uDlg.InitDialog(UFOName); uDlg.exec(); if(uDlg.m_pPlane) SetUFO(uDlg.m_pPlane->PlaneName()); else if(uDlg.m_pWing) SetUFO(uDlg.m_pWing->m_WingName); else SetUFO(); pMainFrame->UpdateUFOs(); SetControls(); m_bResetglGeom = true; m_bResetglMesh = true; UpdateView(); } /** * The user has toggled the display of moments in the 3D view **/ void QMiarex::OnMoment() { m_bMoments = m_pctrlMoment->isChecked(); UpdateView(); } /** * The user has requested the creation of a new wing. * Launches the dialog box, and stores the wing in the array i.a.w. user instructions */ void QMiarex::OnNewWing() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; int i; Wing *pOldWing; Wing* pWing = new Wing; GL3dWingDlg wingDlg(pMainFrame); wingDlg.m_bAcceptName= true; if(!wingDlg.InitDialog(pWing)) return; if(QDialog::Accepted == wingDlg.exec()) { MainFrame::SetSaveState(false); bool bExists = false; for(i=0; isize(); i++) { pOldWing = (Wing*)m_poaWing->at(i); if(pWing->m_WingName == pOldWing->m_WingName) { bExists = true; break; } } if(bExists) { if(!SetModWing(pWing)) { delete pWing; SetControls(); return; } } m_pCurWing = AddWing(pWing); MainFrame::SetSaveState(false); m_pCurPlane = NULL; SetUFO(); pMainFrame->UpdateUFOs(); m_bIs2DScaleSet = false; SetScale(); if(m_iView==WOPPVIEW) OnAdjustToWing(); SetWGraphScale(); SetControls(); UpdateView(); } else { delete pWing; } SetControls(); } /** * The user has requested the creation of a new plane. * Launches the dialog box, and stores the plane in the array i.a.w. user instructions */ void QMiarex::OnNewPlane() { int i; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; Plane* pPlane = new Plane; Plane* pOldPlane = NULL; PlaneDlg plDlg(pMainFrame); plDlg.m_pPlane = pPlane; plDlg.m_bAcceptName = true; plDlg.InitDialog(); if(QDialog::Accepted == plDlg.exec()) { MainFrame::SetSaveState(false); bool bExists = false; for(i=0; isize(); i++) { pOldPlane = (Plane*)m_poaPlane->at(i); if(pPlane->PlaneName() == pOldPlane->PlaneName()) { bExists = true; break; } } if(bExists) { if(!SetModPlane(pPlane)) { delete pPlane; SetControls(); return; } } m_pCurPlane = AddPlane(pPlane); SetUFO(); m_bResetglLegend = true; pMainFrame->UpdateUFOs(); } else { delete pPlane; } SetControls(); UpdateView(); } /** *The user has toggled the switch for the display of the outline of the surfaces in 3D view */ void QMiarex::OnOutline() { s_bOutline = m_pctrlOutline->isChecked(); UpdateView(); } /** *The user has toggled the switch for the display of the panels in 3D view */ void QMiarex::OnPanels() { s_bVLMPanels = m_pctrlPanels->isChecked(); UpdateView(); } /** * Reads the analysis input from the dialog boxes */ void QMiarex::OnReadAnalysisData() { m_bSequence = m_pctrlSequence->isChecked(); m_bInitLLTCalc = m_pctrlInitLLTCalc->isChecked(); if(m_pCurWPolar && m_pCurWPolar->m_WPolarType==FIXEDAOAPOLAR) { m_QInfMin = m_pctrlAlphaMin->Value() /MainFrame::s_mstoUnit; m_QInfMax = m_pctrlAlphaMax->Value() /MainFrame::s_mstoUnit; m_QInfDelta = qAbs(m_pctrlAlphaDelta->Value()) /MainFrame::s_mstoUnit; if(qAbs(m_QInfDelta)<0.1) { m_QInfDelta = 1.0; m_pctrlAlphaDelta->SetValue(1.0); } } else if(m_pCurWPolar && m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { m_ControlMin = m_pctrlAlphaMin->Value(); m_ControlMax = m_pctrlAlphaMax->Value(); m_ControlDelta = qAbs(m_pctrlAlphaDelta->Value()); if(qAbs(m_ControlDelta)<0.001) { m_ControlDelta = 0.001; m_pctrlAlphaDelta->SetValue(0.001); } } else if(m_pCurWPolar) { m_AlphaMin = m_pctrlAlphaMin->Value(); m_AlphaMax = m_pctrlAlphaMax->Value(); m_AlphaDelta = qAbs(m_pctrlAlphaDelta->Value()); if(qAbs(m_AlphaDelta)<0.01) { m_AlphaDelta = 0.01; m_pctrlAlphaDelta->SetValue(0.01); } } } /** * The user has requested a change to the type of polars which ought to be displayed */ void QMiarex::OnPolarFilter() { PolarFilterDlg pfDlg((MainFrame*)s_pMainFrame); pfDlg.m_bMiarex = true; pfDlg.m_bType1 = m_bType1; pfDlg.m_bType2 = m_bType2; pfDlg.m_bType4 = m_bType4; pfDlg.m_bType5 = m_bType5; pfDlg.m_bType6 = m_bType6; pfDlg.m_bType7 = m_bType7; pfDlg.InitDialog(); if(pfDlg.exec()==QDialog::Accepted) { m_bType1 = pfDlg.m_bType1; m_bType2 = pfDlg.m_bType2; m_bType4 = pfDlg.m_bType4; m_bType5 = pfDlg.m_bType5; m_bType6 = pfDlg.m_bType6; m_bType7 = pfDlg.m_bType7; if(m_iView==WPOLARVIEW) { CreateWPolarCurves(); UpdateView(); } else if(m_iView==WSTABVIEW) { CreateStabilityCurves(); UpdateView(); } } } /** * The user has requested that the active polar be renames * Changes the polar name and updates the references in all child oppoints */ void QMiarex::OnRenameCurWPolar() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(!m_pCurWPolar) return; if(!m_pCurWing) return; int resp, k,l; WPolar* pWPolar = NULL; PlaneOpp * pPOpp = NULL; WingOpp * pWOpp = NULL; QString OldName = m_pCurWPolar->m_PlrName; QString UFOName; if(m_pCurPlane) UFOName = m_pCurPlane->PlaneName(); else if(m_pCurWing) UFOName = m_pCurWing->WingName(); QStringList NameList; for(k=0; ksize(); k++) { pWPolar = (WPolar*)m_poaWPolar->at(k); if(pWPolar->m_UFOName==UFOName) NameList.append(pWPolar->m_PlrName); } RenameDlg renDlg(pMainFrame); renDlg.m_pstrArray = & NameList; renDlg.m_strQuestion = tr("Enter the new name for the wing polar :"); renDlg.m_strName = m_pCurWPolar->m_PlrName; renDlg.InitDialog(); bool bExists = true; while (bExists) { resp = renDlg.exec(); if(resp==QDialog::Accepted) { if (OldName == renDlg.m_strName) return; //Is the new name already used ? bExists = false; for (k=0; ksize(); k++) { pWPolar = (WPolar*)m_poaWPolar->at(k); if (pWPolar->m_PlrName == renDlg.m_strName && pWPolar->m_UFOName == m_pCurWing->WingName()) { bExists = true; break; } } if(!bExists) { m_pCurWPolar->m_PlrName = renDlg.m_strName; if(m_pCurPlane) { for (l=m_poaPOpp->size()-1;l>=0; l--) { pPOpp = (PlaneOpp*)m_poaPOpp->at(l); if (pPOpp->m_PlrName == OldName && pPOpp->m_PlaneName == m_pCurPlane->PlaneName()) { pPOpp->m_PlrName = renDlg.m_strName; } } } for (l=m_poaWOpp->size()-1;l>=0; l--) { pWOpp = (WingOpp*)m_poaWOpp->at(l); if (pWOpp->m_PlrName == OldName && pWOpp->m_WingName == m_pCurWing->WingName()) { pWOpp->m_PlrName = renDlg.m_strName; } } } //put the Wplr at its new place in alphabetical order //so find the current polar's index for (k=0; ksize(); k++) if(m_pCurWPolar==m_poaWPolar->at(k)) break; if(ksize())//you never know { //remove the WPolar m_poaWPolar->removeAt(k); //And re-insert it bool bInserted = false; for (k=0; ksize(); k++) { pWPolar = (WPolar*)m_poaWPolar->at(k); if (m_pCurWPolar->m_PlrName.compare(pWPolar->m_PlrName, Qt::CaseInsensitive)<0 && pWPolar->m_UFOName == m_pCurWing->WingName()) { m_poaWPolar->insert(k, m_pCurWPolar); bInserted = true; break; } } if(!bInserted) { m_poaWPolar->append(m_pCurWPolar); } } MainFrame::SetSaveState(false); } else if(resp ==10) { //user wants to overwrite if (OldName == renDlg.m_strName) return; for (k=0; ksize(); k++) { pWPolar = (WPolar*)m_poaWPolar->at(k); if (pWPolar->m_PlrName == renDlg.m_strName && pWPolar->m_UFOName == m_pCurWing->WingName()) { bExists = true; break; } } for (l=m_poaWOpp->size()-1;l>=0; l--) { pWOpp = (WingOpp*)m_poaWOpp->at(l); if (pWOpp->m_PlrName == pWPolar->m_PlrName && pWOpp->m_WingName == m_pCurWing->WingName()) { m_poaWOpp->removeAt(l); if(pWOpp==m_pCurWOpp) { m_pCurPOpp = NULL; m_pCurWOpp = NULL; } delete pWOpp; } } m_poaWPolar->removeAt(k); if(pWPolar==m_pCurWPolar) { m_pCurWPolar = NULL; } delete pWPolar; //and rename everything m_pCurWPolar->m_PlrName = renDlg.m_strName; for (l=m_poaWOpp->size()-1;l>=0; l--) { pWOpp = (WingOpp*)m_poaWOpp->at(l); if (pWOpp->m_PlrName == OldName && pWOpp->m_WingName == m_pCurWing->WingName()) { pWOpp->m_PlrName = renDlg.m_strName; } } bExists = false; MainFrame::SetSaveState(false); } else { return ;//cancelled } } // SetWPlr(); pMainFrame->UpdateWPolars(); UpdateView(); } /** * The user has requested that the active wing ot plane be renames * Changes the name and updates the references in all child polars and oppoints */ void QMiarex::OnRenameCurUFO() { //Rename the currently selected UFO MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(!m_pCurWing) return; if(m_pCurPlane) RenameUFO(m_pCurPlane->PlaneName()); else if (m_pCurWing) RenameUFO(m_pCurWing->WingName()); pMainFrame->UpdateUFOs(); m_bResetglLegend = true; UpdateView(); } /** * The user has requested a deletion of all the previously stored curves in the Cp Graph */ void QMiarex::OnResetCpSection() { for(int i=m_CpGraph.GetCurveCount()-1; i>3 ;i--) m_CpGraph.DeleteCurve(i); CreateCpCurves(); UpdateView(); } /** * The user has requested that the results data of the current CWPolar object be deleted. * Deletes it and all its child operating points, and updates the graphs */ void QMiarex::OnResetCurWPolar() { if (!m_pCurWPolar) return; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QString strong = tr("Are you sure you want to reset the content of the polar :\n")+ m_pCurWPolar->m_PlrName +"?\n"; if (QMessageBox::Yes != QMessageBox::question(pMainFrame, tr("Question"), strong, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Cancel)) return; m_pCurWPolar->ResetWPlr(); PlaneOpp *pPOpp; WingOpp *pWOpp; if(m_pCurWing) { for(int i=m_poaWOpp->size()-1; i>=0; --i) { pWOpp = (WingOpp*) m_poaWOpp->at(i); if(pWOpp->m_PlrName==m_pCurWPolar->m_PlrName && pWOpp->m_WingName==m_pCurWing->WingName()) { m_poaWOpp->removeAt(i); delete pWOpp; } } } if(m_pCurPlane) { for(int i=m_poaPOpp->size()-1; i>=0; --i) { pPOpp = (PlaneOpp*) m_poaPOpp->at(i); if(pPOpp->m_PlrName==m_pCurWPolar->m_PlrName && pPOpp->m_PlaneName==m_pCurPlane->PlaneName()) { m_poaPOpp->removeAt(i); delete pPOpp; } } } pMainFrame->UpdateWOpps(); m_pCurWOpp = NULL; m_pCurPOpp = NULL; if(m_iView==WPOLARVIEW) { CreateWPolarCurves(); if(m_pCurWPolar) { QString PolarProps; m_pCurWPolar->GetPolarProperties(PolarProps); m_pctrlPolarProps1->setText(PolarProps); } } else if(m_iView==WSTABVIEW) CreateStabilityCurves(); else if(m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); MainFrame::SetSaveState(false); UpdateView(); } /** * The user has requested that the wing scale be reset to its default value in the operating point graph view */ void QMiarex::OnResetWingGraphScale() { //resets the scale of the current graph if(!m_pCurGraph) return; m_pCurGraph->SetAuto(true); m_pCurGraph->ResetXLimits(); m_pCurGraph->ResetYLimits(); if (m_pCurGraph == &m_WingGraph[0] || m_pCurGraph == &m_WingGraph[1] || m_pCurGraph == &m_WingGraph[2] || m_pCurGraph == &m_WingGraph[3]) { m_pCurGraph->SetAutoX(false); double halfspan = m_pCurWing->m_PlanformSpan/2.0; if(m_bHalfWing) m_pCurGraph->SetXMin(0.0); else m_pCurGraph->SetXMin(-halfspan*MainFrame::s_mtoUnit); m_pCurGraph->SetXMax( halfspan*MainFrame::s_mtoUnit); } UpdateView(); } /** * The user has requested that the wing scale be reset to its default value in the 3D view */ void QMiarex::OnResetWingScale() { m_bIs2DScaleSet = false; Set2DScale(); UpdateView(); } /** * The user has requested that the position of the legend be reset to its default in the operating point graph view */ void QMiarex::OnResetWOppLegend() { SetWingLegendPos(); UpdateView(); } /** * The user has requested that the position of the legend be reset to its default in the polar graph view */ void QMiarex::OnResetWPlrLegend() { SetWPlrLegendPos(); UpdateView(); } /** * The user has requested that the size of the active wing be scaled. * Launches the dialog box, creates a new wing, and overwrites the existing wing or plane, * or creates a new one i.a.w. user instructions. */ void QMiarex::OnScaleWing() { if(!m_pCurWing) return; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; WingScaleDlg wsDlg(pMainFrame); wsDlg.InitDialog(m_pCurWing->m_PlanformSpan, m_pCurWing->Chord(0), m_pCurWing->AverageSweep(), m_pCurWing->TipTwist()); if(QDialog::Accepted == wsDlg.exec()) { if (wsDlg.m_bSpan || wsDlg.m_bChord || wsDlg.m_bSweep || wsDlg.m_bTwist) { if(m_pCurPlane) { Plane *pNewPlane = new Plane; pNewPlane->Duplicate(m_pCurPlane); if(wsDlg.m_bSpan) pNewPlane->wing()->ScaleSpan(wsDlg.m_NewSpan); if(wsDlg.m_bChord) pNewPlane->wing()->ScaleChord(wsDlg.m_NewChord); if(wsDlg.m_bSweep) pNewPlane->wing()->ScaleSweep(wsDlg.m_NewSweep); if(wsDlg.m_bTwist) pNewPlane->wing()->ScaleTwist(wsDlg.m_NewTwist); pNewPlane->ComputePlane(); if(SetModPlane(pNewPlane)) { m_pCurPlane = AddPlane(pNewPlane); m_pCurWPolar = NULL; m_pCurPOpp = NULL; m_pCurWOpp = NULL; } else delete pNewPlane; } else { Wing* pNewWing = new Wing; pNewWing->Duplicate(m_pCurWing); if(wsDlg.m_bSpan) pNewWing->ScaleSpan(wsDlg.m_NewSpan); if(wsDlg.m_bChord) pNewWing->ScaleChord(wsDlg.m_NewChord); if(wsDlg.m_bSweep) pNewWing->ScaleSweep(wsDlg.m_NewSweep); if(wsDlg.m_bTwist) pNewWing->ScaleTwist(wsDlg.m_NewTwist); if(AddWing(pNewWing)) { m_pCurWing = pNewWing; m_pCurWPolar = NULL; m_pCurPOpp = NULL; m_pCurWOpp = NULL; } else delete pNewWing; } SetUFO(); pMainFrame->UpdateUFOs(); } if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); else if(m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); UpdateView(); } } /** * The user has toggled the switch for a sequential analyis */ void QMiarex::OnSequence() { m_bSequence = m_pctrlSequence->isChecked(); m_pctrlAlphaMax->setEnabled(m_bSequence); m_pctrlAlphaDelta->setEnabled(m_bSequence); } /** * The user has requested the display of all the operating point curves */ void QMiarex::OnShowAllWOpps() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; int i; //Switch all WOpps view to on for all UFO and WPolar m_bCurWOppOnly = false; pMainFrame->showCurWOppOnly->setChecked(false); PlaneOpp *pPOpp; WingOpp *pWOpp; for (i=0; i< m_poaWOpp->size(); i++) { pWOpp = (WingOpp*)m_poaWOpp->at(i); pWOpp->m_bIsVisible = true; } for (i=0; i< m_poaPOpp->size(); i++) { pPOpp = (PlaneOpp*)m_poaPOpp->at(i); pPOpp->m_bIsVisible = true; } MainFrame::SetSaveState(false); SetCurveParams(); if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); UpdateView(); } /** * The user has requested the display of all the polar curves */ void QMiarex::OnShowAllWPolars() { int i; WPolar *pWPolar; for (i=0; isize(); i++) { pWPolar = (WPolar*)m_poaWPolar->at(i); pWPolar->m_bIsVisible = true; } if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); MainFrame::SetSaveState(false); SetCurveParams(); UpdateView(); } /** * The user has requested the display exclusively of all the polar curves associated to the active wing or plane. * The display of all other polar curves is turned off */ void QMiarex::OnShowUFOWPolarsOnly() { if(!m_pCurWing) return; int i; QString UFOName; if(m_pCurPlane) UFOName = m_pCurPlane->PlaneName(); else if(m_pCurWing) UFOName = m_pCurWing->WingName(); else return; WPolar *pWPolar; for (i=0; isize(); i++) { pWPolar = (WPolar*)m_poaWPolar->at(i); pWPolar->m_bIsVisible = (pWPolar->m_UFOName == UFOName); } if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); SetCurveParams(); MainFrame::SetSaveState(false); UpdateView(); } /** * The user has requested the display of all the polar curves associated to the active wing or plane */ void QMiarex::OnShowUFOWPolars() { if(!m_pCurWing) return; int i; QString UFOName; if(m_pCurPlane) UFOName = m_pCurPlane->PlaneName(); else if(m_pCurWing) UFOName = m_pCurWing->WingName(); else return; WPolar *pWPolar; for (i=0; isize(); i++) { pWPolar = (WPolar*)m_poaWPolar->at(i); if (pWPolar->m_UFOName == UFOName) pWPolar->m_bIsVisible = true; } if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); SetCurveParams(); MainFrame::SetSaveState(false); UpdateView(); } /** * The user has requested the display of all the operating point curves for the active wing or plane */ void QMiarex::OnShowUFOWOpps() { PlaneOpp *pPOpp; WingOpp *pWOpp; int i; for (i=0; i< m_poaWOpp->size(); i++) { pWOpp = (WingOpp*)m_poaWOpp->at(i); if (pWOpp->m_WingName == m_pCurWPolar->m_UFOName) { pWOpp->m_bIsVisible = true; } } for (i=0; i< m_poaPOpp->size(); i++) { pPOpp = (PlaneOpp*)m_poaPOpp->at(i); if (pPOpp->m_PlaneName == m_pCurWPolar->m_UFOName) { pPOpp->m_bIsVisible = true; } } if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); MainFrame::SetSaveState(false); SetCurveParams(); UpdateView(); } /** * The user has requested the display of all the operating point curves for the active polar */ void QMiarex::OnShowAllWPlrOpps() { int i; //Switch all WOpps view to on for the current UFO and WPolar m_bCurWOppOnly = false; PlaneOpp *pPOpp; WingOpp *pWOpp; if(m_pCurPlane) { for (i=0; i< m_poaPOpp->size(); i++) { pPOpp = (PlaneOpp*)m_poaPOpp->at(i); if (pPOpp->m_PlaneName == m_pCurWPolar->m_UFOName && pPOpp->m_PlrName == m_pCurWPolar->m_PlrName) { pPOpp->m_bIsVisible = true; } } } else if (m_pCurWing) { for (i=0; i< m_poaWOpp->size(); i++) { pWOpp = (WingOpp*)m_poaWOpp->at(i); if (pWOpp->m_WingName == m_pCurWPolar->m_UFOName && pWOpp->m_PlrName == m_pCurWPolar->m_PlrName) { pWOpp->m_bIsVisible = true; } } } MainFrame::SetSaveState(false); SetCurveParams(); if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); UpdateView(); } /** * The user has toggled the display of the elliptic curve in the lift graph in the operating point view */ void QMiarex::OnShowEllipticCurve() { m_bShowElliptic = !m_bShowElliptic; // CheckMenus(); CreateWOppCurves(); UpdateView(); } /** * The user has toggled the display of the moment reference point in the operating point view */ void QMiarex::OnShowXCmRef() { //Show the Moment reference point m_bXCmRef = !m_bXCmRef; UpdateView(); } /** * The user has toggled the display of the forces acting on the panels in the 3D view */ void QMiarex::OnPanelForce() { m_bPanelForce = m_pctrlPanelForce->isChecked(); if(m_bPanelForce) { m_b3DCp =false; m_pctrlCp->setChecked(false); } if(m_iView == W3DVIEW) { if(!m_bAnimateWOpp) UpdateView(); } } /** * The user has toggled the display of the lift in the operating point view or in the 3D view */ void QMiarex::OnShowLift() { m_bXCP = m_pctrlLift->isChecked(); if(m_iView==WOPPVIEW || m_iView == W3DVIEW) { if(!m_bAnimateWOpp) UpdateView(); } } /** * The user has toggled the display of the induced drag forces in the 3D view */ void QMiarex::OnShowIDrag() { m_bICd = m_pctrlIDrag->isChecked(); m_bResetglDrag = true; if(m_iView==WOPPVIEW || m_iView == W3DVIEW) { if(!m_bAnimateWOpp) UpdateView(); } } /** * The user has toggled the display of the viscous drag forces in the 3D view */ void QMiarex::OnShowVDrag() { m_bVCd = m_pctrlVDrag->isChecked(); m_bResetglDrag = true; if(m_iView==WOPPVIEW || m_iView == W3DVIEW) { if(!m_bAnimateWOpp) UpdateView(); } } /** * The user has toggled the display of the laminar to turbulent transition lines in the 3D view */ void QMiarex::OnShowTransitions() { m_bXTop = m_pctrlTrans->isChecked(); m_bXBot = m_pctrlTrans->isChecked(); if(m_iView==WOPPVIEW || m_iView == W3DVIEW) { if(!m_bAnimateWOpp) UpdateView(); } } /** * The user has toggled the display of the active curve */ void QMiarex::OnShowCurve() { m_bCurveVisible = m_pctrlShowCurve->isChecked(); m_bCurvePoints = m_pctrlShowPoints->isChecked(); UpdateCurve(); } /** * The user has requested the display of the top left graph only **/ void QMiarex::OnSingleGraph1() { if(m_iView==WSTABVIEW) { m_iStabilityView = STABTIMEVIEW; m_iStabTimeView = 1; m_pCurGraph = m_TimeGraph; m_pCurTimeGraph= m_pCurGraph; SetWingLegendPos(); UpdateView(); } else if(m_iView==WOPPVIEW) { m_iWingView = 1; m_pCurGraph = m_WingGraph; m_pCurWingGraph= m_pCurGraph; SetWingLegendPos(); UpdateView(); } else if(m_iView==WPOLARVIEW) { m_iWPlrView = ONEPOLARGRAPH; m_pCurGraph = m_WPlrGraph; m_pCurWPlrGraph = m_pCurGraph; SetWPlrLegendPos(); UpdateView(); } else return; SetControls(); } /** * The user has requested the display of the top right graph only **/ void QMiarex::OnSingleGraph2() { if(m_iView==WSTABVIEW) { m_iStabilityView = STABTIMEVIEW; m_iStabTimeView = 1; m_pCurGraph = m_TimeGraph+1; m_pCurTimeGraph= m_pCurGraph; SetWingLegendPos(); UpdateView(); } else if(m_iView==WOPPVIEW) { m_iWingView = 1; m_pCurGraph = m_WingGraph+1; m_pCurWingGraph= m_pCurGraph; SetWingLegendPos(); UpdateView(); } else if(m_iView==WPOLARVIEW) { m_iWPlrView = ONEPOLARGRAPH; m_pCurGraph = m_WPlrGraph+1; m_pCurWPlrGraph = m_pCurGraph; SetWPlrLegendPos(); UpdateView(); } else return; SetControls(); } /** * The user has requested the display of the bottom left graph only **/ void QMiarex::OnSingleGraph3() { if(m_iView==WSTABVIEW) { m_iStabilityView = STABTIMEVIEW; m_iStabTimeView = 1; m_pCurGraph = m_TimeGraph+2; m_pCurTimeGraph= m_pCurGraph; SetWingLegendPos(); } else if(m_iView==WOPPVIEW) { m_iWingView = 1; m_pCurGraph = m_WingGraph+2; m_pCurWingGraph= m_pCurGraph; SetWingLegendPos(); } else if(m_iView==WPOLARVIEW) { m_iWPlrView = ONEPOLARGRAPH; m_pCurGraph = m_WPlrGraph+2; m_pCurWPlrGraph = m_pCurGraph; SetWPlrLegendPos(); } else return; UpdateView(); SetControls(); } /** * The user has requested the display of the bottom right graph only **/ void QMiarex::OnSingleGraph4() { if(m_iView==WSTABVIEW) { m_iStabilityView = STABTIMEVIEW; m_iStabTimeView = 1; m_pCurGraph = m_TimeGraph+3; m_pCurTimeGraph= m_pCurGraph; SetWingLegendPos(); } else if(m_iView==WOPPVIEW) { m_iWingView = 1; m_pCurGraph = m_WingGraph+3; m_pCurWingGraph= m_pCurGraph; SetWingLegendPos(); } else if(m_iView==WPOLARVIEW) { m_iWPlrView = ONEPOLARGRAPH; m_pCurGraph = m_WPlrGraph+3; m_pCurWPlrGraph = m_pCurGraph; SetWPlrLegendPos(); } else return; UpdateView(); SetControls(); } /** * The user has toggled the display of stability results between longitudinal and lateral directions */ void QMiarex::OnStabilityDirection() { //the user has clicked either the longitudinal or lateral mode display //so update the view accordingly MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; m_bLongitudinal = pStabView->m_pctrlLongDynamics->isChecked(); for(int ig=0; ig<4; ig++) m_TimeGraph[ig].DeleteCurves(); pStabView->m_pCurve = NULL; pStabView->FillCurveList(); if(m_bLongitudinal) m_pCurRLStabGraph = &m_LongRLGraph; else m_pCurRLStabGraph = &m_LatRLGraph; if(m_iStabilityView==STABPOLARVIEW) { m_pCurGraph = m_pCurRLStabGraph; } pStabView->SetMode(); pStabView->SetControls(); SetStabGraphTitles(); SetWPlrLegendPos(); CreateStabilityCurves(); SetCurveParams(); SetControls(); UpdateView(); } /** * The user has requested to change the display of stability results to the time view */ void QMiarex::OnTimeView() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; StopAnimate(); m_iView = WSTABVIEW; m_iStabilityView = STABTIMEVIEW; pStabView->SetControls(); SetWingLegendPos(); CreateStabilityCurves(); pMainFrame->SetCentralWidget(); SetCurveParams(); SetControls(); UpdateView(); } /** * The user has requested to change the display of stability results to the root locus view */ void QMiarex::OnRootLocusView() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StopAnimate(); m_iView = WSTABVIEW; m_iStabilityView = STABPOLARVIEW; SetWPlrLegendPos(); CreateStabilityCurves(); pMainFrame->SetCentralWidget(); SetCurveParams(); SetControls(); UpdateView(); } /** * The user has requested to change the display of stability results to the modal view */ void QMiarex::OnModalView() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; m_iView = WSTABVIEW; m_iStabilityView = STAB3DVIEW; pMainFrame->SetCentralWidget(); SetCurveParams(); SetControls(); UpdateView(); } /** * The user has toggled the display of the streamlines in the 3D view */ void QMiarex::OnStreamlines() { m_bStream = m_pctrlStream->isChecked(); if(m_pctrlStream->isChecked()) { // m_bResetglStream = true; } if(m_iView==W3DVIEW) UpdateView(); } /** * The user has toggled the display of the surfaces in the 3D view */ void QMiarex::OnSurfaces() { s_bSurfaces = m_pctrlSurfaces->isChecked(); if(s_bSurfaces) { m_b3DCp = false; m_pctrlCp->setChecked(false); } UpdateView(); } /** * The user has toggled the display of the velocity vectors on the surfaces in the 3D view */ void QMiarex::OnSurfaceSpeeds() { m_bSpeeds = m_pctrlSurfVel->isChecked(); if(m_pctrlSurfVel->isChecked()) { // m_bResetglStream = true; } if(m_iView==W3DVIEW) UpdateView(); } /** * The user has requested a modification of the light settings in the 3D view */ void QMiarex::OnSetupLight() { if(m_iView!=W3DVIEW && m_iView!=WSTABVIEW) return; ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; GLLightDlg *pgllDlg = (GLLightDlg*)m_pglLightDlg; pgllDlg->m_p3DWidget= s_p3dWidget; /* QSize size = QSize(400,400); QPoint pos = QPoint(100,50); gllDlg.resize(size); gllDlg.move(pos); */ pgllDlg->show(); double LightFactor; if(m_pCurWing) LightFactor = (GLfloat)pow(m_pCurWing->m_PlanformSpan/2.0,0.1); else LightFactor = 1.0; p3dWidget->GLSetupLight(m_UFOOffset.y, LightFactor); UpdateView(); } /** * The user has toggled the request to store or not the operating points of an analysis */ void QMiarex::OnStoreWOpp() { m_bStoreWOpp = m_pctrlStoreWOpp->isChecked(); } /** * The user has requested to switch to the two graph view top-left and top-right */ void QMiarex::OnTwoGraphs() { if(m_iView==WOPPVIEW) { m_iWingView = 2; m_pCurGraph = m_WingGraph; m_pCurWingGraph = m_pCurGraph; SetWingLegendPos(); } else if(m_iView==WPOLARVIEW) { m_iWPlrView = TWOPOLARGRAPHS; m_pCurGraph = m_WPlrGraph; m_pCurWPlrGraph = m_pCurGraph; SetWPlrLegendPos(); } else if(m_iView==WSTABVIEW) { m_iStabTimeView= 2; m_pCurGraph = m_TimeGraph; m_pCurTimeGraph = m_pCurGraph; SetWingLegendPos(); } else return; UpdateView(); SetControls(); } /** * The user has requested to switch to the four graph view */ void QMiarex::OnFourGraphs() { if(m_iView==WOPPVIEW) { m_iWingView = 4; m_pCurGraph = m_WingGraph; m_pCurWingGraph = m_pCurGraph; SetWingLegendPos(); } else if(m_iView==WPOLARVIEW) { m_iWPlrView = ALLPOLARGRAPHS; m_pCurGraph = m_WPlrGraph; m_pCurWPlrGraph = m_pCurGraph; SetWPlrLegendPos(); } else if(m_iView==WSTABVIEW) { m_iStabTimeView= 4; m_pCurGraph = m_TimeGraph; m_pCurTimeGraph = m_pCurGraph; SetWingLegendPos(); } else return; UpdateView(); SetControls(); } /** * The user has changed the scale of the velocity display in 3D view * @param pos the new position of the slider */ void QMiarex::OnVelocityScale(int pos) { m_VelocityScale = pos/100.0/sqrt(1.01-pos/100.0); m_bResetglDownwash = true; UpdateView(); } /** * The user has toggled the display of the vortices in 3D view *@deprecated Option disabled, only used for development */ void QMiarex::OnVortices() { m_bVortices = m_pctrlVortices->isChecked(); UpdateView(); } /** * The user has toggled the display of the curves for the second wing in case of a bi-plane *@todo not thouroughly tested */ void QMiarex::OnWing2Curve() { m_bShowWingCurve[1] = !m_bShowWingCurve[1]; // CheckMenus(); if (m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); UpdateView(); } /** * The user has requested the edition of the inertia data for the current wing or plane * Updates the inertia, resets the depending polars, and deletes the obsolete operating points * Updates the display */ void QMiarex::OnUFOInertia() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(!m_pCurWing) return; InertiaDlg iDlg(pMainFrame); iDlg.m_pPlane = NULL; iDlg.m_pWing = NULL; iDlg.m_pBody = NULL; Plane *pSavePlane = new Plane; Wing *pSaveWing = new Wing; WPolar *pWPolar; QString UFOName; bool bHasResults = false; if(m_pCurPlane) { UFOName = m_pCurPlane->PlaneName(); pSavePlane->Duplicate(m_pCurPlane); iDlg.m_pPlane = m_pCurPlane; } else if(m_pCurWing) { UFOName = m_pCurWing->WingName(); pSaveWing->Duplicate(m_pCurWing); iDlg.m_pWing = m_pCurWing; } for (int i=0; i< m_poaWPolar->size(); i++) { pWPolar = (WPolar*)m_poaWPolar->at(i); if(pWPolar->m_Alpha.size() && pWPolar->m_UFOName==UFOName && pWPolar->m_bAutoInertia) { // if(pWPolar->m_WPolarType==STABILITYPOLAR) // { bHasResults = true; break; // } } } iDlg.InitDialog(); ModDlg mdDlg(pMainFrame); if(iDlg.exec()==QDialog::Accepted) { if(bHasResults) { mdDlg.m_Question = tr("The modification will erase all polar results associated to this Plane.\nContinue ?"); mdDlg.InitDialog(); int Ans = mdDlg.exec(); if (Ans == QDialog::Rejected) { //restore saved UFO if(m_pCurPlane) m_pCurPlane->Duplicate(pSavePlane); else if(m_pCurWing) m_pCurWing->Duplicate(pSaveWing); return; } else if(Ans==20) { if(m_pCurPlane) { //save mods to a new plane object Plane* pNewPlane= new Plane; pNewPlane->Duplicate(m_pCurPlane); //restore geometry for initial plane m_pCurPlane->Duplicate(pSavePlane); if(!SetModPlane(pNewPlane)) delete pNewPlane; else m_pCurPlane = AddPlane(pNewPlane); } else if(m_pCurWing) { //save mods to a new wing object Wing* pNewWing= new Wing; pNewWing->Duplicate(m_pCurWing); //restore geometry for initial plane m_pCurWing->Duplicate(pSaveWing); if(!SetModWing(pNewWing)) delete pNewWing; else m_pCurWing = AddWing(pNewWing); } SetUFO(); pMainFrame->UpdateUFOs(); UpdateView(); return; } //last case, user wants to overwrite, so reset all polars, WOpps and POpps with autoinertia associated to the UFO for (int i=0; isize(); i++) { pWPolar = (WPolar*)m_poaWPolar->at(i); if(pWPolar && pWPolar->m_UFOName==UFOName && pWPolar->m_bAutoInertia) { pWPolar->ResetWPlr(); if(m_pCurPlane) pWPolar->RetrieveInertia(m_pCurPlane, true); else if(m_pCurWing) pWPolar->RetrieveInertia(m_pCurWing, false); for (int i=m_poaWOpp->size()-1; i>=0; i--) { WingOpp *pWOpp = (WingOpp*)m_poaWOpp->at(i); if(pWOpp && pWOpp->m_WingName==UFOName && pWOpp->m_PlrName==pWPolar->m_PlrName) { m_poaWOpp->removeAt(i); delete pWOpp; } } for (int i=m_poaPOpp->size()-1; i>=0; i--) { PlaneOpp *pPOpp = (PlaneOpp*)m_poaPOpp->at(i); if(pPOpp && pPOpp->m_PlaneName==UFOName && pPOpp->m_PlrName==pWPolar->m_PlrName) { m_poaPOpp->removeAt(i); delete pPOpp; } } } } m_pCurWOpp = NULL; m_pCurPOpp = NULL; } SetWPolar(); MainFrame::SetSaveState(false); if(m_iView==WPOLARVIEW) CreateWPolarCurves(); UpdateView(); } else { //restore saved UFO if(m_pCurPlane) m_pCurPlane->Duplicate(pSavePlane); else if(m_pCurWing) m_pCurWing->Duplicate(pSaveWing); } delete pSavePlane; delete pSaveWing; } /** * The user ha requested to switch to the operating point view */ void QMiarex::OnWOpps() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if(m_iView==WOPPVIEW) { SetControls(); UpdateView(); return; } m_pCurGraph = NULL; m_iView=WOPPVIEW; pMainFrame->SetCentralWidget(); m_bIs2DScaleSet = false; Set2DScale(); CreateWOppCurves(); SetCurveParams(); SetControls(); UpdateView(); } /** * The user ha requested to switch to the polar view */ void QMiarex::OnWPolars() { MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; if (m_bAnimateWOpp) StopAnimate(); if(m_iView==WPOLARVIEW) { SetControls(); UpdateView(); return; } m_iView=WPOLARVIEW; if(!m_pCurWPlrGraph) m_pCurGraph = NULL; else m_pCurGraph = m_pCurWPlrGraph; pMainFrame->SetCentralWidget(); SetWPlrLegendPos(); CreateWPolarCurves(); SetCurveParams(); SetControls(); UpdateView(); } /** * Dispatching method for the update of the client area of the active twodwidget * @param painter a reference to the QPainter object on which the view shall be drawn */ void QMiarex::PaintView(QPainter &painter) { static int h,w,w2,h2, h23,h34, h38,w3,w23; static QRect Rect1, Rect2, Rect3, Rect4; static QPoint Place; QPen TextPen; QString GraphName; painter.save(); w = m_r2DCltRect.width(); w2 = (int)(w/2); w3 = (int)(0.35*w); w23 = 2*w3; h = m_r2DCltRect.height(); h2 = (int)(h/2); h23 = (int)(2*h/3); h34 = (int)(3*h/4); h38 = (int)(3*h/8); //Refresh the active view painter.fillRect(m_r2DCltRect, MainFrame::s_BackgroundColor); if(m_r2DCltRect.width()<200 || m_r2DCltRect.height()<200) { painter.restore(); return;//too small to paint } if (m_iView==WPOLARVIEW) { if (m_iWPlrView == ONEPOLARGRAPH) { if(!m_pCurGraph) { m_pCurGraph = m_WPlrGraph; m_pCurWPlrGraph = m_WPlrGraph; } Rect1.setRect(0,0,w23,m_r2DCltRect.bottom()-00); m_pCurGraph->DrawGraph(Rect1, painter); DrawWPolarLegend(painter, m_WPlrLegendOffset, Rect1.bottom()); } else if(m_iWPlrView == TWOPOLARGRAPHS) { // PaintWCoupleGraphs(painter); Rect1.setRect(0,0,w2,h23); Rect2.setRect(w2,0,w2,h23); m_WPlrGraph[0].DrawGraph(Rect1, painter); m_WPlrGraph[1].DrawGraph(Rect2, painter); DrawWPolarLegend(painter, m_WPlrLegendOffset, m_r2DCltRect.bottom()); } else if(m_iWPlrView == ALLPOLARGRAPHS) { // PaintWFourGraphs(painter); Rect1.setRect(0,0,w3,h2); Rect2.setRect(w3,0,w3,h2); Rect3.setRect(0,h2,w3,h2); Rect4.setRect(w3,h2,w3,h2); m_WPlrGraph[0].DrawGraph(Rect1, painter); m_WPlrGraph[1].DrawGraph(Rect2, painter); m_WPlrGraph[2].DrawGraph(Rect3, painter); m_WPlrGraph[3].DrawGraph(Rect4, painter); DrawWPolarLegend(painter, m_WPlrLegendOffset, m_r2DCltRect.bottom()); } } else if (m_iView==WOPPVIEW) { if (m_iWingView == 1 && m_pCurWing) { // PaintSingleWingGraph(painter); if (m_pCurWingGraph && m_pCurWing && m_r2DCltRect.width()/2>200 && m_r2DCltRect.height()>250) { QPoint Place(m_r2DCltRect.left()+10, m_r2DCltRect.top() +30); DrawWOppLegend(painter, Place, m_r2DCltRect.bottom()); m_pCurWingGraph->DrawGraph(m_rSingleRect, painter); } painter.setFont(MainFrame::s_TextFont); QPen TextPen(MainFrame::s_TextColor); TextPen.setWidth(1); painter.setPen(TextPen); // int dwidth, dheight; // QFontMetrics fm(pMainFrame->m_TextFont); // dheight = fm.height(); // dwidth = fm.width(tr("abcdefghijklmnopqrstuvwxyz012345678")); if(m_pCurWing) { PaintWing(painter, m_ptOffset, m_WingScale); if(m_pCurWOpp && m_pCurWOpp->m_bIsVisible) { QPoint PtLegend; PtLegend.rx() = (int)(m_r2DCltRect.width()/2); PtLegend.ry() = m_r2DCltRect.bottom(); PaintXTr(painter, m_ptOffset, m_WingScale); if (m_bXCP) PaintXCP(painter, m_ptOffset, m_WingScale); if (m_bXCmRef) PaintXCmRef(painter, m_ptOffset, m_WingScale); } PaintWingLegend(painter); if(m_pCurWOpp) PaintCurWOppLegend(painter); } } else if (m_iWingView == 2 && m_pCurWing) { // PaintTwoWingGraph(painter); DrawWOppLegend(painter, m_WingLegendOffset, m_r2DCltRect.bottom()); Rect1.setRect(m_r2DCltRect.left(), m_r2DCltRect.top(), w2, h23); Rect2.setRect(w2, m_r2DCltRect.top(), w2, h23); m_WingGraph[0].DrawGraph(Rect1, painter); m_WingGraph[1].DrawGraph(Rect2, painter); } else if (m_iWingView == 4 && m_pCurWing) { // PaintFourWingGraph(painter); DrawWOppLegend(painter, m_WingLegendOffset, m_r2DCltRect.bottom()); Rect1.setRect(0,0,w2,h38); Rect2.setRect(w2,0,w2,h38); Rect3.setRect(0,h38,w2,h38); Rect4.setRect(w2,h38,w2,h38); m_WingGraph[0].DrawGraph(Rect1, painter); m_WingGraph[1].DrawGraph(Rect2, painter); m_WingGraph[2].DrawGraph(Rect3, painter); m_WingGraph[3].DrawGraph(Rect4, painter); } } else if (m_iView==WCPVIEW) { // PaintCp(painter); m_CpGraph.DrawGraph(painter); QPoint Place(50, h34+20); DrawCpLegend(painter, Place, m_r2DCltRect.bottom()); } else if (m_iView==WSTABVIEW) { if(m_iStabilityView==STABTIMEVIEW) { if(m_iStabTimeView==1) { // PaintSingleTimeGraph(painter); if(!m_pCurTimeGraph) m_pCurTimeGraph = m_TimeGraph; Rect1.setRect(0,0,w,h34); m_pCurTimeGraph->DrawGraph(Rect1, painter); Place.setX((int)(w*2/5)); Place.setY(m_pCurTimeGraph->GetMargin()/2); m_pCurTimeGraph->GetGraphName(GraphName); TextPen.setColor(m_pCurTimeGraph->GetTitleColor()); painter.setPen(TextPen); painter.drawText(Place, GraphName); DrawStabTimeLegend(painter, m_WingLegendOffset, m_r2DCltRect.bottom()); } else if(m_iStabTimeView==2) { //Paint a two graph time view DrawStabTimeLegend(painter, m_WingLegendOffset, m_r2DCltRect.bottom()); Rect1.setRect(m_r2DCltRect.left(), m_r2DCltRect.top(), w2, h23); Rect2.setRect(w2, m_r2DCltRect.top(), w2, h23); m_TimeGraph[0].DrawGraph(Rect1, painter); m_TimeGraph[1].DrawGraph(Rect2, painter); } else if(m_iStabTimeView==4) { // PaintFourTimeGraph(painter); //Paint a four graph time view DrawStabTimeLegend(painter, m_WingLegendOffset, m_r2DCltRect.bottom()); Rect1.setRect(0,0,w2,h38); Rect2.setRect(w2,0,w2,h38); Rect3.setRect(0,h38,w2,h38); Rect4.setRect(w2,h38,w2,h38); m_TimeGraph[0].DrawGraph(Rect1, painter); m_TimeGraph[1].DrawGraph(Rect2, painter); m_TimeGraph[2].DrawGraph(Rect3, painter); m_TimeGraph[3].DrawGraph(Rect4, painter); } } else { // PaintRLStabGraphs(painter); if(m_iStabilityView==STABPOLARVIEW) { if(m_pCurRLStabGraph) { Rect1.setRect(0,0,w23,m_r2DCltRect.bottom()-00); m_pCurRLStabGraph->DrawGraph(Rect1, painter); Place.setX((int)(w23/3)); Place.setY(m_pCurRLStabGraph->GetMargin()/2); m_pCurRLStabGraph->GetGraphName(GraphName); TextPen.setColor(m_pCurRLStabGraph->GetTitleColor()); painter.setPen(TextPen); painter.drawText(Place, GraphName); Place.setX(w23+10); Place.setY(10); DrawWPolarLegend(painter, m_WPlrLegendOffset, m_r2DCltRect.bottom()); } } } } painter.restore(); } /** * Draws the wing in the 2D operating point view * @param painter a reference to the QPainter object on which the view shall be drawn * @param ORef the origin of the tip of the root chord, in client coordinates * @param scale the scaling factor with which to draw the wing */ void QMiarex::PaintWing(QPainter &painter, QPoint ORef, double scale) { if(!m_pCurWing) return; static int i; // MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; static double scalex, scaley; scalex = scale; scaley = scale; painter.save(); QPen WingPen(W3dPrefsDlg::s_OutlineColor); WingPen.setStyle(GetStyle(W3dPrefsDlg::s_OutlineStyle)); WingPen.setWidth(W3dPrefsDlg::s_OutlineWidth); painter.setPen(WingPen); QPoint O(ORef); //Right Wing O.rx() = ORef.x(); O.ry() = ORef.y(); for (i=0; iNWingSection()-1;i++) { O.rx() +=(int)(m_pCurWing->Length(i)*scalex); painter.drawLine(O.x(), O.y()+(int)(m_pCurWing->Offset(i)*scaley), O.x()+(int)(m_pCurWing->Length(i+1)*scalex), O.y()+(int)(m_pCurWing->Offset(i+1)*scaley)); painter.drawLine(O.x()+(int)(m_pCurWing->Length(i+1)*scalex), O.y()+(int)(m_pCurWing->Offset(i+1)*scaley), O.x()+(int)(m_pCurWing->Length(i+1)*scalex), O.y()+(int)((m_pCurWing->Offset(i+1)+m_pCurWing->Chord(i+1))*scaley)); painter.drawLine(O.x()+(int)(m_pCurWing->Length(i+1)*scalex), O.y()+(int)((m_pCurWing->Offset(i+1)+m_pCurWing->Chord(i+1))*scaley), O.x(), O.y() +(int)((m_pCurWing->Offset(i)+m_pCurWing->Chord(i))*scaley)); painter.drawLine(O.x(), O.y() +(int)((m_pCurWing->Offset(i)+m_pCurWing->Chord(i))*scaley), O.x(), O.y()+(int)(m_pCurWing->Offset(i)*scaley)); } if(!m_bHalfWing) { //LeftWing O.rx() = ORef.x(); O.ry() = ORef.y(); for (i=0; iNWingSection()-1;i++) { O.rx() -= (int)(m_pCurWing->Length(i)*scalex); painter.drawLine(O.x(), O.y()+(int)(m_pCurWing->Offset(i)*scaley), O.x()-(int)(m_pCurWing->Length(i+1)*scalex), O.y()+(int)(m_pCurWing->Offset(i+1)*scaley)); painter.drawLine(O.x()-(int)(m_pCurWing->Length(i+1)*scalex), O.y()+(int)(m_pCurWing->Offset(i+1)*scaley), O.x()-(int)(m_pCurWing->Length(i+1)*scalex), O.y()+(int)((m_pCurWing->Offset(i+1)+m_pCurWing->Chord(i+1))*scaley)); painter.drawLine(O.x()-(int)(m_pCurWing->Length(i+1)*scalex), O.y()+(int)((m_pCurWing->Offset(i+1)+m_pCurWing->Chord(i+1))*scaley), O.x(), O.y() +(int)((m_pCurWing->Offset(i)+m_pCurWing->Chord(i))*scaley)); painter.drawLine(O.x(), O.y() +(int)((m_pCurWing->Offset(i)+m_pCurWing->Chord(i))*scaley), O.x(), O.y()+(int)(m_pCurWing->Offset(i)*scaley)); } } QPen SymPen(QColor(155,128,190)); painter.setPen(SymPen); painter.setBackgroundMode(Qt::TransparentMode); painter.drawLine(ORef.x(), ORef.y()-20, ORef.x(), ORef.y()+75); painter.restore(); } /** * Draws the wing legend in the 2D operating point view * @param painter a reference to the QPainter object on which the view shall be drawn */ void QMiarex::PaintWingLegend(QPainter &painter) { if(!m_pCurWing) return; painter.save(); QString Result, str, strong; QString str1; static double Mass; static int margin,dheight; margin = 10; QFontMetrics fm(MainFrame::s_TextFont); dheight = fm.height(); // dwidth = fm.width(tr("abcdefghijklmnopqrstuvwxyz012345678")); int D = 0; int LeftPos = margin; int ZPos = m_r2DCltRect.height()-11*dheight; // double area = m_pCurWing->s_RefArea; if(m_pCurPlane && m_pWingList[2]) ZPos -= dheight; if(m_pCurWPolar) ZPos -= dheight*2; painter.drawText(LeftPos, ZPos, m_pCurWing->WingName()); D+=dheight; QString length, surface; GetLengthUnit(length, MainFrame::s_LengthUnit); GetAreaUnit(surface, MainFrame::s_AreaUnit); str1 = QString(tr("Wing Span =")+" %1 ").arg(m_pCurWing->m_PlanformSpan*MainFrame::s_mtoUnit,12,'f',3); str1 += length; painter.drawText(LeftPos,ZPos+D, str1); D+=dheight; str1 = QString(tr("xyProj. Span =")+" %1 ").arg(m_pCurWing->m_ProjectedSpan*MainFrame::s_mtoUnit,11,'f',3); str1 += length; painter.drawText(LeftPos,ZPos+D, str1); D+=dheight; str1 = QString(tr("Wing Area =")+" %1 ").arg(m_pCurWing->m_PlanformArea * MainFrame::s_m2toUnit,13,'f',3); str1 += surface; painter.drawText(LeftPos,ZPos+D, str1); D+=dheight; str1 = QString(tr("xyProj. Area =")+" %1 ").arg(m_pCurWing->m_ProjectedArea * MainFrame::s_m2toUnit,11,'f',3); str1 += surface; painter.drawText(LeftPos,ZPos+D, str1); D+=dheight; if(m_pCurWPolar) { if(!m_pCurWPolar->m_bAutoInertia) Mass = m_pCurWPolar->m_Mass; else { if(m_pCurPlane) Mass = m_pCurPlane->TotalMass(); else if(m_pCurWing) Mass = m_pCurWing->TotalMass(); } GetWeightUnit(str, MainFrame::s_WeightUnit); Result = QString(tr("Plane Mass =")+" %1 ").arg(Mass*MainFrame::s_kgtoUnit,10,'f',3); Result += str; painter.drawText(LeftPos, ZPos+D, Result); D+=dheight; GetAreaUnit(strong, MainFrame::s_AreaUnit); Result = QString(tr("Wing Load =")+" %1 ").arg(Mass*MainFrame::s_kgtoUnit/m_pCurWPolar->m_WArea/MainFrame::s_m2toUnit,13,'f',3); Result += str + "/" + strong; painter.drawText(LeftPos, ZPos+D, Result); D+=dheight; } if(m_pCurPlane && m_pWingList[2]) { str1 = QString(tr("Tail Volume =")+" %1").arg(m_pCurPlane->TailVolume(),7,'f',3); painter.drawText(LeftPos, ZPos+D, str1); D+=dheight; } str1 = QString(tr("Root Chord =")+" %1 ").arg(m_pCurWing->Chord(0)*MainFrame::s_mtoUnit, 11,'f', 3); Result = str1+length; painter.drawText(LeftPos, ZPos+D, Result); D+=dheight; str1 = QString(tr("MAC =")+" %1 ").arg(m_pCurWing->m_MAChord*MainFrame::s_mtoUnit, 11,'f', 3); Result = str1+length; painter.drawText(LeftPos, ZPos+D, Result); D+=dheight; str1 = QString(tr("TipTwist =")+" %1 deg").arg(m_pCurWing->TipTwist(), 13,'f', 3); painter.drawText(LeftPos, ZPos+D, str1); D+=dheight; str1 = QString(tr("Aspect Ratio =")+" %1").arg(m_pCurWing->m_AR,9,'f',3); painter.drawText(LeftPos, ZPos+D, str1); D+=dheight; str1 = QString(tr("Taper Ratio =")+" %1").arg(m_pCurWing->m_TR,10,'f',3); painter.drawText(LeftPos, ZPos+D, str1); D+=dheight; str1 = QString(tr("Root-Tip Sweep =")+" %1 deg").arg(m_pCurWing->AverageSweep(), 9,'f',3); painter.drawText(LeftPos, ZPos+D, str1); painter.restore(); } /** * Draws the legend of the operating point in the 2D operating point view * @param painter a reference to the QPainter object on which the view shall be drawn */ void QMiarex::PaintCurWOppLegend(QPainter &painter) { if(!m_pCurWOpp) return; painter.save(); QString Result, str; int i; int margin = 10; int dwidth, dheight; QFontMetrics fm(MainFrame::s_TextFont); dheight = fm.height(); dwidth = fm.width(tr("abcdefghijklmnopqrstuvwxyz012345678")); int D = 0; D = 0; int RightPos = m_r2DCltRect.right()-margin-fm.width(tr("abcdefghijklmnopqrstuvwxyz01234567")); int ZPos = m_r2DCltRect.height()-13*dheight; if(m_pCurWOpp && m_pCurWOpp->m_WPolarType==STABILITYPOLAR) ZPos -=dheight; if(m_pCurWOpp && m_pCurWOpp->m_bOut) ZPos -= dheight; if(m_pCurWOpp) ZPos -= dheight*m_pCurWOpp->m_nFlaps; if(m_pCurWOpp && m_pCurWOpp->m_bIsVisible) { GetSpeedUnit(str, MainFrame::s_SpeedUnit); int l = str.length(); if(l==2) Result = QString(tr("V = %1 ")).arg(m_pCurWOpp->m_QInf*MainFrame::s_mstoUnit,7,'f',2); else if(l==3) Result = QString(tr("V = %1 ")).arg(m_pCurWOpp->m_QInf*MainFrame::s_mstoUnit,6,'f',1); else if(l==4) Result = QString(tr("V = %1 ")).arg(m_pCurWOpp->m_QInf*MainFrame::s_mstoUnit,5,'f',1); else Result = tr("No unit defined for speed..."); Result += str; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); Result = QString(tr("Alpha = %1 ")).arg(m_pCurWOpp->m_Alpha, 9,'f',4); D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); if(m_pCurWOpp->m_bOut) { Result = tr("Point is out of the flight envelope"); D+=dheight; painter.drawText(RightPos, ZPos+D, Result); } Result = QString(tr("Lift Coef. = %1 ")).arg(m_pCurWOpp->m_CL, 9,'f',4); D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); Result = QString(tr("Drag Coef. = %1 ")).arg(m_pCurWOpp->m_VCD+m_pCurWOpp->m_ICD, 9,'f',4); D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); /* oswald=CZ^2/CXi/PI/allongement;*/ double cxielli=m_pCurWOpp->m_CL*m_pCurWOpp->m_CL/PI/m_pCurWing->m_AR; Result = QString(tr("Efficiency = %1 ")).arg(cxielli/m_pCurWOpp->m_ICD, 9,'f',4); D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); Result = QString(tr("Cl/Cd = %1 ")).arg(m_pCurWOpp->m_CL/(m_pCurWOpp->m_ICD+m_pCurWOpp->m_VCD), 9,'f',4); D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); Result = QString(tr("GCm = %1 ")).arg(m_pCurWOpp->m_GCm,9,'f',4); D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); Result = QString(tr("Rolling Moment Coef. = %1 ")).arg(m_pCurWOpp->m_GRm, 9,'f',4); D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); Result = QString(tr("Induced Moment Coef = %1 ")).arg(m_pCurWOpp->m_IYm, 9,'f',4); D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); Result = QString(tr("Profile Yawing Moment = %1 ")).arg(m_pCurWOpp->m_GYm, 9,'f',4); D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); GetLengthUnit(str, MainFrame::s_LengthUnit); l = str.length(); int c, d; if(l==1) {c=8, d=3;} else if(l==2) {c=7, d=3;} else {c=6, d=3;} if(m_pCurWOpp->m_WPolarType==STABILITYPOLAR) { Result = QString(QObject::tr("X_NP = %1 ")).arg(m_pCurWOpp->m_XNP*MainFrame::s_mtoUnit, c,'f',d); Result += str; D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); } Result = QString(QObject::tr("X_CP = %1 ")).arg(m_pCurWOpp->m_CP.x*MainFrame::s_mtoUnit, c, 'f', d); Result += str; D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); Result = QString(QObject::tr("X_CG = %1 ")).arg(m_pCurWPolar->m_CoG.x*MainFrame::s_mtoUnit, c, 'f', d); Result += str; D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); for(i=0; im_nFlaps; i++) { Result = QString(tr("Flap %1 Moment =%2")).arg(i+1).arg(m_pCurWOpp->m_FlapMoment[i]*MainFrame::s_NmtoUnit,9,'f',4); GetMomentUnit(str, MainFrame::s_MomentUnit); Result += str; D+=dheight; painter.drawText(RightPos, ZPos+D, dwidth, dheight, Qt::AlignRight | Qt::AlignTop, Result); } } painter.restore(); } /** * Draws the laminar to turbulent translition lines in the operating view * @param painter a reference to the QPainter object on which the view shall be drawn * @param ORef the origin of the tip of the root chord, in client coordinates * @param scale the scaling factor with which to draw the wing */ void QMiarex::PaintXTr(QPainter & painter, QPoint ORef, double scale) { //Draws the transition lines on the 2D view if(!m_pCurWing) return; painter.save(); // MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; double y; int m,nStart; if(m_pCurWOpp->m_AnalysisMethod==LLTMETHOD) nStart = 1; else nStart = 0; if(m_bHalfWing) nStart = m_pCurWOpp->m_NStation/2; QPoint O(ORef); QPoint offset, From, To; double offLE; double scalex, scaley; offset.rx() = ORef.x(); offset.ry() = ORef.y(); scalex = scale; scaley = scale; O.rx() = offset.x(); O.ry() = offset.y(); QPen TopPen(W3dPrefsDlg::s_TopColor); TopPen.setStyle(GetStyle(W3dPrefsDlg::s_TopStyle)); TopPen.setWidth(W3dPrefsDlg::s_TopWidth); painter.setPen(TopPen); if (m_bXTop) { offLE = m_pCurWing->Offset(m_pCurWOpp->m_SpanPos[nStart]*2.0/m_pCurWOpp->m_Span); y = (offLE+m_pCurWOpp->m_Chord[nStart]*m_pCurWOpp->m_XTrTop[nStart])*scaley; From = QPoint(O.x()+(int)(m_pCurWOpp->m_SpanPos[nStart]*scalex), O.y()+(int)y); for (m=nStart; mm_NStation; m++) { offLE = m_pCurWing->Offset(m_pCurWOpp->m_SpanPos[m]*2.0/m_pCurWOpp->m_Span); y = (offLE+m_pCurWOpp->m_Chord[m]*m_pCurWOpp->m_XTrTop[m])*scaley; To = QPoint(O.x()+(int)(m_pCurWOpp->m_SpanPos[m]*scalex), O.y()+(int)y ); painter.drawLine(From, To); From = To; } int x = (int)(m_r2DCltRect.width()/2); int y = m_r2DCltRect.bottom(); painter.drawLine(x-60, y - 50, x-40, y - 50); painter.drawText(x-35, y - 48, tr("Top transition")); } QPen BotPen(W3dPrefsDlg::s_BotColor); BotPen.setStyle(GetStyle(W3dPrefsDlg::s_BotStyle)); BotPen.setWidth(W3dPrefsDlg::s_BotWidth); painter.setPen(BotPen); if (m_bXBot) { offLE = m_pCurWing->Offset(m_pCurWOpp->m_SpanPos[nStart]*2.0/m_pCurWOpp->m_Span); y = (offLE+m_pCurWOpp->m_Chord[nStart]*m_pCurWOpp->m_XTrBot[nStart])*scaley; From = QPoint(O.x() +(int)(m_pCurWOpp->m_SpanPos[nStart]*scalex), O.y()+(int)y ); for (m=nStart; mm_NStation; m++) { offLE = m_pCurWing->Offset(m_pCurWOpp->m_SpanPos[m]*2.0/m_pCurWOpp->m_Span); y = (offLE+m_pCurWOpp->m_Chord[m]*m_pCurWOpp->m_XTrBot[m])*scaley; To = QPoint(O.x()+(int)(m_pCurWOpp->m_SpanPos[m]*scalex), O.y()+(int)y ); painter.drawLine(From, To); From = To; } int x = (int)(m_r2DCltRect.width()/2); int y = m_r2DCltRect.bottom(); painter.drawLine(x-60, y - 35, x-40, y - 35); painter.drawText(x-35, y - 33, tr("Bottom transition")); } painter.restore(); } /** * Draws the lift line and the position of the center of pressure in the operating view * @param painter a reference to the QPainter object on which the view shall be drawn * @param ORef the origin of the tip of the root chord, in client coordinates * @param scale the scaling factor with which to draw the wing */ void QMiarex::PaintXCP(QPainter & painter, QPoint ORef, double scale) { //Draws the lift line and center of pressure position on the the 2D view if(!m_pCurWing) return; painter.save(); // MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QPoint From, To; double y; int nStart; double offLE; if(m_pCurWOpp->m_AnalysisMethod==LLTMETHOD) nStart = 1; else nStart = 0; if(m_bHalfWing) nStart = m_pCurWOpp->m_NStation/2; QPoint O(ORef); QPoint offset; double scalex, scaley; offset.rx() = ORef.x(); offset.ry() = ORef.y(); scalex = scale; scaley = scale; O.rx() = offset.x(); O.ry() = offset.y(); QPen XCPPen(W3dPrefsDlg::s_XCPColor); XCPPen.setWidth(W3dPrefsDlg::s_XCPWidth); XCPPen.setStyle(GetStyle(W3dPrefsDlg::s_XCPStyle)); painter.setPen(XCPPen); int XCp = O.x() + (int)(m_pCurWOpp->m_CP.y*scalex); int YCp = O.y() + (int)(m_pCurWOpp->m_CP.x*scaley); // int ZCp = O.z() + (int)(m_pCurWOpp->m_ZCP*scalez); int size = 3; QRect CP(XCp-size, YCp-size, 2*size, 2*size); painter.drawEllipse(CP); offLE = m_pCurWing->Offset(m_pCurWOpp->m_SpanPos[nStart]*2.0/m_pCurWOpp->m_Span); y = (offLE+m_pCurWOpp->m_Chord[nStart]*m_pCurWOpp->m_XCPSpanRel[nStart])*scaley; From = QPoint(O.x()+(int)(m_pCurWOpp->m_SpanPos[nStart]*scalex), O.y()+(int)y ); for (int m=nStart; mm_NStation; m++) { offLE = m_pCurWing->Offset(m_pCurWOpp->m_SpanPos[m]*2.0/m_pCurWOpp->m_Span); y = (offLE+m_pCurWOpp->m_Chord[m]*m_pCurWOpp->m_XCPSpanRel[m])*scaley; To = QPoint(O.x()+(int)(m_pCurWOpp->m_SpanPos[m]*scalex), O.y()+(int)y ); painter.drawLine(From, To); From = To; } int x = (int)(m_r2DCltRect.width()/2); int y1 = m_r2DCltRect.bottom(); painter.drawLine(x-60, y1- 20, x-40, y1 - 20); painter.drawText(x-35, y1 - 18, tr("Centre of Pressure")); painter.restore(); } /** * Draws the position of the reference point for the moments in the operating view * @param painter a reference to the QPainter object on which the view shall be drawn * @param ORef the origin of the tip of the root chord, in client coordinates * @param scale the scaling factor with which to draw the wing */ void QMiarex::PaintXCmRef(QPainter & painter, QPoint ORef, double scale) { //Draws the moment reference point on the 2D view if(!m_pCurWing || !m_pCurWPolar) return; painter.save(); QPoint O(ORef); QPoint offset; double scaley; offset.rx() = ORef.x(); offset.ry() = ORef.y(); // scalex = scale; scaley = scale; O.rx() = offset.x(); O.ry() = offset.y(); QPen XCmRefPen(MainFrame::s_TextColor); painter.setPen(XCmRefPen); int XCm = O.x() ; int YCm = O.y() + (int)(m_pCurWPolar->m_CoG.x*scaley); int size = 3; QRect CM(XCm-size, YCm-size, 2*size, 2*size); painter.drawEllipse(CM); painter.drawText(XCm+10, YCm-5, tr("Moment ref. location")); painter.restore(); } /** * Launches a 3D panel analysis * @param V0 the initial aoa * @param VMax the final aoa * @param VDelta the increment * @param bSequence if true, the analysis will run for a sequence of aoa from V0 to Vmax, if not only V0 shall be calculated */ void QMiarex::PanelAnalyze(double V0, double VMax, double VDelta, bool bSequence) { if(!m_pCurWing || !m_pCurWPolar) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; int i,pl, pr; //Join surfaces together pl = 0; pr = m_pSurface[0]->m_NElements; for (i=0; im_bIsTipRight) { if(m_pSurface[i]->m_bJoinRight) JoinSurfaces(m_pSurface[i], m_pSurface[i+1], pl, pr); } pl = pr; pr += m_pSurface[i+1]->m_NElements; } m_pPanelDlg->m_bSequence = bSequence; m_pPanelDlg->m_pWPolar = m_pCurWPolar; m_pPanelDlg->m_MaxWakeIter = m_MaxWakeIter; m_pPanelDlg->m_WakeInterNodes = m_WakeInterNodes; m_pPanelDlg->m_bSequence = bSequence; m_pPanelDlg->m_nWakeNodes = m_nWakeNodes; m_pPanelDlg->m_WakeSize = m_WakeSize; m_pPanelDlg->m_bTrefftz = m_bTrefftz; m_pPanelDlg->m_nNodes = m_nNodes; m_pPanelDlg->m_NSurfaces = m_NSurfaces; m_pPanelDlg->m_ppSurface = m_pSurface; m_pPanelDlg->m_MatSize = m_MatSize; m_pPanelDlg->m_NWakeColumn = m_NWakeColumn; m_pPanelDlg->m_pPlane = m_pCurPlane; if(m_pCurPlane) m_pPanelDlg->m_pBody = m_pCurPlane->body(); else m_pPanelDlg->m_pBody = NULL; m_pPanelDlg->m_pWing = m_pCurWing; for(int iw=0; iwm_pWingList[iw] = m_pWingList[iw]; if(m_pCurWPolar->m_WPolarType==FIXEDAOAPOLAR) { m_pPanelDlg->m_Alpha = m_pCurWPolar->m_ASpec; m_pPanelDlg->m_QInf = V0; m_pPanelDlg->m_QInfMax = VMax; m_pPanelDlg->m_QInfDelta = VDelta; } else if(m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { m_pPanelDlg->m_Alpha = m_pCurWPolar->m_ASpec; m_pPanelDlg->m_ControlMin = V0; m_pPanelDlg->m_ControlMax = VMax; m_pPanelDlg->m_ControlDelta = VDelta; } else { m_pPanelDlg->m_QInf = m_pCurWPolar->m_QInf; m_pPanelDlg->m_Alpha = V0; m_pPanelDlg->m_AlphaMax = VMax; m_pPanelDlg->m_AlphaDelta = VDelta; } if(!m_pPanelDlg->InitDialog()) return; m_pPanelDlg->show(); m_pPanelDlg->StartAnalysis(); // m_bResetglMesh = true; if(!m_bLogFile || !m_pPanelDlg->m_bWarning) m_pPanelDlg->hide(); pMainFrame->UpdateWOpps(); if(m_pCurPlane) SetPlaneOpp(false, m_pPanelDlg->m_Alpha); else if(m_pCurWing) SetWingOpp(false, m_pPanelDlg->m_Alpha); m_bResetglWake=true; //TODO remove } /** * Renames the active wing or plane * Updates the references in child polars and oppoints * @param UFOName the new name for the wing or plane */ void QMiarex::RenameUFO(QString UFOName) { QString OldName; WingOpp *pWOpp; PlaneOpp *pPOpp; int l; WPolar *pWPolar; Plane *pPlane = GetPlane(UFOName); Wing *pWing = GetWing(UFOName); if(pPlane) { OldName = pPlane->PlaneName(); SetModPlane(pPlane); pPlane->RenameWings(); for (l=m_poaWPolar->size()-1;l>=0; l--) { pWPolar = (WPolar*)m_poaWPolar->at(l); if (pWPolar->m_UFOName == OldName) { pWPolar->m_UFOName = pPlane->PlaneName(); } } for (l=m_poaPOpp->size()-1;l>=0; l--) { pPOpp = (PlaneOpp*)m_poaPOpp->at(l); if (pPOpp->m_PlaneName == OldName) { pPOpp->m_PlaneName = pPlane->PlaneName(); } } // return pPlane->PlaneName(); } else if(pWing) { OldName = pWing->m_WingName; SetModWing(pWing); for (l=m_poaWPolar->size()-1;l>=0; l--) { pWPolar = (WPolar*)m_poaWPolar->at(l); if (pWPolar->m_UFOName == OldName){ pWPolar->m_UFOName = pWing->m_WingName; } } for (l=m_poaWOpp->size()-1;l>=0; l--) { pWOpp = (WingOpp*)m_poaWOpp->at(l); if (pWOpp->m_WingName == OldName) { pWOpp->m_WingName = pWing->m_WingName; } } // return pWing->m_WingName; } // return ""; } /** * Rotates all the panels about the y-axis * @param Angle the rotation angle in degrees * @param P the point of origin of the rotation */ void QMiarex::RotateGeomY(double const &Angle, CVector const &P) { int n, p, pw, kw, lw; int iLA, iLB, iTA, iTB; CVector LATB, TALB, Pt, Trans; for (n=0; n< m_nNodes; n++) m_Node[n].RotateY(P, Angle); for (p=0; p< m_MatSize; p++) { iLA = m_Panel[p].m_iLA; iLB = m_Panel[p].m_iLB; iTA = m_Panel[p].m_iTA; iTB = m_Panel[p].m_iTB; LATB = m_Node[iLA] - m_Node[iTB]; TALB = m_Node[iTA] - m_Node[iLB]; if(m_Panel[p].m_Pos==MIDSURFACE || m_Panel[p].m_Pos==TOPSURFACE) m_Panel[p].SetFrame(m_Node[iLA], m_Node[iLB], m_Node[iTA], m_Node[iTB]); else if (m_Panel[p].m_Pos==BOTSURFACE) m_Panel[p].SetFrame(m_Node[iLB], m_Node[iLA], m_Node[iTB], m_Node[iTA]); } // the wake array is not rotated but translated to remain at the wing's trailing edge pw=0; if(!m_pCurWPolar) return; for (kw=0; kwm_NXWakePanels; lw++) { if(lw==0) m_WakeNode[m_WakePanel[pw].m_iLA] += Trans; m_WakeNode[m_WakePanel[pw].m_iTA] += Trans; pw++; } } //do the same for the very last right wake node column pw -= m_pCurWPolar->m_NXWakePanels; Pt = m_WakeNode[m_WakePanel[pw].m_iLB]; Pt.RotateY(P, Angle); //define the translation to be applied to the column's left points Trans = Pt-m_WakeNode[m_WakePanel[pw].m_iLB]; //each wake column has m_NXWakePanels ... translate all right B nodes for(lw=0; lwm_NXWakePanels; lw++) { if(lw==0) m_WakeNode[m_WakePanel[pw].m_iLB] += Trans; m_WakeNode[m_WakePanel[pw].m_iTB] += Trans; pw++; } //Reset panel frame : CollPt has been translated for (pw=0; pw< m_WakeSize; pw++) { iLA = m_WakePanel[pw].m_iLA; iLB = m_WakePanel[pw].m_iLB; iTA = m_WakePanel[pw].m_iTA; iTB = m_WakePanel[pw].m_iTB; m_WakePanel[pw].SetFrame(m_WakeNode[iLA], m_WakeNode[iLB], m_WakeNode[iTA], m_WakeNode[iTB]); } } /** * Rotates all the panels about the z-axis * @param pPanel a pointer to the array of surface mesh panels * @param pNode a pointer to the array of surface panel nodes * @param pWakePanel a pointer to the array of wake mesh panels * @param pWakeNode a pointer to the array of wake panel nodes * @param beta the rotation angle in degrees * @param P the point of origin of the rotation */ void QMiarex::RotateGeomZ(Panel *pPanel, CVector *pNode, Panel *pWakePanel, CVector *pWakeNode, double const &Beta, CVector const &P) { int n, p, pw, kw, lw; int iLA, iLB, iTA, iTB; CVector LATB, TALB, Pt, Trans; for (n=0; n< m_nNodes; n++) pNode[n].RotateZ(P, Beta); for (p=0; p< m_MatSize; p++) { iLA = pPanel[p].m_iLA; iLB = pPanel[p].m_iLB; iTA = pPanel[p].m_iTA; iTB = pPanel[p].m_iTB; LATB = pNode[iLA] - pNode[iTB]; TALB = pNode[iTA] - pNode[iLB]; if(pPanel[p].m_Pos>=MIDSURFACE) pPanel[p].SetFrame(pNode[iLA], pNode[iLB], pNode[iTA], pNode[iTB]); else if (pPanel[p].m_Pos==BOTSURFACE) pPanel[p].SetFrame(pNode[iLB], pNode[iLA], pNode[iTB], pNode[iTA]); } // the wake array is not rotated but translated to remain at the wing's trailing edge pw=0; if(!m_pCurWPolar) return; for (kw=0; kwm_NXWakePanels; lw++) { if(lw==0) pWakeNode[pWakePanel[pw].m_iLA] += Trans; pWakeNode[pWakePanel[pw].m_iTA] += Trans; pw++; } } pw -= m_pCurWPolar->m_NXWakePanels; //consider the first panel of the column; Pt = pWakeNode[pWakePanel[pw].m_iLB]; Pt.RotateZ(P, Beta); //define the translation to be applied to the column's left points Trans = Pt - pWakeNode[pWakePanel[pw].m_iLB]; //each wake column has m_NXWakePanels ... translate all left A nodes for(lw=0; lwm_NXWakePanels; lw++) { if(lw==0) pWakeNode[pWakePanel[pw].m_iLB] += Trans; pWakeNode[pWakePanel[pw].m_iTB] += Trans; pw++; } //Reset panel frame : CollPt has been translated for (pw=0; pw< m_WakeSize; pw++) { iLA = pWakePanel[pw].m_iLA; iLB = pWakePanel[pw].m_iLB; iTA = pWakePanel[pw].m_iTA; iTB = pWakePanel[pw].m_iTB; pWakePanel[pw].SetFrame(pWakeNode[iLA], pWakeNode[iLB], pWakeNode[iTA], pWakeNode[iTB]); } } /** * Saves the user settings to the QSettings object * @param pSettings a pointer to the QSettings object * @return true if the save was successfull, false if an error was encountered */ bool QMiarex::SaveSettings(QSettings *pSettings) { QString strong; int k=0; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; OnReadAnalysisData(); pSettings->beginGroup("Miarex"); { pSettings->setValue("bXTop", m_bXTop); pSettings->setValue("bXBot", m_bXBot ); pSettings->setValue("bXCP", m_bXCP); pSettings->setValue("bPanelForce", m_bPanelForce); pSettings->setValue("bXCmRef", m_bXCmRef ); pSettings->setValue("bICd", m_bICd ); pSettings->setValue("bVCd", m_bVCd ); pSettings->setValue("bWakePanels", m_bWakePanels ); pSettings->setValue("bSurfaces", s_bSurfaces ); pSettings->setValue("bOutline", s_bOutline ); pSettings->setValue("bVLMPanels", s_bVLMPanels ); pSettings->setValue("bAxes", s_bAxes ); pSettings->setValue("b3DCp", m_b3DCp ); pSettings->setValue("bDownwash", m_bDownwash ); pSettings->setValue("bMoments", m_bMoments ); pSettings->setValue("bAutoCpScale", s_bAutoCpScale ); pSettings->setValue("bShowCpScale", m_bShowCpScale ); pSettings->setValue("CurWOppOnly", m_bCurWOppOnly ); pSettings->setValue("bShowElliptic", m_bShowElliptic); pSettings->setValue("LogFile", m_bLogFile ); pSettings->setValue("bVLM1", m_bVLM1); pSettings->setValue("Dirichlet", m_bDirichlet ); pSettings->setValue("Trefftz", m_bTrefftz ); pSettings->setValue("KeepOutOpps", m_bKeepOutOpps ); pSettings->setValue("ResetWake", m_bResetWake ); pSettings->setValue("ShowWing", m_bShowWingCurve[0]); pSettings->setValue("ShowWing2", m_bShowWingCurve[1]); pSettings->setValue("ShowStab", m_bShowWingCurve[2]); pSettings->setValue("ShowFin", m_bShowWingCurve[3]); pSettings->setValue("StoreWOpp", m_bStoreWOpp ); pSettings->setValue("Sequence", m_bSequence ); pSettings->setValue("HighlightOpp", m_bHighlightOpp); pSettings->setValue("AlphaMin", m_AlphaMin); pSettings->setValue("AlphaMax", m_AlphaMax); pSettings->setValue("AlphaDelta", m_AlphaDelta); pSettings->setValue("QInfMin", m_QInfMin ); pSettings->setValue("QInfMax", m_QInfMax ); pSettings->setValue("QInfDelta", m_QInfDelta ); pSettings->setValue("ControlMin", m_ControlMin ); pSettings->setValue("ControlMax", m_ControlMax ); pSettings->setValue("ControlDelta", m_ControlDelta ); pSettings->setValue("bAutoInertia", WPolarDlg::s_WPolar.m_bAutoInertia); pSettings->setValue("CpStyle", m_CpStyle ); pSettings->setValue("CpWidth", m_CpWidth ); pSettings->setValue("CpColorRed", m_CpColor.red() ); pSettings->setValue("CpColorGreen", m_CpColor.green() ); pSettings->setValue("CpColorBlue", m_CpColor.blue() ); pSettings->setValue("CvPrec", LLTAnalysis::s_CvPrec); pSettings->setValue("RelaxMax", LLTAnalysis::s_RelaxMax); pSettings->setValue("NLLTStations", LLTAnalysis::s_NLLTStations); pSettings->setValue("iView", m_iView); switch(m_iView) { case WOPPVIEW: { pSettings->setValue("iView", 0); break; } case WPOLARVIEW: { pSettings->setValue("iView", 1); break; } case W3DVIEW: { pSettings->setValue("iView", 2); break; } case WCPVIEW: { pSettings->setValue("iView", 3); break; } case WSTABVIEW: { pSettings->setValue("iView", 4); break; } } pSettings->setValue("iWingView", m_iWingView); switch(m_iWPlrView) { case ONEPOLARGRAPH: pSettings->setValue("iWPlrView", 1); break; case TWOPOLARGRAPHS: pSettings->setValue("iWPlrView", 2); break; default: pSettings->setValue("iWPlrView", 0); break; } switch(m_iStabilityView) { case STABTIMEVIEW: { pSettings->setValue("iWStabView", 0); break; } case STABPOLARVIEW: { pSettings->setValue("iWStabView", 1); break; } case STAB3DVIEW: { pSettings->setValue("iWStabView", 2); break; } } if (m_pCurWingGraph==m_WingGraph) k=1; else if(m_pCurWingGraph==m_WingGraph+1) k=2; else if(m_pCurWingGraph==m_WingGraph+2) k=3; else if(m_pCurWingGraph==m_WingGraph+3) k=4; pSettings->setValue("CurrentWingGraph", k); if (m_pCurWPlrGraph==m_WPlrGraph) k=1; else if(m_pCurWPlrGraph==m_WPlrGraph+1) k=2; else if(m_pCurWPlrGraph==m_WPlrGraph+2) k=3; else if(m_pCurWPlrGraph==m_WPlrGraph+3) k=4; pSettings->setValue("CurWPlrGraph", k); if (m_pCurRLStabGraph == &m_LongRLGraph) k=1; else if(m_pCurRLStabGraph == &m_LatRLGraph) k=2; pSettings->setValue("CurRLStabGraph",k); if(m_iView==WOPPVIEW) m_pCurGraph=m_pCurWingGraph; else if(m_iView==WPOLARVIEW) m_pCurGraph=m_pCurWPlrGraph; pSettings->setValue("Iter", m_Iter); pSettings->setValue("NStation", m_NStation); pSettings->setValue("InducedDragPoint", m_InducedDragPoint); pSettings->setValue("NHoopPoints", GL3dBodyDlg::s_NHoopPoints); pSettings->setValue("NXPoints", GL3dBodyDlg::s_NXPoints); pSettings->setValue("LiftScale", m_LiftScale); pSettings->setValue("DragScale", m_DragScale); pSettings->setValue("VelocityScale", m_VelocityScale); pSettings->setValue("WakeInterNodes", m_WakeInterNodes); pSettings->setValue("MaxWakeIter", m_MaxWakeIter); pSettings->setValue("CtrlPos", Panel::s_CtrlPos); pSettings->setValue("VortexPos", Panel::s_VortexPos); pSettings->setValue("CoreSize", s_CoreSize); pSettings->setValue("MinPanelSize", s_MinPanelSize); pSettings->setValue("TotalTime", m_TotalTime); pSettings->setValue("Delta_t", m_Deltat); pSettings->setValue("RampTime", m_RampTime); pSettings->setValue("RampAmplitude", m_RampAmplitude); pSettings->setValue("TimeIn0", m_TimeInput[0]); pSettings->setValue("TimeIn1", m_TimeInput[1]); pSettings->setValue("TimeIn2", m_TimeInput[2]); pSettings->setValue("TimeIn3", m_TimeInput[3]); pSettings->setValue("DynamicsMode", m_bLongitudinal); pSettings->setValue("StabCurveType",m_StabilityResponseType); pSettings->setValue("StabTimeView", m_iStabTimeView); if(m_pCurTimeGraph == m_TimeGraph) k=1; else if(m_pCurTimeGraph == m_TimeGraph+1) k=2; else if(m_pCurTimeGraph == m_TimeGraph+2) k=3; else if(m_pCurTimeGraph == m_TimeGraph+3) k=4; pSettings->setValue("TimeGraph",k); // pSettings->setValue("AVLControls", StabPolarDlg::s_StabPolar.m_bAVLControls); pStabView->ReadControlModelData(); for(int i=0; i<20; i++) { strong = QString("ForcedTime%1").arg(i); pSettings->setValue(strong, pStabView->m_Time[i]); } for(int i=0; i<20; i++) { strong = QString("ForcedAmplitude%1").arg(i); pSettings->setValue(strong, pStabView->m_Amplitude[i]); } pSettings->setValue("StabPolarAutoInertia", StabPolarDlg::s_StabPolar.m_bAutoInertia); pSettings->setValue("StabPolarMass", StabPolarDlg::s_StabPolar.m_Mass); pSettings->setValue("StabPolarCoGx", StabPolarDlg::s_StabPolar.m_CoG.x); pSettings->setValue("StabPolarCoGy", StabPolarDlg::s_StabPolar.m_CoG.y); pSettings->setValue("StabPolarCoGz", StabPolarDlg::s_StabPolar.m_CoG.z); pSettings->setValue("StabPolarCoGIxx", StabPolarDlg::s_StabPolar.m_CoGIxx); pSettings->setValue("StabPolarCoGIyy", StabPolarDlg::s_StabPolar.m_CoGIyy); pSettings->setValue("StabPolarCoGIzz", StabPolarDlg::s_StabPolar.m_CoGIzz); pSettings->setValue("StabPolarCoGIxz", StabPolarDlg::s_StabPolar.m_CoGIxz); } pSettings->endGroup(); m_CpGraph.SaveSettings(pSettings); m_LongRLGraph.SaveSettings(pSettings); m_LatRLGraph.SaveSettings(pSettings); for(int ig=0; iggeometry(); // m_rSingleRect.setRect(m_r2DCltRect.x(), m_r2DCltRect.y(), m_r2DCltRect.width(), m_r2DCltRect.height()); m_rSingleRect = m_r2DCltRect; h = m_r2DCltRect.height(); w = m_r2DCltRect.width(); int w2 = (int)(w/2); // int w3 = (int)(w/3); // int h23 = (int)(2*h/3); int h38 = (int)(3*h/8); int h34 = (int)(3*h/4); QRect CpRect(0,0,w,h34); m_CpGraph.SetDrawRect(CpRect); // m_TimeGraph.SetDrawRect(CpRect); m_LongRLGraph.SetDrawRect(CpRect); m_LatRLGraph.SetDrawRect(CpRect); if(m_bHalfWing) m_ptOffset.rx() = m_rSingleRect.left() + m_WingGraph[0].GetMargin(); else m_ptOffset.rx() = (int)(m_r2DCltRect.width()/2.0); m_ptOffset.ry() = m_r2DCltRect.bottom()-185; m_rSingleRect.setRect(40,10,m_r2DCltRect.right()-80,m_r2DCltRect.bottom()-230); QRect Rect1(0,0,w2,h38); QRect Rect2(w2,0,w2,h38); QRect Rect3(0,h38,w2,h38); QRect Rect4(w2,h38,w2,h38); m_WingGraph[0].SetDrawRect(Rect1); m_WingGraph[1].SetDrawRect(Rect2); m_WingGraph[2].SetDrawRect(Rect3); m_WingGraph[3].SetDrawRect(Rect4); for(int ig=0; ig<4; ig++) { m_WingGraph[ig].Init(); m_WingGraph[ig].SetAutoXUnit(); } if(m_iView==WOPPVIEW) SetWingLegendPos(); else if(m_iView==WPOLARVIEW) SetWPlrLegendPos(); else if(m_iView==WSTABVIEW) { if(m_iStabilityView==STABTIMEVIEW) SetWingLegendPos(); else SetWPlrLegendPos(); } if(m_pCurWing) { m_WingScale = (m_rSingleRect.width()-2*m_WingGraph[0].GetMargin())/m_pCurWing->m_PlanformSpan; if(m_bHalfWing) m_WingScale *= 2.0; m_bIs2DScaleSet = true; } } /** * Adjusts the new rotation center after a translation or a rotation */ void QMiarex::Set3DRotationCenter() { int i,j; for(i=0; i<4; i++) for(j=0; j<4; j++) MatOut[i][j] = m_ArcBall.ab_quat[i*4+j]; m_glRotCenter.x = MatOut[0][0]*(m_glViewportTrans.x) + MatOut[0][1]*(-m_glViewportTrans.y) + MatOut[0][2]*m_glViewportTrans.z; m_glRotCenter.y = MatOut[1][0]*(m_glViewportTrans.x) + MatOut[1][1]*(-m_glViewportTrans.y) + MatOut[1][2]*m_glViewportTrans.z; m_glRotCenter.z = MatOut[2][0]*(m_glViewportTrans.x) + MatOut[2][1]*(-m_glViewportTrans.y) + MatOut[2][2]*m_glViewportTrans.z; } /** * Adjusts the new rotation center after the user has picked a point on the screen * Finds the closest panel under the point and changes the rotation vector and viewport translation *@param the point clicked by the user, in client coordinates */ void QMiarex::Set3DRotationCenter(QPoint point) { int i, j, p; CVector I, A, B, AA, BB, PP, U; double dmin, dist; ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; i=-1; dmin = 100000.0; p3dWidget->ClientToGL(point, B); B.x += -m_UFOOffset.x - m_glViewportTrans.x*m_glScaled; B.y += -m_UFOOffset.y + m_glViewportTrans.y*m_glScaled; B *= 1.0/m_glScaled; A.Set(B.x, B.y, +1.0); B.z = -1.0; for(i=0; i<4; i++) for(j=0; j<4; j++) MatIn[i][j] = m_ArcBall.ab_quat[i*4+j]; //convert screen to model coordinates AA.x = MatIn[0][0]*A.x + MatIn[0][1]*A.y + MatIn[0][2]*A.z; AA.y = MatIn[1][0]*A.x + MatIn[1][1]*A.y + MatIn[1][2]*A.z; AA.z = MatIn[2][0]*A.x + MatIn[2][1]*A.y + MatIn[2][2]*A.z; BB.x = MatIn[0][0]*B.x + MatIn[0][1]*B.y + MatIn[0][2]*B.z; BB.y = MatIn[1][0]*B.x + MatIn[1][1]*B.y + MatIn[1][2]*B.z; BB.z = MatIn[2][0]*B.x + MatIn[2][1]*B.y + MatIn[2][2]*B.z; if(m_pCurWOpp) { AA.RotateY(-m_pCurWOpp->m_Alpha); BB.RotateY(-m_pCurWOpp->m_Alpha); } U.Set(BB.x-AA.x, BB.y-AA.y, BB.z-AA.z); U.Normalize(); bool bIntersect = false; if(m_iView==W3DVIEW || (m_iView==WSTABVIEW && m_iStabilityView==STAB3DVIEW)) { for(p=0; pm_Alpha); } // instantaneous visual transition // m_glRotCenter -= PP * m_glScaled; // smooth visual transition GLInverseMatrix(); U.x = (-PP.x -m_glRotCenter.x)/30.0; U.y = (-PP.y -m_glRotCenter.y)/30.0; U.z = (-PP.z -m_glRotCenter.z)/30.0; for(i=0; i<30; i++) { m_glRotCenter +=U; m_glViewportTrans.x = (MatOut[0][0]*m_glRotCenter.x + MatOut[0][1]*m_glRotCenter.y + MatOut[0][2]*m_glRotCenter.z); m_glViewportTrans.y = -(MatOut[1][0]*m_glRotCenter.x + MatOut[1][1]*m_glRotCenter.y + MatOut[1][2]*m_glRotCenter.z); m_glViewportTrans.z= (MatOut[2][0]*m_glRotCenter.x + MatOut[2][1]*m_glRotCenter.y + MatOut[2][2]*m_glRotCenter.z); UpdateView(); } } } /** * Sets an automatic scale for the wing or plane in the 3D view, depending on wing span. */ void QMiarex::Set3DScale() { if(m_iView!=W3DVIEW && (m_iView!=WSTABVIEW || m_iStabilityView!=STAB3DVIEW)) return; if(m_iView==W3DVIEW) m_bResetglLegend = true; if(m_bIs3DScaleSet && !m_bAutoScales) return; ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; m_r3DCltRect = p3dWidget->geometry(); if(m_pCurWing) { //wing along X axis will take 3/4 of the screen m_glScaled = (GLfloat)(3./4.*2.0*m_GLScale/m_pCurWing->m_PlanformSpan); m_glViewportTrans.x = 0.0; m_glViewportTrans.y = 0.0; m_glViewportTrans.z = 0.0; m_bIs3DScaleSet = true; } else //(m_iView==3) { double gh = (double)m_r3DCltRect.height()/(double)m_r3DCltRect.width() ; if(gh<1.0) { m_UFOOffset.x = 0.0; m_UFOOffset.y = (GLfloat)(gh - 1.0)*m_GLScale; } else { m_UFOOffset.x = (GLfloat)(1.0/gh - 1.0)*m_GLScale; m_UFOOffset.y = 0.0; } m_UFOOffset.x = 0.0; m_UFOOffset.y = 0.0; } } /** * Initializes the input parameters depending onthe type of the active polar */ void QMiarex::SetAnalysisParams() { m_pctrlSequence->setChecked(m_bSequence); m_pctrlAlphaMax->setEnabled(m_bSequence); m_pctrlAlphaDelta->setEnabled(m_bSequence); if (!m_pCurWPolar) { m_pctrlSequence->setEnabled(false); m_pctrlAlphaMin->setEnabled(false); m_pctrlAlphaMax->setEnabled(false); m_pctrlAlphaDelta->setEnabled(false); m_pctrlInitLLTCalc->setEnabled(false); m_pctrlStoreWOpp->setEnabled(false); return; } else { m_pctrlSequence->setEnabled(true); m_pctrlAlphaMin->setEnabled(true); m_pctrlAlphaMax->setEnabled(m_bSequence); m_pctrlAlphaDelta->setEnabled(m_bSequence); m_pctrlInitLLTCalc->setEnabled(true); m_pctrlStoreWOpp->setEnabled(true); } m_pctrlInitLLTCalc->setChecked(m_bInitLLTCalc); m_pctrlStoreWOpp->setChecked(m_bStoreWOpp); if (!m_pCurWPolar || (m_pCurWPolar && m_pCurWPolar->m_WPolarType SetValue(m_AlphaMin); m_pctrlAlphaMax->SetValue(m_AlphaMax); m_pctrlAlphaDelta->SetValue(m_AlphaDelta); } else if(m_pCurWPolar && m_pCurWPolar->m_WPolarType ==FIXEDAOAPOLAR) { m_pctrlAlphaMin->SetValue(m_QInfMin*MainFrame::s_mstoUnit); m_pctrlAlphaMax->SetValue(m_QInfMax*MainFrame::s_mstoUnit); m_pctrlAlphaDelta->SetValue(m_QInfDelta*MainFrame::s_mstoUnit); } else if(m_pCurWPolar && (m_pCurWPolar->m_WPolarType==STABILITYPOLAR)) { m_pctrlAlphaMin->SetValue(m_ControlMin); m_pctrlAlphaMax->SetValue(m_ControlMax); m_pctrlAlphaDelta->SetValue(m_ControlDelta); } } /** * Initializes the input parameters in the style dialog boxes depending on the type of view and on the active polar or operating point */ void QMiarex::SetCurveParams() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(m_iView==WPOLARVIEW || (m_iView==WSTABVIEW && m_iStabilityView==STABPOLARVIEW)) { if(m_pCurWPolar) { m_pctrlShowCurve->setChecked(m_pCurWPolar->m_bIsVisible); m_pctrlShowPoints->setChecked(m_pCurWPolar->m_bShowPoints); m_CurveColor = m_pCurWPolar->m_Color; m_CurveStyle = m_pCurWPolar->m_Style; m_CurveWidth = m_pCurWPolar->m_Width; FillComboBoxes(); } else { FillComboBoxes(false); } } else if(m_iView==WSTABVIEW&& m_iStabilityView==STABTIMEVIEW) { StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; if(pStabView->m_pCurve) { m_CurveColor = pStabView->m_pCurve->color(); m_CurveStyle = pStabView->m_pCurve->style(); m_CurveWidth = pStabView->m_pCurve->width(); m_pctrlShowCurve->setChecked(pStabView->m_pCurve->IsVisible()); m_pctrlShowPoints->setChecked(pStabView->m_pCurve->PointsVisible()); FillComboBoxes(); } } else if(m_iView==WOPPVIEW) { //set OpPoint params if(m_pCurPOpp) { m_pctrlShowCurve->setChecked(m_pCurPOpp->m_bIsVisible); m_pctrlShowPoints->setChecked(m_pCurPOpp->m_bShowPoints); m_CurveColor = m_pCurPOpp->m_Color; m_CurveStyle = m_pCurPOpp->m_Style; m_CurveWidth = m_pCurPOpp->m_Width; FillComboBoxes(); } else if(m_pCurWOpp) { m_pctrlShowCurve->setChecked(m_pCurWOpp->m_bIsVisible); m_pctrlShowPoints->setChecked(m_pCurWOpp->m_bShowPoints); m_CurveColor = m_pCurWOpp->m_Color; m_CurveStyle = m_pCurWOpp->m_Style; m_CurveWidth = m_pCurWOpp->m_Width; FillComboBoxes(); } else { FillComboBoxes(false); } } else if(m_iView==WCPVIEW) { //set Cp params if(m_pCurWOpp) { m_pctrlShowCurve->setChecked(true); m_pctrlShowPoints->setChecked(m_bShowCpPoints); m_CurveColor = m_CpColor; m_CurveStyle = m_CpStyle; m_CurveWidth = m_CpWidth; FillComboBoxes(); } else { FillComboBoxes(false); } } if(m_pCurWPolar) { if(m_pCurWPolar->m_WPolarTypesetText(QString::fromUtf8("°")); m_pctrlUnit2->setText(QString::fromUtf8("°")); m_pctrlUnit3->setText(QString::fromUtf8("°")); } else if(m_pCurWPolar->m_WPolarType==FIXEDAOAPOLAR) { QString str; GetSpeedUnit(str, MainFrame::s_SpeedUnit); m_pctrlUnit1->setText(str); m_pctrlUnit2->setText(str); m_pctrlUnit3->setText(str); } else { m_pctrlUnit1->setText(""); m_pctrlUnit2->setText(""); m_pctrlUnit3->setText(""); } } } /** * Inserts a modified CPlane object in the array, i.a.w. user instructions * @param pModPlane a pointer to the instance of the CPlane object to be inserted * @return true if the plane was successfully inserted, false otherwise */ bool QMiarex::SetModPlane(Plane *pModPlane) { if(!pModPlane) pModPlane = m_pCurPlane; Plane * pPlane; Wing *pWing; WPolar* pWPolar; PlaneOpp * pPOpp; WingOpp *pWOpp; bool bExists = true; int resp, k, l; QString OldName = pModPlane->PlaneName(); QStringList NameList; for(k=0; ksize(); k++) { pPlane = (Plane*)m_poaPlane->at(k); NameList.append(pPlane->PlaneName()); } for(k=0; ksize(); k++) { pWing = (Wing*)m_poaWing->at(k); NameList.append(pWing->m_WingName); } RenameDlg renDlg((MainFrame*)s_pMainFrame); renDlg.m_pstrArray = & NameList; renDlg.m_strQuestion = tr("Enter the new name for the Plane :"); renDlg.m_strName = pModPlane->PlaneName(); renDlg.InitDialog(); while (bExists) { resp = renDlg.exec(); if(resp==QDialog::Accepted) { if (OldName == renDlg.m_strName) return true; //Is the new name already used ? bExists = false; for (k=0; ksize(); k++) { pPlane = (Plane*)m_poaPlane->at(k); if (pPlane->PlaneName() == renDlg.m_strName) { bExists = true; break; } } for (k=0; ksize(); k++) { pWing = (Wing*)m_poaWing->at(k); if (pWing->m_WingName == renDlg.m_strName) { bExists = true; break; } } if(!bExists) { pModPlane->rPlaneName() = renDlg.m_strName; //replace the Plane in alphabetical order in the array //remove the current Plane from the array bool bInserted = false; for (l=0; lsize();l++) { pPlane = (Plane*)m_poaPlane->at(l); if(pPlane == pModPlane) { m_poaPlane->removeAt(l); // but don't delete it ! //and re-insert it for (l=0; lsize();l++) { pPlane = (Plane*)m_poaPlane->at(l); if(pPlane->PlaneName().compare(pModPlane->PlaneName(), Qt::CaseInsensitive) >0) { //then insert before m_poaPlane->insert(l, pModPlane); bInserted = true; break; } } if(!bInserted) m_poaPlane->append(pModPlane); break; } } } MainFrame::SetSaveState(false); } else if(resp ==10) { //user wants to overwrite the old plane/wing if (OldName == renDlg.m_strName) return true;//don't bother to overwrite itself if(GetPlane(renDlg.m_strName)) { for (k=0; ksize(); k++) { pPlane = (Plane*)m_poaPlane->at(k); if (pPlane->PlaneName() == renDlg.m_strName) { for (l=m_poaWPolar->size()-1;l>=0; l--) { pWPolar = (WPolar*)m_poaWPolar->at(l); if (pWPolar->m_UFOName == pPlane->PlaneName()) { /* m_poaWPolar->removeAt(l); if(pWPolar==m_pCurWPolar) m_pCurWPolar = NULL; delete pWPolar;*/ pWPolar->ResetWPlr(); } } for (l=m_poaPOpp->size()-1;l>=0; l--) { pPOpp = (PlaneOpp*)m_poaPOpp->at(l); if (pPOpp->m_PlaneName == pPlane->PlaneName()) { m_poaPOpp->removeAt(l); delete pPOpp; } } m_pCurPOpp = NULL; m_pCurWOpp = NULL; m_poaPlane->removeAt(k); if(pPlane==m_pCurPlane) m_pCurPlane = NULL; delete pPlane; } } } else if (GetWing(renDlg.m_strName)) { //delete the wing the user wants to overwrite for (k=0; ksize(); k++) { pWing = (Wing*)m_poaWing->at(k); if (pWing->m_WingName == renDlg.m_strName) { for (l=m_poaWPolar->size()-1;l>=0; l--) { pWPolar = (WPolar*)m_poaWPolar->at(l); if (pWPolar->m_UFOName == pWing->m_WingName) { pWPolar->ResetWPlr(); /* m_poaWPolar->removeAt(l); if(pWPolar==m_pCurWPolar) m_pCurWPolar = NULL; delete pWPolar;*/ } } for (l=m_poaWOpp->size()-1;l>=0; l--) { pWOpp = (WingOpp*)m_poaWOpp->at(l); if (pWOpp->m_WingName == pWing->m_WingName) { m_poaWOpp->removeAt(l); if(pWOpp==m_pCurWOpp) m_pCurWOpp = NULL; delete pWOpp; } } m_poaWing->removeAt(k); if(pWing==m_pCurWing) m_pCurWing = NULL; delete pWing; } } } pModPlane->rPlaneName() = renDlg.m_strName; pModPlane->wing()->m_WingName = pModPlane->PlaneName()+"_Wing"; if(pModPlane->wing2()) pModPlane->wing2()->m_WingName = pModPlane->PlaneName()+"_Wing2"; if(pModPlane->stab()) pModPlane->stab()->m_WingName = pModPlane->PlaneName()+"_Elev"; if(pModPlane->fin()) pModPlane->fin()->m_WingName = pModPlane->PlaneName()+"_Fin"; //place the Plane in alphabetical order in the array //remove the current Plane from the array for (l=0; lsize();l++) { pPlane = (Plane*)m_poaPlane->at(l); if(pPlane == m_pCurPlane) { m_poaPlane->removeAt(l); // but don't delete it ! break; } } //and re-insert it bool bInserted = false; for (l=0; lsize();l++) { pPlane = (Plane*)m_poaPlane->at(l); if(pPlane->PlaneName().compare(m_pCurPlane->PlaneName(), Qt::CaseInsensitive) <0) { //then insert before m_poaPlane->insert(l, m_pCurPlane); bInserted = true; break; } } if(!bInserted) m_poaPlane->append(m_pCurPlane); bExists = false; MainFrame::SetSaveState(false); } else { return false;//cancelled } } pModPlane->RenameWings(); return true; } /** * Inserts a modified CWing object in the array, i.a.w. user instructions * @param pModWing a pointer to the instance of the CWing object to be inserted * @return true if the wing was successfully inserted, false otherwise */ bool QMiarex::SetModWing(Wing *pModWing) { if(!pModWing) pModWing = m_pCurWing; Wing * pWing, *pOldWing; Plane *pPlane, *pOldPlane; WPolar* pWPolar; WingOpp * pWOpp; PlaneOpp * pPOpp; bool bExists = true; int resp, k, l; QStringList NameList; for(k=0; ksize(); k++) { pWing = (Wing*)m_poaWing->at(k); NameList.append(pWing->m_WingName); } for(k=0; ksize(); k++) { pPlane = (Plane*)m_poaPlane->at(k); NameList.append(pPlane->PlaneName()); } RenameDlg renDlg((MainFrame*)s_pMainFrame); renDlg.m_pstrArray = & NameList; renDlg.m_strQuestion = tr("Enter the new name for the wing :"); renDlg.m_strName = pModWing->m_WingName; renDlg.InitDialog(); while (bExists) { resp = renDlg.exec(); if(resp==QDialog::Accepted) { //Is the new name already used ? bExists = false; for (k=0; ksize(); k++) { pWing = (Wing*)m_poaWing->at(k); if (pWing->m_WingName == renDlg.m_strName) { bExists = true; break; } } for (k=0; ksize(); k++) { pPlane = (Plane*)m_poaPlane->at(k); if (pPlane->PlaneName() == renDlg.m_strName) { bExists = true; break; } } if(!bExists) { pModWing->m_WingName = renDlg.m_strName; //replace the Wing in alphabetical order in the array //remove the current Wing from the array bool bInserted = false; for (l=0; lsize();l++) { pWing = (Wing*)m_poaWing->at(l); if(pWing == pModWing) { m_poaWing->removeAt(l); // but don't delete it ! //and re-insert it for (l=0; lsize();l++) { pWing = (Wing*)m_poaWing->at(l); if(pWing->m_WingName.compare(pModWing->m_WingName, Qt::CaseInsensitive) >0) { //then insert before m_poaWing->insert(l, pModWing); bInserted = true; break; } } if(!bInserted) m_poaWing->append(pModWing); break; } } MainFrame::SetSaveState(false); return true; } } else if(resp==10) { //user wants to overwrite pOldWing = GetWing(renDlg.m_strName); pOldPlane = GetPlane(renDlg.m_strName); if(pOldWing) { for (k=0; ksize(); k++) { pWing = (Wing*)m_poaWing->at(k); if (pWing->m_WingName == renDlg.m_strName) { for (l=m_poaWPolar->size()-1;l>=0; l--) { pWPolar = (WPolar*)m_poaWPolar->at(l); if (pWPolar->m_UFOName == pWing->m_WingName) { pWPolar->ResetWPlr(); /* m_poaWPolar->removeAt(l); if(pWPolar==m_pCurWPolar) { m_pCurWPolar = NULL; } delete pWPolar;*/ } } for (l=m_poaWOpp->size()-1;l>=0; l--) { pWOpp = (WingOpp*)m_poaWOpp->at(l); if (pWOpp->m_WingName == pWing->m_WingName) { m_poaWOpp->removeAt(l); delete pWOpp; } } m_pCurWOpp = NULL; m_pCurPOpp = NULL; m_poaWing->removeAt(k); if(pWing==m_pCurWing) m_pCurWing = NULL; delete pWing; bExists = false; break; } } } else if(pOldPlane) { // if(pOldPlane->m_bActive) QMessageBox::warning(pMainFrame, tr("Warning"),tr("Cannot overwrite current plane")); // else { for (k=0; ksize(); k++) { pPlane = (Plane*)m_poaPlane->at(k); if (pPlane->PlaneName() == renDlg.m_strName) { for (l=m_poaWPolar->size()-1;l>=0; l--) { pWPolar = (WPolar*)m_poaWPolar->at(l); if (pWPolar->m_UFOName == pPlane->PlaneName()) { pWPolar->ResetWPlr(); /* m_poaWPolar->removeAt(l); if(pWPolar==m_pCurWPolar) { m_pCurWPolar = NULL; m_pCurPOpp = NULL; m_pCurWOpp = NULL; } delete pWPolar;*/ } } for (l=m_poaPOpp->size()-1;l>=0; l--) { pPOpp = (PlaneOpp*)m_poaPOpp->at(l); if (pPOpp->m_PlaneName == pPlane->PlaneName()) { m_poaPOpp->removeAt(l); delete pPOpp; } } m_pCurPOpp = NULL; m_pCurPOpp = NULL; m_poaPlane->removeAt(k); delete pPlane; bExists = false; break; } } } } pModWing->m_WingName = renDlg.m_strName; // m_pCurWing = pModWing; MainFrame::SetSaveState(false); return true; } else { return false;//cancelled } } return false ;//useless... } /** * Inserts a modified CWPolar object in the array, i.a.w. user instructions * @param pModWPolar a pointer to the instance of the CWPolar object to be inserted * @return true if the polr was successfully inserted, false otherwise */ bool QMiarex::SetModWPolar(WPolar *pModWPolar) { if(!pModWPolar) pModWPolar = m_pCurWPolar; WPolar *pWPolar, *pOldWPolar; bool bExists = true; int resp, k, l; QStringList NameList; for(k=0; ksize(); k++) { pWPolar = (WPolar*)m_poaWPolar->at(k); if(pWPolar->m_UFOName==UFOName()) NameList.append(pWPolar->m_PlrName); } RenameDlg dlg(this); dlg.m_pstrArray = & NameList; dlg.m_strQuestion = tr("Enter the new name for the Polar:"); dlg.m_strName = pModWPolar->m_PlrName; dlg.InitDialog(); while (bExists) { //Is the new name already used ? bExists = false; for (k=0; km_PlrName = dlg.m_strName; //replace the WPolar in alphabetical order in the array bool bInserted = false; for (l=0; lsize();l++) { pOldWPolar = (WPolar*)m_poaWPolar->at(l); if(pOldWPolar->m_PlrName.compare(pModWPolar->m_PlrName, Qt::CaseInsensitive) >0) { //then insert before m_poaWPolar->insert(l, pModWPolar); bInserted = true; break; } } if(!bInserted) m_poaWPolar->append(pModWPolar); m_pCurWPolar = pModWPolar; m_pCurWOpp = NULL; m_pCurPOpp = NULL; MainFrame::SetSaveState(false); return true; } //Name exists, ask for a new name resp = dlg.exec(); if(resp==10) { //user wants to overwrite an existing name pOldWPolar = NULL; for(int ipb=0; ipbsize(); ipb++) { pWPolar = (WPolar*)m_poaWPolar->at(ipb); if(pWPolar->m_PlrName==pModWPolar->m_PlrName && pWPolar->m_UFOName==UFOName()) { pOldWPolar = pWPolar; for (l=m_poaPOpp->size()-1;l>=0; l--) { PlaneOpp *pPOpp = (PlaneOpp*)m_poaPOpp->at(l); if (pPOpp->m_PlaneName==pOldWPolar->m_UFOName && pPOpp->m_PlrName==pOldWPolar->m_PlrName) { m_poaPOpp->removeAt(l); delete pPOpp; } } for (l=m_poaWOpp->size()-1;l>=0; l--) { WingOpp *pWOpp = (WingOpp*)m_poaWOpp->at(l); if (pWOpp->m_WingName==pOldWPolar->m_UFOName && pWOpp->m_PlrName==pOldWPolar->m_PlrName) { m_poaWOpp->removeAt(l); delete pWOpp; } } m_pCurPOpp = NULL; m_pCurWOpp = NULL; m_poaWPolar->removeAt(ipb); delete pOldWPolar; m_poaWPolar->insert(ipb, pModWPolar); m_pCurWPolar = pModWPolar; return true; } } } else if(resp==QDialog::Rejected) { return false; } //else continue loop with new name pModWPolar->m_PlrName=dlg.m_strName; } return false ;//useless... } /** * Searches for an operating point with aoa or velocity or control paramter x, for the active polar * Sets it as active, if valid * else sets the current WOpp, if any * else sets the comboBox's first, if any * else sets it to NULL *@param bCurrent, if true, uses the x value of the current operating point; this is useful if the user has changed the polar, but wants to display the same aoa for instance *@return true if a new valid operating point has been selected */ bool QMiarex::SetPlaneOpp(bool bCurrent, double x) { if(!m_pCurPlane) return false; PlaneOpp *pPOpp = NULL; if(bCurrent) pPOpp = m_pCurPOpp; else pPOpp = GetPOpp(x); MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; QString strong; bool bOK; // m_bResetglMesh = true; // m_bResetglWake = true; m_bResetglOpp = true; m_bResetglStream = true; m_bResetglFlow = true; m_bResetglLegend = true; // first restore the panel geometry memcpy(m_Panel, m_MemPanel, m_MatSize* sizeof(Panel)); memcpy(m_Node, m_MemNode, m_nNodes * sizeof(CVector)); if(!pPOpp) { if(m_pCurWPolar) pPOpp = GetPOpp(m_pCurWPolar->m_AMem); else pPOpp = GetPOpp(m_LastWOpp); } if(!pPOpp) { //try to select the first in the ListBox if(pMainFrame->m_pctrlWOpp->count()) { pMainFrame->blockSignals(true); pMainFrame->m_pctrlWOpp->setCurrentIndex(0); pMainFrame->blockSignals(false); strong = pMainFrame->m_pctrlWOpp->itemText(0); x = strong.toDouble(&bOK); if(bOK) { pPOpp = GetPOpp(x); } else pPOpp = NULL; } else{ pPOpp = NULL; } } m_pCurPOpp = pPOpp; SetCurveParams(); if(m_pCurPOpp) { m_LastWOpp = m_pCurPOpp->m_Alpha; m_pCurWOpp = m_pCurPOpp->m_pPlaneWOpp[0]; for(int iw=0; iwm_pPlaneWOpp[iw]) m_pWOpp[iw] = m_pCurPOpp->m_pPlaneWOpp[iw]; else m_pWOpp[iw] = NULL; } if(m_pCurWPolar) m_pCurWPolar->m_AMem = m_pCurPOpp->m_Alpha; //select m_pCurPOpp in the listbox pMainFrame->SelectWOpp(m_pCurPOpp); //if we have a type 7 polar, set the panels in the control's position if(m_pCurWPolar && m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { //set the controls m_pPanelDlg->m_pWPolar = m_pCurWPolar; int nCtrls; QString strong; SetControlPositions(m_Panel, m_Node, m_pCurPOpp->m_Ctrl, nCtrls, strong, false); m_bResetglMesh = true; } } else { m_pCurWOpp = NULL; m_pWOpp[0] = m_pWOpp[1] = m_pWOpp[2] = m_pWOpp[3] = NULL; } if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WSTABVIEW) { StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; pStabView->SetControls(); pStabView->SetMode(); CreateStabilityCurves(); } else if(m_iView==W3DVIEW) { StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; pStabView->SetControls(); pStabView->SetMode(); } if(!m_pCurPOpp) return false; else if(m_iView==WOPPVIEW) { m_bCurveVisible = m_pCurPOpp->m_bIsVisible; m_bCurvePoints = m_pCurPOpp->m_bShowPoints; } return true; } /** * Sets the scale for the 2d or 3d selected view */ void QMiarex::SetScale() { if(m_iView==W3DVIEW || (m_iView==WSTABVIEW&& m_iStabilityView==STAB3DVIEW)) Set3DScale(); else Set2DScale(); } /** * Sets the active wing or plane * Sets an active polar and operating point for this plane, if any are available * @param UFOName the name of the wing or plane to be set as active */ void QMiarex::SetUFO(QString UFOName) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); int i; Wing *pWing; Plane *pPlane; if(!UFOName.length()) { if(m_pCurPlane) UFOName = m_pCurPlane->PlaneName(); else if(m_pCurWing) UFOName = m_pCurWing->WingName(); else { // Find out which is first in Alphabetical order QString FirstWingName, FirstPlaneName; if(m_poaWing->size()) { pWing = (Wing*)m_poaWing->at(0); if(pWing) FirstWingName = pWing->m_WingName; } if(m_poaPlane->size()) { pPlane = (Plane*)m_poaPlane->at(0); if(pPlane) FirstPlaneName = pPlane->PlaneName(); } if(FirstPlaneName.length() && FirstWingName.length()) { if(FirstWingName.compare(FirstPlaneName, Qt::CaseInsensitive) >0) UFOName = FirstPlaneName; else UFOName = FirstWingName; } else if(FirstPlaneName.length()) UFOName = FirstPlaneName; else if(FirstWingName.length()) UFOName = FirstWingName; if(!UFOName.size()) { for(int i=0; iwing(); m_pWingList[0] = m_pCurPlane->wing(); m_pWingList[1] = m_pCurPlane->wing2(); m_pWingList[2] = m_pCurPlane->stab(); if(m_pCurPlane->fin()) { m_pWingList[3] = m_pCurPlane->fin(); m_pWingList[3]->m_bDoubleSymFin = m_pCurPlane->m_bDoubleSymFin; } else m_pWingList[3] = NULL; } else { m_pCurPOpp = NULL; m_pWingList[0] = m_pCurWing; m_pWingList[1] = m_pWingList[2] =m_pWingList[3] = NULL; } m_bResetglGeom = true; if(m_pCurPlane && m_pCurPlane->body()) m_bResetglBody = true; else m_bResetglBody = false; m_bResetglMesh = true; double dx, dz; dx=dz=0.0; if(m_pCurPlane) { if(m_pCurPlane->body()) { dx = m_pCurPlane->BodyPos().x; dz = m_pCurPlane->BodyPos().z; m_pCurPlane->body()->SetKnots(); m_pCurPlane->body()->SetPanelPos(); } } m_NSurfaces = 0; Body *pCurBody=NULL; if(m_pCurPlane) pCurBody = m_pCurPlane->body(); for(int iw=0; iwCreateSurfaces(T, 0.0, 0.0); else if(iw<3) m_pWingList[iw]->CreateSurfaces(m_pCurPlane->WingLE(iw), 0.0, m_pCurPlane->WingTiltAngle(iw)); else if(iw==3) m_pWingList[iw]->CreateSurfaces(m_pCurPlane->WingLE(iw), -90.0, m_pCurPlane->WingTiltAngle(iw)); for (i=0; im_NSurfaces; i++) { m_pWingList[iw]->m_Surface[i].SetSidePoints(pCurBody, dx, dz); m_pSurface[m_NSurfaces] = &m_pWingList[iw]->m_Surface[i]; m_NSurfaces++; } m_pWingList[iw]->ComputeBodyAxisInertia(); } } if(m_pCurPlane) m_pCurPlane->ComputeBodyAxisInertia(); MainFrame*pMainFrame = (MainFrame*)s_pMainFrame; pMainFrame->UpdateWPolars(); if (m_pCurWPolar) { // try to set the same as the existing polar SetWPolar(false, m_pCurWPolar->m_PlrName); } else { SetWPolar(); } SetScale(); SetWGraphScale(); SetControls(); QApplication::restoreOverrideCursor(); } /** * Constructs the layout of the QMiarex widget */ void QMiarex::SetupLayout() { QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::Expanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Expanding); QSizePolicy szPolicyMinimum; szPolicyMinimum.setHorizontalPolicy(QSizePolicy::Minimum); szPolicyMinimum.setVerticalPolicy(QSizePolicy::Minimum); QSizePolicy szPolicyMaximum; szPolicyMaximum.setHorizontalPolicy(QSizePolicy::Maximum); szPolicyMaximum.setVerticalPolicy(QSizePolicy::Maximum); QSizePolicy szPolicyPreferred; szPolicyPreferred.setHorizontalPolicy(QSizePolicy::Preferred); szPolicyPreferred.setVerticalPolicy(QSizePolicy::Preferred); //_______________________Analysis QGroupBox *AnalysisBox = new QGroupBox(tr("Analysis settings")); { QVBoxLayout *AnalysisGroupLayout = new QVBoxLayout; { m_pctrlSequence = new QCheckBox(tr("Sequence")); QGridLayout *SequenceGroupLayout = new QGridLayout; { QLabel *AlphaMinLab = new QLabel(tr("Start=")); QLabel *AlphaMaxLab = new QLabel(tr("End=")); QLabel *AlphaDeltaLab = new QLabel(tr("D=")); AlphaDeltaLab->setFont(QFont("Symbol")); AlphaDeltaLab->setAlignment(Qt::AlignRight); AlphaMinLab->setAlignment(Qt::AlignRight); AlphaMaxLab->setAlignment(Qt::AlignRight); m_pctrlAlphaMin = new DoubleEdit(0.0, 3); m_pctrlAlphaMax = new DoubleEdit(1., 3); m_pctrlAlphaDelta = new DoubleEdit(0.5, 3); m_pctrlUnit1 = new QLabel(QString::fromUtf8("°")); m_pctrlUnit2 = new QLabel(QString::fromUtf8("°")); m_pctrlUnit3 = new QLabel(QString::fromUtf8("°")); m_pctrlAlphaMin->setAlignment(Qt::AlignRight); m_pctrlAlphaMax->setAlignment(Qt::AlignRight); m_pctrlAlphaDelta->setAlignment(Qt::AlignRight); SequenceGroupLayout->addWidget(AlphaMinLab,1,1); SequenceGroupLayout->addWidget(AlphaMaxLab,2,1); SequenceGroupLayout->addWidget(AlphaDeltaLab,3,1); SequenceGroupLayout->addWidget(m_pctrlAlphaMin,1,2); SequenceGroupLayout->addWidget(m_pctrlAlphaMax,2,2); SequenceGroupLayout->addWidget(m_pctrlAlphaDelta,3,2); SequenceGroupLayout->addWidget(m_pctrlUnit1,1,3); SequenceGroupLayout->addWidget(m_pctrlUnit2,2,3); SequenceGroupLayout->addWidget(m_pctrlUnit3,3,3); } QHBoxLayout *AnalysisSettingsLayout = new QHBoxLayout; { m_pctrlInitLLTCalc = new QCheckBox(tr("Init LLT")); m_pctrlStoreWOpp = new QCheckBox(tr("Store OpPoint")); AnalysisSettingsLayout->addWidget(m_pctrlInitLLTCalc); AnalysisSettingsLayout->addWidget(m_pctrlStoreWOpp); } m_pctrlAnalyze = new QPushButton(tr("Analyze")); AnalysisGroupLayout->addWidget(m_pctrlSequence); AnalysisGroupLayout->addLayout(SequenceGroupLayout); AnalysisGroupLayout->addStretch(1); AnalysisGroupLayout->addLayout(AnalysisSettingsLayout); AnalysisGroupLayout->addWidget(m_pctrlAnalyze); } AnalysisBox->setLayout(AnalysisGroupLayout); } //_______________________Display QGroupBox *DisplayBox = new QGroupBox(tr("Results")); { QGridLayout *CheckDispLayout = new QGridLayout; { m_pctrlPanelForce = new QCheckBox(tr("Panel Forces")); m_pctrlPanelForce->setToolTip(tr("Display the force 1/2.rho.V2.S.Cp acting on the panel")); m_pctrlLift = new QCheckBox(tr("Lift")); m_pctrlIDrag = new QCheckBox(tr("Ind. Drag")); m_pctrlVDrag = new QCheckBox(tr("Visc. Drag")); m_pctrlTrans = new QCheckBox(tr("Trans.")); m_pctrlMoment = new QCheckBox(tr("Moment")); m_pctrlDownwash = new QCheckBox(tr("Downw.")); m_pctrlCp = new QCheckBox(tr("Cp")); m_pctrlSurfVel = new QCheckBox(tr("Surf. Vel.")); m_pctrlStream = new QCheckBox(tr("Stream")); m_pctrlWOppAnimate = new QCheckBox(tr("Animate")); // m_pctrlHighlightOpp = new QCheckBox(tr("Highlight OpPoint")); m_pctrlAnimateWOppSpeed = new QSlider(Qt::Horizontal); m_pctrlAnimateWOppSpeed->setMinimum(0); m_pctrlAnimateWOppSpeed->setMaximum(500); m_pctrlAnimateWOppSpeed->setSliderPosition(250); m_pctrlAnimateWOppSpeed->setTickInterval(50); m_pctrlAnimateWOppSpeed->setTickPosition(QSlider::TicksBelow); CheckDispLayout->addWidget(m_pctrlCp, 1,1); CheckDispLayout->addWidget(m_pctrlPanelForce, 1, 2); CheckDispLayout->addWidget(m_pctrlLift, 2, 1); CheckDispLayout->addWidget(m_pctrlMoment, 2, 2); CheckDispLayout->addWidget(m_pctrlIDrag, 3, 1); CheckDispLayout->addWidget(m_pctrlVDrag, 3, 2); CheckDispLayout->addWidget(m_pctrlTrans, 4, 1); CheckDispLayout->addWidget(m_pctrlDownwash, 4, 2); CheckDispLayout->addWidget(m_pctrlSurfVel, 5, 1); CheckDispLayout->addWidget(m_pctrlStream, 5, 2); CheckDispLayout->addWidget(m_pctrlWOppAnimate, 6, 1); CheckDispLayout->addWidget(m_pctrlAnimateWOppSpeed,6,2); } DisplayBox->setLayout(CheckDispLayout); } QGroupBox *PolarPropsBox = new QGroupBox(tr("Polar properties")); { m_pctrlPolarProps1 = new QTextEdit; m_pctrlPolarProps1->setReadOnly(true); // m_pctrlPolarProps1->setWordWrapMode(QTextOption::NoWrap); QHBoxLayout *PolarPropsLayout = new QHBoxLayout; { PolarPropsLayout->addWidget(m_pctrlPolarProps1); PolarPropsLayout->addStretch(1); } PolarPropsBox->setLayout(PolarPropsLayout); } //_______________________Curve params QGroupBox *CurveBox = new QGroupBox(tr("Curve settings")); { QVBoxLayout *CurveGroupLayout = new QVBoxLayout; { m_pctrlShowCurve = new QCheckBox(tr("Curve")); m_pctrlShowPoints = new QCheckBox(tr("Points")); m_pctrlCurveStyle = new LineCbBox(this); m_pctrlCurveWidth = new LineCbBox(this); m_pctrlCurveColor = new LineBtn(); // m_pctrlCurveColor->setMinimumHeight(m_pctrlCurveStyle->sizeHint().height()); for (int i=0; i<5; i++) { m_pctrlCurveStyle->addItem(tr("item")); m_pctrlCurveWidth->addItem(tr("item")); } m_pStyleDelegate = new LineDelegate; m_pWidthDelegate = new LineDelegate; m_pctrlCurveStyle->setItemDelegate(m_pStyleDelegate); m_pctrlCurveWidth->setItemDelegate(m_pWidthDelegate); QHBoxLayout *ShowCurve = new QHBoxLayout; { ShowCurve->addWidget(m_pctrlShowCurve); ShowCurve->addWidget(m_pctrlShowPoints); } QGridLayout *CurveStyleLayout = new QGridLayout; { QLabel *lab200 = new QLabel(tr("Style")); QLabel *lab201 = new QLabel(tr("Width")); QLabel *lab202 = new QLabel(tr("Color")); lab200->setAlignment(Qt::AlignRight |Qt::AlignVCenter); lab201->setAlignment(Qt::AlignRight |Qt::AlignVCenter); lab202->setAlignment(Qt::AlignRight |Qt::AlignVCenter); CurveStyleLayout->addWidget(lab200,1,1); CurveStyleLayout->addWidget(lab201,2,1); CurveStyleLayout->addWidget(lab202,3,1); CurveStyleLayout->addWidget(m_pctrlCurveStyle,1,2); CurveStyleLayout->addWidget(m_pctrlCurveWidth,2,2); CurveStyleLayout->addWidget(m_pctrlCurveColor,3,2); CurveStyleLayout->setColumnStretch(2,5); } CurveGroupLayout->addLayout(ShowCurve); CurveGroupLayout->addLayout(CurveStyleLayout); CurveGroupLayout->addStretch(1); } CurveBox->setLayout(CurveGroupLayout); } //_______________________Cp Params QGroupBox *CpBox = new QGroupBox(tr("Cp Sections")); { QVBoxLayout *CpParams = new QVBoxLayout; { m_pctrlCpSectionSlider = new QSlider(Qt::Horizontal); m_pctrlCpSectionSlider->setMinimum(-100); m_pctrlCpSectionSlider->setMaximum(100); m_pctrlCpSectionSlider->setSliderPosition(00); m_pctrlCpSectionSlider->setTickInterval(10); m_pctrlCpSectionSlider->setTickPosition(QSlider::TicksBelow); QHBoxLayout *CpPos = new QHBoxLayout; { QLabel *label1000 = new QLabel(tr("Span Position")); m_pctrlSpanPos = new DoubleEdit(0.0, 3); CpPos->addWidget(label1000); CpPos->addWidget(m_pctrlSpanPos); } QHBoxLayout *CpSections = new QHBoxLayout; { m_pctrlKeepCpSection = new QPushButton(tr("Keep")); m_pctrlResetCpSection = new QPushButton(tr("Reset")); CpSections->addWidget(m_pctrlKeepCpSection); CpSections->addWidget(m_pctrlResetCpSection); } CpParams->addWidget(m_pctrlCpSectionSlider); CpParams->addLayout(CpPos); CpParams->addLayout(CpSections); CpParams->addStretch(1); } CpBox->setLayout(CpParams); } //_______________________3D view controls QGroupBox *ThreeDViewBox = new QGroupBox(tr("Display")); { QVBoxLayout *ThreeDViewControls = new QVBoxLayout; { QGridLayout *ThreeDParams = new QGridLayout; { m_pctrlAxes = new QCheckBox(tr("Axes")); m_pctrlLight = new QCheckBox(tr("Light")); m_pctrlSurfaces = new QCheckBox(tr("Surfaces")); m_pctrlOutline = new QCheckBox(tr("Outline")); m_pctrlPanels = new QCheckBox(tr("Panels")); m_pctrlFoilNames = new QCheckBox(tr("Foil Names")); m_pctrlVortices = new QCheckBox(tr("Vortices")); m_pctrlMasses = new QCheckBox(tr("Masses")); ThreeDParams->addWidget(m_pctrlAxes, 1,1); // ThreeDParams->addWidget(m_pctrlLight, 1,2); ThreeDParams->addWidget(m_pctrlPanels, 1,2); ThreeDParams->addWidget(m_pctrlSurfaces, 2,1); ThreeDParams->addWidget(m_pctrlOutline, 2,2); ThreeDParams->addWidget(m_pctrlFoilNames, 3,1); ThreeDParams->addWidget(m_pctrlMasses, 3,2); } QVBoxLayout *ThreeDView = new QVBoxLayout; { QHBoxLayout *AxisViewLayout = new QHBoxLayout; { m_pctrlX = new QToolButton; m_pctrlY = new QToolButton; m_pctrlZ = new QToolButton; m_pctrlIso = new QToolButton; if(m_pctrlX->iconSize().height()<=48) { m_pctrlX->setIconSize(QSize(24,24)); m_pctrlY->setIconSize(QSize(24,24)); m_pctrlZ->setIconSize(QSize(24,24)); m_pctrlIso->setIconSize(QSize(24,24)); } m_pXView = new QAction(QIcon(":/images/OnXView.png"), tr("X View"), this); m_pYView = new QAction(QIcon(":/images/OnYView.png"), tr("Y View"), this); m_pZView = new QAction(QIcon(":/images/OnZView.png"), tr("Z View"), this); m_pIsoView = new QAction(QIcon(":/images/OnIsoView.png"), tr("Iso View"), this); m_pXView->setCheckable(true); m_pYView->setCheckable(true); m_pZView->setCheckable(true); m_pIsoView->setCheckable(true); m_pctrlX->setDefaultAction(m_pXView); m_pctrlY->setDefaultAction(m_pYView); m_pctrlZ->setDefaultAction(m_pZView); m_pctrlIso->setDefaultAction(m_pIsoView); AxisViewLayout->addWidget(m_pctrlX); AxisViewLayout->addWidget(m_pctrlY); AxisViewLayout->addWidget(m_pctrlZ); AxisViewLayout->addWidget(m_pctrlIso); } QHBoxLayout *ViewResetLayout = new QHBoxLayout; { m_pctrlPickCenter = new QPushButton(tr("Pick Center")); m_pctrlPickCenter->setToolTip(tr("Activate the button, then click on the object to center it in the viewport; alternatively, double click on the object")); m_pctrlReset = new QPushButton(tr("Reset")); m_pctrlPickCenter->setCheckable(true); ViewResetLayout->addWidget(m_pctrlReset); ViewResetLayout->addWidget(m_pctrlPickCenter); } ThreeDView->addLayout(AxisViewLayout); ThreeDView->addLayout(ViewResetLayout); } QHBoxLayout *ClipLayout = new QHBoxLayout; { QLabel *ClipLabel = new QLabel(tr("Clip:")); m_pctrlClipPlanePos = new QSlider(Qt::Horizontal); m_pctrlClipPlanePos->setMinimum(-300); m_pctrlClipPlanePos->setMaximum(300); m_pctrlClipPlanePos->setSliderPosition(0); m_pctrlClipPlanePos->setTickInterval(30); m_pctrlClipPlanePos->setTickPosition(QSlider::TicksBelow); ClipLayout->addWidget(ClipLabel); ClipLayout->addWidget(m_pctrlClipPlanePos,1); } ThreeDViewControls->addLayout(ThreeDParams); ThreeDViewControls->addStretch(1); ThreeDViewControls->addLayout(ThreeDView); ThreeDViewControls->addLayout(ClipLayout); ThreeDViewControls->addStretch(1); } ThreeDViewBox->setLayout(ThreeDViewControls); } //_________________________Main Layout QVBoxLayout *mainLayout = new QVBoxLayout; { m_pctrlMiddleControls = new QStackedWidget; m_pctrlMiddleControls->addWidget(DisplayBox); m_pctrlMiddleControls->addWidget(PolarPropsBox); m_pctrlMiddleControls->addWidget(CpBox); m_pctrBottomControls = new QStackedWidget; m_pctrBottomControls->addWidget(CurveBox); m_pctrBottomControls->addWidget(ThreeDViewBox); mainLayout->addWidget(AnalysisBox); mainLayout->addWidget(m_pctrlMiddleControls); mainLayout->addWidget(m_pctrBottomControls); } setLayout(mainLayout); } /** * Sets the scale of the graphs in the operating point view. *The scale is set i.a.w. with wing span, if any */ void QMiarex::SetWGraphScale() { if(!m_pCurWing) { for(int ig=0; ig<4; ig++) { m_WingGraph[ig].SetAuto(false); m_WingGraph[ig].SetXUnit(10.0); m_WingGraph[ig].SetXMin(-100.0); m_WingGraph[ig].SetXMax( 100.0); } } else { double halfspan = m_pCurWing->m_PlanformSpan/2.0; double xmin; if(m_bHalfWing) xmin = 0.0; else xmin = -halfspan*MainFrame::s_mtoUnit; for(int ig=0; ig<4; ig++) { m_WingGraph[ig].SetAutoX(false); m_WingGraph[ig].SetXMin(xmin); m_WingGraph[ig].SetXMax( halfspan*MainFrame::s_mtoUnit); m_WingGraph[ig].SetAutoXUnit(); } } } /** * Sets the active polar * Builds the array of panels depending on the polar type * @param bCurrent if true, the active polar is set anew * @param WPlrName the name of the polar to set for the active wing or plane */ void QMiarex::SetWPolar(bool bCurrent, QString WPlrName) { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; WPolar *pWPolar = NULL; WPolar *pOldWPolar = NULL; QString UFOName; int i,j,k,m, NStation; double SpanPos; if(m_pCurPlane) UFOName = m_pCurPlane->PlaneName(); else if(m_pCurWing) UFOName = m_pCurWing->WingName(); else return; if(!WPlrName.length() && m_pCurWPolar) WPlrName = m_pCurWPolar->m_PlrName; if(bCurrent) pWPolar = m_pCurWPolar; else { for (i=0; isize(); i++) { pOldWPolar = (WPolar*) m_poaWPolar->at(i); if (pOldWPolar->m_UFOName == UFOName && pOldWPolar->m_PlrName == WPlrName) { pWPolar = pOldWPolar; break; } } } if(!pWPolar || pWPolar != m_pCurWPolar) { m_bResetglMesh = true; if(!m_pCurWing) { pWPolar = NULL; m_pCurWPolar = NULL; } if(pWPolar) m_pCurWPolar = pWPolar; else if(m_pCurWing) { // set the first one in the array, if any m_pCurWPolar = NULL; for(i=0; i< m_poaWPolar->size(); i++) { pWPolar = (WPolar*)m_poaWPolar->at(i); if(pWPolar && pWPolar->m_UFOName==UFOName) { m_pCurWPolar = pWPolar; break; } } } } if(m_pCurWPolar) { int pos = pMainFrame->m_pctrlWPolar->findText(m_pCurWPolar->m_PlrName); if (pos>=0) { pMainFrame->m_pctrlWPolar->blockSignals(true); pMainFrame->m_pctrlWPolar->setCurrentIndex(pos); pMainFrame->m_pctrlWPolar->blockSignals(false); } } if(!InitializePanels()) return; //set sideslip CVector RefPoint(0.0, 0.0, 0.0); if(m_pCurWPolar && qAbs(m_pCurWPolar->m_Beta)>0.001) { RotateGeomZ(m_MemPanel, m_MemNode, m_WakePanel, m_WakeNode, m_pCurWPolar->m_Beta, RefPoint); } if(m_pCurWPolar && m_pCurWPolar->m_UFOName==UFOName) { if(m_pCurWPolar->m_AnalysisMethod>LLTMETHOD) { for(int iw=0; iwComputeChords(); NStation = 0; m=0; SpanPos = 0; for (j=0; jm_NSurfaces; j++) NStation += m_pWingList[iw]->m_Surface[j].m_NYPanels; for (j=(int)(m_pWingList[iw]->m_NSurfaces/2); jm_NSurfaces; j++) { for(k=0; km_Surface[j].m_NYPanels; k++) { m_pWingList[iw]->m_SpanPos[m+NStation/2] = SpanPos + m_pWingList[iw]->m_Surface[j].GetStripSpanPos(k); m++; } SpanPos += m_pWingList[iw]->m_Surface[j].m_Length; } for(m=0; mm_SpanPos[m] = -m_pWingList[iw]->m_SpanPos[NStation-m-1]; } } } else if(m_pCurWPolar->m_AnalysisMethod==LLTMETHOD) { // m_pCurWing->m_NStation = m_NStation; // m_pCurWing->m_bLLT = true; } pMainFrame->UpdateWOpps(); double Alpha = 0.0; if(m_pCurWOpp) Alpha = m_pCurWOpp->m_Alpha; if(m_pCurPlane) SetPlaneOpp(false, Alpha); else if(m_pCurWing) SetWingOpp(false, Alpha); /* if (m_pCurPOpp){ // try to set the same as the existing WOpp... Special for Marc if(!SetPOpp(false, m_pCurPOpp->m_Alpha)) SetPOpp(true);// try again from scratch } else if (m_pCurWOpp){ // try to set the same as the existing WOpp... Special for Marc if(!SetWOpp(false, m_pCurWOpp->m_Alpha)) SetWOpp(true);// try again from scratch } else SetWOpp(true);*/ } else { m_pCurWPolar = NULL; m_pCurPOpp = NULL; m_pCurWOpp = NULL; for(int iw=0; iwUpdateWOpps(); } if(m_pCurWPolar) { m_bCurveVisible = m_pCurWPolar->m_bIsVisible; m_bCurvePoints = m_pCurWPolar->m_bShowPoints; if(m_pCurWPolar->m_bAutoInertia) { if(m_pCurPlane) { m_pCurWPolar->m_Mass = m_pCurPlane->TotalMass(); m_pCurWPolar->m_CoG = m_pCurPlane->CoG(); m_pCurWPolar->m_CoGIxx = m_pCurPlane->m_CoGIxx; m_pCurWPolar->m_CoGIyy = m_pCurPlane->m_CoGIyy; m_pCurWPolar->m_CoGIzz = m_pCurPlane->m_CoGIzz; m_pCurWPolar->m_CoGIxz = m_pCurPlane->m_CoGIxz; } else if(m_pCurWing) { m_pCurWPolar->m_Mass = m_pCurWing->TotalMass(); m_pCurWPolar->m_CoG = m_pCurWing->m_CoG; m_pCurWPolar->m_CoGIxx = m_pCurWing->m_CoGIxx; m_pCurWPolar->m_CoGIyy = m_pCurWing->m_CoGIyy; m_pCurWPolar->m_CoGIzz = m_pCurWing->m_CoGIzz; m_pCurWPolar->m_CoGIxz = m_pCurWing->m_CoGIxz; } QString PolarProps; m_pCurWPolar->GetPolarProperties(PolarProps); m_pctrlPolarProps1->setText(PolarProps); } } else m_pctrlPolarProps1->clear(); if(m_iView==WPOLARVIEW) CreateWPolarCurves(); else if(m_iView==WSTABVIEW) CreateStabilityCurves(); else if(m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); SetAnalysisParams(); SetCurveParams(); m_bResetglLegend = true; m_pPanelDlg->m_pWPolar = m_pCurWPolar; m_pPanelDlg->m_MatSize = m_MatSize; m_pPanelDlg->m_WakeSize = m_WakeSize; m_pPanelDlg->m_nNodes = m_nNodes; m_pPanelDlg->m_NSurfaces = m_NSurfaces; m_pPanelDlg->m_NWakeColumn = m_NWakeColumn; if(m_pCurWPolar && m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; pStabView->SetControls(); pStabView->SetMode(); pMainFrame->m_pctrlStabViewWidget->show(); pStabView->show(); } QApplication::restoreOverrideCursor(); } /** * Sets the position for the legend in the operating point view */ void QMiarex::SetWingLegendPos() { int h = m_r2DCltRect.height(); int h23 = (int)(2*h/3); int h34 = (int)(3*h/4); int margin = 10; if(m_iView==WOPPVIEW) { if(m_iWingView == 1) { m_WingLegendOffset.rx() = m_r2DCltRect.right()-300+margin; m_WingLegendOffset.ry() = 0; } else if(m_iWingView == 2) { m_WingLegendOffset.rx() = margin; m_WingLegendOffset.ry() = h23+margin; } else { m_WingLegendOffset.rx() = margin; m_WingLegendOffset.ry() = h34+margin; } } else if(m_iView==WSTABVIEW) { if(m_iStabTimeView < 4) { m_WingLegendOffset.rx() = margin; m_WingLegendOffset.ry() = h34+margin; } else if(m_iStabTimeView ==4) { m_WingLegendOffset.rx() = margin; m_WingLegendOffset.ry() = h34+margin; } } } /** * Sets the position for the legend in the polar view */ void QMiarex::SetWPlrLegendPos() { int h = m_r2DCltRect.height(); int w = m_r2DCltRect.width(); int h23 = (int)(2*h/3); int margin = 10; if(m_iView==WPOLARVIEW) { if(m_iWPlrView == ONEPOLARGRAPH) { m_WPlrLegendOffset.rx() = (int)(0.70*w)+margin; m_WPlrLegendOffset.ry() = margin; } else if (m_iWPlrView == TWOPOLARGRAPHS) { m_WPlrLegendOffset.rx() = margin; m_WPlrLegendOffset.ry() = h23+margin; } else if (m_iWPlrView == ALLPOLARGRAPHS) { m_WPlrLegendOffset.rx() = (int)(0.70*w)+margin; m_WPlrLegendOffset.ry() = margin; } } else if(m_iView==WSTABVIEW) { if(m_iStabilityView==STABPOLARVIEW) { m_WPlrLegendOffset.rx() = (int)(0.70*w)+margin; m_WPlrLegendOffset.ry() = margin; } } } /** * Sets the active WOpp * If a plane is active rather than a wing, a CPOpp will be set instead *@param bCurrent if true, the active wopp is set anew *@param x the aoa or velocity or control parameter of the operating point to set *@return true if an operating point was successfully set */ bool QMiarex::SetWingOpp(bool bCurrent, double x) { m_bResetglOpp = true; m_bResetglStream = true; m_bResetglFlow = true; m_bResetglLegend = true; // first restore the panel geometry memcpy(m_Panel, m_MemPanel, m_MatSize* sizeof(Panel)); memcpy(m_Node, m_MemNode, m_nNodes * sizeof(CVector)); if(!m_pCurWing || !m_pCurWPolar) { m_pCurWOpp = NULL; m_pCurPOpp = NULL; m_pWOpp[0] = m_pWOpp[1] = m_pWOpp[2] = m_pWOpp[3] = NULL; SetCurveParams(); return false; } MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; // set set the current WOpp, if any // else set the comboBox's first, if any // else set it to NULL QString strong; if(m_pCurPlane) return SetPlaneOpp(bCurrent, x); WingOpp *pWOpp = NULL; if(bCurrent) { pWOpp = m_pCurWOpp; if(pWOpp) { //Check it is consistent with wing and polar if(pWOpp->m_WingName != m_pCurWing->WingName() || pWOpp->m_PlrName!=m_pCurWPolar->m_PlrName) pWOpp=NULL; } } else pWOpp = GetWOpp(x); if(!pWOpp) { //first try to set the last alpha which has been selected if(m_pCurWPolar) pWOpp = GetWOpp(m_pCurWPolar->m_AMem); else pWOpp = GetWOpp(m_LastWOpp); } if(!pWOpp) { //try to select the first in the ListBox if(pMainFrame->m_pctrlWOpp->count()) { double x; pMainFrame->blockSignals(true); pMainFrame->m_pctrlWOpp->setCurrentIndex(0); pMainFrame->blockSignals(false); strong = pMainFrame->m_pctrlWOpp->itemText(0); bool bOK; x = strong.toDouble(&bOK); if(bOK) { pWOpp = GetWOpp(x); } else pWOpp = NULL; } else { pWOpp = NULL; } } m_pCurWOpp = pWOpp; m_pWOpp[0] = pWOpp; m_pWOpp[1] = m_pWOpp[2] = m_pWOpp[3] = NULL; SetCurveParams(); if(m_pCurWOpp) { m_LastWOpp = m_pCurWOpp->m_Alpha; m_pCurWPolar->m_AMem = m_pCurWOpp->m_Alpha; // m_nWakeNodes = m_pCurWOpp->m_nWakeNodes; // m_NXWakePanels = m_pCurWOpp->m_NXWakePanels; // m_TotalWakeLength = m_pCurWOpp->m_FirstWakePanel; // m_WakePanelFactor = m_pCurWOpp->m_WakeFactor; //select m_pCurWOpp in the listbox pMainFrame->SelectWOpp(m_pCurWOpp); //if we have a type 7 polar, set the panels in the control's position if(m_pCurWPolar && m_pCurWPolar->m_WPolarType==STABILITYPOLAR) { //set the controls m_pPanelDlg->m_pWPolar = m_pCurWPolar; m_pPanelDlg->m_pPlane = m_pCurPlane; for(int iw=0; iwm_pWingList[iw] = m_pWingList[iw]; Body *pCurBody = NULL; if(m_pCurPlane) pCurBody = m_pCurPlane->body(); m_pPanelDlg->m_pBody = pCurBody; int nCtrls; QString strong; SetControlPositions(m_Panel, m_Node, m_pCurWOpp->m_Ctrl, nCtrls, strong, false); m_bResetglMesh = true; } } if(m_iView==WPOLARVIEW) { if(m_bHighlightOpp) CreateWPolarCurves(); } else if(m_iView==WOPPVIEW) CreateWOppCurves(); else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==WSTABVIEW) { StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; pStabView->SetControls(); pStabView->SetMode(); CreateStabilityCurves(); } else if(m_iView==W3DVIEW) { StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; pStabView->SetControls(); pStabView->SetMode(); // CreateStabilityCurves(); } if(!m_pCurWOpp) return false; else if(m_iView==WOPPVIEW) { m_bCurveVisible = m_pCurWOpp->m_bIsVisible; m_bCurvePoints = m_pCurWOpp->m_bShowPoints; } return true; } /** * Sets the y-axis titles of the stability time response graphs, depending on the selected units */ void QMiarex::SetStabGraphTitles() { QString strLength; GetSpeedUnit(strLength, MainFrame::s_SpeedUnit); if(m_bLongitudinal) { m_TimeGraph[0].SetYTitle("u ("+strLength+")"); m_TimeGraph[1].SetYTitle("w ("+strLength+")"); m_TimeGraph[2].SetYTitle("q ("+QString::fromUtf8("°") +"/s)"); m_TimeGraph[3].SetYTitle("theta "+QString::fromUtf8("(°)")); } else { m_TimeGraph[0].SetYTitle("v ("+strLength+")"); m_TimeGraph[1].SetYTitle("p ("+QString::fromUtf8("°") +"/s)"); m_TimeGraph[2].SetYTitle("r ("+QString::fromUtf8("°") +"/s)"); m_TimeGraph[3].SetYTitle("phi "+QString::fromUtf8("(°)")); } } /** * Sets the x and y axis titles of the polar graphs */ void QMiarex::SetWGraphTitles(Graph* pGraph) { QString Title; WPolar::GetUFOPlrVariableName(pGraph->GetXVariable(), Title); pGraph->SetXTitle(Title); WPolar::GetUFOPlrVariableName(pGraph->GetYVariable(), Title); pGraph->SetYTitle(Title); } /** * Overrides the parent's widget showEvent method * Fills the main dialog box with default or selected data * @param event unused */ void QMiarex::showEvent(QShowEvent *event) { SetAnalysisParams(); SetCurveParams(); } /** * Captures the pixels of the client area and writes them to a file * @param FileName the name of the destination image file */ void QMiarex::SnapClient(QString const &FileName) { int NbBytes, bitsPerPixel; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QSize size(m_r3DCltRect.width(),m_r3DCltRect.height()); ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; QGLFormat GLFormat = p3dWidget->format(); if(!GLFormat.rgba()) { QMessageBox::warning(pMainFrame,tr("Warning"),tr("OpenGL color format is not recognized... Sorry")); return; } bitsPerPixel = 24; int width = size.width(); switch(bitsPerPixel) { case 8: { QMessageBox::warning(pMainFrame,tr("Warning"),tr("Cannot (yet ?) save 8 bit depth opengl screen images... Sorry")); return; } case 16: { QMessageBox::warning(pMainFrame,tr("Warning"),tr("Cannot (yet ?) save 16 bit depth opengl screen images... Sorry")); size.setWidth(width - size.width() % 2); return; } case 24: { NbBytes = 4 * size.width() * size.height();//24 bits type BMP // size.setWidth(width - size.width() % 4); break; } case 32: { NbBytes = 4 * size.width() * size.height();//32 bits type BMP break; } default: { QMessageBox::warning(pMainFrame,tr("Warning"),tr("Unidentified bit depth... Sorry")); return; } } uchar *pPixelData = new uchar[NbBytes]; // Copy from OpenGL glReadBuffer(GL_FRONT); switch(bitsPerPixel) { case 8: return; case 16: return; case 24: { #if QT_VERSION >= 0x040400 glReadPixels(0,0,size.width(),size.height(),GL_RGB,GL_UNSIGNED_BYTE,pPixelData); QImage Image(pPixelData, size.width(),size.height(), QImage::Format_RGB888); QImage FlippedImaged; FlippedImaged = Image.mirrored(); //flip vertically FlippedImaged.save(FileName); #else QMessageBox::warning(pMainFrame,tr("Warning"),"The version of Qt used to compile the code is older than 4.4 and does not support 24 bit images... Sorry"); #endif break; } case 32: { glReadPixels(0,0,size.width(),size.height(),GL_RGBA,GL_UNSIGNED_BYTE,pPixelData); QImage Image(pPixelData, size.width(),size.height(), QImage::Format_ARGB32); QImage FlippedImaged; FlippedImaged = Image.mirrored(); //flip vertically FlippedImaged.save(FileName); break; } default: break; } } /** * Cancels the animation whatever the active view */ void QMiarex::StopAnimate() { m_bAnimateWOpp = false; m_pctrlWOppAnimate->setChecked(false); m_pTimerWOpp->stop(); m_pTimerMode->stop(); MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; StabViewDlg *pStabView =(StabViewDlg*)pMainFrame->m_pStabView; m_bAnimateMode = false; pStabView->m_pctrlAnimate->setChecked(false); if(!m_bAnimateWOpp) return; if(m_iView!=WSTABVIEW) { if(m_pCurPlane) { SetPlaneOpp(true); } else if(m_pCurWing) { SetWingOpp(true); } } } /** * Updates the active curve with the data from the currently active operating points or polars. */ void QMiarex::UpdateCurve() { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; if(m_iView==WPOLARVIEW && m_pCurWPolar) { m_pCurWPolar->m_Color = m_CurveColor; m_pCurWPolar->m_Style = m_CurveStyle; m_pCurWPolar->m_Width = m_CurveWidth; m_pCurWPolar->m_bIsVisible = m_bCurveVisible; m_pCurWPolar->m_bShowPoints = m_bCurvePoints; CreateWPolarCurves(); } else if(m_iView==WSTABVIEW && m_pCurWPolar) { if(m_iStabilityView==STABTIMEVIEW) { StabViewDlg *pStabView = (StabViewDlg*)pMainFrame->m_pStabView; pStabView->SetTimeCurveStyle(m_CurveColor, m_CurveStyle, m_CurveWidth, m_bCurveVisible, m_bCurvePoints); } else if(m_iStabilityView==STABPOLARVIEW) { m_pCurWPolar->m_Color = m_CurveColor; m_pCurWPolar->m_Style = m_CurveStyle; m_pCurWPolar->m_Width = m_CurveWidth; m_pCurWPolar->m_bIsVisible = m_bCurveVisible; m_pCurWPolar->m_bShowPoints = m_bCurvePoints; CreateStabilityCurves(); } } else if (m_iView==WOPPVIEW) { if(m_pCurPOpp) { m_pCurPOpp->m_Color = m_CurveColor; m_pCurPOpp->m_Style = m_CurveStyle; m_pCurPOpp->m_Width = m_CurveWidth; m_pCurPOpp->m_bIsVisible = m_bCurveVisible; m_pCurPOpp->m_bShowPoints = m_bCurvePoints; m_pCurWOpp->m_Color = m_CurveColor; m_pCurWOpp->m_Style = m_CurveStyle; m_pCurWOpp->m_Width = m_CurveWidth; m_pCurWOpp->m_bIsVisible = m_bCurveVisible; m_pCurWOpp->m_bShowPoints = m_bCurvePoints; } else if(m_pCurWOpp) { m_pCurWOpp->m_Color = m_CurveColor; m_pCurWOpp->m_Style = m_CurveStyle; m_pCurWOpp->m_Width = m_CurveWidth; m_pCurWOpp->m_bIsVisible = m_bCurveVisible; m_pCurWOpp->m_bShowPoints = m_bCurvePoints; } CreateWOppCurves(); } else if (m_iView==WCPVIEW && m_pCurWOpp) { m_CpColor = m_CurveColor; m_CpStyle = m_CurveStyle; m_CpWidth = m_CurveWidth; m_bShowCp = m_bCurveVisible; m_bShowCpPoints = m_bCurvePoints; CreateCpCurves(); } UpdateView(); MainFrame::SetSaveState(false); } /** * Updates the graphs and the views after a change of units */ void QMiarex::UpdateUnits() { if(m_iView==WPOLARVIEW) { CreateWPolarCurves(); for(int ig=0; ig<4; ig++) SetWGraphTitles(m_WPlrGraph+ig); } else if(m_iView==WSTABVIEW) { CreateStabilityCurves(); SetStabGraphTitles(); } else { if(!m_pCurWing) return; if (m_iView==WOPPVIEW) { CreateWOppCurves(); OnAdjustToWing(); } else if(m_iView==WCPVIEW) CreateCpCurves(); else if(m_iView==W3DVIEW) m_bResetglLegend = true; else if(m_iView==WSTABVIEW) m_bResetglLegend = true; } SetCurveParams(); UpdateView(); } /** * Dispatches the drawing request depending on the type of the active view */ void QMiarex::UpdateView() { TwoDWidget *p2dWidget = (TwoDWidget*)s_p2dWidget; ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; if(m_iView==W3DVIEW || (m_iView==WSTABVIEW && m_iStabilityView==STAB3DVIEW)) { if(p3dWidget) p3dWidget->updateGL(); } else { if(p2dWidget) p2dWidget->update(); } } /** * Overrides the parent's widget wheel event * @param event the QWheelEvent sent by Qt */ void QMiarex::wheelEvent(QWheelEvent *event) { //The mouse button has been wheeled //Process the message QPoint pt(event->x(), event->y()); //client coordinates static double ZoomFactor; if(event->delta()>0) { if(!MainFrame::s_bReverseZoom) ZoomFactor = 1./1.06; else ZoomFactor = 1.06; } else { if(!MainFrame::s_bReverseZoom) ZoomFactor = 1.06; else ZoomFactor = 1./1.06; } if(m_iView==W3DVIEW || (m_iView==WSTABVIEW&&m_iStabilityView==STAB3DVIEW)) { if(m_pCurWing) { //zoom wing m_glScaled *= ZoomFactor; UpdateView(); } } else if(m_iView ==WOPPVIEW || m_iView ==WPOLARVIEW || m_iView ==WCPVIEW || m_iView ==WSTABVIEW) { m_pCurGraph = GetGraph(pt); if(m_pCurGraph && m_pCurGraph->IsInDrawRect(pt)) { if (m_bXPressed) { //zoom x scale m_pCurGraph->SetAutoX(false); m_pCurGraph->Scalex(1./ZoomFactor); } else if(m_bYPressed) { //zoom y scale m_pCurGraph->SetAutoY(false); m_pCurGraph->Scaley(1./ZoomFactor); } else { //zoom both m_pCurGraph->SetAuto(false); m_pCurGraph->Scale(1./ZoomFactor); } m_pCurGraph->SetAutoXUnit(); m_pCurGraph->SetAutoYUnit(); UpdateView(); } else if(m_pCurWing && m_iView==WOPPVIEW) { m_WingScale *= ZoomFactor; UpdateView(); } } } /** * The user has requested a detailed display of the data of the active polar */ void QMiarex::OnWPolarProps() { if(!m_pCurWPolar) return; ObjectPropsDlg opDlg((MainFrame*)s_pMainFrame); opDlg.m_pXDirect = NULL; opDlg.m_pOpp = NULL; opDlg.m_pPolar = NULL; opDlg.m_pMiarex = this; opDlg.m_pWOpp = NULL; opDlg.m_pWPolar = m_pCurWPolar; opDlg.InitDialog(); opDlg.exec(); } /** * The user has requested a detailed display of the data of the active operating point */ void QMiarex::OnWOppProps() { if(!m_pCurWOpp) return; ObjectPropsDlg opDlg((MainFrame*)s_pMainFrame); opDlg.m_pXDirect = NULL; opDlg.m_pOpp = NULL; opDlg.m_pPolar = NULL; opDlg.m_pMiarex = this; opDlg.m_pWOpp = m_pCurWOpp; opDlg.m_pWPolar = NULL; opDlg.InitDialog(); opDlg.exec(); } /** * Called by a stability analysis to modify the panels and nodes by setting the control positions to the specified position t * The panels and nodes to be rotated are pointed by pPanel and pNode * @param pPanel a pointer to the array of surface panels to be rotated * @param pNode a pointer to the array of mesh nodes to be rotated * @param t the value of the control parameter which defines the amount of rotation * @param &NCtrls counts tha active controls * @param &out the output message for the log file * @param bBCOnly, if true, then only the control points and normal vector and rotates; if not,the whole geometry is rotated */ void QMiarex::SetControlPositions(Panel *pPanel, CVector *pNode, double t, int &NCtrls, QString &out, bool bBCOnly) { if(!m_pCurWPolar) return; if(!m_pCurPlane && ! m_pCurWing) return; QString strange; Quaternion Quat; int j, nFlap; double angle, TotalAngle; Wing *pWing; CVector YVector(0.0, 1.0, 0.0); CVector W; // update the variables & geometry // if plane : WingTilt, elevator Tilt // if flaps : wing flaps, elevator flaps //the CG position is fixed for this analysis NCtrls = 0; if(m_pCurPlane) { //wing incidence if(qAbs(m_pCurWPolar->m_ControlGain[0])>0.0) { //wing tilt angle = m_pCurWPolar->m_ControlGain[0] * t; //maxcontrol is the gain TotalAngle = m_pCurPlane->WingTiltAngle(0) + angle; strange = QString::fromUtf8(" Rotating the wing by %1°, total angle is %2°").arg(angle, 5, 'f',2).arg(TotalAngle, 5, 'f',2); strange += "\n"; out +=strange; Quat.Set(angle, YVector); if(bBCOnly) { for(int p=0; pwing()->m_MatSize; p++) { memcpy(pPanel+p, m_MemPanel+p, sizeof(Panel)); (pPanel+p)->RotateBC(m_pCurPlane->WingLE(0), Quat); } } else { for(int n=0; nwing()->IsWingNode(n)) { pNode[n].Copy(m_MemNode[n]); W = pNode[n] - m_pCurPlane->WingLE(0); Quat.Conjugate(W); pNode[n] = W + m_pCurPlane->WingLE(0); } } for(int p=0; pwing()->IsWingPanel(p)) m_Panel[p].SetFrame(); } } } NCtrls=1; if(m_pCurPlane->stab()) { //elevator incidence if(qAbs(m_pCurWPolar->m_ControlGain[1])>0.0) { //Elevator tilt angle = m_pCurWPolar->m_ControlGain[1] * t; //maxcontrol is the gain TotalAngle = m_pCurPlane->WingTiltAngle(2) + angle; strange = QString::fromUtf8(" Rotating the elevator by %1°, total angle is %2°").arg(angle, 5, 'f',2).arg(TotalAngle, 5, 'f',2); strange += "\n"; out +=strange; Quat.Set(angle, YVector); if(!bBCOnly) { for(int n=0; nstab()->IsWingNode(n)) { pNode[n].Copy(m_MemNode[n]); W = pNode[n] - m_pCurPlane->WingLE(2); Quat.Conjugate(W); pNode[n] = W + m_pCurPlane->WingLE(2); } } for(int p=0; pIsWingPanel(p)) m_Panel[p].SetFrame(); } } else { for(int p=0; pstab()->m_MatSize; p++) { m_pCurPlane->stab()->m_pWingPanel[p].RotateBC(m_pCurPlane->WingLE(2), Quat); } } } NCtrls = 2; } } // flap controls for(int iw=0; iwm_NSurfaces; j++) { if(pWing->m_Surface[j].m_bTEFlap) { if(qAbs(m_pCurWPolar->m_ControlGain[NCtrls])>0.0) { angle = m_pCurWPolar->m_ControlGain[NCtrls] * t; //maxcontrol is the gain if(pWing->m_Surface[j].m_pFoilA->m_TEFlapAngle && pWing->m_Surface[j].m_pFoilA->m_TEFlapAngle) TotalAngle = angle + (pWing->m_Surface[j].m_pFoilA->m_TEFlapAngle + pWing->m_Surface[j].m_pFoilB->m_TEFlapAngle)/2.0; else TotalAngle = angle; strange = QString::fromUtf8(" Rotating the flap by %1°, total angle is %2°").arg(angle, 5, 'f',2).arg(TotalAngle, 5, 'f',2); strange += "\n"; out +=strange; if(qAbs(angle)>PRECISION) { // pWing->m_Surface[j].RotateFlap(angle, bBCOnly); Quat.Set(angle, pWing->m_Surface[j].m_HingeVector); if(bBCOnly) { for(int p=0; pm_Surface[j].IsFlapPanel(p)) { memcpy(pPanel+p, m_MemPanel+p, sizeof(Panel)); pPanel[p].RotateBC(pWing->m_Surface[j].m_HingePoint, Quat); } } } else { for(int n=0; nm_Surface[j].IsFlapNode(n)) { pNode[n].Copy(m_MemNode[n]); W = pNode[n] - pWing->m_Surface[j].m_HingePoint; Quat.Conjugate(W); pNode[n] = W + pWing->m_Surface[j].m_HingePoint; } } for(int p=0; pm_Surface[j].IsFlapPanel(p)) m_Panel[p].SetFrame(); } } } } nFlap++; NCtrls++; } } } } } /** * returns the value of the core size of the vortices for the VLM analysis * @return the core size */ double QMiarex::coreSize() { return s_CoreSize; } /** * Sets the value of the core size of the vortices for the VLM analysis. * @param the new core size */ void QMiarex::SetCoreSize(double CoreSize) { s_CoreSize = CoreSize; } /** * Overrides the parent's widget method * Displays the appropriate context menu depending on the view. * @param event */ void QMiarex::contextMenuEvent (QContextMenuEvent * event) { MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; TwoDWidget *p2dWidget = (TwoDWidget*)s_p2dWidget; ThreeDWidget *p3dWidget = (ThreeDWidget*)s_p3dWidget; if(pMainFrame->m_pctrlCentralWidget->currentIndex()==0) p2dWidget->contextMenuEvent(event); else p3dWidget->contextMenuEvent(event); } /** * Returns the name of the active wing or plane. * @return the name of the active wing or plane */ QString QMiarex::UFOName() { if(m_pCurPlane) return m_pCurPlane->PlaneName(); else if(m_pCurWing) return m_pCurWing->WingName(); else return ""; } /** * Reserves the memory necessary to all the arrays used in a Panel analysis. *@return true if the memory could be allocated, false otherwise. */ bool QMiarex::Allocate(int &memsize) { Trace(QString("QMiarex::Allocating() %1 Panels").arg(s_MaxMatSize)); try { m_Node = new CVector[2*s_MaxMatSize]; m_MemNode = new CVector[2*s_MaxMatSize]; m_WakeNode = new CVector[2*s_MaxMatSize]; m_RefWakeNode = new CVector[2*s_MaxMatSize]; m_Panel = new Panel[s_MaxMatSize]; m_MemPanel = new Panel[s_MaxMatSize]; m_WakePanel = new Panel[s_MaxMatSize]; m_RefWakePanel = new Panel[s_MaxMatSize]; } catch(std::exception & e) { // m_Node = m_MemNode = m_WakeNode = m_RefWakeNode = NULL; // m_Panel = m_MemPanel = m_WakePanel = m_RefWakePanel = NULL; Release(); s_MaxMatSize = 0; Trace(e.what()); QString strange = "Memory allocation error: the request for additional memory has been denied.\nPlease reduce the model's size."; QMessageBox::warning((MainFrame*)s_pMainFrame, tr("Warning"), strange); return false; } m_pPanelDlg->m_pPanel = m_Panel; m_pPanelDlg->m_pNode = m_Node; m_pPanelDlg->m_pWakePanel = m_WakePanel; m_pPanelDlg->m_pWakeNode = m_WakeNode; m_pPanelDlg->m_pMemNode = m_MemNode; m_pPanelDlg->m_pMemPanel = m_MemPanel; m_pPanelDlg->m_pRefWakeNode = m_RefWakeNode; m_pPanelDlg->m_pRefWakePanel = m_RefWakePanel; memsize = sizeof(CVector) * 8 * 2 * s_MaxMatSize; //bytes memsize += sizeof(Panel) * 8 * 2 * s_MaxMatSize; //bytes int MatrixSize=0; if(!m_pPanelDlg->AllocateMatrix(MatrixSize)) { Release(); return false; } memsize += MatrixSize; Trace(QString(" ...Allocated %1MB").arg((double)memsize/1024./1024.)); return true; } /** * Releases the memory allocated to the Panel and node arrays. * Sets the pointers to NULL and the matrixsize to 0. */ void QMiarex::Release() { Trace("QMiarex::Releasing()"); m_pPanelDlg->Release(); if(m_Node) delete[] m_Node; if(m_MemNode) delete[] m_MemNode; if(m_WakeNode) delete[] m_WakeNode; if(m_RefWakeNode) delete[] m_RefWakeNode; m_Node = m_MemNode = m_WakeNode = m_RefWakeNode = NULL; if(m_Panel) delete[] m_Panel; if(m_MemPanel) delete[] m_MemPanel; if(m_WakePanel) delete[] m_WakePanel; if(m_RefWakePanel) delete[] m_RefWakePanel; m_Panel = m_MemPanel = m_WakePanel = m_RefWakePanel = NULL; m_MatSize = 0; m_nNodes = 0; } xflr5-6.09-06/src/miarex/WPolarDlg.h000644 001750 000144 00000007667 12247174407 020376 0ustar00techwinderusers000000 000000 /**************************************************************************** WPolarDlg Class Copyright (C) 2009-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ /** *@file This file contains the definition of the class WPolarDlg which is used to define the data for a WPolar object. */ #ifndef WPOLARDLG_H #define WPOLARDLG_H #include #include #include #include #include #include #include "../misc/DoubleEdit.h" #include "../objects/Plane.h" /** *@class WPolarDlg *@brief This class provides the interface dialog box which is used to define or to edit the paramaters of a type 1, 2 or 4 polar. * The class uses a static instance of the WPolar class as the default data. * This is so that the next call to the class uses the existing data, and only modifications are required. * The creation and storage of the new polar object is managed from the calling class QMiarex. * The rest of the methods and variables is self explanatory and not documented further. */ class WPolarDlg : public QDialog { Q_OBJECT friend class QMiarex; friend class MainFrame; public: WPolarDlg(QWidget *pParent=NULL); private: void Connect(); void EnableControls(); void InitDialog(Plane *pPlane, Wing *pWing, WPolar *pWPolar=NULL); void keyPressEvent(QKeyEvent *event); void ReadValues(); void SetDensity(); void SetReynolds(); void SetupLayout(); void SetWingLoad(); void SetWPolarName(); private slots: void OnOK(); void OnArea(); void OnUnit(); void OnMethod(); void OnWPolarName(); void OnAutoName(); void OnTiltedGeom(); void OnViscous(); void OnIgnoreBodyPanels(); void OnGroundEffect(); void OnWPolarType(); void OnEditingFinished(); void OnPlaneInertia(); private: static void *s_pMiarex; Plane *m_pPlane; Wing *m_pWing; static WPolar s_WPolar; bool m_bAutoName; int m_UnitType;//1= International, 2= English double m_WingLoad; QStackedWidget *m_pctrlAnalysisControls; DoubleEdit *m_pctrlXCmRef, *m_pctrlZCmRef; DoubleEdit *m_pctrlDensity; DoubleEdit *m_pctrlViscosity; DoubleEdit *m_pctrlAlpha; DoubleEdit *m_pctrlBeta; DoubleEdit *m_pctrlWeight; DoubleEdit *m_pctrlQInf; DoubleEdit *m_pctrlHeight; QLineEdit *m_pctrlWPolarName; QCheckBox *m_pctrlPlaneInertia; QCheckBox *m_pctrlGroundEffect; QCheckBox *m_pctrlViscous; QCheckBox *m_pctrlIgnoreBodyPanels; QCheckBox *m_pctrlTiltGeom; QCheckBox *m_pctrlAutoName; QRadioButton *m_pctrlType1,*m_pctrlType2,*m_pctrlType4; QRadioButton *m_pctrlWingMethod1, *m_pctrlWingMethod2, *m_pctrlWingMethod3; QRadioButton *m_pctrlPanelMethod; QRadioButton *m_pctrlUnit1, *m_pctrlUnit2; QRadioButton *m_pctrlArea1, *m_pctrlArea2; QLabel *m_pctrlSRe; QLabel *m_pctrlRRe; QLabel *m_pctrlQInfCl; QLabel *m_pctrlUFOName; QLabel *m_pctrlWingLoad; QLabel *m_pctrlSpeedUnit; QLabel *m_pctrlWeightUnit; QLabel *m_pctrlRho, *m_pctrlNu; QLabel *m_pctrlDensityUnit, *m_pctrlViscosityUnit; QLabel *m_pctrlLengthUnit1, *m_pctrlLengthUnit2, *m_pctrlLengthUnit3; QPushButton *OKButton, *CancelButton; }; #endif // WPOLARDLG_H xflr5-6.09-06/src/miarex/GLCreateBodyLists.cpp000644 001750 000144 00000067330 12247174402 022345 0ustar00techwinderusers000000 000000 /**************************************************************************** GLCreateLists Copyright (C) 2012 Andre Deperrois sail7@xflr5.com All rights reserved *****************************************************************************/ #include "GLCreateBodyLists.h" #include "../misc/W3dPrefsDlg.h" #include "../mainframe.h" #include "../params.h" #define NXPOINTS 87 #define NHOOPPOINTS 53 static CVector m_T[(NXPOINTS+1)*(NHOOPPOINTS+1)]; //temporary points to save calculation times for body NURBS surfaces void GLCreateBody3DSplines( int iList, Body *pBody, int nx, int nh) { int i,j,k,l; int p; double v; CVector Point; double hinc, u; CVector N, LATB, TALB; CVector LA, LB, TA, TB; nx = qMin(nx, NXPOINTS); nh = qMax(3, nh); nh = qMin(nh, NHOOPPOINTS); p = 0; for (k=0; k<=nx; k++) { u = (double)k / (double)nx; for (l=0; l<=nh; l++) { v = (double)l / (double)nh; pBody->GetPoint(u, v, true, m_T[p]); p++; } } glNewList(iList, GL_COMPILE); { if(MainFrame::s_bAlphaChannel && pBody->m_BodyColor.alpha()<255) { glColor4d(pBody->m_BodyColor.redF(),pBody->m_BodyColor.greenF(),pBody->m_BodyColor.blueF(), pBody->m_BodyColor.alphaF()); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glColor3d(pBody->m_BodyColor.redF(),pBody->m_BodyColor.greenF(),pBody->m_BodyColor.blueF()); glDisable(GL_BLEND); } glEnable(GL_DEPTH_TEST); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonOffset(1.0, 1.0); //right side first; p=0; for (k=0; kFrameSize(); i++) { u = pBody->Getu(pBody->getFrame(i)->m_Position.x); glBegin(GL_LINE_STRIP); { v = 0.0; for (j=0; jGetPoint(u,v,true, Point); glVertex3d(Point.x, Point.y, Point.z); v += hinc; } } glEnd(); glBegin(GL_LINE_STRIP); { v = 0.0; for (j=0; jGetPoint(u,v,false, Point); glVertex3d(Point.x,Point.y, Point.z); v += hinc; } } glEnd(); } //top line glBegin(GL_LINE_STRIP); { v = 0.0; for (int iu=0; iu<=nh; iu++) { pBody->GetPoint((double)iu/(double)nh,v, true, Point); glVertex3d(Point.x, Point.y, Point.z); } } glEnd(); //bottom line glBegin(GL_LINE_STRIP); { v = 1.0; for (int iu=0; iu<=nh; iu++) { pBody->GetPoint((double)iu/(double)nh,v, true, Point); glVertex3d(Point.x, Point.y, Point.z); } } glEnd(); glDisable(GL_DEPTH_TEST); glDisable(GL_LINE_STIPPLE); } glEndList(); } void GLCreateBody3DFlatPanels(int iList, Body *pBody) { int j,k; QColor color; int style, width; CVector P1, P2, P3, P4, N, P1P3, P2P4, Tj, Tjp1; glNewList(iList,GL_COMPILE); { if(MainFrame::s_bAlphaChannel) { glColor4d(pBody->m_BodyColor.redF(),pBody->m_BodyColor.greenF(),pBody->m_BodyColor.blueF(), pBody->m_BodyColor.alphaF()); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glColor3d(pBody->m_BodyColor.redF(),pBody->m_BodyColor.greenF(),pBody->m_BodyColor.blueF()); glDisable (GL_BLEND); } glEnable(GL_DEPTH_TEST); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonOffset(1.0, 1.0); glDisable(GL_LINE_STIPPLE); glLineWidth(1.0); for (k=0; kSideLineCount()-1;k++) { for (j=0; jFrameSize()-1;j++) { Tj.Set(pBody->getFrame(j)->m_Position.x, 0.0, 0.0); Tjp1.Set(pBody->getFrame(j+1)->m_Position.x, 0.0, 0.0); glBegin(GL_QUADS); { P1 = pBody->getFrame(j)->m_CtrlPoint[k]; P1.x = pBody->getFrame(j)->m_Position.x; P2 = pBody->getFrame(j+1)->m_CtrlPoint[k]; P2.x = pBody->getFrame(j+1)->m_Position.x; P3 = pBody->getFrame(j+1)->m_CtrlPoint[k+1]; P3.x = pBody->getFrame(j+1)->m_Position.x; P4 = pBody->getFrame(j)->m_CtrlPoint[k+1]; P4.x = pBody->getFrame(j)->m_Position.x; P1P3 = P3-P1; P2P4 = P4-P2; N = P1P3 * P2P4; N.Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(P1.x, P1.y, P1.z); glVertex3d(P2.x, P2.y, P2.z); glVertex3d(P3.x, P3.y, P3.z); glVertex3d(P4.x, P4.y, P4.z); } glEnd(); glBegin(GL_QUADS); { //and symetric quad P1.y = -P1.y; P2.y = -P2.y; P3.y = -P3.y; P4.y = -P4.y; glNormal3d(N.x, -N.y, N.z); glVertex3d(P4.x, P4.y, P4.z); glVertex3d(P3.x, P3.y, P3.z); glVertex3d(P2.x, P2.y, P2.z); glVertex3d(P1.x, P1.y, P1.z); } glEnd(); } } glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); } glEndList(); glNewList(iList+MAXBODIES,GL_COMPILE); { glEnable(GL_DEPTH_TEST); glEnable (GL_LINE_STIPPLE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); color = W3dPrefsDlg::s_OutlineColor; style = W3dPrefsDlg::s_OutlineStyle; width = W3dPrefsDlg::s_OutlineWidth; glLineWidth(width); if (style == Qt::DashLine) glLineStipple (1, 0xCFCF); else if(style == Qt::DotLine) glLineStipple (1, 0x6666); else if(style == Qt::DashDotLine) glLineStipple (1, 0xFF18); else if(style == Qt::DashDotDotLine) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glColor3d(color.redF(), color.greenF(), color.blueF()); for (k=0; kSideLineCount()-1;k++) { for (j=0; jFrameSize()-1;j++) { Tj.Set(pBody->getFrame(j)->m_Position.x, 0.0, 0.0); Tjp1.Set(pBody->getFrame(j+1)->m_Position.x, 0.0, 0.0); glBegin(GL_QUADS); { P1 = pBody->getFrame(j)->m_CtrlPoint[k]; P1.x = pBody->getFrame(j)->m_Position.x; P2 = pBody->getFrame(j+1)->m_CtrlPoint[k]; P2.x = pBody->getFrame(j+1)->m_Position.x; P3 = pBody->getFrame(j+1)->m_CtrlPoint[k+1]; P3.x = pBody->getFrame(j+1)->m_Position.x; P4 = pBody->getFrame(j)->m_CtrlPoint[k+1]; P4.x = pBody->getFrame(j)->m_Position.x; P1P3 = P3-P1; P2P4 = P4-P2; N = P1P3 * P2P4; N.Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(P1.x, P1.y, P1.z); glVertex3d(P2.x, P2.y, P2.z); glVertex3d(P3.x, P3.y, P3.z); glVertex3d(P4.x, P4.y, P4.z); } glEnd(); glBegin(GL_QUADS); { //and symetric quad P1.y = -P1.y; P2.y = -P2.y; P3.y = -P3.y; P4.y = -P4.y; P1P3 = P3-P1; P2P4 = P4-P2; N = P1P3 * P2P4; N.Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(P4.x, P4.y, P4.z); glVertex3d(P3.x, P3.y, P3.z); glVertex3d(P2.x, P2.y, P2.z); glVertex3d(P1.x, P1.y, P1.z); } glEnd(); } } glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable (GL_LINE_STIPPLE); glDisable(GL_DEPTH_TEST); } glEndList(); } void GLCreateBodyMesh(int iList, Body *pBody) { if(!pBody) return; int i,j,k,l; int p, nx, nh; double uk, v, dj, dj1, dl1; CVector N, LATB, TALB, LA, LB, TA, TB; CVector PLA, PLB, PTA, PTB; QColor color; nx = pBody->m_nxPanels; nh = pBody->m_nhPanels; if(pBody->m_LineType==BODYPANELTYPE) //LINES { glNewList(iList,GL_COMPILE); { glDisable(GL_LINE_STIPPLE); glEnable(GL_DEPTH_TEST); glEnable(GL_POLYGON_OFFSET_LINE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glPolygonOffset(-1.0, -1.0); color = W3dPrefsDlg::s_VLMColor; glColor3d(color.redF(),color.greenF(),color.blueF()); glLineWidth(1.0); for (i=0; iFrameSize()-1; i++) { for (j=0; jm_xPanels[i]; j++) { dj = (double) j /(double)(pBody->m_xPanels[i]); dj1 = (double)(j+1)/(double)(pBody->m_xPanels[i]); //body left side for (k=0; kSideLineCount()-1; k++) { //build the four corner points of the strips PLB.x = (1.0- dj) * pBody->getFrame(i)->m_Position.x + dj * pBody->getFrame(i+1)->m_Position.x; PLB.y = -(1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k].y - dj * pBody->getFrame(i+1)->m_CtrlPoint[k].y; PLB.z = (1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k].z + dj * pBody->getFrame(i+1)->m_CtrlPoint[k].z; PTB.x = (1.0-dj1) * pBody->getFrame(i)->m_Position.x + dj1 * pBody->getFrame(i+1)->m_Position.x; PTB.y = -(1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k].y - dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k].y; PTB.z = (1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k].z + dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k].z; PLA.x = (1.0- dj) * pBody->getFrame(i)->m_Position.x + dj * pBody->getFrame(i+1)->m_Position.x; PLA.y = -(1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k+1].y - dj * pBody->getFrame(i+1)->m_CtrlPoint[k+1].y; PLA.z = (1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k+1].z + dj * pBody->getFrame(i+1)->m_CtrlPoint[k+1].z; PTA.x = (1.0-dj1) * pBody->getFrame(i)->m_Position.x + dj1 * pBody->getFrame(i+1)->m_Position.x; PTA.y = -(1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k+1].y - dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k+1].y; PTA.z = (1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k+1].z + dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k+1].z; glBegin(GL_QUAD_STRIP); { N.Set(0.0, 0.0, 1.0);//top line normal is vertical LB = PLB; TB = PTB; glVertex3d(LB.x, LB.y, LB.z); glVertex3d(TB.x, TB.y, TB.z); for (l=0; lm_hPanels[k]; l++) { dl1 = (double) (l+1) /(double)(pBody->m_hPanels[k]); LA = PLB * (1.0- dl1) + PLA * dl1; TA = PTB * (1.0- dl1) + PTA * dl1; LATB = TB - LA; TALB = LB - TA; N = TALB * LATB; N.Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(LA.x, LA.y, LA.z); glVertex3d(TA.x, TA.y, TA.z); TB = TA; LB = LA; } } glEnd(); } //body right side for (k=pBody->SideLineCount()-2; k>=0; k--) { //build the four corner points of the strips PLA.x = (1.0- dj) * pBody->getFrame(i)->m_Position.x + dj * pBody->getFrame(i+1)->m_Position.x; PLA.y = (1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k].y + dj * pBody->getFrame(i+1)->m_CtrlPoint[k].y; PLA.z = (1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k].z + dj * pBody->getFrame(i+1)->m_CtrlPoint[k].z; PTA.x = (1.0-dj1) * pBody->getFrame(i)->m_Position.x + dj1 * pBody->getFrame(i+1)->m_Position.x; PTA.y = (1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k].y + dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k].y; PTA.z = (1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k].z + dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k].z; PLB.x = (1.0- dj) * pBody->getFrame(i)->m_Position.x + dj * pBody->getFrame(i+1)->m_Position.x; PLB.y = (1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k+1].y + dj * pBody->getFrame(i+1)->m_CtrlPoint[k+1].y; PLB.z = (1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k+1].z + dj * pBody->getFrame(i+1)->m_CtrlPoint[k+1].z; PTB.x = (1.0-dj1) * pBody->getFrame(i)->m_Position.x + dj1 * pBody->getFrame(i+1)->m_Position.x; PTB.y = (1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k+1].y + dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k+1].y; PTB.z = (1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k+1].z + dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k+1].z; glBegin(GL_QUAD_STRIP); { N.Set(0.0, 0.0, 1.0);//top line normal is vertical LB = PLB; TB = PTB; glVertex3d(LB.x, LB.y, LB.z); glVertex3d(TB.x, TB.y, TB.z); for (l=0; lm_hPanels[k]; l++) { dl1 = (double) (l+1) /(double)(pBody->m_hPanels[k]); LA = PLB * (1.0- dl1) + PLA * dl1; TA = PTB * (1.0- dl1) + PTA * dl1; LATB = TB - LA; TALB = LB - TA; N = TALB * LATB; N.Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(LA.x, LA.y, LA.z); glVertex3d(TA.x, TA.y, TA.z); TB = TA; LB = LA; } } glEnd(); } } } glDisable(GL_DEPTH_TEST); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_POLYGON_OFFSET_LINE); } glEndList(); glNewList(iList+MAXBODIES,GL_COMPILE); { glDisable (GL_LINE_STIPPLE); glEnable(GL_DEPTH_TEST); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.0, 1.0); color = MainFrame::s_BackgroundColor; glColor3d(color.redF(), color.greenF(), color.blueF()); glLineWidth(1.0); for (i=0; iFrameSize()-1; i++) { for (j=0; jm_xPanels[i]; j++) { dj = (double) j /(double)(pBody->m_xPanels[i]); dj1 = (double)(j+1)/(double)(pBody->m_xPanels[i]); //body left side for (k=0; kSideLineCount()-1; k++) { //build the four corner points of the strips PLB.x = (1.0- dj) * pBody->getFrame(i)->m_Position.x + dj * pBody->getFrame(i+1)->m_Position.x; PLB.y = -(1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k].y - dj * pBody->getFrame(i+1)->m_CtrlPoint[k].y; PLB.z = (1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k].z + dj * pBody->getFrame(i+1)->m_CtrlPoint[k].z; PTB.x = (1.0-dj1) * pBody->getFrame(i)->m_Position.x + dj1 * pBody->getFrame(i+1)->m_Position.x; PTB.y = -(1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k].y - dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k].y; PTB.z = (1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k].z + dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k].z; PLA.x = (1.0- dj) * pBody->getFrame(i)->m_Position.x + dj * pBody->getFrame(i+1)->m_Position.x; PLA.y = -(1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k+1].y - dj * pBody->getFrame(i+1)->m_CtrlPoint[k+1].y; PLA.z = (1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k+1].z + dj * pBody->getFrame(i+1)->m_CtrlPoint[k+1].z; PTA.x = (1.0-dj1) * pBody->getFrame(i)->m_Position.x + dj1 * pBody->getFrame(i+1)->m_Position.x; PTA.y = -(1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k+1].y - dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k+1].y; PTA.z = (1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k+1].z + dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k+1].z; glBegin(GL_QUAD_STRIP); { N.Set(0.0, 0.0, 1.0);//top line normal is vertical LB = PLB; TB = PTB; glVertex3d(LB.x, LB.y, LB.z); glVertex3d(TB.x, TB.y, TB.z); for (l=0; lm_hPanels[k]; l++) { dl1 = (double) (l+1) /(double)(pBody->m_hPanels[k]); LA = PLB * (1.0- dl1) + PLA * dl1; TA = PTB * (1.0- dl1) + PTA * dl1; LATB = TB - LA; TALB = LB - TA; N = TALB * LATB; N.Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(LA.x, LA.y, LA.z); glVertex3d(TA.x, TA.y, TA.z); TB = TA; LB = LA; } } glEnd(); } //body right side for (k=pBody->SideLineCount()-2; k>=0; k--) { //build the four corner points of the strips PLA.x = (1.0- dj) * pBody->getFrame(i)->m_Position.x + dj * pBody->getFrame(i+1)->m_Position.x; PLA.y = (1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k].y + dj * pBody->getFrame(i+1)->m_CtrlPoint[k].y; PLA.z = (1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k].z + dj * pBody->getFrame(i+1)->m_CtrlPoint[k].z; PTA.x = (1.0-dj1) * pBody->getFrame(i)->m_Position.x + dj1 * pBody->getFrame(i+1)->m_Position.x; PTA.y = (1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k].y + dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k].y; PTA.z = (1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k].z + dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k].z; PLB.x = (1.0- dj) * pBody->getFrame(i)->m_Position.x + dj * pBody->getFrame(i+1)->m_Position.x; PLB.y = (1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k+1].y + dj * pBody->getFrame(i+1)->m_CtrlPoint[k+1].y; PLB.z = (1.0- dj) * pBody->getFrame(i)->m_CtrlPoint[k+1].z + dj * pBody->getFrame(i+1)->m_CtrlPoint[k+1].z; PTB.x = (1.0-dj1) * pBody->getFrame(i)->m_Position.x + dj1 * pBody->getFrame(i+1)->m_Position.x; PTB.y = (1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k+1].y + dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k+1].y; PTB.z = (1.0-dj1) * pBody->getFrame(i)->m_CtrlPoint[k+1].z + dj1 * pBody->getFrame(i+1)->m_CtrlPoint[k+1].z; glBegin(GL_QUAD_STRIP); { N.Set(0.0, 0.0, 1.0);//top line normal is vertical LB = PLB; TB = PTB; glVertex3d(LB.x, LB.y, LB.z); glVertex3d(TB.x, TB.y, TB.z); for (l=0; lm_hPanels[k]; l++) { dl1 = (double) (l+1) /(double)(pBody->m_hPanels[k]); LA = PLB * (1.0- dl1) + PLA * dl1; TA = PTB * (1.0- dl1) + PTA * dl1; LATB = TB - LA; TALB = LB - TA; N = TALB * LATB; N.Normalize(); glNormal3d(N.x, N.y, N.z); glVertex3d(LA.x, LA.y, LA.z); glVertex3d(TA.x, TA.y, TA.z); TB = TA; LB = LA; } } glEnd(); } } } glDisable (GL_LINE_STIPPLE); } glEndList(); } else if(pBody->m_LineType==BODYSPLINETYPE) //NURBS { pBody->SetPanelPos(); p = 0; for (k=0; k<=nx; k++) { uk = pBody->s_XPanelPos[k]; for (l=0; l<=nh; l++) { v = (double)l / (double)(nh); pBody->GetPoint(uk, v, true, m_T[p]); p++; } } glNewList(iList,GL_COMPILE); { glDisable (GL_LINE_STIPPLE); glEnable(GL_DEPTH_TEST); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); color = W3dPrefsDlg::s_VLMColor; // style = W3dPrefsDlg::s_VLMStyle; // width = W3dPrefsDlg::s_VLMWidth; glColor3d(color.redF(), color.greenF(), color.blueF()); glLineWidth(1.0); //left side first; p=0; for (k=0; k #include #include #include #include "../mainframe.h" #include "../objects/Plane.h" #include "ImportObjectDlg.h" ImportObjectDlg::ImportObjectDlg(QWidget *pParent):QDialog(pParent) { m_bWing = m_bBody = false; setWindowTitle(tr("Import Object")); SetupLayout(); } void ImportObjectDlg::InitDialog(bool bWing) { if(bWing) { m_bWing = true; m_bBody = false; m_pctrlQuestion->setText(tr("Select the wing to import")); Wing *pWing; for(int i=0;iaddItem(pWing->m_WingName); } } else { m_bWing = false; m_bBody = true; m_pctrlQuestion->setText(tr("Select the body to import")); //list all bodies not attached to a plane... remnants from versions < 6.09.06 Body *pBody; for(int ib=0; ibaddItem(pBody->m_BodyName); } Plane *pPlane; for(int ip=0; ipbody()) { if(pPlane->m_BodyName != m_ObjectName) m_pctrlNameList->addItem(pPlane->PlaneName()+"/Body"); } } } } void ImportObjectDlg::SetupLayout() { QDesktopWidget desktop; QRect r = desktop.geometry(); setMinimumHeight(r.height()/3); move(r.width()/3, r.height()/6); QVBoxLayout *MainLayout = new QVBoxLayout; m_pctrlQuestion = new QLabel; m_pctrlNameList = new QListWidget; m_pctrlNameList->setMinimumHeight(300); connect(m_pctrlNameList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(OnOK())); QHBoxLayout *CommandButtons = new QHBoxLayout; { QPushButton *OKButton = new QPushButton(tr("OK")); OKButton->setAutoDefault(false); QPushButton *CancelButton = new QPushButton(tr("Cancel")); CancelButton->setAutoDefault(false); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); } MainLayout->addStretch(1); MainLayout->addWidget(m_pctrlQuestion); MainLayout->addWidget(m_pctrlNameList); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); setLayout(MainLayout); } void ImportObjectDlg::OnOK() { QListWidgetItem *pItem = m_pctrlNameList->currentItem(); m_ObjectName = pItem->text(); QDialog::accept(); } xflr5-6.09-06/src/miarex/StabPolarDlg.h000644 001750 000144 00000006505 12247174407 021047 0ustar00techwinderusers000000 000000 /**************************************************************************** StabPolarDlg Class Copyright (C) 2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef STABPOLARDLG_H #define STABPOLARDLG_H #include #include #include #include #include #include #include #include #include "CtrlTableDelegate.h" #include "../misc/DoubleEdit.h" #include "../objects/Plane.h" class StabPolarDlg : public QDialog { Q_OBJECT friend class QMiarex; friend class MainFrame; public: StabPolarDlg(QWidget *pParent=NULL); void InitDialog(Plane *pPlane, Wing *pWing, WPolar *pWPolar=NULL); private: void SetupLayout(); void Connect(); private slots: void OnOK(); void OnAutoName(); void OnWPolarName(); void OnArea(); void OnEditingFinished(); void OnViscous(); void OnIgnoreBodyPanels(); void OnUnit(); void OnCellChanged(QWidget *pWidget); void OnMethod(); void OnAutoInertia(); private: void keyPressEvent(QKeyEvent *event); void showEvent(QShowEvent *event); void ReadCtrlData(); void FillControlList(); void FillUFOInertia(); void ReadParams(); void SetDensity(); void SetWPolarName(); void SetViscous(); QTableView *m_pctrlControlTable; QStandardItemModel *m_pControlModel; CtrlTableDelegate *m_pCtrlDelegate; DoubleEdit *m_pctrlDensity; DoubleEdit *m_pctrlViscosity; DoubleEdit *m_pctrlBeta; DoubleEdit *m_pctrlPhi; QLineEdit *m_pctrlWPolarName; QCheckBox *m_pctrlViscous; QCheckBox *m_pctrlAutoName; QCheckBox *m_pctrlPlaneInertia; QCheckBox *m_pctrlIgnoreBodyPanels; QRadioButton *m_pctrlUnit1, *m_pctrlUnit2; QRadioButton *m_pctrlArea1, *m_pctrlArea2; QStackedWidget *m_pctrlAnalysisControls; QRadioButton *m_pctrlWingMethod2, *m_pctrlWingMethod3; QRadioButton *m_pctrlPanelMethod; QLabel *m_pctrlUFOName; QLabel *m_pctrlRho, *m_pctrlNu; QLabel *m_pctrlDensityUnit, *m_pctrlViscosityUnit; QLabel *m_pctrlLab299,*m_pctrlLab300,*m_pctrlLab301,*m_pctrlLab302,*m_pctrlLab303,*m_pctrlLab304,*m_pctrlLab305; DoubleEdit *m_pctrlMass, *m_pctrlCoGx,*m_pctrlCoGz, *m_pctrlIxx, *m_pctrlIyy, *m_pctrlIzz, *m_pctrlIxz; QPushButton *OKButton, *CancelButton; static void *s_pMiarex; static WPolar s_StabPolar; Plane *m_pPlane; Wing *m_pWingList[MAXWINGS]; // pointers to the four wings of the currently selected plane bool m_bAutoName; int m_UnitType;//1= International, 2= Imperial }; #endif // STABPOLARDLG_H xflr5-6.09-06/src/miarex/GL3dBodyDlg.cpp000644 001750 000144 00000314535 12247174401 021061 0ustar00techwinderusers000000 000000 /**************************************************************************** BodyDlg Class Copyright (C) 2009-12 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../miarex/Miarex.h" #include "../mainframe.h" #include "../threedwidget.h" #include "../globals.h" #include "../misc/LinePickerDlg.h" #include "../misc/GLLightDlg.h" #include "../misc/W3dPrefsDlg.h" #include "../misc/UnitsDlg.h" #include "./BodyTransDlg.h" #include "./InertiaDlg.h" #include "./BodyScaleDlg.h" #include "./GL3dBodyDlg.h" #include "./GLCreateBodyLists.h" #include #include #include #include #include #include #include #include #include //2D #define BODYAXIALLINES 1304 #define BODYFRAME 1305 #define BODYFRAME3D 1306 #define BODYFRAMEGRID 1307 #define BODYLINEGRID 1308 #define BODYPOINTS 1309 #define FRAMEPOINTS 1310 #define BODYFRAMESCALES 1316 #define BODYLINESCALES 1317 void* GL3dBodyDlg::s_pMainFrame; bool GL3dBodyDlg::s_bglLight = true; bool GL3dBodyDlg::s_bOutline = true; bool GL3dBodyDlg::s_bSurfaces = true; bool GL3dBodyDlg::s_bVLMPanels = false; bool GL3dBodyDlg::s_bAxes = true; bool GL3dBodyDlg::s_bShowMasses = false; int GL3dBodyDlg::s_NHoopPoints = 37; int GL3dBodyDlg::s_NXPoints = 47; QPoint GL3dBodyDlg::s_WindowPos=QPoint(20,20); QSize GL3dBodyDlg::s_WindowSize=QSize(900, 700); #ifdef Q_WS_MAC bool GL3dBodyDlg::s_bWindowMaximized=true; #else bool GL3dBodyDlg::s_bWindowMaximized=false; #endif GL3dBodyDlg::GL3dBodyDlg(QWidget *pParent): QDialog(pParent) { setWindowTitle(tr("Body Edition")); setWindowFlags(Qt::Window); m_BodyGridDlg = new BodyGridDlg(this); m_pBody = NULL; m_BodyOffset.Set( 0.20, -0.12, 0.0); m_FrameOffset.Set(0.80, -0.50, 0.0); m_HorizontalSplit = -0.45; m_VerticalSplit = 0.35; m_GLList = 0; m_ClipPlanePos = 5.0; m_glViewportTrans.x = 0.0; m_glViewportTrans.y = 0.0; m_glViewportTrans.z = 0.0; m_glScaled = 1.0; m_StackPos = 0; //the current position on the stack m_bResetFrame = true; m_BodyScale = 1.0; m_BodyRefScale = 1.0; m_FrameScale = 1.0; m_FrameRefScale = 1.0; m_bChanged = false; m_bEnableName = true; m_bResetglBody = true;//otherwise endless repaint if no body present m_bResetglBody2D = true;// m_bResetglBodyPoints = true; m_bResetglBody2D = true; m_bResetglBodyMesh = true; m_bTrans = false; m_bDragPoint = false; m_bArcball = false; m_bCrossPoint = false; s_bglLight = true; m_bPickCenter = false; m_bShowLight = false; m_bIs3DScaleSet = false; m_LastPoint.setX(0); m_LastPoint.setY(0); m_PointDown.setX(0); m_PointDown.setY(0); memset(MatIn, 0, 16*sizeof(double)); memset(MatOut, 0, 16*sizeof(double)); m_ArcBall.m_pOffx = &m_UFOOffset.x; m_ArcBall.m_pOffy = &m_UFOOffset.y; m_ArcBall.m_pTransx = &m_glViewportTrans.x; m_ArcBall.m_pTransy = &m_glViewportTrans.y; m_pInsertPoint = new QAction(tr("Insert Point") + QString("\tShift+Click"), this); m_pRemovePoint = new QAction(tr("Remove Point") + QString("\tCtrl+Click"), this); m_pScaleBody = new QAction(tr("Scale"), this); m_pGrid = new QAction(tr("Grid Setup"), this); m_pResetScales = new QAction(tr("Reset Scales")+("\t(R)"), this); m_pShowCurFrameOnly = new QAction(tr("Show Current Frame Only"), this); m_pShowCurFrameOnly->setCheckable(true); m_pUndo= new QAction(QIcon(":/images/OnUndo.png"), tr("Undo"), this); m_pUndo->setStatusTip(tr("Cancels the last modification")); m_pUndo->setShortcut(Qt::CTRL + Qt::Key_Z); connect(m_pUndo, SIGNAL(triggered()), this, SLOT(OnUndo())); m_pRedo = new QAction(QIcon(":/images/OnRedo.png"), tr("Redo"), this); m_pRedo->setStatusTip(tr("Restores the last cancelled modification")); m_pRedo->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_Z); connect(m_pRedo, SIGNAL(triggered()), this, SLOT(OnRedo())); m_pExportBodyGeom = new QAction(tr("Export Body Geometry to File"), this); connect(m_pExportBodyGeom, SIGNAL(triggered()), this, SLOT(OnExportBodyGeom())); m_pExportBodyDef = new QAction(tr("Export Body Definition to File"), this); connect(m_pExportBodyDef, SIGNAL(triggered()), this, SLOT(OnExportBodyDef())); m_pImportBodyDef = new QAction(tr("Import Body Definition from File"), this); connect(m_pImportBodyDef, SIGNAL(triggered()), this, SLOT(OnImportBodyDef())); m_pBodyInertia = new QAction(tr("Define Inertia")+"\tF12", this); connect(m_pBodyInertia, SIGNAL(triggered()), this, SLOT(OnBodyInertia())); m_pTranslateBody = new QAction(tr("Translate"), this); connect(m_pTranslateBody, SIGNAL(triggered()), this, SLOT(OnTranslateBody())); SetupLayout(); SetTableUnits(); connect(m_pInsertPoint, SIGNAL(triggered()), this, SLOT(OnInsert())); connect(m_pRemovePoint, SIGNAL(triggered()), this, SLOT(OnRemove())); connect(m_pScaleBody, SIGNAL(triggered()), this, SLOT(OnScaleBody())); connect(m_pShowCurFrameOnly, SIGNAL(triggered()), this, SLOT(OnShowCurFrameOnly())); connect(m_pResetScales, SIGNAL(triggered()), this, SLOT(OnResetScales())); connect(m_pGrid, SIGNAL(triggered()), this, SLOT(OnGrid())); connect(m_pctrlIso, SIGNAL(clicked()),this, SLOT(On3DIso())); connect(m_pctrlX, SIGNAL(clicked()),this, SLOT(On3DFront())); connect(m_pctrlY, SIGNAL(clicked()),this, SLOT(On3DLeft())); connect(m_pctrlZ, SIGNAL(clicked()),this, SLOT(On3DTop())); connect(m_pctrlReset, SIGNAL(clicked()),this, SLOT(On3DReset())); connect(m_pctrlPickCenter, SIGNAL(clicked()),this, SLOT(On3DPickCenter())); connect(m_pctrlClipPlanePos, SIGNAL(sliderMoved(int)), this, SLOT(OnClipPlane())); connect(m_pctrlClipPlanePos, SIGNAL(sliderReleased()), this, SLOT(OnClipPlane())); connect(m_pctrlEdgeWeight, SIGNAL(sliderReleased()), this, SLOT(OnEdgeWeight())); connect(m_pctrlPanelBunch, SIGNAL(sliderMoved(int)), this, SLOT(OnNURBSPanels())); connect(m_pctrlAxes, SIGNAL(clicked()), this, SLOT(OnAxes())); connect(m_pctrlPanels, SIGNAL(clicked()), this, SLOT(OnPanels())); connect(m_pctrlLight, SIGNAL(clicked()), this, SLOT(OnLight())); connect(m_pctrlShowMasses, SIGNAL(clicked()), this, SLOT(OnShowMasses())); connect(m_pctrlSurfaces, SIGNAL(clicked()), this, SLOT(OnSurfaces())); connect(m_pctrlOutline, SIGNAL(clicked()), this, SLOT(OnOutline())); connect(m_pctrlFlatPanels, SIGNAL(clicked()), this, SLOT(OnLineType())); connect(m_pctrlBSplines, SIGNAL(clicked()), this, SLOT(OnLineType())); connect(m_pctrlBodyStyle, SIGNAL(clickedLB()), this, SLOT(OnBodyStyle())); connect(m_pctrlBodyName, SIGNAL(editingFinished()), this, SLOT(OnBodyName())); connect(m_pctrlNHoopPanels,SIGNAL(editingFinished()), this, SLOT(OnNURBSPanels())); connect(m_pctrlNXPanels, SIGNAL(editingFinished()), this, SLOT(OnNURBSPanels())); connect(m_pctrlXDegree, SIGNAL(activated(int)), this, SLOT(OnSelChangeXDegree(int))); connect(m_pctrlHoopDegree, SIGNAL(activated(int)), this, SLOT(OnSelChangeHoopDegree(int))); connect(m_pctrlUndo, SIGNAL(clicked()),this, SLOT(OnUndo())); connect(m_pctrlRedo, SIGNAL(clicked()),this, SLOT(OnRedo())); connect(m_pSelectionModelFrame, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnFrameItemClicked(QModelIndex))); connect(m_pFrameDelegate, SIGNAL(closeEditor(QWidget *)), this, SLOT(OnFrameCellChanged(QWidget *))); connect(m_pSelectionModelPoint, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnPointItemClicked(QModelIndex))); connect(m_pPointDelegate, SIGNAL(closeEditor(QWidget *)), this, SLOT(OnPointCellChanged(QWidget *))); connect(m_pctrlOK, SIGNAL(clicked()),this, SLOT(OnOK())); connect(m_pctrlCancel, SIGNAL(clicked()),this, SLOT(reject())); setMouseTracking(true); } void GL3dBodyDlg::SetTableUnits() { QString length; GetLengthUnit(length, MainFrame::s_LengthUnit); m_pFrameModel->setHeaderData(0, Qt::Horizontal, "x ("+length+")"); m_pFrameModel->setHeaderData(1, Qt::Horizontal, tr("NPanels")); m_pPointModel->setHeaderData(0, Qt::Horizontal, "y ("+length+")"); m_pPointModel->setHeaderData(1, Qt::Horizontal, "z ("+length+")"); m_pPointModel->setHeaderData(2, Qt::Horizontal, tr("NPanels")); } GL3dBodyDlg::~GL3dBodyDlg() { ClearStack(-1); delete m_BodyGridDlg; } void GL3dBodyDlg::FillFrameCell(int iItem, int iSubItem) { QModelIndex ind; switch (iSubItem) { case 0: { ind = m_pFrameModel->index(iItem, 0, QModelIndex()); m_pFrameModel->setData(ind, m_pBody->getFrame(iItem)->m_Position.x * MainFrame::s_mtoUnit); break; } case 1: { ind = m_pFrameModel->index(iItem, 1, QModelIndex()); m_pFrameModel->setData(ind, m_pBody->m_xPanels[iItem]); break; } default: { break; } } } void GL3dBodyDlg::FillFrameDataTable() { if(!m_pBody) return; int i; m_pFrameModel->setRowCount(m_pBody->FrameSize()); for(i=0; iFrameSize(); i++) { FillFrameTableRow(i); } } void GL3dBodyDlg::FillFrameTableRow(int row) { QModelIndex ind; ind = m_pFrameModel->index(row, 0, QModelIndex()); m_pFrameModel->setData(ind, m_pBody->getFrame(row)->m_Position.x * MainFrame::s_mtoUnit); ind = m_pFrameModel->index(row, 1, QModelIndex()); m_pFrameModel->setData(ind, m_pBody->m_xPanels[row]); } void GL3dBodyDlg::FillPointCell(int iItem, int iSubItem) { QModelIndex ind; if(!m_pBody) return; int l = m_pBody->m_iActiveFrame; switch (iSubItem) { case 0: { ind = m_pPointModel->index(iItem, 0, QModelIndex()); m_pPointModel->setData(ind, m_pBody->getFrame(l)->m_CtrlPoint[iItem].y * MainFrame::s_mtoUnit); break; } case 1: { ind = m_pPointModel->index(iItem, 1, QModelIndex()); m_pPointModel->setData(ind, m_pBody->getFrame(l)->m_CtrlPoint[iItem].z*MainFrame::s_mtoUnit); break; } case 2: { ind = m_pPointModel->index(iItem, 2, QModelIndex()); m_pPointModel->setData(ind,m_pBody->m_hPanels[iItem]); break; } default: { break; } } } void GL3dBodyDlg::FillPointDataTable() { if(!m_pBody) return; int i; m_pPointModel->setRowCount(m_pBody->SideLineCount()); for(i=0; iSideLineCount(); i++) { FillPointTableRow(i); } } void GL3dBodyDlg::FillPointTableRow(int row) { if(!m_pFrame) return; QModelIndex ind; ind = m_pPointModel->index(row, 0, QModelIndex()); m_pPointModel->setData(ind, m_pFrame->m_CtrlPoint[row].y * MainFrame::s_mtoUnit); ind = m_pPointModel->index(row, 1, QModelIndex()); m_pPointModel->setData(ind, m_pFrame->m_CtrlPoint[row].z * MainFrame::s_mtoUnit); ind = m_pPointModel->index(row, 2, QModelIndex()); m_pPointModel->setData(ind, m_pBody->m_hPanels[row]); } void GL3dBodyDlg::GLCreateBody2DBodySection() { int i,k, width; double zpos; QColor color; if(!m_pBody) { glNewList(BODYAXIALLINES,GL_COMPILE); m_GLList++; glEndList(); return; } glNewList(BODYAXIALLINES,GL_COMPILE); { m_GLList++; glEnable(GL_DEPTH_TEST); glEnable (GL_LINE_STIPPLE); color = m_pBody->m_BodyColor; width = 1; glLineWidth(width); glColor3d(color.redF(), color.greenF(), color.blueF()); //Middle Line // style = Qt::DashLine; glLineStipple (1, 0xCFCF); glBegin(GL_LINE_STRIP); { for (k=0; kFrameSize();k++) { zpos = (m_pBody->getFrame(k)->m_CtrlPoint.first().z +m_pBody->getFrame(k)->m_CtrlPoint.last().z )/2.0; glVertex3d(m_pBody->getFrame(k)->m_Position.x, zpos , 0.0); } } glEnd(); glDisable(GL_LINE_STIPPLE); if(m_pBody->m_LineType==BODYPANELTYPE) { //Top Line glBegin(GL_LINE_STRIP); { for (k=0; kFrameSize();k++) glVertex3d(m_pBody->getFrame(k)->m_Position.x, m_pBody->getFrame(k)->m_CtrlPoint[0].z, 0.0); } glEnd(); //Bottom Line glBegin(GL_LINE_STRIP); { for (k=0; kFrameSize();k++) glVertex3d(m_pBody->getFrame(k)->m_Position.x, m_pBody->getFrame(k)->m_CtrlPoint[ m_pBody->getFrame(k)->PointCount()-1].z, 0.0); } glEnd(); } else { CVector Point; double xinc, u, v; int nh = 50; xinc = 1./(double)(nh-1); u=0.0; v = 0.0; //top line u=0.0; glBegin(GL_LINE_STRIP); { v = 0.0; for (i=0; i<=nh; i++) { m_pBody->GetPoint(u,v,true, Point); glVertex3d(Point.x, Point.z, Point.y); u += xinc; } } glEnd(); //bot line u=0.0; glBegin(GL_LINE_STRIP); { v = 1.0; for (i=0; i<=nh; i++) { m_pBody->GetPoint(u,v,true, Point); glVertex3d(Point.x, Point.z, Point.y); u += xinc; } } glEnd(); } glDisable(GL_DEPTH_TEST); glDisable (GL_LINE_STIPPLE); } glEndList(); } void GL3dBodyDlg::GLCreateBodyPoints() { int k,width; double zpos; if(!m_pBody) { glNewList(BODYPOINTS,GL_COMPILE); glEndList(); glNewList(FRAMEPOINTS,GL_COMPILE); glEndList(); m_GLList+=2; return; } glNewList(BODYPOINTS,GL_COMPILE); { m_GLList++; glEnable(GL_DEPTH_TEST); glEnable (GL_LINE_STIPPLE); glPolygonMode(GL_FRONT,GL_LINE); width = 1; glLineWidth(width); glDisable(GL_LINE_STIPPLE); glColor3d(m_pBody->m_BodyColor.redF(), m_pBody->m_BodyColor.greenF(), m_pBody->m_BodyColor.blueF()); for (k=0; kFrameSize();k++) { if(m_pBody->m_iActiveFrame==k) { glLineWidth(2.0); glColor3d(0.,0.,1.0); } else if(m_pBody->m_iHighlight==k) { glLineWidth(2.0); glColor3d(1.,0.,0.0); } else { glLineWidth(1.0); glColor3d(m_pBody->m_BodyColor.redF(), m_pBody->m_BodyColor.greenF(), m_pBody->m_BodyColor.blueF()); } zpos = (m_pBody->getFrame(k)->m_CtrlPoint.first().z + m_pBody->getFrame(k)->m_CtrlPoint.last().z ) /2.0; glRectd(m_pBody->getFrame(k)->m_Position.x -0.006/m_BodyScale, zpos -0.006/m_BodyScale, m_pBody->getFrame(k)->m_Position.x +0.006/m_BodyScale, zpos +0.006/m_BodyScale); } glPolygonMode(GL_FRONT,GL_FILL); glDisable(GL_DEPTH_TEST); } glEndList(); if(!m_pFrame) return; glNewList(FRAMEPOINTS,GL_COMPILE); { m_GLList++; glEnable(GL_DEPTH_TEST); glEnable (GL_LINE_STIPPLE); glPolygonMode(GL_FRONT,GL_LINE); width = 1; glLineWidth(width); glDisable(GL_LINE_STIPPLE); for (k=0; kPointCount();k++) { if(m_pFrame->m_iSelect==k) { glLineWidth(2.0); glColor3d(0.0,0.0,1.0); } else if(m_pFrame->m_iHighlight==k) { glLineWidth(2.0); glColor3d(1.,0.,0.0); } else { glLineWidth(1.0); glColor3d(m_pBody->m_BodyColor.redF(), m_pBody->m_BodyColor.greenF(), m_pBody->m_BodyColor.blueF()); } glRectd(m_pFrame->m_CtrlPoint[k].y-0.006/m_FrameScale, m_pFrame->m_CtrlPoint[k].z-0.006/m_FrameScale, m_pFrame->m_CtrlPoint[k].y+0.006/m_FrameScale, m_pFrame->m_CtrlPoint[k].z+0.006/m_FrameScale); } glPolygonMode(GL_FRONT,GL_FILL); glDisable(GL_DEPTH_TEST); } glEndList(); } void GL3dBodyDlg::GLCreateBodyFrames() { int j,k; CVector Point; double hinc, u, v; int nh,style, width; QColor color; if(!m_pBody || ! m_pFrame || (m_pBody && m_pBody->m_iActiveFrame<0)) { glNewList(BODYFRAME,GL_COMPILE); m_GLList++; glEndList(); glNewList(BODYFRAME3D,GL_COMPILE); m_GLList++; glEndList(); return; } nh = 23; // xinc = 0.1; hinc = 1.0/(double)(nh-1); glNewList(BODYFRAME,GL_COMPILE);//create 2D Splines or Lines { m_GLList++; glEnable(GL_DEPTH_TEST); glEnable (GL_LINE_STIPPLE); color = m_pBody->m_BodyColor; style = 0; width = 1; glLineWidth(width); if (style == Qt::DashLine) glLineStipple (1, 0xCFCF); else if(style == Qt::DotLine) glLineStipple (1, 0x6666); else if(style == Qt::DashDotLine) glLineStipple (1, 0xFF18); else if(style == Qt::DashDotDotLine) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glColor3d(color.redF(), color.greenF(), color.blueF()); if(m_pBody->m_LineType ==BODYSPLINETYPE) { if(m_pBody->activeFrame()) { u = m_pBody->Getu(m_pBody->activeFrame()->m_Position.x); glBegin(GL_LINE_STRIP); { v = 0.0; for (k=0; kGetPoint(u,v,true, Point); glVertex3d(Point.y, Point.z, 0.0); v += hinc; } } glEnd(); glBegin(GL_LINE_STRIP); { v = 0.0; for (k=0; kGetPoint(u,v,false, Point); glVertex3d(Point.y, Point.z, 0.0); v += hinc; } } glEnd(); } } else { glBegin(GL_LINE_STRIP); { for (k=0; kPointCount();k++) glVertex3d(m_pFrame->m_CtrlPoint[k].y, m_pFrame->m_CtrlPoint[k].z, 0.0); } glEnd(); glBegin(GL_LINE_STRIP); { for (k=0; kPointCount();k++) glVertex3d(-m_pFrame->m_CtrlPoint[k].y, m_pFrame->m_CtrlPoint[k].z, 0.0); } glEnd(); } glDisable(GL_LINE_STIPPLE); if(!m_bCurFrameOnly) { glEnable (GL_LINE_STIPPLE); glLineStipple (1, 0x0F0F); glLineWidth(1.0); for(j=0; jFrameSize(); j++) { if(j!=m_pBody->m_iActiveFrame) { if(m_pBody->m_LineType ==BODYSPLINETYPE) { u = m_pBody->Getu(m_pBody->getFrame(j)->m_Position.x); glBegin(GL_LINE_STRIP); { v = 0.0; for (k=0; kGetPoint(u,v,true, Point); glVertex3d(Point.y, Point.z, 0.0); v += hinc; } } glEnd(); glBegin(GL_LINE_STRIP); { v = 0.0; for (k=0; kGetPoint(u,v,false, Point); glVertex3d(Point.y, Point.z, 0.0); v += hinc; } } glEnd(); } else { glBegin(GL_LINE_STRIP); { for (k=0; kSideLineCount();k++) glVertex3d(m_pBody->getFrame(j)->m_CtrlPoint[k].y, m_pBody->getFrame(j)->m_CtrlPoint[k].z, 0.0); } glEnd(); glBegin(GL_LINE_STRIP); { for (k=0; kSideLineCount();k++) glVertex3d(m_pBody->getFrame(j)->m_CtrlPoint[k].y, m_pBody->getFrame(j)->m_CtrlPoint[k].z, 0.0); } glEnd(); } } } glDisable(GL_LINE_STIPPLE); } glDisable(GL_DEPTH_TEST); } glEndList(); //create 3D Splines or Lines to overlay on the body glNewList(BODYFRAME3D,GL_COMPILE); { m_GLList++; glEnable(GL_DEPTH_TEST); glEnable (GL_LINE_STIPPLE); color = QColor(0,0,255); style = 0; width = 3; glLineWidth(width); if (style == Qt::DashLine) glLineStipple (1, 0xCFCF); else if(style == Qt::DotLine) glLineStipple (1, 0x6666); else if(style == Qt::DashDotLine) glLineStipple (1, 0xFF18); else if(style == Qt::DashDotDotLine) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glColor3d(color.redF(), color.greenF(), color.blueF()); if(m_pBody->m_LineType ==BODYSPLINETYPE) { if(m_pBody->activeFrame()) { u = m_pBody->Getu(m_pBody->activeFrame()->m_Position.x); glBegin(GL_LINE_STRIP); { v = 0.0; for (k=0; kGetPoint(u,v,true, Point); glVertex3d(Point.x, Point.y, Point.z); v += hinc; } } glEnd(); glBegin(GL_LINE_STRIP); { v = 0.0; for (k=0; kGetPoint(u,v,false, Point); glVertex3d(Point.x, Point.y, Point.z); v += hinc; } } glEnd(); } } else { glBegin(GL_LINE_STRIP); { for (k=0; kPointCount();k++) glVertex3d( m_pBody->activeFrame()->m_Position.x, m_pFrame->m_CtrlPoint[k].y, m_pFrame->m_CtrlPoint[k].z); } glEnd(); glBegin(GL_LINE_STRIP); { for (k=0; kPointCount();k++) glVertex3d( m_pBody->activeFrame()->m_Position.x, -m_pFrame->m_CtrlPoint[k].y, m_pFrame->m_CtrlPoint[k].z); } glEnd(); } glDisable (GL_LINE_STIPPLE); glDisable(GL_DEPTH_TEST); } glEndList(); } void GL3dBodyDlg::GLDrawBodyFrameScale() { int i; QString strong; double unit = m_BodyGridDlg->s_Unit2 * MainFrame::s_mtoUnit; QFontMetrics fm(MainFrame::s_TextFont); double LabelWidth; double h2 = (double)m_3dWidget.geometry().height() /2.0; double w2 = (double)m_3dWidget.geometry().width() /2.0; if(w2>h2) LabelWidth = (double)fm.width("-12.34") / w2; else LabelWidth = (double)fm.width("-12.34") /h2; glEnable(GL_DEPTH_TEST); glDisable (GL_LINE_STIPPLE); glColor3d(W3dPrefsDlg::s_3DAxisColor.redF(), W3dPrefsDlg::s_3DAxisColor.greenF(), W3dPrefsDlg::s_3DAxisColor.blueF()); glLineWidth(W3dPrefsDlg::s_3DAxisWidth); // Horizontal scale____________ if(qAbs(1.0-m_VerticalSplit)/m_BodyGridDlg->s_Unit2/m_FrameScale<20) { glBegin(GL_LINES); { for(i=0; is_Unit2/m_FrameScale; i++) { glVertex2d(m_FrameScaledOffset.x+(double)i*m_BodyGridDlg->s_Unit2*m_FrameScale, m_FrameScaledOffset.y+0.00); glVertex2d(m_FrameScaledOffset.x+(double)i*m_BodyGridDlg->s_Unit2*m_FrameScale, m_FrameScaledOffset.y-0.02); } for(i=1; is_Unit2/m_FrameScale; i++) { glVertex2d(m_FrameScaledOffset.x-(double)i*m_BodyGridDlg->s_Unit2*m_FrameScale, m_FrameScaledOffset.y+0.00); glVertex2d(m_FrameScaledOffset.x-(double)i*m_BodyGridDlg->s_Unit2*m_FrameScale, m_FrameScaledOffset.y-0.02); } } glEnd(); glColor3d(MainFrame::s_TextColor.redF(),MainFrame::s_TextColor.greenF(),MainFrame::s_TextColor.blueF()); for(i=0; is_Unit2/m_FrameScale; i++) { strong = QString("%1").arg((double)i*unit, 6,'f', 2); /* m_3dWidget.renderText(m_FrameScaledOffset.x+(double)i*m_BodyGridDlg->m_Unit2*m_FrameScale-LabelWidth/2, m_FrameScaledOffset.y-0.04, 0.0, strong, MainFrame::s_TextFont);*/ } for(i=1; is_Unit2/m_FrameScale; i++) { strong = QString("%1").arg(-(double)i*unit, 6,'f', 2); /* m_3dWidget.renderText(m_FrameScaledOffset.x-(double)i*m_BodyGridDlg->m_Unit2*m_FrameScale-LabelWidth/2, m_FrameScaledOffset.y-0.04, 0.0, strong, MainFrame::s_TextFont);*/ } } // Vertical scale____________ if(qAbs(m_glTop+1.0)/m_BodyGridDlg->s_Unit2/m_FrameScale<100) { glBegin(GL_LINES); { for(i=0; is_Unit2/m_FrameScale; i++) { glVertex2d(m_FrameScaledOffset.x+ 0.00, m_FrameScaledOffset.y+(double)i*m_BodyGridDlg->s_Unit2*m_FrameScale); glVertex2d(m_FrameScaledOffset.x- 0.02, m_FrameScaledOffset.y+(double)i*m_BodyGridDlg->s_Unit2*m_FrameScale); } for(i=1; is_Unit2/m_FrameScale; i++) { glVertex2d(m_FrameScaledOffset.x+ 0.00, m_FrameScaledOffset.y-(double)i*m_BodyGridDlg->s_Unit2*m_FrameScale); glVertex2d(m_FrameScaledOffset.x- 0.02, m_FrameScaledOffset.y-(double)i*m_BodyGridDlg->s_Unit2*m_FrameScale); } } glEnd(); glColor3d(MainFrame::s_TextColor.redF(),MainFrame::s_TextColor.greenF(),MainFrame::s_TextColor.blueF()); for(i=0; is_Unit2/m_FrameScale; i++) { strong = QString("%1").arg((double)i*unit, 6,'f', 2); /* m_3dWidget.renderText(m_FrameScaledOffset.x- 0.02 -LabelWidth, m_FrameScaledOffset.y+(double)i*m_BodyGridDlg->m_Unit2*m_FrameScale, 0.0, strong);*/ } for(i=1; is_Unit2/m_FrameScale; i++) { strong = QString("%1").arg(-(double)i*unit, 6,'f', 2); /* m_3dWidget.renderText(m_FrameScaledOffset.x- 0.02 -LabelWidth, m_FrameScaledOffset.y-(double)i*m_BodyGridDlg->m_Unit2*m_FrameScale, 0.0, strong);*/ } } glDisable(GL_DEPTH_TEST); } void GL3dBodyDlg::GLDrawBodyLineScale() { int i; QString strong; double unit = m_BodyGridDlg->s_Unit * MainFrame::s_mtoUnit; QFontMetrics fm(MainFrame::s_TextFont); double LabelWidth; double h2 = (double)m_3dWidget.geometry().height() /2.0; double w2 = (double)m_3dWidget.geometry().width() /2.0; if(w2>h2) LabelWidth = (double)fm.width("-12.34") / w2; else LabelWidth = (double)fm.width("-12.34") /h2; glEnable(GL_DEPTH_TEST); glDisable (GL_LINE_STIPPLE); glColor3d(W3dPrefsDlg::s_3DAxisColor.redF(), W3dPrefsDlg::s_3DAxisColor.greenF(), W3dPrefsDlg::s_3DAxisColor.blueF()); glLineWidth(W3dPrefsDlg::s_3DAxisWidth); // Horizontal scale____________ if(qAbs(m_VerticalSplit+1.0)/m_BodyGridDlg->s_Unit/m_BodyScale < 50) { glBegin(GL_LINES); { for(i=0; is_Unit/m_BodyScale; i++) { glVertex2d(m_BodyScaledOffset.x+(double)i*m_BodyGridDlg->s_Unit*m_BodyScale, m_BodyScaledOffset.y+0.00); glVertex2d(m_BodyScaledOffset.x+(double)i*m_BodyGridDlg->s_Unit*m_BodyScale, m_BodyScaledOffset.y-0.02); } for(i=1; is_Unit/m_BodyScale; i++) { glVertex2d(m_BodyScaledOffset.x-(double)i*m_BodyGridDlg->s_Unit*m_BodyScale,m_BodyScaledOffset.y+0.00); glVertex2d(m_BodyScaledOffset.x-(double)i*m_BodyGridDlg->s_Unit*m_BodyScale,m_BodyScaledOffset.y-0.02); } } glEnd(); glColor3d(MainFrame::s_TextColor.redF(),MainFrame::s_TextColor.greenF(),MainFrame::s_TextColor.blueF()); for(i=0; is_Unit/m_BodyScale; i++) { strong = QString("%1").arg((double)i*unit, 6,'f', 2); /* m_3dWidget.renderText(m_BodyScaledOffset.x+(double)i*m_BodyGridDlg->m_Unit*m_BodyScale - LabelWidth/2.0, m_BodyScaledOffset.y-0.04, 0.0, strong);*/ } for(i=1; is_Unit/m_BodyScale; i++) { strong = QString("%1").arg(-(double)i*unit, 6,'f', 2); /* m_3dWidget.renderText(m_BodyScaledOffset.x-(double)i*m_BodyGridDlg->m_Unit*m_BodyScale - LabelWidth/2.0, m_BodyScaledOffset.y-0.04, 0.0, strong);*/ } } // Vertical scale____________ if(qAbs(m_glTop-m_HorizontalSplit)/m_BodyScale/m_BodyGridDlg->s_Unit<50) { glColor3d(W3dPrefsDlg::s_3DAxisColor.redF(), W3dPrefsDlg::s_3DAxisColor.greenF(), W3dPrefsDlg::s_3DAxisColor.blueF()); glBegin(GL_LINES); { for(i=0; is_Unit; i++) { glVertex2d(m_BodyScaledOffset.x+ 0.00, m_BodyScaledOffset.y+(double)i*m_BodyGridDlg->s_Unit*m_BodyScale); glVertex2d(m_BodyScaledOffset.x- 0.02, m_BodyScaledOffset.y+(double)i*m_BodyGridDlg->s_Unit*m_BodyScale); } for(i=1; is_Unit; i++) { glVertex2d(m_BodyScaledOffset.x+ 0.00, m_BodyScaledOffset.y-(double)i*m_BodyGridDlg->s_Unit*m_BodyScale); glVertex2d(m_BodyScaledOffset.x- 0.02, m_BodyScaledOffset.y-(double)i*m_BodyGridDlg->s_Unit*m_BodyScale); } } glEnd(); glColor3d(MainFrame::s_TextColor.redF(),MainFrame::s_TextColor.greenF(),MainFrame::s_TextColor.blueF()); for(i=0; is_Unit; i++) { strong = QString("%1").arg((double)i*unit, 6,'f', 2); /* m_3dWidget.renderText(m_BodyScaledOffset.x- 0.02 - LabelWidth, m_BodyScaledOffset.y+(double)i*m_BodyGridDlg->m_Unit*m_BodyScale, 0.0, strong);*/ } for(i=1; is_Unit; i++) { strong = QString("%1").arg(-(double)i*unit, 6,'f', 2); /* m_3dWidget.renderText(m_BodyScaledOffset.x- 0.02 - LabelWidth, m_BodyScaledOffset.y-(double)i*m_BodyGridDlg->m_Unit*m_BodyScale, 0.0, strong);*/ } } glDisable(GL_DEPTH_TEST); } void GL3dBodyDlg::GLCreateBodyGrid() { int i; double nLines; int style = W3dPrefsDlg::s_3DAxisStyle; int MaxLines = 150; int start = 0; if(s_bAxes) start = 1; glNewList(BODYFRAMEGRID,GL_COMPILE); { m_GLList++; glEnable(GL_DEPTH_TEST); glEnable (GL_LINE_STIPPLE); if(s_bAxes) { // Frame axis____________ glColor3d(W3dPrefsDlg::s_3DAxisColor.redF(), W3dPrefsDlg::s_3DAxisColor.greenF(), W3dPrefsDlg::s_3DAxisColor.blueF()); glLineWidth(W3dPrefsDlg::s_3DAxisWidth); if (style == Qt::DashLine) glLineStipple (1, 0xCFCF); else if(style == Qt::DotLine) glLineStipple (1, 0x6666); else if(style == Qt::DashDotLine) glLineStipple (1, 0xFF18); else if(style == Qt::DashDotDotLine) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glBegin(GL_LINES); { //vertical line glVertex2d(0.0, (-1.0-m_FrameScaledOffset.y)/m_FrameScale); glVertex2d(0.0, (m_glTop-m_FrameScaledOffset.y) /m_FrameScale); //horizontal Line glVertex2d((m_VerticalSplit-m_FrameScaledOffset.x)/m_FrameScale, 0.0); glVertex2d(( 1.0 -m_FrameScaledOffset.x) /m_FrameScale, 0.0); } glEnd(); } // Frame grid____________ //Main Grid glColor3d(m_BodyGridDlg->s_Color2.redF(), m_BodyGridDlg->s_Color2.greenF(), m_BodyGridDlg->s_Color2.blueF()); glLineWidth(m_BodyGridDlg->s_Width2); style = m_BodyGridDlg->s_Style2; if (style == Qt::DashLine) glLineStipple (1, 0xCFCF); else if(style == Qt::DotLine) glLineStipple (1, 0x6666); else if(style == Qt::DashDotLine) glLineStipple (1, 0xFF18); else if(style == Qt::DashDotDotLine) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glBegin(GL_LINES); { if(m_BodyGridDlg->s_bGrid2) { //Main X Grid nLines = (1.0 - m_VerticalSplit)/m_BodyGridDlg->s_Unit2/m_FrameScale; if(nLines < MaxLines) { for(i=start; is_Unit2/m_FrameScale; i++) { glVertex2d(+(double)i*m_BodyGridDlg->s_Unit2, (-1.0-m_FrameScaledOffset.y) /m_FrameScale); glVertex2d(+(double)i*m_BodyGridDlg->s_Unit2, (m_glTop-m_FrameScaledOffset.y) /m_FrameScale); } for(i=start; is_Unit2/m_FrameScale; i++) { glVertex2d((-(double)i*m_BodyGridDlg->s_Unit2), (-1.0-m_FrameScaledOffset.y) /m_FrameScale); glVertex2d((-(double)i*m_BodyGridDlg->s_Unit2), (m_glTop-m_FrameScaledOffset.y) /m_FrameScale); } } //Main Y Grid nLines = (m_glTop+1.0)/m_BodyGridDlg->s_Unit2/m_FrameScale; if(nLines < MaxLines) { for(i=start; is_Unit2/m_FrameScale; i++) { glVertex2d((m_VerticalSplit-m_FrameScaledOffset.x)/m_FrameScale, +(double)i*m_BodyGridDlg->s_Unit2); glVertex2d(( 1.0 -m_FrameScaledOffset.x) /m_FrameScale, +(double)i*m_BodyGridDlg->s_Unit2); } for(i=start; is_Unit2/m_FrameScale; i++) { glVertex2d((m_VerticalSplit-m_FrameScaledOffset.x)/m_FrameScale, -(double)i*m_BodyGridDlg->s_Unit2); glVertex2d(( 1.0 -m_FrameScaledOffset.x) /m_FrameScale, -(double)i*m_BodyGridDlg->s_Unit2); } } } } glEnd(); //Minor Grid glColor3d(m_BodyGridDlg->s_MinColor2.redF(), m_BodyGridDlg->s_MinColor2.greenF(), m_BodyGridDlg->s_MinColor2.blueF()); glLineWidth(m_BodyGridDlg->s_MinWidth2); style = m_BodyGridDlg->s_MinStyle2 ; if (style == Qt::DashLine) glLineStipple (1, 0xCFCF); else if(style == Qt::DotLine) glLineStipple (1, 0x6666); else if(style == Qt::DashDotLine) glLineStipple (1, 0xFF18); else if(style == Qt::DashDotDotLine) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glBegin(GL_LINES); { if(m_BodyGridDlg->s_bMinGrid2) { //Minor X Grid nLines = (1.0 - m_VerticalSplit)/m_BodyGridDlg->s_MinorUnit2/m_FrameScale; if(nLines < MaxLines) { for(i=start; is_MinorUnit2/m_FrameScale; i++) { glVertex2d(+(double)i*m_BodyGridDlg->s_MinorUnit2, (-1.0-m_FrameScaledOffset.y)/m_FrameScale); glVertex2d(+(double)i*m_BodyGridDlg->s_MinorUnit2, (m_glTop-m_FrameScaledOffset.y) /m_FrameScale); } for(i=start; is_MinorUnit2/m_FrameScale; i++) { glVertex2d((-(double)i*m_BodyGridDlg->s_MinorUnit2), (-1.0-m_FrameScaledOffset.y) /m_FrameScale); glVertex2d((-(double)i*m_BodyGridDlg->s_MinorUnit2), (m_glTop-m_FrameScaledOffset.y) /m_FrameScale); } } //Minor Y Grid nLines = (m_glTop+1.0)/m_BodyGridDlg->s_MinorUnit2/m_FrameScale; if(nLines < MaxLines) { for(i=start; is_MinorUnit2/m_FrameScale; i++) { glVertex2d((m_VerticalSplit-m_FrameScaledOffset.x)/m_FrameScale, +(double)i*m_BodyGridDlg->s_MinorUnit2); glVertex2d(( 1.0 -m_FrameScaledOffset.x) /m_FrameScale, +(double)i*m_BodyGridDlg->s_MinorUnit2); } for(i=start; is_MinorUnit2/m_FrameScale; i++) { glVertex2d((m_VerticalSplit-m_FrameScaledOffset.x)/m_FrameScale, -(double)i*m_BodyGridDlg->s_MinorUnit2); glVertex2d(( 1.0 -m_FrameScaledOffset.x) /m_FrameScale, -(double)i*m_BodyGridDlg->s_MinorUnit2); } } } } glEnd(); glDisable(GL_LINE_STIPPLE); glDisable(GL_DEPTH_TEST); } glEndList(); glNewList(BODYLINEGRID,GL_COMPILE); { m_GLList++; glEnable(GL_DEPTH_TEST); glEnable (GL_LINE_STIPPLE); if(s_bAxes) { // Frame axis____________ glColor3d(W3dPrefsDlg::s_3DAxisColor.redF(), W3dPrefsDlg::s_3DAxisColor.greenF(), W3dPrefsDlg::s_3DAxisColor.blueF()); glLineWidth(W3dPrefsDlg::s_3DAxisWidth); style = W3dPrefsDlg::s_3DAxisStyle; if (style == Qt::DashLine) glLineStipple (1, 0xCFCF); else if(style == Qt::DotLine) glLineStipple (1, 0x6666); else if(style == Qt::DashDotLine) glLineStipple (1, 0xFF18); else if(style == Qt::DashDotDotLine) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); // BodyLine axis____________ glBegin(GL_LINES); { //horizontal Line glVertex2d((m_VerticalSplit- m_BodyScaledOffset.x)/m_BodyScale, 0.0); glVertex2d((-1.0 - m_BodyScaledOffset.x)/m_BodyScale, 0.0); //vertical Line glVertex2d(0.0, (m_HorizontalSplit-m_BodyScaledOffset.y)/m_BodyScale); glVertex2d(0.0, (m_glTop -m_BodyScaledOffset.y)/m_BodyScale); } glEnd(); } // BodyLine grid____________ //Main Grid glColor3d(m_BodyGridDlg->s_Color.redF(), m_BodyGridDlg->s_Color.greenF(), m_BodyGridDlg->s_Color.blueF()); glLineWidth(m_BodyGridDlg->s_Width); style = m_BodyGridDlg->s_Style; if (style == Qt::DashLine) glLineStipple (1, 0xCFCF); else if(style == Qt::DotLine) glLineStipple (1, 0x6666); else if(style == Qt::DashDotLine) glLineStipple (1, 0xFF18); else if(style == Qt::DashDotDotLine) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glBegin(GL_LINES); { if(m_BodyGridDlg->s_bGrid) { //Main X Grid nLines = (m_VerticalSplit+1.0)/m_BodyScale/m_BodyGridDlg->s_Unit; if(nLiness_Unit; i++) { glVertex2d(+(double)i*m_BodyGridDlg->s_Unit, (m_HorizontalSplit-m_BodyScaledOffset.y)/m_BodyScale); glVertex2d(+(double)i*m_BodyGridDlg->s_Unit, (m_glTop-m_BodyScaledOffset.y) /m_BodyScale); } for(i=start; is_Unit; i++) { glVertex2d((-(double)i*m_BodyGridDlg->s_Unit),(m_HorizontalSplit-m_BodyScaledOffset.y)/m_BodyScale); glVertex2d((-(double)i*m_BodyGridDlg->s_Unit),(m_glTop-m_BodyScaledOffset.y) /m_BodyScale); } } //Main Y Grid nLines = (m_glTop-m_HorizontalSplit)/m_BodyScale/m_BodyGridDlg->s_Unit; if(nLiness_Unit; i++) { glVertex2d((m_VerticalSplit-m_BodyScaledOffset.x)/m_BodyScale, +(double)i*m_BodyGridDlg->s_Unit); glVertex2d((-1.0 -m_BodyScaledOffset.x) /m_BodyScale, +(double)i*m_BodyGridDlg->s_Unit); } for(i=start; is_Unit; i++) { glVertex2d((m_VerticalSplit-m_BodyScaledOffset.x)/m_BodyScale, -(double)i*m_BodyGridDlg->s_Unit); glVertex2d((-1.0 -m_BodyScaledOffset.x) /m_BodyScale, -(double)i*m_BodyGridDlg->s_Unit); } } } } glEnd(); //Minor Grid glColor3d(m_BodyGridDlg->s_MinColor.redF(), m_BodyGridDlg->s_MinColor.greenF(), m_BodyGridDlg->s_MinColor.blueF()); glLineWidth(m_BodyGridDlg->s_MinWidth); style = m_BodyGridDlg->s_MinStyle; if (style == Qt::DashLine) glLineStipple (1, 0xCFCF); else if(style == Qt::DotLine) glLineStipple (1, 0x6666); else if(style == Qt::DashDotLine) glLineStipple (1, 0xFF18); else if(style == Qt::DashDotDotLine) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glBegin(GL_LINES); { if(m_BodyGridDlg->s_bMinGrid) { //Minor X Grid nLines = (m_VerticalSplit+1.0)/m_BodyScale/m_BodyGridDlg->s_MinorUnit; if(nLiness_MinorUnit; i++) { glVertex2d(+(double)i*m_BodyGridDlg->s_MinorUnit,(m_HorizontalSplit-m_BodyScaledOffset.y)/m_BodyScale); glVertex2d(+(double)i*m_BodyGridDlg->s_MinorUnit,(m_glTop -m_BodyScaledOffset.y)/m_BodyScale); } for(i=start; is_MinorUnit; i++) { glVertex2d((-(double)i*m_BodyGridDlg->s_MinorUnit),(m_HorizontalSplit-m_BodyScaledOffset.y)/m_BodyScale); glVertex2d((-(double)i*m_BodyGridDlg->s_MinorUnit),(m_glTop -m_BodyScaledOffset.y)/m_BodyScale); } } //Minor Y Grid nLines = (m_glTop-m_HorizontalSplit)/m_BodyScale/m_BodyGridDlg->s_MinorUnit; if(nLiness_MinorUnit; i++) { glVertex2d((m_VerticalSplit -m_BodyScaledOffset.x)/m_BodyScale, +(double)i*m_BodyGridDlg->s_MinorUnit); glVertex2d((-1.0 -m_BodyScaledOffset.x)/m_BodyScale, +(double)i*m_BodyGridDlg->s_MinorUnit); } for(i=start; is_MinorUnit; i++) { glVertex2d((m_VerticalSplit -m_BodyScaledOffset.x)/m_BodyScale, -(double)i*m_BodyGridDlg->s_MinorUnit); glVertex2d((-1.0 -m_BodyScaledOffset.x)/m_BodyScale, -(double)i*m_BodyGridDlg->s_MinorUnit); } } } } glEnd(); glDisable(GL_LINE_STIPPLE); glDisable(GL_DEPTH_TEST); } glEndList(); } void GL3dBodyDlg::GLDraw3D() { glClearColor(MainFrame::s_BackgroundColor.redF(), MainFrame::s_BackgroundColor.greenF(), MainFrame::s_BackgroundColor.blueF(),0.0); if(!glIsList(GLLISTSPHERE)) { m_3dWidget.GLCreateUnitSphere(); m_GLList++; } if((m_bResetglBody2D || m_bResetglBodyPoints) && m_pBody) { if(glIsList(BODYPOINTS)) { glDeleteLists(BODYPOINTS,2); m_GLList -=2; } GLCreateBodyPoints(); m_bResetglBodyPoints = false; } if(m_bResetglBody2D && m_pBody) { if(glIsList(BODYAXIALLINES)) { glDeleteLists(BODYAXIALLINES,5); m_GLList -=5; } GLCreateBody2DBodySection(); GLCreateBodyFrames(); GLCreateBodyGrid(); m_bResetglBody2D = false; } if(m_bResetglBody ) { m_ArcBall.GetMatrix(); CVector eye(0.0,0.0,1.0); CVector up(0.0,1.0,0.0); m_ArcBall.SetZoom(0.3,eye,up); if(glIsList(ARCBALL)) { glDeleteLists(ARCBALL,2); m_GLList-=2; } m_3dWidget.CreateArcballList(m_ArcBall, 1.0); m_GLList+=2; } if(m_bResetglBody && m_pBody) { if(glIsList(BODYGEOMBASE)) { glDeleteLists(BODYGEOMBASE,1); glDeleteLists(BODYGEOMBASE+MAXBODIES,1); m_GLList -=2; } if(m_pBody->m_LineType==BODYPANELTYPE) GLCreateBody3DFlatPanels(BODYGEOMBASE, m_pBody); else if(m_pBody->m_LineType==BODYSPLINETYPE) GLCreateBody3DSplines(BODYGEOMBASE, m_pBody, s_NXPoints, s_NHoopPoints); m_bResetglBody = false; if(glIsList(BODYMESHBASE)) { glDeleteLists(BODYMESHBASE,1); glDeleteLists(BODYMESHBASE+MAXBODIES,1); m_GLList -=2; } GLCreateBodyMesh(BODYMESHBASE, m_pBody); m_bResetglBodyMesh = false; } } void GL3dBodyDlg::GLDrawBodyLegend() { QString strong, strLengthUnit; int width; QColor color; GetLengthUnit(strLengthUnit, MainFrame::s_LengthUnit); // glNewList(BODYLEGEND,GL_COMPILE);//create 2D Splines or Lines //draw view rectangles glEnable(GL_DEPTH_TEST); glEnable (GL_LINE_STIPPLE); color = MainFrame::s_TextColor; // style = 0; width = 3; glLineWidth((float)width); glLineStipple (1, 0xFFFF);// Solid glColor3d(color.redF(),color.greenF(),color.blueF()); glBegin(GL_LINES); { glVertex2d( -1.0, m_HorizontalSplit); glVertex2d(m_VerticalSplit, m_HorizontalSplit); } glEnd(); glBegin(GL_LINES); { glVertex2d(m_VerticalSplit, m_3dWidget.m_GLViewRect.bottom); glVertex2d(m_VerticalSplit, m_3dWidget.m_GLViewRect.top ); } glEnd(); if(m_pBody) { //draw the legend glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); // Draw the labels CVector real; m_3dWidget.ClientToGL(m_MousePos, real); QFontMetrics fm(MainFrame::s_TextFont); int dD = fm.height(); strong = QString(tr("Frame %1")).arg(m_pBody->m_iActiveFrame+1,2); m_3dWidget.renderText(m_FrameRect.left() +dD ,dD,strong, MainFrame::s_TextFont); strong = QString(tr("Scale = %1")).arg(m_FrameScale/m_BodyRefScale,4,'f',2); m_3dWidget.renderText(m_FrameRect.left() +dD ,2*dD,strong, MainFrame::s_TextFont); strong = QString(tr("Scale = %1")).arg(m_BodyScale/m_BodyRefScale,4,'f',2); m_3dWidget.renderText(m_BodyLineRect.left() +dD ,dD,strong, MainFrame::s_TextFont); if(m_FrameRect.contains(m_MousePos)) { real.x = (real.x - m_FrameScaledOffset.x)/m_FrameScale; real.y = (real.y - m_FrameScaledOffset.y)/m_FrameScale; real.z = 0.0; strong = QString("y = %1 ").arg(real.x * MainFrame::s_mtoUnit,9,'f',3); strong += strLengthUnit; m_3dWidget.renderText(m_FrameRect.left() +dD ,3*dD,strong, MainFrame::s_TextFont); strong = QString("z = %1 ").arg(real.y * MainFrame::s_mtoUnit,9,'f',3); strong += strLengthUnit; m_3dWidget.renderText(m_FrameRect.left() +dD ,4*dD,strong, MainFrame::s_TextFont); } else if(m_BodyLineRect.contains(m_MousePos)) { real.x = (real.x - m_BodyScaledOffset.x)/m_BodyScale; real.y = (real.y - m_BodyScaledOffset.y)/m_BodyScale; real.z = 0.0; strong = QString("x = %1 ").arg(real.x * MainFrame::s_mtoUnit,9,'f',3); strong += strLengthUnit; m_3dWidget.renderText(m_BodyLineRect.left() +dD ,2*dD,strong, MainFrame::s_TextFont); strong = QString("z = %1 ").arg(real.y * MainFrame::s_mtoUnit,9,'f',3); strong += strLengthUnit; m_3dWidget.renderText(m_BodyLineRect.left() +dD ,3*dD,strong, MainFrame::s_TextFont); } } glDisable(GL_DEPTH_TEST); glDisable (GL_LINE_STIPPLE); } void GL3dBodyDlg::GLInverseMatrix() { //Step 1. Transpose the 3x3 rotation portion of the 4x4 matrix to get the inverse rotation int i,j; for(i=0 ; i<3; i++) { for(j=0; j<3; j++) { MatOut[j][i] = MatIn[i][j]; } } } void GL3dBodyDlg::GLRenderBody() { // int width; GLdouble pts[4]; pts[0]= 1.0; pts[1]=0.0; pts[2]=0.0; pts[3]=-m_VerticalSplit; //x=m_VerticalSplit glClipPlane(GL_CLIP_PLANE1, pts); pts[0]=0.0; pts[1]= 1.0; pts[2]=0.0; pts[3]=-m_HorizontalSplit; //y=m_HorizontalSplit glClipPlane(GL_CLIP_PLANE2, pts); pts[0]=-1.0; pts[1]=0.0; pts[2]=0.0; pts[3]=m_VerticalSplit; //x=m_VerticalSplit glClipPlane(GL_CLIP_PLANE3, pts); pts[0]=0.0; pts[1]=-1.0; pts[2]=0.0; pts[3]=m_HorizontalSplit; //y=m_HorizontalSplit glClipPlane(GL_CLIP_PLANE4, pts); pts[0]= 0.0; pts[1]=0.0; pts[2]=-1.0; pts[3]= m_ClipPlanePos; glClipPlane(GL_CLIP_PLANE5, pts); // width = m_rCltRect.width(); glPushMatrix(); { glFlush(); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Display 2D View glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glDisable(GL_CLIP_PLANE1); glDisable(GL_CLIP_PLANE2); glDisable(GL_CLIP_PLANE3); glDisable(GL_CLIP_PLANE4); glDisable(GL_CLIP_PLANE5); GLDrawBodyLegend(); if(m_BodyGridDlg->s_bScale) GLDrawBodyLineScale(); glEnable(GL_CLIP_PLANE3); glEnable(GL_CLIP_PLANE2); glPushMatrix(); { glTranslated(m_BodyOffset.x, m_BodyOffset.y, 0.0); glTranslated(-m_BodyOffset.x + m_BodyScalingCenter.x, -m_BodyOffset.y + m_BodyScalingCenter.y, 0.0); glScaled(m_BodyScale, m_BodyScale,0.0); glTranslated(+m_BodyOffset.x + -m_BodyScalingCenter.x, +m_BodyOffset.y + -m_BodyScalingCenter.y, 0.0); glCallList(BODYLINEGRID); glCallList(BODYPOINTS); glCallList(BODYAXIALLINES); } glPopMatrix(); glDisable(GL_CLIP_PLANE1); glDisable(GL_CLIP_PLANE2); glDisable(GL_CLIP_PLANE3); glDisable(GL_CLIP_PLANE4); if(m_pFrame) { if(m_BodyGridDlg->s_bScale) GLDrawBodyFrameScale(); glEnable(GL_CLIP_PLANE1); glPushMatrix(); { glTranslated(m_FrameOffset.x, m_FrameOffset.y, 0.0); glTranslated(-m_FrameOffset.x + m_FrameScalingCenter.x, -m_FrameOffset.y + m_FrameScalingCenter.y, 0.0); glScaled(m_FrameScale, m_FrameScale,0.0); glTranslated(+m_FrameOffset.x + -m_FrameScalingCenter.x, +m_FrameOffset.y + -m_FrameScalingCenter.y, 0.0); glCallList(FRAMEPOINTS); glCallList(BODYFRAME); glCallList(BODYFRAMEGRID); } glPopMatrix(); } glDisable(GL_CLIP_PLANE1); glDisable(GL_CLIP_PLANE2); glDisable(GL_CLIP_PLANE3); glDisable(GL_CLIP_PLANE4); glEnable(GL_CLIP_PLANE3); glEnable(GL_CLIP_PLANE4); if(m_ClipPlanePos>4.9999) glDisable(GL_CLIP_PLANE5); else glEnable(GL_CLIP_PLANE5); glPushMatrix(); { m_3dWidget.GLSetupLight(m_BodyOffset.y, 1.0); glLoadIdentity(); glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); if(m_bCrossPoint && m_bArcball) { glPushMatrix(); { glTranslated(m_UFOOffset.x, m_UFOOffset.y, 0.0); m_ArcBall.RotateCrossPoint(); glRotated(m_ArcBall.angle, m_ArcBall.p.x, m_ArcBall.p.y, m_ArcBall.p.z); glCallList(ARCPOINT); } glPopMatrix(); } if(m_bArcball) { glPushMatrix(); { glTranslated(m_UFOOffset.x, m_UFOOffset.y, 0.0); m_ArcBall.Rotate(); glCallList(ARCBALL); } glPopMatrix(); } glTranslated(m_UFOOffset.x, m_UFOOffset.y, 0.0); m_ArcBall.Rotate(); glScaled(m_glScaled, m_glScaled, m_glScaled); glTranslated(m_glRotCenter.x, m_glRotCenter.y, m_glRotCenter.z); if(s_bAxes) m_3dWidget.GLDrawAxes(1.0, W3dPrefsDlg::s_3DAxisColor, W3dPrefsDlg::s_3DAxisStyle, W3dPrefsDlg::s_3DAxisWidth); if(s_bglLight) { glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); } else { glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); } if(s_bSurfaces && m_pBody) glCallList(BODYGEOMBASE); glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); if(m_pBody && m_pFrame && (s_bOutline||s_bSurfaces)) glCallList(BODYFRAME3D); if(s_bOutline && m_pBody) glCallList(BODYGEOMBASE+MAXBODIES); if(s_bVLMPanels && m_pBody) { glCallList(BODYMESHBASE); if(!s_bSurfaces) glCallList(BODYMESHBASE+MAXBODIES); } glDisable(GL_CLIP_PLANE1); glDisable(GL_CLIP_PLANE2); glDisable(GL_CLIP_PLANE3); glDisable(GL_CLIP_PLANE4); if(s_bShowMasses) GLDrawMasses(); } glPopMatrix(); } glPopMatrix(); glFinish(); } /** * Draws the point masses, the object masses, and the CG position on the OpenGL viewport. **/ void GL3dBodyDlg::GLDrawMasses() { QString MassUnit; GetWeightUnit(MassUnit, MainFrame::s_WeightUnit); // double zdist = 25.0/(double)m_r3DCltRect.width(); if(m_pBody) { glPushMatrix(); { glColor3d(0.5, 1.0, 0.5); m_3dWidget.renderText(m_pBody->Length()/2., 0.0, m_pBody->Length()/20, m_pBody->m_BodyName + QString(" %1").arg(m_pBody->m_VolumeMass*MainFrame::s_kgtoUnit, 7,'g',3)+ MassUnit); } glPopMatrix(); for(int im=0; imm_PointMass.size(); im++) { glPushMatrix(); { glTranslated(m_pBody->m_PointMass[im]->position().x,m_pBody->m_PointMass[im]->position().y,m_pBody->m_PointMass[im]->position().z); glColor3d(W3dPrefsDlg::s_MassColor.redF(), W3dPrefsDlg::s_MassColor.greenF(), W3dPrefsDlg::s_MassColor.blueF()); m_3dWidget.GLRenderSphere(W3dPrefsDlg::s_MassRadius/m_glScaled); glColor3d(MainFrame::s_TextColor.redF(), MainFrame::s_TextColor.greenF(), MainFrame::s_TextColor.blueF()); m_3dWidget.renderText(0.0, 0.0, 0.0+.02, m_pBody->m_PointMass[im]->tag() +QString(" %1").arg(m_pBody->m_PointMass[im]->mass()*MainFrame::s_kgtoUnit, 7,'g',3) +MassUnit); } glPopMatrix(); } } } void GL3dBodyDlg::keyPressEvent(QKeyEvent *event) { bool bShift = false; bool bCtrl = false; if(event->modifiers() & Qt::ShiftModifier) bShift =true; if(event->modifiers() & Qt::ControlModifier) bCtrl =true; switch (event->key()) { case Qt::Key_Z: { if(bCtrl) { if(bShift) { OnRedo(); } else OnUndo(); event->accept(); } else event->ignore(); break; } case Qt::Key_R: { if(m_FrameRect.contains(m_LastPoint)) SetFrameScale(); else if(m_BodyLineRect.contains(m_LastPoint)) SetBodyLineScale(); else SetBodyScale(); UpdateView(); break; } case Qt::Key_Y: { if(bCtrl) { OnRedo(); event->accept(); } else event->ignore(); break; } case Qt::Key_Return: { if(!m_pctrlOK->hasFocus() && !m_pctrlCancel->hasFocus()) m_pctrlOK->setFocus(); else if(m_pctrlOK->hasFocus()) OnOK(); else if(m_pctrlCancel->hasFocus()) reject(); break; } case Qt::Key_Escape: { reject(); return; } case Qt::Key_Control: { m_bArcball = true; UpdateView(); break; } case Qt::Key_F12: { OnBodyInertia(); break; } default: event->ignore(); } } void GL3dBodyDlg::keyReleaseEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Control: { m_bArcball = false; UpdateView(); break; } default: event->ignore(); } } void GL3dBodyDlg::mouseDoubleClickEvent(QMouseEvent *event) { QPoint point(event->pos().x(), event->pos().y()); CVector Real; // bool bCtrl = false; // if(event->modifiers() & Qt::ControlModifier) bCtrl =true; m_3dWidget.ClientToGL(point, Real); if(m_3dWidget.geometry().contains(point)) m_3dWidget.setFocus(); Set3DRotationCenter(point); m_bPickCenter = false; m_pctrlPickCenter->setChecked(false); } void GL3dBodyDlg::mouseMoveEvent(QMouseEvent *event) { static int n; static CVector Real; static QPoint Delta, point; blockSignalling(true); point = event->pos(); m_MousePos = event->pos(); Delta.setX(point.x() - m_LastPoint.x()); Delta.setY(point.y() - m_LastPoint.y()); m_3dWidget.ClientToGL(point, Real); // if(!m_3dWidget.hasFocus()) m_3dWidget.setFocus(); bool bCtrl = false; if (event->modifiers() & Qt::ControlModifier) bCtrl =true; if (event->buttons() & Qt::LeftButton) { if(bCtrl&& m_BodyRect.contains(point)) { //rotate m_ArcBall.Move(point.x(), m_3dWidget.geometry().height()-point.y()); UpdateView(); } else if(m_bTrans) { //translate if(m_BodyRect.contains(point)) { m_glViewportTrans.x += (GLfloat)(Delta.x()*2.0/m_glScaled/m_3dWidget.geometry().width()); m_glViewportTrans.y += (GLfloat)(Delta.y()*2.0/m_glScaled/m_3dWidget.geometry().width()); m_glRotCenter.x = MatOut[0][0]*(m_glViewportTrans.x) + MatOut[0][1]*(-m_glViewportTrans.y) + MatOut[0][2]*m_glViewportTrans.z; m_glRotCenter.y = MatOut[1][0]*(m_glViewportTrans.x) + MatOut[1][1]*(-m_glViewportTrans.y) + MatOut[1][2]*m_glViewportTrans.z; m_glRotCenter.z = MatOut[2][0]*(m_glViewportTrans.x) + MatOut[2][1]*(-m_glViewportTrans.y) + MatOut[2][2]*m_glViewportTrans.z; UpdateView(); } else if (m_BodyLineRect.contains(point) && m_pBody) { m_BodyOffset.x += (double)Delta.x()*2.0/(double)m_3dWidget.geometry().width()/m_BodyScale; m_BodyOffset.y += -(double)Delta.y()*2.0/(double)m_3dWidget.geometry().width()/m_BodyScale; m_BodyScaledOffset.Set((1.0-m_BodyScale)*m_BodyScalingCenter.x + m_BodyScale * m_BodyOffset.x, (1.0-m_BodyScale)*m_BodyScalingCenter.y + m_BodyScale * m_BodyOffset.y, 0.0); UpdateView(); } else if(m_FrameRect.contains(point) && m_pFrame) { m_FrameOffset.x += (double)Delta.x()*2.0/(double)m_3dWidget.geometry().width()/m_FrameScale; m_FrameOffset.y += -(double)Delta.y()*2.0/(double)m_3dWidget.geometry().width()/m_FrameScale; m_FrameScaledOffset.Set((1.0-m_FrameScale)*m_FrameScalingCenter.x + m_FrameScale * m_FrameOffset.x, (1.0-m_FrameScale)*m_FrameScalingCenter.y + m_FrameScale * m_FrameOffset.y, 0.0); UpdateView(); } } else if (m_BodyLineRect.contains(point) && m_pBody) { Real.x = (Real.x - m_BodyScaledOffset.x)/m_BodyScale; Real.y = (Real.y - m_BodyScaledOffset.y)/m_BodyScale; Real.z = 0.0; int n = m_pBody->m_iActiveFrame; if (n>=0 && n<=m_pBody->FrameSize() && !m_bTrans && m_bDragPoint) { //dragging a point m_pFrame = m_pBody->activeFrame(); m_pBody->getFrame(n)->m_Position.x = Real.x; double zpos = (m_pBody->getFrame(n)->m_CtrlPoint.first().z + m_pBody->getFrame(n)->m_CtrlPoint.last().z)/2.0; for(int ic=0; icgetFrame(n)->PointCount(); ic++) { m_pBody->getFrame(n)->m_CtrlPoint[ic].x = Real.x; m_pBody->getFrame(n)->m_CtrlPoint[ic].z += Real.y-zpos; } m_bTrans = false; m_bResetglBody2D = true; } UpdateView(); } else if(m_FrameRect.contains(point) && m_pFrame) { Real.x = (Real.x - m_FrameScaledOffset.x)/m_FrameScale; Real.y = (Real.y - m_FrameScaledOffset.y)/m_FrameScale; Real.z = m_pFrame->m_Position.x; if(m_pFrame) n = m_pFrame->m_iSelect; else n = -10; if (n>0 && nPointCount()-1 && !m_bTrans && m_bDragPoint) { //dragging a point if(Real.x<0.0) m_pFrame->m_CtrlPoint[n].y = 0.0; else m_pFrame->m_CtrlPoint[n].y = Real.x; m_pFrame->m_CtrlPoint[n].z = Real.y; m_bTrans = false; m_bResetglBody2D = true; } else if ((n==0 || n==m_pFrame->PointCount()-1) && !m_bTrans && m_bDragPoint) { //dragging a point m_pFrame->m_CtrlPoint[n].y = 0.0; m_pFrame->m_CtrlPoint[n].y = Real.x;//TODO : remove m_pFrame->m_CtrlPoint[n].z = Real.y; m_bTrans = false; m_bResetglBody2D = true; } if(m_pFrame->m_CtrlPoint[n].y<0.0) m_pFrame->m_CtrlPoint[n].y=0.0; UpdateView(); } } else if (event->buttons() & Qt::MidButton) { if(m_BodyRect.contains(point)) { //rotate m_ArcBall.Move(point.x(), m_3dWidget.geometry().height()-point.y()); UpdateView(); } } else { //Highlight points if (m_BodyLineRect.contains(point) && m_pBody) { Real.x = (Real.x - m_BodyScaledOffset.x)/m_BodyScale; Real.y = (Real.y - m_BodyScaledOffset.y)/m_BodyScale; Real.z = 0.0; int n = m_pBody->IsFramePos(Real, m_BodyScale/m_BodyRefScale); m_pBody->m_iHighlight = -10; if (n>=0 && n<=m_pBody->FrameSize()) { m_pBody->m_iHighlight = n; } m_bResetglBodyPoints = true; UpdateView(); } else if (m_pFrame && m_FrameRect.contains(point)) { Real.z = (Real.y - m_FrameScaledOffset.y)/m_FrameScale; Real.y = (Real.x - m_FrameScaledOffset.x)/m_FrameScale; Real.x = m_pFrame->m_Position.x; int n = m_pFrame->IsPoint(Real, m_FrameScale/m_FrameRefScale); m_pFrame->m_iHighlight = -10; if (n>=0 && n<=m_pFrame->PointCount()) { m_pFrame->m_iHighlight = n; } m_bResetglBodyPoints = true; UpdateView(); } } m_LastPoint = point; blockSignalling(false); } void GL3dBodyDlg::mousePressEvent(QMouseEvent *event) { int iF; QPoint point(event->pos().x(), event->pos().y()); CVector Real; bool bCtrl = false; bool bShift = false; if(event->modifiers() & Qt::ControlModifier) bCtrl =true; if(event->modifiers() & Qt::ShiftModifier) bShift =true; m_3dWidget.ClientToGL(point, Real); if(m_3dWidget.geometry().contains(point)) m_3dWidget.setFocus(); if(m_bPickCenter) { Set3DRotationCenter(point); m_bPickCenter = false; m_pctrlPickCenter->setChecked(false); } if (event->buttons() & Qt::MidButton) { if(m_BodyRect.contains(point)) { m_bArcball = true; m_ArcBall.Start(event->pos().x(), m_3dWidget.geometry().height()-event->pos().y()); m_bCrossPoint = true; Set3DRotationCenter(); UpdateView(); } } else if (event->buttons() & Qt::LeftButton) { m_ptPopUp = event->pos(); m_bTrans=true; if(m_pBody && m_BodyRect.contains(point)) { m_ArcBall.Start(point.x(), m_3dWidget.geometry().height()-point.y()); m_bCrossPoint = true; Set3DRotationCenter(); if (!bCtrl) { m_bTrans = true; m_3dWidget.setCursor(Qt::ClosedHandCursor); } else { m_bArcball = true; } UpdateView(); } else if(bShift) Insert(Real); else if(bCtrl) Remove(Real); else if(m_pBody && m_BodyLineRect.contains(point)) { Real.x = (Real.x - m_BodyScaledOffset.x)/m_BodyScale; Real.y = (Real.y - m_BodyScaledOffset.y)/m_BodyScale; Real.z = 0.0; iF = m_pBody->IsFramePos(Real, m_BodyScale/m_BodyRefScale); if(iF >=0) { m_pBody->m_iActiveFrame = iF; m_pFrame = m_pBody->activeFrame(); SetFrame(m_pBody->m_iActiveFrame); m_pctrlFrameTable->selectRow(iF); if(m_pFrame && m_pFrame->m_iSelect>=0) m_pctrlPointTable->selectRow(m_pFrame->m_iSelect); m_bTrans = false; m_bDragPoint = true; UpdateView(); } } else if(m_pFrame && m_FrameRect.contains(point)) { Real.z = (Real.y - m_FrameScaledOffset.y)/m_FrameScale; Real.y = (Real.x - m_FrameScaledOffset.x)/m_FrameScale; Real.x = m_pFrame->m_Position.x; m_pFrame->m_iSelect = m_pFrame->IsPoint(Real, m_FrameScale/m_FrameRefScale); if(m_pFrame->m_iSelect >=0) { m_bTrans = false; m_bDragPoint = true; /** @todo do something*/ // m_pctrlPointTable->selectRow(m_pFrame->m_iSelect); } } if(m_bTrans && !bCtrl) m_3dWidget.setCursor(Qt::ClosedHandCursor); } m_bPickCenter = false; m_pctrlPickCenter->setChecked(false); m_PointDown = point; m_LastPoint = point; } void GL3dBodyDlg::mouseReleaseEvent(QMouseEvent *event) { QPoint point(event->pos().x(), event->pos().y()); m_3dWidget.setCursor(Qt::CrossCursor); blockSignalling(true); if(!m_bTrans) { if(point==m_PointDown) { m_bResetglBodyPoints = true; } else { int n1, n2; n1 = m_pBody->m_iActiveFrame; if(m_pFrame) n2 = m_pFrame->m_iSelect; else n2 = -10; if (m_BodyLineRect.contains(point) && n1>=0 && n1FrameSize()) { //the user has been dragging a point FillFrameCell(n1,0); FillFrameCell(n1,1); SetFrame(n1); m_bResetglBody = true; m_bResetglBodyMesh = true; m_bResetglBody2D = true; } else if (m_FrameRect.contains(point) && n2>=0 && n2PointCount()) { //the user has been dragging a point FillFrameCell(n1,0); FillFrameCell(n1,1); FillPointCell(n2,0); FillPointCell(n2,1); TakePicture(); m_bResetglBody = true; m_bResetglBodyMesh = true; m_bResetglBody2D = true; } } } else m_bResetglBody2D = true; m_bTrans = false; m_bDragPoint = false; m_bArcball = false; m_bCrossPoint = false; UpdateView(); // We need to re-calculate the translation vector int i,j; for(i=0; i<4; i++) for(j=0; j<4; j++) MatIn[i][j] = m_ArcBall.ab_quat[i*4+j]; GLInverseMatrix(); m_glViewportTrans.x = (MatOut[0][0]*m_glRotCenter.x + MatOut[0][1]*m_glRotCenter.y + MatOut[0][2]*m_glRotCenter.z); m_glViewportTrans.y = -(MatOut[1][0]*m_glRotCenter.x + MatOut[1][1]*m_glRotCenter.y + MatOut[1][2]*m_glRotCenter.z); m_glViewportTrans.z = (MatOut[2][0]*m_glRotCenter.x + MatOut[2][1]*m_glRotCenter.y + MatOut[2][2]*m_glRotCenter.z); blockSignalling(false); } void GL3dBodyDlg::On3DIso() { SetViewControls(); m_pctrlIso->setChecked(true); m_ArcBall.ab_quat[0] = -0.65987748f; m_ArcBall.ab_quat[1] = 0.38526487f; m_ArcBall.ab_quat[2] = -0.64508355f; m_ArcBall.ab_quat[3] = 0.0f; m_ArcBall.ab_quat[4] = -0.75137258f; m_ArcBall.ab_quat[5] = -0.33720365f; m_ArcBall.ab_quat[6] = 0.56721509f; m_ArcBall.ab_quat[7] = 0.0f; m_ArcBall.ab_quat[8] = 0.000f; m_ArcBall.ab_quat[9] = 0.85899049f; m_ArcBall.ab_quat[10] = 0.51199043f; m_ArcBall.ab_quat[11] = 0.0f; m_ArcBall.ab_quat[12] = 0.0f; m_ArcBall.ab_quat[13] = 0.0f; m_ArcBall.ab_quat[14] = 0.0f; m_ArcBall.ab_quat[15] = 1.0f; Set3DRotationCenter(); UpdateView(); } void GL3dBodyDlg::On3DTop() { SetViewControls(); m_pctrlZ->setChecked(true); m_ArcBall.SetQuat(sqrt(2.0)/2.0, 0.0, 0.0, -sqrt(2.0)/2.0); Set3DRotationCenter(); UpdateView(); } void GL3dBodyDlg::On3DLeft() { SetViewControls(); m_pctrlY->setChecked(true); m_ArcBall.SetQuat(sqrt(2.0)/2.0, -sqrt(2.0)/2.0, 0.0, 0.0);// rotate by 90 deg around x Set3DRotationCenter(); UpdateView(); } void GL3dBodyDlg::On3DFront() { SetViewControls(); m_pctrlX->setChecked(true); Quaternion Qt1(sqrt(2.0)/2.0, 0.0, -sqrt(2.0)/2.0, 0.0);// rotate by 90 deg around y Quaternion Qt2(sqrt(2.0)/2.0, -sqrt(2.0)/2.0, 0.0, 0.0);// rotate by 90 deg around x m_ArcBall.SetQuat(Qt1 * Qt2); Set3DRotationCenter(); UpdateView(); } void GL3dBodyDlg::SetViewControls() { m_pctrlX->setChecked(false); m_pctrlY->setChecked(false); m_pctrlZ->setChecked(false); m_pctrlIso->setChecked(false); } void GL3dBodyDlg::On3DReset() { m_glViewportTrans.Set(0.0, 0.0, 0.0); m_bPickCenter = false; m_pctrlPickCenter->setChecked(false); m_bIs3DScaleSet = false; m_bResetglBody2D = true; SetBodyScale(); UpdateView(); } void GL3dBodyDlg::On3DPickCenter() { m_bPickCenter = true; m_pctrlPickCenter->setChecked(true); } void GL3dBodyDlg::OnAxes() { s_bAxes = m_pctrlAxes->isChecked(); // m_bResetglBody2D = true; UpdateView(); } void GL3dBodyDlg::OnBodyName() { if(m_pBody) { m_pBody->m_BodyName = m_pctrlBodyName->text(); m_pBody->m_BodyDescription = m_pctrlBodyDescription->toPlainText(); } } void GL3dBodyDlg::OnBodyStyle() { LinePickerDlg dlg(this); int s,w; QColor color; s = m_pBody->m_BodyStyle; w = m_pBody->m_BodyWidth; color = m_pBody->m_BodyColor; dlg.InitDialog(s,w,color); if(QDialog::Accepted==dlg.exec()) { m_bChanged = true; m_pBody->m_BodyStyle = dlg.GetStyle(); m_pBody->m_BodyWidth = dlg.GetWidth(); m_pBody->m_BodyColor = dlg.GetColor(); m_pctrlBodyStyle->SetStyle(dlg.GetStyle()); m_pctrlBodyStyle->SetWidth(dlg.GetWidth()); m_pctrlBodyStyle->SetColor(dlg.GetColor()); m_bResetglBody2D = true; m_bResetglBody = true; UpdateView(); } } void GL3dBodyDlg::OnBodyInertia() { if(!m_pBody) return; InertiaDlg dlg(this); dlg.m_pBody = m_pBody; dlg.m_pPlane = NULL; dlg.m_pWing = NULL; dlg.InitDialog(); dlg.move(pos().x()+25, pos().y()+25); if(dlg.exec()==QDialog::Accepted) m_bChanged=true; m_pBody->ComputeBodyAxisInertia(); } void GL3dBodyDlg::OnClipPlane() { double planepos = (double)m_pctrlClipPlanePos->sliderPosition()/100.0; m_ClipPlanePos = sinh(planepos) * 0.5; UpdateView(); } void GL3dBodyDlg::OnExportBodyDef() { if(!m_pBody) return; m_pBody->ExportDefinition(); } void GL3dBodyDlg::OnExportBodyGeom() { if(!m_pBody) return; QString LengthUnit, FileName; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; GetLengthUnit(LengthUnit, MainFrame::s_LengthUnit); FileName = m_pBody->m_BodyName; FileName.replace("/", " "); int type = 1; QString filter =".csv"; FileName = QFileDialog::getSaveFileName(pMainFrame, QObject::tr("Export Body Geometry"), MainFrame::s_LastDirName , QObject::tr("Text File (*.txt);;Comma Separated Values (*.csv)"), &filter); if(!FileName.length()) return; int pos = FileName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = FileName.left(pos); pos = FileName.lastIndexOf(".csv"); if (pos>0) type = 2; QFile XFile(FileName); if (!XFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QTextStream out(&XFile); m_pBody->ExportGeometry(out, MainFrame::s_mtoUnit, type, s_NXPoints, s_NHoopPoints); } void GL3dBodyDlg::OnImportBodyDef() { Body *pNewBody = new Body(); if(!pNewBody) return; MainFrame* pMainFrame = (MainFrame*)s_pMainFrame; double mtoUnit; UnitsDlg Dlg(this); Dlg.m_bLengthOnly = true; Dlg.m_Length = MainFrame::s_LengthUnit; Dlg.m_Area = MainFrame::s_AreaUnit; Dlg.m_Speed = MainFrame::s_SpeedUnit; Dlg.m_Weight = MainFrame::s_WeightUnit; Dlg.m_Force = MainFrame::s_ForceUnit; Dlg.m_Moment = MainFrame::s_MomentUnit; Dlg.m_Question = QObject::tr("Choose the length unit to read this file :"); Dlg.InitDialog(); if(Dlg.exec() == QDialog::Accepted) { switch(Dlg.m_Length) { case 0:{//mdm mtoUnit = 1000.0; break; } case 1:{//cm mtoUnit = 100.0; break; } case 2:{//dm mtoUnit = 10.0; break; } case 3:{//m mtoUnit = 1.0; break; } case 4:{//in mtoUnit = 1000.0/25.4; break; } case 5:{///ft mtoUnit = 1000.0/25.4/12.0; break; } default:{//m mtoUnit = 1.0; break; } } } else return; QString PathName; PathName = QFileDialog::getOpenFileName(pMainFrame, QObject::tr("Open File"), MainFrame::s_LastDirName, QObject::tr("All files (*.*)")); if(!PathName.length()) return; int pos = PathName.lastIndexOf("/"); if(pos>0) MainFrame::s_LastDirName = PathName.left(pos); QFile XFile(PathName); if (!XFile.open(QIODevice::ReadOnly)) { QString strange = QObject::tr("Could not read the file\n")+PathName; QMessageBox::warning(pMainFrame, QObject::tr("Warning"), strange); return; } QTextStream in(&XFile); if(!pNewBody->ImportDefinition(in, mtoUnit)) { delete pNewBody; return; } XFile.close(); SetBody(pNewBody); } void GL3dBodyDlg::OnFrameCellChanged(QWidget *pWidget) { TakePicture(); m_bChanged = true; // int n = m_pBody->m_iActiveFrame; ReadFrameSectionData(m_pBody->m_iActiveFrame); m_bResetglBody = true; m_bResetglBody2D = true; m_bResetglBodyMesh = true; UpdateView(); } void GL3dBodyDlg::ReadFrameSectionData(int sel) { if(sel>=m_pFrameModel->rowCount()) return; double x; int k; bool bOK; QString strong; QStandardItem *pItem; pItem = m_pFrameModel->item(sel,0); strong = pItem->text(); strong.replace(" ",""); x = strong.toDouble(&bOK); if(bOK) m_pBody->getFrame(sel)->SetuPosition(x / MainFrame::s_mtoUnit); for(int ic=0; icgetFrame(sel)->PointCount(); ic++) { m_pBody->getFrame(sel)->m_CtrlPoint[ic].x = x / MainFrame::s_mtoUnit; } pItem = m_pFrameModel->item(sel,1); strong = pItem->text(); strong.replace(" ",""); k = strong.toInt(&bOK); if(bOK) m_pBody->m_xPanels[sel] = k; } void GL3dBodyDlg::OnFrameItemClicked(const QModelIndex &index) { m_pBody->m_iActiveFrame = index.row(); SetFrame(m_pBody->m_iActiveFrame); UpdateView(); } void GL3dBodyDlg::OnGrid() { m_BodyGridDlg->InitDialog(); m_BodyGridDlg->exec(); m_bResetglBody2D = true; UpdateView(); } void GL3dBodyDlg::OnInsert() { Insert(m_RealPopUp); } void GL3dBodyDlg::Insert(CVector Pt) { CVector Real; m_bChanged = true; int FrameSel = 0; if(m_BodyLineRect.contains(m_ptPopUp)) { TakePicture(); Real.x = (Pt.x - m_BodyScaledOffset.x)/m_BodyScale; Real.z = (Pt.y - m_BodyScaledOffset.y)/m_BodyScale; Real.y = 0.0; if(m_pFrame) { FrameSel = m_pBody->InsertFrame(Real); if(FrameSel>0) m_pFrame = m_pBody->getFrame(FrameSel); else m_pFrame = NULL; } m_bResetglBody = true; m_bResetglBody2D = true; FillFrameDataTable(); SetFrame(FrameSel); UpdateView(); } else if(m_FrameRect.contains(m_ptPopUp) && m_pFrame) { TakePicture(); Real.x = m_pFrame->m_CtrlPoint.first().x; Real.y = (Pt.x - m_FrameScaledOffset.x)/m_FrameScale; Real.z = (Pt.y - m_FrameScaledOffset.y)/m_FrameScale; if(Real.y<0.0) return; m_pBody->InsertPoint(Real); m_bResetglBody = true; m_bResetglBody2D = true; FillPointDataTable(); // SetPointSel(point); UpdateView(); } } void GL3dBodyDlg::OnLight() { s_bglLight = m_pctrlLight->isChecked(); UpdateView(); } void GL3dBodyDlg::OnShowMasses() { s_bShowMasses = m_pctrlShowMasses->isChecked(); UpdateView(); } void GL3dBodyDlg::OnLineType() { m_bChanged = true; if(m_pctrlFlatPanels->isChecked()) { m_pBody->m_LineType = BODYPANELTYPE; m_pctrlNXPanels->setEnabled(false); m_pctrlNHoopPanels->setEnabled(false); m_pctrlXDegree->setEnabled(false); m_pctrlHoopDegree->setEnabled(false); } else { m_pBody->m_LineType = BODYSPLINETYPE; m_pctrlNXPanels->setEnabled(true); m_pctrlNHoopPanels->setEnabled(true); m_pctrlXDegree->setEnabled(true); m_pctrlHoopDegree->setEnabled(true); } m_bResetglBody2D = true; m_bResetglBody = true; UpdateView(); } void GL3dBodyDlg::OnOK() { if(m_pBody) { m_pBody->m_BodyDescription = m_pctrlBodyDescription->toPlainText(); m_pBody->m_BodyColor = m_pctrlBodyStyle->GetColor(); m_pBody->m_BodyStyle = m_pctrlBodyStyle->GetStyle(); m_pBody->m_BodyWidth = m_pctrlBodyStyle->GetWidth(); } s_bWindowMaximized= isMaximized(); s_WindowPos = pos(); s_WindowSize = size(); accept(); } void GL3dBodyDlg::OnOutline() { s_bOutline = m_pctrlOutline->isChecked(); UpdateView(); } void GL3dBodyDlg::OnPanels() { s_bVLMPanels = m_pctrlPanels->isChecked(); UpdateView(); } void GL3dBodyDlg::OnPointCellChanged(QWidget *pWidget) { if(!m_pFrame) return; TakePicture(); m_bChanged = true; ReadPointSectionData(m_pFrame->m_iSelect); m_bResetglBodyPoints = true; m_bResetglBody = true; m_bResetglBody2D = true; m_bResetglBodyMesh = true; UpdateView(); } void GL3dBodyDlg::OnPointItemClicked(const QModelIndex &index) { if(!m_pFrame) return; m_pFrame->m_iSelect = index.row(); m_pFrame->m_iHighlight = index.row(); m_bResetglBodyPoints = true; UpdateView(); } void GL3dBodyDlg::OnRemove() { Remove(m_RealPopUp); } void GL3dBodyDlg::Remove(CVector Pt) { int i,n; CVector Real; Frame *pBodyFrame; if(m_BodyLineRect.contains(m_ptPopUp)) { Real.x = (Pt.x - m_BodyScaledOffset.x)/m_BodyScale; Real.y = (Pt.y - m_BodyScaledOffset.y)/m_BodyScale; Real.z = 0.0; n = m_pBody->IsFramePos(Real, m_BodyScale/m_BodyRefScale); if (n>=0) { TakePicture(); n = m_pBody->RemoveFrame(n); FillFrameDataTable(); SetFrame(n); m_bResetglBody = true; m_bResetglBody2D = true; } UpdateView(); } else if(m_FrameRect.contains(m_ptPopUp) && m_pFrame) { Real.x = m_pFrame->m_CtrlPoint.first().x; Real.y = (Pt.x - m_FrameScaledOffset.x)/m_FrameScale; Real.z = (Pt.y - m_FrameScaledOffset.y)/m_FrameScale; n = m_pFrame->IsPoint(Real, m_FrameScale/m_FrameRefScale); if (n>=0) { TakePicture(); for (i=0; iFrameSize();i++) { pBodyFrame = m_pBody->getFrame(i); pBodyFrame->RemovePoint(n); } m_pBody->SetKnots(); SetFrame(m_pBody->m_iActiveFrame); m_bResetglBody = true; m_bResetglBody2D = true; } UpdateView(); } } void GL3dBodyDlg::OnResetScales() { m_bIs3DScaleSet = false; m_bResetglBody2D = true; if(m_FrameRect.contains(m_ptPopUp)) SetFrameScale(); else if(m_BodyLineRect.contains(m_ptPopUp)) SetBodyLineScale(); else SetBodyScale(); UpdateView(); } void GL3dBodyDlg::OnScaleBody() { if(!m_pBody) return; BodyScaleDlg dlg(this); if(m_FrameRect.contains(m_ptPopUp)) { dlg.m_bFrameOnly = true; } dlg.m_FrameID = m_pBody->m_iActiveFrame; dlg.InitDialog(); if(dlg.exec()==QDialog::Accepted) { TakePicture(); m_pBody->Scale(dlg.m_XFactor, dlg.m_YFactor, dlg.m_ZFactor, dlg.m_bFrameOnly, dlg.m_FrameID); m_bResetglBody = true; m_bResetglBodyMesh = true; m_bResetglBody2D = true; UpdateView(); } } void GL3dBodyDlg::OnSelChangeXDegree(int sel) { if(!m_pBody) return; if (sel <0) return; MainFrame::SetSaveState(false); TakePicture(); m_bChanged = true; m_pBody->m_SplineSurface.m_iuDegree = sel+1; m_pBody->SetKnots(); m_bResetglBody = true; m_bResetglBody2D = true; UpdateView(); } void GL3dBodyDlg::OnSelChangeHoopDegree(int sel) { if(!m_pBody) return; if (sel <0) return; MainFrame::SetSaveState(false); TakePicture(); m_pBody->m_SplineSurface.m_ivDegree = sel+1; m_pBody->SetKnots(); m_bResetglBody = true; m_bResetglBody2D = true; UpdateView(); } void GL3dBodyDlg::OnEdgeWeight() { if(!m_pBody) return; MainFrame::SetSaveState(false); m_bChanged = true; TakePicture(); double w= (double)m_pctrlEdgeWeight->value()/100.0 + 1.0; m_pBody->SetEdgeWeight(w, w); m_bResetglBody = true; m_bResetglBody2D = true; m_bResetglBodyMesh = true; UpdateView(); } void GL3dBodyDlg::OnNURBSPanels() { if(!m_pBody) return; MainFrame::SetSaveState(false); m_bChanged = true; TakePicture(); m_pBody->m_Bunch = m_pctrlPanelBunch->sliderPosition()/100.0; m_pBody->m_nhPanels = m_pctrlNHoopPanels->Value(); m_pBody->m_nxPanels = m_pctrlNXPanels->Value(); m_pBody->SetPanelPos(); m_bResetglBody = true; m_bResetglBody2D = true; m_bResetglBodyMesh = true; UpdateView(); } void GL3dBodyDlg::OnShowCurFrameOnly() { m_bCurFrameOnly = !m_bCurFrameOnly; m_bResetglBody2D = true; m_pShowCurFrameOnly->setChecked(m_bCurFrameOnly); UpdateView(); } void GL3dBodyDlg::OnSurfaces() { s_bSurfaces = m_pctrlSurfaces->isChecked(); UpdateView(); } void GL3dBodyDlg::OnTranslateBody() { if(!m_pBody) return; BodyTransDlg dlg(this); dlg.m_FrameID = m_pBody->m_iActiveFrame; dlg.InitDialog(); if(dlg.exec()==QDialog::Accepted) { TakePicture(); m_pBody->Translate(dlg.m_XTrans, dlg.m_YTrans, dlg.m_ZTrans, dlg.m_bFrameOnly, dlg.m_FrameID); FillFrameDataTable(); FillPointDataTable(); m_bResetglBody = true; m_bResetglBodyMesh = true; m_bResetglBody2D = true; UpdateView(); } } void GL3dBodyDlg::ReadPointSectionData(int sel) { if(sel>=m_pPointModel->rowCount()) return; if(!m_pFrame) return; double d; int k; bool bOK; QString strong; QStandardItem *pItem; pItem = m_pPointModel->item(sel,0); strong = pItem->text(); strong.replace(" ",""); d =strong.toDouble(&bOK); if(bOK) m_pFrame->m_CtrlPoint[sel].y =d / MainFrame::s_mtoUnit; pItem = m_pPointModel->item(sel,1); strong = pItem->text(); strong.replace(" ",""); d =strong.toDouble(&bOK); if(bOK) m_pFrame->m_CtrlPoint[sel].z =d / MainFrame::s_mtoUnit; pItem = m_pPointModel->item(sel,2); strong = pItem->text(); strong.replace(" ",""); k =strong.toInt(&bOK); if(bOK) m_pBody->m_hPanels[sel] = k; } void GL3dBodyDlg::reject() { if(m_bChanged) { m_pBody->m_BodyName = m_pctrlBodyName->text(); int res = QMessageBox::question(this, tr("Body Dlg Exit"), tr("Save the Body ?"), QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel); if (QMessageBox::No == res) { m_pBody = NULL; QDialog::reject(); } else if (QMessageBox::Cancel == res) return; else { m_pBody = NULL; done(QDialog::Accepted); return; } } else m_pBody = NULL; s_bWindowMaximized= isMaximized(); s_WindowPos = pos(); s_WindowSize = size(); done(QDialog::Rejected); } void GL3dBodyDlg::resizeEvent(QResizeEvent *event) { m_bResetglBody2D = true; m_bIs3DScaleSet = false; m_bResetglBody2D = true; // SetBodyScale(); // SetRectangles(); ResizeTables(); } bool GL3dBodyDlg::LoadSettings(QSettings *pSettings) { pSettings->beginGroup("GL3dBody"); { s_WindowPos = pSettings->value("BodyWindowPos", QPoint(20,20)).toPoint(); s_WindowSize = pSettings->value("BodyWindowSize", QSize(900,700)).toSize(); } pSettings->endGroup(); BodyGridDlg::LoadSettings(pSettings); return true; } bool GL3dBodyDlg::SaveSettings(QSettings *pSettings) { pSettings->beginGroup("GL3dBody"); { pSettings->setValue("BodyWindowPos",s_WindowPos); pSettings->setValue("BodyWindowSize",s_WindowSize); } pSettings->endGroup(); BodyGridDlg::SaveSettings(pSettings); return true; } void GL3dBodyDlg::Set3DRotationCenter() { //adjust the new rotation center after a translation or a rotation int i,j; for(i=0; i<4; i++) for(j=0; j<4; j++) MatOut[i][j] = m_ArcBall.ab_quat[i*4+j]; m_glRotCenter.x = MatOut[0][0]*(m_glViewportTrans.x) + MatOut[0][1]*(-m_glViewportTrans.y) + MatOut[0][2]*m_glViewportTrans.z; m_glRotCenter.y = MatOut[1][0]*(m_glViewportTrans.x) + MatOut[1][1]*(-m_glViewportTrans.y) + MatOut[1][2]*m_glViewportTrans.z; m_glRotCenter.z = MatOut[2][0]*(m_glViewportTrans.x) + MatOut[2][1]*(-m_glViewportTrans.y) + MatOut[2][2]*m_glViewportTrans.z; } void GL3dBodyDlg::Set3DRotationCenter(QPoint point) { //adjusts the new rotation center after the user has picked a point on the screen //finds the closest panel under the point, //and changes the rotation vector and viewport translation int i, j; CVector A, B, AA, BB, PP, U; i=-1; m_3dWidget.ClientToGL(point, B); B.x += -m_UFOOffset.x - m_glViewportTrans.x*m_glScaled; B.y += -m_UFOOffset.y + m_glViewportTrans.y*m_glScaled; B *= 1.0/m_glScaled; A.Set(B.x, B.y, +1.0); B.z = -1.0; for(i=0; i<4; i++) for(j=0; j<4; j++) MatIn[i][j] = m_ArcBall.ab_quat[i*4+j]; //convert screen to model coordinates AA.x = MatIn[0][0]*A.x + MatIn[0][1]*A.y + MatIn[0][2]*A.z; AA.y = MatIn[1][0]*A.x + MatIn[1][1]*A.y + MatIn[1][2]*A.z; AA.z = MatIn[2][0]*A.x + MatIn[2][1]*A.y + MatIn[2][2]*A.z; BB.x = MatIn[0][0]*B.x + MatIn[0][1]*B.y + MatIn[0][2]*B.z; BB.y = MatIn[1][0]*B.x + MatIn[1][1]*B.y + MatIn[1][2]*B.z; BB.z = MatIn[2][0]*B.x + MatIn[2][1]*B.y + MatIn[2][2]*B.z; U.Set(BB.x-AA.x, BB.y-AA.y, BB.z-AA.z); U.Normalize(); bool bIntersect = false; bIntersect = m_pBody->Intersect(AA,BB, PP, true); if(!bIntersect) bIntersect = m_pBody->Intersect(AA,BB, PP, false); if(bIntersect) { // smooth visual transition GLInverseMatrix(); U.x = (-PP.x -m_glRotCenter.x)/30.0; U.y = (-PP.y -m_glRotCenter.y)/30.0; U.z = (-PP.z -m_glRotCenter.z)/30.0; for(i=0; i<30; i++) { m_glRotCenter +=U; m_glViewportTrans.x = (MatOut[0][0]*m_glRotCenter.x + MatOut[0][1]*m_glRotCenter.y + MatOut[0][2]*m_glRotCenter.z); m_glViewportTrans.y = -(MatOut[1][0]*m_glRotCenter.x + MatOut[1][1]*m_glRotCenter.y + MatOut[1][2]*m_glRotCenter.z); m_glViewportTrans.z= (MatOut[2][0]*m_glRotCenter.x + MatOut[2][1]*m_glRotCenter.y + MatOut[2][2]*m_glRotCenter.z); UpdateView(); } } } void GL3dBodyDlg::SetControls() { m_pctrlBodyName->setEnabled(m_bEnableName); m_pctrlOutline->setChecked(s_bOutline); m_pctrlPanels->setChecked(s_bVLMPanels); m_pctrlAxes->setChecked(s_bAxes); m_pctrlLight->setChecked(s_bglLight); m_pctrlShowMasses->setChecked(s_bShowMasses); m_pctrlSurfaces->setChecked(s_bSurfaces); m_pctrlOutline->setChecked(s_bOutline); m_pctrlClipPlanePos->setValue((int)(m_ClipPlanePos*100.0)); m_pctrlSurfaces->setChecked(s_bSurfaces); m_pctrlPanelBunch->setSliderPosition((int)(m_pBody->m_Bunch*100.0)); m_pctrlUndo->setEnabled(m_StackPos>0); m_pctrlRedo->setEnabled(m_StackPossetSliderPosition((int)((m_pBody->m_SplineSurface.m_EdgeWeightu-1.0)*100.0)); if(m_pBody && m_pBody->m_LineType==BODYPANELTYPE) { m_pctrlNXPanels->setEnabled(false); m_pctrlNHoopPanels->setEnabled(false); m_pctrlXDegree->setEnabled(false); m_pctrlHoopDegree->setEnabled(false); } else if(m_pBody && m_pBody->m_LineType==BODYSPLINETYPE) { m_pctrlNXPanels->setEnabled(true); m_pctrlNHoopPanels->setEnabled(true); m_pctrlXDegree->setEnabled(true); m_pctrlHoopDegree->setEnabled(true); } m_pctrlBodyStyle->SetStyle(m_pBody->m_BodyStyle); m_pctrlBodyStyle->SetWidth(m_pBody->m_BodyWidth); m_pctrlBodyStyle->SetColor(m_pBody->m_BodyColor); m_pctrlNXPanels->SetValue(m_pBody->m_nxPanels); m_pctrlNHoopPanels->SetValue(m_pBody->m_nhPanels); m_pctrlXDegree->setCurrentIndex(m_pBody->m_SplineSurface.m_iuDegree-1); m_pctrlHoopDegree->setCurrentIndex(m_pBody->m_SplineSurface.m_ivDegree-1); } bool GL3dBodyDlg::InitDialog(Body *pBody) { if(!pBody) return false; return SetBody(pBody); } bool GL3dBodyDlg::SetBody(Body *pBody) { m_pBody = pBody; if(!m_pBody) return false; if(m_pBody->m_LineType==BODYPANELTYPE) m_pctrlFlatPanels->setChecked(true); else if(m_pBody->m_LineType==BODYSPLINETYPE) m_pctrlBSplines->setChecked(true); m_pFrame = m_pBody->activeFrame(); m_bResetglBody2D = true; SetControls(); FillFrameDataTable(); FillPointDataTable(); m_pctrlBodyName->setText(pBody->m_BodyName); TakePicture(); return true; } void GL3dBodyDlg::SetBodyLineScale() { if(m_pBody) m_BodyScale = (m_VerticalSplit-m_3dWidget.m_GLViewRect.left)*.7/m_pBody->Length(); else return; m_BodyOffset.Set((m_3dWidget.m_GLViewRect.left+m_VerticalSplit)/2.0-m_pBody->Length()/2.0-m_pBody->LeadingPoint().x, (m_3dWidget.m_GLViewRect.top+m_HorizontalSplit)/2.0, 0.0); m_BodyScaledOffset.Set((1.0 - m_BodyScale)*m_BodyScalingCenter.x + m_BodyScale * m_BodyOffset.x, (1.0 - m_BodyScale)*m_BodyScalingCenter.y + m_BodyScale * m_BodyOffset.y, 0.0); m_BodyRefScale = m_BodyScale; m_BodyScalingCenter.x = (m_VerticalSplit + m_3dWidget.m_GLViewRect.left) /2.0; m_BodyScalingCenter.y = (m_3dWidget.m_GLViewRect.top + m_HorizontalSplit) /2.0; } void GL3dBodyDlg::SetFrameScale() { int k; double height; if(m_pBody) { height = 0.0; for(k=0; kFrameSize(); k++) { height = qMax(height,m_pBody->getFrame(k)->Height()); } m_FrameScale = (1.0-0.5)/height; } else m_FrameScale = 1.0; m_FrameOffset.Set((m_VerticalSplit + m_3dWidget.m_GLViewRect.right)/2.0, (m_3dWidget.m_GLViewRect.top +m_3dWidget.m_GLViewRect.bottom)/2.0, 0.0); m_FrameScaledOffset.Set((1.0 - m_FrameScale)*m_FrameScalingCenter.x + m_FrameScale * m_FrameOffset.x, (1.0 - m_FrameScale)*m_FrameScalingCenter.y + m_FrameScale * m_FrameOffset.y, 0.0); m_FrameRefScale = m_FrameScale; m_FrameScalingCenter.x = (m_VerticalSplit + m_3dWidget.m_GLViewRect.right) /2.0; m_FrameScalingCenter.y = (m_3dWidget.m_GLViewRect.top + m_3dWidget.m_GLViewRect.bottom) /2.0; } void GL3dBodyDlg::SetRectangles() { CVector V1, V2; QPoint P1, P2; m_glTop = m_3dWidget.m_GLViewRect.top; m_VerticalSplit = m_3dWidget.m_GLViewRect.width() /6.0; m_HorizontalSplit = m_3dWidget.m_GLViewRect.height() /6.0; V1.Set(m_3dWidget.m_GLViewRect.left, m_3dWidget.m_GLViewRect.top, 0.0); V2.Set(m_VerticalSplit, m_HorizontalSplit, 0.0); m_3dWidget.GLToClient(V1, P1); m_3dWidget.GLToClient(V2, P2); m_BodyLineRect.setTopLeft(P1); m_BodyLineRect.setBottomRight(P2); V1.Set(m_VerticalSplit, m_3dWidget.m_GLViewRect.top, 0.0); V2.Set(m_3dWidget.m_GLViewRect.right, m_3dWidget.m_GLViewRect.bottom, 0.0); m_3dWidget.GLToClient(V1, P1); m_3dWidget.GLToClient(V2, P2); m_FrameRect.setTopLeft(P1); m_FrameRect.setBottomRight(P2); V1.Set(m_3dWidget.m_GLViewRect.left, m_HorizontalSplit, 0.0); V2.Set(m_VerticalSplit, m_3dWidget.m_GLViewRect.bottom, 0.0); m_3dWidget.GLToClient(V1, P1); m_3dWidget.GLToClient(V2, P2); m_BodyRect.setTopLeft(P1); m_BodyRect.setBottomRight(P2); } void GL3dBodyDlg::SetBodyScale() { if(!m_pBody) return; // if(m_bIs3DScaleSet /*&& !m_bAutoScales*/) return; m_glViewportTrans.x = 0.0; m_glViewportTrans.y = 0.0; m_glViewportTrans.z = 0.0; m_bIs3DScaleSet = true; m_UFOOffset.x = (GLfloat)(m_3dWidget.m_GLViewRect.left + m_VerticalSplit )/2.0; m_UFOOffset.y = (GLfloat)(m_3dWidget.m_GLViewRect.bottom + m_HorizontalSplit)/2.0; m_glScaled = (GLfloat)(3./4.* (m_VerticalSplit+1.0) / m_pBody->Length()); m_ArcBall.GetMatrix(); CVector eye(0.0,0.0,1.0); CVector up(0.0,1.0,0.0); m_ArcBall.SetZoom(0.3,eye,up); Set3DRotationCenter(); } void GL3dBodyDlg::SetScales() { SetBodyScale(); SetFrameScale(); SetBodyLineScale(); } void GL3dBodyDlg::SetFrame(int iFrame) { if(!m_pBody) return; if(iFrame<0 || iFrame>=m_pBody->FrameSize()) m_pFrame = NULL; else m_pFrame = m_pBody->getFrame(iFrame); m_pBody->m_iActiveFrame = iFrame; FillPointDataTable();; m_bResetglBody2D = true; } void GL3dBodyDlg::SetFrame(Frame *pFrame) { if(!m_pBody || !pFrame) return; m_pBody->SetActiveFrame(pFrame); FillPointDataTable();; m_bResetglBody2D = true; } void GL3dBodyDlg::SetupLayout() { int i; QString str; QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::Expanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Expanding); QSizePolicy szPolicyMinimum; szPolicyMinimum.setHorizontalPolicy(QSizePolicy::Minimum); szPolicyMinimum.setVerticalPolicy(QSizePolicy::Minimum); QSizePolicy szPolicyMaximum; szPolicyMaximum.setHorizontalPolicy(QSizePolicy::Maximum); szPolicyMaximum.setVerticalPolicy(QSizePolicy::Maximum); m_3dWidget.m_pParent = this; m_3dWidget.m_iView = GLBODYVIEW; m_ArcBall.m_p3dWidget = &m_3dWidget; QVBoxLayout *ControlsLayout = new QVBoxLayout; { QGridLayout *ThreeDParams = new QGridLayout; { m_pctrlAxes = new QCheckBox(tr("Axes")); m_pctrlLight = new QCheckBox(tr("Light")); m_pctrlSurfaces = new QCheckBox(tr("Surfaces")); m_pctrlOutline = new QCheckBox(tr("Outline")); m_pctrlPanels = new QCheckBox(tr("Panels")); m_pctrlShowMasses = new QCheckBox(tr("Masses")); m_pctrlAxes->setSizePolicy(szPolicyMinimum); m_pctrlLight->setSizePolicy(szPolicyMinimum); m_pctrlSurfaces->setSizePolicy(szPolicyMinimum); m_pctrlOutline->setSizePolicy(szPolicyMinimum); m_pctrlPanels->setSizePolicy(szPolicyMinimum); ThreeDParams->addWidget(m_pctrlAxes, 1,1); ThreeDParams->addWidget(m_pctrlPanels, 1,2); ThreeDParams->addWidget(m_pctrlLight, 1,3); ThreeDParams->addWidget(m_pctrlSurfaces, 2,1); ThreeDParams->addWidget(m_pctrlOutline, 2,2); ThreeDParams->addWidget(m_pctrlShowMasses, 2,3); } QHBoxLayout*AxisView = new QHBoxLayout; { m_pctrlX = new QToolButton; m_pctrlY = new QToolButton; m_pctrlZ = new QToolButton; m_pctrlIso = new QToolButton; if(m_pctrlX->iconSize().height()<=48) { m_pctrlX->setIconSize(QSize(32,32)); m_pctrlY->setIconSize(QSize(32,32)); m_pctrlZ->setIconSize(QSize(32,32)); m_pctrlIso->setIconSize(QSize(32,32)); } m_pXView = new QAction(QIcon(":/images/OnXView.png"), tr("X View"), this); m_pYView = new QAction(QIcon(":/images/OnYView.png"), tr("Y View"), this); m_pZView = new QAction(QIcon(":/images/OnZView.png"), tr("Z View"), this); m_pIsoView = new QAction(QIcon(":/images/OnIsoView.png"), tr("Iso View"), this); m_pXView->setCheckable(true); m_pYView->setCheckable(true); m_pZView->setCheckable(true); m_pIsoView->setCheckable(true); m_pctrlX->setDefaultAction(m_pXView); m_pctrlY->setDefaultAction(m_pYView); m_pctrlZ->setDefaultAction(m_pZView); m_pctrlIso->setDefaultAction(m_pIsoView); AxisView->addWidget(m_pctrlX); AxisView->addWidget(m_pctrlY); AxisView->addWidget(m_pctrlZ); AxisView->addWidget(m_pctrlIso); } QHBoxLayout* ThreeDView = new QHBoxLayout; { m_pctrlPickCenter = new QPushButton(tr("Pick Center")); m_pctrlPickCenter->setSizePolicy(szPolicyMinimum); m_pctrlPickCenter->setCheckable(true); m_pctrlReset = new QPushButton(tr("Reset Scales")); m_pctrlReset->setSizePolicy(szPolicyMinimum); ThreeDView->addWidget(m_pctrlReset); ThreeDView->addWidget(m_pctrlPickCenter); } QHBoxLayout *ThreeDViewControls = new QHBoxLayout; { QLabel *ClipLabel = new QLabel(tr("Clip Plane")); ClipLabel->setSizePolicy(szPolicyMaximum); m_pctrlClipPlanePos = new QSlider(Qt::Horizontal); m_pctrlClipPlanePos->setMinimum(-300); m_pctrlClipPlanePos->setMaximum(300); m_pctrlClipPlanePos->setSliderPosition(0); m_pctrlClipPlanePos->setTickInterval(30); m_pctrlClipPlanePos->setTickPosition(QSlider::TicksBelow); m_pctrlClipPlanePos->setSizePolicy(szPolicyMinimum); ThreeDViewControls->addWidget(ClipLabel); ThreeDViewControls->addWidget(m_pctrlClipPlanePos); } QHBoxLayout *ActionButtons = new QHBoxLayout; { m_pctrlUndo = new QPushButton(QIcon(":/images/OnUndo.png"), tr("Undo")); m_pctrlRedo = new QPushButton(QIcon(":/images/OnRedo.png"), tr("Redo")); m_pctrlMenuButton = new QPushButton(tr("Other")); BodyMenu = new QMenu(tr("Actions..."),this); BodyMenu->addAction(m_pGrid); BodyMenu->addSeparator(); BodyMenu->addAction(m_pImportBodyDef); BodyMenu->addAction(m_pExportBodyDef); BodyMenu->addAction(m_pExportBodyGeom); BodyMenu->addSeparator(); BodyMenu->addAction(m_pBodyInertia); BodyMenu->addSeparator(); BodyMenu->addAction(m_pTranslateBody); BodyMenu->addAction(m_pScaleBody); BodyMenu->addSeparator(); m_pctrlMenuButton->setMenu(BodyMenu); ActionButtons->addWidget(m_pctrlUndo); ActionButtons->addWidget(m_pctrlRedo); ActionButtons->addWidget(m_pctrlMenuButton); } QHBoxLayout *CommandButtons = new QHBoxLayout; { m_pctrlOK = new QPushButton(tr("Save and Close")); m_pctrlOK->setAutoDefault(true); m_pctrlCancel = new QPushButton(tr("Cancel")); m_pctrlCancel->setAutoDefault(false); CommandButtons->addWidget(m_pctrlOK); CommandButtons->addWidget(m_pctrlCancel); } ControlsLayout->addLayout(AxisView); ControlsLayout->addLayout(ThreeDViewControls); ControlsLayout->addLayout(ThreeDParams); ControlsLayout->addLayout(ThreeDView); ControlsLayout->addStretch(1); ControlsLayout->addLayout(ActionButtons); ControlsLayout->addStretch(1); ControlsLayout->addLayout(CommandButtons); } QVBoxLayout *BodyParams = new QVBoxLayout; { QHBoxLayout *BodyDef = new QHBoxLayout; { m_pctrlBodyName = new QLineEdit(tr("BodyName")); m_pctrlBodyStyle = new LineBtn(this); m_pctrlBodyStyle->setSizePolicy(szPolicyMinimum); BodyDef->addWidget(m_pctrlBodyName); BodyDef->addWidget(m_pctrlBodyStyle); } QLabel *BodyDes = new QLabel(tr("Description:")); m_pctrlBodyDescription = new QTextEdit(); m_pctrlBodyDescription->setToolTip(tr("Enter here a short description for the body")); BodyParams->setStretchFactor(m_pctrlBodyDescription,1); QHBoxLayout *BodyType = new QHBoxLayout; { m_pctrlFlatPanels = new QRadioButton(tr("Flat Panels")); m_pctrlBSplines = new QRadioButton(tr("BSplines")); m_pctrlFlatPanels->setSizePolicy(szPolicyMinimum); m_pctrlBSplines->setSizePolicy(szPolicyMinimum); BodyType->addWidget(m_pctrlFlatPanels); BodyType->addWidget(m_pctrlBSplines); } QGridLayout *SplineParams = new QGridLayout; { QLabel *lab1 = new QLabel(tr("x")); QLabel *lab2 = new QLabel(tr("Hoop")); QLabel *lab3 = new QLabel(tr("Degree")); QLabel *lab4 = new QLabel(tr("Panels")); QLabel *labBunch = new QLabel(tr("Panel bunch")); m_pctrlXDegree = new QComboBox; m_pctrlHoopDegree = new QComboBox; m_pctrlNXPanels = new DoubleEdit; m_pctrlNHoopPanels = new DoubleEdit; m_pctrlEdgeWeight = new QSlider(Qt::Horizontal); m_pctrlEdgeWeight->setMinimum(0); m_pctrlEdgeWeight->setMaximum(100); m_pctrlEdgeWeight->setSliderPosition(1); m_pctrlEdgeWeight->setTickInterval(10); m_pctrlEdgeWeight->setTickPosition(QSlider::TicksBelow); m_pctrlEdgeWeight->setSizePolicy(szPolicyMinimum); m_pctrlPanelBunch= new QSlider(Qt::Horizontal); m_pctrlPanelBunch->setMinimum(0 ); m_pctrlPanelBunch->setMaximum(100.0); m_pctrlPanelBunch->setSliderPosition(0); m_pctrlPanelBunch->setTickInterval(10); m_pctrlPanelBunch->setTickPosition(QSlider::TicksBelow); m_pctrlPanelBunch->setSizePolicy(szPolicyMinimum); lab1->setSizePolicy(szPolicyMinimum); lab2->setSizePolicy(szPolicyMinimum); lab3->setSizePolicy(szPolicyMinimum); lab4->setSizePolicy(szPolicyMinimum); m_pctrlXDegree->setSizePolicy(szPolicyMinimum); m_pctrlHoopDegree->setSizePolicy(szPolicyMinimum); m_pctrlNXPanels->setSizePolicy(szPolicyMinimum); m_pctrlNHoopPanels->setSizePolicy(szPolicyMinimum); m_pctrlNXPanels->SetPrecision(0); m_pctrlNHoopPanels->SetPrecision(0); SplineParams->addWidget(lab1,1,2, Qt::AlignCenter); SplineParams->addWidget(lab2,1,3, Qt::AlignCenter); SplineParams->addWidget(lab3,2,1, Qt::AlignRight); SplineParams->addWidget(lab4,3,1, Qt::AlignRight); SplineParams->addWidget(m_pctrlXDegree,2,2); SplineParams->addWidget(m_pctrlHoopDegree,2,3); SplineParams->addWidget(m_pctrlNXPanels,3,2); SplineParams->addWidget(m_pctrlNHoopPanels,3,3); // SplineParams->addWidget(labWeight,4,1); // SplineParams->addWidget(m_pctrlEdgeWeight,4,2,1,2); SplineParams->addWidget(labBunch,5,1); SplineParams->addWidget(m_pctrlPanelBunch,5,2,1,2); } BodyParams->addLayout(BodyDef); BodyParams->addWidget(BodyDes); BodyParams->addWidget(m_pctrlBodyDescription); BodyParams->addStretch(1); BodyParams->addLayout(BodyType); BodyParams->addLayout(SplineParams); } QVBoxLayout * FramePosLayout = new QVBoxLayout; { m_pctrlFrameTable = new QTableView; // m_pctrlFrameTable->setSizePolicy(szPolicyMinimum); m_pctrlFrameTable->setWindowTitle(tr("Frames")); QLabel *LabelFrame = new QLabel(tr("Frame Positions")); LabelFrame->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); FramePosLayout->addWidget(LabelFrame); // FramePosLayout->addStretch(1); m_pctrlFrameTable->setSelectionMode(QAbstractItemView::SingleSelection); m_pctrlFrameTable->setSelectionBehavior(QAbstractItemView::SelectRows); m_pctrlFrameTable->setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed | QAbstractItemView::AnyKeyPressed); FramePosLayout->addWidget(m_pctrlFrameTable); } QVBoxLayout * FramePointLayout = new QVBoxLayout; { m_pctrlPointTable = new QTableView; // m_pctrlPointTable->setSizePolicy(szPolicyMinimum); m_pctrlPointTable->setWindowTitle(tr("Points")); QLabel *LabelPoints = new QLabel(tr("Current Frame Definition")); LabelPoints->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); FramePointLayout->addWidget(LabelPoints); // FramePointLayout->addStretch(1); m_pctrlPointTable->setSelectionMode(QAbstractItemView::SingleSelection); m_pctrlPointTable->setSelectionBehavior(QAbstractItemView::SelectRows); m_pctrlPointTable->setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed | QAbstractItemView::AnyKeyPressed); FramePointLayout->addWidget(m_pctrlPointTable); } m_pctrlControlsWidget = new QWidget; { QHBoxLayout *AllControls = new QHBoxLayout; { AllControls->addLayout(BodyParams); AllControls->addStretch(1); AllControls->addLayout(FramePosLayout); AllControls->addStretch(1); AllControls->addLayout(FramePointLayout); AllControls->addStretch(1); AllControls->addLayout(ControlsLayout); } m_pctrlControlsWidget->setLayout(AllControls); } QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addWidget(&m_3dWidget,2); MainLayout->addWidget(m_pctrlControlsWidget,1); setLayout(MainLayout); for (i=1; i<6; i++) { str = QString("%1").arg(i); m_pctrlXDegree->addItem(str); m_pctrlHoopDegree->addItem(str); } //Setup Frame table m_pctrlFrameTable->horizontalHeader()->setStretchLastSection(true); m_pFrameModel = new QStandardItemModel; m_pFrameModel->setRowCount(10);//temporary m_pFrameModel->setColumnCount(2); m_pctrlFrameTable->setModel(m_pFrameModel); m_pSelectionModelFrame = new QItemSelectionModel(m_pFrameModel); m_pctrlFrameTable->setSelectionModel(m_pSelectionModelFrame); m_pFrameDelegate = new BodyTableDelegate; m_pctrlFrameTable->setItemDelegate(m_pFrameDelegate); int *pFramePrecision = new int[2]; pFramePrecision[0] = 3;//five digits for x and y coordinates pFramePrecision[1] = 0; m_pFrameDelegate->SetPointer(pFramePrecision); //Setup Point Table m_pctrlPointTable->horizontalHeader()->setStretchLastSection(true); m_pPointModel = new QStandardItemModel; m_pPointModel->setRowCount(10);//temporary m_pPointModel->setColumnCount(3); m_pctrlPointTable->setModel(m_pPointModel); m_pSelectionModelPoint = new QItemSelectionModel(m_pPointModel); m_pctrlPointTable->setSelectionModel(m_pSelectionModelPoint); m_pPointDelegate = new BodyTableDelegate; m_pctrlPointTable->setItemDelegate(m_pPointDelegate); int *pPointPrecision = new int[3]; pPointPrecision[0] = 3;//five digits for x and y coordinates pPointPrecision[1] = 3; pPointPrecision[2] = 0; m_pPointDelegate->SetPointer(pPointPrecision); } void GL3dBodyDlg::ShowContextMenu(QContextMenuEvent * event) { m_pShowCurFrameOnly->setChecked(m_bCurFrameOnly); QMenu *CtxMenu = new QMenu(tr("Context Menu"),this); CtxMenu->addAction(m_pInsertPoint); CtxMenu->addAction(m_pRemovePoint); CtxMenu->addSeparator(); CtxMenu->addAction(m_pTranslateBody); CtxMenu->addAction(m_pScaleBody); CtxMenu->addSeparator(); CtxMenu->addAction(m_pShowCurFrameOnly); CtxMenu->addSeparator(); CtxMenu->addAction(m_pResetScales); CtxMenu->addSeparator(); CtxMenu->addAction(m_pGrid); CtxMenu->addSeparator(); CtxMenu->addAction(m_pUndo); CtxMenu->addAction(m_pRedo); CtxMenu->addSeparator(); CtxMenu->addAction(m_pImportBodyDef); CtxMenu->addAction(m_pExportBodyDef); CtxMenu->addAction(m_pExportBodyGeom); CtxMenu->addSeparator(); CtxMenu->addAction(m_pBodyInertia);; QPoint CltPt = event->pos(); m_ptPopUp.rx() = CltPt.x(); m_ptPopUp.ry() = CltPt.y(); m_3dWidget.ClientToGL(m_ptPopUp, m_RealPopUp); CtxMenu->exec(event->globalPos()); m_3dWidget.setCursor(Qt::CrossCursor); } void GL3dBodyDlg::showEvent(QShowEvent *event) { /** @todo restore, test, and remove elsewhere */ // move(s_WindowPos); // resize(s_WindowSize); SetTableUnits(); m_bChanged = false; m_bResetglBody = true; m_bIs3DScaleSet = false; SetScales(); ResizeTables(); UpdateView(); } void GL3dBodyDlg::ResizeTables() { int ColumnWidth = (int)((double)(m_pctrlFrameTable->width())/2.5); m_pctrlFrameTable->setColumnWidth(0,ColumnWidth); m_pctrlFrameTable->setColumnWidth(1,ColumnWidth); // m_pctrlFrameTable->setColumnWidth(2,ColumnWidth); ColumnWidth = (int)((double)(m_pctrlPointTable->width())/4); m_pctrlPointTable->setColumnWidth(0,ColumnWidth); m_pctrlPointTable->setColumnWidth(1,ColumnWidth); m_pctrlPointTable->setColumnWidth(2,ColumnWidth); } /** * Clears the stack starting at a given position. * @param the first stack element to remove */ void GL3dBodyDlg::ClearStack(int pos) { for(int il=m_UndoStack.size()-1; il>pos; il--) { delete m_UndoStack.at(il); m_UndoStack.removeAt(il); // remove from the stack } m_StackPos = m_UndoStack.size()-1; } /** * Restores a SplineFoil definition from the current position in the stack. */ void GL3dBodyDlg::SetPicture() { Body *pTmpBody = m_UndoStack.at(m_StackPos); m_pBody->Duplicate(pTmpBody); m_pBody->SetKnots(); FillFrameDataTable(); m_pFrame = m_pBody->activeFrame(); FillPointDataTable(); m_bResetglBody = true; m_bResetglBody2D = true; UpdateView(); } /** * Copies the current Body object to a new Body and pushes it on the stack. */ void GL3dBodyDlg::TakePicture() { m_bChanged = true; //clear the downstream part of the stack which becomes obsolete ClearStack(m_StackPos); // append a copy of the current object Body *pBody = new Body(); pBody->Duplicate(m_pBody); m_UndoStack.append(pBody); // the new current position is the top of the stack m_StackPos = m_UndoStack.size()-1; m_pctrlUndo->setEnabled(m_StackPos>0); m_pctrlRedo->setEnabled(m_StackPossetEnabled(m_StackPos>0); m_pctrlRedo->setEnabled(m_StackPos0) { m_StackPos--; SetPicture(); m_pctrlRedo->setEnabled(true); } else { //nothing to restore } m_pctrlUndo->setEnabled(m_StackPos>0); m_pctrlRedo->setEnabled(m_StackPospos().x() - m_3dWidget.geometry().x(), event->pos().y() - m_3dWidget.geometry().y()); //The mouse button has been wheeled //Process the message // point is in client coordinates if(m_BodyRect.contains(point)) { if(event->delta()<0) m_glScaled *= (GLfloat)1.06; else m_glScaled /= (GLfloat)1.06; } else if(m_BodyLineRect.contains(point)) { if(event->delta()<0) m_BodyScale *= 1.06; else m_BodyScale /= 1.06; m_BodyScaledOffset.Set((1.0 - m_BodyScale)*m_BodyScalingCenter.x + m_BodyScale * m_BodyOffset.x, (1.0 - m_BodyScale)*m_BodyScalingCenter.y + m_BodyScale * m_BodyOffset.y, 0.0); m_bResetglBody2D=true; } else if(m_FrameRect.contains(point)) { if(event->delta()<0) m_FrameScale *= 1.06; else m_FrameScale /= 1.06; m_FrameScaledOffset.Set((1.0 - m_FrameScale)*m_FrameScalingCenter.x + m_FrameScale * m_FrameOffset.x, (1.0 - m_FrameScale)*m_FrameScalingCenter.y + m_FrameScale * m_FrameOffset.y, 0.0); m_bResetglBody2D=true; } UpdateView(); } void GL3dBodyDlg::blockSignalling(bool bBlock) { blockSignals(bBlock); m_pPointDelegate->blockSignals(bBlock); m_pFrameDelegate->blockSignals(bBlock); m_pctrlPointTable->blockSignals(bBlock); m_pctrlFrameTable->blockSignals(bBlock); m_pSelectionModelPoint->blockSignals(bBlock); m_pSelectionModelFrame->blockSignals(bBlock); } xflr5-6.09-06/src/miarex/GL3DScales.h000644 001750 000144 00000004521 12247174402 020344 0ustar00techwinderusers000000 000000 /**************************************************************************** GL3DScales Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef GL3DSCALES_H #define GL3DSCALES_H #include #include #include #include #include #include #include #include "../misc/DoubleEdit.h" class GL3DScales : public QWidget { Q_OBJECT friend class MainFrame; friend class QMiarex; public: GL3DScales(QWidget *parent = NULL); void InitDialog(); private slots: void OnCpScale(); void OnApply(); void OnLiftScale(int pos); void OnDragScale(int pos); void OnVelocityScale(int pos); private: void showEvent(QShowEvent *event); void keyPressEvent(QKeyEvent *event); void SetupLayout(); void ReadStreamParams(); static bool LoadSettings(QSettings *pSettings); static bool SaveSettings(QSettings *pSettings); QSlider *m_pctrlLiftScaleSlider, *m_pctrlDragScaleSlider, *m_pctrlVelocityScaleSlider; QPushButton *ApplyButton; QCheckBox *m_pctrlAutoCpScale; DoubleEdit *m_pctrlLegendMin, *m_pctrlLegendMax; DoubleEdit *m_pctrlNXPoint, *m_pctrlDeltaL, *m_pctrlXFactor, *m_pctrlXOffset, *m_pctrlZOffset; QRadioButton *m_pctrlLE, *m_pctrlTE, *m_pctrlLine; QLabel *m_pctrlLengthUnit1, *m_pctrlLengthUnit2, *m_pctrlLengthUnit3; void *m_pMiarex; void *m_pMainFrame; public: static int s_pos; static int s_NX; static double s_DeltaL; static double s_XFactor; static double s_XOffset, s_ZOffset; }; #endif // GL3DSCALES_H xflr5-6.09-06/src/miarex/PanelAnalysisDlg.cpp000644 001750 000144 00000424235 12247174407 022262 0ustar00techwinderusers000000 000000 /**************************************************************************** PanelAnalysisDlg Class Copyright (C) 2009-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include "PanelAnalysisDlg.h" #include "../mainframe.h" #include "../globals.h" #include "../objects/CVector.h" #include "Miarex.h" void *PanelAnalysisDlg::s_pMiarex; QPoint PanelAnalysisDlg::s_Position; int PanelAnalysisDlg::s_MaxRHSSize = VLMMAXRHS; /** * The public constructor */ PanelAnalysisDlg::PanelAnalysisDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("3D Panel Analysis")); SetupLayout(); m_nRHS = 0; m_aij = m_aijWake = NULL; m_RHS = m_RHSRef = m_SigmaRef = m_Sigma = m_Mu = m_Cp = NULL; m_3DQInf = NULL; m_uVl = m_wVl = NULL; m_uRHS = m_vRHS = m_wRHS = m_rRHS = m_cRHS = m_uWake = m_wWake = NULL; m_Index = NULL; m_Speed = NULL; m_Alpha = 0.0; m_AlphaMax = 0.0; m_AlphaDelta = 0.0; m_QInf = 0.0; m_QInfMax = 0.0; m_QInfDelta = 0.0; RFF = 10.0; eps = 1.e-7; m_bSequence = false; m_bIsFinished = false; m_b3DSymetric = false; m_bSequence = false; m_bWarning = false; m_bInverted = false; m_bCancel = false; m_bTrefftz = false; m_MatSize = m_nNodes = m_NSurfaces = 0; m_CL = m_CX = m_CY = 0.0; m_GCm = m_GRm = m_GYm = m_VCm = m_VYm = m_IYm = 0.0; m_ControlMin = m_ControlMax = m_ControlDelta = 0.0; m_CP.Set(0.0,0.0,0.0); m_ViscousDrag = m_InducedDrag = 0.0; m_MatSize = 0; m_SymSize = 0; m_nNodes = 0; m_NSurfaces = 0; m_NWakeColumn = 0; m_WakeInterNodes = 1; m_MaxWakeIter = 0; m_nWakeNodes = 0; m_WakeSize = 0; m_strOut = ""; m_pWingList[0] = m_pWingList[1] = m_pWingList[2] = m_pWingList[3] = NULL; m_pBody = NULL; m_pWing = NULL; m_pWPolar = NULL; m_pPlane = NULL; m_ppSurface = NULL; m_pPanel = NULL; m_pWakePanel = NULL; m_pRefWakePanel = NULL; m_pMemPanel = NULL; m_pNode = NULL; m_pMemNode = NULL; m_pWakeNode = NULL; m_pRefWakeNode = NULL; m_Ctrl = 0.0; Theta0 = 0.0; u0 = 0.0; // m_Mass = 0.0; //Dimensional stability derivatives Xu = Xw = Zu = Zw = Zq = Mu = Mw = Mq = Zwp = Mwp = 0.0; Yv = Yp = Yr = Lv = Lp = Lr = Nv = Np = Nr = 0.0; // Non dimensional stability derivatives CXu = CZu = Cmu = CXq = CZq = Cmq = CXa = CZa = Cma = 0.0; CYb = CYp = CYr = Clb = Clp = Clr = Cnb = Cnp = Cnr = 0.0; CXe = CYe = CZe = Cle = Cme = Cne = 0.0; memset(m_ALong, 0, 16*sizeof(double)); memset(m_ALat, 0, 16*sizeof(double)); memset(m_R, 0, 9*sizeof(double)); memset(m_Is, 0, 9*sizeof(double)); memset(m_Ib, 0, 9*sizeof(double)); } /** * The public destructor. * */ PanelAnalysisDlg::~PanelAnalysisDlg() { Release(); } /** * Reserves the memory necessary to matrix arrays. *@return true if the memory could be allocated, false otherwise. */ bool PanelAnalysisDlg::AllocateMatrix(int &memsize) { Trace("Allocating matrix arrays"); int size2 = QMiarex::s_MaxMatSize * QMiarex::s_MaxMatSize; try { m_aij = new double[size2]; m_aijWake = new double[size2]; m_uRHS = new double[QMiarex::s_MaxMatSize]; m_vRHS = new double[QMiarex::s_MaxMatSize]; m_wRHS = new double[QMiarex::s_MaxMatSize]; m_pRHS = new double[QMiarex::s_MaxMatSize]; m_qRHS = new double[QMiarex::s_MaxMatSize]; m_rRHS = new double[QMiarex::s_MaxMatSize]; m_cRHS = new double[QMiarex::s_MaxMatSize]; m_uWake = new double[QMiarex::s_MaxMatSize]; m_wWake = new double[QMiarex::s_MaxMatSize]; m_uVl = new CVector[QMiarex::s_MaxMatSize]; m_wVl = new CVector[QMiarex::s_MaxMatSize]; m_Speed = new CVector[QMiarex::s_MaxMatSize]; m_Index = new int[QMiarex::s_MaxMatSize]; } catch(std::exception & e) { Release(); Trace(e.what()); QString strange = "Memory allocation error: the request for additional memory has been denied.\nPlease reduce the model's size."; QMessageBox::warning(this, tr("Warning"), strange); AddString(strange); return false; } memsize = sizeof(double) * 2 * size2; //bytes memsize += sizeof(double) * 9 * QMiarex::s_MaxMatSize; //bytes memsize += sizeof(CVector) * 3 * QMiarex::s_MaxMatSize; memsize += sizeof(int) * 1 * QMiarex::s_MaxMatSize; memset(m_aij, 0, size2 * sizeof(double)); memset(m_aijWake, 0, size2 * sizeof(double)); memset(m_uRHS, 0, QMiarex::s_MaxMatSize*sizeof(double)); memset(m_vRHS, 0, QMiarex::s_MaxMatSize*sizeof(double)); memset(m_wRHS, 0, QMiarex::s_MaxMatSize*sizeof(double)); memset(m_pRHS, 0, QMiarex::s_MaxMatSize*sizeof(double)); memset(m_qRHS, 0, QMiarex::s_MaxMatSize*sizeof(double)); memset(m_rRHS, 0, QMiarex::s_MaxMatSize*sizeof(double)); memset(m_cRHS, 0, QMiarex::s_MaxMatSize*sizeof(double)); memset(m_uWake, 0, QMiarex::s_MaxMatSize*sizeof(double)); memset(m_wWake, 0, QMiarex::s_MaxMatSize*sizeof(double)); memset(m_uVl, 0, QMiarex::s_MaxMatSize*sizeof(CVector)); memset(m_wVl, 0, QMiarex::s_MaxMatSize*sizeof(CVector)); memset(m_Speed, 0, QMiarex::s_MaxMatSize*sizeof(CVector)); memset(m_Index, 0, QMiarex::s_MaxMatSize*sizeof(int)); int RHSSize = 0; if(!AllocateRHS(RHSSize)) { QString strange = "Memory allocation error: the request for additional memory has been denied.\nPlease educe the model's size."; QMessageBox::warning(this, tr("Warning"), strange); AddString(strange); return false; } memsize += RHSSize; return true; } /** * Reserves the memory necessary to RHS arrays. *@return true if the memory could be allocated, false otherwise. */ bool PanelAnalysisDlg::AllocateRHS(int &memsize) { Trace("Allocating RHS arrays"); int size = QMiarex::s_MaxMatSize * s_MaxRHSSize; try { m_RHS = new double[size]; m_RHSRef = new double[size]; m_SigmaRef = new double[size]; m_Sigma = new double[size]; m_Mu = new double[size]; m_Cp = new double[size]; m_3DQInf = new double[s_MaxRHSSize]; } catch(std::exception &e) { Release(); // qDebug()<< e.what(); return false; } memsize = sizeof(double) * 6 * size; memset(m_RHS, 0, size*sizeof(double)); memset(m_RHSRef, 0, size*sizeof(double)); memset(m_Sigma, 0, size*sizeof(double)); memset(m_SigmaRef, 0, size*sizeof(double)); memset(m_Mu, 0, size*sizeof(double)); memset(m_Cp, 0, size*sizeof(double)); memset(m_3DQInf, 0, s_MaxRHSSize*sizeof(double)); return true; } /** * Releases the memory reserved for matrix and RHS arrays */ void PanelAnalysisDlg::Release() { if(m_aij) delete [] m_aij; if(m_aijWake) delete [] m_aijWake; m_aij = m_aijWake = NULL; if(m_RHS) delete [] m_RHS; if(m_RHSRef) delete [] m_RHSRef; if(m_SigmaRef) delete [] m_SigmaRef; if(m_Sigma) delete [] m_Sigma; if(m_Mu) delete [] m_Mu; if(m_Cp) delete [] m_Cp; m_RHS = m_RHSRef = m_SigmaRef = m_Sigma = m_Mu = m_Cp = NULL; if(m_3DQInf) delete m_3DQInf; m_3DQInf = NULL; if(m_uVl) delete [] m_uVl; if(m_wVl) delete [] m_wVl; m_uVl = m_wVl = NULL; if(m_uRHS) delete [] m_uRHS; if(m_vRHS) delete [] m_vRHS; if(m_wRHS) delete [] m_wRHS; if(m_rRHS) delete [] m_rRHS; if(m_cRHS) delete [] m_cRHS; if(m_uWake) delete [] m_uWake; if(m_wWake) delete [] m_wWake; m_uRHS = m_vRHS = m_wRHS = m_pRHS = m_qRHS = m_rRHS = m_cRHS = m_uWake = m_wWake = NULL; if(m_Index) delete [] m_Index; m_Index = NULL; if(m_Speed) delete [] m_Speed; m_Speed = NULL; } /** *Adds a string to the output widget and to the log file *@param strong the string to output */ void PanelAnalysisDlg::AddString(QString strong) { m_pctrlTextOutput->insertPlainText(strong); m_pctrlTextOutput->ensureCursorVisible(); WriteString(strong); } /** * Launches a calculation over the input sequence of aoa. * Used for type 1 & 2 analysis, without tilted geometry. * * The calculation is performed for two unit RHS, and all the Operating POints are calculated by linear combination. * The two unit RHS are for a unit velocity along the x-axis, and for a unit velocity along the z-axis. *@return true if all the aoa were computed successfully, false otherwise. Interpolation issues are not counted as unsuccessful. */ bool PanelAnalysisDlg::AlphaLoop() { QString str; if(m_AlphaMaxm_bThinSurfaces) TotalTime +=1.0; //for wake contribution if(m_pWPolar->m_bWakeRollUp) TotalTime += 20*m_nRHS*MaxWakeIter; m_pctrlProgress->setMinimum(0); m_pctrlProgress->setMaximum((int)TotalTime); m_Progress = 0.0; qApp->processEvents(); str = QString(tr(" Solving the problem... ")+"\n"); AddString("\n"+str); BuildInfluenceMatrix(); if (m_bCancel) return true; CreateUnitRHS(); if (m_bCancel) return true; if(!m_pWPolar->m_bThinSurfaces) { //compute wake contribution CreateWakeContribution(); //add wake contribution to matrix and RHS for(int p=0; p=0) // add symmetric contribution { GetDoubletInfluence(CC, m_pPanel+pp, VS, phiSym); V.x += VS.x; V.y -= VS.y; V.z += VS.z; phi += phiSym; } if(!m_pWPolar->m_bDirichlet || m_pPanel[p].m_Pos==MIDSURFACE) m_aij[m*Size+mm] = V.dot(m_pPanel[p].Normal); else if(m_pWPolar->m_bDirichlet) m_aij[m*Size+mm] = phi; mm++; } } m++; } m_Progress += 10.0*(double)Size/400./(double)Size; qApp->processEvents(); } } /** * Creates the source strengths for all requested RHS in a Panel analysis, using the specified boundary conditions (BC). * BC may be of the Neumann or Dirichlet type depending on the analysis type and on the geometry * * Uses NASA 4023 equation (20) & (22) * * The computation is performed for a unit speed. The results are scaled to speed later depending on the polar type. * *@param Alpha0 the first aoa in the sequence *@param AlphaDeltathe aoa increment *@param the total number of aoa and of source arrays to build */ void PanelAnalysisDlg::CreateSourceStrength(double Alpha0, double AlphaDelta, int nval) { int p, pp, q; double alpha; CVector WindDirection; AddString(tr(" Creating source strengths...")+"\n"); p=0; for (q=0; qm_bDirichlet || m_pPanel[p].m_Pos==MIDSURFACE) { // first term of RHS is -V.n RHS[m] = - m_pPanel[p].Normal.dot(VPanel); } else if(m_pWPolar->m_bDirichlet) RHS[m] = 0.0; if(m_pPanel[p].m_Pos!=MIDSURFACE) C = m_pPanel[p].CollPt; else C = m_pPanel[p].CtrlPt; for (pp=0; ppm_bDirichlet || m_pPanel[p].m_Pos==MIDSURFACE) { // Apply Neumann B.C. // NASA4023 eq. (22) and (23) // The RHS term is sigma[pp]*DJK = nj.Vjk RHS[m] -= V.dot(m_pPanel[p].Normal) * sigmapp; } else if(m_pWPolar->m_bDirichlet) { //NASA4023 eq. (20) RHS[m] -= (phi * sigmapp); } } } m++; } m_Progress += 5.0/(double)m_MatSize; qApp->processEvents(); } } /** *Builds the two unit RHS for freestream velocities directed along x and z */ void PanelAnalysisDlg::CreateUnitRHS() { AddString(" Creating the unit RHS vectors...\n"); CVector VInf; VInf.Set(1.0, 0.0, 0.0); CreateRHS(m_uRHS, VInf); VInf.Set(0.0, 0.0, 1.0); CreateRHS(m_wRHS, VInf); } /** * In the case of a panel analysis, adds the contribution of the wake columns to the coefficients of the influence matrix * Method : * - follow the method described in NASA 4023 eq. (44) * - add the wake's doublet contribution to the matrix * - add the difference in potential at the trailing edge panels to the RHS * Only a flat wake is considered. Wake roll-up has been tested but did not prove robust enough for implementation. */ void PanelAnalysisDlg::CreateWakeContribution() { int kw, lw, pw, p, pp, Size; CVector V, VS, C, CC, TrPt; double phi, phiSym; double PHC[MAXSPANSTATIONS]; CVector VHC[MAXSPANSTATIONS]; AddString(tr(" Adding the wake's contribution...")+"\n"); if(m_b3DSymetric) Size = m_SymSize; else Size = m_MatSize; int m, mm; m = mm = 0; for(p=0; pm_NXWakePanels; lw++) { GetDoubletInfluence(C, m_pWakePanel+pw, V, phi, true, true); PHC[kw] += phi; VHC[kw] += V; if(m_b3DSymetric && m_pPanel[p].m_bIsLeftPanel) { GetDoubletInfluence(CC, m_pWakePanel+pw, VS, phiSym, true,true); PHC[kw] += phiSym; VHC[kw].x += VS.x; VHC[kw].y -= VS.y; VHC[kw].z += VS.z; } pw++; } } //____________________________________________________________________________ //Add the contributions of the trailing panels to the matrix coefficients and to the RHS mm = 0; for(pp=0; ppm_bDirichlet || m_pPanel[p].m_Pos==MIDSURFACE) { //then add the velocity contribution of the wake column to the matrix coefficient m_aijWake[m*Size+mm] += VHC[m_pPanel[pp].m_iWakeColumn].dot(m_pPanel[p].Normal); //we do not add the term Phi_inf_KWPUM - Phi_inf_KWPLM (eq. 44) since it is 0, thin edge } else if(m_pWPolar->m_bDirichlet) { //then add the potential contribution of the wake column to the matrix coefficient m_aijWake[m*Size+mm] += PHC[m_pPanel[pp].m_iWakeColumn]; //we do not add the term Phi_inf_KWPUM - Phi_inf_KWPLM (eq. 44) since it is 0, thin edge } } else if(m_pPanel[pp].m_Pos==BOTSURFACE) { //the panel sedding a wake is on the bottom side, substract if(!m_pWPolar->m_bDirichlet || m_pPanel[p].m_Pos==MIDSURFACE) { //use Neumann B.C. m_aijWake[m*Size+mm] -= VHC[m_pPanel[pp].m_iWakeColumn].dot(m_pPanel[p].Normal); //corrected in v6.02; m_uWake[m] -= TrPt.x * VHC[m_pPanel[pp].m_iWakeColumn].dot(m_pPanel[p].Normal); m_wWake[m] -= TrPt.z * VHC[m_pPanel[pp].m_iWakeColumn].dot(m_pPanel[p].Normal); } else if(m_pWPolar->m_bDirichlet) { m_aijWake[m*Size+mm] -= PHC[m_pPanel[pp].m_iWakeColumn]; m_uWake[m] += TrPt.x * PHC[m_pPanel[pp].m_iWakeColumn]; m_wWake[m] += TrPt.z * PHC[m_pPanel[pp].m_iWakeColumn]; } } else if(m_pPanel[pp].m_Pos==TOPSURFACE) { //the panel sedding a wake is on the top side, add if(!m_pWPolar->m_bDirichlet || m_pPanel[p].m_Pos==MIDSURFACE) { //use Neumann B.C. m_aijWake[m*Size+mm] += VHC[m_pPanel[pp].m_iWakeColumn].dot(m_pPanel[p].Normal); //corrected in v6.02; m_uWake[m] += TrPt.x * VHC[m_pPanel[pp].m_iWakeColumn].dot(m_pPanel[p].Normal); m_wWake[m] += TrPt.z * VHC[m_pPanel[pp].m_iWakeColumn].dot(m_pPanel[p].Normal); } else if(m_pWPolar->m_bDirichlet) { m_aijWake[m*Size+mm] += PHC[m_pPanel[pp].m_iWakeColumn]; m_uWake[m] -= TrPt.x * PHC[m_pPanel[pp].m_iWakeColumn]; m_wWake[m] -= TrPt.z * PHC[m_pPanel[pp].m_iWakeColumn]; } } } mm++; } } m++; } m_Progress += 1.0/(double)m_MatSize; qApp->processEvents(); } } /** * In the case of a panel analysis, adds the contribution of the wake columns to the coefficients of the influence matrix * Method : * - follow the method described in NASA 4023 eq. (44) * - add the wake's doublet contribution to the matrix * - add the potential difference at the trailing edge panels to the RHS ; the potential's origin * is set arbitrarily to the geometrical orgin so that phi = V.dot(WindDirectio) x point_position * Only a flat wake is considered. Wake roll-up has been tested but did not prove robust enough for implementation. */ void PanelAnalysisDlg::CreateWakeContribution(double *pWakeContrib, CVector WindDirection) { int kw, lw, pw, p, pp; static CVector V, VS, C, CC, TrPt; double phi, phiSym; double PHC[MAXSPANSTATIONS]; CVector VHC[MAXSPANSTATIONS]; AddString(tr(" Adding the wake's contribution...")+"\n"); // if(m_b3DSymetric) Size = m_SymSize; // else Size = m_MatSize; int m, mm; m = mm = 0; for(p=0; pm_NXWakePanels; lw++) { GetDoubletInfluence(C, m_pWakePanel+pw, V, phi, true, true); PHC[kw] += phi; VHC[kw] += V; if(m_b3DSymetric && m_pPanel[p].m_bIsLeftPanel) { GetDoubletInfluence(CC, m_pWakePanel+pw, VS, phiSym, true, true); PHC[kw] += phiSym; VHC[kw].x += VS.x; VHC[kw].y -= VS.y; VHC[kw].z += VS.z; } pw++; } } //____________________________________________________________________________ //Add the contributions to the matrix coefficients and to the RHS mm = 0; for(pp=0; ppm_bDirichlet || m_pPanel[p].m_Pos==MIDSURFACE) { //then add the velocity contribution of the wake column to the matrix coefficient //we do not add the term Phi_inf_KWPUM - Phi_inf_KWPLM (eq. 44) since it is 0, thin edge } else if(m_pWPolar->m_bDirichlet) { //then add the potential contribution of the wake column to the matrix coefficient //we do not add the term Phi_inf_KWPUM - Phi_inf_KWPLM (eq. 44) since it is 0, thin edge } } else if(m_pPanel[pp].m_Pos==BOTSURFACE)//bottom side, substract { //evaluate the potential on the bottom side panel pp which is shedding a wake if(!m_pWPolar->m_bDirichlet || m_pPanel[p].m_Pos==MIDSURFACE) { //use Neumann B.C. pWakeContrib[m] -= TrPt.dot(WindDirection) * VHC[m_pPanel[pp].m_iWakeColumn].dot(m_pPanel[p].Normal); } else if(m_pWPolar->m_bDirichlet) { pWakeContrib[m] += TrPt.dot(WindDirection) * PHC[m_pPanel[pp].m_iWakeColumn]; } } else if(m_pPanel[pp].m_Pos==TOPSURFACE) //top side, add { //evaluate the potential on the top side panel pp which is shedding a wake if(!m_pWPolar->m_bDirichlet || m_pPanel[p].m_Pos==MIDSURFACE) { //use Neumann B.C. pWakeContrib[m] += TrPt.dot(WindDirection) * VHC[m_pPanel[pp].m_iWakeColumn].dot(m_pPanel[p].Normal); } else if(m_pWPolar->m_bDirichlet) { pWakeContrib[m] -= TrPt.dot(WindDirection) * PHC[m_pPanel[pp].m_iWakeColumn]; } } } mm++; } } m++; } m_Progress += 1.0/(double)m_MatSize; qApp->processEvents(); } } /** * This method performs the computation in the far-field (Trefftz) plane. * For each of the wings, calculates, the resulting Force vector and induced drag, and the coefficients for each chordwise strip. * The calculations are made based on the source and doublet strengths or on the vortex circulations which have been previously computed. * The results are used a first time to calculate the balance velocities, and a second time for the calculation of aero coefficients * @param QInf the freestream velocity * @param Alpha0 the first aoa in the sequence * @param AlphaDelta the aoa increment * @param nval the number of aoa in the sequence */ void PanelAnalysisDlg::ComputeFarField(double QInf, double Alpha0, double AlphaDelta, int nval) { QString strong; int q, pos; double alpha, IDrag, *Mu, *Sigma; double ThinSize = 0.0; CVector WindNormal, WingForce; AddString(tr(" Calculating aerodynamic coefficients in the far field plane")+"\n"); for(int iw=0; iwm_MatSize; } for (q=0; qm_WPolarType!=FIXEDAOAPOLAR) alpha = Alpha0 + q*AlphaDelta; else alpha = m_OpAlpha; WindNormal.Set(-sin(alpha*PI/180.0), 0.0, cos(alpha*PI/180.0)); pos = 0; Mu = m_Mu + q*m_MatSize; Sigma = m_Sigma + q*m_MatSize; strong = tr(" Calculating point ") + QString("%1").arg(alpha,7,'f',2)+QString::fromUtf8("°....\n"); AddString(strong); for(int iw=0; iwPanelTrefftz(QInf, alpha, Mu, Sigma, pos, WingForce, IDrag, m_pWPolar, m_pWakePanel, m_pWakeNode); //save the results... will save another FF calculation when computing operating point m_WingForce[q*MAXWINGS+iw] = WingForce; m_WingIDrag[q*MAXWINGS+iw] = IDrag; memcpy(m_Cl + q*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS, m_pWingList[iw]->m_Cl, m_pWingList[iw]->m_NStation*sizeof(double)); memcpy(m_ICd + q*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS, m_pWingList[iw]->m_ICd, m_pWingList[iw]->m_NStation*sizeof(double)); memcpy(m_Ai + q*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS, m_pWingList[iw]->m_Ai, m_pWingList[iw]->m_NStation*sizeof(double)); memcpy(m_F + q*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS, m_pWingList[iw]->m_F, m_pWingList[iw]->m_NStation*sizeof(CVector)); memcpy(m_Vd + q*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS, m_pWingList[iw]->m_Vd, m_pWingList[iw]->m_NStation*sizeof(CVector)); pos += m_pWingList[iw]->m_MatSize; m_Progress += 10.0 * (double)m_pWingList[iw]->m_MatSize/ThinSize *(double)m_MatSize/400.; qApp->processEvents(); if(m_bCancel)return; } } } AddString("\n"); } /** * In the case of Type 2 or Type 7 polars, computes the velocity for which the lift force balances the plane's weight. * Assumes the lift force on each lifting wing has been calculated for a unit velocity. * @param Alpha the angle of attack to calculate * @param q the index of the aoa in the sequence */ void PanelAnalysisDlg::ComputeBalanceSpeeds(double Alpha, int q) { QString strong, strange; CVector Force, WindNormal; double TempCl,Lift; WindNormal.Set(-sin(Alpha*PI/180.0), 0.0, cos(Alpha*PI/180.0)); Force.Set(0.0,0.0,0.0); for(int iw=0; iwm_WPolarType==FIXEDSPEEDPOLAR) m_3DQInf[q] = m_pWPolar->m_QInf; else if(m_pWPolar->m_WPolarType==FIXEDLIFTPOLAR) { Lift = Force.dot(WindNormal) ;//N/q, for 1/ms TempCl = Lift/m_pWPolar->m_WArea; if(Lift<=0.0) { strong = " "+QString(tr("Found a negative lift for Alpha=%1.... skipping the angle...")+"\n").arg(Alpha, 5,'f',2); AddString(strong); m_bPointOut = true; m_bWarning = true; m_3DQInf[q] = -100.0; } else { m_3DQInf[q] = sqrt(2.0* 9.81 * m_pWPolar->m_Mass/m_pWPolar->m_Density/TempCl/m_pWPolar->m_WArea); strong = QString(" Alpha=%1 QInf=%2").arg(Alpha, 5,'f',2).arg(m_3DQInf[q]*MainFrame::s_mstoUnit,5,'f',2); GetSpeedUnit(strange, MainFrame::s_SpeedUnit); strong+= strange + "\n"; AddString(strong); } } } /** * Scales the unit results using the specified freestream velocity. * The velocity may have been specified directly in the case of a type 1 polar, or may have been calculated to balance the plane's weight. * The velocity for each aoa are provided in the member variable array m_3DQInf * @param nval the number of aoa in the sequence */ void PanelAnalysisDlg::ScaleResultstoSpeed(int nval) { int p, q, pp; //______________________________________________________________________________________ // Scale RHS and Sigma i.a.w. speeds (so far we have unit doublet and source strengths) QString strong="\n"; AddString(strong); memcpy(m_SigmaRef, m_Sigma, nval*m_MatSize*sizeof(double)); memcpy(m_RHSRef, m_Mu, nval*m_MatSize*sizeof(double)); if(m_pWPolar->m_WPolarType!=FIXEDAOAPOLAR) { p=0; for (q=0; qm_WPolarType!=FIXEDAOAPOLAR) { for (q=0; qm_NStation; m++) { m_F[ m+ q*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS] *= m_3DQInf[q] * m_3DQInf[q]; m_Vd[m+ q*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS] *= m_3DQInf[q] * m_3DQInf[q]; } } } } } else { for (q=0; qm_NStation; m++) { m_F[ m+ q*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS] = m_F[ m] * m_3DQInf[q] * m_3DQInf[q]; m_Vd[m+ q*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS] = m_Vd[m] * m_3DQInf[q] * m_3DQInf[q]; } m_WingForce[q*MAXWINGS+iw] = m_WingForce[iw]; m_WingIDrag[q*MAXWINGS+iw] = m_WingIDrag[iw]; } } } } } /** * Computes the viscous and inviscid aerodynamic coefficients. * @param V0 the initial aoa or velocity, depending on the polar type * @param VDelta the aoa or velocity increment, depending on the polar type * @param nrhs the number of points in the sequence */ void PanelAnalysisDlg::ComputeAeroCoefs(double V0, double VDelta, int nrhs) { int q; QString str, strong; if(m_pWPolar->m_WPolarType!=FIXEDAOAPOLAR) { for (q=0; q0.0) { if(!m_pWPolar->m_bTiltedGeom) str = QString(tr(" Computing Plane for alpha=%1")).arg(V0+q*VDelta,7,'f',2); else str = QString(tr(" Computing Plane for alpha=%1")).arg(m_OpAlpha,7,'f',2); str += QString::fromUtf8("°\n"); AddString(str); ComputePlane(V0+q*VDelta, m_3DQInf[q], q); } m_Progress += 5.0*(double)nrhs/(double)nrhs; qApp->processEvents(); } } else { for (q=0; qprocessEvents(); } } } /** * This method calculates the all the viscous and inviscid aerodynamic coefficients for one aoa. * The method calls the method in the QMiarex class which creates the operating points, updates the polar data, and updates the graphs. * The method uses in input the result data stored in the member variables. * @param Alpha the aoa of this calculation * @param QInf the freesteam velocity of this calculation * @param qrhs the index of the current right hand side calculation */ void PanelAnalysisDlg::ComputePlane(double Alpha, double QInf, int qrhs) { QMiarex *pMiarex = (QMiarex*)s_pMiarex; int pos; double *Mu, *Sigma; double cosa, sina; double Lift, IDrag, VDrag ,XCP, YCP, ZCP, WingVDrag; CVector WindNormal, WindDirection, WindSide; CVector Force; QString OutString; // Define wind (stability) axis cosa = cos(Alpha*PI/180.0); sina = sin(Alpha*PI/180.0); WindNormal.Set( -sina, 0.0, cosa); WindDirection.Set(cosa, 0.0, sina); WindSide = WindNormal * WindDirection; Mu = m_Mu + qrhs*m_MatSize; Sigma = m_Sigma + qrhs*m_MatSize; m_QInf = QInf; if(m_pWPolar->m_bTiltedGeom) Alpha = m_OpAlpha; else m_OpAlpha = Alpha; for(int iw=0; iwm_bWingOut = false; m_pWing->m_bWingOut = false; if(QInf >0.0) { AddString(tr(" Calculating aerodynamic coefficients...")+"\n"); m_bPointOut = false; Force.Set(0.0, 0.0, 0.0); Lift = IDrag = VDrag = XCP = YCP = ZCP = 0.0; m_GCm = m_VCm = m_ICm = m_GRm = m_GYm = m_VYm = m_IYm = 0.0; pos = 0; for(int iw=0; iwm_WingName+"\n"); //restore the saved FF results if(m_pWPolar->m_WPolarType!=FIXEDAOAPOLAR) { memcpy(m_pWingList[iw]->m_Cl, m_Cl + qrhs*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS, m_pWingList[iw]->m_NStation*sizeof(double)); memcpy(m_pWingList[iw]->m_ICd, m_ICd + qrhs*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS, m_pWingList[iw]->m_NStation*sizeof(double)); memcpy(m_pWingList[iw]->m_Ai, m_Ai + qrhs*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS, m_pWingList[iw]->m_NStation*sizeof(double)); memcpy(m_pWingList[iw]->m_F, m_F + qrhs*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS, m_pWingList[iw]->m_NStation*sizeof(CVector)); memcpy(m_pWingList[iw]->m_Vd, m_Vd + qrhs*MAXWINGS*MAXSPANSTATIONS + iw*MAXSPANSTATIONS, m_pWingList[iw]->m_NStation*sizeof(CVector)); } else { memcpy(m_pWingList[iw]->m_Cl, m_Cl , m_pWingList[iw]->m_NStation*sizeof(double)); memcpy(m_pWingList[iw]->m_ICd, m_ICd , m_pWingList[iw]->m_NStation*sizeof(double)); memcpy(m_pWingList[iw]->m_Ai, m_Ai , m_pWingList[iw]->m_NStation*sizeof(double)); memcpy(m_pWingList[iw]->m_F, m_F , m_pWingList[iw]->m_NStation*sizeof(CVector)); memcpy(m_pWingList[iw]->m_Vd, m_Vd , m_pWingList[iw]->m_NStation*sizeof(CVector)); } Force += m_WingForce[qrhs*MAXWINGS+iw]; IDrag += m_WingIDrag[qrhs*MAXWINGS+iw]; //Get viscous interpolations m_pWingList[iw]->PanelComputeViscous(QInf, Alpha, m_pWPolar, WingVDrag, m_pWPolar->m_bViscous, OutString); VDrag += WingVDrag; AddString(OutString); if(m_pWingList[iw]->m_bWingOut) m_bPointOut = true; //Compute moment coefficients m_pWingList[iw]->PanelComputeOnBody(QInf, Alpha, m_Cp+qrhs*m_MatSize+pos, m_Mu+qrhs*m_MatSize+pos, XCP, YCP, ZCP, m_GCm, m_VCm, m_ICm, m_GRm, m_GYm, m_VYm, m_IYm, m_pWPolar, m_pWPolar->m_CoG); m_pWingList[iw]->PanelComputeBending(m_pWPolar->m_bThinSurfaces); pos += m_pWingList[iw]->m_MatSize; } } if(m_pBody && m_pWPolar->m_AnalysisMethod==PANELMETHOD && !m_pWPolar->m_bIgnoreBodyPanels) { double ICm = 0.0; AddString(tr(" Calculating body...")+"\n"); m_pBody->ComputeAero(m_Cp+qrhs*m_MatSize+pos, XCP, YCP, ZCP, ICm, m_GRm, m_GYm, Alpha, m_pWPolar->m_CoG); m_ICm += ICm; m_GCm += ICm; //the body does not shed any wake --> no induced lift or drag } if(!m_bTrefftz) SumPanelForces(m_Cp+qrhs*m_MatSize, Alpha, Lift, IDrag); m_CL = Force.dot(WindNormal) /m_pWPolar->m_WArea; m_CX = Force.dot(WindDirection) /m_pWPolar->m_WArea; m_CY = Force.dot(WindSide) /m_pWPolar->m_WArea; m_InducedDrag = 1.0*IDrag/m_pWPolar->m_WArea; m_ViscousDrag = 1.0*VDrag/m_pWPolar->m_WArea; if(qAbs(Force.dot(WindNormal))>0.0) { m_CP.x = XCP/Force.dot(WindNormal); m_CP.y = YCP/Force.dot(WindNormal); m_CP.z = ZCP/Force.dot(WindNormal); } else { m_CP.Set(0.0,0.0,0.0); } m_GCm *= 1.0 / m_pWPolar->m_WArea /m_pWing->m_MAChord; m_VCm *= 1.0 / m_pWPolar->m_WArea /m_pWing->m_MAChord; m_ICm *= 1.0 / m_pWPolar->m_WArea /m_pWing->m_MAChord; m_GRm *= 1.0 / m_pWPolar->m_WArea /m_pWPolar->m_WSpan; m_GYm *= 1.0 / m_pWPolar->m_WArea /m_pWPolar->m_WSpan; m_VYm *= 1.0 / m_pWPolar->m_WArea /m_pWPolar->m_WSpan; m_IYm *= 1.0 / m_pWPolar->m_WArea /m_pWPolar->m_WSpan; if(m_bPointOut) m_bWarning = true; if(m_pWPolar->m_WPolarType==STABILITYPOLAR) m_Alpha = m_AlphaEq; // so it is set by default at the end of the analyis if(m_pPlane) pMiarex->AddPOpp(m_bPointOut, m_Cp+qrhs*m_MatSize, Mu, Sigma); else pMiarex->AddWOpp(QInf, Alpha, m_bPointOut, Mu, Sigma, m_Cp+qrhs*m_MatSize); if(pMiarex->m_iView==WPOLARVIEW) { pMiarex->CreateWPolarCurves(); pMiarex->UpdateView(); } else if(pMiarex->m_iView==WSTABVIEW && pMiarex->m_iStabilityView==STABPOLARVIEW) { pMiarex->CreateStabRLCurves(); pMiarex->UpdateView(); } AddString("\n"); } else m_bPointOut = true; qApp->processEvents(); } /** * Returns the estimation of the panel's lift coeficient based on the vortex circulation. * @param p the index of the panel * @param Gamma the pointer to the array of vortex circulations * @param Cp a pointer to the array of resulting panel lift coefficients * @param VInf the freestream velocity vector */ void PanelAnalysisDlg::GetVortexCp(const int &p, double *Gamma, double *Cp, CVector &VInf) { static CVector PanelForce, Force; // for each panel along the chord, add the lift coef PanelForce = VInf * m_pPanel[p].Vortex; PanelForce *= Gamma[p] * m_pWPolar->m_Density; //Newtons if(!m_pWPolar->m_bVLM1 && !m_pPanel[p].m_bIsLeading) { Force = VInf* m_pPanel[p].Vortex; Force *= Gamma[p+1] * m_pWPolar->m_Density; //Newtons PanelForce -= Force; } Cp[p] = -2.0 * PanelForce.dot(m_pPanel[p].Normal) /m_pPanel[p].Area/m_pWPolar->m_Density; } /** * This method calculates the Cp coefficient on a panel based on the distribution of doublet strengths. *The Cp coefficient is the derivative of the doublet strength on the surface *This calculation follows the method provided in document NASA 4023. * @param p the index of the panel for which the calculation is performed * @param Mu the array of doublet strength values * @param Cp a reference to the Cp variable to evaluate * @param VLocal a reference to the CVector holding the local velocity on the panel * @param QInf the freestream velocity * @param Vx the x-component of the freestream velocity vector * @param Vz the z-component of the freestream velocity vector */ void PanelAnalysisDlg::GetDoubletDerivative(const int &p, double *Mu, double &Cp, CVector &VLocal, double const &QInf, double Vx, double Vy, double Vz) { static int PL,PR, PU, PD; static double DELQ, DELP, mu0,mu1,mu2, x0,x1,x2, Speed2; static CVector VTot;//total local panel speed static CVector S2, Sl2; PL = m_pPanel[p].m_iPL; PR = m_pPanel[p].m_iPR; PU = m_pPanel[p].m_iPU; PD = m_pPanel[p].m_iPD; if(PL>=0 && PR>=0) { //we have two side neighbours x1 = 0.0; x0 = x1 - m_pPanel[p].SMQ - m_pPanel[PL].SMQ; x2 = x1 + m_pPanel[p].SMQ + m_pPanel[PR].SMQ; mu0 = Mu[PL]; mu1 = Mu[p]; mu2 = Mu[PR]; DELQ = mu0 *(x1-x2) /(x0-x1)/(x0-x2) + mu1 *(2.0*x1-x0-x2)/(x1-x0)/(x1-x2) + mu2 *(x1-x0) /(x2-x0)/(x2-x1); } else if(PL>=0 && PR<0) { // no right neighbour // do we have two left neighbours ? if(m_pPanel[PL].m_iPL>=0){ x2 = 0.0; x1 = x2 - m_pPanel[p].SMQ - m_pPanel[PL].SMQ; x0 = x1 - m_pPanel[PL].SMQ - m_pPanel[m_pPanel[PL].m_iPL].SMQ; mu0 = Mu[m_pPanel[PL].m_iPL]; mu1 = Mu[PL]; mu2 = Mu[p]; DELQ = mu0 *(x2-x1) /(x0-x1)/(x0-x2) + mu1 *(x2-x0) /(x1-x0)/(x1-x2) + mu2 *(2.0*x2-x0-x1)/(x2-x0)/(x2-x1); } else { //calculate the derivative on two panels only DELQ = -(Mu[PL]-Mu[p])/(m_pPanel[p].SMQ + m_pPanel[PL].SMQ); } } else if(PL<0 && PR>=0) { // no left neighbour // do we have two right neighbours ? if(m_pPanel[PR].m_iPR>=0){ x0 = 0.0; x1 = x0 + m_pPanel[p].SMQ + m_pPanel[PR].SMQ; x2 = x1 + m_pPanel[PR].SMQ + m_pPanel[m_pPanel[PR].m_iPR].SMQ; mu0 = Mu[p]; mu1 = Mu[PR]; mu2 = Mu[m_pPanel[PR].m_iPR]; DELQ = mu0 *(2.0*x0-x1-x2)/(x0-x1)/(x0-x2) + mu1 *(x0-x2) /(x1-x0)/(x1-x2) + mu2 *(x0-x1) /(x2-x0)/(x2-x1); } else { //calculate the derivative on two panels only DELQ = (Mu[PR]-Mu[p])/(m_pPanel[p].SMQ + m_pPanel[PR].SMQ); } } else { DELQ = 0.0; //Cannot calculate a derivative on one panel only } if(PU>=0 && PD>=0) { //we have one upstream and one downstream neighbour x1 = 0.0; x0 = x1 - m_pPanel[p].SMP - m_pPanel[PU].SMP; x2 = x1 + m_pPanel[p].SMP + m_pPanel[PD].SMP; mu0 = Mu[PU]; mu1 = Mu[p]; mu2 = Mu[PD]; DELP = mu0 *(x1-x2) /(x0-x1)/(x0-x2) + mu1 *(2.0*x1-x0-x2)/(x1-x0)/(x1-x2) + mu2 *(x1-x0) /(x2-x0)/(x2-x1); } else if(PU>=0 && PD<0) { // no downstream neighbour // do we have two upstream neighbours ? if(m_pPanel[PU].m_iPU>=0) { x2 = 0.0; x1 = x2 - m_pPanel[p ].SMP - m_pPanel[PU].SMP; x0 = x1 - m_pPanel[PU].SMP - m_pPanel[m_pPanel[PU].m_iPU].SMP; mu0 = Mu[m_pPanel[PU].m_iPU]; mu1 = Mu[PU]; mu2 = Mu[p]; DELP = mu0 *(x2-x1) /(x0-x1)/(x0-x2) + mu1 *(x2-x0) /(x1-x0)/(x1-x2) + mu2 *(2.0*x2-x0-x1)/(x2-x0)/(x2-x1); } else { //calculate the derivative on two panels only DELP = -(Mu[PU]-Mu[p])/(m_pPanel[p].SMP + m_pPanel[PU].SMP); } } else if(PU<0 && PD>=0) { // no upstream neighbour // do we have two downstream neighbours ? if(m_pPanel[PD].m_iPD>=0) { x0 = 0.0; x1 = x0 + m_pPanel[p].SMP + m_pPanel[PD].SMP; x2 = x1 + m_pPanel[PD].SMP + m_pPanel[m_pPanel[PD].m_iPD].SMP; mu0 = Mu[p]; mu1 = Mu[PD]; mu2 = Mu[m_pPanel[PD].m_iPD]; DELP = mu0 *(2.0*x0-x1-x2)/(x0-x1)/(x0-x2) + mu1 *(x0-x2) /(x1-x0)/(x1-x2) + mu2 *(x0-x1) /(x2-x0)/(x2-x1); } else { //calculate the derivative on two panels only DELP = (Mu[PD]-Mu[p])/(m_pPanel[p].SMP + m_pPanel[PD].SMP); } } else { DELP = 0.0; } //find middle of side 2 S2 = (m_pNode[m_pPanel[p].m_iTA] + m_pNode[m_pPanel[p].m_iTB])/2.0 - m_pPanel[p].CollPt; //convert to local coordinates Sl2 = m_pPanel[p].GlobalToLocal(S2); VTot = m_pPanel[p].GlobalToLocal(Vx, Vy, Vz); //in panel referential VLocal.x = -4.0*PI*(m_pPanel[p].SMP*DELP - Sl2.y*DELQ)/Sl2.x; VLocal.y = -4.0*PI*DELQ; // Vl.z = 4.0*PI*Sigma[p]; VTot +=VLocal; VTot.z = 0.0; Speed2 = VTot.x*VTot.x + VTot.y*VTot.y; Cp = 1.0-Speed2/QInf/QInf; } /** * Calculates the Cp coefficient on each panel, using hte vortex circulations or the doublet strengths, depending on the analysis method. * @param V0 the first value in the sequence, either aoa for type 1 & 2 polars or velocity for type 4 * @param VDelta the increment value of the input parameter, either aoa for type 1 & 2 polars or velocity for type 4 * @param nval the number of values in the sequence */ void PanelAnalysisDlg::ComputeOnBodyCp(double V0, double VDelta, int nval) { //following VSAERO theory manual //the on-body tangential perturbation speed is the derivative of the doublet strength int p, q; static double Alpha, *Mu, *Cp; static CVector WindDirection, VInf, VLocal; double Speed2, cosa, sina; //______________________________________________________________________________________ AddString(tr(" Computing On-Body Speeds...")+"\n"); if(m_pWPolar->m_WPolarType != FIXEDAOAPOLAR) { for (q=0; qprocessEvents(); } } else //FIXEDAOAPOLAR { // Define wind axis WindDirection.Set(cos(m_Alpha*PI/180.0), 0.0, sin(m_Alpha*PI/180.0)); for (q=0; qprocessEvents(); } for (q=1; qlonger code, but 4x more efficient. * *@param C the point where the influence is to be evaluated *@param pPanel a pointer to the Panel with the doublet strength *@param V the perturbation velocity at point C *@param phi the potential at point C *@param bWake true if the panel is located on the wake */ void PanelAnalysisDlg::DoubletNASA4023(CVector const &C, Panel *pPanel, CVector &V, double &phi, bool bWake) { int i; double CoreSize = 0.00000; if(qAbs(*m_pCoreSize)>1.e-10) CoreSize = *m_pCoreSize; CVector *pNode; if(bWake) pNode = m_pWakeNode; else pNode = m_pNode; phi = 0.0; V.x=0.0; V.y=0.0; V.z=0.0; PJK.x = C.x - pPanel->CollPt.x; PJK.y = C.y - pPanel->CollPt.y; PJK.z = C.z - pPanel->CollPt.z; PN = PJK.x*pPanel->Normal.x + PJK.y*pPanel->Normal.y + PJK.z*pPanel->Normal.z; pjk = sqrt(PJK.x*PJK.x + PJK.y*PJK.y + PJK.z*PJK.z); if(pjk> RFF*pPanel->Size) { // use far-field formula phi = PN * pPanel->Area /pjk/pjk/pjk; T1.x =PJK.x*3.0*PN - pPanel->Normal.x*pjk*pjk; T1.y =PJK.y*3.0*PN - pPanel->Normal.y*pjk*pjk; T1.z =PJK.z*3.0*PN - pPanel->Normal.z*pjk*pjk; V.x = T1.x * pPanel->Area /pjk/pjk/pjk/pjk/pjk; V.y = T1.y * pPanel->Area /pjk/pjk/pjk/pjk/pjk; V.z = T1.z * pPanel->Area /pjk/pjk/pjk/pjk/pjk; return; } if(pPanel->m_Pos>=MIDSURFACE) { m_pR[0] = pNode + pPanel->m_iLA; m_pR[1] = pNode + pPanel->m_iTA; m_pR[2] = pNode + pPanel->m_iTB; m_pR[3] = pNode + pPanel->m_iLB; m_pR[4] = pNode + pPanel->m_iLA; } else { m_pR[0] = pNode + pPanel->m_iLB; m_pR[1] = pNode + pPanel->m_iTB; m_pR[2] = pNode + pPanel->m_iTA; m_pR[3] = pNode + pPanel->m_iLA; m_pR[4] = pNode + pPanel->m_iLB; } for (i=0; i<4; i++) { a.x = C.x - m_pR[i]->x; a.y = C.y - m_pR[i]->y; a.z = C.z - m_pR[i]->z; b.x = C.x - m_pR[i+1]->x; b.y = C.y - m_pR[i+1]->y; b.z = C.z - m_pR[i+1]->z; s.x = m_pR[i+1]->x - m_pR[i]->x; s.y = m_pR[i+1]->y - m_pR[i]->y; s.z = m_pR[i+1]->z - m_pR[i]->z; A = sqrt(a.x*a.x + a.y*a.y + a.z*a.z); B = sqrt(b.x*b.x + b.y*b.y + b.z*b.z); SM = s.x*pPanel->m.x + s.y*pPanel->m.y + s.z*pPanel->m.z; SL = s.x*pPanel->l.x + s.y*pPanel->l.y + s.z*pPanel->l.z; AM = a.x*pPanel->m.x + a.y*pPanel->m.y + a.z*pPanel->m.z; AL = a.x*pPanel->l.x + a.y*pPanel->l.y + a.z*pPanel->l.z; Al = AM*SL - AL*SM; PA = PN*PN*SL + Al*AM; PB = PA - Al*SM; //get the distance of the TestPoint to the panel's side h.x = a.y*s.z - a.z*s.y; h.y = -a.x*s.z + a.z*s.x; h.z = a.x*s.y - a.y*s.x; //first the potential if(m_pR[i]->IsSame(*m_pR[i+1])) { CJKi = 0.0; //no contribution to speed either } else if ((((h.x*h.x+h.y*h.y+h.z*h.z)/(s.x*s.x+s.y*s.y+s.z*s.z) <= CoreSize*CoreSize) && a.x*s.x+a.y*s.y+a.z*s.z>=0.0 && b.x*s.x+b.y*s.y+b.z*s.z<=0.0) || A < CoreSize || B < CoreSize) { CJKi = 0.0;//speed is singular at panel edge, the value of the potential is unknown } else { RNUM = SM*PN * (B*PA-A*PB); DNOM = PA*PB + PN*PN*A*B*SM*SM; if(qAbs(PN)0 if on the panel's right side side = pPanel->Normal.x*h.x +pPanel->Normal.y*h.y +pPanel->Normal.z*h.z; if(side >=0.0) sign = 1.0; else sign = -1.0; if(DNOM<0.0) { if(PN>0.0) CJKi = PI * sign; else CJKi = -PI * sign; } else if(DNOM == 0.0) { if(PN>0.0) CJKi = PI/2.0 * sign; else CJKi = -PI/2.0 * sign; } else CJKi = 0.0; } else { CJKi = atan2(RNUM,DNOM); } // next the induced velocity h.x = a.y*b.z - a.z*b.y; h.y = -a.x*b.z + a.z*b.x; h.z = a.x*b.y - a.y*b.x; GL = ((A+B) /A/B/ (A*B + a.x*b.x+a.y*b.y+a.z*b.z)); V.x += h.x * GL; V.y += h.y * GL; V.z += h.z * GL; } phi += CJKi; } if (( (C.x-pPanel->CollPt.x)*(C.x-pPanel->CollPt.x) +(C.y-pPanel->CollPt.y)*(C.y-pPanel->CollPt.y) +(C.z-pPanel->CollPt.z)*(C.z-pPanel->CollPt.z))<1.e-10) { // if(m_R[0]->IsSame(*m_R[1]) || m_R[1]->IsSame(*m_R[2]) || m_R[2]->IsSame(*m_R[3]) || m_R[3]->IsSame(*m_R[0])) // phi = -3.0*pi/2.0; // else phi = -2.0*PI; } } /** * Returns the influence at point C of the panel pPanel. * If the panel pPanel is located on a thin surface, then its the influence of a vortex. * If it is on a thick surface, then its a doublet. * *@param C the point where the influence is to be evaluated *@param pPanel a pointer to the Panel with the doublet strength *@param V the perturbation velocity at point C *@param phi the potential at point C *@param bWake true if the panel is located on the wake *@param bAll true if the influence of the bound vortex should be evaluated, in the case of a VLM analysis. */ void PanelAnalysisDlg::GetDoubletInfluence(CVector const &C, Panel *pPanel, CVector &V, double &phi, bool bWake, bool bAll) { if(pPanel->m_Pos!=MIDSURFACE || pPanel->m_bIsWakePanel) DoubletNASA4023(C, pPanel, V, phi, bWake); else { VLMGetVortexInfluence(pPanel, C, V, bAll); phi = 0.0; } if(m_pWPolar->m_bGround) { CG.Set(C.x, C.y, -C.z-2.0*m_pWPolar->m_Height); if(pPanel->m_Pos!=MIDSURFACE || pPanel->m_bIsWakePanel) DoubletNASA4023(CG, pPanel, VG, phiG, bWake); else { VLMGetVortexInfluence(pPanel, CG, VG, bAll); phiG = 0.0; } V.x += VG.x; V.y += VG.y; V.z -= VG.z; phi += phiG; } } /** * Returns the influence at point C of a uniform source distribution on the panel pPanel * The panel is necessarily located on a thick surface, else the source strength is zero *@param C the point where the influence is to be evaluated *@param pPanel a pointer to the Panel with the doublet strength *@param V the perturbation velocity at point C *@param phi the potential at point C */ void PanelAnalysisDlg::GetSourceInfluence(CVector const &C, Panel *pPanel, CVector &V, double &phi) { SourceNASA4023(C, pPanel, V, phi); if(m_pWPolar->m_bGround) { CG.Set(C.x, C.y, -C.z-2.0*m_pWPolar->m_Height); SourceNASA4023(CG, pPanel, VG, phiG); V.x += VG.x; V.y += VG.y; V.z -= VG.z; phi += phiG; } } /** * Returns the perturbation velocity vector at a given point, due to the distribution of source and doublet/circulation strengths. * @param C the point where the influence is to be evaluated * @param Mu a pointer to the array of doublet strength or vortex circulations * @param sigma a pointer to the array of source strengths * @param VT the resulting perturbation velocity * @param bAll true if the influence of the bound vortex should be included, in the case of a VLM analysis */ void PanelAnalysisDlg::GetSpeedVector(CVector const &C, double *Mu, double *Sigma, CVector &VT, bool bAll) { CVector V; int pp, pw, lw; double phi, sign; VT.Set(0.0,0.0,0.0); for (pp=0; ppm_NXWakePanels; lw++) { GetDoubletInfluence(C, m_pWakePanel+pw+lw, V, phi, true, bAll); VT += V * Mu[pp]*sign; } } } } /** * Returns the perturbation velocity vector at a given point, due to the distribution of source and doublet/circulation strengths. * Overloaded function in the case where the source and doublet/vortex strengths are float values loaded from a file and not doublet values. * @param C the point where the influence is to be evaluated * @param Mu a pointer to the array of doublet strength or vortex circulations * @param sigma a pointer to the array of source strengths * @param VT the resulting perturbation velocity * @param bAll true if the influence of the bound vortex should be included, in the case of a VLM analysis */ void PanelAnalysisDlg::GetSpeedVector(CVector const &C, float *Mu, float *Sigma, CVector &VT, bool bAll) { CVector V; int pp, pw, lw; double phi, sign; VT.Set(0.0,0.0,0.0); for (pp=0; ppm_NXWakePanels; lw++) { GetDoubletInfluence(C, m_pWakePanel+pw+lw, V, phi, true, bAll); VT += V * Mu[pp]*sign; } } } } /** *Initializes the dialog and the analysis */ bool PanelAnalysisDlg::InitDialog() { m_Progress = 0.0; m_pctrlProgress->setValue(m_Progress); QString FileName = QDir::tempPath() + "/XFLR5.log"; m_pXFile = new QFile(FileName); if (!m_pXFile->open(QIODevice::WriteOnly | QIODevice::Text)) m_pXFile = NULL; m_pctrlTextOutput->clear(); m_bPointOut = false; m_bCancel = false; m_bWarning = false; m_bWakeRollUp = false; m_nRHS = 0; if(m_pWPolar->polarType()==FIXEDAOAPOLAR) m_nRHS = (int)qAbs((m_QInfMax-m_QInf)*1.0001/m_QInfDelta) +1; else if(m_pWPolar->polarType()==STABILITYPOLAR) m_nRHS = (int)qAbs((m_ControlMax-m_ControlMin)*1.0001/m_ControlDelta) +1; else m_nRHS = (int)qAbs((m_AlphaMax-m_Alpha)*1.0001/m_AlphaDelta) +1; if(!m_bSequence) m_nRHS = 1; else if(m_nRHS>=VLMMAXRHS) { QString strange = QString("The number of points to be calculated will be limited to %1").arg(VLMMAXRHS); QMessageBox::warning(this, tr("Warning"), strange); m_nRHS = VLMMAXRHS-1; s_MaxRHSSize = (int)((double)m_nRHS * 1.2); } SetFileHeader(); QString str = ""; m_b3DSymetric = m_pWing->m_bSymetric; for(int iw=0; iwm_bSymetric) { m_b3DSymetric = false; break; } } } if(m_pWPolar->m_WPolarType==STABILITYPOLAR ) m_b3DSymetric=false; if(qAbs(m_pWPolar->m_Beta)>0) m_b3DSymetric=false; if (m_b3DSymetric) AddString(tr("Performing symmetric calculation")+"\n"); else { str = tr("Performing asymmetric calculation : ")+ str +"\n"; AddString(str); } str = QString(tr("Counted %1 panel elements")+"\n").arg(m_MatSize,4); AddString(str); AddString("\n"); Wing::s_bVLMSymetric = m_b3DSymetric; m_pctrlProgress->setMinimum(0); m_pctrlProgress->setMaximum(100); return true; } /** Overrides the keyPressEvent sent by Qt */ void PanelAnalysisDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Escape: { OnCancelAnalysis(); event->accept(); return; } default: event->ignore(); } } /** The user has requested to cancel the on-going analysis*/ void PanelAnalysisDlg::OnCancelAnalysis() { if(m_pXFile->isOpen()) m_pXFile->close(); // CWing::s_bCancel = true; m_bCancel = true; m_bSkip = true; m_bExit = true; if(m_bIsFinished) { m_bCancel = false; done(1); } } /** * Launches a calculation over the input sequence of velocity. * Used for type 4 analysis, without tilted geometry. * * The calculation is performed for two unit RHS, and all the Operating POints are calculated by linear combination. * The two unit RHS are for a unit velocity along the x-axis, and for a unit velocity along the z-axis. *@return true if all the aoa were computed successfully, false otherwise. Interpolation issues are not counted as unsuccessful. */ bool PanelAnalysisDlg::QInfLoop() { QString str; double Alpha = 0.0; QMiarex *pMiarex = (QMiarex*)s_pMiarex; if(m_QInfMaxm_bThinSurfaces) TotalTime +=1.0; //for wake contribution m_pctrlProgress->setMinimum(0); m_pctrlProgress->setMaximum((int)TotalTime); m_Progress = 0.0; qApp->processEvents(); if(m_pWPolar->m_bTiltedGeom) { //reset the initial geometry before a new angle is processed memcpy(m_pPanel, m_pMemPanel, m_MatSize * sizeof(Panel)); memcpy(m_pNode, m_pMemNode, m_nNodes * sizeof(CVector)); memcpy(m_pWakePanel, m_pRefWakePanel, m_WakeSize * sizeof(Panel)); memcpy(m_pWakeNode, m_pRefWakeNode, m_nWakeNodes * sizeof(CVector)); // Rotate the wing panels and translate the wake to the new T.E. position CVector O; pMiarex->RotateGeomY(m_pWPolar->m_ASpec, O); m_OpAlpha = m_pWPolar->m_ASpec; Alpha = 0.0; } else Alpha = m_Alpha; str = QString(tr(" Solving the problem... ")+"\n"); AddString("\n"+str); BuildInfluenceMatrix(); if (m_bCancel) return true; CreateUnitRHS(); if (m_bCancel) return true; CreateSourceStrength(m_Alpha, m_AlphaDelta, m_nRHS); if (m_bCancel) return true; if(!m_pWPolar->m_bThinSurfaces) { //compute wake contribution CreateWakeContribution(); //add wake contribution to matrix and RHS for(int p=0; plonger code, but 4x more efficient. * *@param C the point where the influence is to be evaluated *@param pPanel a pointer to the Panel with the doublet strength *@param V the perturbation velocity at point C *@param phi the potential at point C */ void PanelAnalysisDlg::SourceNASA4023(CVector const &C, Panel *pPanel, CVector &V, double &phi) { int i; double CoreSize = 0.00000; if(qAbs(*m_pCoreSize)>1.e-10) CoreSize = *m_pCoreSize; phi = 0.0; V.x=0.0; V.y=0.0; V.z=0.0; PJK.x = C.x - pPanel->CollPt.x; PJK.y = C.y - pPanel->CollPt.y; PJK.z = C.z - pPanel->CollPt.z; PN = PJK.x*pPanel->Normal.x + PJK.y*pPanel->Normal.y + PJK.z*pPanel->Normal.z; pjk = sqrt(PJK.x*PJK.x + PJK.y*PJK.y + PJK.z*PJK.z); if(pjk> RFF*pPanel->Size) { // use far-field formula phi = pPanel->Area /pjk; V.x = PJK.x * pPanel->Area/pjk/pjk/pjk; V.y = PJK.y * pPanel->Area/pjk/pjk/pjk; V.z = PJK.z * pPanel->Area/pjk/pjk/pjk; return; } if(pPanel->m_Pos>=MIDSURFACE) { m_pR[0] = m_pNode + pPanel->m_iLA; m_pR[1] = m_pNode + pPanel->m_iTA; m_pR[2] = m_pNode + pPanel->m_iTB; m_pR[3] = m_pNode + pPanel->m_iLB; m_pR[4] = m_pNode + pPanel->m_iLA; } else { m_pR[0] = m_pNode + pPanel->m_iLB; m_pR[1] = m_pNode + pPanel->m_iTB; m_pR[2] = m_pNode + pPanel->m_iTA; m_pR[3] = m_pNode + pPanel->m_iLA; m_pR[4] = m_pNode + pPanel->m_iLB; } for (i=0; i<4; i++) { a.x = C.x - m_pR[i]->x; a.y = C.y - m_pR[i]->y; a.z = C.z - m_pR[i]->z; b.x = C.x - m_pR[i+1]->x; b.y = C.y - m_pR[i+1]->y; b.z = C.z - m_pR[i+1]->z; s.x = m_pR[i+1]->x - m_pR[i]->x; s.y = m_pR[i+1]->y - m_pR[i]->y; s.z = m_pR[i+1]->z - m_pR[i]->z; A = sqrt(a.x*a.x + a.y*a.y + a.z*a.z); B = sqrt(b.x*b.x + b.y*b.y + b.z*b.z); S = sqrt(s.x*s.x + s.y*s.y + s.z*s.z); SM = s.x*pPanel->m.x + s.y*pPanel->m.y + s.z*pPanel->m.z; SL = s.x*pPanel->l.x + s.y*pPanel->l.y + s.z*pPanel->l.z; AM = a.x*pPanel->m.x + a.y*pPanel->m.y + a.z*pPanel->m.z; AL = a.x*pPanel->l.x + a.y*pPanel->l.y + a.z*pPanel->l.z; Al = AM*SL - AL*SM; PA = PN*PN*SL + Al*AM; PB = PA - Al*SM; //get the distance of the TestPoint to the panel's side h.x = a.y*s.z - a.z*s.y; h.y = -a.x*s.z + a.z*s.x; h.z = a.x*s.y - a.y*s.x; if(m_pR[i]->IsSame(*m_pR[i+1])) { //no contribution from this side CJKi = 0.0; } else if ((((h.x*h.x+h.y*h.y+h.z*h.z)/(s.x*s.x+s.y*s.y+s.z*s.z) <= CoreSize*CoreSize) && a.x*s.x+a.y*s.y+a.z*s.z>=0.0 && b.x*s.x+b.y*s.y+b.z*s.z<=0.0) || A < CoreSize || B < CoreSize) { //if lying on the panel's side... no contribution CJKi = 0.0; } else { //first the potential if(A+B-S>0.0) GL = 1.0/S * log((A+B+S)/(A+B-S)); RNUM = SM*PN * (B*PA-A*PB); DNOM = PA*PB + PN*PN*A*B*SM*SM; if(qAbs(PN)0 if the point is on the panel's right side side = pPanel->Normal.x*h.x + pPanel->Normal.y*h.y + pPanel->Normal.z*h.z; if(side >=0.0) sign = 1.0; else sign = -1.0; if(DNOM<0.0) { if(PN>0.0) CJKi = PI * sign; else CJKi = -PI * sign; } else if(DNOM == 0.0) { if(PN>0.0) CJKi = PI/2.0 * sign; else CJKi = -PI/2.0 * sign; } else CJKi = 0.0; } else { CJKi = atan2(RNUM, DNOM); } phi += Al*GL - PN*CJKi; // next the induced velocity T1.x = pPanel->l.x * SM*GL; T1.y = pPanel->l.y * SM*GL; T1.z = pPanel->l.z * SM*GL; T2.x = pPanel->m.x * SL*GL; T2.y = pPanel->m.y * SL*GL; T2.z = pPanel->m.z * SL*GL; T.x = pPanel->Normal.x * CJKi; T.y = pPanel->Normal.y * CJKi; T.z = pPanel->Normal.z * CJKi; V.x += T.x + T1.x - T2.x; V.y += T.y + T1.y - T2.y; V.z += T.z + T1.z - T2.z; } } } /** *Initializes the header of the log file */ void PanelAnalysisDlg::SetFileHeader() { QTextStream out(m_pXFile); out << "\n"; out << MainFrame::versionName(); out << "\n"; QDateTime dt = QDateTime::currentDateTime(); QString str = dt.toString("dd.MM.yyyy hh:mm:ss"); out << str<<"\n"; if(m_pPlane) out << m_pPlane->PlaneName(); else if(m_pWing) out << m_pWing->WingName(); out << "\n"; out << m_pWPolar->m_PlrName; out << "\n___________________________________\n"; } /**Updates the progress of the analysis in the slider widget */ void PanelAnalysisDlg::OnProgress() { m_pctrlProgress->setValue((int)m_Progress); } /** Sets up the GUI */ void PanelAnalysisDlg::SetupLayout() { QDesktopWidget desktop; QRect r = desktop.geometry(); setMinimumHeight(r.height()/2); setMinimumWidth(r.width()/2); m_pctrlTextOutput = new QTextEdit; m_pctrlTextOutput->setReadOnly(true); m_pctrlTextOutput->setLineWrapMode(QTextEdit::NoWrap); m_pctrlTextOutput->setWordWrapMode(QTextOption::NoWrap); m_pctrlTextOutput->setFontFamily("Courier"); m_pctrlProgress = new QProgressBar; m_pctrlProgress->setOrientation(Qt::Horizontal); m_pctrlProgress->setMinimum(0); m_pctrlProgress->setMaximum(100); m_pctrlProgress->setValue(0); m_pctrlCancel = new QPushButton(tr("Cancel")); connect(m_pctrlCancel, SIGNAL(clicked()), this, SLOT(OnCancelAnalysis())); QHBoxLayout *ButtonLayout = new QHBoxLayout; ButtonLayout->addStretch(1); ButtonLayout->addWidget(m_pctrlCancel); ButtonLayout->addStretch(1); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(m_pctrlTextOutput); mainLayout->addWidget(m_pctrlProgress); mainLayout->addLayout(ButtonLayout); setLayout(mainLayout); } /** * Solves the linear system for the unit RHS, using LU decomposition. * Method : * - If the polar is of type 1 or 2, solve the linear system * - for cosine and sine parts, for a unit speed * - If the polar is of type 4, solve only for unit speed and for the specified Alpha * - Reconstruct right side results if calculation was symetric * - Sort results i.a.w. panel numbering * * Calculates the local velocities on each panel */ bool PanelAnalysisDlg::SolveUnitRHS() { int Size = m_MatSize; if(m_b3DSymetric) Size = m_SymSize; memcpy(m_RHS, m_uRHS, Size * sizeof(double)); memcpy(m_RHS+Size, m_wRHS, Size * sizeof(double)); AddString(" Performing LU Matrix decomposition...\n"); if(!Crout_LU_Decomposition_with_Pivoting(m_aij, m_Index, Size, &m_bCancel, 90.0*(double)m_MatSize/400.0, m_Progress)) { AddString(tr(" Singular Matrix.... Aborting calculation...\n")); m_bInverted = false; return false; } else m_bInverted = true; AddString(" Solving LU system...\n"); Crout_LU_with_Pivoting_Solve(m_aij, m_uRHS, m_Index, m_RHS, Size, &m_bCancel); Crout_LU_with_Pivoting_Solve(m_aij, m_wRHS, m_Index, m_RHS+Size, Size, &m_bCancel); //______________________________________________________________________________________ //Reconstruct right side results if calculation was symetric int m,p; if(m_b3DSymetric) { m=0; for (p=0; p=0) { m_uRHS[m_pPanel[p].m_iSym] = m_RHS[m]; m_wRHS[m_pPanel[p].m_iSym] = m_RHS[m+Size]; } m++; } } } else { memcpy(m_uRHS, m_RHS, m_MatSize*sizeof(double)); memcpy(m_wRHS, m_RHS+m_MatSize, m_MatSize*sizeof(double)); } // Define unit local velocity vector, necessary for moment calculations in stability analysis of 3D panels CVector u(1.0, 0.0, 0.0); CVector w(0.0, 0.0, 1.0); double Cp; for (p=0; pm_WPolarType!=FIXEDAOAPOLAR) nrhs = nval; // else nrhs = 0; //______________________________________________________________________________________ // reconstruct all results from cosine and sine unit vectors for (q=0; qprocessEvents(); if(!m_pWPolar) return; QString strong; m_pctrlCancel->setText(tr("Cancel")); m_bIsFinished = false; if(m_pWPolar->m_AnalysisMethod==PANELMETHOD) strong = tr("Launching 3D Panel Analysis....")+"\n"; else if(m_pWPolar->m_AnalysisMethod==VLMMETHOD) { if(m_pWPolar->m_bVLM1) strong = tr("Launching VLM1 Analysis....")+"\n"; else strong = tr("Launching VLM2 Analysis....")+"\n"; } AddString(strong); if(m_pWPolar->m_AnalysisMethod==PANELMETHOD) { strong = tr("Using Dirichlet boundary conditions")+"\n"; if(m_pWPolar->m_bDirichlet) strong = tr("Using Dirichlet boundary conditions")+"\n"; else strong = tr("Using Neumann boundary conditions")+"\n"; AddString(strong); } if(m_pPlane) { QString len, str; GetLengthUnit(len, MainFrame::s_LengthUnit); if(qAbs(m_pPlane->WingLE(0).z-m_pPlane->WingLE(2).z)<.0001) { str = QString("%1 ").arg(m_pPlane->WingLE(0).z*MainFrame::s_mtoUnit, 7, 'g', 3); strong = tr("Warning: The wing and elevator lie in the same plane z=")+str+len+"\n"; AddString(strong); strong = tr("It is recommended to slightly offset the wing or the elevator to avoid numerical instabilities")+"\n\n"; AddString(strong); } } if(m_pWPolar->m_WPolarType==FIXEDSPEEDPOLAR) strong = tr("Type 1 - Fixed speed polar"); else if(m_pWPolar->m_WPolarType==FIXEDLIFTPOLAR) strong = tr("Type 2 - Fixed lift polar"); else if(m_pWPolar->m_WPolarType==FIXEDAOAPOLAR) strong = tr("Type 4 - Fixed angle of attack polar"); else if(m_pWPolar->m_WPolarType==STABILITYPOLAR) strong = tr("Type 7 - Stability polar"); AddString(strong); m_bCancel = false; m_SymSize = 0; int PlusSize=0; for(int p=0; p=0) PlusSize++; } QTimer *pTimer = new QTimer; connect(pTimer, SIGNAL(timeout()), this, SLOT(OnProgress())); pTimer->setInterval(100); pTimer->start(); qApp->processEvents(); if(m_pWPolar->m_WPolarTypem_bTiltedGeom) UnitLoop(); else AlphaLoop(); } else if(m_pWPolar->m_WPolarType==FIXEDAOAPOLAR) { QInfLoop(); } else if(m_pWPolar->m_WPolarType==STABILITYPOLAR) { m_Ib[0][0] = m_pWPolar->m_CoGIxx; m_Ib[1][1] = m_pWPolar->m_CoGIyy; m_Ib[2][2] = m_pWPolar->m_CoGIzz; m_Ib[0][2] = m_Ib[2][0] = m_pWPolar->m_CoGIxz; m_Ib[1][0] = m_Ib[1][2] = m_Ib[0][1] = m_Ib[2][1] = 0.0; ControlLoop(); } if (!m_bCancel && !m_bWarning) strong = "\n"+tr("Panel Analysis completed successfully")+"\n"; else if (m_bWarning) strong = "\n"+tr("Panel Analysis completed ... Errors encountered")+"\n"; AddString(strong); pTimer->stop(); if(m_pWPolar && (m_pWPolar->m_WPolarType==STABILITYPOLAR || m_pWPolar->m_bTiltedGeom || m_pWPolar->m_bWakeRollUp)) { //restore the panels and nodes; memcpy(m_pPanel, m_pMemPanel, m_MatSize * sizeof(Panel)); memcpy(m_pNode, m_pMemNode, m_nNodes * sizeof(CVector)); memcpy(m_pWakePanel, m_pRefWakePanel, m_WakeSize * sizeof(Panel)); memcpy(m_pWakeNode, m_pRefWakeNode, m_nWakeNodes * sizeof(CVector)); } m_bIsFinished = true; m_bCancel = false; m_pctrlCancel->setText(tr("Close")); } /** * Performs the summation of on-body forces to calculate the total lift and drag forces * @param Cp a pointer to the array of previously calculated Cp coefficients * @param Alpha the aoa for which this calculation is performed * @param Lift the resulting lift force * @param Drag the resulting drag force */ void PanelAnalysisDlg::SumPanelForces(double *Cp, double Alpha, double &Lift, double &Drag) { int p; CVector PanelForce; for(p=0; pm_bWakeRollUp) MaxWakeIter = 1; else MaxWakeIter = qMax(m_MaxWakeIter, 1); // int Size = m_MatSize; // if(m_b3DSymetric) Size = m_SymSize; //ESTIMATED UNIT TIMES FOR OPERATIONS //BuildInfluenceMatrix : 10 x MatSize/400 //CreateRHS : 10 //CreateWakeContribution : 1 //SolveUnitRHS : 90 x MatSize/400 //ComputeFarField : 10 x MatSize/400x nrhs //ComputeOnBodyCp : 1 x nrhs //RelaxWake : 20 x nrhs x MaxWakeIter * //ComputeAeroCoefs : 5 x nrhs double TotalTime = 10.0*(double)m_MatSize/400.*(double)m_nRHS + 10.*(double)m_nRHS + 90.*(double)m_MatSize/400.*(double)m_nRHS + 10*(double)m_MatSize/400*(double)m_nRHS + 1*(double)m_nRHS + 5*(double)m_nRHS ; // if(m_pWPolar->m_bWakeRollUp) TotalTime += 20.0 * (double)nrhs * (double)MaxWakeIter; m_pctrlProgress->setMinimum(0); m_pctrlProgress->setMaximum((int)TotalTime); m_Progress = 0.0; qApp->processEvents(); str = QString(tr(" Solving the problem... ")+"\n"); AddString("\n"+str); for (n=0; nRotateGeomY(m_OpAlpha, O); BuildInfluenceMatrix(); if (m_bCancel) return true; // The calculation will be performed at AOA=0.0 because the geometry is tilted... // ... but the operating angle is different : CreateUnitRHS(); if (m_bCancel) return true; CreateSourceStrength(0.0, m_AlphaDelta, 1); if (m_bCancel) return true; for (nWakeIter = 0; nWakeIterm_bWakeRollUp) { str = QString(tr(" Wake iteration %1")+"\n").arg(nWakeIter+1,3); AddString(str); } if (m_bCancel) return true; //todo : check... may not be quite correct if(!m_pWPolar->m_bThinSurfaces) { //compute wake contribution CreateWakeContribution(); //add wake contribution to matrix and RHS for(int p=0; p0 && m_pWPolar->m_bWakeRollUp) RelaxWake(); } ComputeAeroCoefs(0.0, m_AlphaDelta, 1); } return true; } /** * Writes a string message to the log file * @param strong the string message. */ void PanelAnalysisDlg::WriteString(QString strong) { if(!m_pXFile) return; if(!m_pXFile->isOpen()) return; QTextStream ds(m_pXFile); ds << strong; } /** * Returns the perturbation velocity created at a point C by a horseshoe or quad vortex with unit circulation located on a panel pPanel * @param pPanel a pointer to the Panel where the vortex is located * @param C the point where the perrturbation is evaluated * @param V a reference to the perturbation velocity vector * @param bAll true if the influence of the bound vector should be included */ void PanelAnalysisDlg::VLMGetVortexInfluence(Panel *pPanel, CVector const &C, CVector &V, bool bAll) { // calculates the the panel p's vortex influence at point C // V is the resulting velocity static int lw, pw, p; static CVector AA, BB, AA1, BB1, AAG, BBG, VT; p = pPanel->m_iElement; V.x = V.y = V.z = 0.0; if(m_pWPolar->m_bVLM1) { //just get the horseshoe vortex's influence VLMCmn(pPanel->VA, pPanel->VB, C, V, bAll); } else { // we have quad vortices // so we follow Katz and Plotkin's lead if(!pPanel->m_bIsTrailing) { if(bAll) { VLMQmn(pPanel->VA, pPanel->VB, m_pPanel[p-1].VA, m_pPanel[p-1].VB, C, V); } } else { // then panel p is trailing and shedding a wake if(!m_bWakeRollUp) { // since Panel p+1 does not exist... // we define the points AA=A+1 and BB=B+1 AA1.x = m_pNode[pPanel->m_iTA].x + (m_pNode[pPanel->m_iTA].x-pPanel->VA.x)/3.0; AA1.y = m_pNode[pPanel->m_iTA].y; AA1.z = m_pNode[pPanel->m_iTA].z; BB1.x = m_pNode[pPanel->m_iTB].x + (m_pNode[pPanel->m_iTB].x-pPanel->VB.x)/3.0; BB1.y = m_pNode[pPanel->m_iTB].y; BB1.z = m_pNode[pPanel->m_iTB].z; // first we get the quad vortex's influence if (bAll) { VLMQmn(pPanel->VA, pPanel->VB, AA1, BB1, C, V); } //we just add a trailing horseshoe vortex's influence to simulate the wake VLMCmn(AA1,BB1,C,VT,bAll); V.x += VT.x; V.y += VT.y; V.z += VT.z; } else { // if there is a wake roll-up required pw = pPanel->m_iWake; // first close the wing's last vortex ring at T.E. if (bAll) { VLMQmn(pPanel->VA, pPanel->VB, m_pWakePanel[pw].VA, m_pWakePanel[pw].VB, C, V); } //each wake panel has the same vortex strength than the T.E. panel //so we just cumulate their unit influences if(bAll) { for (lw=0; lwm_NXWakePanels-1; lw++) { VLMQmn(m_pWakePanel[pw ].VA, m_pWakePanel[pw ].VB, m_pWakePanel[pw+1].VA, m_pWakePanel[pw+1].VB, C, VT); V += VT; pw++; } } // // For the very last wake panel downstream, just add a horseshoe vortex influence // // TODO : check influence on results // // VLMCmn(m_pWakePanel[pw].A, m_pWakePanel[pw].B,C,VT,bAll); // V += VT; // // simple really ! // } } } } /** * Performs a stability analysis for each requested position of the control surfaces. * */ bool PanelAnalysisDlg::ControlLoop() { // // Loop for each control value // Update the geometry, design variables // Build the influence matrix // Perform LU matrix decomposition // Solve a first time the VLM problem to find the trimmed conditions: // - solve for unit RHS // - iterate to find equilibrium aoa such that Cm=0 in steady level flight or banked turn // Build the rotation matrix from body axes to stability axes // Build the RHS for unit velocity fields in stability axes // Build the RHS for unit control rotations (Normals only) in stability axes // Solve the VLM problem for RHS in stability axes // Compute stability derivatives // Compute control derivatives // Compute inertia in stability axis // Longitudinal stability : // - Build longitudinal state matrix // - Solve for eigenvalues and eigenvectors // Lateral stability // - Build lateral state matrix // - Solve for eigenvalues and eigenvectors // Compute aero coeffs for alpha_eq // Store OpPoint and polar data // end loop // int i; QString str, strlen, strmass, strInertia, outString; QMiarex *pMiarex = (QMiarex*)s_pMiarex; GetLengthUnit(strlen, MainFrame::s_LengthUnit); GetWeightUnit(strmass, MainFrame::s_WeightUnit); strInertia = strmass+"."+strlen+QString::fromUtf8("²"); str = QString(" Mass=%1 ").arg(m_pWPolar->m_Mass*MainFrame::s_kgtoUnit, 12,'f',3)+strmass+"\n"; AddString(str); str = "\n ___Center of Gravity Position - Body axis____\n"; AddString(str); str = QString(" CoG_x=%1 ").arg(m_pWPolar->m_CoG.x * MainFrame::s_mtoUnit, 12,'f',4)+strlen+"\n"; AddString(str); str = QString(" CoG_y=%1 ").arg(m_pWPolar->m_CoG.y * MainFrame::s_mtoUnit, 12,'f',4)+strlen+"\n"; AddString(str); str = QString(" CoG_z=%1 ").arg(m_pWPolar->m_CoG.z * MainFrame::s_mtoUnit, 12,'f',4)+strlen+"\n"; AddString(str); str = "\n ___Inertia - Body Axis - CoG Origin____\n"; AddString(str); str = QString(" Ibxx=%1 ").arg(m_Ib[0][0]*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit*MainFrame::s_kgtoUnit, 12,'g',4); AddString(str+strInertia+"\n"); str = QString(" Ibyy=%1 ").arg(m_Ib[1][1]*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit*MainFrame::s_kgtoUnit, 12,'g',4); AddString(str+strInertia+"\n"); str = QString(" Ibzz=%1 ").arg(m_Ib[2][2]*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit*MainFrame::s_kgtoUnit, 12,'g',4); AddString(str+strInertia+"\n"); str = QString(" Ibxz=%1 ").arg(m_Ib[0][2]*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit*MainFrame::s_kgtoUnit, 12,'g',4); AddString(str+strInertia+"\n\n"); if(m_ControlMaxsetMinimum(0); m_pctrlProgress->setMaximum((int)TotalTime); m_Progress = 0.0; qApp->processEvents(); m_bTrace = true; str = QString(" Solving the problem... \n\n"); AddString("\n"+str); for (i=0; iSetControlPositions(m_pPanel, m_pNode, m_Ctrl, m_NCtrls, outString, true); AddString(outString); if(m_bCancel) break; // next find the balanced and trimmed conditions if(!ComputeTrimmedConditions()) { if(m_bCancel) break; //no zero moment alpha str = QString(" Unsuccessfull attempt to trim the model for control position=%1 - skipping.\n\n\n").arg(m_Ctrl,5,'f',2); AddString(str); m_bWarning = true; } else { m_3DQInf[i] = u0; m_QInf = u0; if (m_bCancel) return true; //Build the rotation matrix from body axes to stability axes BuildRotationMatrix(); if(m_bCancel) break; // Compute inertia in stability axes ComputeStabilityInertia(); if(m_bCancel) break; str = "\n ___Inertia - Stability Axis - CoG Origin____\n"; AddString(str); str = QString(" Isxx=%1 ").arg(m_Is[0][0]*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit*MainFrame::s_kgtoUnit, 12,'g',4); AddString(str+strInertia+"\n"); str = QString(" Isyy=%1 ").arg(m_Is[1][1]*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit*MainFrame::s_kgtoUnit, 12,'g',4); AddString(str+strInertia+"\n"); str = QString(" Iszz=%1 ").arg(m_Is[2][2]*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit*MainFrame::s_kgtoUnit, 12,'g',4); AddString(str+strInertia+"\n"); str = QString(" Isxz=%1 ").arg(m_Is[0][2]*MainFrame::s_mtoUnit*MainFrame::s_mtoUnit*MainFrame::s_kgtoUnit, 12,'g',4); AddString(str+strInertia+"\n\n"); // Compute stability and control derivatives in stability axes // viscous or not viscous ? ComputeStabilityDerivatives(); if(m_bCancel) break; ComputeControlDerivatives(); //single derivative, wrt the polar's control variable if(m_bCancel) break; ComputeNDStabDerivatives(); // Construct the state matrices - longitudinal and lateral BuildStateMatrices(); // Solve for eigenvalues if(!SolveEigenvalues()) { str = QString(" Unsuccessfull attempt to compute eigenvalues for Control=%1 - skipping.\n\n\n").arg(m_Ctrl,10,'f',3); AddString(str); m_bWarning = true; } else { // Compute aero coefficients for trimmed conditions ComputeFarField(m_QInf, m_AlphaEq, 0.0, 1); if (m_bCancel) return true; ComputeOnBodyCp(m_AlphaEq, 0.0, 1); if (m_bCancel) return true; str = QString(tr(" Computing Plane for alpha=%1")).arg(m_AlphaEq,7,'f',2); str += QString::fromUtf8("°\n"); AddString(str); ComputePlane(m_AlphaEq, u0, 0); if (m_bCancel) return true; } str = QString("\n ______Finished operating point calculation for control position %1________\n\n\n\n\n").arg(m_Ctrl, 5,'f',2); AddString(str); } if(m_bCancel) break; } return true; } /** * Extracts the eigenvalues and eigenvectors from the state matrices. * Stores the results in the memeber variables if successful. * @return true if the extraction was successful. */ bool PanelAnalysisDlg::SolveEigenvalues() { // Finds the eigenvalues and eigenvectors of the state matrices ALong and ALat static double pLong[5], pLat[5];//the coefficients of the characteristic polynomial static int i; QString str; CharacteristicPol(m_ALong, pLong); if(!LinBairstow(pLong, m_rLong, 4)) { AddString("\n Error extracting longitudinal eigenvalues\n"); return false; } //sort them ComplexSort(m_rLong, 4); for(i=0; i<4; i++) { if(!Eigenvector(m_ALong, m_rLong[i], m_vLong+i*4)) { str = QString("Error extracting longitudinal eigenvector for mode %1\n").arg(i); return false; } } str = "\n\n ___Longitudinal modes____\n\n"; AddString(str); str = QString(" Eigenvalue: %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_rLong[0].real(),9, 'g', 4).arg(m_rLong[0].imag(),9, 'g', 4) .arg(m_rLong[1].real(),9, 'g', 4).arg(m_rLong[1].imag(),9, 'g', 4) .arg(m_rLong[2].real(),9, 'g', 4).arg(m_rLong[2].imag(),9, 'g', 4) .arg(m_rLong[3].real(),9, 'g', 4).arg(m_rLong[3].imag(),9, 'g', 4); AddString(str); str=(" _____________________________________________________________________________________________________\n"); AddString(str); i=0; str = QString(" Eigenvector: %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_vLong[i].real(), 9, 'g', 4).arg(m_vLong[i].imag(), 9, 'g', 4) .arg(m_vLong[i+4].real(), 9, 'g', 4).arg(m_vLong[i+4].imag(), 9, 'g', 4) .arg(m_vLong[i+8].real(), 9, 'g', 4).arg(m_vLong[i+8].imag(), 9, 'g', 4) .arg(m_vLong[i+12].real(), 9, 'g', 4).arg(m_vLong[i+12].imag(), 9, 'g', 4); AddString(str); for (i=1; i<4; i++) { str = QString(" %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_vLong[i].real(), 9, 'g', 4).arg(m_vLong[i].imag(), 9, 'g', 4) .arg(m_vLong[i+4].real(), 9, 'g', 4).arg(m_vLong[i+4].imag(), 9, 'g', 4) .arg(m_vLong[i+8].real(), 9, 'g', 4).arg(m_vLong[i+8].imag(), 9, 'g', 4) .arg(m_vLong[i+12].real(), 9, 'g', 4).arg(m_vLong[i+12].imag(), 9, 'g', 4); AddString(str); } str = "\n"; AddString(str); CharacteristicPol(m_ALat, pLat); if(!LinBairstow(pLat, m_rLat, 4)) { AddString("\n Error extracting lateral eigenvalues\n"); return false; } //sort them ComplexSort(m_rLat, 4); for(i=0; i<4; i++) { if(!Eigenvector(m_ALat, m_rLat[i], m_vLat+i*4)) { str = QString("Error extracting lateral eigenvector for mode %1\n").arg(i); return false; } } str = "\n\n ___Lateral modes____\n\n"; AddString(str); str = QString(" Eigenvalue: %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_rLat[0].real(),9, 'g', 4).arg(m_rLat[0].imag(),9, 'g', 4) .arg(m_rLat[1].real(),9, 'g', 4).arg(m_rLat[1].imag(),9, 'g', 4) .arg(m_rLat[2].real(),9, 'g', 4).arg(m_rLat[2].imag(),9, 'g', 4) .arg(m_rLat[3].real(),9, 'g', 4).arg(m_rLat[3].imag(),9, 'g', 4); AddString(str); str=(" _____________________________________________________________________________________________________\n"); AddString(str); i=0; str = QString(" Eigenvector: %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_vLat[i].real(), 9, 'g', 4).arg(m_vLat[i].imag(), 9, 'g', 4) .arg(m_vLat[i+4].real(), 9, 'g', 4).arg(m_vLat[i+4].imag(), 9, 'g', 4) .arg(m_vLat[i+8].real(), 9, 'g', 4).arg(m_vLat[i+8].imag(), 9, 'g', 4) .arg(m_vLat[i+12].real(), 9, 'g', 4).arg(m_vLat[i+12].imag(), 9, 'g', 4); AddString(str); for (i=1; i<4; i++) { str = QString(" %1+%2i | %3+%4i | %5+%6i | %7+%8i\n") .arg(m_vLat[i].real(), 9, 'g', 4).arg(m_vLat[i].imag(), 9, 'g', 4) .arg(m_vLat[i+4].real(), 9, 'g', 4).arg(m_vLat[i+4].imag(), 9, 'g', 4) .arg(m_vLat[i+8].real(), 9, 'g', 4).arg(m_vLat[i+8].imag(), 9, 'g', 4) .arg(m_vLat[i+12].real(), 9, 'g', 4).arg(m_vLat[i+12].imag(), 9, 'g', 4); AddString(str); } str = "\n"; AddString(str); return true; } /** * Computes the non-dimensional stability derivatives. * Outputs the results to the log file */ void PanelAnalysisDlg::ComputeNDStabDerivatives() { QString str; double b, S, mac, q, theta0, Cw0; double mass = m_pWPolar->m_Mass; double rho = m_pWPolar->m_Density; q = 1./2. * m_pWPolar->m_Density * u0 * u0; b = m_pWPolar->m_WSpan; S = m_pWPolar->m_WArea; mac = m_pWing->m_MAChord; theta0 = 0.0;//steady level flight only ? Cw0 = mass * 9.81/q/S; //E&R p.127 // Cx0 = Cw0 * sin(theta0); //E&R p.119 // Cz0 = -Cw0 * cos(theta0); //E&R p.118 //E&R p. 118, table 4.4 CXu = (Xu - rho * u0*S*Cw0*sin(theta0))/(0.5*rho*u0*S); CZu = (Zu + rho * u0*S*Cw0*cos(theta0))/(0.5*rho*u0*S); Cmu = Mu /(0.5*rho*u0*mac*S); CXa = Xw /(0.5*rho*u0*S); CZa = Zw /(0.5*rho*u0*S); Cma = Mw /(0.5*rho*u0*mac*S); CXq = Xq /(.25*rho*u0*mac*S); CZq = Zq /(.25*rho*u0*mac*S); Cmq = Mq /(.25*rho*u0*mac*mac*S); XNP = m_pWPolar->m_CoG.x + Cma/CZa * mac; //E&R (eq. 2.3.5 p.29) CYb = Yv* u0 /(q*S); CYp = Yp* 2.*u0 /(q*S*b); CYr = Yr* 2.*u0 /(q*S*b); Clb = Lv* u0 /(q*S*b); Clp = Lp*(2.*u0/b) /(q*S*b); Clr = Lr*(2.*u0/b) /(q*S*b); Cnb = Nv* u0 /(q*S*b); Cnp = Np*(2.*u0/b) /(q*S*b); Cnr = Nr*(2.*u0/b) /(q*S*b); CXe = Xde/(q*S); CYe = Yde/(q*S); CZe = Zde/(q*S); Cle = Lde/(q*S*b); Cme = Mde/(q*S*mac); Cne = Nde/(q*S*b); // no OpPoint, we output the data to the log file str = " Longitudinal derivatives\n"; AddString(str); str = QString(" Xu=%1 Cxu=%2\n").arg(Xu,12,'g',5).arg(CXu, 12, 'g', 5); AddString(str); str = QString(" Xw=%1 Cxa=%2\n").arg(Xw,12,'g',5).arg(CXa, 12, 'g', 5); AddString(str); str = QString(" Zu=%1 Czu=%2\n").arg(Zu,12,'g',5).arg(CZu, 12, 'g', 5); AddString(str); str = QString(" Zw=%1 CLa=%2\n").arg(Zw,12,'g',5).arg(-CZa,12, 'g', 5); AddString(str); str = QString(" Zq=%1 CLq=%2\n").arg(Zq,12,'g',5).arg(-CZq,12, 'g', 5); AddString(str); str = QString(" Mu=%1 Cmu=%2\n").arg(Mu,12,'g',5).arg(Cmu, 12, 'g', 5); AddString(str); str = QString(" Mw=%1 Cma=%2\n").arg(Mw,12,'g',5).arg(Cma, 12, 'g', 5); AddString(str); str = QString(" Mq=%1 Cmq=%2\n").arg(Mq,12,'g',5).arg(Cmq, 12, 'g', 5); AddString(str); QString strLength; GetLengthUnit(strLength, MainFrame::s_LengthUnit); str = QString(" Neutral Point position=%1").arg(XNP*MainFrame::s_mtoUnit, 10,'f',5); str += strLength; str +="\n\n"; AddString(str); str = "\n Lateral derivatives\n"; AddString(str); str = QString(" Yv=%1 CYb=%2\n").arg(Yv,12,'g',5).arg(CYb,12,'g',5); AddString(str); str = QString(" Yp=%1 CYp=%2\n").arg(Yp,12,'g',5).arg(CYp,12,'g',5); AddString(str); str = QString(" Yr=%1 CYr=%2\n").arg(Yr,12,'g',5).arg(CYr,12,'g',5); AddString(str); str = QString(" Lv=%1 Clb=%2\n").arg(Lv,12,'g',5).arg(Clb,12,'g',5); AddString(str); str = QString(" Lp=%1 Clp=%2\n").arg(Lp,12,'g',5).arg(Clp,12,'g',5); AddString(str); str = QString(" Lr=%1 Clr=%2\n").arg(Lr,12,'g',5).arg(Clr,12,'g',5); AddString(str); str = QString(" Nv=%1 Cnb=%2\n").arg(Nv,12,'g',5).arg(Cnb,12,'g',5); AddString(str); str = QString(" Np=%1 Cnp=%2\n").arg(Np,12,'g',5).arg(Cnp,12,'g',5); AddString(str); str = QString(" Nr=%1 Cnr=%2\n\n").arg(Nr,12,'g',5).arg(Cnr,12,'g',5); AddString(str); //output control derivatives str = QString(" Control derivatives \n"); AddString(str); str = QString(" Xde=%1 CXde=%2\n").arg(Xde,12,'g',5).arg(Xde/(q*S),12,'g',5); AddString(str); str = QString(" Yde=%1 CYde=%2\n").arg(Yde,12,'g',5).arg(Yde/(q*S),12,'g',5); AddString(str); str = QString(" Zde=%1 CZde=%2\n").arg(Zde,12,'g',5).arg(Zde/(q*S),12,'g',5); AddString(str); str = QString(" Lde=%1 CLde=%2\n").arg(Lde,12,'g',5).arg(Lde/(q*S*b),12,'g',5); AddString(str); str = QString(" Mde=%1 CMde=%2\n").arg(Mde,12,'g',5).arg(Mde/(q*S*mac),12,'g',5); AddString(str); str = QString(" Nde=%1 CNde=%2\n").arg(Nde,12,'g',5).arg(Nde/(q*S*b),12,'g',5); AddString(str+"\n"); str ="\n"; AddString(str); } /** * Calculates the forces using a farfield method. * Calculates the moments by a near field method, i.e. direct summation on the panels. * Downwash is evaluated at a distance 100 times the span downstream (i.e. infinite) * @param Mu a pointer to the array of doublet strengths or vortex circulations * @param Sigma a pointer to the array of source strengths * @param *VInf a pointer to the array of the velocity vectors on the panels * @param Force the resulting force vector * @param Moment the resulting moment vector * @param bTilted true if the calculation is performed on a tilted geometry */ void PanelAnalysisDlg::Forces(double *Mu, double *Sigma, double alpha, double *VInf, CVector &Force, CVector &Moment, bool bTilted) { if(!m_pPanel||!m_pWPolar) return; static bool bOutRe, bError, bOut, bOutCl; static int j, k, l, p, pp, m, nw, iTA, iTB; static double cosa, sina, Re, PCd, Cl, Cp, tau, StripArea, ViscousDrag; static double QInf, QInfStrip, qdyn, GammaStrip; static CVector C, PtC4, LeverArm, WindDirection, WindNormal, PanelLeverArm, Wg; static CVector Velocity, StripForce, ViscousMoment, dF, PanelForce, PanelForcep1; bOut = bOutCl = bError = false; int coef = 2; if (m_pWPolar->m_bThinSurfaces) coef = 1; cosa = cos(alpha*PI/180.0); sina = sin(alpha*PI/180.0); // Define the wind axis WindNormal.Set( -sina, 0.0, cosa); WindDirection.Set( cosa, 0.0, sina); p=m=0; Force.Set( 0.0, 0.0, 0.0); Moment.Set(0.0, 0.0, 0.0); ViscousDrag = 0.0; ViscousMoment.Set(0.0,0.0,0.0); for(j=0; jm_bIsTipLeft && !m_pWPolar->m_bThinSurfaces) p+=m_ppSurface[j]->m_NXPanels;//tip patch panels for(k=0; km_NYPanels; k++) { //Get the strip area pp=p; StripArea = 0.0; for (l=0; lm_NXPanels; l++) { StripArea += m_pPanel[pp].Area; pp++; } //Get the strip's lifting force if(m_pPanel[p].m_Pos!=MIDSURFACE) { StripArea /=2.0; //FF force nw = m_pPanel[p].m_iWake; iTA = m_pWakePanel[nw].m_iTA; iTB = m_pWakePanel[nw].m_iTB; C = (m_pWakeNode[iTA] + m_pWakeNode[iTB])/2.0; GetSpeedVector(C, Mu, Sigma, Wg, false); Wg.x += VInf[p ]; Wg.y += VInf[p+m_MatSize ]; Wg.z += VInf[p+2*m_MatSize]; GammaStrip = (-Mu[p+coef*m_ppSurface[j]->m_NXPanels-1] + Mu[p]) *4.0*PI; StripForce = m_pPanel[p].Vortex * Wg; StripForce *= GammaStrip; //Newtons/rho Force += StripForce; Velocity.x = *(VInf +p); Velocity.y = *(VInf + m_MatSize +p); Velocity.z = *(VInf + 2*m_MatSize +p); QInfStrip = Velocity.VAbs(); //used for viscous drag at the next step p+=m_ppSurface[j]->m_NXPanels*coef; } else { //iPos=0, VLM type panel StripForce.Set(0.0,0.0,0.0); for(l=0; lm_NXPanels; l++) { Velocity.x = *(VInf +p); Velocity.y = *(VInf + m_MatSize +p); Velocity.z = *(VInf + 2*m_MatSize +p); QInfStrip = Velocity.VAbs(); //FF force if(m_pWPolar->m_bVLM1 || m_pPanel[p].m_bIsTrailing) { C = m_pPanel[p].CtrlPt; C.x = m_pWing->m_PlanformSpan * 100.0; GetSpeedVector(C, Mu, Sigma, Wg, false); Wg += Velocity; //total speed vector //induced force dF = Wg * m_pPanel[p].Vortex; dF *= Mu[p]; // N/rho Force += dF; // N/rho StripForce += dF; } //On-Body moment PanelForce = Velocity * m_pPanel[p].Vortex; PanelForce *= Mu[p]; //Newtons/rho if(!m_pWPolar->m_bVLM1 && !m_pPanel[p].m_bIsLeading) { PanelForcep1 = Velocity * m_pPanel[p].Vortex; PanelForcep1 *= Mu[p+1]; //Newtons/rho PanelForce -= PanelForcep1; } PanelLeverArm = m_pPanel[p].VortexPos - m_pWPolar->m_CoG; Moment += PanelLeverArm * PanelForce; // N.m/rho p++; } } if(m_pWPolar->m_bViscous) { //add the viscous drag component to force and moment qdyn = 0.5 * m_pWPolar->m_Density * QInfStrip * QInfStrip; m_ppSurface[j]->GetC4(k, PtC4, tau); Re = m_ppSurface[j]->GetChord(tau) * QInfStrip /m_pWPolar->m_Viscosity; Cl = StripForce.dot(WindNormal)*m_pWPolar->m_Density/qdyn/StripArea; PCd = GetVar(2, m_ppSurface[j]->m_pFoilA, m_ppSurface[j]->m_pFoilB, Re, Cl, tau, bOutRe, bError); PCd *= StripArea * 1/2*QInfStrip*QInfStrip; // Newtons/rho bOut = bOut || bOutRe || bError; ViscousDrag += PCd ; // Newtons/rho LeverArm = PtC4 - m_pWPolar->m_CoG; ViscousMoment.x += PCd * (WindDirection.y*LeverArm.z - WindDirection.z*LeverArm.y); // N.m/rho ViscousMoment.y += PCd * (WindDirection.z*LeverArm.x - WindDirection.x*LeverArm.z); ViscousMoment.z += PCd * (WindDirection.x*LeverArm.y - WindDirection.y*LeverArm.x); } m++; } } if(!m_pWPolar->m_bThinSurfaces) { //On-Body moment // same as before, except that we take into account tip patches CVector VLocal; Moment.Set(0.0,0.0,0.0); for(p=0; pm_CoG; Moment += PanelLeverArm * PanelForce; // N.m/rho } } if(m_pWPolar->m_bThinSurfaces) Force -= WindDirection*Force.dot(WindDirection)/2.0; if(m_pWPolar->m_bViscous) { Force += WindDirection * ViscousDrag; Moment += ViscousMoment; } Force *= m_pWPolar->m_Density; // N Moment *= m_pWPolar->m_Density; // N.m } #define CM_ITER_MAX 50 /** * Finds the zero-pitching-moment aoa such that Cm=0. * Proceeds by iteration between -PI/4 and PI/4 * @return true if an equlibrium angle was found false otherwise. */ bool PanelAnalysisDlg::GetZeroMomentAngle() { static int iter; static double a, a0, a1, Cm, Cm0, Cm1, tmp; static double eps = 1.e-7; iter = 0; a0 = -PI/4.0; a1 = PI/4.0; a = 0.0; Cm0 = ComputeCm(a0*180.0/PI); Cm1 = ComputeCm(a1*180.0/PI); Cm = 1.0; //are there two initial values of opposite signs ? while(Cm0*Cm1>0.0 && iter <=20) { a0 *=0.9; a1 *=0.9; Cm0 = ComputeCm(a0*180.0/PI); Cm1 = ComputeCm(a1*180.0/PI); iter++; qApp->processEvents(); if(m_bCancel) break; } if(iter>=100 || m_bCancel) return false; iter = 0; //Cm0 and Cm1 are of opposite sign if(Cm0>Cm1) { tmp = Cm1; Cm1 = Cm0; Cm0 = tmp; tmp = a0; a0 = a1; a1 = tmp; } while (qAbs(Cm)>eps && iter<=CM_ITER_MAX) { a = a0 - (a1-a0) * Cm0/(Cm1-Cm0); Cm = ComputeCm(a*180.0/PI); if(Cm>0.0) { a1 = a; Cm1 = Cm; } else { a0 = a; Cm0 = Cm; } iter++; qApp->processEvents(); if(m_bCancel) break; } if(iter>=CM_ITER_MAX || m_bCancel) return false; m_AlphaEq = a*180.0/PI; Cm = ComputeCm(m_AlphaEq);// for information only, should be zero return true; } /** * Creates the longitudinal and lateral state matrices * from the derivatives and inertias calculated previously * Creates the control state matrix from the control derivatives */ void PanelAnalysisDlg::BuildStateMatrices() { static int i; static double Ipxx, Ipzz, Ipzx; static double Ixx,Iyy,Izz, Izx; QString strange; double Mass = m_pWPolar->m_Mass; //use inertia measured in stability axis, CoG origin Ixx = m_Is[0][0]; Iyy = m_Is[1][1]; Izz = m_Is[2][2]; Izx = m_Is[0][2]; //____________________Longitudinal stability_____________ m_ALong[0][0] = Xu/Mass; m_ALong[0][1] = Xw/Mass; m_ALong[0][2] = 0.0; m_ALong[0][3] = -9.81*cos(Theta0*PI/180.0); m_ALong[1][0] = Zu /(Mass-Zwp); m_ALong[1][1] = Zw /(Mass-Zwp); m_ALong[1][2] = (Zq+Mass*u0) /(Mass-Zwp); m_ALong[1][3] = -9.81*Mass*sin(Theta0*PI/180.0)/(Mass-Zwp); m_ALong[2][0] = (Mu + Mwp*Zu/(Mass-Zwp)) /Iyy; m_ALong[2][1] = (Mw + Mwp*Zw/(Mass-Zwp)) /Iyy; m_ALong[2][2] = (Mq + Mwp*(Zq+Mass*u0)/(Mass-Zwp)) /Iyy; m_ALong[2][3] = (Mwp*(-Mass*9.81*sin(Theta0))/(Mass-Zwp))/Iyy; m_ALong[3][0] = 0.0; m_ALong[3][1] = 0.0; m_ALong[3][2] = 1.0; m_ALong[3][3] = 0.0; strange = " _____State matrices__________\n"; AddString(strange); strange = " Longitudinal state matrix\n"; AddString(strange); for (i=0; i<4; i++) { strange = QString(" %1 %2 %3 %4\n") .arg(m_ALong[i][0], 14, 'g', 6) .arg(m_ALong[i][1], 14, 'g', 6) .arg(m_ALong[i][2], 14, 'g', 6) .arg(m_ALong[i][3], 14, 'g', 6); AddString(strange); } //____________________Lateral stability_____________ Ipxx = (Ixx * Izz - Izx*Izx)/Izz; Ipzz = (Ixx * Izz - Izx*Izx)/Ixx; Ipzx = Izx/(Ixx * Izz - Izx*Izx); m_ALat[0][0] = Yv/Mass; m_ALat[0][1] = Yp/Mass; m_ALat[0][2] = Yr/Mass - u0; m_ALat[0][3] = 9.81 * cos(Theta0*PI/180.0); m_ALat[1][0] = Lv/Ipxx+Ipzx*Nv; m_ALat[1][1] = Lp/Ipxx+Ipzx*Np; m_ALat[1][2] = Lr/Ipxx+Ipzx*Nr; m_ALat[1][3] = 0.0; m_ALat[2][0] = Lv*Ipzx+ Nv/Ipzz; m_ALat[2][1] = Lp*Ipzx+ Np/Ipzz; m_ALat[2][2] = Lr*Ipzx+ Nr/Ipzz; m_ALat[2][3] = 0.0; m_ALat[3][0] = 0.0; m_ALat[3][1] = 1.0; m_ALat[3][2] = tan(Theta0*PI/180.0); m_ALat[3][3] = 0.0; strange = " Lateral state matrix\n"; AddString(strange); for (i=0; i<4; i++) { strange = QString(" %1 %2 %3 %4\n") .arg(m_ALat[i][0], 14, 'g', 6) .arg(m_ALat[i][1], 14, 'g', 6) .arg(m_ALat[i][2], 14, 'g', 6) .arg(m_ALat[i][3], 14, 'g', 6); AddString(strange); } strange ="\n"; AddString(strange); //build the control matrix // for(i=0; im_nControls; i++) { // per radian m_BLong[0] = Xde/Mass; m_BLong[1] = Zde/Mass; m_BLong[2] = Mde/Iyy; m_BLong[3] = 0.0; m_BLat[0] = Yde/Mass; m_BLat[1] = Lde/Ipxx+Nde*Ipzx; m_BLat[2] = Lde*Ipzx+Nde/Ipzz; m_BLat[3] = 0.0; } strange = " _____Control Matrices__________\n"; AddString(strange); strange = " Longitudinal control matrix\n"; AddString(strange); strange = QString(" %1\n %2\n %3\n %4\n\n") .arg(m_BLong[0], 13, 'g', 7) .arg(m_BLong[1], 13, 'g', 7) .arg(m_BLong[2], 13, 'g', 7) .arg(m_BLong[3], 13, 'g', 7); AddString(strange); strange = " Lateral control matrix\n"; AddString(strange); strange = QString(" %1\n %2\n %3\n %4\n\n") .arg(m_BLat[0], 13, 'g', 7) .arg(m_BLat[1], 13, 'g', 7) .arg(m_BLat[2], 13, 'g', 7) .arg(m_BLat[3], 13, 'g', 7); AddString(strange); } /** * This methods builds the rotation matrix from geometrical axis to stability axis, * i.e. if V is a vector defined in the body axis, its coordinates in stability axis are v = R.V * In XFLR5, the x-body-axis is pointing backward, and the convention * for stability axes is with the x-axis pointing forward. * The rotation matrix is set in accordance. */ void PanelAnalysisDlg::BuildRotationMatrix() { m_R[0][0] = -cos(m_AlphaEq*PI/180.0); m_R[1][0] = 0.0; m_R[2][0] = sin(m_AlphaEq*PI/180.0); m_R[0][1] = 0.0; m_R[1][1] = 1.0; m_R[2][1] = 0.0; m_R[0][2] = -sin(m_AlphaEq*PI/180.0); m_R[1][2] = 0.0; m_R[2][2] = -cos(m_AlphaEq*PI/180.0); } /** * Computes the trimmed condition for a stability analysis * Method : * - For level flight, find the a.o.a. such that Cm=0 * - Reconstruct the right side circulations if the calculation was symmetric * - Sort results i.a.w. panel numbering * - Set trimmed parameters for level flight or other */ bool PanelAnalysisDlg::ComputeTrimmedConditions() { QString strong, strange; int p; static double Lift, phi, VerticalCl; static CVector VInf, Force, Moment, WindNormal; // find aoa such that Cm=0; //Build the unit RHS vectors along x and z in Body Axis CreateUnitRHS(); if (m_bCancel) return false; // build the influence matrix in Body Axis BuildInfluenceMatrix(); if (m_bCancel) return false; if(!m_pWPolar->m_bThinSurfaces) { //compute wake contribution CreateWakeContribution(); //add wake contribution to matrix and RHS for(int p=0; pprocessEvents(); if(m_bCancel) return false; //______________________________________________________________________________________ // Calculate the trimmed conditions for this control setting and calculated Alpha_eq /* phi = bank angle V = sqrt(2 m g / rho S CL cos(phi)) (airspeed) R = V^2 / g tan(phi) (turn radius, positive for right turn) W = V / R (turn rate, positive for right turn) p = 0 (roll rate, zero for steady turn) q = W sin(phi) (pitch rate, positive nose upward) r = W cos(phi) (yaw rate, positive for right turn) */ //so far we have a unit Vortex Strength // find the speeds which will create a lift equal to the weight AddString(" Calculating speed to balance the weight..."); WindNormal.Set(-sin(m_AlphaEq*PI/180.0), 0.0, cos(m_AlphaEq*PI/180.0)); VInf.Set( cos(m_AlphaEq*PI/180.0), 0.0, sin(m_AlphaEq*PI/180.0)); for(p=0; pm_bTiltedGeom); phi = m_pWPolar->m_BankAngle *PI/180.0; Lift = Force.dot(WindNormal); //N/rho ; bank effect not included VerticalCl = Lift*2.0/m_pWPolar->m_WArea * cos(phi)/m_pWPolar->m_Density; if(Lift<=0.0) { u0 = -100.0; strong = QString(" Found a negative lift for Alpha=%1.... skipping the angle...\n").arg(m_AlphaEq,0,'f',5); if(m_bTrace) AddString(strong); m_bPointOut = true; m_bWarning = true; return false; } else { u0 = sqrt( 2.0* 9.81 * m_pWPolar->m_Mass /m_pWPolar->m_Density/m_pWPolar->m_WArea / VerticalCl ); strong = QString("VInf = %2").arg(u0*MainFrame::s_mstoUnit,0,'f',5); GetSpeedUnit(strange, MainFrame::s_SpeedUnit); strong+= strange + "\n"; if(m_bTrace) AddString(strong); if(qAbs(m_pWPolar->m_BankAngle)>PRECISION) { m_radius = u0*u0/9.81/tan(phi); m_W = u0/m_radius; m_p = 0.0; m_q = m_W * sin(phi); m_r = m_W * cos(phi); strong = QString(" Phi =%1").arg(m_pWPolar->m_BankAngle,5,'f',2); strong += QString::fromUtf8("°"); if(m_bTrace) AddString(strong); strong = QString(" Turn radius =%1").arg(m_radius,5,'f',2); if(m_bTrace) AddString(strong); strong = QString(" Turn rate =%1").arg(m_W,5,'f',2); if(m_bTrace) AddString(strong); strong = QString(" Roll rate =%1").arg(m_p,5,'f',2); if(m_bTrace) AddString(strong); strong = QString(" Pitch rate =%1").arg(m_q,5,'f',2); if(m_bTrace) AddString(strong); strong = QString(" Yaw rate =%1").arg(m_r,5,'f',2); if(m_bTrace) AddString(strong); } } //______________________________________________________________________________________ // Scale circulations to speeds for(p=0; pm_bTiltedGeom); return true; } /** * Calculates the stability derivatives. * @todo implement automatic differentiation. Considerable task. The stability derivatives are estimated by forward difference at U=(U0,0,0). The reference condition has been saved during the calculation of the trimmed condition. */ void PanelAnalysisDlg::ComputeStabilityDerivatives() { static CVector V0, Force, Moment, CGM, is, js, ks, Vi, Vj, Vk, Ris, Rjs, Rks, WindDirection, WindNormal; static int p; static double alpha, sina, cosa, deltaspeed, deltarotation; QString strong; int Size= m_MatSize; if(m_b3DSymetric) Size = m_SymSize; strong = " Calculating the stability derivatives\n"; AddString(strong); deltaspeed = 0.01; // m/s for forward difference estimation deltarotation = 0.001; // rad/s for forward difference estimation // Define the stability axes cosa = cos(m_AlphaEq*PI/180); sina = sin(m_AlphaEq*PI/180); WindDirection.Set(cosa, 0.0, sina); WindNormal.Set(-sina, 0.0, cosa); is.Set(-cosa, 0.0, -sina); js.Set( 0.0, 1.0, 0.0); ks.Set( sina, 0.0, -cosa); V0 = is * (-u0); //is the steady state velocity vector, if no sideslip //______________________________________________________________________________ // RHS for unit speed vectors // The change in wind velocity is opposite to the change in plane velocity Vi = V0 - is * deltaspeed; //a positive increase in axial speed is a positive increase in wind speed Vj = V0 - js * deltaspeed; //a plane movement to the right is a wind flow to the left, i.e. negative y Vk = V0 - ks * deltaspeed; //a plane movement downwards (Z_stability>0) is a positive increase of V in geometry axes for (p=0; pm_CoG; else CGM = m_pPanel[p].CollPt - m_pWPolar->m_CoG; // a rotation of the plane about a vector is the opposite of a rotation of the freestream about this vector Ris = is*CGM * (-deltarotation) + V0; Rjs = js*CGM * (-deltarotation) + V0; Rks = ks*CGM * (-deltarotation) + V0; m_RHS[59*m_MatSize+p] = Ris.x; m_RHS[60*m_MatSize+p] = Ris.y; m_RHS[61*m_MatSize+p] = Ris.z; m_RHS[62*m_MatSize+p] = Rjs.x; m_RHS[63*m_MatSize+p] = Rjs.y; m_RHS[64*m_MatSize+p] = Rjs.z; m_RHS[65*m_MatSize+p] = Rks.x; m_RHS[66*m_MatSize+p] = Rks.y; m_RHS[67*m_MatSize+p] = Rks.z; m_Sigma[p+3*m_MatSize] = -1.0/4.0/PI* (m_RHS[59*m_MatSize+p]*m_pPanel[p].Normal.x + m_RHS[60*m_MatSize+p]*m_pPanel[p].Normal.y + m_RHS[61*m_MatSize+p]*m_pPanel[p].Normal.z); m_Sigma[p+4*m_MatSize] = -1.0/4.0/PI* (m_RHS[62*m_MatSize+p]*m_pPanel[p].Normal.x + m_RHS[63*m_MatSize+p]*m_pPanel[p].Normal.y + m_RHS[64*m_MatSize+p]*m_pPanel[p].Normal.z); m_Sigma[p+5*m_MatSize] = -1.0/4.0/PI* (m_RHS[65*m_MatSize+p]*m_pPanel[p].Normal.x + m_RHS[66*m_MatSize+p]*m_pPanel[p].Normal.y + m_RHS[67*m_MatSize+p]*m_pPanel[p].Normal.z); } CreateRHS(m_pRHS, WindDirection, m_RHS+59*m_MatSize); CreateRHS(m_qRHS, WindDirection, m_RHS+62*m_MatSize); CreateRHS(m_rRHS, WindDirection, m_RHS+65*m_MatSize); if(!m_pWPolar->m_bThinSurfaces) { // Compute the wake's contribution // We ignore the perturbations and consider only the potential of the steady state flow // Clearly an approximation which is also implicit in the VLM formulation CreateWakeContribution(m_uWake, WindDirection);// re-use m_uWake memory, which is re-calculated anyway at the next control iteration //add wake contribution to all 6 RHS for(p=0; pm_bTiltedGeom); Xu = (Force - Force0).dot(is) /deltaspeed; Zu = (Force - Force0).dot(ks) /deltaspeed; Mu = (Moment- Moment0).dot(js) /deltaspeed; // y-derivatives________________________ alpha = atan2(Vj.z, Vj.x)*180.0/PI;// =m_AlphaEq.... Forces(m_vRHS, m_Sigma+m_MatSize, alpha, m_RHS+53*m_MatSize, Force, Moment, m_pWPolar->m_bTiltedGeom); Yv = (Force - Force0).dot(js) /deltaspeed; // Lv = (Moment.dot(WindDirection) - Moment0.dot(is)) /deltaspeed; Nv = (Moment.dot(WindNormal) - Moment0.dot(ks)) /deltaspeed; Lv = (Moment - Moment0).dot(is) /deltaspeed; Nv = (Moment - Moment0).dot(ks) /deltaspeed; // z-derivatives________________________ alpha = atan2(Vk.z, Vk.x)* 180.0/PI; Forces(m_wRHS, m_Sigma+2*m_MatSize, alpha, m_RHS+56*m_MatSize, Force, Moment, m_pWPolar->m_bTiltedGeom); Xw = (Force - Force0).dot(is) /deltaspeed; Zw = (Force - Force0).dot(ks) /deltaspeed; Mw = (Moment - Moment0).dot(js) /deltaspeed; m_Progress +=1; qApp->processEvents(); // p-derivatives Forces(m_pRHS, m_Sigma+3*m_MatSize, m_AlphaEq, m_RHS+59*m_MatSize, Force, Moment, m_pWPolar->m_bTiltedGeom); Yp = (Force-Force0).dot(js) /deltarotation; Lp = (Moment-Moment0).dot(is) /deltarotation; Np = (Moment-Moment0).dot(ks) /deltarotation; // q-derivatives Forces(m_qRHS, m_Sigma+4*m_MatSize, m_AlphaEq, m_RHS+62*m_MatSize, Force, Moment, m_pWPolar->m_bTiltedGeom); Xq = (Force-Force0).dot(is) /deltarotation; Zq = (Force-Force0).dot(ks) /deltarotation; Mq = (Moment-Moment0).dot(js) /deltarotation; // r-derivatives Forces(m_rRHS, m_Sigma+5*m_MatSize, m_AlphaEq, m_RHS+65*m_MatSize, Force, Moment, m_pWPolar->m_bTiltedGeom); Yr = (Force-Force0).dot(js) /deltarotation; Lr = (Moment-Moment0).dot(is) /deltarotation; Nr = (Moment-Moment0).dot(ks) /deltarotation; m_Progress +=1; qApp->processEvents(); //________________________________________________ // 2nd ORDER STABILITY DERIVATIVES // Zwp & Mwp ... ? // M. Drela's answer to the question posted on Yahoo Groups: /* May I take this opportunity to ask you about the stability derivatives w.r.t. alpha dot ? Are they ignored in AVL and if so, is it a safe assumption ? Yes, the _alphadot derivatives are ignored, for the simple reason that there's no way to do it in an algorithmic way for a general configuration. The usual estimates in Etkin or Nelson assume a "typical" tailed airplane configuration, with a small tail and a well-defined tail arm. These estimates won't work for other configurations like canard, tandem, or flying wing. Normally, only the Cm_alphadot derivative is significant, and slightly augments the pitch-damping derivative Cm_q. Leaving it out therefore underpredicts pitch damping slightly, so this is a conservative approximation. And pitch damping is not a major concern in any case. Simple static pitch stability is more important, and that's not affected by alphadot. All this is for a conventional configuration. Not sure what the impact is on the pitch damping of flying wings. */ } /** * Returns the inertia tensor in stability axis * R is the rotation matrix from Body Frame to stability frame * Ib is the inertia tensor in the body frame, with origin at the CoG * The body frame is the one in which the geometry has been defined, * i.e. the x axis points backwards, y is starboard and z is upwards * Is is the inertia tensor in stability axes with origin at the CoG * Is = tR.Ib.R */ void PanelAnalysisDlg::ComputeStabilityInertia() { static int i,j; static double tR[3][3], tmp[3][3]; tR[0][0] = m_R[0][0]; tR[0][1] = m_R[1][0]; tR[0][2] = m_R[2][0]; tR[1][0] = m_R[0][1]; tR[2][0] = m_R[0][2]; tR[1][1] = m_R[1][1]; tR[1][2] = m_R[2][1]; tR[2][1] = m_R[1][2]; tR[2][2] = m_R[2][2]; // tmp = Ib.R for(i=0; i<3; i++) { for(j=0; j<3; j++) { tmp[i][j] = m_Ib[i][0]*m_R[0][j] + m_Ib[i][1]*m_R[1][j] + m_Ib[i][2]*m_R[2][j]; } } // Is = tR.tmp for(i=0; i<3; i++) { for(j=0; j<3; j++) { m_Is[i][j] = tR[i][0]*tmp[0][j] + tR[i][1]*tmp[1][j] + tR[i][2]*tmp[2][j]; } } } /** * Calculates the control derivatives for small control deflections, using forward derivatives * The geometry has been previously modified to set the control in the position defined for this iteration of the analysis * The problem is not linear, since we take into account viscous forces * Therefore to get the derivative, we need to make the difference between two states * We use forward differences between the reference state corresponding to the trimmed conditions * and the same state + application of a delta angle to all the controls * AVL ignores the modification of the matrix terms and therefore requires only a single LU decomposition throughout the problem. * The same method is applied here * - Save the reference geometry * - Change the control point positions and the normals of the flaps * - re-generate the RHS vector * - the geometry is reset at the next iteration loop */ void PanelAnalysisDlg::ComputeControlDerivatives() { CVector WindDirection, H, Force, Moment, V0, is, js, ks; static int j, p, pos, NCtrls; static double DeltaAngle, SignedDeltaAngle, q, S, b, mac, cosa, sina; QString str; Quaternion Quat; bool bActive = false; for(int c=0; cm_ControlGain[c])>PRECISION) { bActive = true; break; } } if(!bActive) { str = "\n No active control - skipping control derivatives\n\n\n"; AddString(str); return; } // Define the stability axes and the freestream velocity field cosa = cos(m_AlphaEq*PI/180); sina = sin(m_AlphaEq*PI/180); V0.Set(u0*cosa, 0.0, u0*sina); WindDirection.Set(cosa, 0.0, sina); is.Set(-cosa, 0.0, -sina); js.Set( 0.0, 1.0, 0.0); ks.Set( sina, 0.0, -cosa); q = 1./2. * m_pWPolar->m_Density * u0 * u0; b = m_pWPolar->m_WSpan; S = m_pWPolar->m_WArea; mac = m_pWing->m_MAChord; DeltaAngle = 0.001; pos = 0; Xde = Yde = Zde = Lde = Mde = Nde= 0.0; NCtrls = 0; if(m_pPlane) { //Wing tilt if(qAbs(m_pWPolar->m_ControlGain[0])>PRECISION) { //rotate the normals and control point positions H.Set(0.0, 1.0, 0.0); if(qAbs(m_pWPolar->m_ControlGain[0])>PRECISION) SignedDeltaAngle = DeltaAngle * m_pWPolar->m_ControlGain[0]/qAbs(m_pWPolar->m_ControlGain[0]); else SignedDeltaAngle = DeltaAngle; Quat.Set(SignedDeltaAngle*180.0/PI, H); for(p=0; pm_MatSize; p++) { (m_pWing->m_pWingPanel+p)->RotateBC(m_pPlane->WingLE(0), Quat); } } pos = m_pWing->m_MatSize; NCtrls = 1; } if(m_pPlane && m_pWingList[2]) { //Elevator tilt if (qAbs(m_pWPolar->m_ControlGain[1])>PRECISION) { H.Set(0.0, 1.0, 0.0); if(qAbs(m_pWPolar->m_ControlGain[1])>PRECISION) SignedDeltaAngle = DeltaAngle * m_pWPolar->m_ControlGain[1]/qAbs(m_pWPolar->m_ControlGain[1]); else SignedDeltaAngle = DeltaAngle; Quat.Set(SignedDeltaAngle*180.0/PI, H); for(p=0; pm_MatSize; p++) { (m_pWingList[2]->m_pWingPanel+p)->RotateBC(m_pPlane->WingLE(2), Quat); } } pos += m_pWingList[2]->m_MatSize; NCtrls = 2; } //flap tilt // TODO : exclude fin flaps, or add them to StabPolarDlg for (j=0; jm_bTEFlap) { if (qAbs(m_pWPolar->m_ControlGain[NCtrls])>PRECISION) { //Add delta rotations to initial control setting and to wing or flap delta rotation if(qAbs(m_pWPolar->m_ControlGain[NCtrls])>PRECISION) SignedDeltaAngle = DeltaAngle * m_pWPolar->m_ControlGain[NCtrls]/qAbs(m_pWPolar->m_ControlGain[NCtrls]); else SignedDeltaAngle = DeltaAngle; Quat.Set(SignedDeltaAngle*180.0/PI, m_ppSurface[j]->m_HingeVector); for(p=0; pIsFlapPanel(p)) { m_pPanel[p].RotateBC(m_ppSurface[j]->m_HingePoint, Quat); } } } NCtrls++; } } //create the RHS CreateRHS(m_cRHS, V0); if(!m_pWPolar->m_bThinSurfaces) { CreateWakeContribution(m_uWake, WindDirection);// re-use m_uWake memory, which is re-calculated anyway at the next control iteration for(p=0; pm_bTiltedGeom); // make the forward difference with nominal results // which gives the stability derivative for a rotation of control ic Xde = (Force-Force0).dot(is)/DeltaAngle; Yde = (Force-Force0).dot(js)/DeltaAngle; Zde = (Force-Force0).dot(ks)/DeltaAngle; Lde = (Moment - Moment0).dot(is) /DeltaAngle; // N.m/rad Mde = (Moment - Moment0).dot(js) /DeltaAngle; Nde = (Moment - Moment0).dot(ks) /DeltaAngle; } /** * Returns the geometric pitching moment coefficient for the specified angle of attack * The effect of the viscous drag is not included. *@param Alpha the aoa for which Cm is calculated */ double PanelAnalysisDlg::ComputeCm(double Alpha) { static int p; static double Cm, cosa, sina, Gamma, Gammap1; static CVector VInf, Force, PanelLeverArm, ForcePt, PanelForce, WindDirection, VLocal; double Speed2, Cp; // Define the wind axis cosa = cos(Alpha*PI/180.0); sina = sin(Alpha*PI/180.0); WindDirection.Set( cosa, 0.0, sina); VInf.Set(cosa, 0.0, sina); Cm = 0.0; for(p=0; pm_bVLM1 && !m_pPanel[p].m_bIsLeading) { Force = WindDirection * m_pPanel[p].Vortex; Force *= 2.0 * Gammap1; //Newtons/q/QInf PanelForce -= Force; } m_Cp[p] = PanelForce.dot(m_pPanel[p].Normal)/m_pPanel[p].Area; //todo : remove, for information only } PanelLeverArm.x = ForcePt.x - m_pWPolar->m_CoG.x; PanelLeverArm.y = ForcePt.y - m_pWPolar->m_CoG.y; PanelLeverArm.z = ForcePt.z - m_pWPolar->m_CoG.z; Cm += -PanelLeverArm.x * PanelForce.z + PanelLeverArm.z*PanelForce.x; //N.m/rho } Cm *= m_pWPolar->m_Density; return Cm; } /** * QUAD VORTEX FORMULATION * * LA, LB, TA, TB are the vortex's four corners * LA and LB are at the 3/4 point of panel nx * TA and TB are at the 3/4 point of panel nx+1 * * LA__________LB | * | | | * | | | freestream speed * | | | * | | \/ * | | * TA__________TB * * * Returns the velocity greated by a ring vortex with unit circulation at a distant point * * Notes : * - The geometry has been rotated by the sideslip angle, hence, there is no need to align the trailing vortices with sideslip * - Vectorial operations are written inline to save computing times -->longer code, but 4x more efficient.... * * @param LA the leading left point of the quad vortex * @param LB the leading right point of the quad vortex * @param TA the trailing left point of the quad vortex * @param TB the trailing right point of the quad vortex * @param C the point where the velocity is calculated * @param V the resulting velocity vector at point C */ void PanelAnalysisDlg::VLMQmn(CVector const &LA, CVector const &LB, CVector const &TA, CVector const &TB, CVector const &C, CVector &V) { // // C is the point where the induced speed is calculated // V is the resulting speed // // Vectorial operations are written explicitly to save computing times (4x more efficient) // double CoreSize = 0.0001; if(qAbs(*m_pCoreSize)>1.e-10) CoreSize = *m_pCoreSize; V.x = 0.0; V.y = 0.0; V.z = 0.0; R[0].x = LB.x; R[0].y = LB.y; R[0].z = LB.z; R[1].x = TB.x; R[1].y = TB.y; R[1].z = TB.z; R[2].x = TA.x; R[2].y = TA.y; R[2].z = TA.z; R[3].x = LA.x; R[3].y = LA.y; R[3].z = LA.z; R[4].x = LB.x; R[4].y = LB.y; R[4].z = LB.z; for (int i=0; i<4; i++) { r0.x = R[i+1].x - R[i].x; r0.y = R[i+1].y - R[i].y; r0.z = R[i+1].z - R[i].z; r1.x = C.x - R[i].x; r1.y = C.y - R[i].y; r1.z = C.z - R[i].z; r2.x = C.x - R[i+1].x; r2.y = C.y - R[i+1].y; r2.z = C.z - R[i+1].z; Psi.x = r1.y*r2.z - r1.z*r2.y; Psi.y =-r1.x*r2.z + r1.z*r2.x; Psi.z = r1.x*r2.y - r1.y*r2.x; ftmp = Psi.x*Psi.x + Psi.y*Psi.y + Psi.z*Psi.z; r1v = sqrt((r1.x*r1.x + r1.y*r1.y + r1.z*r1.z)); r2v = sqrt((r2.x*r2.x + r2.y*r2.y + r2.z*r2.z)); //get the distance of the TestPoint to the panel's side t.x = r1.y*r0.z - r1.z*r0.y; t.y = -r1.x*r0.z + r1.z*r0.x; t.z = r1.x*r0.y - r1.y*r0.x; if ((t.x*t.x+t.y*t.y+t.z*t.z)/(r0.x*r0.x+r0.y*r0.y+r0.z*r0.z) > CoreSize * CoreSize) { Psi.x /= ftmp; Psi.y /= ftmp; Psi.z /= ftmp; Omega = (r0.x*r1.x + r0.y*r1.y + r0.z*r1.z)/r1v - (r0.x*r2.x + r0.y*r2.y + r0.z*r2.z)/r2v; V.x += Psi.x * Omega/4.0/PI; V.y += Psi.y * Omega/4.0/PI; V.z += Psi.z * Omega/4.0/PI; } } } /** * HORSESHOE VORTEX FORMULATION/ * * LA__________LB | * | | | * | | | freestream speed * | | | * | | \/ * | | * \/ \/ * * * Returns the velocity greated by a horseshoe vortex with unit circulation at a distant point * * Notes : * - The geometry has been rotated by the sideslip angle, hence, there is no need to align the trailing vortices with sideslip * - Vectorial operations are written inline to save computing times -->longer code, but 4x more efficient.... * * @param A the left point of the bound vortex * @param B the right point of the bound vortex * @param C the point where the velocity is calculated * @param V the resulting velocity vector at point C * @param bAll true if the influence of the bound vortex should be evaluated; false for a distant point in the far field. */ void PanelAnalysisDlg::VLMCmn(CVector const &A, CVector const &B, CVector const &C, CVector &V, bool const &bAll) { double CoreSize = 0.0001; if(qAbs(*m_pCoreSize)>1.e-10) CoreSize = *m_pCoreSize; V.x = 0.0; V.y = 0.0; V.z = 0.0; if(bAll) { r0.x = B.x - A.x; r0.y = B.y - A.y; r0.z = B.z - A.z; r1.x = C.x - A.x; r1.y = C.y - A.y; r1.z = C.z - A.z; r2.x = C.x - B.x; r2.y = C.y - B.y; r2.z = C.z - B.z; Psi.x = r1.y*r2.z - r1.z*r2.y; Psi.y =-r1.x*r2.z + r1.z*r2.x; Psi.z = r1.x*r2.y - r1.y*r2.x; ftmp = Psi.x*Psi.x + Psi.y*Psi.y + Psi.z*Psi.z; //get the distance of the TestPoint to the panel's side t.x = r1.y*r0.z - r1.z*r0.y; t.y = -r1.x*r0.z + r1.z*r0.x; t.z = r1.x*r0.y - r1.y*r0.x; if ((t.x*t.x+t.y*t.y+t.z*t.z)/(r0.x*r0.x+r0.y*r0.y+r0.z*r0.z) >CoreSize * CoreSize) { Psi.x /= ftmp; Psi.y /= ftmp; Psi.z /= ftmp; Omega = (r0.x*r1.x + r0.y*r1.y + r0.z*r1.z)/sqrt((r1.x*r1.x + r1.y*r1.y + r1.z*r1.z)) -(r0.x*r2.x + r0.y*r2.y + r0.z*r2.z)/sqrt((r2.x*r2.x + r2.y*r2.y + r2.z*r2.z)); V.x = Psi.x * Omega/4.0/PI; V.y = Psi.y * Omega/4.0/PI; V.z = Psi.z * Omega/4.0/PI; } } // We create Far points to align the trailing vortices with the reference axis // The trailing vortex legs are not aligned with the free-stream, i.a.w. the small angle approximation // If this approximation is not valid, then the geometry should be tilted in the polar definition // calculate left contribution Far.x = A.x + 1.0e10; Far.y = A.y; Far.z = A.z;// + (Far.x-A.x) * tan(m_Alpha*PI/180.0); r0.x = A.x - Far.x; r0.y = A.y - Far.y; r0.z = A.z - Far.z; r1.x = C.x - A.x; r1.y = C.y - A.y; r1.z = C.z - A.z; r2.x = C.x - Far.x; r2.y = C.y - Far.y; r2.z = C.z - Far.z; Psi.x = r1.y*r2.z - r1.z*r2.y; Psi.y =-r1.x*r2.z + r1.z*r2.x; Psi.z = r1.x*r2.y - r1.y*r2.x; ftmp = Psi.x*Psi.x + Psi.y*Psi.y + Psi.z*Psi.z; t.x=1.0; t.y=0.0; t.z=0.0; h.x = r1.y*t.z - r1.z*t.y; h.y = -r1.x*t.z + r1.z*t.x; h.z = r1.x*t.y - r1.y*t.x; //Next add 'left' semi-infinite contribution //eq.6-56 if ((h.x*h.x+h.y*h.y+h.z*h.z) > CoreSize * CoreSize) { Psi.x /= ftmp; Psi.y /= ftmp; Psi.z /= ftmp; Omega = (r0.x*r1.x + r0.y*r1.y + r0.z*r1.z)/sqrt((r1.x*r1.x + r1.y*r1.y + r1.z*r1.z)) -(r0.x*r2.x + r0.y*r2.y + r0.z*r2.z)/sqrt((r2.x*r2.x + r2.y*r2.y + r2.z*r2.z)); V.x += Psi.x * Omega/4.0/PI; V.y += Psi.y * Omega/4.0/PI; V.z += Psi.z * Omega/4.0/PI; } // calculate right vortex contribution Far.x = B.x + 1.0e10; Far.y = B.y ; Far.z = B.z;// + (Far.x-B.x) * tan(m_Alpha*PI/180.0); r0.x = Far.x - B.x; r0.y = Far.y - B.y; r0.z = Far.z - B.z; r1.x = C.x - Far.x; r1.y = C.y - Far.y; r1.z = C.z - Far.z; r2.x = C.x - B.x; r2.y = C.y - B.y; r2.z = C.z - B.z; Psi.x = r1.y*r2.z - r1.z*r2.y; Psi.y =-r1.x*r2.z + r1.z*r2.x; Psi.z = r1.x*r2.y - r1.y*r2.x; ftmp = Psi.x*Psi.x + Psi.y*Psi.y + Psi.z*Psi.z; //Last add 'right' semi-infinite contribution //eq.6-57 h.x = r2.y*t.z - r2.z*t.y; h.y = -r2.x*t.z + r2.z*t.x; h.z = r2.x*t.y - r2.y*t.x; if ((h.x*h.x+h.y*h.y+h.z*h.z) > CoreSize * CoreSize) { Psi.x /= ftmp; Psi.y /= ftmp; Psi.z /= ftmp; Omega = (r0.x*r1.x + r0.y*r1.y + r0.z*r1.z)/sqrt((r1.x*r1.x + r1.y*r1.y + r1.z*r1.z)) -(r0.x*r2.x + r0.y*r2.y + r0.z*r2.z)/sqrt((r2.x*r2.x + r2.y*r2.y + r2.z*r2.z)); V.x += Psi.x * Omega/4.0/PI; V.y += Psi.y * Omega/4.0/PI; V.z += Psi.z * Omega/4.0/PI; } } void PanelAnalysisDlg::showEvent(QShowEvent *event) { move(s_Position); } void PanelAnalysisDlg::hideEvent(QHideEvent *event) { s_Position = pos(); } xflr5-6.09-06/src/miarex/ManageUFOsDlg.cpp000644 001750 000144 00000026451 12247174402 021435 0ustar00techwinderusers000000 000000 /**************************************************************************** ManageUFOsDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include #include "Miarex.h" #include "../globals.h" #include "../mainframe.h" #include "ManageUFOsDlg.h" void *ManageUFOsDlg::s_pMainFrame; void *ManageUFOsDlg::s_pMiarex; ManageUFOsDlg::ManageUFOsDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Object Management")); m_pWing = NULL; m_pPlane = NULL; SetupLayout(); connect(m_pctrlDelete, SIGNAL(clicked()),this, SLOT(OnDelete())); connect(m_pctrlRename, SIGNAL(clicked()),this, SLOT(OnRename())); connect(m_pctrlUFOTable, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(OnDoubleClickTable(const QModelIndex &))); connect(m_pctrlDescription, SIGNAL(textChanged()), this, SLOT(OnDescriptionChanged())); connect(CloseButton, SIGNAL(clicked()),this, SLOT(accept())); } void ManageUFOsDlg::InitDialog(QString &UFOName) { FillUFOTable(); QMiarex *pMiarex = (QMiarex*)s_pMiarex; QString strong; QString strArea, strLength; GetLengthUnit(strLength, MainFrame::s_LengthUnit); GetAreaUnit(strArea, MainFrame::s_AreaUnit); m_pUFOModel->setHeaderData(0, Qt::Horizontal, tr("Name")); m_pUFOModel->setHeaderData(1, Qt::Horizontal, tr("Span")+" ("+strLength+")"); m_pUFOModel->setHeaderData(2, Qt::Horizontal, tr("Area")+" ("+strArea+")"); m_pUFOModel->setHeaderData(3, Qt::Horizontal, tr("M.A.C.")+" ("+strLength+")"); m_pUFOModel->setHeaderData(4, Qt::Horizontal, tr("AR")); m_pUFOModel->setHeaderData(5, Qt::Horizontal, tr("TR")); QString str = tr("Rt-Tip Sweep") +QString::fromUtf8(" (°)"); m_pUFOModel->setHeaderData(6, Qt::Horizontal, str); m_pUFOModel->setHeaderData(7, Qt::Horizontal, tr("Tail Volume")); if(m_pUFOModel->rowCount()) { if(UFOName.length()) { QModelIndex ind; for(int i=0; i< m_pUFOModel->rowCount(); i++) { ind = m_pUFOModel->index(i, 0, QModelIndex()); strong = ind.model()->data(ind, Qt::EditRole).toString(); if(strong == UFOName) { m_pctrlUFOTable->selectRow(i); break; } } } else { m_pctrlUFOTable->selectRow(0); QStandardItem *pItem = m_pUFOModel->item(0,0); if(pItem) UFOName = pItem->text(); else UFOName.clear(); } m_pWing = pMiarex->GetWing(UFOName); if(m_pWing) m_pPlane = NULL; else m_pPlane = pMiarex->GetPlane(UFOName); } else { m_pWing = NULL; m_pPlane = NULL; } } void ManageUFOsDlg::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Return: { if(!CloseButton->hasFocus()) CloseButton->setFocus(); else accept(); break; } case Qt::Key_Escape: { reject(); return; } default: event->ignore(); } } void ManageUFOsDlg::SetupLayout() { QVBoxLayout *CommandButtons = new QVBoxLayout; { m_pctrlDelete = new QPushButton(tr("Delete")); m_pctrlRename = new QPushButton(tr("Rename")); CloseButton = new QPushButton(tr("Close")); CommandButtons->addStretch(1); CommandButtons->addWidget(m_pctrlRename); CommandButtons->addWidget(m_pctrlDelete); CommandButtons->addStretch(2); CommandButtons->addWidget(CloseButton); CommandButtons->addStretch(1); } QVBoxLayout *LeftLayout = new QVBoxLayout; { m_pctrlUFOTable = new QTableView(this); m_pctrlUFOTable->setSelectionMode(QAbstractItemView::SingleSelection); m_pctrlUFOTable->setSelectionBehavior(QAbstractItemView::SelectRows); m_pctrlUFOTable->horizontalHeader()->setStretchLastSection(true); QSizePolicy szPolicyExpanding; szPolicyExpanding.setHorizontalPolicy(QSizePolicy::MinimumExpanding); szPolicyExpanding.setVerticalPolicy(QSizePolicy::Expanding); m_pctrlUFOTable->setSizePolicy(szPolicyExpanding); m_pctrlUFOTable->setMinimumWidth(800); m_pctrlDescription = new QTextEdit; // m_pctrlDescription->setEnabled(false); QLabel *Description = new QLabel(tr("Description:")); LeftLayout->addWidget(m_pctrlUFOTable); LeftLayout->addWidget(Description); LeftLayout->addWidget(m_pctrlDescription); LeftLayout->setStretchFactor(m_pctrlUFOTable, 5); LeftLayout->setStretchFactor(m_pctrlDescription, 1); } QHBoxLayout * MainLayout = new QHBoxLayout(this); { MainLayout->addLayout(LeftLayout); MainLayout->addLayout(CommandButtons); } setLayout(MainLayout); m_pUFOModel = new QStandardItemModel; m_pUFOModel->setRowCount(10);//temporary m_pUFOModel->setColumnCount(8); m_pctrlUFOTable->setModel(m_pUFOModel); m_pctrlUFOTable->setWindowTitle(tr("UFOs")); QItemSelectionModel *selectionModel = new QItemSelectionModel(m_pUFOModel); m_pctrlUFOTable->setSelectionModel(selectionModel); connect(selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnUFOClicked(QModelIndex))); m_pUFODelegate = new UFOTableDelegate; m_pctrlUFOTable->setItemDelegate(m_pUFODelegate); m_pUFODelegate->m_pUFOModel = m_pUFOModel; int *precision = new int[12]; precision[0] = 2; precision[1] = 3; precision[2] = 3; precision[3] = 3; precision[4] = 2; precision[5] = 2; precision[6] = 1; precision[7] = 2; precision[8] = 3; m_pUFODelegate->m_Precision = precision; } void ManageUFOsDlg::FillUFOTable() { int i,n; m_pUFOModel->setRowCount(MainFrame::s_oaWing.size() + MainFrame::s_oaPlane.size()); for(i=0; i=MainFrame::s_oaWing.size()) return; QModelIndex ind; Wing *pWing = (Wing*)MainFrame::s_oaWing.at(row); if(!pWing) return; ind = m_pUFOModel->index(row, 0, QModelIndex()); m_pUFOModel->setData(ind, pWing->m_WingName); if(pWing->m_WingDescription.length()) m_pUFOModel->setData(ind, pWing->m_WingDescription, Qt::ToolTipRole); ind = m_pUFOModel->index(row, 1, QModelIndex()); m_pUFOModel->setData(ind, pWing->m_PlanformSpan*MainFrame::s_mtoUnit); ind = m_pUFOModel->index(row, 2, QModelIndex()); m_pUFOModel->setData(ind, pWing->m_PlanformArea*MainFrame::s_m2toUnit); ind = m_pUFOModel->index(row, 3, QModelIndex()); m_pUFOModel->setData(ind, pWing->m_MAChord*MainFrame::s_mtoUnit); ind = m_pUFOModel->index(row, 4, QModelIndex()); m_pUFOModel->setData(ind, pWing->m_AR); ind = m_pUFOModel->index(row, 5, QModelIndex()); m_pUFOModel->setData(ind, pWing->m_TR); ind = m_pUFOModel->index(row, 6, QModelIndex()); m_pUFOModel->setData(ind,pWing->AverageSweep()); ind = m_pUFOModel->index(row, 7, QModelIndex()); m_pUFOModel->setData(ind,0.0); } void ManageUFOsDlg::FillPlaneRow(int row, int n) { QModelIndex ind; if(row>=MainFrame::s_oaPlane.size()) return; Plane *pPlane = (Plane*)MainFrame::s_oaPlane.at(row); if(!pPlane) return; Wing *pWing = pPlane->wing(); ind = m_pUFOModel->index(row+n, 0, QModelIndex()); m_pUFOModel->setData(ind,pPlane->PlaneName()); if(pPlane->PlaneDescription().length()) m_pUFOModel->setData(ind, pPlane->PlaneDescription(), Qt::ToolTipRole); ind = m_pUFOModel->index(row+n, 1, QModelIndex()); m_pUFOModel->setData(ind, pWing->m_PlanformSpan*MainFrame::s_mtoUnit); ind = m_pUFOModel->index(row+n, 2, QModelIndex()); m_pUFOModel->setData(ind, pWing->m_PlanformArea*MainFrame::s_m2toUnit); ind = m_pUFOModel->index(row+n, 3, QModelIndex()); m_pUFOModel->setData(ind, pWing->m_MAChord*MainFrame::s_mtoUnit); ind = m_pUFOModel->index(row+n, 4, QModelIndex()); m_pUFOModel->setData(ind, pWing->m_AR); ind = m_pUFOModel->index(row+n, 5, QModelIndex()); m_pUFOModel->setData(ind, pWing->m_TR); ind = m_pUFOModel->index(row+n, 6, QModelIndex()); m_pUFOModel->setData(ind,pWing->AverageSweep()); ind = m_pUFOModel->index(row+n, 7, QModelIndex()); m_pUFOModel->setData(ind,pPlane->TailVolume()); } void ManageUFOsDlg::OnRename() { QMiarex *pMiarex = (QMiarex*)s_pMiarex; if(m_pPlane) pMiarex->RenameUFO(m_pPlane->PlaneName()); else if (m_pWing) pMiarex->RenameUFO(m_pWing->m_WingName); FillUFOTable(); MainFrame::SetSaveState(false); } void ManageUFOsDlg::OnDelete() { if(!m_pWing && !m_pPlane) return; MainFrame *pMainFrame = (MainFrame*)s_pMainFrame; QMiarex *pMiarex = (QMiarex*)s_pMiarex; QString strong; if(m_pPlane) strong = tr("Are you sure you want to delete the plane :\n") + m_pPlane->PlaneName() +"?\n"; else strong = tr("Are you sure you want to delete the wing :\n") + m_pWing->m_WingName +"?\n"; if (QMessageBox::Yes != QMessageBox::question(window(), tr("Question"), strong, QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes)) return; if(m_pPlane) pMainFrame->DeletePlane(m_pPlane); else pMainFrame->DeleteWing(m_pWing, false); QModelIndex index = m_pctrlUFOTable->currentIndex(); int sel = qMax(index.row()-1,0); FillUFOTable(); if(m_pUFOModel->rowCount()>0) { m_pctrlUFOTable->selectRow(sel); QString UFOName; QStandardItem *pItem = m_pUFOModel->item(sel,0); if(pItem) UFOName = pItem->text(); else UFOName.clear(); m_pWing = pMiarex->GetWing(UFOName); if(m_pWing) m_pPlane = NULL; //not necessary... else m_pPlane = pMiarex->GetPlane(UFOName); } else { m_pWing = NULL; m_pPlane = NULL; } } void ManageUFOsDlg::OnDoubleClickTable(const QModelIndex &index) { if(index.row()>=0) accept(); } void ManageUFOsDlg::OnDescriptionChanged() { if(m_pPlane) { m_pPlane->rPlaneDescription() = m_pctrlDescription->toPlainText(); } else if(m_pWing) { m_pWing->m_WingDescription = m_pctrlDescription->toPlainText(); } MainFrame::SetSaveState(false); } void ManageUFOsDlg::OnUFOClicked(QModelIndex index) { QMiarex *pMiarex = (QMiarex*)s_pMiarex; QStandardItem *pItem = m_pUFOModel->item(index.row(),0); QString UFOName; if(pItem) UFOName = pItem->text(); else UFOName.clear(); m_pWing = pMiarex->GetWing(UFOName); if(m_pWing) { m_pPlane = NULL; //not necessary... m_pctrlDescription->setText(m_pWing->m_WingDescription); } else { m_pPlane = pMiarex->GetPlane(UFOName); if(m_pPlane) m_pctrlDescription->setText(m_pPlane->PlaneDescription()); } } void ManageUFOsDlg::resizeEvent(QResizeEvent *event) { int w = m_pctrlUFOTable->width(); int w8 = (int)((double)w/12.0); // int w10 = (int)((double)w/10.0); m_pctrlUFOTable->setColumnWidth(1,w8); m_pctrlUFOTable->setColumnWidth(3,w8); m_pctrlUFOTable->setColumnWidth(2,w8); m_pctrlUFOTable->setColumnWidth(4,w8); m_pctrlUFOTable->setColumnWidth(5,w8); m_pctrlUFOTable->setColumnWidth(6,w8); m_pctrlUFOTable->setColumnWidth(7,w8); m_pctrlUFOTable->setColumnWidth(0,w-7*w8-40); } xflr5-6.09-06/src/miarex/BodyTransDlg.h000644 001750 000144 00000003426 12247174401 021056 0ustar00techwinderusers000000 000000 /**************************************************************************** BodyTransDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef BODYTRANSDLG_H #define BODYTRANSDLG_H #include #include #include #include #include "../misc/DoubleEdit.h" class BodyTransDlg : public QDialog { Q_OBJECT friend class MainFrame; friend class QMiarex; friend class Body; friend class GL3dBodyDlg; public: BodyTransDlg(QWidget *pParent); void InitDialog(); private slots: void OnOK(); void OnFrameOnly(); private: void keyPressEvent(QKeyEvent *event); void SetupLayout(); DoubleEdit *m_pctrlXTransFactor; DoubleEdit *m_pctrlYTransFactor; DoubleEdit *m_pctrlZTransFactor; DoubleEdit *m_pctrlFrameID; QCheckBox *m_pctrlFrameOnly; QLabel *m_pctrlLength1; QLabel *m_pctrlLength2; QLabel *m_pctrlLength3; QPushButton *OKButton, *CancelButton; double m_XTrans, m_YTrans, m_ZTrans; bool m_bFrameOnly; int m_FrameID; }; #endif // BODYTRANSDLG_H xflr5-6.09-06/src/miarex/GLCreateLists.cpp000644 001750 000144 00000210436 12247174402 021524 0ustar00techwinderusers000000 000000 /**************************************************************************** GLCreateLists Copyright (C) 2010-2010 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include "../globals.h" #include "../mainframe.h" #include "GLCreateLists.h" #include "Miarex.h" #include "GL3DScales.h" #include "../misc/W3dPrefsDlg.h" #include "StabViewDlg.h" #include "../objects/Wing.h" #include #define SIDEPOINTS 51 void GLCreateGeom(void *pQMiarex, Wing *pWing, int List, Body *pBody) { if(!pWing) return; QMiarex * pMiarex = (QMiarex*)pQMiarex; static int j, l ; static double x, xDistrib[SIDEPOINTS]; static CVector Pt, PtA, PtB, PtNormal, A, B, C, D, N, BD, AC; static CVector PtILeft[2*SIDEPOINTS],PtIRight[2*SIDEPOINTS]; static Foil * pFoilA, *pFoilB; N.Set(0.0, 0.0, 0.0); double xx; for(int i=0; im_GLList++; if(MainFrame::s_bAlphaChannel) { glColor4d(pWing->m_WingColor.redF(),pWing->m_WingColor.greenF(),pWing->m_WingColor.blueF(), pWing->m_WingColor.alphaF()); glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glColor3d(pWing->m_WingColor.redF(),pWing->m_WingColor.greenF(),pWing->m_WingColor.blueF()); glDisable (GL_BLEND); } glEnable(GL_DEPTH_TEST); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonOffset(1.0, 1.0); //top surface for (j=0; jm_NSurfaces; j++) { glBegin(GL_QUAD_STRIP); { for (l=0; lm_Surface[j].GetSurfacePointNormal(x,x,0.0,PtA, PtNormal,1); pWing->m_Surface[j].GetSurfacePointNormal(x,x,1.0,PtB, PtNormal,1); if(pBody && pWing->m_Surface[j].IsCenterSurf() && pWing->m_Surface[j].IsLeftSurf()) { pBody->Intersect(PtA, PtB, PtB, false); PtIRight[l] = PtB; } else if(pBody && pWing->m_Surface[j].IsCenterSurf() && pWing->m_Surface[j].IsRightSurf()) { pBody->Intersect(PtA, PtB, PtA, true); PtILeft[l] = PtA; } glNormal3d(PtNormal.x, PtNormal.y, PtNormal.z); glVertex3d(PtA.x, PtA.y, PtA.z); glVertex3d(PtB.x, PtB.y, PtB.z); } } glEnd(); } //bottom surface for (j=0; jm_NSurfaces; j++) { glBegin(GL_QUAD_STRIP); { for (l=0; lm_Surface[j].GetSurfacePointNormal(x,x,0.0,PtA, PtNormal,-1); pWing->m_Surface[j].GetSurfacePointNormal(x,x,1.0,PtB, PtNormal,-1); if(pBody && pWing->m_Surface[j].IsCenterSurf() && pWing->m_Surface[j].IsLeftSurf()) { pBody->Intersect(PtA, PtB, PtB, false); PtIRight[l+SIDEPOINTS] = PtB; } else if(pBody && pWing->m_Surface[j].IsCenterSurf() && pWing->m_Surface[j].IsRightSurf()) { pBody->Intersect(PtA, PtB, PtA, true); PtILeft[l+SIDEPOINTS] = PtA; } glNormal3d(PtNormal.x, PtNormal.y, PtNormal.z); glVertex3d(PtA.x, PtA.y, PtA.z); glVertex3d(PtB.x, PtB.y, PtB.z); } } glEnd(); } for (j=0; jm_NSurfaces; j++) { //Tip left surface if(pWing->m_Surface[j].IsTipLeft()) { glBegin(GL_QUAD_STRIP); { pWing->m_Surface[j].GetPanel(0, 0, BOTSURFACE); C. Copy(pWing->m_Surface[0].LA); D. Copy(pWing->m_Surface[0].TA); pWing->m_Surface[j].GetPanel(0, 0, TOPSURFACE); A. Copy(pWing->m_Surface[0].TA); B. Copy(pWing->m_Surface[0].LA); BD = D-B; AC = C-A; N = AC*BD; N.Normalize(); glNormal3d( N.x, N.y, N.z); for (l=0; lm_Surface[j].GetSurfacePointNormal(x,x,0.0,Pt, PtNormal,1); glVertex3d(Pt.x, Pt.y, Pt.z); pWing->m_Surface[j].GetSurfacePointNormal(x,x,0.0,Pt, PtNormal,-1); glVertex3d(Pt.x, Pt.y, Pt.z); } } glEnd(); } if (pWing->m_Surface[j].IsTipRight() && (!pWing->IsFin() || (pWing->IsFin()&&!pBody)) ) { //Tip right surface glBegin(GL_QUAD_STRIP); { pWing->m_Surface[j].GetPanel(pWing->m_Surface[j].m_NYPanels-1,0, TOPSURFACE); A. Copy(pWing->m_Surface[0].TB); B. Copy(pWing->m_Surface[0].LB); pWing->m_Surface[j].GetPanel(pWing->m_Surface[j].m_NYPanels-1,0, BOTSURFACE); C. Copy(pWing->m_Surface[0].LB); D. Copy(pWing->m_Surface[0].TB); BD = D-B; AC = C-A; N = BD * AC; N.Normalize(); glNormal3d( N.x, N.y, N.z); for (l=0; lm_Surface[j].GetSurfacePointNormal(x,x,1.0,Pt, PtNormal,1); glVertex3d(Pt.x, Pt.y, Pt.z); pWing->m_Surface[j].GetSurfacePointNormal(x,x,1.0,Pt, PtNormal,-1); glVertex3d(Pt.x, Pt.y, Pt.z); } } glEnd(); } } glDisable(GL_DEPTH_TEST); glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_BLEND); } glEndList(); //OUTLINE glNewList(List+4,GL_COMPILE); { pMiarex->m_GLList++; glEnable(GL_DEPTH_TEST); glEnable (GL_LINE_STIPPLE); if (W3dPrefsDlg::s_OutlineStyle == 1) glLineStipple (1, 0xCFCF); else if(W3dPrefsDlg::s_OutlineStyle == 2) glLineStipple (1, 0x6666); else if(W3dPrefsDlg::s_OutlineStyle == 3) glLineStipple (1, 0xFF18); else if(W3dPrefsDlg::s_OutlineStyle == 4) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glColor3d(W3dPrefsDlg::s_OutlineColor.redF(),W3dPrefsDlg::s_OutlineColor.greenF(),W3dPrefsDlg::s_OutlineColor.blueF()); glLineWidth((GLfloat)W3dPrefsDlg::s_OutlineWidth); //TOP outline for (j=0; jm_NSurfaces; j++) { glBegin(GL_LINE_STRIP); { for (l=0; lm_Surface[j].IsCenterSurf() && pWing->m_Surface[j].IsRightSurf()) { // pBody->Intersect(PtA, PtB, PtA, true); PtA = PtILeft[l]; } else { x = xDistrib[l]; pWing->m_Surface[j].GetSurfacePointNormal(x ,x ,0.0 ,PtA, PtNormal, 1); pWing->m_Surface[j].GetSurfacePointNormal(x, x, 1.0, PtB, PtNormal, 1); } glVertex3d(PtA.x, PtA.y, PtA.z); } } glEnd(); glBegin(GL_LINE_STRIP); { for (l=0; lm_Surface[j].IsCenterSurf() && pWing->m_Surface[j].IsRightSurf()) { // pBody->Intersect(PtA, PtB, PtA, true); PtA = PtILeft[l+SIDEPOINTS]; } else { x = (double)l/(double)(SIDEPOINTS-1); pWing->m_Surface[j].GetSurfacePointNormal(x ,x ,0.0 ,PtA, PtNormal, -1); pWing->m_Surface[j].GetSurfacePointNormal(x, x, 1.0, PtB, PtNormal, -1); } glVertex3d(PtA.x, PtA.y, PtA.z); } } glEnd(); glBegin(GL_LINE_STRIP); { //top right surface outline for (l=0; lm_Surface[j].IsCenterSurf() && pWing->m_Surface[j].IsLeftSurf()) { // pBody->Intersect(PtA, PtB, PtB, false); PtB = PtIRight[l]; } else { x = xDistrib[l]; pWing->m_Surface[j].GetSurfacePointNormal(x ,x ,0.0 ,PtA, PtNormal, 1); pWing->m_Surface[j].GetSurfacePointNormal(x, x, 1.0, PtB, PtNormal, 1); } glVertex3d(PtB.x, PtB.y, PtB.z); } } glEnd(); glBegin(GL_LINE_STRIP); { //bottom right surface outline for (l=0; lm_Surface[j].IsCenterSurf() && pWing->m_Surface[j].IsLeftSurf()) { // pBody->Intersect(PtA, PtB, PtB, false); PtB = PtIRight[l+SIDEPOINTS]; } else { x = xDistrib[l]; pWing->m_Surface[j].GetSurfacePointNormal(x ,x ,0.0 ,PtA, PtNormal, -1); pWing->m_Surface[j].GetSurfacePointNormal(x, x, 1.0, PtB, PtNormal, -1); } glVertex3d(PtB.x, PtB.y, PtB.z); } } glEnd(); } //WingContour //Leading edge outline for (j=0; jm_NSurfaces; j++) { glBegin(GL_LINES); { pWing->m_Surface[j].GetPanel(0,pWing->m_Surface[j].m_NXPanels-1, MIDSURFACE); glVertex3d(pWing->m_Surface[j].LA.x, pWing->m_Surface[j].LA.y, pWing->m_Surface[j].LA.z); pWing->m_Surface[j].GetPanel( pWing->m_Surface[j].m_NYPanels-1,pWing->m_Surface[j].m_NXPanels-1, MIDSURFACE); glVertex3d(pWing->m_Surface[j].LB.x, pWing->m_Surface[j].LB.y, pWing->m_Surface[j].LB.z); } glEnd(); } //Trailing edge outline for (j=0; jm_NSurfaces; j++) { glBegin(GL_LINES); { pWing->m_Surface[j].GetPanel(0,0, MIDSURFACE); glVertex3d(pWing->m_Surface[j].TA.x, pWing->m_Surface[j].TA.y, pWing->m_Surface[j].TA.z); pWing->m_Surface[j].GetPanel( pWing->m_Surface[j].m_NYPanels-1, 0, MIDSURFACE); glVertex3d(pWing->m_Surface[j].TB.x, pWing->m_Surface[j].TB.y, pWing->m_Surface[j].TB.z); } glEnd(); } //flap outline.... for (j=0; jm_NSurfaces; j++) { pFoilA = pWing->m_Surface[j].m_pFoilA; pFoilB = pWing->m_Surface[j].m_pFoilB; if(pFoilA && pFoilB && pFoilA->m_bTEFlap && pFoilB->m_bTEFlap) { glBegin(GL_LINES); { if(pFoilA->m_bTEFlap) pWing->m_Surface[j].GetSurfacePoint(pWing->m_Surface[j].m_pFoilA->m_TEXHinge/100.0, pWing->m_Surface[j].m_pFoilA->m_TEXHinge/100.0, 0.0, Pt, 1); else pWing->m_Surface[j].GetSurfacePoint(1.0, 1.0, 0.0, Pt, 1); glVertex3d(Pt.x, Pt.y, Pt.z); if(pFoilB->m_bTEFlap) pWing->m_Surface[j].GetSurfacePoint(pWing->m_Surface[j].m_pFoilB->m_TEXHinge/100.0, pWing->m_Surface[j].m_pFoilB->m_TEXHinge/100.0, 1.0, Pt, 1); else pWing->m_Surface[j].GetSurfacePoint(1.0, 1.0, 1.0, Pt, 1); glVertex3d(Pt.x, Pt.y, Pt.z); } glEnd(); glBegin(GL_LINES); { if(pFoilA->m_bTEFlap) pWing->m_Surface[j].GetSurfacePoint(pWing->m_Surface[j].m_pFoilA->m_TEXHinge/100.0, pWing->m_Surface[j].m_pFoilA->m_TEXHinge/100.0, 0.0, Pt, -1); else pWing->m_Surface[j].GetSurfacePoint(1.0, 1.0, 0.0, Pt, -1); glVertex3d(Pt.x, Pt.y, Pt.z); if(pFoilB->m_bTEFlap) pWing->m_Surface[j].GetSurfacePoint(pWing->m_Surface[j].m_pFoilB->m_TEXHinge/100.0, pWing->m_Surface[j].m_pFoilB->m_TEXHinge/100.0, 1.0, Pt, -1); else pWing->m_Surface[j].GetSurfacePoint(1.0, 1.0, 1.0, Pt, -1); glVertex3d(Pt.x, Pt.y, Pt.z); } glEnd(); } } for (j=0; jm_NSurfaces; j++) { pFoilA = pWing->m_Surface[j].m_pFoilA; pFoilB = pWing->m_Surface[j].m_pFoilB; if(pFoilA && pFoilB && pFoilA->m_bLEFlap && pFoilB->m_bLEFlap) { glBegin(GL_LINES); { if(pFoilA->m_bLEFlap) pWing->m_Surface[j].GetSurfacePoint(pWing->m_Surface[j].m_pFoilA->m_LEXHinge/100.0, pWing->m_Surface[j].m_pFoilA->m_LEXHinge/100.0, 0.0, Pt, 1); else pWing->m_Surface[j].GetSurfacePoint(1.0, 1.0, 0.0, Pt, 1); glVertex3d(Pt.x, Pt.y, Pt.z); if(pFoilB->m_bLEFlap) pWing->m_Surface[j].GetSurfacePoint(pWing->m_Surface[j].m_pFoilB->m_LEXHinge/100.0, pWing->m_Surface[j].m_pFoilB->m_LEXHinge/100.0, 1.0, Pt, 1); else pWing->m_Surface[j].GetSurfacePoint(1.0, 1.0, 1.0, Pt, 1); glVertex3d(Pt.x, Pt.y, Pt.z); } glEnd(); glBegin(GL_LINES); { if(pFoilA->m_bLEFlap) pWing->m_Surface[j].GetSurfacePoint(pWing->m_Surface[j].m_pFoilA->m_LEXHinge/100.0, pWing->m_Surface[j].m_pFoilA->m_LEXHinge/100.0, 0.0, Pt, -1); else pWing->m_Surface[j].GetSurfacePoint(1.0, 1.0, 0.0, Pt, -1); glVertex3d(Pt.x, Pt.y, Pt.z); if(pFoilB->m_bLEFlap) pWing->m_Surface[j].GetSurfacePoint(pWing->m_Surface[j].m_pFoilB->m_LEXHinge/100.0, pWing->m_Surface[j].m_pFoilB->m_LEXHinge/100.0, 1.0, Pt, -1); else pWing->m_Surface[j].GetSurfacePoint(1.0, 1.0, 1.0, Pt, -1); glVertex3d(Pt.x, Pt.y, Pt.z); } glEnd(); } } glDisable (GL_LINE_STIPPLE); glDisable(GL_DEPTH_TEST); } glEndList(); } void GLCreateCp(void *pQMiarex, CVector *pNode, Panel *pPanel, WingOpp *pWOpp, PlaneOpp *pPOpp) { QMiarex * pMiarex = (QMiarex*)pQMiarex; if((!pWOpp && !pPOpp) || !pPanel || !pNode || !pMiarex->m_MatSize) { glNewList(PANELCP,GL_COMPILE); glEndList(); return; } int p, pp, n, averageInf, averageSup, average100; int nPanels; double color; double lmin, lmax, range; float *tab; double *CpInf = new double[2*QMiarex::s_MaxMatSize]; double *CpSup = new double[2*QMiarex::s_MaxMatSize]; double *Cp100 = new double[2*QMiarex::s_MaxMatSize]; CVector LA,LB,TA,TB; glNewList(PANELCP, GL_COMPILE); { pMiarex->m_GLList++; glEnable(GL_DEPTH_TEST); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonOffset(1.0, 1.0); if(pPOpp) { tab = pPOpp->m_Cp; nPanels = pPOpp->m_NPanels; } else { tab = pWOpp->m_Cp; nPanels = pWOpp->m_NVLMPanels; } lmin = 10000.0; lmax = -10000.0; // find min and max Cp for scale set for (n=0; nm_nNodes; n++) { averageInf = 0; averageSup = 0; average100 = 0; CpInf[n] = 0.0; CpSup[n] = 0.0; Cp100[n] = 0.0; for (pp=0; pp< nPanels; pp++) { if (pNode[pPanel[pp].m_iLA].IsSame(pNode[n]) || pNode[pPanel[pp].m_iTA].IsSame(pNode[n]) || pNode[pPanel[pp].m_iTB].IsSame(pNode[n]) || pNode[pPanel[pp].m_iLB].IsSame(pNode[n])) { if(pPanel[pp].m_Pos==TOPSURFACE) { CpSup[n] +=tab[pp]; averageSup++; } else if(pPanel[pp].m_Pos<=MIDSURFACE) { CpInf[n] +=tab[pp]; averageInf++; } else if(pPanel[pp].m_Pos==BODYSURFACE) { Cp100[n] +=tab[pp]; average100++; } } } if(averageSup>0) { CpSup[n] /= averageSup; if(CpSup[n]0) { CpInf[n] /= averageInf; if(CpInf[n]0) { Cp100[n] /= average100; if(Cp100[n]s_bAutoCpScale) { pMiarex->s_LegendMin = lmin; pMiarex->s_LegendMax = lmax; } else { lmin = pMiarex->s_LegendMin; lmax = pMiarex->s_LegendMax; } range = lmax - lmin; glLineWidth(1.0); for (p=0; pm_MatSize; p++) { glBegin(GL_QUADS); { TA.Copy(pNode[pPanel[p].m_iTA]); TB.Copy(pNode[pPanel[p].m_iTB]); LA.Copy(pNode[pPanel[p].m_iLA]); LB.Copy(pNode[pPanel[p].m_iLB]); if(pPanel[p].m_Pos==TOPSURFACE) color = (CpSup[pPanel[p].m_iLA]-lmin)/range; else if(pPanel[p].m_Pos<=MIDSURFACE) color = (CpInf[pPanel[p].m_iLA]-lmin)/range; else color = (Cp100[pPanel[p].m_iLA]-lmin)/range; glColor3d(GLGetRed(color),GLGetGreen(color),GLGetBlue(color)); glVertex3d(LA.x, LA.y, LA.z); if(pPanel[p].m_Pos==TOPSURFACE) color = (CpSup[pPanel[p].m_iTA]-lmin)/range; else if(pPanel[p].m_Pos<=MIDSURFACE) color = (CpInf[pPanel[p].m_iTA]-lmin)/range; else color = (Cp100[pPanel[p].m_iTA]-lmin)/range; glColor3d(GLGetRed(color),GLGetGreen(color),GLGetBlue(color)); glVertex3d(TA.x, TA.y, TA.z); if(pPanel[p].m_Pos==TOPSURFACE) color = (CpSup[pPanel[p].m_iTB]-lmin)/range; else if(pPanel[p].m_Pos<=MIDSURFACE) color = (CpInf[pPanel[p].m_iTB]-lmin)/range; else color = (Cp100[pPanel[p].m_iTB]-lmin)/range; glColor3d(GLGetRed(color),GLGetGreen(color),GLGetBlue(color)); glVertex3d(TB.x, TB.y, TB.z); if(pPanel[p].m_Pos==TOPSURFACE) color = (CpSup[pPanel[p].m_iLB]-lmin)/range; else if(pPanel[p].m_Pos<=MIDSURFACE) color = (CpInf[pPanel[p].m_iLB]-lmin)/range; else color = (Cp100[pPanel[p].m_iLB]-lmin)/range; glColor3d(GLGetRed(color),GLGetGreen(color),GLGetBlue(color)); glVertex3d(LB.x, LB.y, LB.z); } glEnd(); } glDisable(GL_DEPTH_TEST); glDisable(GL_POLYGON_OFFSET_FILL); } glEndList(); delete [] CpInf; delete [] CpSup; delete [] Cp100; } void GLCreateCpLegendClr(void *pQMiarex) { int i; QMiarex *pMiarex = (QMiarex*)pQMiarex; QFont fnt(MainFrame::s_TextFont); //valgrind QFontMetrics fm(fnt); double fmw = (double) fm.averageCharWidth(); double fi, ZPos,dz,Right1, Right2; double color = 0.0; double w = (double)pMiarex->m_r3DCltRect.width(); double h = (double)pMiarex->m_r3DCltRect.height(); double XPos; if(w>h) { XPos = 1.0; dz = h/w /40.0; ZPos = h/w/10 - 12.0*dz; } else { XPos = w/h; dz = 1. /40.0; ZPos = 1./10 - 12.0*dz; } Right1 = XPos - 8 * fmw/w; Right2 = XPos - 3 * fmw/w; glNewList(WOPPCPLEGENDCLR,GL_COMPILE); { pMiarex->m_GLList++; glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glBegin(GL_QUAD_STRIP); { for (i=0; i<=20; i++) { fi = (double)i*dz; color += 0.05; glColor3d(GLGetRed(color),GLGetGreen(color),GLGetBlue(color)); glVertex3d(Right1, ZPos+fi*2, 0.0); glVertex3d(Right2, ZPos+fi*2, 0.0); } } glEnd(); } glEndList(); } void GLCreateDownwash(void *pQMiarex, Wing *pWing, WingOpp *pWOpp, int List) { // pWing is either the Wing, the stab, or the fin // pWOpp is related to the pWing QMiarex *pMiarex = (QMiarex*)pQMiarex; if(!pWing || !pWOpp) return; QColor color; int style, width; int i,j,k,p; double dih, xt, yt, zt, yob; double y1, y2, z1, z2, xs, ys, zs; CVector C; double factor, amp; double sina = -sin(pWOpp->m_Alpha*PI/180.0); double cosa = cos(pWOpp->m_Alpha*PI/180.0); factor = pMiarex->m_VelocityScale/100.0; //DOWNWASH glNewList(List,GL_COMPILE); { pMiarex->m_GLList++; glEnable (GL_LINE_STIPPLE); color = W3dPrefsDlg::s_DownwashColor; style = W3dPrefsDlg::s_DownwashStyle; width = W3dPrefsDlg::s_DownwashWidth; glColor3d(color.redF(), color.greenF(), color.blueF()); glLineWidth((GLfloat)width); if (style == 1) glLineStipple (1, 0xCFCF); else if(style == 2) glLineStipple (1, 0x6666); else if(style == 3) glLineStipple (1, 0xFF18); else if(style == 4) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); if(pWOpp) { if(pWOpp->m_AnalysisMethod==LLTMETHOD) { for (i=1; im_NStation; i++) { yob = 2.0*pWOpp->m_SpanPos[i]/pWOpp->m_Span; xt = pWing->Offset(yob) + pWing->Chord(yob); pWing->GetViewYZPos(1., pWOpp->m_SpanPos[i], yt,zt,0); dih = -pWing->Dihedral(yob)*PI/180.0; amp = pWOpp->m_QInf*sin(pWOpp->m_Ai[i]*PI/180.0); amp *= factor; glBegin(GL_LINES); { glVertex3d(xt, yt, zt); glVertex3d(xt + amp * cos(dih)* sina, yt + amp * sin(dih), zt + amp * cos(dih)* cosa); } glEnd(); } glBegin(GL_LINE_STRIP); { for (i=1; im_NStation; i++) { yob = 2.0*pWOpp->m_SpanPos[i]/pWOpp->m_Span; xt = pWing->Offset(yob) + pWing->Chord(yob); pWing->GetViewYZPos(1., pWOpp->m_SpanPos[i], yt,zt,0); dih = -pWing->Dihedral(yob)*PI/180.0; amp = pWOpp->m_QInf*sin(pWOpp->m_Ai[i]*PI/180.0); amp *= factor; glVertex3d(xt + amp * cos(dih)* sina, yt + amp * sin(dih), zt + amp * cos(dih)* cosa); } } glEnd(); } else { p = 0; i = 0; for (j=0; jm_NSurfaces; j++) { for (k=0; k< pWing->m_Surface[j].m_NYPanels; k++) { // m_pSurface[j+surf0]->GetTrailingPt(k, C); pWing->m_Surface[j].GetTrailingPt(k, C); // if (pWOpp->m_Vd[i].z>0) sign = 1.0; else sign = -1.0; glBegin(GL_LINES); { glVertex3d(C.x, C.y, C.z); glVertex3d(C.x+factor*pWOpp->m_Vd[i].z * sina, C.y+factor*pWOpp->m_Vd[i].y, C.z+factor*pWOpp->m_Vd[i].z * cosa); } glEnd(); xs = C.x+factor*pWOpp->m_Vd[i].z*sina; ys = C.y+factor*pWOpp->m_Vd[i].y; zs = C.z+factor*pWOpp->m_Vd[i].z*cosa; y1 = ys - 0.085*factor*pWOpp->m_Vd[i].y + 0.05*factor*pWOpp->m_Vd[i].z*cosa; z1 = zs - 0.085*factor*pWOpp->m_Vd[i].z*cosa - 0.05*factor*pWOpp->m_Vd[i].y; y2 = ys - 0.085*factor*pWOpp->m_Vd[i].y - 0.05*factor*pWOpp->m_Vd[i].z*cosa; z2 = zs - 0.085*factor*pWOpp->m_Vd[i].z*cosa + 0.05*factor*pWOpp->m_Vd[i].y; glBegin(GL_LINES); { glVertex3d(xs, ys, zs); glVertex3d(xs, y1, z1); } glEnd(); glBegin(GL_LINES); { glVertex3d(xs, ys, zs); glVertex3d(xs, y2, z2); } glEnd(); i++; } p++; } } } glDisable (GL_LINE_STIPPLE); } glEndList(); } void GLCreateDrag(void *pQMiarex, Wing *pWing, WPolar* pWPolar, WingOpp *pWOpp, int List) { if(!pWing || !pWPolar || !pWOpp) return; CVector C; int i,j,k; int Istyle, Iwidth, Vstyle, Vwidth; QColor Icolor, Vcolor; QMiarex * pMiarex = (QMiarex*)pQMiarex; double coef = 5.0; GLushort IDash, VDash; static double Ir,Ig,Ib, Vr, Vg, Vb; static double amp, amp1, amp2; static double yob, xt, yt, zt, dih; static double cosa, cosb, sina, sinb; cosa = cos(pWOpp->m_Alpha * PI/180.0); sina = -sin(pWOpp->m_Alpha * PI/180.0); cosb = cos(pWPolar->sideSlip()*PI/180.0); sinb = sin(pWPolar->sideSlip()*PI/180.0); Icolor = W3dPrefsDlg::s_IDragColor; Istyle = W3dPrefsDlg::s_IDragStyle; Iwidth = W3dPrefsDlg::s_IDragWidth; Vcolor = W3dPrefsDlg::s_VDragColor; Vstyle = W3dPrefsDlg::s_VDragStyle; Vwidth = W3dPrefsDlg::s_VDragWidth; if (Istyle == 1) IDash = 0xCFCF; else if(Istyle == 2) IDash = 0x6666; else if(Istyle == 3) IDash = 0xFF18; else if(Istyle == 4) IDash = 0x7E66; else IDash = 0xFFFF; if (Vstyle == 1) VDash = 0xCFCF; else if(Vstyle == 2) VDash = 0x6666; else if(Vstyle == 3) VDash = 0xFF18; else if(Vstyle == 4) VDash = 0x7E66; else VDash = 0xFFFF; Ir = Icolor.redF(); Ig = Icolor.greenF(); Ib = Icolor.blueF(); Vr = Vcolor.redF(); Vg = Vcolor.greenF(); Vb = Vcolor.blueF(); //DRAGLINE glNewList(List,GL_COMPILE); { pMiarex->m_GLList++; glEnable (GL_LINE_STIPPLE); glLineStipple (1, IDash);// Solid glLineWidth((GLfloat)(Iwidth)); // glPolygonMode(GL_FRONT,GL_LINE); double q0 = 0.5 * pWPolar->m_Density * pWPolar->m_WArea * pWOpp->m_QInf * pWOpp->m_QInf; if(pWOpp) { if(pWOpp->m_AnalysisMethod==LLTMETHOD) { for (i=1; im_NStation; i++) { yob = 2.0*pWOpp->m_SpanPos[i]/pWOpp->m_Span; xt = pWing->Offset(yob) + pWOpp->m_Chord[i]; pWing->GetViewYZPos(1.0, pWOpp->m_SpanPos[i],yt,zt,0); dih = pWing->Dihedral(yob)*PI/180.0; amp1 = q0*pWOpp->m_ICd[i]*pWOpp->m_Chord[i]/pWOpp->m_MAChord*pMiarex->m_DragScale/coef; amp2 = q0*pWOpp->m_PCd[i]*pWOpp->m_Chord[i]/pWOpp->m_MAChord*pMiarex->m_DragScale/coef; if(pMiarex->m_bICd) { glColor3f((GLfloat)Ir,(GLfloat)Ig,(GLfloat)Ib); glLineStipple (1, IDash);// Solid glLineWidth((GLfloat)(Iwidth)); glBegin(GL_LINES); { glVertex3d(xt, yt, zt); glVertex3d( xt + amp1 * cos(dih)*cosa, yt, zt - amp1 * cos(dih)*sina); } glEnd(); } if(pMiarex->m_bVCd) { glColor3f((GLfloat)Vr,(GLfloat)Vg,(GLfloat)Vb); glLineStipple (1, VDash);// Solid glLineWidth((GLfloat)(Vwidth)); glBegin(GL_LINES); { if(!pMiarex->m_bICd) { glVertex3d(xt, yt,zt); glVertex3d(xt + amp2 * cos(dih)*cosa, yt, zt - amp2 * cos(dih)*sina); } else { glVertex3d(xt + amp1 * cos(dih)*cosa, yt, zt - amp1 * cos(dih)*sina); glVertex3d(xt + (amp1+amp2) * cos(dih)*cosa, yt, zt - (amp1+amp2) * cos(dih)*sina); } } glEnd(); } } if(pMiarex->m_bICd) { glColor3f((GLfloat)Ir,(GLfloat)Ig,(GLfloat)Ib); glLineStipple (1, IDash);// Solid glLineWidth((GLfloat)(Iwidth)); glBegin(GL_LINE_STRIP); { for (i=1; im_NStation; i++) { yob = 2.0*pWOpp->m_SpanPos[i]/pWOpp->m_Span; xt = pWing->Offset(yob) + pWOpp->m_Chord[i]; pWing->GetViewYZPos(1.0, pWOpp->m_SpanPos[i],yt,zt,0); dih = pWing->Dihedral(yob)*PI/180.0; amp = q0*pWOpp->m_ICd[i]*pWOpp->m_Chord[i]/pWOpp->m_MAChord; amp *= pMiarex->m_DragScale/coef; glVertex3d(xt + amp * cos(dih)*cosa, yt, zt - amp * cos(dih)*sina); } } glEnd(); } if(pMiarex->m_bVCd) { glColor3f((GLfloat)Vr,(GLfloat)Vg,(GLfloat)Vb); glLineStipple (1, VDash);// Solid glLineWidth((GLfloat)(Vwidth)); glBegin(GL_LINE_STRIP); { for (i=1; im_NStation; i++) { yob = 2.0*pWOpp->m_SpanPos[i]/pWOpp->m_Span; xt = pWing->Offset(yob) + pWOpp->m_Chord[i]; pWing->GetViewYZPos(1.0, pWOpp->m_SpanPos[i],yt,zt,0); dih = pWing->Dihedral(yob)*PI/180.0; amp=0.0; if(pMiarex->m_bICd) amp+=pWOpp->m_ICd[i]; amp +=pWOpp->m_PCd[i]; amp *= q0*pWOpp->m_Chord[i]/pWOpp->m_MAChord; amp *= pMiarex->m_DragScale/coef; glVertex3d( xt + amp * cos(dih)*cosa, yt , zt - amp * cos(dih)*sina); } } glEnd(); } } else { //VLM type drag i = 0; for (j=0; jm_NSurfaces; j++) { //All surfaces for (k=0; k< pWing->m_Surface[j].m_NYPanels; k++) { pWing->m_Surface[j].GetTrailingPt(k, C); amp1 = q0*pWOpp->m_ICd[i]*pWOpp->m_Chord[i]/pWing->m_MAChord*pMiarex->m_DragScale/coef; amp2 = q0*pWOpp->m_PCd[i]*pWOpp->m_Chord[i]/pWing->m_MAChord*pMiarex->m_DragScale/coef; if(pMiarex->m_bICd) { glColor3f((GLfloat)Ir,(GLfloat)Ig,(GLfloat)Ib); glLineStipple (1, IDash);// Solid glLineWidth((GLfloat)(Iwidth)); glBegin(GL_LINES); { glVertex3d(C.x, C.y, C.z); glVertex3d(C.x + amp1*cosa * cosb, C.y + amp1*cosa * sinb, C.z - amp1*sina); } glEnd(); } if(pMiarex->m_bVCd) { glColor3f((GLfloat)Vr,(GLfloat)Vg,(GLfloat)Vb); glLineStipple (1, VDash);// Solid glLineWidth((GLfloat)(Vwidth)); glBegin(GL_LINES); { if(!pMiarex->m_bICd) { glVertex3d(C.x, C.y, C.z); glVertex3d(C.x + amp2*cosa*cosb, C.y + amp2*cosa*sinb, C.z - amp2*sina); } else { glVertex3d(C.x + amp1*cosa*cosb, C.y + amp1*cosa*sinb, C.z - amp1*sina); glVertex3d(C.x + (amp1+amp2)*cosa*cosb, C.y + (amp1+amp2)*cosa*sinb, C.z - (amp1+amp2)*sina); } } glEnd(); } i++; } } if(!pWing->IsFin()) { if(pMiarex->m_bICd) { glColor3f((GLfloat)Ir,(GLfloat)Ig,(GLfloat)Ib); glLineStipple (1, IDash);// Solid glLineWidth((GLfloat)(Iwidth)); glBegin(GL_LINE_STRIP); { i = 0; for (j=0; jm_NSurfaces; j++) { for (k=0; k< pWing->m_Surface[j].m_NYPanels; k++) { pWing->m_Surface[j].GetTrailingPt(k, C); amp = q0*(pWOpp->m_ICd[i])*pWOpp->m_Chord[i]/pWing->m_MAChord; amp *= pMiarex->m_DragScale/coef; glVertex3d(C.x + amp*cosa*cosb, C.y + amp*cosa*sinb, C.z - amp*sina); i++; } } } glEnd(); } if(pMiarex->m_bVCd) { glColor3f((GLfloat)Vr,(GLfloat)Vg,(GLfloat)Vb); glLineStipple (1, VDash);// Solid glLineWidth((GLfloat)(Vwidth)); glBegin(GL_LINE_STRIP); { i = 0; for (j=0; jm_NSurfaces; j++) { for (k=0; k< pWing->m_Surface[j].m_NYPanels; k++) { pWing->m_Surface[j].GetTrailingPt(k, C); amp=0.0; if(pMiarex->m_bICd) amp+=pWOpp->m_ICd[i]; amp +=pWOpp->m_PCd[i]; amp *= q0*pWOpp->m_Chord[i]/pWing->m_MAChord; amp *= pMiarex->m_DragScale/coef; glVertex3d(C.x + amp*cosa*cosb, C.y + amp*cosa*sinb, C.z - amp*sina); i++; } } } glEnd(); } } else { if(pMiarex->m_bICd) { glColor3f((GLfloat)Ir,(GLfloat)Ig,(GLfloat)Ib); glLineStipple (1, IDash);// Solid glLineWidth((GLfloat)Iwidth); i = 0; for (j=0; jm_NSurfaces; j++) { glBegin(GL_LINE_STRIP); { for (k=0; k< pWing->m_Surface[j].m_NYPanels; k++) { pWing->m_Surface[j].GetTrailingPt(k, C); amp = q0*(pWOpp->m_ICd[i])*pWOpp->m_Chord[i]/pWing->m_MAChord; amp *= pMiarex->m_DragScale/coef; glVertex3d(C.x + amp*cosa*cosb, C.y + amp*cosa*sinb, C.z - amp*sina); i++; } } glEnd(); } } if(pMiarex->m_bVCd) { glColor3f((GLfloat)Vr,(GLfloat)Vg,(GLfloat)Vb); glLineStipple (1, VDash);// Solid glLineWidth((GLfloat)Vwidth); i = 0; for (j=0; jm_NSurfaces; j++) { glBegin(GL_LINE_STRIP); { for (k=0; k< pWing->m_Surface[j].m_NYPanels; k++) { pWing->m_Surface[j].GetTrailingPt(k, C); amp=0.0; if(pMiarex->m_bICd) amp+=pWOpp->m_ICd[i]; amp +=pWOpp->m_PCd[i]; amp *= q0*pWOpp->m_Chord[i]/pWing->m_MAChord; amp *= pMiarex->m_DragScale/coef; glVertex3d(C.x + amp*cosa*cosb, C.y + amp*cosa*sinb, C.z - amp*sina); i++; } } glEnd(); } } } } } glDisable (GL_LINE_STIPPLE); } glEndList(); } void GLCreateMesh(int iList, int size, Panel *pPanel, CVector *pNode, QColor PanelColor, QColor BackColor, bool bBack) { if(!pPanel || !pNode) { glNewList(iList, GL_COMPILE); glEndList(); return; } int iLA, iLB, iTA, iTB; int p; CVector N; N.Set(0.0, 0.0, 0.0); glNewList(iList, GL_COMPILE); { glDisable(GL_LINE_STIPPLE); glEnable(GL_DEPTH_TEST); // glEnable(GL_POLYGON_OFFSET_LINE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // glPolygonOffset(1.0, 1.0); glLineWidth(1.0); glColor3d(PanelColor.redF(),PanelColor.greenF(),PanelColor.blueF()); for (p=0; pm_MatSize) { glNewList(VLMCTRLPTS, GL_COMPILE); glEndList(); return; } glNewList(VLMCTRLPTS,GL_COMPILE); { pMiarex->m_GLList++; glLineWidth(1.0); glColor3d(0.0,1.0,0.0); for (int p=0; pm_MatSize; p++) { //All panels glBegin(GL_LINES); { glVertex3d(pPanel[p].CtrlPt.x, pPanel[p].CtrlPt.y, pPanel[p].CtrlPt.z); glVertex3d((pPanel[p].CtrlPt.x + pPanel[p].Normal.x * 0.04), (pPanel[p].CtrlPt.y + pPanel[p].Normal.y * 0.04), (pPanel[p].CtrlPt.z + pPanel[p].Normal.z * 0.04)); } glEnd(); } } glEndList(); } void GLCreateVortices(void *pQMiarex, Panel *pPanel, CVector *pNode, WPolar *pWPolar) { QMiarex * pMiarex = (QMiarex*)pQMiarex; if(!pNode || !pPanel || !pMiarex->m_MatSize) { glNewList(VLMVORTICES, GL_COMPILE); glEndList(); return; } int p; CVector A, B, C, D, AC, BD; glNewList(VLMVORTICES,GL_COMPILE); { pMiarex->m_GLList++; glEnable (GL_LINE_STIPPLE); glLineStipple (1, 0xFFFF); glLineWidth(1.0); glColor3d(0.7,0.0,0.0); for (p=0; pm_MatSize; p++) { if(!pPanel[p].m_bIsTrailing) { if(pPanel[p].m_Pos<=MIDSURFACE) { A = pPanel[p].VA; B = pPanel[p].VB; C = pPanel[p-1].VB; D = pPanel[p-1].VA; } else { A = pPanel[p].VA; B = pPanel[p].VB; C = pPanel[p+1].VB; D = pPanel[p+1].VA; } } else { A = pPanel[p].VA; B = pPanel[p].VB; // we define point AA=A+1 and BB=B+1 C.x = pNode[pPanel[p].m_iTB].x + (pNode[pPanel[p].m_iTB].x-pPanel[p].VB.x)/3.0; C.y = pNode[pPanel[p].m_iTB].y; C.z = pNode[pPanel[p].m_iTB].z; D.x = pNode[pPanel[p].m_iTA].x + (pNode[pPanel[p].m_iTA].x-pPanel[p].VA.x)/3.0; D.y = pNode[pPanel[p].m_iTA].y; D.z = pNode[pPanel[p].m_iTA].z; } //next we "shrink" the points to avoid confusion with panels sides AC = C-A; BD = D-B; AC *= 0.03; A += AC; C -= AC; BD *= 0.03; B += BD; D -= BD; if(pWPolar && pWPolar->m_bVLM1) { glLineStipple (1, 0xFFFF); glBegin(GL_LINES); { glVertex3d(A.x, A.y, A.z); glVertex3d(B.x, B.y, B.z); } glEnd(); glLineStipple (1, 0x0F0F); glBegin(GL_LINES); { glVertex3d(A.x, A.y, A.z); glVertex3d(D.x, D.y, D.z); } glEnd(); glBegin(GL_LINES); { glVertex3d(B.x, B.y, B.z); glVertex3d(C.x, C.y, C.z); } glEnd(); } else if(!pWPolar || (pWPolar && !pWPolar->m_bVLM1)) { glBegin(GL_LINE_STRIP); { glVertex3d(A.x, A.y, A.z); glVertex3d(B.x, B.y, B.z); glVertex3d(C.x, C.y, C.z); glVertex3d(D.x, D.y, D.z); glVertex3d(A.x, A.y, A.z); } glEnd(); } } glDisable (GL_LINE_STIPPLE); } glEndList(); } void GLCreateLiftForce(void *pQMiarex, WPolar *pWPolar, WingOpp *pWOpp) { if(!pWPolar || !pWOpp) return; int style; double forcez,forcex,glx, gly, glz; double sign; QMiarex * pMiarex = (QMiarex*)pQMiarex; glNewList(LIFTFORCE, GL_COMPILE); { pMiarex->m_GLList++; glEnable (GL_LINE_STIPPLE); style = W3dPrefsDlg::s_XCPStyle; if (style == 1) glLineStipple (1, 0xCFCF); else if(style == 2) glLineStipple (1, 0x6666); else if(style == 3) glLineStipple (1, 0xFF18); else if(style == 4) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glColor3d(W3dPrefsDlg::s_XCPColor.redF(),W3dPrefsDlg::s_XCPColor.greenF(),W3dPrefsDlg::s_XCPColor.blueF()); //Resulting force vector glLineWidth((GLfloat)(W3dPrefsDlg::s_XCPWidth * 2.0)); double force = 0.5*pWPolar->m_Density * pWPolar->m_WArea *pWOpp->m_QInf*pWOpp->m_QInf *pWOpp->m_CL; force *= pMiarex->m_LiftScale/500.0; forcez = force * cos(pWOpp->m_Alpha * PI/180.0); forcex = -force * sin(pWOpp->m_Alpha * PI/180.0); if (force>0.0) sign = 1.0; else sign = -1.0; glLineStipple (1, 0xFFFF);// Solid glLineWidth(3.0); glx = (GLfloat)pWOpp->m_CP.x; gly = (GLfloat)pWOpp->m_CP.y; glz = (GLfloat)pWOpp->m_CP.z; glBegin(GL_LINES); glVertex3d(glx,gly,glz); glVertex3d(glx+forcex,gly,glz+forcez); glEnd(); glBegin(GL_LINES); glVertex3d(glx+forcex, gly, glz+forcez); //glVertex3d(glx+forcex+0.008, gly+0.008, glz+forcez-0.012*sign/pMiarex->m_glScaled); glVertex3d(glx+forcex+0.008, gly+0.008, glz+forcez-0.012*sign); glEnd(); glBegin(GL_LINES); glVertex3d(glx+forcex, gly, glz+forcez); //glVertex3d(glx+forcex-0.008, gly-0.008, glz+forcez-0.012*sign/pMiarex->m_glScaled); glVertex3d(glx+forcex-0.008, gly-0.008, glz+forcez-0.012*sign); glEnd(); glDisable (GL_LINE_STIPPLE); } glEndList(); } void GLCreateMoments(void *pQMiarex, Wing *pWing, WPolar *pWPolar, WingOpp *pWOpp) { // The most common aeronautical convention defines // - the roll as acting about the longitudinal axis, positive with the starboard wing down. // - The yaw is about the vertical body axis, positive with the nose to starboard. // - Pitch is about an axis perpendicular to the longitudinal plane of symmetry, positive nose up. // -- Wikipedia flight dynamics -- if(!pWing || !pWPolar || !pWOpp) return; int i; int style, width; QColor color; double sign, amp, radius; double angle=0.0;//radian double endx, endy, endz, dx, dy, dz,xae, yae, zae; double factor = 10.0; QMiarex * pMiarex = (QMiarex*)pQMiarex; // MainFrame *pMainFrame = (MainFrame*)pMiarex->m_pMainFrame; glNewList(VLMMOMENTS, GL_COMPILE); { pMiarex->m_GLList++; glEnable (GL_LINE_STIPPLE); color = W3dPrefsDlg::s_MomentColor; style = W3dPrefsDlg::s_MomentStyle; width = W3dPrefsDlg::s_MomentWidth; if (style == 1) glLineStipple (1, 0xCFCF); else if(style == 2) glLineStipple (1, 0x6666); else if(style == 3) glLineStipple (1, 0xFF18); else if(style == 4) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glColor3d(color.redF(),color.greenF(),color.blueF()); glLineWidth((GLfloat)(width*2.0)); amp = 0.5*pWPolar->m_Density * pWPolar->m_WArea * pWPolar->m_WSpan *pWOpp->m_QInf*pWOpp->m_QInf *pWOpp->m_GCm/3.0; amp *= pMiarex->m_LiftScale*factor; radius= pWing->m_PlanformSpan/4.0; if (amp>0.0) sign = -1.0; else sign = 1.0; glBegin(GL_LINE_STRIP); { for (i=0; i<=int(qAbs(amp)); i++) { angle = sign*(double)i/500.0*PI; glVertex3d(radius*cos(angle),0.0,radius*sin(angle)); } } glEnd(); endx = radius*cos(angle); endz = radius*sin(angle); dx = 0.03; dz = 0.03*sign; xae = (radius-dx)*cos(angle) +dz *sin(angle); zae = (radius-dx)*sin(angle) -dz *cos(angle); glBegin(GL_LINES); { glVertex3d(endx, 0.0, endz); glVertex3d(xae, 0.0, zae); } glEnd(); xae = (radius+dx)*cos(angle) +dz *sin(angle); zae = (radius+dx)*sin(angle) -dz *cos(angle); glBegin(GL_LINES); { glVertex3d(endx, 0.0, endz); glVertex3d(xae, 0.0, zae); } glEnd(); //Resulting Rolling Moment Arc vector amp = 0.5*pWPolar->m_Density * pWPolar->m_WArea * pWPolar->m_WMAChord *pWOpp->m_QInf*pWOpp->m_QInf *pWOpp->m_GRm/3.0; amp *= pMiarex->m_LiftScale*factor; if (amp>0.0) sign = -1.0; else sign = 1.0; glBegin(GL_LINE_STRIP); for (i=0; i<=int(qAbs(amp)); i++) { angle = sign*(double)i/500.0*PI; glVertex3d(0.0,radius*cos(angle),radius*sin(angle)); } glEnd(); endy = radius*cos(angle); endz = radius*sin(angle); dy = 0.03; dz = 0.03*sign; yae = (radius-dy)*cos(angle) +dz *sin(angle); zae = (radius-dy)*sin(angle) -dz *cos(angle); glBegin(GL_LINES); glVertex3d(0.0, endy, endz); glVertex3d(0.0, yae, zae); glEnd(); yae = (radius+dy)*cos(angle) +dz *sin(angle); zae = (radius+dy)*sin(angle) -dz *cos(angle); glBegin(GL_LINES); glVertex3d(0.0, endy, endz); glVertex3d(0.0, yae, zae); glEnd(); //Resulting Yawing Moment Arc vector amp = 0.5*pWPolar->m_Density * pWPolar->m_WArea * pWPolar->m_WSpan *pWOpp->m_QInf*pWOpp->m_QInf *(pWOpp->m_GYm)/3.0; amp *= pMiarex->m_LiftScale*factor; if (amp>0.0) sign = -1.0; else sign = 1.0; glBegin(GL_LINE_STRIP); { for (i=0; i<=int(qAbs(amp)); i++) { angle = sign*(double)i/500.0*PI; glVertex3d(-radius*cos(angle),-radius*sin(angle),0.0); } } glEnd(); endx = -radius*cos(angle); endy = -radius*sin(angle); dx = 0.03; dy = -0.03*sign; xae = (-radius+dx)*cos(angle) +dy *sin(angle); yae = (-radius+dx)*sin(angle) -dy *cos(angle); glBegin(GL_LINES); { glVertex3d(endx, endy, 0.0); glVertex3d(xae, yae, 0.0); } glEnd(); xae = (-radius-dx)*cos(angle) +dy *sin(angle); yae = (-radius-dx)*sin(angle) -dy *cos(angle); glBegin(GL_LINES); { glVertex3d(endx, endy, 0.0); glVertex3d(xae, yae, 0.0); } glEnd(); glDisable (GL_LINE_STIPPLE); } glEndList(); } void GLCreateLiftStrip(void *pQMiarex, Wing *pWing, WPolar *pWPolar, WingOpp *pWOpp, int List) { if(!pWing || !pWPolar || !pWOpp) return; int i,j,k; int style, width; CVector C, CL; QColor color; double amp, yob, xt, yt, zt, dih; double cosa = cos(pWOpp->m_Alpha * PI/180.0); double sina = -sin(pWOpp->m_Alpha * PI/180.0); QMiarex * pMiarex = (QMiarex*)pQMiarex; //LIFTLINE glNewList(List,GL_COMPILE); { pMiarex->m_GLList++; glEnable (GL_LINE_STIPPLE); color = W3dPrefsDlg::s_XCPColor; style = W3dPrefsDlg::s_XCPStyle; width = W3dPrefsDlg::s_XCPWidth; if (style == 1) glLineStipple (1, 0xCFCF); else if(style == 2) glLineStipple (1, 0x6666); else if(style == 3) glLineStipple (1, 0xFF18); else if(style == 4) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glColor3d(color.redF(), color.greenF(), color.blueF()); glLineWidth((GLfloat)width); //dynamic pressure x area double q0 = 0.5 * pWPolar->m_Density * pWOpp->m_QInf * pWOpp->m_QInf; if(pWOpp) { if(pWOpp->m_AnalysisMethod==LLTMETHOD) { for (i=1; im_NStation; i++) { yob = 2.0*pWOpp->m_SpanPos[i]/pWOpp->m_Span; xt = pWing->Offset(yob) + pWOpp->m_XCPSpanRel[i]*pWOpp->m_Chord[i]; pWing->GetViewYZPos(pWOpp->m_XCPSpanRel[i], pWOpp->m_SpanPos[i], yt, zt, 0); dih = -pWing->Dihedral(yob)*PI/180.0; amp = q0*pWOpp->m_Cl[i]*pWOpp->m_Chord[i]/pWOpp->m_MAChord; amp *= pMiarex->m_LiftScale/1000.0; glBegin(GL_LINES); { glVertex3d(xt, yt, zt); glVertex3d((xt + amp * cos(dih)*sina), yt + amp * sin(dih), zt + amp * cos(dih)*cosa); } glEnd(); } glBegin(GL_LINE_STRIP); { for (i=1; im_NStation; i++) { yob = 2.0*pWOpp->m_SpanPos[i]/pWOpp->m_Span; xt = pWing->Offset(yob) + pWOpp->m_XCPSpanRel[i]*pWOpp->m_Chord[i]; pWing->GetViewYZPos(pWOpp->m_XCPSpanRel[i], pWOpp->m_SpanPos[i],yt,zt,0); dih = -pWing->Dihedral(yob)*PI/180.0; amp = q0*pWOpp->m_Cl[i]*pWOpp->m_Chord[i]/pWOpp->m_MAChord; amp *= pMiarex->m_LiftScale/1000.0; glVertex3d(xt + amp * cos(dih)*sina, yt + amp * sin(dih), zt + amp * cos(dih)*cosa); } } glEnd(); } else { i = 0; for (j=0; jm_NSurfaces; j++) { for (k=0; k< pWing->m_Surface[j].m_NYPanels; k++) { pWing->m_Surface[j].GetLeadingPt(k, C); amp = pWOpp->m_Chord[i] / pWOpp->m_StripArea[i] / pWing->m_MAChord * pMiarex->m_LiftScale/1000.0; C.x += pWOpp->m_XCPSpanRel[i] * pWing->m_Surface[j].GetChord(k); glBegin(GL_LINES); { glVertex3d(C.x, C.y, C.z); glVertex3d(C.x + pWOpp->m_F[i].x*amp,//F is in Body axes C.y + pWOpp->m_F[i].y*amp, C.z + pWOpp->m_F[i].z*amp); } glEnd(); i++; } } //Lift strip on each surface i = 0; for (j=0; jm_NSurfaces; j++) { if(j>0 && pWing->m_Surface[j-1].m_bJoinRight) { //then connect strip to previous surface's last point glBegin(GL_LINES); { glVertex3d(CL.x, CL.y, CL.z); k=0; pWing->m_Surface[j].GetLeadingPt(k, C); amp = pWOpp->m_Chord[i] / pWOpp->m_StripArea[i] / pWing->m_MAChord * pMiarex->m_LiftScale/1000.0; C.x += pWOpp->m_XCPSpanRel[i] * pWing->m_Surface[j].GetChord(k); glVertex3d(C.x + pWOpp->m_F[i].x*amp, C.y + pWOpp->m_F[i].y*amp, C.z + pWOpp->m_F[i].z*amp); } glEnd(); } glBegin(GL_LINE_STRIP); { for (k=0; k< pWing->m_Surface[j].m_NYPanels; k++) { pWing->m_Surface[j].GetLeadingPt(k, C); amp = pWOpp->m_Chord[i] / pWOpp->m_StripArea[i] / pWing->m_MAChord * pMiarex->m_LiftScale/1000.0; C.x += pWOpp->m_XCPSpanRel[i] * pWing->m_Surface[j].GetChord(k); CL.x = C.x + pWOpp->m_F[i].x*amp; CL.y = C.y + pWOpp->m_F[i].y*amp; CL.z = C.z + pWOpp->m_F[i].z*amp; glVertex3d(CL.x, CL.y, CL.z); i++; } } glEnd(); } } } glDisable (GL_LINE_STIPPLE); } glEndList(); } void GLCreateTrans(void *pQMiarex, Wing *pWing, WingOpp *pWOpp, int List) { if(!pWing || !pWOpp) return; int i,j,k,m, style; double yrel, xt, yt, zt, yob ; CVector Pt; QMiarex*pMiarex = (QMiarex*)pQMiarex; //TOP TRANSITION glNewList(List,GL_COMPILE); { pMiarex->m_GLList++; glEnable (GL_LINE_STIPPLE); style = W3dPrefsDlg::s_TopStyle; if (style == 1) glLineStipple (1, 0xCFCF); else if(style == 2) glLineStipple (1, 0x6666); else if(style == 3) glLineStipple (1, 0xFF18); else if(style == 4) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glColor3d(W3dPrefsDlg::s_TopColor.redF(),W3dPrefsDlg::s_TopColor.greenF(),W3dPrefsDlg::s_TopColor.blueF()); glLineWidth((GLfloat)W3dPrefsDlg::s_TopWidth); if(pWOpp) { if(pWOpp->m_AnalysisMethod==LLTMETHOD) { glBegin(GL_LINE_STRIP); { for (i=1; im_NStation; i++) { yob = 2.0*pWOpp->m_SpanPos[i]/pWOpp->m_Span; xt = pWing->Offset(yob) + pWOpp->m_XTrTop[i]*pWOpp->m_Chord[i]; pWing->GetViewYZPos(pWOpp->m_XTrTop[i], pWOpp->m_SpanPos[i],yt,zt,0); glVertex3d(xt,yt,zt); } } glEnd(); } else { if(!pWing->IsFin()) { glBegin(GL_LINE_STRIP); { m = 0; for(j=0; jm_NSurfaces; j++) { for(k=0; km_Surface[j].m_NYPanels; k++) { yrel = pWing->yrel(pWOpp->m_SpanPos[m]); pWing->m_Surface[j].GetSurfacePoint(pWOpp->m_XTrTop[m],pWOpp->m_XTrTop[m],yrel,Pt,1); glVertex3d(Pt.x, Pt.y, Pt.z); m++; } } } glEnd(); } else { m = 0; for(j=0; jm_NSurfaces; j++) { glBegin(GL_LINE_STRIP); { for(k=0; km_Surface[j].m_NYPanels; k++) { yrel = pWing->yrel(pWOpp->m_SpanPos[m]); pWing->m_Surface[j].GetSurfacePoint(pWOpp->m_XTrTop[m],pWOpp->m_XTrTop[m],yrel,Pt,1); glVertex3d(Pt.x, Pt.y, Pt.z); m++; } } glEnd(); } } } } glDisable (GL_LINE_STIPPLE); } glEndList(); //BOTTOM TRANSITION glNewList(List+MAXWINGS,GL_COMPILE); { pMiarex->m_GLList++; glEnable (GL_LINE_STIPPLE); style = W3dPrefsDlg::s_BotStyle; if (style == 1) glLineStipple (1, 0xCFCF); else if(style == 2) glLineStipple (1, 0x6666); else if(style == 3) glLineStipple (1, 0xFF18); else if(style == 4) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glColor3d(W3dPrefsDlg::s_BotColor.redF(),W3dPrefsDlg::s_BotColor.greenF(),W3dPrefsDlg::s_BotColor.blueF()); glLineWidth((GLfloat)W3dPrefsDlg::s_BotWidth); if(pWOpp) { if(pWOpp->m_AnalysisMethod==LLTMETHOD) { glBegin(GL_LINE_STRIP); { for (i=1; im_NStation; i++) { yob = 2.0*pWOpp->m_SpanPos[i]/pWOpp->m_Span; xt = pWing->Offset(yob) + pWOpp->m_XTrBot[i]*pWOpp->m_Chord[i]; pWing->GetViewYZPos(pWOpp->m_XTrBot[i], pWOpp->m_SpanPos[i],yt,zt,0); glVertex3d(xt,yt, zt); } } glEnd(); } else { if(!pWing->IsFin()) { glBegin(GL_LINE_STRIP); { int m = 0; for(j=0; jm_NSurfaces; j++) { for(k=0; km_Surface[j].m_NYPanels; k++) { yrel = pWing->yrel(pWOpp->m_SpanPos[m]); pWing->m_Surface[j].GetSurfacePoint(pWOpp->m_XTrBot[m],pWOpp->m_XTrBot[m],yrel,Pt,-1); glVertex3d(Pt.x, Pt.y, Pt.z); m++; } } } glEnd(); } else { int m = 0; for(j=0; jm_NSurfaces; j++) { glBegin(GL_LINE_STRIP); { for(k=0; km_Surface[j].m_NYPanels; k++) { yrel = pWing->yrel(pWOpp->m_SpanPos[m]); pWing->m_Surface[j].GetSurfacePoint(pWOpp->m_XTrBot[m],pWOpp->m_XTrBot[m],yrel,Pt,-1); glVertex3d(Pt.x, Pt.y, Pt.z); m++; } } glEnd(); } } } } glDisable (GL_LINE_STIPPLE); } glEndList(); } void GLCreateStreamLines(void *pQMiarex, Wing *PlaneWing[MAXWINGS], CVector *pNode, WPolar *pWPolar, WingOpp *pWOpp) { QMiarex * pMiarex = (QMiarex*)pQMiarex; MainFrame *pMainFrame = (MainFrame*)pMiarex->s_pMainFrame; if(!PlaneWing[0] || !pWOpp || !pWPolar || pWPolar->m_AnalysisMethod==LLTMETHOD || !pMiarex->m_MatSize) { glNewList(VLMSTREAMLINES,GL_COMPILE); glEndList(); pMiarex->m_GLList++; return; } double memcoresize = pMiarex->coreSize(); pMiarex->SetCoreSize(0.0005); //mm, just for the time needed to build the streamlines Wing *pWing; QProgressDialog dlg("Streamlines calculation", "Abort", 0, pMiarex->m_MatSize, pMainFrame); // dlg.setWindowModality(Qt::WindowModal); GL3DScales *p3DScales = (GL3DScales *)pMainFrame->m_pGL3DScales; bool bFound; int i; int m, p, style, iWing; double ds; float *Mu, *Sigma; CVector C, D, D1, VA, VAT, VB, VBT, VT, VInf, TC, TD; CVector RefPoint(0.0,0.0,0.0); D1.Set(987654321.0, 0.0, 0.0); PlaneOpp *pPOpp = pMiarex->m_pCurPOpp; if(pMiarex->m_pCurPOpp) { Mu = pPOpp->m_G; Sigma = pPOpp->m_Sigma; } else if (pWOpp) { Mu = pWOpp->m_G; Sigma = pWOpp->m_Sigma; } else { Mu = NULL; Sigma = NULL; } pMiarex->m_pPanelDlg->m_pWing = PlaneWing[0]; glNewList(VLMSTREAMLINES,GL_COMPILE); { pMiarex->m_GLList++; glEnable (GL_LINE_STIPPLE); style = W3dPrefsDlg::s_StreamLinesStyle; if (style == 1) glLineStipple (1, 0xCFCF); else if(style == 2) glLineStipple (1, 0x6666); else if(style == 3) glLineStipple (1, 0xFF18); else if(style == 4) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glLineWidth(W3dPrefsDlg::s_StreamLinesWidth); glColor3d(W3dPrefsDlg::s_StreamLinesColor.redF(), W3dPrefsDlg::s_StreamLinesColor.greenF(), W3dPrefsDlg::s_StreamLinesColor.blueF()); VInf.Set(pWOpp->m_QInf,0.0,0.0); m = 0; for (iWing=0; iWingm_MatSize; p++) { bFound = false; if(p3DScales->s_pos==0 && pWing->m_pWingPanel[p].m_bIsLeading && pWing->m_pWingPanel[p].m_Pos<=MIDSURFACE) { C.Set(pNode[pWing->m_pWingPanel[p].m_iLA]); D.Set(pNode[pWing->m_pWingPanel[p].m_iLB]); bFound = true; } else if(p3DScales->s_pos==1 && pWing->m_pWingPanel[p].m_bIsTrailing && pWing->m_pWingPanel[p].m_Pos<=MIDSURFACE) { C.Set(pNode[pWing->m_pWingPanel[p].m_iTA]); D.Set(pNode[pWing->m_pWingPanel[p].m_iTB]); bFound = true; } else if(p3DScales->s_pos==2 && pWing->m_pWingPanel[p].m_bIsLeading && pWing->m_pWingPanel[p].m_Pos<=MIDSURFACE) { C.Set(0.0, pNode[pWing->m_pWingPanel[p].m_iLA].y, 0.0); D.Set(0.0, pNode[pWing->m_pWingPanel[p].m_iLB].y, 0.0); bFound = true; } if(bFound) { TC = C; TD = D; TC.RotateY(RefPoint, pWOpp->m_Alpha); TD.RotateY(RefPoint, pWOpp->m_Alpha); TC -= C; TD -= D; if(p3DScales->s_pos==1 && qAbs(p3DScales->s_XOffset)<0.001 && qAbs(p3DScales->s_ZOffset)<0.001) { //apply Kutta's condition : initial speed vector is parallel to the T.E. bisector angle VA.Set(pNode[pWing->m_pWingPanel[p].m_iTA] - pNode[pWing->m_pWingPanel[p].m_iLA]); VA. Normalize(); VB.Set(pNode[pWing->m_pWingPanel[p].m_iTB] - pNode[pWing->m_pWingPanel[p].m_iLB]); VB. Normalize(); if(pWing->m_pWingPanel[p].m_Pos==BOTSURFACE) { //corresponding upper panel is the next one coming up for (i=p; im_MatSize;i++) if(pWing->m_pWingPanel[i].m_Pos>MIDSURFACE && pWing->m_pWingPanel[i].m_bIsTrailing) break; VAT = pNode[pWing->m_pWingPanel[i].m_iTA] - pNode[pWing->m_pWingPanel[i].m_iLA]; VAT.Normalize(); VA = VA+VAT; VA.Normalize();//VA is parallel to the bisector angle VBT = pNode[pWing->m_pWingPanel[i].m_iTB] - pNode[pWing->m_pWingPanel[i].m_iLB]; VBT.Normalize(); VB = VB+VBT; VB.Normalize();//VB is parallel to the bisector angle } VA.RotateY(pWOpp->m_Alpha); VB.RotateY(pWOpp->m_Alpha); } if(!C.IsSame(D1)) { C.x += p3DScales->s_XOffset; C.z += p3DScales->s_ZOffset; ds = p3DScales->s_DeltaL; // One very special case is where we initiate the streamlines exactly at the T.E. // without offset either in X ou Z directions // V1.Set(0.0,0.0,0.0); glBegin(GL_LINE_STRIP); { glVertex3d(C.x+TC.x, C.y+TC.y, C.z+TC.z); C += VA *ds; glVertex3d(C.x+TC.x, C.y+TC.y, C.z+TC.z); ds *= p3DScales->s_XFactor; for (i=1; i< p3DScales->s_NX ;i++) { pMiarex->m_pPanelDlg->GetSpeedVector(C, Mu, Sigma, VT); VT += VInf; VT.Normalize(); C += VT* ds; glVertex3d(C.x+TC.x, C.y+TC.y, C.z+TC.z); ds *= p3DScales->s_XFactor; } } glEnd(); } D1 = D; D.x += p3DScales->s_XOffset; D.z += p3DScales->s_ZOffset; ds = p3DScales->s_DeltaL; // V1.Set(0.0,0.0,0.0); glBegin(GL_LINE_STRIP); { glVertex3d(D.x+TD.x, D.y+TD.y, D.z+TD.z); D += VB *ds; glVertex3d(D.x+TD.x, D.y+TD.y, D.z+TD.z); ds *= p3DScales->s_XFactor; for (i=1; i< p3DScales->s_NX ;i++) { pMiarex->m_pPanelDlg->GetSpeedVector(D, Mu, Sigma, VT); VT += VInf; VT.Normalize(); D += VT* ds; glVertex3d(D.x+TD.x, D.y+TD.y, D.z+TD.z); ds *= p3DScales->s_XFactor; } } glEnd(); } dlg.setValue(m); m++; // qApp->processEvents(); if(dlg.wasCanceled()) break; } if(dlg.wasCanceled()) break; } if(dlg.wasCanceled()) break; } glDisable (GL_LINE_STIPPLE); } glEndList(); //restore things as they were pMiarex->SetCoreSize(memcoresize); } void GLCreateSurfSpeeds(void *pQMiarex, Panel *pPanel, WPolar *pWPolar, WingOpp *pWOpp) { QMiarex * pMiarex = (QMiarex*)pQMiarex; if(!pWPolar || !pWOpp || pWOpp->m_AnalysisMethod==LLTMETHOD || !pPanel || !pMiarex->m_MatSize) { glNewList(SURFACESPEEDS, GL_COMPILE); pMiarex->m_GLList++; glEndList(); return; } QProgressDialog dlg("Streamlines calculation", "Abort", 0, pMiarex->m_MatSize, (MainFrame*)QMiarex::s_pMainFrame); int p, style; double factor; double length, sinT, cosT; float *Mu, *Sigma; double x1, x2, y1, y2, z1, z2, xe, ye, ze, dlx, dlz; CVector C, V, VT; CVector RefPoint(0.0,0.0,0.0); factor = pMiarex->m_VelocityScale/100.0; PlaneOpp *pPOpp = pMiarex->m_pCurPOpp; if(pMiarex->m_pCurPOpp) { Mu = pPOpp->m_G; Sigma = pPOpp->m_Sigma; } else if (pWOpp) { Mu = pWOpp->m_G; Sigma = pWOpp->m_Sigma; } else { Mu = NULL; Sigma = NULL; } glNewList(SURFACESPEEDS, GL_COMPILE); { pMiarex->m_GLList++; glEnable (GL_LINE_STIPPLE); glLineWidth(W3dPrefsDlg::s_WakeWidth); style = W3dPrefsDlg::s_WakeStyle; if (style == 1) glLineStipple (1, 0xCFCF); else if(style == 2) glLineStipple (1, 0x6666); else if(style == 3) glLineStipple (1, 0xFF18); else if(style == 4) glLineStipple (1, 0x7E66); else glLineStipple (1, 0xFFFF); glColor3d(W3dPrefsDlg::s_WakeColor.redF(), W3dPrefsDlg::s_WakeColor.greenF(), W3dPrefsDlg::s_WakeColor.blueF()); for (p=0; pm_MatSize; p++) { VT.Set(pWOpp->m_QInf,0.0,0.0); if(pWPolar->m_AnalysisMethod==PANELMETHOD) { if(pPanel[p].m_Pos==MIDSURFACE) C.Copy(pPanel[p].CtrlPt); else C.Copy(pPanel[p].CollPt); pMiarex->m_pPanelDlg->GetSpeedVector(C, Mu, Sigma, V); VT += V; // if(!pWPolar->m_bTiltedGeom) C.RotateY(RefPoint, pWOpp->m_Alpha); //Tilt the geometry w.r.t. sideslip // C.RotateZ(RefPoint, -pWOpp->m_Beta); } length = VT.VAbs()*factor; xe = C.x+factor*VT.x; ye = C.y+factor*VT.y; ze = C.z+factor*VT.z; if(length>0.0) { cosT = (xe-C.x)/length; sinT = (ze-C.z)/length; dlx = 0.15*length; dlz = 0.07*length; } else { cosT = 0.0; sinT = 0.0; dlx = 0.0; dlz = 0.0; } x1 = xe -dlx*cosT - dlz*sinT; y1 = ye; z1 = ze -dlx*sinT + dlz*cosT; x2 = xe -dlx*cosT + dlz*sinT; y2 = ye; z2 = ze -dlx*sinT - dlz*cosT; glBegin(GL_LINES); { glVertex3d(C.x, C.y, C.z); glVertex3d(xe,ye,ze); } glEnd(); glBegin(GL_LINES); { glVertex3d(xe, ye, ze); glVertex3d(x1, y1, z1); } glEnd(); glBegin(GL_LINES); { glVertex3d(xe, ye, ze); glVertex3d(x2, y2, z2); } glEnd(); dlg.setValue(p); if(dlg.wasCanceled()) break; } glDisable (GL_LINE_STIPPLE); } glEndList(); dlg.hide(); } /** Creates an OpenGl list of pressure arrows on the panelss*/ void GLCreatePanelForce(void *pQMiarex, WPolar *pWPolar, WingOpp *pWOpp, PlaneOpp *pPOpp) { QMiarex * pMiarex = (QMiarex*)pQMiarex; Panel *pPanel = pMiarex->m_Panel; if((!pWOpp && !pPOpp) || !pWPolar || !pPanel || !pMiarex->m_MatSize) { glNewList(PANELFORCEARROWS,GL_COMPILE); glEndList(); glNewList(PANELFORCELEGENDTXT,GL_COMPILE); glEndList(); return; } int p; float *Cp; double force, cosa, sina2, cosa2, color; double rmin, rmax, range; double coef = 1.; Quaternion Qt; // Quaternion operator to align the reference arrow to the panel's normal CVector Omega; //rotation vector to align the reference arrow to the panel's normal CVector O; //The vectors defining the reference arrow CVector R(0.0,0.0,1.0); CVector R1( 0.05, 0.0, -0.1); CVector R2(-0.05, 0.0, -0.1); //The three vectors defining the arrow on the panel CVector P, P1, P2; //define the range of values to set the colors in accordance rmin = 1.e10; rmax = -rmin; if(pPOpp) Cp = pPOpp->m_Cp; else Cp = pWOpp->m_Cp; for (int p=0; pm_MatSize; p++) { rmax = qMax(rmax, Cp[p] * pMiarex->m_Panel[p].GetArea()); rmin = qMin(rmin, Cp[p] * pMiarex->m_Panel[p].GetArea()); } rmin *= 0.5*pWPolar->m_Density *pWOpp->m_QInf*pWOpp->m_QInf *pMiarex->m_LiftScale *coef; rmax *= 0.5*pWPolar->m_Density *pWOpp->m_QInf*pWOpp->m_QInf *pMiarex->m_LiftScale *coef; range = rmax - rmin; glNewList(PANELFORCEARROWS, GL_COMPILE); { pMiarex->m_GLList++; glLineWidth(1.0); // glColor3d(pMiarex->m_XCPColor.redF(), pMiarex->m_XCPColor.greenF(), pMiarex->m_XCPColor.blueF()); for (p=0; pm_MatSize; p++) { // plot Cp? f? f/s=q.Cp? force = 0.5*pWPolar->m_Density *pWOpp->m_QInf*pWOpp->m_QInf * Cp[p]*pPanel[p].GetArea(); force *= pMiarex->m_LiftScale *coef; color = (force-rmin)/range; glColor3d(GLGetRed(color),GLGetGreen(color),GLGetBlue(color)); if(pWPolar->m_AnalysisMethod==VLMMETHOD) O = pPanel[p].CtrlPt; else O = pPanel[p].CollPt; // Rotate the reference arrow to align it with the panel normal if(R==P) { Qt.Set(0.0, 0.0,0.0,1.0); //Null quaternion } else { cosa = R.dot(pPanel[p].Normal); sina2 = sqrt((1.0 - cosa)*0.5); cosa2 = sqrt((1.0 + cosa)*0.5); Omega = R * pPanel[p].Normal;//crossproduct Omega.Normalize(); Omega *=sina2; Qt.Set(cosa2, Omega.x, Omega.y, Omega.z); } Qt.Conjugate(R, P); Qt.Conjugate(R1, P1); Qt.Conjugate(R2, P2); // Scale the pressure vector P *= force; P1 *= force; P2 *= force; // Plot if(pPanel[p].m_Pos==MIDSURFACE) { glBegin(GL_LINES); { glVertex3d(O.x, O.y, O.z); glVertex3d(O.x+P.x, O.y+P.y, O.z+P.z); } glEnd(); if(force>0) { glBegin(GL_LINES); { glVertex3d(O.x+P.x, O.y+P.y, O.z+P.z); glVertex3d(O.x+P.x+P1.x, O.y+P.y+P1.y, O.z+P.z+P1.z); } glEnd(); glBegin(GL_LINES); { glVertex3d(O.x+P.x, O.y+P.y, O.z+P.z); glVertex3d(O.x+P.x+P2.x, O.y+P.y+P2.y, O.z+P.z+P2.z); } glEnd(); } else { glBegin(GL_LINES); { glVertex3d(O.x+P.x, O.y+P.y, O.z+P.z); glVertex3d(O.x+P.x+P1.x, O.y+P.y+P1.y, O.z+P.z+P1.z); } glEnd(); glBegin(GL_LINES); { glVertex3d(O.x+P.x, O.y+P.y, O.z+P.z); glVertex3d(O.x+P.x+P2.x, O.y+P.y+P2.y, O.z+P.z+P2.z); } glEnd(); } } else { if(Cp[p]>0) { // compression, point towards the surface // P.Set(-P.x, -P.y, -P.z); glBegin(GL_LINES); { glVertex3d(O.x, O.y, O.z); glVertex3d(O.x+P.x, O.y+P.y, O.z+P.z); } glEnd(); glBegin(GL_LINES); { glVertex3d(O.x, O.y, O.z); glVertex3d(O.x-P1.x, O.y-P1.y, O.z-P1.z); } glEnd(); glBegin(GL_LINES); { glVertex3d(O.x, O.y, O.z); glVertex3d(O.x-P2.x, O.y-P2.y, O.z-P2.z); } glEnd(); } else { // depression, point outwards from the surface P.Set(-P.x, -P.y, -P.z); glBegin(GL_LINES); { glVertex3d(O.x, O.y, O.z); glVertex3d(O.x+P.x, O.y+P.y, O.z+P.z); } glEnd(); glBegin(GL_LINES); { glVertex3d(O.x+P.x, O.y+P.y, O.z+P.z); glVertex3d(O.x+P.x-P1.x, O.y+P.y-P1.y, O.z+P.z-P1.z); } glEnd(); glBegin(GL_LINES); { glVertex3d(O.x+P.x, O.y+P.y, O.z+P.z); glVertex3d(O.x+P.x-P2.x, O.y+P.y-P2.y, O.z+P.z-P2.z); } glEnd(); } } } } glEndList(); } void GLDrawCpLegend(void *pQMiarex) { int i; QMiarex *pMiarex = (QMiarex*)pQMiarex; ThreeDWidget *pGLWidget = (ThreeDWidget*)pMiarex->s_p3dWidget; QString strong; double labellength; double f; double range, delta; QFontMetrics fm(MainFrame::s_TextFont); int back = fm.averageCharWidth() * 5; double h = (double)pMiarex->m_r3DCltRect.height(); double y0 = 2.*h/5.0; int ixPos, iyPos, dy; ixPos = pMiarex->m_r3DCltRect.width()-back; dy = (int) (h/40.0); iyPos = (int) (y0 - 12.0*dy); range = (pMiarex->s_LegendMax - pMiarex->s_LegendMin); delta = range / 20; //glNewList(WOPPCPLEGENDTXT,GL_COMPILE); { //pMiarex->m_GLList++; glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glColor3d(MainFrame::s_TextColor.redF(),MainFrame::s_TextColor.greenF(),MainFrame::s_TextColor.blueF()); strong = "Cp"; labellength = fm.width(strong)+5; pGLWidget->renderText(ixPos-labellength, iyPos-dy, strong, MainFrame::s_TextFont); for (i=0; i<=20; i ++) { f = pMiarex->s_LegendMax - (double)i * delta; strong = QString("%1").arg(f, 5,'f',2); labellength = (fm.width(strong)+5); pGLWidget->renderText(ixPos-labellength, iyPos+i*dy, strong, MainFrame::s_TextFont); } } //glEndList(); } void GLDrawPanelForceLegend(void *pQMiarex, WPolar *pWPolar) { if(!pWPolar) return; QMiarex * pMiarex = (QMiarex*)pQMiarex; ThreeDWidget *pGLWidget = (ThreeDWidget*)pMiarex->s_p3dWidget; int p, i; int labellength; double f; double rmin, rmax, range, delta; QString strong, strForce; GetForceUnit(strForce, MainFrame::s_ForceUnit); Wing *pWingList[MAXWINGS]; WingOpp *pWOppList[MAXWINGS]; for(int ip=0; ipm_pWingList[ip]; pWOppList[ip] = pMiarex->m_pWOpp[ip]; } //define the range of values to set the colors in accordance rmin = 1.e10; rmax = -rmin; for(int iw=0; iwm_MatSize; p++) { rmax = qMax(rmax,pWOppList[iw]->m_Cp[p]*pWingList[iw]->m_pWingPanel[p].GetArea()); rmin = qMin(rmin,pWOppList[iw]->m_Cp[p]*pWingList[iw]->m_pWingPanel[p].GetArea()); } } } rmin *= 0.5*pWPolar->m_Density *pWOppList[0]->m_QInf*pWOppList[0]->m_QInf *MainFrame::s_NtoUnit; rmax *= 0.5*pWPolar->m_Density *pWOppList[0]->m_QInf*pWOppList[0]->m_QInf *MainFrame::s_NtoUnit; range = rmax - rmin; QFontMetrics fm(MainFrame::s_TextFont); int back = fm.averageCharWidth() * 5; double h = (double)pMiarex->m_r3DCltRect.height(); double y0 = 2.*h/5.0; int ixPos, iyPos, dy; ixPos = pMiarex->m_r3DCltRect.width()-back; dy = (int) (h/40.0); iyPos = (int) (y0 - 12.0*dy); delta = range / 20.0; //glNewList(WOPPCPLEGENDTXT,GL_COMPILE); { //pMiarex->m_GLList++; glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glColor3d(MainFrame::s_TextColor.redF(),MainFrame::s_TextColor.greenF(),MainFrame::s_TextColor.blueF()); labellength = fm.width(strong)+5; pGLWidget->renderText(ixPos-labellength, iyPos-dy, strForce, MainFrame::s_TextFont); for (i=0; i<=20; i ++) { f = rmin + (double)i * delta; strong = QString("%1").arg(f, 5,'f',2); labellength = (fm.width(strong)+5); pGLWidget->renderText(ixPos-labellength, iyPos+i*dy, strong, MainFrame::s_TextFont); } } //glEndList();} } xflr5-6.09-06/src/miarex/BodyTransDlg.cpp000644 001750 000144 00000010620 12247174402 021404 0ustar00techwinderusers000000 000000 /**************************************************************************** BodyTransDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include #include "BodyTransDlg.h" #include "../mainframe.h" #include "../globals.h" BodyTransDlg::BodyTransDlg(QWidget *pParent): QDialog(pParent) { setWindowTitle(tr("Body Translation")); m_XTrans = m_YTrans = m_ZTrans = 0.0; m_bFrameOnly = false; m_FrameID = 1; SetupLayout(); } void BodyTransDlg::InitDialog() { m_pctrlXTransFactor->SetValue(m_XTrans); m_pctrlYTransFactor->SetValue(m_YTrans); m_pctrlZTransFactor->SetValue(m_ZTrans); m_pctrlYTransFactor->setEnabled(false); m_pctrlFrameOnly->setChecked(m_bFrameOnly); m_pctrlFrameID->SetValue(m_FrameID+1); m_pctrlFrameID->setEnabled(m_bFrameOnly); QString length; GetLengthUnit(length, MainFrame::s_LengthUnit); m_pctrlLength1->setText(length); m_pctrlLength2->setText(length); m_pctrlLength3->setText(length); } void BodyTransDlg::keyPressEvent(QKeyEvent *event) { // Prevent Return Key from closing App switch (event->key()) { case Qt::Key_Return: { if(!OKButton->hasFocus() && !CancelButton->hasFocus()) { OKButton->setFocus(); return; } else { OnOK(); return; } break; } case Qt::Key_Escape: { reject(); break; } default: event->ignore(); } } void BodyTransDlg::OnOK() { m_bFrameOnly = m_pctrlFrameOnly->isChecked(); m_FrameID = m_pctrlFrameID->Value()-1; m_XTrans = m_pctrlXTransFactor->Value() / MainFrame::s_mtoUnit; m_YTrans = m_pctrlYTransFactor->Value() / MainFrame::s_mtoUnit; m_ZTrans = m_pctrlZTransFactor->Value() / MainFrame::s_mtoUnit; accept(); } void BodyTransDlg::OnFrameOnly() { m_bFrameOnly = m_pctrlFrameOnly->isChecked(); m_pctrlFrameID->setEnabled(m_bFrameOnly); } void BodyTransDlg::SetupLayout() { QHBoxLayout *FrameID = new QHBoxLayout; m_pctrlFrameOnly = new QCheckBox(tr("Frame Only")); m_pctrlFrameID = new DoubleEdit(0.0,0); FrameID->addWidget(m_pctrlFrameOnly); FrameID->addWidget(m_pctrlFrameID); QGridLayout *TransLayout = new QGridLayout; QLabel * XTrans = new QLabel(tr("X Translation")); QLabel * YTrans = new QLabel(tr("Y Translation")); QLabel * ZTrans = new QLabel(tr("Z Translation")); m_pctrlXTransFactor = new DoubleEdit(0.0,3); m_pctrlYTransFactor = new DoubleEdit(0.0,3); m_pctrlZTransFactor = new DoubleEdit(0.0,3); m_pctrlLength1 = new QLabel("m"); m_pctrlLength2 = new QLabel("m"); m_pctrlLength3 = new QLabel("m"); TransLayout->addWidget(XTrans,1,1); TransLayout->addWidget(YTrans,2,1); TransLayout->addWidget(ZTrans,3,1); TransLayout->addWidget(m_pctrlXTransFactor,1,2); TransLayout->addWidget(m_pctrlYTransFactor,2,2); TransLayout->addWidget(m_pctrlZTransFactor,3,2); TransLayout->addWidget(m_pctrlLength1,1,3); TransLayout->addWidget(m_pctrlLength2,2,3); TransLayout->addWidget(m_pctrlLength3,3,3); QHBoxLayout *CommandButtons = new QHBoxLayout; OKButton = new QPushButton(tr("OK")); CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); connect(OKButton, SIGNAL(clicked()),this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addLayout(FrameID); MainLayout->addLayout(TransLayout); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); setLayout(MainLayout); connect(m_pctrlFrameOnly, SIGNAL(clicked()), SLOT(OnFrameOnly())); } xflr5-6.09-06/src/miarex/NURBSDomDoc.h000644 001750 000144 00000002200 12247174401 020466 0ustar00techwinderusers000000 000000 /**************************************************************************** NURBSDomDoc Class Copyright (C) 2012 Andre Deperrois sail7@xflr5.com All rights reserved *****************************************************************************/ /** * @file * This file is an attempt to implement an XML format for the input/output of NURBS definitions * Unfinished. @todo : finish the implementation. */ #ifndef NURBSDOMDOC_H #define NURBSDOMDOC_H #include #include /** * @class NURBSDomDoc * This class is an attempt to implement an XML format for the input/output of plan definitions * Unfinished. @todo : finish the implementation. */ class NURBSDomDoc : public QDomDocument { public: NURBSDomDoc(void *pNURBS=NULL); QDomNode GetNode(QDomNode const &node, QString const &NodeName); QDomElement GetElement(const QDomNode &node, QString const &TagName, QString const &AttributeName); QDomElement GetElement(QDomNode const &node, QString const &elementName); void ReadNodes(QDomNode node); void Export(QTextStream &outStream); bool Import(QFile *pFile); void *m_pNURBS; }; #endif // NURBSDOMDOC_H xflr5-6.09-06/src/miarex/CtrlTableDelegate.h000644 001750 000144 00000004156 12247174402 022033 0ustar00techwinderusers000000 000000 /**************************************************************************** CtrlTableDelegate Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef CTRLTABLEDELEGATE_H #define CTRLTABLEDELEGATE_H #include #include #include #include "../misc/DoubleEdit.h" class CtrlTableDelegate : public QItemDelegate { Q_OBJECT friend class StabPolarDlg; friend class StabViewDlg; public: CtrlTableDelegate(QObject *parent = 0); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawCheck(QPainter *painter, const QStyleOptionViewItem &option, const QRect &, Qt::CheckState state) const; bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index); private: QStandardItemModel *m_pCtrlModel; int *m_Precision; ///table of float precisions for each column static void *s_pMiarex; }; #endif // CTRLTABLEDELEGATE_H xflr5-6.09-06/src/miarex/GL3dWingDlg.h000644 001750 000144 00000016054 12247174402 020531 0ustar00techwinderusers000000 000000 /**************************************************************************** GL3dWingDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef GL3DWINGDLG_H #define GL3DWINGDLG_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../objects/ArcBall.h" #include "WingDelegate.h" #include "../threedwidget.h" #include "../misc/DoubleEdit.h" #include "../misc/ColorButton.h" #include "../objects/Wing.h" class GL3dWingDlg: public QDialog { Q_OBJECT friend class MainFrame; friend class QMiarex; friend class ThreeDWidget; friend class Wing; friend class GLLightDlg; friend class PlaneDlg; friend class WingDelegate; public: GL3dWingDlg(QWidget *pParent); ~GL3dWingDlg(); private slots: void OnAxes(); void On3DIso(); void On3DTop(); void On3DLeft(); void On3DFront(); void On3DReset(); void On3DPickCenter(); // void OnSetupLight(); void OnClipPlane(int pos); void OnLight(); void OnSurfaces(); void OnOutline(); void OnPanels(); void OnFoilNames(); void OnShowMasses(); void OnOK(); void OnDescriptionChanged(); void OnCellChanged(QWidget *pWidget); void OnItemClicked(const QModelIndex &index); void OnWingColor(); void OnSide(); void OnSymetric(); void OnInsertBefore(); void OnInsertAfter(); void OnDeleteSection(); void OnResetSection(); void OnResetMesh(); void OnScaleWing(); void OnInertia(); void OnImportWing(); void OnExportWing(); private: void reject(); void WheelEvent(QWheelEvent *event); void MouseDoubleClickEvent(QMouseEvent *event); void MouseMoveEvent(QMouseEvent *event); void MousePressEvent(QMouseEvent *event) ; void MouseReleaseEvent(QMouseEvent *event) ; void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void showEvent(QShowEvent *event); void contextMenuEvent(QContextMenuEvent *event); bool CheckWing(); void CreateXPoints(int NXPanels, int XDist, Foil *pFoilA, Foil *pFoilB, double *xPointA, double *xPointB, int &NXLead, int &NXFlap); void ComputeGeometry(); void SetWingData(); void FillDataTable(); void FillTableRow(int row); void ReadParams(); void ReadSectionData(int sel); void SetCurrentSection(int section); void SetScale(); int VLMGetPanelTotal(); bool VLMSetAutoMesh(int total=0); bool InitDialog(Wing *pWing); void Connect(); void SetupLayout(); void GLCreateMesh(); void GLRenderView(); void GLDrawFoils(); void GLCreateSectionHighlight(); void GLInverseMatrix(); void GLCallViewLists(); void GLDraw3D(); void Set3DRotationCenter(); void Set3DRotationCenter(QPoint point); void SetWingScale(); void UpdateView(); private: static void *s_pMiarex; static QList *s_poaFoil; static QList *s_poaWing; static QPoint s_WindowPos; static QSize s_WindowSize; static bool s_bWindowMaximized; ThreeDWidget *m_pGLWidget; QLineEdit *m_pctrlWingName; QTextEdit *m_pctrlWingDescription; QCheckBox *m_pctrlSymetric; QRadioButton *m_pctrlLeftSide, *m_pctrlRightSide; ColorButton *m_pctrlWingColor; QPushButton *m_pctrlResetMesh, *m_pctrlScaleWing; QPushButton *m_pctrlInsertBefore, *m_pctrlInsertAfter, *m_pctrlDeleteSection; QLabel *m_pctrlWingSpan, *m_pctrlWingArea, *m_pctrlMAC, *m_pctrlGeomChord; QLabel *m_pctrlMACSpanPos, *m_pctrlAspectRatio, *m_pctrlTaperRatio, *m_pctrlSweep, *m_pctrlNFlaps; QLabel *m_pctrlVLMPanels, *m_pctrl3DPanels; QLabel *m_pctrlProjectedArea, *m_pctrlProjectedSpan; QLabel *m_pctrlLength1, *m_pctrlLength2, *m_pctrlLength3, *m_pctrlLength4, *m_pctrlLength5; QLabel *m_pctrlAreaUnit1, *m_pctrlAreaUnit2, * m_pctrlVolumeUnit; QTableView *m_pctrlWingTable; QStandardItemModel *m_pWingModel; WingDelegate *m_pWingDelegate; QPushButton *OKButton, *CancelButton; QCheckBox *m_pctrlAxes, *m_pctrlLight, *m_pctrlSurfaces, *m_pctrlOutline, *m_pctrlPanels, *m_pctrlFoilNames; QCheckBox *m_pctrlShowMasses; QPushButton *m_pctrlReset, *m_pctrlPickCenter; QToolButton *m_pctrlX, *m_pctrlY, *m_pctrlZ, *m_pctrlIso; QAction *m_pXView, *m_pYView, *m_pZView, *m_pIsoView; QPushButton *m_pctrlInertiaButton; QSlider *m_pctrlClipPlanePos; QAction *m_pResetScales; QAction *m_pExportWingAct, *m_pImportWingAct; QPushButton *m_pExportWingBtn, *m_pImportWingBtn; QMenu *m_pContextMenu; QAction *m_pInsertBefore, *m_pInsertAfter, *m_pDeleteSection, *m_pResetSection; QWidget *m_pctrlControlsWidget; Wing *m_pWing; bool m_bAcceptName; bool m_bRightSide; bool m_bChanged, m_bDescriptionChanged; bool m_bTrans; bool m_bStored; bool m_bEnableName; bool m_bDragPoint; bool m_bArcball; //true if the arcball is to be displayed bool m_bCrossPoint; //true if the control point on the arcball is to be displayed bool m_bPickCenter; //true if the user is in the process of picking a new center for OpenGL display bool m_bResetglWing; bool m_bResetglSectionHighlight; static bool s_bOutline; /**< true if the surface outlines are to be displayed in the 3D view*/ static bool s_bSurfaces; /**< true if the surfaces are to be displayed in the 3D view*/ static bool s_bVLMPanels; /**< true if the panels are to be displayed in the 3D view*/ static bool s_bAxes; /**< true if the axes are to be displayed in the 3D view*/ static bool s_bShowMasses; /**< true if the point masses are to be displayed on the openGL 3D view */ static bool s_bFoilNames; /**< true if the foil names are to be displayed on the openGL 3D view */ int m_iSection; int m_GLList; double m_glScaled;//zoom factor for UFO double m_ClipPlanePos; double MatIn[4][4], MatOut[4][4]; QPoint m_MousePos; QPoint m_ptPopUp; QPoint m_LastPoint, m_PointDown; CVector m_RealPopUp; CVector m_UFOOffset; CVector m_glViewportTrans;// the translation vector in gl viewport coordinates CVector m_glRotCenter; // the center of rotation in object coordinates... is also the opposite of the translation vector CVector m_L[(MAXBODYFRAMES+1)*(MAXSIDELINES+1)]; //temporary points to save calculation times for body NURBS surfaces CVector m_T[(MAXBODYFRAMES+1)*(MAXSIDELINES+1)]; Panel *m_pPanel; CVector *m_pNode; ArcBall m_ArcBall; }; #endif // GL3DWINGDLG_H xflr5-6.09-06/src/miarex/WingScaleDlg.cpp000644 001750 000144 00000020724 12247174407 021366 0ustar00techwinderusers000000 000000 /**************************************************************************** WingScaleDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #include #include #include #include "WingScaleDlg.h" #include "../mainframe.h" #include "../globals.h" WingScaleDlg::WingScaleDlg(QWidget *pParent) : QDialog(pParent) { setWindowTitle(tr("Scale Wing Dlg")); m_bSweep = m_bSpan = m_bChord = m_bTwist = false; m_NewSweep = m_NewChord = m_NewTwist = m_NewSpan = false; m_RefSweep = m_RefChord = m_RefTwist = m_RefSpan = 1.0; SetupLayout(); } void WingScaleDlg::SetupLayout() { QGridLayout *ScaleLayout = new QGridLayout; m_pctrlSpan = new QCheckBox(tr("Span Scaling")); m_pctrlChord = new QCheckBox(tr("Chord Scaling")); m_pctrlSweep = new QCheckBox(tr("Sweep Scaling")); m_pctrlTwist = new QCheckBox(tr("Twist Scaling")); m_pctrlNewSpan = new DoubleEdit(0,3); m_pctrlNewChord = new DoubleEdit(0,3); m_pctrlNewTwist = new DoubleEdit(0,3); m_pctrlNewSweep = new DoubleEdit(0,3); m_pctrlRefSpan = new QLabel("0.000"); m_pctrlRefChord = new QLabel("0.000"); m_pctrlRefSweep = new QLabel("0.000"); m_pctrlRefTwist = new QLabel("0.000"); m_pctrlRefSpan->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlRefChord->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlRefSweep->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlRefTwist->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlSpanRatio = new QLabel("1.000"); m_pctrlChordRatio = new QLabel("1.000"); m_pctrlSweepRatio = new QLabel("1.000"); m_pctrlTwistRatio = new QLabel("1.000"); m_pctrlSpanRatio->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlChordRatio->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlSweepRatio->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_pctrlTwistRatio->setAlignment(Qt::AlignRight | Qt::AlignVCenter); QLabel *lab11 = new QLabel(tr("Reference")); QLabel *lab12 = new QLabel(tr("New")); QLabel *lab13 = new QLabel(tr("Ratio")); lab11->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); lab12->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); lab13->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); ScaleLayout->addWidget(lab11, 1,2); ScaleLayout->addWidget(lab12, 1,3); ScaleLayout->addWidget(lab13, 1,5); ScaleLayout->addWidget(m_pctrlSpan, 2,1); ScaleLayout->addWidget(m_pctrlRefSpan, 2,2); ScaleLayout->addWidget(m_pctrlNewSpan, 2,3); ScaleLayout->addWidget(m_pctrlSpanRatio, 2,5); ScaleLayout->addWidget(m_pctrlChord, 3,1); ScaleLayout->addWidget(m_pctrlRefChord, 3,2); ScaleLayout->addWidget(m_pctrlNewChord, 3,3); ScaleLayout->addWidget(m_pctrlChordRatio,3,5); ScaleLayout->addWidget(m_pctrlSweep, 4,1); ScaleLayout->addWidget(m_pctrlRefSweep, 4,2); ScaleLayout->addWidget(m_pctrlNewSweep, 4,3); ScaleLayout->addWidget(m_pctrlSweepRatio,4,5); ScaleLayout->addWidget(m_pctrlTwist, 5,1); ScaleLayout->addWidget(m_pctrlRefTwist, 5,2); ScaleLayout->addWidget(m_pctrlNewTwist, 5,3); ScaleLayout->addWidget(m_pctrlTwistRatio,5,5); m_pctrlUnit20 = new QLabel; m_pctrlUnit21 = new QLabel; QLabel *Unit22 = new QLabel(QString::fromUtf8("°")); ScaleLayout->addWidget(m_pctrlUnit20, 2,4); ScaleLayout->addWidget(m_pctrlUnit21, 3,4); ScaleLayout->addWidget(Unit22, 4,4); QHBoxLayout *CommandButtons = new QHBoxLayout; QPushButton *OKButton = new QPushButton(tr("OK")); QPushButton *CancelButton = new QPushButton(tr("Cancel")); CommandButtons->addStretch(1); CommandButtons->addWidget(OKButton); CommandButtons->addStretch(1); CommandButtons->addWidget(CancelButton); CommandButtons->addStretch(1); QHBoxLayout *StretchLayout = new QHBoxLayout; StretchLayout->addStretch(1); StretchLayout->addLayout(ScaleLayout); StretchLayout->addStretch(1); QVBoxLayout *MainLayout = new QVBoxLayout; MainLayout->addStretch(1); MainLayout->addLayout(StretchLayout); MainLayout->addStretch(1); MainLayout->addLayout(CommandButtons); MainLayout->addStretch(1); setLayout(MainLayout); connect(OKButton, SIGNAL(clicked()), this, SLOT(OnOK())); connect(CancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(m_pctrlSpan, SIGNAL(clicked()), this, SLOT(OnClickedCheckBox())); connect(m_pctrlChord, SIGNAL(clicked()), this, SLOT(OnClickedCheckBox())); connect(m_pctrlSweep, SIGNAL(clicked()), this, SLOT(OnClickedCheckBox())); connect(m_pctrlTwist, SIGNAL(clicked()), this, SLOT(OnClickedCheckBox())); connect(m_pctrlNewSpan, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlNewChord, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlNewSweep, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); connect(m_pctrlNewTwist, SIGNAL(editingFinished()), this, SLOT(OnEditingFinished())); } void WingScaleDlg::InitDialog(double const &RefSpan, double const &RefChord, double const &RefSweep, double const &RefTwist) { QString len; GetLengthUnit(len, MainFrame::s_LengthUnit); m_pctrlUnit20->setText(len); m_pctrlUnit21->setText(len); m_RefSpan = RefSpan; m_RefChord = RefChord; m_RefSweep = RefSweep; m_RefTwist = RefTwist; m_NewSpan = RefSpan; m_NewChord = RefChord; m_NewSweep = RefSweep; m_NewTwist = RefTwist; m_pctrlSpan->setChecked(m_bSpan);//(false) m_pctrlChord->setChecked(m_bChord); m_pctrlTwist->setChecked(m_bTwist); m_pctrlSweep->setChecked(m_bSweep); QString strong; strong = QString("%1").arg(m_RefSpan * MainFrame::s_mtoUnit,8,'f',3); m_pctrlRefSpan->setText(strong); strong = QString("%1").arg(m_RefChord * MainFrame::s_mtoUnit,8,'f',3); m_pctrlRefChord->setText(strong); strong = QString("%1").arg(m_RefSweep,8,'f',2); strong += QString::fromUtf8("°"); m_pctrlRefSweep->setText(strong); strong = QString("%1").arg(m_RefTwist,8,'f',2); m_pctrlRefTwist->setText(strong); m_pctrlNewSpan->SetValue(m_NewSpan * MainFrame::s_mtoUnit); m_pctrlNewChord->SetValue(m_NewChord * MainFrame::s_mtoUnit); m_pctrlNewSweep->SetValue(m_NewSweep); m_pctrlNewTwist->SetValue(m_NewTwist); SetResults(); EnableControls(); } void WingScaleDlg::OnClickedCheckBox() { ReadData(); EnableControls(); } void WingScaleDlg::OnOK() { ReadData(); accept(); } void WingScaleDlg::OnEditingFinished() { ReadData(); SetResults(); } void WingScaleDlg::EnableControls() { m_pctrlNewSpan->setEnabled(m_bSpan); m_pctrlNewChord->setEnabled(m_bChord); m_pctrlNewSweep->setEnabled(m_bSweep); m_pctrlNewTwist->setEnabled(m_bTwist); } void WingScaleDlg::ReadData() { m_bSpan = m_pctrlSpan->isChecked(); m_bChord = m_pctrlChord->isChecked(); m_bSweep = m_pctrlSweep->isChecked(); m_bTwist = m_pctrlTwist->isChecked(); m_NewSpan = m_pctrlNewSpan->Value() / MainFrame::s_mtoUnit; m_NewChord = m_pctrlNewChord->Value() / MainFrame::s_mtoUnit; m_NewSweep = m_pctrlNewSweep->Value(); m_NewTwist = m_pctrlNewTwist->Value(); } void WingScaleDlg::SetResults() { QString strong; if(m_RefSpan>0.0) strong = QString("%1").arg(m_NewSpan/m_RefSpan, 6,'f',3); else strong =" 1.000"; m_pctrlSpanRatio->setText(strong); if(m_RefChord>0.0) strong = QString("%1").arg(m_NewChord/m_RefChord, 6,'f',3); else strong =" 1.000"; m_pctrlChordRatio->setText(strong); if(m_RefSweep>0.0) strong = QString("%1").arg(m_NewSweep/m_RefSweep, 6,'f',3); else strong =" 1.000"; m_pctrlSweepRatio->setText(strong); if(m_RefTwist>0.0) strong = QString("%1").arg(m_NewTwist/m_RefTwist, 6,'f',3); else strong =" 1.000"; m_pctrlTwistRatio->setText(strong); } xflr5-6.09-06/src/miarex/NURBSDomDoc.cpp000644 001750 000144 00000021647 12247174402 021042 0ustar00techwinderusers000000 000000 /**************************************************************************** SailDomDoc Class Copyright (C) 2012 Andre Deperrois sail7@xflr5.com All rights reserved *****************************************************************************/ #include #include #include "NURBSDomDoc.h" #include "../objects/NURBSSurface.h" #include "../globals.h" NURBSDomDoc::NURBSDomDoc(void *pNURBS) : QDomDocument("X3D PUBLIC \"ISO//Web3D//DTD X3D 3.2//EN\" \"http://www.web3d.org/specifications/x3d-3.2.dtd\"") //!DOCTYPE { QDomProcessingInstruction xmlHeaderPI = createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"" ); appendChild(xmlHeaderPI); m_pNURBS = pNURBS; } void NURBSDomDoc::Export(QTextStream &outStream) { NURBSSurface *pNURBS = (NURBSSurface*)m_pNURBS; pNURBS->SetKnots(); QDomElement data; QDomElement NURBSdoc = createElement("X3D"); { NURBSdoc.setAttribute("profile", "Interchange"); NURBSdoc.setAttribute("version", "3.2"); NURBSdoc.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema-instance"); NURBSdoc.setAttribute("xsd:noNamespaceSchemaLocation", "http://www.web3d.org/specifications/x3d-3.2.xsd"); QDomElement head = createElement("head"); NURBSdoc.appendChild(head); { data = createElement("component"); data.setAttribute("level", 1); data.setAttribute("name", "NURBS"); head.appendChild(data); data = createElement("meta"); data.setAttribute("content", "NURBS Surface"); data.setAttribute("name", "title"); head.appendChild(data); data = createElement("meta"); data.setAttribute("name", "description"); data.setAttribute("content", "NURBS"); head.appendChild(data); data = createElement("meta"); data.setAttribute("name", "creator"); data.setAttribute("content", "XFLR5 Application"); head.appendChild(data); data = createElement("meta"); data.setAttribute("name", "created"); QDate dt = QDate::currentDate(); QString date = dt.toString("dd.MM.yyyy"); data.setAttribute("content", date); head.appendChild(data); data = createElement("meta"); data.setAttribute("name", "modified"); data.setAttribute("content", date); head.appendChild(data); data = createElement("meta"); data.setAttribute("name", "image"); data.setAttribute("content", "NURBS_Surface.jpg"); head.appendChild(data); data = createElement("meta"); data.setAttribute("name", "reference"); data.setAttribute("content", "http://www.xflr5.com"); head.appendChild(data); data = createElement("meta"); data.setAttribute("name", "identifier"); data.setAttribute("content", "http://www.web3d.org/x3d/content/examples/Basic/NURBS/MobiusNurbs.x3d"); head.appendChild(data); data = createElement("meta"); data.setAttribute("name", "generator"); data.setAttribute("content", "XFLR5 Application"); head.appendChild(data); data = createElement("meta"); data.setAttribute("name", "license"); data.setAttribute("content", "GPL"); head.appendChild(data); } QDomElement scene = createElement("Scene"); { NURBSdoc.appendChild(scene); data = createElement("Background"); data.setAttribute("skyColor", "1 1 1"); data.setAttribute("transparency", 0); scene.appendChild(data); data = createElement("NavigationInfo"); data.setAttribute("type", "\"EXAMINE\" \"ANY\""); data.setAttribute("transitionType", "ANIMATE"); data.setAttribute("transitionTime", "1.0"); scene.appendChild(data); data = createElement("Viewpoint"); data.setAttribute("description", "Normal viewpoint"); data.setAttribute("orientation", "1 0 0 -0.54042"); data.setAttribute("position", "0 60 100"); data.setAttribute("retainUserOffsets", "false"); scene.appendChild(data); QDomElement shape = createElement("Shape"); { scene.appendChild(shape); data = createElement("NurbsPatchSurface"); { data.setAttribute("solid", "false"); data.setAttribute("uDimension", pNURBS->m_iuDegree); data.setAttribute("uOrder", pNURBS->m_iuDegree + pNURBS->FrameSize()+1); //TODO : check order definition data.setAttribute("vDimension", pNURBS->m_ivDegree); data.setAttribute("vOrder", pNURBS->m_iuDegree + pNURBS->FramePointCount()+1); //TODO : check order definition QString uknots; for(int iu=0; ium_nuKnots; iu++) { uknots += QString("%1 ").arg(pNURBS->m_uKnots[iu], 7, 'f', 5); } data.setAttribute("uknot", uknots.trimmed()); QString vknots; for(int iv=0; ivm_nvKnots; iv++) { vknots += QString("%1 ").arg(pNURBS->m_vKnots[iv], 7, 'f', 5); } vknots = vknots.trimmed(); data.setAttribute("vknot", vknots); data.setAttribute("uClosed", "false"); data.setAttribute("vClosed", "false"); data.setAttribute("uTessellation", "0"); data.setAttribute("vTessellation", "0"); data.setAttribute("containerField", "geometry"); shape.appendChild(data); } data = createElement("Coordinate"); { data.setAttribute("containerField", "controlPoint"); QString pointcoordinates; for(int iu=0; iuFrameSize(); iu++) { for(int iv=0; ivFramePointCount(); iv++) { pointcoordinates += QString("%1 %2 %3") .arg(pNURBS->m_pFrame[iu]->m_CtrlPoint[iv].x, 11, 'f', 5) .arg(pNURBS->m_pFrame[iu]->m_CtrlPoint[iv].y, 11, 'f', 5) .arg(pNURBS->m_pFrame[iu]->m_CtrlPoint[iv].z, 11, 'f', 5); } } data.setAttribute("point", pointcoordinates); shape.appendChild(data); } QDomElement appearance = createElement("Appearance"); { shape.appendChild(appearance); data = createElement("Material"); data.setAttribute("diffuseColor", "0 0 1"); appearance.appendChild(data); } } } appendChild(NURBSdoc); } const int IndentSize = 4; save(outStream, IndentSize); } void NURBSDomDoc::ReadNodes(QDomNode node) { while(!node.isNull()) { QDomElement en = node.toElement(); // try to convert the node to an element. if(!en.isNull()) { // qDebug()<close(); return false; } NURBSSurface *pNURBS = (NURBSSurface*)m_pNURBS; QDomElement en; QDomNode n0, n1, n2; QDomNode node = documentElement().firstChild(); n0 = GetNode(node, "Scene"); qDebug()<m_iuDegree = en.attribute("uDimension","999").toInt(); pNURBS->m_ivDegree = en.attribute("vDimension","123456").toInt(); QString uknots = en.attribute("uknot", "1.234, 0.5678"); QTextStream knotstream(&uknots); double u; while(!knotstream.atEnd()) { knotstream >> u; } } en = GetElement(n1, QString("Coordinate")); qDebug()<<"element" <> x>>y>>z; qDebug("%13.6f %13.6f %13.6f ",x,y,z); } } } } //TODO... to be continued return false; } xflr5-6.09-06/src/miarex/BodyGridDlg.h000644 001750 000144 00000004660 12247174401 020655 0ustar00techwinderusers000000 000000 /**************************************************************************** BodyGridDlg Class Copyright (C) 2009 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef BODYGRIDDLG_H #define BODYGRIDDLG_H #include #include #include #include #include "../misc/DoubleEdit.h" #include "../misc/LineBtn.h" class BodyGridDlg : public QDialog { Q_OBJECT friend class GL3dBodyDlg; friend class Body; friend class MainFrame; public: BodyGridDlg(QWidget *pParent); static void LoadSettings (QSettings *pSettings); static void SaveSettings (QSettings *pSettings); private slots: void OnOK(); void OnGrid(); void OnGrid2(); void OnMinGrid(); void OnMinGrid2(); void OnLineStyle(); void OnLine2Style(); void OnMinLineStyle(); void OnMinLine2Style(); private: void SetupLayout(); void InitDialog(); void EnableControls(); private: QCheckBox *m_pctrlScales; QCheckBox *m_pctrlGrid, *m_pctrlMinGrid, *m_pctrlGrid2, *m_pctrlMinGrid2; LineBtn *m_pctrlLine, *m_pctrlMinLine, *m_pctrlLine2, *m_pctrlMinLine2; DoubleEdit *m_pctrlUnit, *m_pctrlMinUnit, *m_pctrlUnit2, *m_pctrlMinUnit2; QLabel *m_pctrlLength1, *m_pctrlLength2, *m_pctrlLength3, *m_pctrlLength4; static bool s_bScale; static bool s_bGrid; static int s_Style, s_Width; static QColor s_Color; static double s_Unit; static bool s_bMinGrid; static int s_MinStyle, s_MinWidth; static QColor s_MinColor; static double s_MinorUnit; static bool s_bGrid2; static int s_Style2, s_Width2; static QColor s_Color2; static double s_Unit2; static bool s_bMinGrid2; static int s_MinStyle2, s_MinWidth2; static QColor s_MinColor2; static double s_MinorUnit2; }; #endif // BODYGRIDDLG_H xflr5-6.09-06/src/miarex/GL3dBodyDlg.h000644 001750 000144 00000020636 12247174402 020523 0ustar00techwinderusers000000 000000 /**************************************************************************** BodyDlg Class Copyright (C) 2009-2012 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ #ifndef BODYDLG_H #define BODYDLG_H #include #include #include #include #include #include #include #include #include #include #include #include #include "BodyGridDlg.h" #include "BodyTableDelegate.h" #include "../misc/DoubleEdit.h" #include "../misc/LineBtn.h" #include "../objects/ArcBall.h" #include "../objects/Body.h" #include "../threedwidget.h" class GL3dBodyDlg : public QDialog { Q_OBJECT friend class MainFrame; friend class QSail7; friend class QMiarex; friend class ThreeDWidget; friend class GLLightDlg; friend class BodyScaleDlg; friend class ManageBodiesDlg; friend class BoatDlg; friend class PlaneDlg; public: GL3dBodyDlg(QWidget *pParent); ~GL3dBodyDlg(); private slots: void OnAxes(); void On3DIso(); void On3DTop(); void On3DLeft(); void On3DFront(); void On3DReset(); void On3DPickCenter(); void OnBodyStyle(); void OnBodyInertia(); void OnEdgeWeight(); void OnExportBodyDef(); void OnExportBodyGeom(); void OnImportBodyDef() ; void OnTranslateBody(); void OnGrid(); void OnClipPlane(); void OnLight(); void OnSurfaces(); void OnOutline(); void OnPanels(); void OnLineType(); void OnNURBSPanels(); void OnInsert(); void OnResetScales(); void OnShowCurFrameOnly(); void OnRemove(); void OnFrameCellChanged(QWidget *pWidget); void OnFrameItemClicked(const QModelIndex &index); void OnPointCellChanged(QWidget *pWidget); void OnPointItemClicked(const QModelIndex &index); void OnScaleBody(); void OnUndo(); void OnRedo(); void OnBodyName(); void OnShowMasses(); void OnSelChangeXDegree(int sel); void OnSelChangeHoopDegree(int sel); void OnOK(); private: void wheelEvent(QWheelEvent *event); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseDoubleClickEvent(QMouseEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void resizeEvent(QResizeEvent *evendyt); void ShowContextMenu(QContextMenuEvent * event); void showEvent(QShowEvent *event); void reject(); void blockSignalling(bool bBlock); void FillFrameTableRow(int row); void FillFrameDataTable(); void FillFrameCell(int iItem, int iSubItem); void ReadFrameSectionData(int sel); void FillPointCell(int iItem, int iSubItem); void FillPointTableRow(int row); void FillPointDataTable(); void ReadPointSectionData(int sel); void SetFrame(int iFrame); void SetFrame(Frame *pFrame); void SetupLayout(); void SetViewControls(); void SetTableUnits(); void GLInverseMatrix(); void GLCreateBody2DBodySection(); void GLCreateBodyPoints(); void GLCreateBodyFrames(); void GLCreateBodyGrid(); void GLRenderBody(); void GLCallViewLists(); void GLDraw3D(); void GLDrawBodyLegend(); void GLDrawBodyLineScale(); void GLDrawBodyFrameScale(); void GLDrawMasses(); void SetControls(); void SetScales(); void SetRectangles(); void SetBodyScale(); void SetBodyLineScale(); void SetFrameScale(); void Set3DRotationCenter(); void Set3DRotationCenter(QPoint point); void UpdateView(); bool InitDialog(Body *pBody); static bool LoadSettings(QSettings *pSettings); static bool SaveSettings(QSettings *pSettings); void ResizeTables(); private: bool SetBody(Body *pBody); void ClearStack(int pos=0); void SetPicture(); void TakePicture(); void Insert(CVector Pt); void Remove(CVector Pt); private: static void *s_pMainFrame; ThreeDWidget m_3dWidget; static QPoint s_WindowPos; static QSize s_WindowSize; static bool s_bWindowMaximized; QWidget *m_pctrlControlsWidget; QCheckBox *m_pctrlAxes, *m_pctrlLight, *m_pctrlSurfaces, *m_pctrlOutline, *m_pctrlPanels, *m_pctrlShowMasses; QAction *m_pXView, *m_pYView, *m_pZView, *m_pIsoView; QToolButton *m_pctrlX, *m_pctrlY, *m_pctrlZ, *m_pctrlIso; QPushButton *m_pctrlReset, *m_pctrlPickCenter; QPushButton *m_pctrlUndo, *m_pctrlRedo; QPushButton *m_pctrlOK, *m_pctrlCancel; QSlider *m_pctrlClipPlanePos; QSlider *m_pctrlEdgeWeight; QSlider *m_pctrlPanelBunch; QLineEdit *m_pctrlBodyName; QTextEdit *m_pctrlBodyDescription; QRadioButton *m_pctrlFlatPanels, *m_pctrlBSplines; LineBtn *m_pctrlBodyStyle; DoubleEdit *m_pctrlNXPanels, *m_pctrlNHoopPanels; QComboBox *m_pctrlXDegree, *m_pctrlHoopDegree; QPushButton *m_pctrlMenuButton; QMenu *BodyMenu; QTableView *m_pctrlFrameTable, *m_pctrlPointTable; QStandardItemModel *m_pFrameModel, *m_pPointModel; BodyTableDelegate *m_pFrameDelegate, *m_pPointDelegate; QItemSelectionModel *m_pSelectionModelPoint, *m_pSelectionModelFrame; QAction *m_pInsertPoint, *m_pRemovePoint, *m_pScaleBody; QAction *m_pShowCurFrameOnly, *m_pResetScales; QAction *m_pUndo, *m_pRedo; QAction *m_pExportBodyDef, *m_pImportBodyDef, *m_pExportBodyGeom, *m_pTranslateBody, *m_pBodyInertia;// *m_pSetupLight; QAction *m_pGrid; int m_StackPos; /**< the current position on the Undo stack */ QList m_UndoStack; /**< the stack of incremental modifications to the SplineFoil; we can't use the QStack though, because we need to access any point in the case of multiple undo operations */ // bool m_bStored; bool m_bResetFrame; bool m_bChanged; QPoint m_MousePos; QPoint m_ptPopUp; CVector m_RealPopUp; Frame *m_pFrame; Body *m_pBody; BodyGridDlg *m_BodyGridDlg; ArcBall m_ArcBall; QPoint m_LastPoint, m_PointDown; //make static to keep settings across multiple calls static bool s_bglLight; static bool s_bOutline; /**< true if the surface outlines are to be displayed in the 3D view*/ static bool s_bSurfaces; /**< true if the surfaces are to be displayed in the 3D view*/ static bool s_bVLMPanels; /**< true if the panels are to be displayed in the 3D view*/ static bool s_bAxes; /**< true if the axes are to be displayed in the 3D view*/ static bool s_bShowMasses; /**< true if the point masses are to be displayed on the openGL 3D view */ bool m_bEnableName; bool m_bTrans; bool m_bDragPoint; bool m_bArcball; //true if the arcball is to be displayed bool m_bCrossPoint; //true if the control point on the arcball is to be displayed bool m_bPickCenter; //true if the user is in the process of picking a new center for OpenGL display bool m_bResetglBody; bool m_bResetglBodyMesh; bool m_bResetglBody2D; bool m_bResetglBodyPoints; bool m_bIs3DScaleSet; // true if the 3D scale has been set, false if needs to be reset bool m_bShowLight; // true if the virtual light is to be displayed bool m_bCurFrameOnly; int m_GLList; static int s_NHoopPoints; //hoop resolution for NURBS bodies static int s_NXPoints; //longitudinal resolution for NURBS Bodies double m_ClipPlanePos; double MatIn[4][4], MatOut[4][4]; double m_glTop, m_HorizontalSplit, m_VerticalSplit;//screen split ratio for body 3D view double m_glScaled;//zoom factor for UFO double m_BodyScale, m_FrameScale, m_BodyRefScale, m_FrameRefScale; // scale for 3D display CVector m_UFOOffset; CVector m_BodyOffset; CVector m_FrameOffset; CVector m_BodyScalingCenter, m_BodyScaledOffset; CVector m_FrameScalingCenter, m_FrameScaledOffset; CVector m_glViewportTrans;// the translation vector in gl viewport coordinates CVector m_glRotCenter; // the center of rotation in object coordinates... is also the opposite of the translation vector QRect m_BodyLineRect; QRect m_FrameRect; QRect m_BodyRect; QRect m_rCltRect; }; #endif // BodyDlg_H xflr5-6.09-06/src/globals.cpp000644 001750 000144 00000232267 12247261301 017216 0ustar00techwinderusers000000 000000 /**************************************************************************** Globals Class Copyright (C) 2008-2013 Andre Deperrois adeperrois@xflr5.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 *****************************************************************************/ //Global functions /**@file This file contains the definitions of methods used throughout the program and not specific to one application. */ #include "globals.h" #include "mainframe.h" #include #include #include #include #include #include #include #include #include /** * Returns a double number as its root and its base 10 exponent * @param f the double number to reformat; is returned as f = f/pow(10.0,exp); * @param exp the base 10 exponent of f. */ void ExpFormat(double &f, int &exp) { if (f==0.0) { exp = 0; f = 0.0; return; } double f1 = qAbs(f); // int sgn = int(f/f1); if(f1<1) exp = (int)log10(f1)-1; else exp = (int)log10(f1); f = f/pow(10.0,exp); } /** * Solves a linear system using Gauss partial pivot method *@param A a pointer to the single dimensionnal array of double values. Size is n². *@param n the size of the square matrix *@param B a pointer to the array of m RHS *@param m the number of RHS arrays to solve *@param pbCancel a pointer to the boolean variable which holds true if the operation shold be interrupted. *@return true if the problem was successfully solved. */ bool Gauss(double *A, int n, double *B, int m, bool *pbCancel) { static int row, i, j, pivot_row, k; static double max, dum, *pa, *pA, *A_pivot_row; // for each variable find pivot row and perform forward substitution pa = A; for (row = 0; row < (n - 1); row++, pa += n) { // qApp->processEvents(); if(*pbCancel) return false; // find the pivot row A_pivot_row = pa; max = qAbs(*(pa + row)); pA = pa + n; pivot_row = row; for (i=row+1; i < n; pA+=n, i++) { if ((dum = qAbs(*(pA+row))) > max) { max = dum; A_pivot_row = pA; pivot_row = i; } } if (max <= 0.0) { return false; // the matrix A is singular } // and if it differs from the current row, interchange the two rows. if (pivot_row != row) { for (i = row; i < n; i++) { dum = *(pa + i); *(pa + i) = *(A_pivot_row + i); *(A_pivot_row + i) = dum; } for(k=0; k= 0; pa -= n, row--) { // qApp->processEvents(); if(*pbCancel) return false; if ( *(pa + row) == 0.0 ) { return false; // matrix is singular } dum = 1.0 / *(pa + row); for ( i = row + 1; i < n; i++) *(pa + i) *= dum; for(k=0; kf2) return false; return true; } /** * Tests if a given integer is between two double values *@param f the integer to test *@param f1 the first bound *@param f2 the second bound *@return true if f1f2) return false; return true; } /** * Tests if a given integer is an even number *@param n the integer to test *@return true if n is an even number */ bool IsEven(int n) { if(n%2==0) return true; else return false; } /** * Returns the index of a Qt-style based on the index of the style in the array *@param s the index of the style *@return The index of the Qt-style */ Qt::PenStyle GetStyle(int s) { if(s==0) return Qt::SolidLine; else if(s==1) return Qt::DashLine; else if(s==2) return Qt::DotLine; else if(s==3) return Qt::DashDotLine; else if(s==4) return Qt::DashDotDotLine; return Qt::SolidLine; } /** *Reads one line from an AVL-format text file *@deprecated the option to map AVL data was too comlplex and has been disabled. */ bool ReadAVLString(QTextStream &in, int &Line, QString &strong) { bool bComment = true; int pos; while(bComment && !in.atEnd()) { bComment = false; strong = in.readLine(); if(in.atEnd()) return false; strong = strong.trimmed(); pos = strong.indexOf("#",0); if(pos>=0) strong = strong.left(pos); pos = strong.indexOf("!",0); if(pos>=0) strong = strong.left(pos); if(strong.isEmpty()) bComment = true; Line++; } if(in.atEnd()) { return false; } return true; } /** * Reads the RGB int values of a color from binary datastream and returns a QColor. Inherited from the MFC versions of XFLR5. *@param ar the binary datastream *@param color the QColor read from the stream */ void ReadCOLORREF(QDataStream &ar, QColor &color) { qint32 colorref; int r,g,b; ar >> colorref; b = (int)(colorref/256/256); colorref -= b*256*256; g = (int)(colorref/256); r = colorref - g*256; color = QColor(r,g,b,255); } /** * Writes the RGB int values of a color to a binary datastream. Inherited from the MFC versions of XFLR5. *@param ar the binary datastream *@param color the QColor to write to the stream */ void WriteCOLORREF(QDataStream &ar, QColor const &color) { qint32 colorref; int r,g,b; color.getRgb(&r,&g,&b); colorref = b*256*256+g*256+r; ar << colorref; } /** * Reads a sequence of characters from a binary stream and returns a QString. Inherited from the MFC versions of XFLR5. *@param ar the binary datastream *@param strong the QString read from the stream */ void ReadCString(QDataStream &ar, QString &strong) { qint8 qi, ch; char c; ar >> qi; strong.clear(); for(int j=0; j> ch; c = char(ch); strong[j] = c; } } /** * Writes a sequence of characters from a QStrinf to a binary stream. Inherited from the MFC versions of XFLR5. *@param ar the binary datastream *@param strong the QString to output to the stream */ void WriteCString(QDataStream &ar, QString const &strong) { qint8 qi = strong.length(); QByteArray textline; char *text; textline = strong.toLatin1(); text = textline.data(); ar << qi; ar.writeRawData(text, qi); } /** *Rewinds one line from a QTextStream opened for reading *@param in the stream opened for reading *@param Line the index of the next Line to read *@param strong the line to =ewind */ bool Rewind1Line(QTextStream &in, int &Line, QString &strong) { int length = strong.length() * 1+2;//1 char takes one byte in the file ? int pos = in.pos(); in.seek(pos-length); Line--; return true; } /** * Takes a double number holding the value of a Reynolds number and returns a string. *@param str the return string with the formatted number *@param f the Reynolds number to be formatted */ void ReynoldsFormat(QString &str, double f) { int i, q, r, exp; f = (int(f/1000.0))*1000.0; exp = (int)log10(f); r = exp%3; q = (exp-r)/3; QString strong; strong = QString("%1").arg(f,0,'f',0); int l = strong.length(); for (i=0; i2.0/3.0) return 1.0; else if(tau>1.0/3.0) return (3.0*(tau-1.0/3.0)); else return 0.0; } /** * Returns the green component of a color scale depending on an input parameter with value between 0 and 1. * Used to draw a color scale between 0=blue and 1=red *@param tau the input parameter between 0 and 1. *@return the green component of the color */ double GLGetGreen(double tau) { if(tau<0.f || tau>1.0) return 0.0; else if(tau<1.0/4.0) return (4.0*tau); else if(tau>3.0/4.0) return (1.0-4.0*(tau-3.0/4.0)); else return 1.0; } /** * Returns the blue component of a color scale depending on an input parameter with value between 0 and 1. * Used to draw a color scale between 0=blue and 1=red *@param tau the input parameter between 0 and 1. *@return the blue component of the color */ double GLGetBlue(double tau) { if(tau>2.0/3.0) return 0.0; else if(tau>1.0/3.0) return (1.0-3.0*(tau-1.0/3.0)); else return 1.0; } /** Auxiliary integral used in LLT calculations */ double IntegralC2(double y1, double y2, double c1, double c2) { double res = 0.0; if (qAbs(y2-y1)<1.e-5) return 0.0; double g = (c2-c1)/(y2-y1); res = (c1-g*y1)*(c1-g*y1)*(y2-y1) + g * (c1-g*y1) *(y2*y2-y1*y1)+ g*g/3.0 *(y2*y2*y2-y1*y1*y1); return res; } /** Auxiliary integral used in LLT calculations */ double IntegralCy(double y1, double y2, double c1, double c2) { double res = 0.0; if (qAbs(y2-y1)<1.e-5) return (y1+y2)/2.0 * (c1+c2)/2.0; double g = (c2-c1)/(y2-y1); res = (c1-g*y1)/2.0 *(y2*y2 - y1*y1) + g/3.0 * (y2*y2*y2-y1*y1*y1); return res; } /** * Extracts three double values from a QString, and returns the number of extracted values. */ void ReadValues(QString line, int &res, double &x, double &y, double &z) { /* char *sx = new char[30]; char *sy = new char[30]; char *text;*/ QString str; bool bOK; line = line.simplified(); int pos = line.indexOf(" "); res = 0; if(pos>0) { str = line.left(pos); line = line.right(line.length()-pos); } else { str = line; line = ""; } x = str.toDouble(&bOK); if(bOK) res++; else { y=z=0.0; return; } line = line.trimmed(); pos = line.indexOf(" "); if(pos>0) { str = line.left(pos); line = line.right(line.length()-pos); } else { str = line; line = ""; } y = str.toDouble(&bOK); if(bOK) res++; else { z=0.0; return; } line = line.trimmed(); if(!line.isEmpty()) { z = line.toDouble(&bOK); if(bOK) res++; } else z=0.0; } /** int Crout_LU_Decomposition_with_Pivoting(double *A, int pivot[], int n) Unknown author http:mymathlib.webtrellis.net/index.html Description: This routine uses Crout's method to decompose a row interchanged version of the n x n matrix A into a lower triangular matrix L and a unit upper triangular matrix U such that A = LU. The matrices L and U replace the matrix A so that the original matrix A is destroyed. Note! In Crout's method the diagonal elements of U are 1 and are not stored. Note! The determinant of A is the product of the diagonal elements of L. (det A = det L * det U = det L). The LU decomposition is convenient when one needs to solve the linear equation Ax = B for the vector x while the matrix A is fixed and the vector B is varied. The routine for solving the linear system Ax = B after performing the LU decomposition for A is Crout_LU_with_Pivoting_Solve. (see below). The Crout method with partial pivoting is: Determine the pivot row and interchange the current row with the pivot row, then assuming that row k is the current row, k = 0, ..., n - 1 evaluate in order the the following pair of expressions L[i][k] = (A[i][k] - (L[i][0]*U[0][k] + . + L[i][k-1]*U[k-1][k])) for i = k, ... , n-1, U[k][j] = A[k][j] - (L[k][0]*U[0][j] + ... + L[k][k-1]*U[k-1][j]) / L[k][k] for j = k+1, ... , n-1. The matrix U forms the upper triangular matrix, and the matrix L forms the lower triangular matrix. Arguments: double *A Pointer to the first element of the matrix A[n][n]. int pivot[] The i-th element is the pivot row interchanged with row i. int n The number of rows or columns of the matrix A. Return Values: 0 Success -1 Failure - The matrix A is singular. */ bool Crout_LU_Decomposition_with_Pivoting(double *A, int pivot[], int n, bool *pbCancel, double TaskSize, double &Progress) { int i, j, k; double *p_k, *p_row, *p_col; double max=0.0; p_col = NULL; // For each row and column, k = 0, ..., n-1, for (k=0, p_k=A; kprocessEvents(); if(*pbCancel) return false; } return true; } /** int Crout_LU_with_Pivoting_Solve(double *LU, double B[], int pivot[], double x[], int n) Unknown author http:mymathlib.webtrellis.net/index.html Description: This routine uses Crout's method to solve the linear equation Ax = B. This routine is called after the matrix A has been decomposed into a product of a lower triangular matrix L and a unit upper triangular matrix U without pivoting. The argument LU is a pointer to the matrix the superdiagonal part of which is U and the subdiagonal together with the diagonal part is L. (The diagonal part of U is 1 and is not stored.) The matrix A = LU. The solution proceeds by solving the linear equation Ly = B for y and subsequently solving the linear equation Ux = y for x. Arguments: double *LU Pointer to the first element of the matrix whose elements form the lower and upper triangular matrix factors of A. double *B Pointer to the column vector, (n x 1) matrix, B. int pivot[] The i-th element is the pivot row interchanged with row i. double *x Solution to the equation Ax = B. int n The number of rows or columns of the matrix LU. Return Values: true : Success false : Failure - The matrix A is singular. */ bool Crout_LU_with_Pivoting_Solve(double *LU, double B[], int pivot[], double x[], int Size, bool *pbCancel) { int i, k; double *p_k; double dum; // Solve the linear equation Lx = B for x, where L is a lower triangular matrix. for (k=0, p_k=LU; kprocessEvents(); if(*pbCancel) return false; } // Solve the linear equation Ux = y, where y is the solution // obtained above of Lx = B and U is an upper triangular matrix. // The diagonal part of the upper triangular part of the matrix is // assumed to be 1.0. for (k=Size-1, p_k=LU+Size*(Size-1); k>=0; k--, p_k-=Size) { if (pivot[k] != k) { dum=B[k]; B[k]=B[pivot[k]]; B[pivot[k]]=dum; } for (i=k+1; iprocessEvents(); if(*pbCancel) return false; } return true; } /** *Returns the determinant of a 4x4 matrix *@param aij a pointer to a one-dimensional array holding the 16 double values of the matrix *@return the matrix's determinant */ double Det44(double *aij) { // returns the determinant of a 4x4 matrix static int i,j,k,l,p,q; static double det, sign, a33[16]; det = 0.0; for(i=0; i<4; i++) { for(j=0; j<4; j++) { p = 0; for(k=0; k<4 && k!=i; k++) { q = 0; for(l=0; l<4 && l!=j; l++) { *(a33+p*3+q) = *(aij+4*k+l);// could also do it by address, to be a little faster q++; } p++; } sign = pow(-1.0,i+j); det += sign * Det33(a33); } } return det; } /** *Returns the determinant of a 3x3 matrix *@param aij a pointer to a one-dimensional array holding the 9 double values of the matrix *@return the matrix's determinant */ double Det33(double *aij) { //returns the determinant of a 3x3 matrix double det; det = aij[0]*aij[4]*aij[8]; det -= aij[0]*aij[5]*aij[7]; det -= aij[1]*aij[3]*aij[8]; det += aij[1]*aij[5]*aij[6]; det += aij[2]*aij[3]*aij[7]; det -= aij[2]*aij[4]*aij[6]; return det; } /** *Returns the determinant of a complex 3x3 matrix *@param aij a pointer to a one-dimensional array holding the 9 complex values of the matrix *@return the matrix's determinant */ complex Det33(complex *aij) { //returns the determinant of a 3x3 matrix complex det; det = aij[0]*aij[4]*aij[8]; det -= aij[0]*aij[5]*aij[7]; det -= aij[1]*aij[3]*aij[8]; det += aij[1]*aij[5]*aij[6]; det += aij[2]*aij[3]*aij[7]; det -= aij[2]*aij[4]*aij[6]; return det; } /** *Returns the cofactor of an element in a 4x4 matrix of complex values. *@param aij a pointer to a one-dimensional array holding the 16 complex values of the matrix. *@param i the number of the element's line, starting at 0. *@param j the number of the element's column, starting at 0. *@return the cofactor of element (i,j). */ complex Cofactor44(complex *aij, int &i, int &j) { //returns the complex cofactor of element i,j, in the 4x4 matrix aij static int k,l,p,q; static complex a33[9]; p = 0; for(k=0; k<4; k++) { if(k!=i) { q = 0; for(l=0; l<4; l++) { if(l!=j) { a33[p*3+q] = *(aij+4*k+l); q++; } } p++; } } return Det33(a33); } /** *Returns the determinant of a complex 4x4 matrix *@param aij a pointer to a one-dimensional array holding the 16 complex double values of the matrix *@return the matrix's determinant */ complex Det44(complex *aij) { // returns the determinant of a 4x4 matrix static int i,j,k,l,p,q; static double sign; static complex det, a33[16]; det = 0.0; i=0; for(j=0; j<4; j++) { p = 0; for(k=0; k<4; k++) { if(k!=i) { q = 0; for(l=0; l<4; l++) { if(l!=j) { a33[p*3+q] = aij[4*k+l]; q++; } } p++; } } sign = pow(-1.0,i+j); det += sign * aij[4*i+j] * Det33(a33); } return det; } /** *Inverts a complex 4x4 matrix *@param ain in input, a pointer to a one-dimensional array holding the 16 complex values of the input matrix *@param aout in output, a pointer to a one-dimensional array holding the 16 complex values of the inverted matrix *@return if the inversion was successful */ bool Invert44(complex *ain, complex *aout) { //small size, use the direct method static int i,j; static complex det; static double sign; det = Det44(ain); if(abs(det) AC[16]; // complex V[4]; complex lambda(2.0, 0.0); for(int i=0; i<4; i++) { for(int j=0; j<4;j++) { AC[i*4+j] = complex(A[i][j],0.0); } } CharacteristicPol(A, p); complex roots[POLYNOMORDER]; if(LinBairstow(p, roots, 4)) { } else { } } /**________________________________________________________________________ * Finds the eigenvector associated to an eigenvalue. * Solves the system A.V = lambda.V where A is a 4x4 complex matrix * in input : * - matrix A * - the array of complex eigenvalues * in output * - the array of complex eigenvectors * * The eigenvector is calculated by direct matrix inversion. * One of the vector's component is set to 1, to avoid the trivial solution V=0; * * (c) Andre Deperrois October 2009 *@param a the complex two-dimensional 4x4 input matrix to diagonalize *@param lambda the output array of four complex eigenvalues *@param V the eigenvector as a one-dimensional array of complex values *________________________________________________________________________ */ bool Eigenvector(double a[][4], complex lambda, complex *V) { static complex detm, detr; static complex r[9], m[9]; int ii, jj, i, j, kp; // first find a pivot for which the associated n-1 determinant is not zero bool bFound = false; kp=0; do { V[kp] = 1.0; ii= 0; for(i=0;i<4 ; i++) { if(i!=kp) { jj=0; for(j=0; j<4; j++) { if(j!=kp) { m[ii*3+jj] = a[i][j]; jj++; } } m[ii*3+ii] -= lambda; ii++; } } detm = Det33(m); bFound = std::abs(detm)>0.0; if(bFound || kp>=3) break; kp++; }while(true); if(!bFound) return false; // at this point we have identified pivot kp // with a non-zero subdeterminant. // so solve for the other 3 eigenvector components. // using Cramer's rule //create rhs determinant jj=0; for(j=0; j<4; j++) { memcpy(r,m, 9*sizeof(complex)); if(j!=kp) { ii= 0; for(i=0; i<4; i++) { if(i!=kp) { r[ii*3+jj] = - a[i][kp]; ii++; } } detr = Det33(r); V[j] = detr/detm; jj++; } } return true; } #define TOLERANCE 1.e-8 #define MAXBAIRSTOWITER 30 /** * Finds the complex roots of a polynom P(x) using Lin-Bairstow's method * P(x) = Sum p_i x^i i = 0..n; * The polynoms coefficient are in array p * * Andre Deperrois October 2009 *@param p the array of the polynoms double's coefficients *@param root the array of the polynom's complex roots *@param n the polynom's order *@return true if the extraction was successful */ bool LinBairstow(double *p, complex *root, int n) { double b[POLYNOMORDER], c[POLYNOMORDER]; int i, k, nn, iter; double r,s,d0,d1,d2; double Delta; memset(b, 0, POLYNOMORDER*sizeof(double)); memset(c, 0, POLYNOMORDER*sizeof(double)); //T(x) = x2 -rx -s; //R(x) = u(x-r)+v //remainder of deivision of by Q //Q(x) = Sum b_i x^(i-2) //P(x) = (x2-rx+s) Q(x) + u(x-r) +v nn=n ;//initial order is polynom order r=-2.0;//initial guesses s=-1.0; do { iter = 0; do { //compute recursively the coefs b_i of polynom Q b[nn] = p[nn]; b[nn-1] = p[nn-1] + r * b[nn]; for(k=nn-2; k>=0; k--) b[k] = p[k] + r*b[k+1] + s*b[k+2]; //build the partial derivatives c_i c[nn] = b[nn]; c[nn-1] = b[nn-1] + r * c[nn]; for(k=nn-2; k>=1; k--) c[k] = b[k] + r*c[k+1] + s*c[k+2]; d0 = c[1]*c[3] - c[2]*c[2]; d1 = (-b[0]*c[3]+b[1]*c[2])/d0; d2 = (-b[1]*c[1]+b[0]*c[2])/d0; r+=d1; s+=d2; iter++; } while((std::abs(d1)> TOLERANCE || std::abs(d2)> TOLERANCE) && iter < MAXBAIRSTOWITER); if(iter>=MAXBAIRSTOWITER)return false; //we have a division //so find the roots of the remainder R Delta = r*r+4.0*s; if(Delta<0.0) { //complex roots root[nn-1] = complex(r/2.0, sqrt(qAbs(Delta))/2.0); root[nn-2] = complex(r/2.0, -sqrt(qAbs(Delta))/2.0); } else { //real roots root[nn-1] = complex(r/2.0 + sqrt(Delta)/2.0, 0.0); root[nn-2] = complex(r/2.0 - sqrt(Delta)/2.0, 0.0); } //deflate polynom order for(i=nn; i>=2; i--) { p[i-2] = b[i]; } nn-=2; if(nn==2) { //last two roots, solve directly if(qAbs(p[2])PRECISION) { //last single root, real root[0] = -p[0]/p[1]; } else return false; } else { Delta = p[1]*p[1]-4.0*p[0]*p[2]; if(Delta<0) { //complex roots root[nn-1] = complex(-p[1]/2.0/p[2], sqrt(qAbs(Delta))/2.0/p[2]); root[nn-2] = complex(-p[1]/2.0/p[2], -sqrt(qAbs(Delta))/2.0/p[2]); } else { //real roots root[nn-1] = complex((-p[1]+sqrt(Delta))/2.0/p[2], 0.0); root[nn-2] = complex((-p[1]-sqrt(Delta))/2.0/p[2], 0.0); } } break; } if(nn==1) { if(qAbs(p[1])>PRECISION) { //last single root, real root[0] = -p[0]/p[1]; } else return false; break; } }while(nn>2); return true; } /** *Interpolates a variable on the polar mesh, based on the geometrical position of a point between two sections on a wing. *@param m_poaPolar the pointer to the array of polars. *@param nVar the index of the variable to interpolate. *@param pFoil0 the pointer to the left foil of the wing's section. *@param pFoil1 the pointer to the left foil of the wing's section. *@param Re the Reynolds number at the point's position. *@param Cl the lift coefficient at the point's position, used as the input parameter. *@param Tau the relative position of the point between the two foils. *@param bOutRe true if Cl is outside the min or max Cl of the polar mesh. *@param bError if Re is outside the min or max Reynolds number of the polar mesh. *@return the interpolated value. */ double GetVar(int nVar, Foil *pFoil0, Foil *pFoil1, double Re, double Cl, double Tau, bool &bOutRe, bool &bError) { bool IsOutRe = false; bool IsError = false; bOutRe = false; bError = false; double Var0, Var1; if(!pFoil0) { Cl = 0.0; Var0 = 0.0; } else Var0 = GetPlrPointFromCl(pFoil0, Re, Cl,nVar, IsOutRe, IsError); if(IsOutRe) bOutRe = true; if(IsError) bError = true; if(!pFoil1) { Cl = 0.0; Var1 = 0.0; } else Var1 = GetPlrPointFromCl(pFoil1, Re, Cl,nVar, IsOutRe, IsError); if(IsOutRe) bOutRe = true; if(IsError) bError = true; if (Tau<0.0) Tau = 0.0; if (Tau>1.0) Tau = 1.0; return ((1-Tau) * Var0 + Tau * Var1); } /** * Returns a pointer to a variable array of a polar object, based on the variable's index * @param pPolar the pointer to the polar object * @param iVar the index of the variable * @return the pointer to the array holding the values of the variable */ void * GetPlrVariable(Polar *pPolar, int iVar) { void * pVar; switch (iVar) { case 0: pVar = &pPolar->m_Alpha; break; case 1: pVar = &pPolar->m_Cl; break; case 2: pVar = &pPolar->m_Cd; break; case 3: pVar = &pPolar->m_Cdp; break; case 4: pVar = &pPolar->m_Cm; break; case 5: pVar = &pPolar->m_XTr1; break; case 6: pVar = &pPolar->m_XTr2; break; case 7: pVar = &pPolar->m_HMom; break; case 8: pVar = &pPolar->m_Cpmn; break; case 9: pVar = &pPolar->m_ClCd; break; case 10: pVar = &pPolar->m_Cl32Cd; break; case 11: pVar = &pPolar->m_XCp; break; default: pVar = &pPolar->m_Alpha; break; } return pVar; } /** * Returns the value of an aero coefficient, interpolated on a polar mesh, and based on the value of the Reynolds Number and of the aoa. * Proceeds by identifiying the two polars surronding Re, then interpolating both with the value of Alpha, * last by interpolating the requested variable between the values measured on the two polars. *@param m_poaPolar the pointer to the array of polars. *@param pFoil the pointer to the foil *@param Re the Reynolds number . *@param Alpha the angle of attack. *@param PlrVar the index of the variable to interpolate. *@param bOutRe true if Cl is outside the min or max Cl of the polar mesh. *@param bError if Re is outside the min or max Reynolds number of the polar mesh. *@return the interpolated value. */ double GetPlrPointFromAlpha(Foil *pFoil, double Re, double Alpha, int PlrVar, bool &bOutRe, bool &bError) { /* Var 0 = m_Alpha; 1 = m_Cl; 2 = m_Cd; 3 = m_Cdp; 4 = m_Cm; 5, 6 = m_XTr1, m_XTr2; 7, 8 = m_HMom, m_Cpmn; 9,10 = m_ClCd, m_Cl32Cd; 11 = m_XCp */ QList *pX; double amin, amax; double Var1, Var2, u; amin = amax = Var1 = Var2 = u = 0.0; int i; Polar *pPolar; bOutRe = false; bError = false; if(!pFoil) { bOutRe = true; bError = true; return 0.000; } int size; int n = 0; // Are there any Type 1 polars available for this foil ? for (i=0; im_PolarType==FIXEDSPEEDPOLAR) && (pPolar->m_FoilName == pFoil->m_FoilName)) { n++; if(n>=2) break; } } //more than one polar - interpolate between - tough job //First Find the two polars with Reynolds number surrounding wanted Re Polar * pPolar1 = NULL; Polar * pPolar2 = NULL; int nPolars = MainFrame::s_oaPolar.size(); //Type 1 Polars are sorted by crescending Re Number //if Re is less than that of the first polar, use this one for (i=0; i< nPolars; i++) { pPolar = (Polar*)MainFrame::s_oaPolar.at(i); if((pPolar->m_PolarType==FIXEDSPEEDPOLAR) && (pPolar->m_FoilName == pFoil->m_FoilName) && pPolar->m_Alpha.size()>0) { // we have found the first type 1 polar for this foil if (Re < pPolar->m_Reynolds) { bOutRe = true; //interpolate Alpha on this polar pX = (QList *) GetPlrVariable(pPolar, PlrVar); size = pPolar->m_Alpha.size(); if(Alpha < pPolar->m_Alpha[0]) { return (*pX)[0]; } else if(Alpha > pPolar->m_Alpha[size-1]) { return (*pX)[size-1]; } for (i=0; im_Alpha[i] <= Alpha && Alpha < pPolar->m_Alpha[i+1]) { //interpolate if(pPolar->m_Alpha[i+1]-pPolar->m_Alpha[i] < 0.00001)//do not divide by zero return (*pX)[i]; else { u = (Alpha - pPolar->m_Alpha[i]) /(pPolar->m_Alpha[i+1]-pPolar->m_Alpha[i]); return ((*pX)[i] + u * ((*pX)[i+1]-(*pX)[i])); } } } break; } break; } } // if not Find the two polars for (i=0; i< nPolars; i++) { pPolar = (Polar*)MainFrame::s_oaPolar.at(i); if((pPolar->m_PolarType==FIXEDSPEEDPOLAR) && (pPolar->m_FoilName == pFoil->m_FoilName) && pPolar->m_Alpha.size()>0) { // we have found the first type 1 polar for this foil pPolar->GetAlphaLimits(amin, amax); if (pPolar->m_Reynolds <= Re) { if(amin <= Alpha && Alpha <= amax) { pPolar1 = pPolar; } } else { if(amin <= Alpha && Alpha <= amax) { pPolar2 = pPolar; break; } } } } if (!pPolar2) { //then Re is greater than that of any polar // so use last polar and interpolate alphas on this polar bOutRe = true; if(!pPolar1) { bError = true; return 0.000; } size = pPolar1->m_Alpha.size(); if(!size) { bError = true; return 0.000; } pX = (QList *) GetPlrVariable(pPolar1, PlrVar); if(Alpha < pPolar1->m_Alpha[0]) return (*pX)[0]; if(Alpha > pPolar1->m_Alpha[size-1]) return (*pX)[size-1]; for (i=0; im_Alpha[i] <= Alpha && Alpha < pPolar1->m_Alpha[i+1]) { //interpolate if(pPolar1->m_Alpha[i+1]-pPolar1->m_Alpha[i] < 0.00001){//do not divide by zero return (*pX)[i]; } else { u = (Alpha - pPolar1->m_Alpha[i]) /(pPolar1->m_Alpha[i+1]-pPolar1->m_Alpha[i]); return (*pX)[i] + u * ((*pX)[i+1]-(*pX)[i]); } } } //Out in Re, out in alpha... return (*pX)[size-1] ; } else { // Re is between that of polars 1 and 2 // so interpolate alphas for each if(!pPolar1) { bOutRe = true; bError = true; return 0.000; } size = (int)pPolar1->m_Alpha.size(); if(!size) { bOutRe = true; bError = true; return 0.000; } pX = (QList *) GetPlrVariable(pPolar1, PlrVar); if(Alpha < pPolar1->m_Alpha[0]) Var1 = (*pX)[0]; else if(Alpha > pPolar1->m_Alpha[size-1]) Var1 = (*pX)[size-1]; else { for (i=0; im_Alpha[i] <= Alpha && Alpha < pPolar1->m_Alpha[i+1]){ //interpolate if(pPolar1->m_Alpha[i+1]-pPolar1->m_Alpha[i] < 0.00001)//do not divide by zero Var1 = (*pX)[i]; else { u = (Alpha - pPolar1->m_Alpha[i]) /(pPolar1->m_Alpha[i+1]-pPolar1->m_Alpha[i]); Var1 = (*pX)[i] + u * ((*pX)[i+1]-(*pX)[i]); } } } } size = (int)pPolar2->m_Alpha.size(); if(!size) { bOutRe = true; bError = true; return 0.000; } pX = (QList *) GetPlrVariable(pPolar2, PlrVar); if(Alpha < pPolar2->m_Alpha[0]) { bOutRe = true; bError = true; Var2 = (*pX)[0]; } else if(Alpha > pPolar2->m_Alpha[size-1]) { bOutRe = true; bError = true; Var2 = (*pX)[size-1]; } else{ for (i=0; im_Alpha[i] <= Alpha && Alpha < pPolar2->m_Alpha[i+1]) { //interpolate pX = (QList *) GetPlrVariable(pPolar2, PlrVar); if(pPolar2->m_Alpha[i+1]-pPolar2->m_Alpha[i] < 0.00001)//do not divide by zero Var2 = (*pX)[i]; else{ u = (Alpha - pPolar2->m_Alpha[i]) /(pPolar2->m_Alpha[i+1]-pPolar2->m_Alpha[i]); Var2 = (*pX)[i] + u * ((*pX)[i+1]-(*pX)[i]); } } } } // then interpolate Variable double v = (Re - pPolar1->m_Reynolds) / (pPolar2->m_Reynolds - pPolar1->m_Reynolds); double Var = Var1 + v * (Var2-Var1); return Var; } // AfxMessageBox("Error interpolating", MB_OK); // bOutRe = true; // bError = true; // return 0.000;// we missed something somewhere... } /** * Returns the value of an aero coefficient, interpolated on a polar mesh, and based on the value of the Reynolds Number and of the lift coefficient. * Proceeds by identifiying the two polars surronding Re, then interpolating both with the value of Alpha, * last by interpolating the requested variable between the values measured on the two polars. *@param m_poaPolar the pointer to the array of polars. *@param pFoil the pointer to the foil *@param Re the Reynolds number . *@param Cl the lift coefficient, used as the input parameter for interpolation. *@param PlrVar the index of the variable to interpolate. *@param bOutRe true if Cl is outside the min or max Cl of the polar mesh. *@param bError if Re is outside the min or max Reynolds number of the polar mesh. *@return the interpolated value. */ double GetPlrPointFromCl(Foil *pFoil, double Re, double Cl, int PlrVar, bool &bOutRe, bool &bError) { /* Var 0 = m_Alpha; 1 = m_Cl; 2 = m_Cd; 3 = m_Cdp; 4 = m_Cm; 5, 6 = m_XTr1, m_XTr2; 7, 8 = m_HMom, m_Cpmn; 9,10 = m_ClCd, m_Cl32Cd; */ QList *pX; double Clmin, Clmax; Polar *pPolar; double Var1, Var2, u, dist; Var1 = Var2 = u = dist = 0.0; int pt; int size; int n, i; bOutRe = false; bError = false; if(!pFoil) { bOutRe = true; bError = true; return 0.000; } n=0; // Are there any Type 1 polars available for this foil ? for (i = 0; i< MainFrame::s_oaPolar.size(); i++) { pPolar = (Polar*)MainFrame::s_oaPolar.at(i); if((pPolar->m_PolarType==FIXEDSPEEDPOLAR) && (pPolar->m_FoilName == pFoil->m_FoilName)) { n++; if(n>=2) break; } } //more than one polar - interpolate between - tough job //First Find the two polars with Reynolds number surrounding wanted Re Polar * pPolar1 = NULL; Polar * pPolar2 = NULL; int nPolars = MainFrame::s_oaPolar.size(); //Type 1 Polars are sorted by crescending Re Number //if Re is less than that of the first polar, use this one for (i=0; i< nPolars; i++) { pPolar = (Polar*)MainFrame::s_oaPolar.at(i); if((pPolar->m_PolarType==FIXEDSPEEDPOLAR) && (pPolar->m_FoilName == pFoil->m_FoilName) && pPolar->m_Cl.size()>0) { // we have found the first type 1 polar for this foil if (Re < pPolar->m_Reynolds) { bOutRe = true; //interpolate Cl on this polar pX = (QList *) GetPlrVariable(pPolar, PlrVar); size = (int)pPolar->m_Cl.size(); if(Cl < pPolar->m_Cl[0]) { return (*pX)[0]; } if(Cl > pPolar->m_Cl[size-1]) { return (*pX)[size-1]; } for (i=0; im_Cl[i] <= Cl && Cl < pPolar->m_Cl[i+1]) { //interpolate if(pPolar->m_Cl[i+1]-pPolar->m_Cl[i] < 0.00001)//do not divide by zero return (*pX)[i]; else { u = (Cl - pPolar->m_Cl[i]) /(pPolar->m_Cl[i+1]-pPolar->m_Cl[i]); return ((*pX)[i] + u * ((*pX)[i+1]-(*pX)[i])); } } } break; } break; } } // if not Find the two polars for (i=0; i< nPolars; i++) { pPolar = (Polar*)MainFrame::s_oaPolar.at(i); if((pPolar->m_PolarType==FIXEDSPEEDPOLAR) && (pPolar->m_FoilName == pFoil->m_FoilName) && pPolar->m_Cl.size()>0) { // we have found the first type 1 polar for this foil pPolar->GetClLimits(Clmin, Clmax); if (pPolar->m_Reynolds <= Re) { if(Clmin <= Cl && Cl <= Clmax) { pPolar1 = pPolar; } } else { if(Clmin <= Cl && Cl <= Clmax) { pPolar2 = pPolar; break; } } } } if (!pPolar2) { //then Re is greater than that of any polar // so use last polar and interpolate Cls on this polar bOutRe = true; if(!pPolar1) { bOutRe = true; bError = true; return 0.000; } size = (int)pPolar1->m_Cl.size(); if(!size) { bOutRe = true; bError = true; return 0.000; } pX = (QList *) GetPlrVariable(pPolar1, PlrVar); if(Cl < pPolar1->m_Cl[0]) return (*pX)[0]; if(Cl > pPolar1->m_Cl[size-1]) return (*pX)[size-1]; for (i=0; im_Cl[i] <= Cl && Cl < pPolar1->m_Cl[i+1]) { //interpolate if(pPolar1->m_Cl[i+1]-pPolar1->m_Cl[i] < 0.00001) {//do not divide by zero return (*pX)[i]; } else { u = (Cl - pPolar1->m_Cl[i]) /(pPolar1->m_Cl[i+1]-pPolar1->m_Cl[i]); return ((*pX)[i] + u * ((*pX)[i+1]-(*pX)[i])); } } } //Out in Re, out in Cl... return (*pX)[size-1]; } else { // Re is between that of polars 1 and 2 // so interpolate Cls for each if(!pPolar1) { bOutRe = true; bError = true; return 0.000; } size = (int)pPolar1->m_Cl.size(); if(!size) { bOutRe = true; bError = true; return 0.000; } pX = (QList *) GetPlrVariable(pPolar1, PlrVar); pPolar1->GetClLimits(Clmin, Clmax); if(Cl < Clmin) { Var1 = (*pX)[0]; bOutRe = true; } else if(Cl > Clmax) { Var1 = (*pX)[size-1]; bOutRe = true; } else { //first Find the point closest to Cl=0 pt = 0; dist = qAbs(pPolar1->m_Cl[0]); for (i=1; im_Cl[i])< dist) { dist = qAbs(pPolar1->m_Cl[i]); pt = i; } } if(Clm_Cl[pt]) { for (i=pt; i>0; i--) { if(Cl<= pPolar1->m_Cl[i] && Cl > pPolar1->m_Cl[i-1]) { //interpolate if(qAbs(pPolar1->m_Cl[i]-pPolar1->m_Cl[i-1]) < 0.00001) { //do not divide by zero Var1 = (*pX)[i]; break; } else { u = (Cl - pPolar1->m_Cl[i-1]) /(pPolar1->m_Cl[i]-pPolar1->m_Cl[i-1]); Var1 = (*pX)[i-1] + u * ((*pX)[i]-(*pX)[i-1]); break; } } } } else { for (i=pt; im_Cl[i] <=Cl && Cl < pPolar1->m_Cl[i+1]) { //interpolate if(qAbs(pPolar1->m_Cl[i+1]-pPolar1->m_Cl[i]) < 0.00001){//do not divide by zero Var1 = (*pX)[i]; break; } else { u = (Cl - pPolar1->m_Cl[i]) /(pPolar1->m_Cl[i+1]-pPolar1->m_Cl[i]); Var1 = (*pX)[i] + u * ((*pX)[i+1]-(*pX)[i]); break; } } } } } size = (int)pPolar2->m_Cl.size(); if(!size) { bOutRe = true; bError = true; return 0.000; } pX = (QList *) GetPlrVariable(pPolar2, PlrVar); pPolar2->GetClLimits(Clmin, Clmax); if(Cl < Clmin) { Var2 = (*pX)[0]; bOutRe = true; } else if(Cl > Clmax) { Var2 = (*pX)[size-1]; bOutRe = true; } else { //first Find the point closest to Cl=0 pt = 0; dist = qAbs(pPolar2->m_Cl[0]); for (i=1; im_Cl[i])< dist) { dist = qAbs(pPolar2->m_Cl[i]); pt = i; } } if(Clm_Cl[pt]) { for (i=pt; i>0; i--) { if(Cl<= pPolar2->m_Cl[i] && Cl > pPolar2->m_Cl[i-1]) { //interpolate if(qAbs(pPolar2->m_Cl[i]-pPolar2->m_Cl[i-1]) < 0.00001) {//do not divide by zero Var2 = (*pX)[i]; break; } else { u = (Cl - pPolar2->m_Cl[i-1]) /(pPolar2->m_Cl[i]-pPolar2->m_Cl[i-1]); Var2 = (*pX)[i-1] + u * ((*pX)[i]-(*pX)[i-1]); break; } } } } else { for (i=pt; im_Cl[i] <=Cl && Cl < pPolar2->m_Cl[i+1]) { //interpolate if(qAbs(pPolar2->m_Cl[i+1]-pPolar2->m_Cl[i]) < 0.00001) { //do not divide by zero Var2 = (*pX)[i]; break; } else { u = (Cl - pPolar2->m_Cl[i]) /(pPolar2->m_Cl[i+1]-pPolar2->m_Cl[i]); Var2 = (*pX)[i] + u * ((*pX)[i+1]-(*pX)[i]); break; } } } } } // then interpolate Variable double v = (Re - pPolar1->m_Reynolds) / (pPolar2->m_Reynolds - pPolar1->m_Reynolds); double Var = Var1 + v * (Var2-Var1); return Var; } } /** *Interpolates the lift coefficient on the polar mesh, based on the geometrical position of a point between two sections on a wing. *@param m_poaPolar the pointer to the array of polars. *@param nVar the index of the variable to interpolate. *@param pFoil0 the pointer to the left foil of the wing's section. *@param pFoil1 the pointer to the left foil of the wing's section. *@param Re the Reynolds number at the point's position. *@param Alpha the apparent aoa at the point's position. *@param Tau the relative position of the point between the two foils. *@param bOutRe true if Cl is outside the min or max Cl of the polar mesh. *@param bError if Re is outside the min or max Reynolds number of the polar mesh. *@return the interpolated value. */ double GetCl(Foil *pFoil0, Foil *pFoil1, double Re, double Alpha, double Tau, bool &bOutRe, bool &bError) { double Cl0, Cl1; bool IsOutRe = false; bool IsError = false; bOutRe = false; bError = false; if(!pFoil0) Cl0 = 2.0*PI*(Alpha*PI/180.0); else Cl0 = GetPlrPointFromAlpha(pFoil0, Re, Alpha, 1, IsOutRe, IsError); if(IsOutRe) bOutRe = true; if(IsError) bError = true; if(!pFoil1) Cl1 = 2.0*PI*(Alpha*PI/180.0); else Cl1 = GetPlrPointFromAlpha(pFoil1, Re, Alpha, 1, IsOutRe, IsError); if(IsOutRe) bOutRe = true; if(IsError) bError = true; if (Tau<0.0) Tau = 0.0; if (Tau>1.0) Tau = 1.0; return ((1-Tau) * Cl0 + Tau * Cl1); } /** *Returns the zero-lift moment coefficient interpolated on the polar mesh, based on the geometrical position of a point between two sections on a wing. *@param m_poaPolar the pointer to the array of polars. *@param pFoil0 the pointer to the left foil of the wing's section. *@param pFoil1 the pointer to the left foil of the wing's section. *@param Re the Reynolds number at the point's position. *@param Tau the relative position of the point between the two foils. *@param bOutRe true if Cl is outside the min or max Cl of the polar mesh. *@param bError if Re is outside the min or max Reynolds number of the polar mesh. *@return the interpolated value for the zero-moment lift coefficient. */ double GetCm0(Foil *pFoil0, Foil *pFoil1, double Re, double Tau, bool &bOutRe, bool &bError) { //Find 0-lift angle for local foil double Alpha; double Cm0, Cm1; double Cl0 = 1.0; double Cl1; bOutRe = false; bError = false; bool IsOutRe; bool IsError; bOutRe = false; for (int i=-10; i<10; i++) { Alpha = (double)i; Cl1 = GetCl(pFoil0, pFoil1, Re, Alpha, Tau, IsOutRe, IsError); if(Cl1>0.0) { if(IsOutRe) bOutRe = true; if(IsError) bError = true; break; } Cl0 = Cl1; } if(Cl0>0.0) { return 0.0; } Cm0 = GetCm(pFoil0, pFoil1, Re, Alpha-1.0, Tau, IsOutRe, IsError); if(IsOutRe) bOutRe = true; if(IsError) bError = true; Cm1 = GetCm(pFoil0, pFoil1, Re, Alpha, Tau, IsOutRe, IsError); if(IsOutRe) bOutRe = true; if(IsError) bError = true; if (Tau<0.0) Tau = 0.0; if (Tau>1.0) Tau = 1.0; double Res = Cm0 + (Cm1-Cm0)*(0.0-Cl0)/(Cl1-Cl0); return Res; } /** *Interpolates the moment coefficient on the polar mesh, based on the geometrical position of a point between two sections on a wing. *@param m_poaPolar the pointer to the array of polars. *@param nVar the index of the variable to interpolate. *@param pFoil0 the pointer to the left foil of the wing's section. *@param pFoil1 the pointer to the left foil of the wing's section. *@param Re the Reynolds number at the point's position. *@param Alpha the apparent aoa at the point's position. *@param Tau the relative position of the point between the two foils. *@param bOutRe true if Cl is outside the min or max Cl of the polar mesh. *@param bError if Re is outside the min or max Reynolds number of the polar mesh. *@return the interpolated value. */ double GetCm(Foil *pFoil0, Foil *pFoil1, double Re, double Alpha, double Tau, bool &bOutRe, bool &bError) { double Cm0, Cm1; bool IsOutRe = false; bool IsError = false; bOutRe = false; bError = false; if(!pFoil0) Cm0 = 0.0; else Cm0 = GetPlrPointFromAlpha(pFoil0, Re, Alpha, 4, IsOutRe, IsError); if(IsOutRe) bOutRe = true; if(IsError) bError = true; if(!pFoil1) Cm1 = 0.0; else Cm1 = GetPlrPointFromAlpha(pFoil1, Re, Alpha, 4, IsOutRe, IsError); if(IsOutRe) bOutRe = true; if(IsError) bError = true; if (Tau<0.0) Tau = 0.0; if (Tau>1.0) Tau = 1.0; return ((1-Tau) * Cm0 + Tau * Cm1); } /** *Interpolates the drag coefficient on the polar mesh, based on the geometrical position of a point between two sections on a wing. *@param m_poaPolar the pointer to the array of polars. *@param nVar the index of the variable to interpolate. *@param pFoil0 the pointer to the left foil of the wing's section. *@param pFoil1 the pointer to the left foil of the wing's section. *@param Re the Reynolds number at the point's position. *@param Alpha the apparent aoa at the point's position. *@param Tau the relative position of the point between the two foils. *@param bOutRe true if Cl is outside the min or max Cl of the polar mesh. *@param bError if Re is outside the min or max Reynolds number of the polar mesh. *@return the interpolated value. */ double GetCd(Foil *pFoil0, Foil *pFoil1, double Re, double Alpha, double Tau, double AR, bool &bOutRe, bool &bError) { //For LLT calculations //returns the interpolated viscous drag // MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; bool IsOutRe = false; bool IsError = false; bOutRe = false; bError = false; double Cd0, Cd1, Cl; if(!pFoil0) { Cl = 2.0*PI*(Alpha*PI/180.0); Cd0 = Cl*Cl/PI/AR; } else Cd0 = GetPlrPointFromAlpha(pFoil0, Re, Alpha,2, IsOutRe, IsError); if(IsOutRe) bOutRe = true; if(IsError) bError = true; if(!pFoil1) { Cl = 2.0*PI*(Alpha*PI/180.0); Cd1 = Cl*Cl/PI/AR; } else Cd1 = GetPlrPointFromAlpha(pFoil1, Re, Alpha,2, IsOutRe, IsError); if(IsOutRe) bOutRe = true; if(IsError) bError = true; if (Tau<0.0) Tau = 0.0; if (Tau>1.0) Tau = 1.0; return ((1-Tau) * Cd0 + Tau * Cd1); } /** *Interpolates the center of pressure's x-position coefficient on the polar mesh, based on the geometrical position of a point between two sections on a wing. *@param m_poaPolar the pointer to the array of polars. *@param pFoil0 the pointer to the left foil of the wing's section. *@param pFoil1 the pointer to the left foil of the wing's section. *@param Re the Reynolds number at the point's position. *@param Alpha the apparent aoa at the point's position. *@param Tau the relative position of the point between the two foils. *@param bOutRe true if Cl is outside the min or max Cl of the polar mesh. *@param bError if Re is outside the min or max Reynolds number of the polar mesh. *@return the interpolated value. */ double GetXCp(Foil *pFoil0, Foil *pFoil1, double Re, double Alpha, double Tau, bool &bOutRe, bool &bError) { //For LLT calculations //returns the interpolated center of pressure position // MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; bool IsOutRe = false; bool IsError = false; bOutRe = false; bError = false; double XCp0, XCp1; if(!pFoil0) return 0.0; else XCp0 = GetPlrPointFromAlpha(pFoil0, Re, Alpha, 11, IsOutRe, IsError); if(IsOutRe) bOutRe = true; if(IsError) bError = true; if(!pFoil1) return 0.0; else XCp1 = GetPlrPointFromAlpha(pFoil1, Re, Alpha, 11, IsOutRe, IsError); if(IsOutRe) bOutRe = true; if(IsError) bError = true; if (Tau<0.0) Tau = 0.0; if (Tau>1.0) Tau = 1.0; return ((1-Tau) * XCp0 + Tau * XCp1); } /** *Interpolates transition locations on the polar mesh, based on the geometrical position of a point between two sections on a wing. *@param m_poaPolar the pointer to the array of polars. *@param pFoil0 the pointer to the left foil of the wing's section. *@param pFoil1 the pointer to the left foil of the wing's section. *@param Re the Reynolds number at the point's position. *@param Alpha the apparent aoa at the point's position. *@param Tau the relative position of the point between the two foils. *@param bTop true if the upper transition is requested, false otherwise *@param bOutRe true if Cl is outside the min or max Cl of the polar mesh. *@param bError if Re is outside the min or max Reynolds number of the polar mesh. *@return the interpolated value. */ double GetXTr(Foil *pFoil0, Foil *pFoil1, double Re, double Alpha, double Tau, bool bTop, bool &bOutRe, bool &bError) { //For LLT calculations //returns the interpolated position of the transition on the surface specified by bTop // MainFrame *pMainFrame = (MainFrame*)m_pMainFrame; bool IsOutRe = false; bool IsError = false; bOutRe = false; bError = false; double Tr0, Tr1; if(!pFoil0) { Tr0 = 1.0; } else { if(bTop) Tr0 = GetPlrPointFromAlpha(pFoil0, Re, Alpha, 5, IsOutRe, IsError); else Tr0 = GetPlrPointFromAlpha(pFoil0, Re, Alpha, 6, IsOutRe, IsError); } if(IsOutRe) bOutRe = true; if(IsError) bError = true; if(!pFoil1) { Tr1 = 1.0; } else { if(bTop) Tr1 = GetPlrPointFromAlpha(pFoil1, Re, Alpha, 5, IsOutRe, IsError); else Tr1 = GetPlrPointFromAlpha(pFoil1, Re, Alpha, 6, IsOutRe, IsError); } if(IsOutRe) bOutRe = true; if(IsError) bError = true; if (Tau<0.0) Tau = 0.0; if (Tau>1.0) Tau = 1.0; return ((1-Tau) * Tr0 + Tau * Tr1); } /** *Interpolates the zero-lift angle on the polar mesh, based on the geometrical position of a point between two sections on a wing. *@param m_poaPolar the pointer to the array of polars. *@param pFoil0 the pointer to the left foil of the wing's section. *@param pFoil1 the pointer to the left foil of the wing's section. *@param Re the Reynolds number at the point's position. *@param Tau the relative position of the point between the two foils. *@return the interpolated value. */ double GetZeroLiftAngle(Foil *pFoil0, Foil *pFoil1, double Re, double Tau) { //returns the 0-lift angle of the foil, at Reynolds=Re //if the polar doesn't reach to 0-lift, returns Alpha0 = 0; double a01, a02; double Alpha00, Alpha01; int i; //Find the two polars which enclose Reynolds int size = 0; Polar *pPolar, *pPolar1, *pPolar2; if(!pFoil0) Alpha00 = 0.0; else { pPolar1 = NULL; pPolar2 = NULL; for (i=0; im_FoilName == pFoil0->m_FoilName) size++; } if(size) { for (i=0; im_FoilName == pFoil0->m_FoilName) { if(pPolar->m_Reynolds < Re) pPolar1 = pPolar; } } for (i=0; im_FoilName == pFoil0->m_FoilName) { if(pPolar->m_Reynolds > Re) { pPolar2 = pPolar; break; } } } } if(pPolar1 && pPolar2) { a01 = pPolar1->GetZeroLiftAngle(); a02 = pPolar2->GetZeroLiftAngle(); Alpha00 = a01 + (a02-a01) * (Re-pPolar1->m_Reynolds)/(pPolar2->m_Reynolds-pPolar1->m_Reynolds); } else Alpha00 = 0.0; } if(!pFoil1) Alpha01 = 0.0; else { pPolar1 = NULL; pPolar2 = NULL; for (i=0; im_FoilName == pFoil1->m_FoilName) size++; } if(size) { for (i=0; im_FoilName == pFoil1->m_FoilName) { if(pPolar->m_Reynolds < Re) pPolar1 = pPolar; } } for (i=0; im_FoilName == pFoil1->m_FoilName) { if(pPolar->m_Reynolds > Re) { pPolar2 = pPolar; break; } } } } if(pPolar1 && pPolar2) { a01 = pPolar1->GetZeroLiftAngle(); a02 = pPolar2->GetZeroLiftAngle(); Alpha01 = a01 + (a02-a01) * (Re-pPolar1->m_Reynolds)/(pPolar2->m_Reynolds-pPolar1->m_Reynolds); } else Alpha01 = 0.0; } return ((1-Tau) * Alpha00 + Tau * Alpha01); } /** *Returns the coefficient of an approximate linearized Cl=f(aoa) curve, based on the geometrical position of a point between two sections on a wing. *@param m_poaPolar the pointer to the array of polars. *@param pFoil0 the pointer to the left foil of the wing's section. *@param pFoil1 the pointer to the left foil of the wing's section. *@param Re the Reynolds number at the point's position. *@param Tau the relative position of the point between the two foils. *@param Alpha0 the zero-lift angle; if the interpolation fails, returns Alpha0 = 0 *@param Slope the slope of the lift curve; if the interpolation fails, returns Slope = 2 PI */ void GetLinearizedPolar(Foil *pFoil0, Foil *pFoil1, double Re, double Tau, double &Alpha0, double &Slope) { double Alpha00, Alpha01; double Slope0, Slope1; double AlphaTemp1, AlphaTemp2, SlopeTemp1, SlopeTemp2; int i; //Find the two polars which enclose the Reynolds number int size = 0; Polar *pPolar, *pPolar1, *pPolar2; if(!pFoil0) { Alpha00 = 0.0; Slope0 = 2.0 * PI *PI/180.0; } else { pPolar1 = NULL; pPolar2 = NULL; for (i=0; im_FoilName == pFoil0->m_FoilName) size++; } if(size) { for (i=0; im_FoilName == pFoil0->m_FoilName) { if(pPolar->m_Reynolds < Re) pPolar1 = pPolar; } } for (i=0; im_FoilName == pFoil0->m_FoilName) { if(pPolar->m_Reynolds > Re) { pPolar2 = pPolar; break; } } } } if(pPolar1 && pPolar2) { pPolar1->GetLinearizedCl(AlphaTemp1, SlopeTemp1); pPolar2->GetLinearizedCl(AlphaTemp2, SlopeTemp2); Alpha00 = AlphaTemp1 + (AlphaTemp2-AlphaTemp1) * (Re-pPolar1->m_Reynolds)/(pPolar2->m_Reynolds-pPolar1->m_Reynolds); Slope0 = SlopeTemp1 + (SlopeTemp2-SlopeTemp1) * (Re-pPolar1->m_Reynolds)/(pPolar2->m_Reynolds-pPolar1->m_Reynolds); } else { Alpha00 = 0.0; Slope0 = 2.0 * PI *PI/180.0; } } if(!pFoil1) { Alpha01 = 0.0; Slope1 = 2.0*PI *PI/180.0; } else { pPolar1 = NULL; pPolar2 = NULL; for (i=0; im_FoilName == pFoil1->m_FoilName) size++; } if(size) { for (i=0; im_FoilName == pFoil1->m_FoilName) { if(pPolar->m_Reynolds < Re) pPolar1 = pPolar; } } for (i=0; im_FoilName == pFoil1->m_FoilName) { if(pPolar->m_Reynolds > Re) { pPolar2 = pPolar; break; } } } } if(pPolar1 && pPolar2) { pPolar1->GetLinearizedCl(AlphaTemp1, SlopeTemp1); pPolar2->GetLinearizedCl(AlphaTemp2, SlopeTemp2); Alpha01 = AlphaTemp1 + (AlphaTemp2-AlphaTemp1) * (Re-pPolar1->m_Reynolds)/(pPolar2->m_Reynolds-pPolar1->m_Reynolds); Slope1 = SlopeTemp1 + (SlopeTemp2-SlopeTemp1) * (Re-pPolar1->m_Reynolds)/(pPolar2->m_Reynolds-pPolar1->m_Reynolds); } else { Alpha01 = 0.0; Slope1 = 2.0*PI *PI/180.0; } } Alpha0 = ((1-Tau) * Alpha00 + Tau * Alpha01); Slope = ((1-Tau) * Slope0 + Tau * Slope1); } /** // Given an array of n+1 pairs (x[i], y[i]), with i ranging from 0 to n, // this function calculates the 3rd order cubic spline which interpolate the pairs. // // The spline is defined for each interval [x[j], x[j+1]) by n third order polynomial functions // p_j(x) = ax3 + bx2 + cx + d // // The equations to determine the coefficients a,b,c,d are // // Interpolation : 2n conditions // p_j(x[j]) = y[j]; // p_j(x[j+1]) = y[j+1]; // // Continuity of 1st and 2nd order derivatives at internal points: 2(n-1) conditions // p_j'(x[j]) = p_j+1'(x[j]) // p_j"(x[j]) = p_j+1"(x[j]) // // Second order derivative is zero at the end points : 2 conditions // p_j"(x[0]) = p_j"(x[n]) =0 // // // This sets a linear system of size 4n which is solved by the Gauss algorithm for coefs a,b,c and d // The RHS vector is // a[0] // b[0] // c[0] // d[0] // a[1] // ... // d[n-1] */ bool SplineInterpolation(int n, double *x, double *y, double *a, double *b, double *c, double *d) { if(n>50) return false; int i,size; double M[16*MAXSPANSTATIONS*MAXSPANSTATIONS];// size is 4 coefs x MAXSPANSTATIONS double RHS[4*MAXSPANSTATIONS*MAXSPANSTATIONS]; memset(M, 0, 16*n*n*sizeof(double)); memset(RHS, 0, 4*n*sizeof(double)); size = 4*n; // Interpolation conditions for (i=0; i Real(b), -1 if Real(a)Image(b), -1 otherwise. */ int Compare(complex a, complexb) { if(a.real()>b.real()) return 1; else if (a.real()b.imag()) return 1; else if (a.imag()*array, int ub) { int indx, indx2; complex temp, temp2; int flipped; if (ub <= 1) return; indx = 1; do { flipped = 0; for (indx2 = ub - 1; indx2 >= indx; --indx2) { temp = array[indx2]; temp2 = array[indx2 - 1]; if (Compare(temp2, temp) > 0) { array[indx2 - 1] = temp; array[indx2] = temp2; flipped = 1; } } } while ((++indx < ub) && flipped); } /** * Returns the intersection of a ray with the object's panels * The ray is defined by a mouse click and is perpendicular to the viewport * A is the ray's origin, * U is the ray's direction * LA, LB, TA, TB define a quadrangle in 3D space. * N is the normal to the quadrangle * I is the resulting intersection point of the ray and the quadrangle, if inside the quadrangle * dist = |AI| * The return value is true if the intersection inside the quadrangle, false otherwise **/ bool Intersect(CVector const &LA, CVector const &LB, CVector const &TA, CVector const &TB, CVector const &Normal, CVector const &A, CVector const &U, CVector &I, double &dist) { static CVector P, W, V, T; bool b1, b2, b3, b4; double r,s; r = (LA.x-A.x)*Normal.x + (LA.y-A.y)*Normal.y + (LA.z-A.z)*Normal.z ; s = U.x*Normal.x + U.y*Normal.y + U.z*Normal.z; dist = 10000.0; if(qAbs(s)>0.0) { dist = r/s; //inline operations to save time P.x = A.x + U.x * dist; P.y = A.y + U.y * dist; P.z = A.z + U.z * dist; // P is inside the panel if on left side of each panel side W.x = P.x - TA.x; W.y = P.y - TA.y; W.z = P.z - TA.z; V.x = TB.x - TA.x; V.y = TB.y - TA.y; V.z = TB.z - TA.z; T.x = V.y * W.z - V.z * W.y; T.y = -V.x * W.z + V.z * W.x; T.z = V.x * W.y - V.y * W.x; b1 = (T.x*T.x+T.y*T.y+T.z*T.z <1.0e-10 || T.x*Normal.x+T.y*Normal.y+T.z*Normal.z>=0.0); W.x = P.x - TB.x; W.y = P.y - TB.y; W.z = P.z - TB.z; V.x = LB.x - TB.x; V.y = LB.y - TB.y; V.z = LB.z - TB.z; T.x = V.y * W.z - V.z * W.y; T.y = -V.x * W.z + V.z * W.x; T.z = V.x * W.y - V.y * W.x; b2 = (T.x*T.x+T.y*T.y+T.z*T.z <1.0e-10 || T.x*Normal.x+T.y*Normal.y+T.z*Normal.z>=0.0); W.x = P.x - LB.x; W.y = P.y - LB.y; W.z = P.z - LB.z; V.x = LA.x - LB.x; V.y = LA.y - LB.y; V.z = LA.z - LB.z; T.x = V.y * W.z - V.z * W.y; T.y = -V.x * W.z + V.z * W.x; T.z = V.x * W.y - V.y * W.x; b3 = (T.x*T.x+T.y*T.y+T.z*T.z <1.0e-10 || T.x*Normal.x+T.y*Normal.y+T.z*Normal.z>=0.0); W.x = P.x - LA.x; W.y = P.y - LA.y; W.z = P.z - LA.z; V.x = TA.x - LA.x; V.y = TA.y - LA.y; V.z = TA.z - LA.z; T.x = V.y * W.z - V.z * W.y; T.y = -V.x * W.z + V.z * W.x; T.z = V.x * W.y - V.y * W.x; b4 = (T.x*T.x+T.y*T.y+T.z*T.z <1.0e-10 || T.x*Normal.x+T.y*Normal.y+T.z*Normal.z>=0.0); if(b1 && b2 && b3 && b4) { I.Set(P.x, P.y, P.z); return true; } } return false; } /** * Calculates the blending value of a point on a BSpline. This is done recursively. * If the numerator and denominator are 0 the expression is 0. * If the denominator is 0 the expression is 0 * * index is the control point's index * p is the spline's degree * t is the spline parameter */ double SplineBlend(int const &index, int const &p, double const &t, double *knots) { static double eps = 1.e-6; double value; if(p==0) { if ((knots[index] <= t) && (t < knots[index+1]) ) value = 1.0; // else if (abs(knots[index]-knots[index+1]) #include #include #include #include #include #include #include #include #include #include #include "params.h" #include "twodwidget.h" #include "threedwidget.h" #include "objects/Foil.h" #include "objects/Polar.h" #include "objects/OpPoint.h" #include "objects/PlaneOpp.h" #include "graph/QGraph.h" /** *@class MainFrame *@brief The class associated to the application's main window. The class fills many functions: - it creates the child windows and toolbars of the application - it manages the loading and saving of settings - it stores and manages the arrays of data as member variables - it manages the load & save operations of project files This class will remain only partially documented. */ class MainFrame : public QMainWindow { friend class TwoDWidget; friend class ThreeDWidget; friend class QXDirect; friend class QMiarex; friend class QAFoil; friend class QXInverse; friend class Miarex; friend class Body; friend class Wing; friend class WPolar; friend class OpPoint; friend class CWOpp; friend class Plane; friend class BodyGridDlg; friend class XFoilAnalysisDlg; friend class FoilPolarDlg; friend class BatchDlg; friend class BatchThreadDlg; friend class InterpolateFoilsDlg; friend class WingDlg; friend class WPolarDlg; friend class StabPolarDlg; friend class StabViewDlg; friend class PlaneDlg; friend class PanelAnalysisDlg; friend class GL3dBodyDlg; friend class GL3DScales; friend class ManageBodiesDlg; friend class WingScaleDlg; friend class BodyTransDlg; friend class GL3dWingDlg; friend class WAdvancedDlg; friend class GraphDlg; friend class LLTAnalysisDlg; friend class wySettingsDlg; friend class ManageFoilsDlg; friend class ManageUFOsDlg; friend class InertiaDlg; friend class TranslatorDlg; friend class DisplaySettingsDlg; Q_OBJECT public: MainFrame(QWidget * parent = 0, Qt::WindowFlags flags = 0); ~MainFrame(); enumApp LoadXFLR5File(QString PathName); static MainFrame* self(); public slots: void OnAFoil(); void OnXDirect(); void OnXInverse(); void OnXInverseMixed(); void OnMiarex(); private slots: void AboutQt(); void AboutQFLR5(); void OnCurFoilStyle(); void OnDuplicateFoil(); void OnGuidelines(); void OnExportCurGraph(); void OnInsertProject(); void OnNewProject(); void OnLanguage(); void OnLoadFile(); void OnLogFile(); void OnRenameCurFoil(); void OnResetCurGraphScales(); void OnResetSettings(); void OnRestoreToolbars(); void OnSaveOptions(); bool OnSaveProjectAs(); void OnSaveViewToImageFile(); void OnSelChangeFoil(int i); void OnSelChangePolar(int i); void OnSelChangeOpp(int i); void OnSelChangeUFO(int i); void OnSelChangeWOpp(int i); void OnSelChangeWPolar(int i); void OnSaveProject(); void OnStyle(); void OnUnits(); void OnSaveUFOAsProject(); void OnPolarProps(); void OnWOppProps(); void openRecentFile(); /*___________________________________________Methods_______________________________*/ public: static Foil * curFoil(){return s_pCurFoil;} void AddFoil(Foil *pFoil); Polar* AddPolar(Polar *pPolar); void AddRecentFile(const QString &PathNAme); void ClientToGL(QPoint const &point, CVector &real); void closeEvent (QCloseEvent * event); void contextMenuEvent (QContextMenuEvent * event) ; void CreateDockWindows(); void CreateToolbars(); void CreateStatusBar(); void CreateActions(); void CreateMenus(); void CreateXDirectActions(); void CreateXDirectMenus(); void CreateXDirectToolbar(); void CreateXInverseActions(); void CreateXInverseMenus(); void CreateXInverseToolbar(); void CreateMiarexActions(); void CreateMiarexMenus(); void CreateMiarexToolbar(); void CreateAFoilActions(); void CreateAFoilMenus(); void CreateAFoilToolbar(); Foil *DeleteFoil(Foil *pFoil, bool bAsk=true); void DeleteProject(bool bClosing=false); void DeletePlane(void *pPlanePtr, bool bResultsOnly = false); void DeleteWing(void *pWingPtr, bool bResultsOnly = false); QColor GetColor(int type); OpPoint *GetOpp(double Alpha); Polar *GetPolar(QString m_FoilName, QString PolarName); void GLToClient(CVector const &real, QPoint &point); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); bool LoadSettings(); bool LoadPolarFileV3(QDataStream &ar, bool bIsStoring, int ArchiveFormat=0); Foil* ReadFoilFile(QTextStream &ar); Foil* ReadPolarFile(QDataStream &ar); static void ReadStyleSheet(QString styleSheetName, QString &styleSheet); void RemoveOpPoint(bool bCurrent); void RenameFoil(Foil *pFoil); bool SaveProject(QString PathName=""); void SaveSettings(); void SelectOpPoint(OpPoint *pOpp); void SelectWOpp(double x=0.0); void SelectWOpp(WingOpp *pWingOpp); void SelectWOpp(PlaneOpp *pPlaneOpp); bool SerializeProject(QDataStream &ar, bool bIsStoring); bool SerializeUFOProject(QDataStream &ar); void SetCentralWidget(); void SetCurrentFoil(Foil* pFoil); void SetGraphSettings(Graph *pGraph); void SetProjectName(QString PathName); void SetMenus(); Foil* SetModFoil(Foil* pNewFoil, bool bKeepExistingFoil = false); void SetupDataDir(); QString ShortenFileName(QString &PathName); void UpdateFoils(); void UpdatePolars(); void UpdateOpps(); void updateRecentFileActions(); void UpdateUFOs(); void UpdateView(); void UpdateWPolars(); void UpdateWOpps(); void WritePolars(QDataStream &ar, Foil *pFoil=NULL); static QString versionName(){return s_VersionName;} static void SetSaveState(bool bSave); static Foil* foil(QString strFoilName); /*___________________________________________Variables_______________________________*/ private: void *m_pAFoil; /**< A void pointer to the instance of the QAFoil application. The pointer will be cast to the QAFoil type at runtime. This is necessary to prevent loop includes of header files. */ void *m_pMiarex; /**< A void pointer to the instance of the QMiarex application. The pointer will be cast to the QMiarex type at runtime. This is necessary to prevent loop includes of header files. */ void *m_pXInverse; /**< A void pointer to the instance of the QXInverse application. The pointer will be cast to the QXInverse type at runtime. This is necessary to prevent loop includes of header files. */ void *m_pXDirect; /**< A void pointer to the instance of the QXDirect application. The pointer will be cast to the QXDirect type at runtime. This is necessary to prevent loop includes of header files. */ void *m_pStabView; /** < A void pointer to the instance of the StabViewDlg window. */ static QPointer _self; /**< @todo need to discuss this one with Francesco */ QStackedWidget *m_pctrlCentralWidget; /** The stacked widget which is loaded at the center of the display area. The stack holds one TwoDWidget and one ThreeDWidget and sxwitches between the two depending on the user's request. */ TwoDWidget *m_p2DWidget; /** A pointer to the instance of the TwoDWidget which is used to perform 2d drawings */ ThreeDWidget *m_pGLWidget; /** A pointer to the instance of the ThreeDWidget which is used to perform all 3D drawings */ QDockWidget *m_pctrlXDirectWidget, *m_pctrlMiarexWidget, *m_pctrlAFoilWidget, *m_pctrlXInverseWidget; QDockWidget *m_pctrl3DScalesWidget, *m_pctrlStabViewWidget; QToolBar *m_pctrlXDirectToolBar; /**< The tool bar container which holds the instance of the QXDirect application */ QToolBar *m_pctrlXInverseToolBar; QToolBar *m_pctrlMiarexToolBar; QToolBar *m_pctrlAFoilToolBar; //Common Menus QMenu * MainMenu; QMenu *fileMenu, *optionsMenu, *helpMenu; //AFoilMenus QMenu *AFoilViewMenu, *AFoilDesignMenu, *AFoilSplineMenu; QMenu *AFoilCtxMenu,*AFoilCurrentFoilMenu, *AFoilTableCtxMenu; // XFoilAnalysis Menus QMenu * XDirectViewMenu; QMenu *FoilMenu, *CurGraphCtxMenu, *CurOppCtxMenu; QMenu *currentFoilMenu; QMenu *DesignMenu; QMenu *XFoilAnalysisMenu; QMenu *OpPointMenu, *CpGraphMenu, *currentOppMenu; QMenu *PolarMenu, *currentPolarMenu, *GraphPolarMenu, *CurPolarGraphMenu; QMenu *OperFoilCtxMenu, *OperPolarCtxMenu, *CurXFoilResults; //XInverse menu QMenu *XInverseViewMenu, *InverseFoilMenu, *InverseGraphMenu, *InverseContextMenu; //Miarex Menus QMenu *MiarexViewMenu; QMenu *MiarexAnalysisMenu; QMenu *UFOMenu, *currentUFOMenu, *curWPlrMenu, *curWOppMenu; QMenu *MiarexWPlrMenu, *MiarexWOppMenu; QMenu *WPlrGraphMenu,*WPlrCurGraphMenu, *WOppGraphMenu, *WOppCurGraphMenu; QMenu *WPlrCtxMenu, *WOppCtxMenu, *W3DCtxMenu, *WCpCtxMenu, *WTimeCtxMenu, *W3DStabCtxMenu; //MainFrame actions QAction *OnXDirectAct, *OnMiarexAct, *OnAFoilAct, *OnXInverseAct, *OnMixedInverseAct; QAction *openAct, *insertAct, *styleAct; QAction *saveAct, *saveProjectAsAct,*newProjectAct, *closeProjectAct, *saveOptionsAct; QAction *unitsAct; QAction *languageAct; QAction *exitAct; QAction *aboutAct, *guidelinesAct, *aboutQtAct; QAction *recentFileActs[MAXRECENTFILES]; QAction *separatorAct; QAction *saveViewToImageFileAct, *resetSettingsAct; //AFoil Actions QAction *zoomInAct, *ResetXScaleAct, *ResetYScaleAct, *ResetXYScaleAct; QAction *zoomYAct, *zoomLessAct, *AFoilGridAct; QAction *AFoilDelete, *AFoilRename, *AFoilExport; QAction *AFoilSetTEGap, *AFoilSetLERadius, *AFoilSetFlap, *AFoilInterpolateFoils, *AFoilNacaFoils; QAction *AFoilDerotateFoil, *AFoilNormalizeFoil, *AFoilRefineLocalFoil, *AFoilRefineGlobalFoil; QAction *AFoilEditCoordsFoil, *AFoilScaleFoil; QAction *AFoilLECircle, *m_pShowLegend; QAction *UndoAFoilAct, *RedoAFoilAct; QAction *HideAllFoils, *ShowAllFoils, *ShowCurrentFoil, *HideCurrentFoil; QAction *storeSplineAct, *newSplinesAct, *splineControlsAct, *exportSplinesToFileAct; QAction *InsertSplinePt, *RemoveSplinePt; QAction *AFoilTableColumns, *AFoilTableColumnWidths; QAction *AFoilLoadImage, *AFoilClearImage; //Miarex Actions QAction *WPolarAct, *WOppAct, *W3DAct, *CpViewAct, *StabTimeAct, *RootLocusAct; QAction *W3DPrefsAct, *W3DLightAct, *W3DScalesAct; QAction *DefineWingAct, *definePlaneAct, *editUFOAct, *SaveUFOAsProject; QAction *renameCurUFO, *deleteCurUFO, *duplicateCurUFO; QAction *renameCurWPolar, *editWPolar,*exportCurWPolar, *resetCurWPolar; QAction *ShowPolarProps, *ShowWOppProps; QAction *deleteCurWPolar, *deleteCurWOpp; QAction *twoGraphs, *fourGraphs; QAction *Graph1,*Graph2,*Graph3,*Graph4; QAction *MiarexGraphDlg; QAction *highlightWOppAct; QAction *ResetWingGraphScale; QAction *MiarexPolarFilter; QAction *allWPolarGraphsScalesAct, *allWingGraphsScalesAct, *allWPolarGraphsSettings, *allWingGraphsSettings; QAction *hideAllWPlrs, *showAllWPlrs; QAction *hideUFOWPlrs, *showUFOWPlrs, *showUFOWPlrsOnly, *deleteUFOWPlrs; QAction *hideUFOWOpps, *showUFOWOpps, *deleteUFOWOpps; QAction *resetWOppLegend, *resetWPlrLegend; QAction *exportCurWOpp, *showCurWOppOnly, *hideAllWOpps, *showAllWOpps, *deleteAllWOpps; QAction *showAllWPlrOpps, *hideAllWPlrOpps, * deleteAllWPlrOpps; QAction *defineWPolar, *defineStabPolar, *advancedSettings; QAction *editCurBodyAct; QAction *halfWingAct; QAction *showEllipticCurve, *showXCmRefLocation, *showStabCurve, *showFinCurve, *showWing2Curve; QAction *exporttoAVL, *resetWingScale, *scaleWingAct; QAction *manageUFOsAct; QAction *m_pImportWPolar, *m_pUFOInertia; //XDirect Actions QAction *PolarsAct, *OpPointsAct, *deletePolar, *definePolar, *editCurPolar, *defineBatch, *resetCurPolar; QAction *MultiThreadedBatchAct; QAction *restoreToolbarsAct; QAction *exportCurPolar, *exportAllPolars, *hideFoilPolars, *showFoilPolars, *showFoilPolarsOnly, *saveFoilPolars,*deleteFoilPolars; QAction *showAllPolars, *hideAllPolars, *showCurOppOnly, *showAllOpPoints, *hideAllOpPoints, *exportPolarOpps; QAction *hideFoilOpps, *showFoilOpps, *deleteFoilOpps; QAction *hidePolarOpps, *showPolarOpps, *deletePolarOpps; QAction *exportCurOpp, *deleteCurOpp, *resetXFoil; QAction *viewXFoilAdvanced, *viewLogFile, *showPanels, *showNeutralLine, *resetFoilScale, *showInviscidCurve; QAction *exportCurFoil, *deleteCurFoil, *renameCurFoil, *setCurFoilStyle; QAction *DerotateFoil, *NormalizeFoil, *RefineLocalFoil, *RefineGlobalFoil , *EditCoordsFoil, *ScaleFoil; QAction *SetTEGap, *SetLERadius, *SetFlap, *InterpolateFoils, *NacaFoils, *DuplicateFoil; QAction *XDirectGraphDlg,*exportCurGraphAct, *resetCurGraphScales, *allPolarGraphsSettingsAct, *allPolarGraphsScales; QAction *TwoPolarGraphsAct, *AllPolarGraphsAct, *resetGraphLegend; QAction *PolarGraphAct[5]; QAction *XDirectStyleAct; QAction *XDirectPolarFilter; QAction *defineCpGraphSettings, *exportCpGraphAct, *setQVarGraph, *setCpVarGraph; QAction *CurXFoilResExport, * CurXFoilCtPlot, *CurXFoilDbPlot, *CurXFoilDtPlot, *CurXFoilRtLPlot; QAction *CurXFoilRtPlot, *CurXFoilNPlot, *CurXFoilCdPlot, *CurXFoilCfPlot, *CurXFoilUePlot, *CurXFoilHPlot; QAction *ManageFoilsAct, *RenamePolarAct; QAction *m_pImportJavaFoilPolar, *m_pImportXFoilPolar; QAction *highlightOppAct; QComboBox *m_pctrlFoil, *m_pctrlPolar, * m_pctrlOpPoint; QComboBox *m_pctrlUFO, *m_pctrlWPolar, * m_pctrlWOpp; QRadioButton *m_pctrlFullInverse, *m_pctrlMixedInverse; static QLabel *m_pctrlProjectName; //XInverse Actions QAction *StoreFoil, *ExtractFoil, *InverseStyles, *InverseResetScale, *InverseInsertCtrlPt, *InverseRemoveCtrlPt; QAction *InvQInitial, *InvQSpec, *InvQViscous, *InvQPoints, *InvQReflected; QAction *InverseResetGraphScale, *XInverseGraphDlg, *InverseZoomIn, *InverseZoomX, *InverseZoomY; QStringList m_RecentFiles; enumApp m_iApp; /**< The identification number of the active app. */ static bool s_bSaved; /**< true if the project has not been modified since the last save operation. */ bool m_bSaveOpps; /**< true if foil operating points should be serialized in the project file */ bool m_bSaveWOpps; /**< true if wing operating points should be serialized in the project file */ bool m_bSaveSettings; /**< true if user-defined settings should be saved on exit. */ bool m_bHighlightOpp; /**< true if the active OpPoint should be highlighted on the polar curve. */ bool m_bHighlightWOpp; /**< true if the active WingOpp should be highlighted on the polar curve. */ static QDir s_StylesheetDir; static QDir s_TranslationDir; static QString s_LanguageFilePath; QString m_ExportLastDirName, m_ImageDirName; QString m_FileName; /**< The absolute path to the file of the current project. */ QList m_ColorList; QGraph m_RefGraph;//Reference setttings QString m_GraphExportFilter; enumImageFormat m_ImageFormat; /**< The index of the type of image file which should be used. */ public: static Foil *s_pCurFoil; static bool s_bTrace; static bool s_bReverseZoom; /**< true if the rolling forward zooms in rather than out. */ static QFile *s_pTraceFile; static QString s_ProjectName; /**< The Project's name. */ static QString s_LastDirName; static QFont s_TextFont; static QColor s_TextColor; static QColor s_BackgroundColor; static bool s_bAlphaChannel; /**< true if transparency is enabled for 3D displays. */ static QString s_VersionName; static enumTextFileType s_ExportFileType; /**< Defines if the list separator for the output text files should be a space or a comma. */ static double s_mtoUnit; /**< Conversion factor from meters to the user selected length unit. */ static double s_mstoUnit; /**< Conversion factor from m/s to the user selected speed unit. */ static double s_m2toUnit; /**< Conversion factor from square meters to the user selected area unit. */ static double s_kgtoUnit; /**< Conversion factor from kg to the user selected mass unit. */ static double s_NtoUnit; /**< Conversion factor from Newtons to the user selected force unit. */ static double s_NmtoUnit; /**< Conversion factor from N.m to the user selected unit for moments. */ static int s_LengthUnit; /**< The index of the user selected unit in the array of length units. @todo use an enumeration instead. */ static int s_AreaUnit; /**< The index of the user selected unit in the array of area units. */ static int s_WeightUnit; /**< The index of the user selected unit in the array of mass units. */ static int s_SpeedUnit; /**< The index of the user selected unit in the array of speed units. */ static int s_ForceUnit; /**< The index of the user selected unit in the array of force units. */ static int s_MomentUnit; /**< The index of the user selected unit in the array of moment units. */ static QList s_oaFoil; /**< The array of void pointers to the Foil objects. */ static QList s_oaPolar; /**< The array of void pointers to the foil Polar objects. */ static QList s_oaPlane; /**< The array of void pointers to the Plane objects. */ static QList s_oaWing; /**< The array of void pointers to the Wing objects. */ static QList s_oaBody; /**< The array of void pointers to the Body objects. */ QList m_oaWPolar; /**< The array of void pointers to the WPolar objects. */ QList m_oaWOpp; /**< The array of void pointers to the WingOpp objects. */ QList m_oaPOpp; /**< The array of void pointers to the PlaneOpp objects. */ QList m_oaOpp; /**< The array of void pointers to the foil operating point objects. */ void *m_pGL3DScales; QTranslator m_Translator; /**< the translator object; due to a Qt bug, need to load twice: once from the main function, once from the mainframe */ }; #endif // MAINFRAME_H xflr5-6.09-06/Compilation_Instructions.txt000644 001750 000144 00000004326 12251146503 022075 0ustar00techwinderusers000000 000000 ******************************************************************************* XFLR5 A tool for the design of Airfoils, Wings and Planes operating at low Reynolds numbers Copyright (C) 2003-2012 Andre Deperrois ******************************************************************************* Licence : This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 ************************** Source code download To keep up-to-date with the latest source code modifications, use an SVN client to check out the code from the repository @sourceforge.net Compilation instructions - To compile on Windows, Mac, and Linux, the easiest way is to download QtCreator from Nokia. In Windows, QtCreator comes with the MinGW compiler. In Linux, you may also need to install the Mesa-devel package Other possibilities: - To compile under Ubuntu/Debian Linux, please do the following: go to the directory, type dpkg-buildpackage -rfakeroot. - To compile manually on any Linux distro, please follow the following steps: 1. Get the libqt4-devel, Mesa and Mesa-devel packages 2. qmake -makefile xflr5.pro target.path=/usr/bin 3. make 4. sudo make install - To compile on MacOSX, please follow the following steps: 1. qmake -makefile 2. qmake -spec macx-g++ 3. make -j3 4. ./mac/makedist xflr5-6.09-06/images/000755 001750 000144 00000000000 12251145323 015531 5ustar00techwinderusers000000 000000 xflr5-6.09-06/images/xflr5_64.png000644 001750 000144 00000002247 12246405674 017631 0ustar00techwinderusers000000 000000 PNG  IHDR@@iq pHYsodYIDATx[MkI~مe?0 s{CdAXl.kl.Pr@ +,A% EEaGݙa}{Pe{z l<}!8T*\@J )=!9B@JsxyƘc\s!8}7c c{m79U'955u*WCPeP6QnHY*lƐ (CR' 1,Xmk?Ք #)s@: !IG 3,=Awmȝ7WWVZR@+rR@[AQ6(ZU3#@R_,nX ®lHJ]ׯwͷaX|lCr|`KM $@HB*HQ@АG9QW@ 46;0omꟹd#:e߱ PJ0o[Zf/>-KR)奮 4…8~ud絸[Bw lP^sa02u@)e %)jmEΝΦA_-j?ީJ# aD$*ȡ̙qu0+za)/~Wz(a3K:+<{6[!g"NP}PT h~Wb0ЧOprF̆Āě>ϽAh:dn ]sW#w0 6;ie[T{0e"#޼y);lHZZP9Ws'[IʕPJaf{zBbHlk멕/_эU.^ Œ6;uh^RĽ@| TpZu8mWd{0==9?7) aeQq?diժ2*bRZm7^m,:1'n:#=++țKtIENDB`xflr5-6.09-06/images/OnUndo.png000644 001750 000144 00000000515 12246405674 017456 0ustar00techwinderusers000000 000000 PNG  IHDR szz pHYsodIDATxՖ! 9b3lTj/O` ϝ}n8&Uÿ/k>P)GHVp4$ʰ۶r޶-*u %4J  (IA*"rQT !f#-Z$D [}̤Mj̽Žu//9yyeVi[Ѳa:9euފiDD{bMŭ)dZ?>ڕ#+Z+/[h٤3bbQι G#bVߵhk0jXMߏ9Bq]aK,q cvm*@fkSEbyD "poȜb٘iXbTH V?!teMSߩnRD(֣`ެ LNpAqSxEWՙ/E<=}%>lM2Wgl0gzfb#c!b̿b:?V54W"(pp`6x_{p>4{:OWf|-py5$3Ow)FE]uENPZhhZO#)^:AUzw^I]PTv( P9z6&!HV`-<.b-`w<{ ŧ8/u=m)|g. 3ԅnδmt{/;7X34[dcXDqq.& "cAkW{#oi4P>ai3+|2E^_>a s CD,2=s@}ʊ<먲|׬-VGbO5ȓ>4%6R7+K9s4٤1vhǿhiIIENDB`xflr5-6.09-06/images/On3DModes.png000644 001750 000144 00000000552 12246405674 020010 0ustar00techwinderusers000000 000000 PNG  IHDRI@V|Z pHYsȥIDATx=@ÍaX[P\{&r؛[` (}d 7a$n,yZbK^>G_s Ym?U)@{53N2r0 -I>Fsρ9bHUvZjq[RmH’$I/Eph :)$y^_CemWoiKt?/ kj}h&yk\|<~wp]ݼtZU-_~I|>WnK.X,֪ش?a_˙zYIENDB`xflr5-6.09-06/images/xflr5_128.png000644 001750 000144 00000004403 12246405674 017706 0ustar00techwinderusers000000 000000 PNG  IHDR>a pHYsodIDATxkGǿs{-QxSVD!>C4C835 })Z5!>ŇًPmTD+O_mܻۻۇٙ@foof6~gfwg=445 >ʕ_0bb $;7?|NI?60?g0mM@Qz'}Lmqv[onNXK @0NR$G @qG @qe+&vP-P-a%H,g'G @qG @qX.YA2hP-P-P &шA;24L$.TDN9J䣫ʼnwІFfш!RqDFw]UiA4bh8ZEyA4b5eh{'#E>wB E^`'P"p@Qz{+)4(_@L͋2 [КE1y?yעbE3::hjQs 颹D\|n%da.o&Ձ !<+ O]3kN?C: VqLѻl"L:  0XDKZL!|huB/k8LR xv+O/Ձ@iBEG 8u'U.&h0N\Ѕ[Zvp[NaeFc1@' BZ[w0Om'D!##i!ѱGh =Z'O^v6 !D{RNС}@dƞR@!ª/F}Ӗ1E( R BmTit'``>X5EQ > Q/@" @z̈wH "!ZЍ"T n|@ez/0hJ\VxTR@lIHN8rH]7b7CB>62sV^l#7r6 #73w xdW?`q3gbƌ0gΒW/.P4ۑ^|hI X78~8X@޽{isCpbH0] w>17*ʡa8z"sdCDX֭ X il[70E `pd*u:МH77X9Heat-]Z!hi,BMM5?t_Bꖵں<40Uƽ`9йz2JUHx/@aٶPIG8@(ozZĉ_sc|a*STy\aKC0WIENDB`xflr5-6.09-06/images/OnBody.png000644 001750 000144 00000000672 12246405674 017452 0ustar00techwinderusers000000 000000 PNG  IHDR@@iq pHYsodlIDATx[ Y:e-ˆRraII3"b L3Ƨr 9s_!V*@êcV*@PÿN@?ti)~;3it ZGwztg/0  !1[k- 3K n)`daC$ X% )>$4Hڳ>" E%P ]P[CG( J'Wįn#`M; "{Q8.|lP1qIENDB`xflr5-6.09-06/images/new.png000644 001750 000144 00000001524 12246405674 017046 0ustar00techwinderusers000000 000000 PNG  IHDR szzgAMAOX2tEXtSoftwareAdobe ImageReadyqe<IDATX՗Na5{q\\0&bXX ѝRHECey{QJ!Iޜ3MN"SsՐn==d 12<S(CfIkR׾TUNK޷’=Oޣqnl4kZS YoK|mu5e<7ɺx&oFh?B~Ql% wIENDB`xflr5-6.09-06/images/OnExtractFoil.png000644 001750 000144 00000001303 12246405674 020771 0ustar00techwinderusers000000 000000 PNG  IHDR szz pHYsoduIDATXݗKkAOVWGN lQqD7F QHV"ۈEA?%3tUW׫M ;}5%GV_p>g!퇻%C% T7kJp1k7^b/|E1TXN[*\#TjA+k7z5?9ăkXmc ΨG G8E)dr/p5sb.j&|҂Ow61 JNYElXYU ހeXxY~g itgY" =0qGo8''3ڳ\SX@Usd'OË>^ےt|}gZ]:bN8pg@r@@HAxmK(txg~NM]] 3%:<H89`vb,MJ=7e#Yf>9V]ujBOjP 8BUEi1|=v1_,&6'ry Apg9&z_Z X}׻si?,3>@~ñs~IENDB`xflr5-6.09-06/images/On3DView.png000644 001750 000144 00000000535 12246405674 017654 0ustar00techwinderusers000000 000000 PNG  IHDR szz pHYsodIDATXUA0,ea DF x0X{'0;t !!?=+2kmDލ9jhڇ."@\I:b 1rp,m[}["9Y*g#j_6A UU!Ϸ-Ku(Qw&2;fy ƺ ,"K::cdGF< CBDAZK<ϜNe@]{f|\->IENDB`xflr5-6.09-06/images/OnStabView.png000644 001750 000144 00000001443 12246405674 020276 0ustar00techwinderusers000000 000000 PNG  IHDR szzsBIT|d pHYs//6tEXtSoftwarewww.inkscape.org<IDATXOUuiyN61FEV4cM-"7*Ҧk ]EA Mբ?B5E(2aSŽݹo|p{d Cx_7iexV pM"V8*oq뱷H) ] M8%o\kppƹRע Lh0wۺF9"EZ8@L}/9.b˂3pA D,F_mE[@20qO`k7ZQwdGm z+ʬ8@}2/i 002UwNpծqLqm3|7?|kߧqQ-m=JЛqU od&⤈GeC.`i^k+ce~5VofXwq.vsef7gs.T|'>52QLJ^m?ut:ju2T.#0]U%n0z 0~ۀ>7i`i%dXρ aR1 575^OgWtsl@ I`@|10$0>T nA c }k}@/yFRJ lwפKy+ruِ"cE^&H*aݷE=['f,p ~t+Q缆o`^WX]Jr0Jk Xp1#J 7-Z _ )cr]+[_%98`6jJ\7;pp+%<~ g 0k@;ƕ974&NjyXb;)k3mw\)pqso3+^xS`axw sߋ/ Lf-xSᖐ'< p„7,nPJxE;1 qLPhOݪ):pl4 29+!e%c|خ{4UqD!቙_\ۙpn}1_Y9EA}L(ȯ ԾIENDB`xflr5-6.09-06/images/splash.png000755 001750 000144 00000022030 12246405674 017545 0ustar00techwinderusers000000 000000 PNG  IHDR,usBIT|dsRGBgAMA a pHYs+#IDATx^keW]I;I4R[B*1LYBT(UD-^hY*S)nI&*5 f!h ;N:n:t'K緟gk{y]g_׾sYSűNrF"l !F"l !F"l !F"l !F"l !F"l !FYj-hWߝsNc 7[/K/l.)ۍ3,=dO)СCŮ*k憬}PO~ mֿ/y~b߾}KOw}w?oCGkOw}rя[W\ !dR%|ݻ]_Y_Wz~8+_)wV2odUV 4 ?>i;Su]Y׾Vz< L?}'TLo?s]լ"U{VoN"ޯbݮ94 /kl9lM:͂> ?FDv>kB\vkKڻ~7\WQ\x-2/8|׶L{*VSvpm8V:|Wni6+ VV!UNT or]L׽bSvtmiJSvEvZߏ}SqWk?1Ё*WUk?\׻U_aqwנe#;xxbϞֿRce~sk=Ymw@]ly:CwP+ȷo7پ}k[=.uh9yZѥk]פ{7z%>ylR#hOOz(pБ.ɍy5׸eDN!ey~YlټٵЅ<66ay$:_kXšeQmŽkWm˹- O밝BKtK{@h/PtI<]f>Rdr]g/NHկξ;*3ZNPG WWo/JJt)[4yt1ɟ,/xя}zm+#D|[\$KN=k~ǚؽ8U牽{]2k?u_{$*GeķC*PRMt]HasgiR{VR BNp&"Et9h,B_:eۺյ{qmW.:h#uX9ׯwmWO_r5}ZT?毛U"@O]w8?F'NS~6 ejf\늻S:nlm|Џ\~kuT`5a3[7cF*&>cC=Q:ylǾ<0vۿe׶lVt=w=_KYMhQm۶me˧MG6 \e]±1 D*/Nn*vbSpuc^xp̜CY??V{`o28t峲bD{dsQx\4O=|kQq睮zp7 Gzn纶q"DtYNVJi+PVc*ULMCY*'@ Q;u*؍zTUtɵ>]5-?71vYiojۏX1?d !t =VakaEDu(L)+sb崡 ^RЂPU^CF-vN\ח7`~\ߥ⪟A{A6NI. +ԱW菺?V߯~յX9M(<&je_VtV1^u{Š\򵯹Fp3<"Ch,3D;vА* tD竺jei/C'K\}(K+h ]<Һ#dtsLR{%*OPa8Ƽ\{+!_b 7xv4?)S@S} *!(U"4z!6I_:s9:t P喺I/L\T(pꩮm*S=PSFsf }[^}q8F"l !F"l !F"l !F"l !F"l !F"l !F4l,5ǖ[KI'`#f=Ί9vlys|+hvQ5kFw5֮aOhu:" }EsάWp,6B$I_,]v!W5ިX,H!Lz:U/;{]euYe?B$iAd޽nذD$TSO=KGuӦM8H })||%8S\>|xiɿPjtO' FD:tlH?< !2 5 !ҁIAB`캜Tb!Dz щ>=esƇ]7 aF` $qb Db AAO 0ml8f=Sz 5O>#Dl 1 ͼBd`o߾"3 9S]p{:B(H&gϞ>"#a6<?^6aQL3LDA裏.h)۴MAB`Zt~s]i?8駟^6#oYS~J6G ƍ]޽li]=i\~YjfoO<$6֭[W.CȚ5k) v}1O90 T@M'_Xg/ 7BdAC"?uaQyG,Y:D}!<!&fdgW"D8(! 4VBd/BA {Bc"DV{袋W#݇Dh"dV!#PKmi 4BrYm\>@h)B%~e"EԺ\&(L oV1Ij>"'gYe]TB&!RwOȕW^Y8pxg￿^mP L!F& x׺8}{e|-{1B$Y#DC=TV*?|H"y !,][C{ B$#D؝wڪ)((v U'sF;bmیټ-/Þx 6i˖-t+:Tu]tODWgBJuǎm?^8Mx,x,2ByZׯ/&*eP>|8rH!b޾}{*UơjEU{-+~Y Yn ). Uj<~<, '*uwuJ;餓@ѫU>llUCG̮]7 i;>Uo,/z:q?w}wYU 7V;Bd?Xp *w8x ΃(Tt/~"F[Y@X_`]w]iӦ[{}ы^TviƍW5:smJ-?ڽ^JU%k:TMwҗԵ};tW!qgԆH]v{HDJBD9n]J\KX /[]/wyO2!2GVa%c -,P"a}'c4H2|F0} [ShTyG\tCDl\](>Ȉ-ZKh^d!"6L>H-B,JhTy]BD]̊>kШ4  6.`:)$DFh!V^HۻwkNӢO!2',pN}>iȜ <䓮m̀O,B "bm ѧFFe3D׮]뺀vi"DӿBP!b瓟!D96=Z2>M0MB$vbȑ#| C%Fa"l!F"l !F"l !F"l !F"l !F"l !F"l !F"l !F"l !F"l !F"l !F"l !F"l"D;ں볬*Cgɴh}ӢPN2xfqyTu딻󺭪Nc>Z5k֔MheU~B~ʲf,^ecY=5^p 2-5}Oض˼|8|Cvk|~J8p| cí;*6^XORcbګp\?'pxlk_qvJ o2pTUm|[6~?[{/pe7/nں~~[5Z+~1cj&ӇlzvSK-CP [Ĵe-OJU__LjƺSe6XX/aTپ&lj3MrXur>rL܉2*_Sbë-]Άe,V{"Zyku65CiRPo <}*i.ϐ:uI}޵}C6'|w2_&b޶ymP(C{fֆ\s ٴ7X/6,mu卅ujㄟ;z59y67s\!'3Xdݚj3]sgQ4]ݢm?i5Ҋ6LaƳzjU&6Ħ76/WL_2cX_NȦ8~w_ĦG+#/+Ʀyݱc$Uʖη'/gRelZ+/7GiS;6/VM̟"1F3̿U}b !F"l [/]t},ݢPs)Zel.8DlF~Sn8hTNg󈴛_lrWuWjrƓTi4Mj*EI)R7N]ebڊypt髆=k,mWv<ݫt2qBa&VV\e+Vە k9[yCf/տXN|"|RzulIvUe+hYijmT &h}iކԕkъoC/k*˺۴֘T.ږv\]e&ܶﭿLjƮnySl{W [NkRrQ!4S躮{1/S]~j>e>>}-wjn&J_۬N6.cf)ږӠjm77؛',WReʨ^R&S_XĦ1ic/RXYR}u%VTMcR3&6Yݒ;-3dhp\;VvGڔ)u?_Mki|Uêڍ__ʰqcӄe׍#uS4dS[..H/_ly3YC҇>|0=qg'_ ' Bd#D&Dt^:Dej]m"q8kV˽,ܳ,V藥=KOJ"+T<$5M+a?;U Սo ǺW/ar%6Ue?i?i_jL8_LߊoJ4)Vnݴ]5Әʲ"&M-wb~Wo=OMk[Fĸ-_9Gr͛]ߥ{NL`٠(ᗸO[˙-Oi"<1ue6琕[_al=Ϛ.,SzyLj"ǿޗ뗿/&Mp~Zӄ,jRl??_y[ݮC@sDrl0Umdy7m{8XMmj}_8;&N>?O#6ǖAëgRíN.ǗXaw XX/Wl~?5O+,]DJvZ떚jD:Pf~2ӂa#^k=^%%NuDl񖈝D.E ܒy'1*bMӶbOad~8U&n\鿁gE/[/D8.L8RO+ ؄==W\qC"8.'0X,&lr߰~QqZFT9}>s2`#uuur\lG}$y dy!Gw{ ɰVZm/.6ƨpNOOYQQÁ3swww%F<==tttp8^1###! ? {W? 6Rb )F @lb# [H-@l"+ ?C>xBVVM&&&&nrllʂhR ~Q ][`Veaa!tϟL&t:cӾdZVfCSS .xxx@Dr!`IIת4 vڞlJB2cbbVy~~,..z[ZZ=mLKKbAbb"NNN+ ^}Dvwmm * V Hм2)))<::bRRe2766>V?///) Fg{@\Ϋ+ߺl6333 +++`FFm6b'q|mm-g===z ^;_~u`||ߗ]v uH W*e`[ '3">vH~Y2ϭB9DQ臆={XSR,::NI1>I,`]YSMM4 1y`Ż?ū)LOϮ׼tCO3@{=.4W S2^5C`\&K|H$8As''H׻ "U77N,V>V:q,k,'6?F}oY1~ Z{?0L(CF&e-,!4{Z;~m$~CF=5iu?PZlY]/sq 1% cbjC'ݼ-Ӱ;3&SXO!,CPF BBsZ*tȼE lϛ'Ào%Q(/bM$"R-BySt < ] /yƪԳs LŔbK˫#7G<<b~/=/-:C(QNܿ}3i 3Th58 X\3>GelAC'b ER$nPD΋J~ m['Ѡe")(Ȑx5 >c f]KcNzI1N[;|%jJ0("3 t.| J*qQF@7 jH7'@L{RE qAAͷ]lC(N#KQWHoXQG `4QɫgA@?noiқ*/ru)S)+vQŕky8n3cjs@"mDžPt +4X$ |J8aVU;:!z/]&o8=cn*F׃H:381 ^QO`+] 9g=JUmCeS@%`+njǩD9|6ZZ8/95j'zLIdnFڍv9,9=NrG ;Fc9=pOJnX,P(@!F.[! o<<5iEX?7Ǎ: !p5U!4[7*4nI:rsm$Jesp)>|c.2*\"]~M 6tvw䈶"I m2JxLKIõ.|me6Y\Q{ %&6ǝՂ^NEXx]\UPuTA/ rjQCO-H/5z-Wxܯ\u˯Ev2g`§ҩ;P 9 /"mak^2/f_=IENDB`xflr5-6.09-06/images/OnResetFoilScale.png000644 001750 000144 00000002423 12246405674 021415 0ustar00techwinderusers000000 000000 PNG  IHDR szzsBIT|d pHYs_tEXtSoftwarewww.inkscape.org<IDATXmWyv3Ij6DhҨE֚4Zb2iBE|BA7jj۝ՔbHAHh#ȦHk6ٝI3.ٝM'{9y{f:2:rپՑ%#TG9_op_r-jAa Fg)j[qVlU?'Y $ j05w2PTFN-_glqяFm AxkF6W),Ő2.8UL39r=N"<FMڬsuQk0VǴb{s O8Y}2SuK.s"_9lzcs֩ y@fD\DY+d|1,l٬KBG=M+>(׊xRa ng?DvVEw x|ВcoVx~K1hz^ߖvQ=7kW)OGEL}"axO^K$' (Q-tg׀3/h_uM5n8*tTpGpt|,C@duñZn[ojX=p /#WOoOc/FXWmW/Uqqh=CcybVX~9Tp /h5WN>~`'ul503hyPBkd~K椈IrPω\Gr S;w((M Qf}xa|w7EVwaXxM!w o.GEK?X";L{۱[ ŋI٬OxX紝%,ncIENDB`xflr5-6.09-06/images/OnPolarView.png000644 001750 000144 00000001055 12246405674 020461 0ustar00techwinderusers000000 000000 PNG  IHDR szzsBIT|d pHYs//6tEXtSoftwarewww.inkscape.org<IDATXMasB4MVRBXf$)l`1K܅@YM-I Vj?N=ܹ9{9}>y? Q+bM `js38s؂ supZ%_69;\fqS.}":cXgDlC|~0b^[S5/(}Ui6eNvMS-GV|p+MW؏Fw+<9IV35f0Rݨ%C]4V<9vW/=fP%2MDw@O׊G!(D|J9P7r򲀹̍`#̕l+.;Ƴ<-Wax4N_1Ԃd]IENDB`xflr5-6.09-06/images/OnZoomLess.png000644 001750 000144 00000003046 12246405674 020326 0ustar00techwinderusers000000 000000 PNG  IHDR szzsBIT|d pHYs<JtEXtSoftwarewww.inkscape.org<IDATX[lUgfvk/TKRDL( h|`4AM0W bPLREҥR;}>v-E]['d3g3cy 06twg XS>RWjmY\6dҩh8;יdҥVt.BhllD W0p޿v!ħe)gU!D/wvܷe+%\X:GɮqСpoo7e=m7캭(4Kn]k]>v f~}⼊R X=/wUWWmUb}w_WǷ!0.޶$T{f0؁p81223JXlZfŭk<3$ذaf7BMoy M }9aQk+n(<^ U2aF=H4Zn4Uʶ6ܾfM)*@4U(J}Q^\={ شq#vv@ u[3m1Tf$1hMQĊe&iFW- W p!O &%__*[:: s@}L(KX,d29 TVS?bWmVV3U?Ok0RTHC}Aq8M2keÇ8_3l;xȑپ)6,2*ۋ9U _lL\r g4A8ql]&W2zH$aۙd8=aɜ{4}~ٲ\vm( cpWD"K2d"̺uۼ~=jjjPTU)S)D#TOG3sU0tg8H2"+ѵ;,{kkkSDhٟzO9Ϥq]iw j98̒t&D$pn7>t/o+bJX+}5ҭ2JEȕQW] x0V`obtBT)8D~G7-Ӝ50 @OJ^)HMnޜ8Pi!tx<=D%m,$lӼn^+ 8櫪:9g"9Hܑ#m&SSUXӼy{sNDR!҇^3g&'Q6UӒ%4MKhR&.\ۦKm̼_.^|ȨRcc+L1?hf|Łis@*{>O1=i8.rBPhH \ߍF4/-7%IENDB`xflr5-6.09-06/images/OnXView.png000644 001750 000144 00000002230 12246405674 017607 0ustar00techwinderusers000000 000000 PNG  IHDR@@iqsBIT|d pHYs+:IDATxO(ǟl6harP;@i(Q. w u"Gi[D98P s/ӆ5^f?>ob`mmmk@[[~? צlQ3'|m?G  ZH-@jd 5R HlF6@jR{Dp Ģ@D&Ddh$nF4o<}D,((@BBGɄ@ 5G$&*| q0|> I`K' lpݰZNmcjZj.--QRQT#/^k^a-..OpwwG^OՀs*JV>www J?j J`KK˻?rQP0==LMMBՄU`RR^4 @3|> y`VV}>&gff^]YY![(?Ckk+EВ`%ZWy{3׈q8)))<;;{ pfU*A~8ZF{=^7322D] 9'&&v  OCdtppggׯ_ 455fgg199 hnnR\__311jN%!6ioo`cc#l@h !1 KbAnn)#@fZ~,//'0ďx)T*nA1!!f屌̗ /}TM|5IENDB`xflr5-6.09-06/images/OnZView.png000644 001750 000144 00000002241 12246405674 017613 0ustar00techwinderusers000000 000000 PNG  IHDR@@iqsBIT|d pHYs+CIDATx+o(6&)('s"Z%p@N@?sBJ!™aJ#yYd[_{n^mwy\> $IPPcBd2dee 鄈)t\_Pm6[,iF#paaM`iii| `uu5J /*iii|||ր.>ZnXrڊ*~%z***~\" oj<>}Aww!Ejfff2;;///>:;; ۛXn W5fF1ϼd2-K⤿9 %%%|{{Kq꣈dhZd2{<"!f*8o31xÀH088H,++}„[ZZ ݎcD:-?[-;::R\Ԉ4?]^^n+++0L+xzzuU944$>}s2RS!\!6x$ }XUUEEp{{ v9圏~@*C>H$ :I uR4@&iHMk MNN CtC"HGhrjrĨxǖ0tİxG<f3pll0::5*߂?WWWh4TT\[[RVuDćMCMkb}uu i&ߙ/rXPPÁl\\\@VGe14D>'j4`___ @ fQ&1//gggɡL&Nb:`yyXTTD&?%zOV+AN4QZ48??)`aaa $I$U9UŐIENDB`xflr5-6.09-06/images/OnResetGraphScale.png000644 001750 000144 00000003637 12246405674 021575 0ustar00techwinderusers000000 000000 PNG  IHDRrr݅}sBIT|d pHYsAxtEXtSoftwarewww.inkscape.org<IDATxiUEMM-,Z m$CMþTZB QJhdb(hK4#2˴ԔL($B̅hU\2aUu{9{Ηys=gOj HO"=! HO"=! HO"=JU,"nyɫTJ3TL$x./f A'Pwdv9{!OdtDd"ہ}`"#"= ', lYJ Fd5"]+VY "Àp#2bqLD1Ri,Fdj$,`"3"Gc!lJ,;(;!qv*Ad!Do( pp1Qi vj#)HH'"KkQ'RUwYDΌ+ ҆qX AWgS7D`r(DڙD Eh% bZ2Ad>":rQ&9|!"O %]Ѩn)FGnDnZ TDF8rgQgRxAd>8w#լ';W#[GaȝP}~<'@ #w3 {U@"9n;&Aa#})kLH+[%JHg[\-R nG$CJE@K^lԐuF|T'ID+Rp#$C슄AijȲ>"&)e9@:)LلIYzH4 "DKDct?GXHEuL4ɖHfI6hiI߂ꞤH$(*@iXh ;"E>jUNvDBGgť,Y)bGIqܩdC̒ O͊t/"H3%}')X*"Ecx9 sof\;KaR8e/tv#f`7vK,n0- TH5jYf7 ի3:.5_5\GGZ"K"[y/&Hx)r"`m'f_2r["@yiߕu".4&yk፞\nFPvUU\u٨ 4L?J.-DV` QտbW >;B3DavV]}O%B"N.#as?+NbޒhchIn遉WQ$*r{hG)t;r4R) QKa#7"m˪T:A܂"Q_#mCGMI%W(޽Qb&?\o F"GXD+3D6V^!r.`VT "Y_z_Q{B"Uk<9`lk}m,[\c)sY{p`6OG1]TG^)GyDGֈ<|*PKfGX:Y`y":Q+u ]P8@9UXuY7eyq&fxďrAY㑪;0e%0D˪bvo踾|}IN"!wRMw[ 脪WsSP;~ԝ8sq[tBel9b{y@a pHYsodIDATxkGǿs{-QxSVD!>C4C835 })Z5!>ŇًPmTD+O_mܻۻۇٙ@foof6~gfwg=445 >ʕ_0bb $;7?|NI?60?g0mM@Qz'}Lmqv[onNXK @0NR$G @qG @qe+&vP-P-a%H,g'G @qG @qX.YA2hP-P-P &шA;24L$.TDN9J䣫ʼnwІFfш!RqDFw]UiA4bh8ZEyA4b5eh{'#E>wB E^`'P"p@Qz{+)4(_@L͋2 [КE1y?yעbE3::hjQs 颹D\|n%da.o&Ձ !<+ O]3kN?C: VqLѻl"L:  0XDKZL!|huB/k8LR xv+O/Ձ@iBEG 8u'U.&h0N\Ѕ[Zvp[NaeFc1@' BZ[w0Om'D!##i!ѱGh =Z'O^v6 !D{RNС}@dƞR@!ª/F}Ӗ1E( R BmTit'``>X5EQ > Q/@" @z̈wH "!ZЍ"T n|@ez/0hJ\VxTR@lIHN8rH]7b7CB>62sV^l#7r6 #73w xdW?`q3gbƌ0gΒW/.P4ۑ^|hI X78~8X@޽{isCpbH0] w>17*ʡa8z"sdCDX֭ X il[70E `pd*u:МH77X9Heat-]Z!hi,BMM5?t_Bꖵں<40Uƽ`9йz2JUHx/@aٶPIG8@(ozZĉ_sc|a*STy\aKC0WIENDB`xflr5-6.09-06/images/OnZoomIn.png000644 001750 000144 00000021316 12246405674 017766 0ustar00techwinderusers000000 000000 PNG  IHDRrr݅}sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATx}y\Wyޫ},w#Ye+ƬNC2`N̄ 932Ca21L=l1 Y xfYRU꽻7^UnjKQ^-~.Dlr'zHH{>pXD/CG$" \ t esHvZWDvX@oe /9W ~3d/xGaXu'ɧ|NDl$7xŝ==z@9Ri/Î]V'|H#Ёxppx̕D7V3hߗxݼ4DQ&֎k={'>$ჹp?a7X"  ]cǎ-RU٦ .? G"ضm ؁ĺkJ=Vvmk]ܽ{۶mFA8nkڦ ""ٶckt]ZZp[nlm^uR -Rtۄ?Gs.f{^[WW=VMֶ>AujB''݋T`EdZ bsZo `0ڱc k+%&ۍo[.wm#֎nFx2@Xy%D|tHR@9VLq[֭[g5I$^X=q ݗ|c$ӋHrvE/UPLx_ { hkknnnv"/jW>c1DP~Xk׮mXE^k!Uc =E[5`z ear ^s+[lؽ4pVsDŰ>k׹V jlD2*`6e5rlڽȟ;Ot&戄5y&@[4]ƒTćʶp\S>:]ݻ4MH/Z;zol~-9R@D)2Y_Q˽bm"҈B9^Z$v뛛aph*4=0UZ+eM? `jjjj ; `C<\}c>㚤x±er=4䶣í4444;"k1DŁaD]X!-ohH_u<Ϣ+QzkT~妛p? 7.Tö G"i"5] :7l{0cyL0 UJ^G{ 8lèG*B(()]jtFt3WV`~|jFW^C(^=2GZY ⧹+mHZޏ%[5Zg/. I;xVf y-^D(Mub҈zVQ Pj5o)b+Iba!"H&f ZV@D% JjE5З[Z._U6G#*aO|˚i47`(A6F^`~B^54T<*C|W_Wm=Ls7_^TR^YDArٙ@(R$"uueܖ`='>[相/78@+"PVI|fiYܺlV-J F>vjldY\\O`%XID+Y~ `.X{{vv}(LL\Df2i'jmZxʜGe'WX5`(MCz 3c(9[Z$r-N%<WDr7Uh?2juEix|KSTD*javv‘Ź9bDa /V ꋭ@X14M;*ã(x"K充l&e*LM2ݯ|iVJVU>DT|ޞptzjzzz  "RѨ9"홺`~bkSN޾K+1Tp%Kx(eCǭ+&':ꗔ#Ҷedldd?!gfG9x)J&+]:x틌/ 'UD$Jb&ziLN;9/Ey[="ZwdEr!ҶC٩823yrܿ,[#+'c%+T<CLOVz̞2 [j#t9rBji O:_`jjdyc| oܷRF4"2 MoV̽Lfx"SSSCzَe~Y0J&Ow?AA Z-jH=Dz0jɠ4ݿ[;{C)>*`e$?LVkxr>̀@P"}{w-//g`ycU"P JZZDxyqls #EDgÓ>*^YNr^YI}#GF# /tO|)~Zͺt5Yk  |a1ZX>&Z^\+~mCvЂ@yM__e: XaL%x ؋;#?ғTj7Zy}@ a`hJ.gQlRd3O~ǎHX>U|VJsҲЋ=y " L{Q[M _AD'zhXZS.'f )1 12?%e]y2̵LV _V:xOq8K}fsַ>J9S~[goBD'N,/gI%~ 2戛8LB m#`~n׾zCA8@˅K0G0{+\396G?ǝX jb`= Ev)NK* /Dtɥ@Z;;k׿M-- Z6zee&B&E"gםwbΊ2v"?D;VJiYޞ+"骫佰d H65E̒J[JG:mrHKK]]" L[ss+4iĸ^\ K~Z & J=96=Gj6=Db{"Aɖ4)\"D:dIo6[*FѴ1ggkR B~Wƶl޶3j4;fb0"is\v2L >p` E5\bwa;F5guE)i"%wMҫfD@4]'D3F>YLLzUo,$,[-bS|L<u4N%Ќz]iW`iuDtZt}7ZKvY=ގ MzR^rWXC 5fLEERJnkH9aާueU{&ZFΆ"Xf^izކsM$zDK"Ucl Mb၁SxH 0m ae4R" MSPDjs[ }H$+ z5gyhG(c:{DĀX)x1/y<muvD4?gx:ᑑOD^ 2R<M3HF''?f< 1n@ٚ:;ytM%y+?)TR|8D0^ C9c[?u5|^[`ڃsNdL4G(g0Śz=375@9493ww)uRb{أgϗ=^!ɀttJppkkJˣ狏@   %7X__*vuu50}\yvSSf4Bx^ލ?;;K)(((((((DS] IENDB`xflr5-6.09-06/images/OnZoomGraphX.png000644 001750 000144 00000001642 12246405674 020611 0ustar00techwinderusers000000 000000 PNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATXOUuϹؼ71*H hQjSD!!bTQ F-Zm B°U TaQ#9F3otf|8\?s~w~FfT\Sk17.4"b'd# \x7`?ޓ(;Lgd'IIEQk?Ї7o-|){4?]:ԓz'nS<2Rwj bGsQV> >b<}L晫-;sNl+qĴ>菈o}<rh%r\Ș|d+FW"y9Yݡnk-s/#,Vzrj9ywFMR @Ӯ[ݾ=&ZELTFUw{Xi젳+|:6<|Ig=-DD߱9Zŀ:O2ˆp֘;tڇͳNlr+:5cZcy*.nV8R>hѢnʓ>2؁[[nlj3#V5jAk7,{-21@H4!z=yI}J+{:(˛=`u%ClP }-RL8ى?D.2Wy2n?԰Ĉ4aT~a$Ftxf:PfV IJ>]vN5ػ」;v<:̗7XSڠkg|p?0x.ory #ӟd}k@E@xp,#˲m00aP|#%"+Օs΃* ,I Iw:琷Ղv+m(r8 㯼IkFؽ{k놮ZVmQg5 ,# /#&|#!Я'aa%% 4M:ólc V_)Fara-р: TIO4/!g iXvj#wPE x:Tx3x$wh6h߱R^DM_ 8ňKvRPZ0}@Ű&WU.2p}Ʉ-Jsf+7QW?תd~')Ü wl 55Y1{X0+WVU!ѐS,-޸Wj'WڣU<_o|w__sl}5ځ?MKFIENDB`xflr5-6.09-06/images/OnRedo.png000644 001750 000144 00000000506 12246405674 017442 0ustar00techwinderusers000000 000000 PNG  IHDR szz pHYsodIDATxӭ0 F CpX4E];҄ʊ;!9L)9˺1[XO)S_Zbc TUDt17 uvhFB\.jۖm뺎Mݾq  m8b ILyμXE*"6w+ @֒6:KBYQ@@c8D CpW8bd޴3eIENDB`xflr5-6.09-06/images/OnWOppView.png000644 001750 000144 00000001101 12246405674 020261 0ustar00techwinderusers000000 000000 PNG  IHDR szzsBIT|d pHYs  PtEXtSoftwarewww.inkscape.org<IDATXֽkTAg\* fH!QiDb#D b"v *Zj  1F "UhVF9fu?nl }̜93"BށSVDcb1Jc1wfJcTRnz5g1܋iL`?z/e-^9D̤9< H!ƃ ׂ7(0 Jm@ ߼Jp%x^=#QK#jԙ ^'P 2t5b0GUg"%EIOG_V}0)p},K+`/E,ݼpIYCs"IJ)q]x*07>a{;jcҸgk R n Mu%šj9sW}tC!0oEY}Kc%IENDB`xflr5-6.09-06/win/000755 001750 000144 00000000000 12246405674 015075 5ustar00techwinderusers000000 000000 xflr5-6.09-06/win/xflr5_doc.ico000644 001750 000144 00000045714 12246405674 017471 0ustar00techwinderusers000000 000000  F00 %  6 hdGPNG  IHDR\rfIDATxݏU`% 6Fͨ 2GUv/ !AAA3!!Id[/]f+/D(Q>vjyd355=U0{zje73f>ۛ`$E?G7_4(@tP0o޼ٳۖϷP˗kmcYe&a8m{?\'u]9s-k .@~m_~i[vʕڥK^ӓκ .0\ -ZxO>^x%pB?ŋu%ލ7]z5 EL-[_`AmɒeN_Ο?{ΝKߟXvbÓ@]`.uP @]Se>@]`.uP @]&Hj'.ӋP @]`.u 6iUs .0\@&ZP8 =(7`F.ɧ.\({`5hʕKS:>>vmP @]׮]MLL- XbիWkׯ_7G>IJI+uP` @  @FFFR`V><g;7`J C`? isgl[izүS>O]>Z'eHx?fΜU1cF㭯y9k[ o^u|+ ߏf5דIr=Ik_Xvky_˂ ޏqtYV'\IJ<:4sw ݝ"2mh % `K{P@ .z<Ȼ=.r05Ȼ=rad4@jA j% (hdhbn@+h5Xn0"?fPhu ( Z@3p a+h PT~(ї~Ghf<<T{w(p+ONqqP2&NT4pW6h@S2ؿC6oV/^~(|GioNXƥ >! @|_{jvmJ jD>7<` 4::VCY3и" xU@ :4t @VyU^$V@$!V Xre%^p¶e@2[VX2>gVe ˵,-hU iZ @{ @ӃkF@ҁй Ν[:uREPXiÆ͕@qiI+ ]lUdC Ey!ƃI,R0OH6MCqٳmpV P `^@Q}zm@@9{6= 9/@wݨyng0&@)p@O?7;ב l!͛wѶl te%(@@7%_ vd{# @ :P[Hpok[ yd/ڶmgP9|ou]6 -4ll+$(WHH y X^ Fײ=-pI oJ Le m4 M"Hi%8d4  D@ [P$2d *db( x`@J6&Tv~ * 2E_  @`H.#A`H."Pƭ<X!(s]3  2_~  iE [P1`TeK-pZ?Ww%(@㎞mzN VN'ׯ?J=P$,XRj2^#i?/|:Pїpj0(J w}w)2AA@? r )σ]4(@gqn>:\~)}w<|f  h~ @.H/φ8?=] wAm;qXڇ_c >RM /i:26of\~  1qLmG|[9&\~ >C}ưP=}PS=33 oOS)!ɷ]ؠ6lؐ>.ڶaBmrBm{X^׏]n:vںc]m露y,hdڲq1 SZ}>]:mzt@ @ ^OgϞ@ ^B/}n4@@!s?@ ^B/}md}yh?@ @ ? P(fKv[ 3@@!k}K.Y\ܝnp?B/@ /_^tʻ^Kz*_r[} Pz|}6͗5 o~󟉜3sw.s堏?~@ՀKßN|@WsQc-94T(׿~v=t4ۏ]\dPP կvTwNŶkTd暏F-WKޞtI9^,>V@Nyzߵsc@С՗BWܹt(}x߬m٘7Aj8.Ag6GP/ti J_WV2^Yzlϻ@jpY2WԵdǎoNmmm(c{uN]>o˛ԈA  2.Ѝi@giy5"B@7^cPƸ o҇sZ?[b0 n|$6+A  ݘw@!Ӟ@  ݘvݻwKMy@'l߾y@u}}Pt'aM5@!ӭ2n(tc h^Phkd۶yE@VPTP [L#0=fMiЍF}|7FdE jҏAutЍ^]}7@1|_>y=4 n -ЍOB@  ? uvڜw@}Sߦ1:@!Ӝ6G0^mH`ɖ-[؜t;@1Mu@ĹJ@<3 |w5@&YXXPO> ŸQF摀iPN|>?ܛ[_zzX7>b~ro\cGY'k*!/8s AufMh6YtG_{ܿONrz7o~4JB4P8{T~ ӋdZr>d_07`)}6ptiD؈Eŋ򒎧Śg D!dEoq׻sZ'VYO1uk-k{ڇHӇ~ֳƬ"ر_25F-"@?yMB5F.]H_sU;S!/>Fuf-I*K%}M~+֊:$0#:ӗ,ZD @bfd_sb +%! $ж(6ҷU_uC @~g,(Mf h ļg$`33Z@keN@`c:9Q›̌IB[COЀ&Q61 @~nCU| 1.ꆾ6}$u c.00v1 kw!csS: Я͟DʹOb C[s4"!Pѵ(5tc: * `c4Ƶ0pc$0":!h/ :zcFc4ƵX )pc7&HCz !/ :zc<W$_@ut, @c] @@0`XGW/HG!p A=AXп @x~8֩$_@u* Gh /  h|9H`v| ?LL73Gӛ#Q + ~ x~B3%kqqw~20oܸ1Mr@wx~B|&_LZ9돻<~+H_|16mM* M @@v9":z.R Y O%@@+x(_}o @T?"=ӱl3Km$N@\t(40pt <03km%C~tLHo$Pcl 蔖wC1Mu ]w|@=aN T'X| g(ʕە"1:up{G ៌Cm R ټ|@XH yܸښ #4zt~W@!\`gJ!D"E8thgiڡ/l/4G(!6 t-B }?y/D)6ËyסoHl.>𧋀Gѭ[Y[P}ekE"U|G1f ȑS%0-HO`":U 1 `& {K݇>_߉Z֠@'O>x챥.C-S0jy *ӡg-^O/|vZ' E}cL=n<}\k+ LD'O6M"e-wsI{9j| Ϧq1ܿ*#^-\L;'}}  b@ yzmIENDB`( xxzz}}tllvnnxoozqq}uuvvxxzz}}g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}};f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}˽;g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}˽;g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}ʻ˽;ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}ʻ˽;meeoggpiitllvnnxoozqq}uuvvxxzz}}ʻʻ˽;meeoggpiitllvnnxoozqq}uuvvxxzz}}Ⱥʻʻ˽;oggpiitllvnnxoozqq}uuvvxxzz}}ƹȺʻʻ˽;piitllvnnxoozqq}uuvvxxzz}}ƹȺʻʻ˽;tllvnnxoozqq}uuvvxxzz}}ŷƹȺʻʻ˽;tllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;vnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;xoozqq}uuvvxxzzõŷƹȺʻʻ˽;/,,zqq}uuvvxxõŷƹȺʻʻ˽;-++/,,2//zqq}uuvvõŷƹȺʻʻ˽;)&&*((-++/,,2//}uuvvõŷƹȺʻʻ˽;)&&*((-++/,,2//522}uuõŷƹȺʻʻ˽;&"")&&*((-++/,,2//522722õŷƹȺʻʻ˽;" &"")&&*((-++/,,2//522722966õŷƹȺʻʻ˽;" &"")&&*((-++/,,2//522722966õŷƹȺʻʻ˽; " &"")&&*((-++/,,2//522722966;77õŷƹȺʻʻ˽; " &"")&&*((-++/,,2//522722966;77=99õŷƹȺʻʻ˽; " &"")&&*((-++/,,2//522722966;77=99A<<õŷƹȺʻʻ˽; " &"")&&*((-++/,,2//522722966;77=99A<>ŷƹȺʻʻ˽; " &"")&&*((-++/,,2//522722966;77=99A<>ŷƹȺʻʻ˽; " &"")&&*((-++/,,2//522722966;77=99A<>FAAƹȺʻʻ˽; " &"")&&*((-++/,,2//522722966;77=99A<>FAAHCCȺʻʻ˽; " &"")&&*((-++/,,2//522722966;77=99A<>FAAHCCJEEʻʻ˽; " &"")&&*((-++/,,2//522722966;77=99A<>FAAHCCJEEʻʻ˽;  " &"")&&*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFʻʻ˽; " &"")&&*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHʻ˽;;77=99A<>FAAHCCJEELFFʻ˽;ʻ˽;ʻ˽;ʻ˽;ʻ˽;˽;˽;˽;˽;˽;˽;ʻ˽;ʻ˽;ʻ˽;ʻ˽;ʻ˽;ʻ˽;ʻʻ˽;ʻʻ˽;Ⱥʻʻ˽;Ⱥʻʻ˽;tllvnnxooƹȺʻʻ˽;piitllvnnxoozqqȺʻʻ˽;oggpiitllvnnxoozqq}uuʻʻ˽;oggpiitllvnnxoozqq}uuvvʻʻ˽;meeoggpiitllvnnxoozqq}uuvvxxʻ˽;ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}˽;ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}};g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}};g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}&"")&&*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;&"")&&*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;)&&*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;)&&*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;)&&*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;)&&*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;)&&*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;)&&*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;*((-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzzõŷƹȺʻʻ˽;-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzzõŷƹȺʻʻ˽;-++/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzzõŷƹȺʻʻ˽;/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzzõŷƹȺʻʻ˽;/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzzõŷƹȺʻʻ˽;/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}/,,2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}2//522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}522722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;722966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;966;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;;77=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;=99A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;A<>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;B>>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;B>>FAAHCCJEELFFNHHQLLSMMUOOYRR[TT\VV`YYb[[f^^g``ibbmeeoggpiitllvnnxoozqq}uuvvxxzz}}õŷƹȺʻʻ˽;?p?????????????@@>?? 8??(@ õhaanffskkwooõƹʻ˽ZSS_YYc\\haanffskkõƹʻ˽_YYc\\haanffskkõƹʻ˽c\\haanffõƹʻ˽haanffõƹʻ˽haaõƹʻ˽õƹʻ˽õƹʻ˽($$,))õƹʻ˽($$,))1..õƹʻ˽ ($$,))1..733õƹʻ˽ ($$,))1..733ƹʻ˽ ($$,))1..733<88ʻ˽ ($$,))1..733<88@;;ʻ˽,))1..733<88˽˽˽˽˽˽˽˽˽ʻ˽ʻ˽haanffskkwooƹʻ˽ZSS_YYc\\haanffskkwoo}ttõƹʻ˽($$,))1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽($$,))1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽($$,))1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽($$,))1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽,))1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽,))1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽,))1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽,))1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽,))1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyyõƹʻ˽,))1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyyõƹʻ˽1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyyõƹʻ˽1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||1..733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||733<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽<88@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽@;;E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽E@@IDDOIITNNZSS_YYc\\haanffskkwoo}ttyy||õƹʻ˽???8?<|`?0(0` tllŷʻ;`YYg``oggŷʻ;`YYg``ŷʻ;g``ŷʻ;ŷʻ;ŷʻ;1..ŷʻ;)''1..833ŷʻ;! )''1..833ʻ;! )''1..833>::ʻ;! )''1..833;;;;;;g``oggtllʻ;YRR`YYg``oggtll|ssʻ;)''1..833>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;)''1..833>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;)''1..833>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;1..833>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;1..833>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;1..833>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;1..833>::FAAMGGQLLYRR`YYg``oggtll|ssyyŷʻ;1..833>::FAAMGGQLLYRR`YYg``oggtll|ssyyŷʻ;1..833>::FAAMGGQLLYRR`YYg``oggtll|ssyy833>::FAAMGGQLLYRR`YYg``oggtll|ssyy833>::FAAMGGQLLYRR`YYg``oggtll|ssyy833>::FAAMGGQLLYRR`YYg``oggtll|ssyy833>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~833>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~833>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;>::FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;FAAMGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;MGGQLLYRR`YYg``oggtll|ssyy~~ŷʻ;??~>?( @ Ķ`ZZmeeĶʼĶʼĶʼĶʼ-**ʼ# -**955meevnnʼ-**955C??LGGXRR`ZZmeevnnwwĶʼ-**955C??LGGXRR`ZZmeevnnwwĶʼ955C??LGGXRR`ZZmeevnnwwĶʼ955C??LGGXRR`ZZmeevnnwwĶʼ955C??LGGXRR`ZZmeevnnwwĶʼ955C??LGGXRR`ZZmeevnnwwC??LGGXRR`ZZmeevnnwwC??LGGXRR`ZZmeevnnwwC??LGGXRR`ZZmeevnnwwC??LGGXRR`ZZmeevnnwwĶʼC??LGGXRR`ZZmeevnnwwĶʼC??LGGXRR`ZZmeevnnwwĶʼLGGXRR`ZZmeevnnwwĶʼLGGXRR`ZZmeevnnwwĶʼLGGXRR`ZZmeevnnwwĶʼx 8@8(  rkkǹǹrkk~~633JEE^XXrkkǹJEE^XXrkkJEE^XXrkk~~JEE^XXrkk~~JEE^XXrkk~~ǹ^XXrkk~~ǹAAA@AA`AAAAAAAAAAAxflr5-6.09-06/License.txt000644 001750 000144 00000043120 12246405674 016423 0ustar00techwinderusers000000 000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. xflr5-6.09-06/xflr5_6.09.pro000644 001750 000144 00000017334 12247173572 016546 0ustar00techwinderusers000000 000000 # ------------------------------------------------- # Project created by QtCreator 2009-02-14T15:30:46 # ------------------------------------------------- CONFIG += qt QT += opengl QT += xml TEMPLATE = app SOURCES += \ src/XFLR5Application.cpp \ src/miarex/BodyGridDlg.cpp \ src/miarex/BodyScaleDlg.cpp \ src/miarex/BodyTableDelegate.cpp \ src/miarex/BodyTransDlg.cpp \ src/miarex/CtrlTableDelegate.cpp \ src/miarex/GLCreateLists.cpp \ src/miarex/GLCreateBodyLists.cpp \ src/miarex/GL3dWingDlg.cpp \ src/miarex/GL3DScales.cpp \ src/miarex/GL3dBodyDlg.cpp \ src/miarex/LLTAnalysisDlg.cpp \ src/miarex/LLTAnalysis.cpp \ src/miarex/InertiaDlg.cpp \ src/miarex/NURBSDomDoc.cpp \ src/miarex/Miarex.cpp \ src/miarex/ManageUFOsDlg.cpp \ src/miarex/PlaneDlg.cpp \ src/miarex/PanelAnalysisDlg.cpp \ src/miarex/StabPolarDlg.cpp \ src/miarex/StabViewDlg.cpp \ src/miarex/UFOTableDelegate.cpp \ src/miarex/WAdvancedDlg.cpp \ src/miarex/WingDelegate.cpp \ src/miarex/WingScaleDlg.cpp \ src/miarex/WPolarDlg.cpp \ src/miarex/ImportObjectDlg.cpp\ src/xdirect/BatchDlg.cpp \ src/xdirect/BatchThreadDlg.cpp \ src/xdirect/XFoilTask.cpp \ src/xdirect/CAddDlg.cpp \ src/xdirect/FoilCoordDlg.cpp \ src/xdirect/FoilGeomDlg.cpp \ src/xdirect/FoilPolarDlg.cpp \ src/xdirect/EditPlrDlg.cpp \ src/xdirect/FlapDlg.cpp \ src/xdirect/InterpolateFoilsDlg.cpp \ src/xdirect/LEDlg.cpp \ src/xdirect/ManageFoilsDlg.cpp \ src/xdirect/NacaFoilDlg.cpp \ src/xdirect/ReListDlg.cpp \ src/xdirect/TEGapDlg.cpp \ src/xdirect/TwoDPanelDlg.cpp \ src/xdirect/XDirectStyleDlg.cpp \ src/xdirect/XFoil.cpp \ src/xdirect/XFoilAnalysisDlg.cpp \ src/xdirect/XFoilAdvancedDlg.cpp \ src/xdirect/XDirect.cpp \ src/objects/ArcBall.cpp \ src/objects/Body.cpp \ src/objects/CVector.cpp \ src/objects/Foil.cpp \ src/objects/Frame.cpp \ src/objects/OpPoint.cpp \ src/objects/Panel.cpp \ src/objects/Plane.cpp \ src/objects/Polar.cpp \ src/objects/Quaternion.cpp \ src/objects/PlaneOpp.cpp \ src/objects/NURBSSurface.cpp \ src/objects/Spline.cpp \ src/objects/Surface.cpp \ src/objects/WPolar.cpp \ src/objects/Wing.cpp \ src/objects/SplineFoil.cpp \ src/objects/WingOpp.cpp \ src/misc/SaveOptionsDlg.cpp \ src/misc/ProgressDlg.cpp \ src/misc/ModDlg.cpp \ src/misc/PolarFilterDlg.cpp \ src/misc/TranslatorDlg.cpp \ src/misc/UnitsDlg.cpp \ src/misc/RenameDlg.cpp \ src/misc/LinePickerDlg.cpp \ src/misc/LineDelegate.cpp \ src/misc/LineCbBox.cpp \ src/misc/FloatEditDelegate.cpp \ src/misc/DisplaySettingsDlg.cpp \ src/misc/ColorButton.cpp \ src/misc/DoubleEdit.cpp \ src/misc/IntEdit.cpp \ src/misc/GLLightDlg.cpp \ src/misc/AboutQ5.cpp \ src/misc/NewNameDlg.cpp \ src/misc/ObjectPropsDlg.cpp \ src/misc/W3dPrefsDlg.cpp \ src/misc/LineBtn.cpp \ src/graph/QGraph.cpp \ src/graph/GraphWidget.cpp \ src/graph/GraphDlg.cpp \ src/graph/Graph.cpp \ src/graph/Curve.cpp \ src/xinverse/FoilSelectionDlg.cpp \ src/xinverse/PertDlg.cpp \ src/xinverse/XInverse.cpp \ src/xinverse/InverseOptionsDlg.cpp \ src/design/FoilTableDelegate.cpp \ src/design/AFoilGridDlg.cpp \ src/design/LECircleDlg.cpp \ src/design/AFoil.cpp \ src/design/SplineCtrlsDlg.cpp \ src/design/AFoilTableDlg.cpp \ src/globals.cpp \ src/main.cpp \ src/mainframe.cpp \ src/threedwidget.cpp \ src/twodwidget.cpp HEADERS += \ src/XFLR5Application.h \ src/miarex/Miarex.h \ src/miarex/GLCreateLists.h \ src/miarex/GLCreateBodyLists.h \ src/miarex/WingScaleDlg.h \ src/miarex/CtrlTableDelegate.h \ src/miarex/WPolarDlg.h \ src/miarex/WingDelegate.h \ src/miarex/PlaneDlg.h \ src/miarex/PanelAnalysisDlg.h \ src/miarex/ManageUFOsDlg.h \ src/miarex/UFOTableDelegate.h \ src/miarex/StabViewDlg.h \ src/miarex/InertiaDlg.h \ src/miarex/StabPolarDlg.h \ src/miarex/LLTAnalysisDlg.h \ src/miarex/LLTAnalysis.h \ src/miarex/BodyGridDlg.h \ src/miarex/BodyTableDelegate.h \ src/miarex/BodyScaleDlg.h \ src/miarex/WAdvancedDlg.h \ src/miarex/GL3dWingDlg.h \ src/miarex/NURBSDomDoc.h \ src/miarex/BodyTransDlg.h \ src/miarex/GL3DScales.h \ src/miarex/GL3dBodyDlg.h \ src/miarex/ImportObjectDlg.h \ src/xdirect/XFoil.h \ src/xdirect/XFoilAnalysisDlg.h \ src/xdirect/XFoilAdvancedDlg.h \ src/xdirect/XDirect.h \ src/xdirect/TwoDPanelDlg.h \ src/xdirect/TEGapDlg.h \ src/xdirect/InterpolateFoilsDlg.h \ src/xdirect/FoilGeomDlg.h \ src/xdirect/FoilCoordDlg.h \ src/xdirect/ReListDlg.h \ src/xdirect/XDirectStyleDlg.h \ src/xdirect/ManageFoilsDlg.h \ src/xdirect/NacaFoilDlg.h \ src/xdirect/EditPlrDlg.h \ src/xdirect/LEDlg.h \ src/xdirect/FoilPolarDlg.h \ src/xdirect/FlapDlg.h \ src/xdirect/CAddDlg.h \ src/xdirect/BatchDlg.h \ src/xdirect/BatchThreadDlg.h \ src/xdirect/XFoilTask.h \ src/xinverse/XInverse.h \ src/xinverse/InverseOptionsDlg.h \ src/xinverse/FoilSelectionDlg.h \ src/xinverse/PertDlg.h \ src/objects/WPolar.h \ src/objects/Wing.h \ src/objects/Surface.h \ src/objects/Spline.h \ src/objects/WingSection.h \ src/objects/OpPoint.h \ src/objects/Quaternion.h \ src/objects/PlaneOpp.h \ src/objects/Polar.h \ src/objects/CVector.h \ src/objects/Plane.h \ src/objects/CRectangle.h \ src/objects/NURBSSurface.h \ src/objects/Panel.h \ src/objects/Frame.h \ src/objects/Foil.h \ src/objects/Body.h \ src/objects/ArcBall.h \ src/objects/SplineFoil.h \ src/objects/WingOpp.h \ src/objects/PointMass.h \ src/misc/SaveOptionsDlg.h \ src/misc/ModDlg.h \ src/misc/PolarFilterDlg.h \ src/misc/TranslatorDlg.h \ src/misc/UnitsDlg.h \ src/misc/RenameDlg.h \ src/misc/LinePickerDlg.h \ src/misc/LineDelegate.h \ src/misc/FloatEditDelegate.h \ src/misc/DisplaySettingsDlg.h \ src/misc/W3dPrefsDlg.h \ src/misc/ColorButton.h \ src/misc/LineCbBox.h \ src/misc/AboutQ5.h \ src/misc/DoubleEdit.h \ src/misc/IntEdit.h \ src/misc/GLLightDlg.h \ src/misc/ProgressDlg.h \ src/misc/NewNameDlg.h \ src/misc/ObjectPropsDlg.h \ src/misc/LineBtn.h \ src/graph/GraphWidget.h \ src/graph/Graph.h \ src/graph/GraphDlg.h \ src/graph/Curve.h \ src/graph/QGraph.h \ src/design/AFoil.h \ src/design/AFoilGridDlg.h \ src/design/LECircleDlg.h \ src/design/SplineCtrlsDlg.h \ src/design/FoilTableDelegate.h \ src/design/AFoilTableDlg.h \ src/params.h \ src/globals.h \ src/mainframe.h \ src/twodwidget.h \ src/threedwidget.h TRANSLATIONS = translations/xflr5v6.ts \ translations/xflr5v6_de.ts \ translations/xflr5v6_fr.ts \ translations/xflr5v6_ja.ts RESOURCES += xflr5.qrc win32 { TARGET = XFLR5 RC_FILE = win/xflr5.rc #win32 compiler QMAKE_LFLAGS_WINDOWS += -Wl,--large-address-aware } unix { TARGET = xflr5 # release: DESTDIR = ../build/release # debug: DESTDIR = ../build/debug # OBJECTS_DIR = $$DESTDIR/.o # MOC_DIR = $$DESTDIR/.moc # RCC_DIR = $$DESTDIR/.rcc # VARIABLES isEmpty(PREFIX):PREFIX = /usr BINDIR = $$PREFIX/bin DATADIR = $$PREFIX/share # MAKE INSTALL INSTALLS += target target.path = $$BINDIR } macx { CONFIG(release, debug|release) { OBJECTS_DIR = ./build/release MOC_DIR = ./build/release RCC_DIR = ./build/release UI_HEADERS_DIR = ./build/release } CONFIG(debug, debug|release) { OBJECTS_DIR = ./build/debug MOC_DIR = ./build/debug RCC_DIR = ./build/debug UI_HEADERS_DIR = ./build/debug } TARGET = XFLR5 TEMPLATE = app CONFIG += i386 QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.4 QMAKE_MAC_SDK = /Developer/SDKs/MacOSX10.6.sdk OTHER_FILES += mac/Info.plist LIBS += -framework \ CoreFoundation QMAKE_INFO_PLIST = mac/Info.plist ICON = mac/xflr5.icns } OTHER_FILES += doc/ReleaseNotes.txt \ qss/appwidget.css \ qss/xflr5_style.qss \ qss/default.qss #MAKE_LFLAGS_WINDOWS += Wl, -heap,500000000 #QMAKE_LFLAGS_WINDOWS += Wl, -heap, 500000000 #QMAKE_CFLAGS+=-pg #QMAKE_CXXFLAGS+=-pg #QMAKE_LFLAGS+=-pg #QMAKE_CXXFLAGS += -Wall xflr5-6.09-06/xflr5.qrc000644 001750 000144 00000002674 12246405674 016060 0ustar00techwinderusers000000 000000 images/new.png images/open.png images/save.png images/On3DView.png images/OnBody.png images/OnCpView.png images/OnExtractFoil.png images/OnPolarView.png images/OnRedo.png images/OnResetFoilScale.png images/OnResetGraphScale.png images/OnStoreFoil.png images/OnUndo.png images/OnWOppView.png images/OnZoomIn.png images/OnZoomLess.png images/OnResetXScale.png images/OnZoomGraphX.png images/OnZoomGraphY.png images/OnZoomYScale.png images/OnStabView.png images/OnRootLocus.png images/On3DModes.png images/xflr5_64.png images/splash.png images/OnYView.png images/OnXView.png images/OnZView.png images/OnIsoView.png qss/images/checkbox_unchecked.png qss/images/checkbox.png qss/images/down_arrow.png qss/images/handle.png xflr5-6.09-06/mac/000755 001750 000144 00000000000 12246405674 015040 5ustar00techwinderusers000000 000000 xflr5-6.09-06/mac/xflr5.icns000755 001750 000144 00000120015 12246405674 016760 0ustar00techwinderusers000000 000000 icns it32_H>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҚH>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҙI<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҙI<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҙI<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҙI<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҙI<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҙI<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҘJ9<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҘJ9<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҘJ9<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҘJ9<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҘJ9<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҘJ9<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҗK79<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҗK79<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҗK79<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҗK79<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҗK79<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҖL679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҖL679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҖL679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҖL679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҖL679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҖL679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҕM2679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҕM2679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҕ#2679<>ACEFHLMORTVY[^`begilnoquvxz}#2679<>ACEFHLMORTVY[^`begilnoquvxz}#2679<>ACEFHLMORTVY[^`begilnoquvxz}"2679<>ACEFHLMORTVY[^`begilnoquvxz}#22679<>ACEFHLMORTVY[^`begilnoquvxz}#22679<>ACEFHLMORTVY[^`begilnoquvxz}#22679<>ACEFHLMORTVY[^`begilnoquvxz}"22679<>ACEFHLMORTVY[^`begilnoquvxz}#/22679<>ACEFHLMORTVY[^`begilnoquvxz}#/22679<>ACEFHLMORTVY[^`begilnoquvxz}#/22679<>ACEFHLMORTVY[^`begilnoquvxz}#/22679<>ACEFHLMORTVY[^`begilnoquvxz}$,/22679<>ACEFHLMORTVY[^`begilnoquvxz}$,/22679<>ACEFHLMORTVY[^`begilnoquvxz}#,/22679<>ACEFHLMORTVY[^`begilnoquvxz#,/22679<>ACEFHLMORTVY[^`begilnoquvxzī$+,/22679<>ACEFHLMORTVY[^`begilnoquvxz&Ʃ$+,/22679<>ACEFHLMORTVY[^`begilnoquvxz(ĀɤQ+,/22679<>ACEFHLMORTVY[^`begilnoquvxzĀˢQ+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̟R(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā ΝR(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀ϛR(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀ϚR(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀ϙR(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀іS&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πS&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πҔS&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πғS&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πсґS&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πсґS&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πтҏT"&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πтҏT"&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҨ^`begilnoquvxz}Ā̀΀πуԉ`begilnoquvxz}Ā̀΀πуԉ`begilnoquvxz}Ā̀΀πуԉbegilnoquvxz}Ā̀΀πуԊ begilnoquvxz}Ā̀΀πуҀԊ egilnoquvx Ā̀΀πуҁԉgilnoquv Ā̀΀πуҁԊgilnoqu Ā̀΀πуҁՊilnoq Ā̀΀πуҁՋlno Ā̀΀πуҁՊ Ā̀΀πуҁՋ Ā̀΀πуҁՌ Ā̀΀πуҁՍ Ā̀΀πуҁՍĀ̀΀πуҁՎĀ̀΀πуҁԀՎĀ̀΀πуҁԀՏĀ̀΀πуҁԀՐĀ̀΀πуҁԀՑĀ̀΀πуҁԀՑĀ̀΀πуҁԀՒĀ̀΀πуҁԀՓĀ̀΀πуҁԀՔĀ̀΀πуҁԀՕĀ̀΀πуҁԀՕĀ̀΀πуҁ՗Ā̀΀πуҁ՘Ā̀΀πуҁՙĀ̀΀πуҁՙĀ̀΀πуҁՑ79<>ACEFĀ̀΀πуҁՇ "&(+,/22679<>ACEFHĀ̀΀πуҁՂ  "&(+,/22679<>ACEF Ā̀΀πуҁՃ "&(+,/22679<>ACE Ā̀΀πуҁԄ "&(+,/22679<>ACE Ā̀΀πуҁԅ "&(+,/22679<>AC Ā̀΀πуҀԆ "&(+,/22679<>A Ā̀΀πуҀԇ "&(+,/22679<> Ā̀΀πуҀԇ "&(+,/22679<> Ā̀΀πуԉ "&(+,/22679<Ā̀΀πуԋ  "&(+,/22679Ā̀΀πуԋ  "&(+,/2267Ā̀΀πуԌ "&(+,/226Ā̀΀πуҍ "&(+,/226Ā̀΀πтҏ"&(+,/22Ā̀΀πтҐ&(+,/2uĀ̀΀πсґ&(+,/uvĀ̀΀πрҔ+,/quvĀ̀΀πҖ,quvxĀ̀΀πҘoquvxzĀ̀΀πј noquvxz}Ā̀΀љ lnoquvxz}Ā̀΀љ lnoquvxz} Ā̀΀ϙ ilnoquvxz} Ā̀Ϛgilnoquvxz} Ā̀Λegilnoquvxz} ĀΜegilnoquvxz} Ā̜begilnoquvxz} Ā˟`begilnoquvxz} Āɠ`begilnoquvxz}ĀȢ^`begilnoquvxz} Ƥ`begilnoquvxz}lnoquvxz} xz}H>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҚH>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҙI<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҙI<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҙI<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҙI<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҙI<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҙI<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҘJ9<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҘJ9<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҘJ9<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҘJ9<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҘJ9<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҘJ9<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҗK79<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҗK79<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҗK79<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҗK79<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҗK79<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҖL679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҖL679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҖL679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҖL679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҖL679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҖL679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҕM2679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҕM2679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҕ#2679<>ACEFHLMORTVY[^`begilnoquvxz}#2679<>ACEFHLMORTVY[^`begilnoquvxz}#2679<>ACEFHLMORTVY[^`begilnoquvxz}"2679<>ACEFHLMORTVY[^`begilnoquvxz}#22679<>ACEFHLMORTVY[^`begilnoquvxz}#22679<>ACEFHLMORTVY[^`begilnoquvxz}#22679<>ACEFHLMORTVY[^`begilnoquvxz}"22679<>ACEFHLMORTVY[^`begilnoquvxz}#/22679<>ACEFHLMORTVY[^`begilnoquvxz}#/22679<>ACEFHLMORTVY[^`begilnoquvxz}#/22679<>ACEFHLMORTVY[^`begilnoquvxz}#/22679<>ACEFHLMORTVY[^`begilnoquvxz}$,/22679<>ACEFHLMORTVY[^`begilnoquvxz}$,/22679<>ACEFHLMORTVY[^`begilnoquvxz}#,/22679<>ACEFHLMORTVY[^`begilnoquvxz#,/22679<>ACEFHLMORTVY[^`begilnoquvxzī$+,/22679<>ACEFHLMORTVY[^`begilnoquvxz&Ʃ$+,/22679<>ACEFHLMORTVY[^`begilnoquvxz(ĀɤQ+,/22679<>ACEFHLMORTVY[^`begilnoquvxzĀˢQ+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̟R(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā ΝR(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀ϛR(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀ϚR(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀ϙR(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀іS&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πS&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πҔS&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πғS&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πсґS&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πсґS&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πтҏT"&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πтҏT"&(+,/22679<>ACEFHLMORTVY[^`begilnoquvxz}Ā̀΀πуҨ^`begilnoquvxz}Ā̀΀πуԉ`begilnoquvxz}Ā̀΀πуԉ`begilnoquvxz}Ā̀΀πуԉbegilnoquvxz}Ā̀΀πуԊ begilnoquvxz}Ā̀΀πуҀԊ egilnoquvx Ā̀΀πуҁԉgilnoquv Ā̀΀πуҁԊgilnoqu Ā̀΀πуҁՊilnoq Ā̀΀πуҁՋlno Ā̀΀πуҁՊ Ā̀΀πуҁՋ Ā̀΀πуҁՌ Ā̀΀πуҁՍ Ā̀΀πуҁՍĀ̀΀πуҁՎĀ̀΀πуҁԀՎĀ̀΀πуҁԀՏĀ̀΀πуҁԀՐĀ̀΀πуҁԀՑĀ̀΀πуҁԀՑĀ̀΀πуҁԀՒĀ̀΀πуҁԀՓĀ̀΀πуҁԀՔĀ̀΀πуҁԀՕĀ̀΀πуҁԀՕĀ̀΀πуҁ՗Ā̀΀πуҁ՘Ā̀΀πуҁՙĀ̀΀πуҁՙĀ̀΀πуҁՑ79<>ACEFĀ̀΀πуҁՇ "&(+,/22679<>ACEFHĀ̀΀πуҁՂ  "&(+,/22679<>ACEF Ā̀΀πуҁՃ "&(+,/22679<>ACE Ā̀΀πуҁԄ "&(+,/22679<>ACE Ā̀΀πуҁԅ "&(+,/22679<>AC Ā̀΀πуҀԆ "&(+,/22679<>A Ā̀΀πуҀԇ "&(+,/22679<> Ā̀΀πуҀԇ "&(+,/22679<> Ā̀΀πуԉ "&(+,/22679<Ā̀΀πуԋ  "&(+,/22679Ā̀΀πуԋ  "&(+,/2267Ā̀΀πуԌ "&(+,/226Ā̀΀πуҍ "&(+,/226Ā̀΀πтҏ"&(+,/22Ā̀΀πтҐ&(+,/2uĀ̀΀πсґ&(+,/uvĀ̀΀πрҔ+,/quvĀ̀΀πҖ,quvxĀ̀΀πҘoquvxzĀ̀΀πј noquvxz}Ā̀΀љ lnoquvxz}Ā̀΀љ lnoquvxz} Ā̀΀ϙ ilnoquvxz} Ā̀Ϛgilnoquvxz} Ā̀Λegilnoquvxz} ĀΜegilnoquvxz} Ā̜begilnoquvxz} Ā˟`begilnoquvxz} Āɠ`begilnoquvxz}ĀȢ^`begilnoquvxz} Ƥ`begilnoquvxz}lnoquvxz} xz}HBFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀HBFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀IABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀IABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀IABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀IABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀IABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀IABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀J=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀J=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀J=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀J=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀J=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀J=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀K;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀K;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀K;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀K;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀K;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀L9;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀L9;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀L9;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀L9;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀L9;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀L9;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀M79;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀M79;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀#79;=ABFHJLNQSUY[\`bfgimoptvxz}#79;=ABFHJLNQSUY[\`bfgimoptvxz}#79;=ABFHJLNQSUY[\`bfgimoptvxz}"79;=ABFHJLNQSUY[\`bfgimoptvxz}#579;=ABFHJLNQSUY[\`bfgimoptvxz}#579;=ABFHJLNQSUY[\`bfgimoptvxz}#579;=ABFHJLNQSUY[\`bfgimoptvxz}"579;=ABFHJLNQSUY[\`bfgimoptvxz}#2579;=ABFHJLNQSUY[\`bfgimoptvxz}#2579;=ABFHJLNQSUY[\`bfgimoptvxz}#2579;=ABFHJLNQSUY[\`bfgimoptvxz}#2579;=ABFHJLNQSUY[\`bfgimoptvxz}$/2579;=ABFHJLNQSUY[\`bfgimoptvxz}$/2579;=ABFHJLNQSUY[\`bfgimoptvxz}#/2579;=ABFHJLNQSUY[\`bfgimoptvxz}α#/2579;=ABFHJLNQSUY[\`bfgimoptvxz}ӫ$-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}&թ$-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}(Ӏ٤Q-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}ӀڢQ-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}ӀܟR*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ ݝR*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀ߛR*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀ߚR*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀ߙR*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀S)*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀S)*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀S)*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀S)*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀S)*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀S)*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀T&)*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀T&)*-/2579;=ABFHJLNQSUY[\`bfgimoptvxz}Ӏ܀݀߀fgimoptvxz}Ӏ܀݀߀gimoptvxz}Ӏ܀݀߀gimoptvxz}Ӏ܀݀߀imoptvxz}Ӏ܀݀߀ imoptvxz}Ӏ܀݀߀ moptvxz} Ӏ܀݀߀optvxz} Ӏ܀݀߀optvxz} Ӏ܀݀߀ptvxz Ӏ܀݀߀tvx Ӏ܀݀߀ Ӏ܀݀߀ Ӏ܀݀߀ Ӏ܀݀߀ Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀Ӏ܀݀߀;=ABFHJLӀ܀݀߀ "&)*-/2579;=ABFHJLNӀ܀݀߀  "&)*-/2579;=ABFHJL Ӏ܀݀߀ "&)*-/2579;=ABFHJ Ӏ܀݀߀ "&)*-/2579;=ABFHJ Ӏ܀݀߀ "&)*-/2579;=ABFH Ӏ܀݀߀ "&)*-/2579;=ABF Ӏ܀݀߀ "&)*-/2579;=AB Ӏ܀݀߀ "&)*-/2579;=AB Ӏ܀݀߀ "&)*-/2579;=AӀ܀݀߀ "&)*-/2579;=Ӏ܀݀߀ "&)*-/2579;Ӏ܀݀߀ "&)*-/2579Ӏ܀݀߀ "&)*-/2579Ӏ܀݀߀&)*-/257Ӏ܀݀߀)*-/25}Ӏ܀݀߀)*-/2}Ӏ܀݀߀-/2z}Ӏ܀݀߀/z}Ӏ܀݀߀xz}Ӏ܀݀߀ vxz}Ӏ܀݀ tvxz}Ӏ܀݀ tvxz} Ӏ܀݀ߙ ptvxz} Ӏ܀ߚoptvxz} Ӏ܀ݛmoptvxz} Ӏݜmoptvxz} Ӏܜimoptvxz} Ӏڟgimoptvxz} Ӏ٠gimoptvxz}Ӏעfgimoptvxz} դgimoptvxz}Чtvxz}Ψ t8mk@xflr5-6.09-06/mac/copybundle000755 001750 000144 00000000257 12246405674 017136 0ustar00techwinderusers000000 000000 #!/bin/sh if [ ! -e XFLR5.app/Contents/MacOS/translations ] then mkdir XFLR5.app/Contents/MacOS/translations fi cp translations/*.qm XFLR5.app/Contents/MacOS/translations xflr5-6.09-06/mac/makedist000755 001750 000144 00000001247 12246405674 016573 0ustar00techwinderusers000000 000000 #!/bin/sh #set -x if [ ! -d mac_release ]; then mkdir mac_release fi if [ -d mac_release/XFLR5 ]; then rm -rf mac_release/XFLR5 fi if [ -z "${QT_HOME}" ]; then QT_HOME=~/QtSDK/Desktop/Qt/4.6.3/gcc fi mkdir mac_release/XFLR5 #rm -r mac_release/XFLR5/* cp -r XFLR5.app mac_release/XFLR5/ $QT_HOME/bin/macdeployqt mac_release/XFLR5/XFLR5.app cp License.txt mac_release/XFLR5/ cp ReadMe.txt mac_release/XFLR5/ cp doc/ReleaseNotes.txt mac_release/XFLR5/ cp doc/Guidelines.pdf mac_release/XFLR5/ if [ -f mac_release/XFLR5.dmg ]; then rm mac_release/XFLR5.dmg fi hdiutil create mac_release/XFLR5.dmg -srcfolder mac_release/XFLR5 hdiutil internet-enable -yes mac_release/XFLR5.dmg xflr5-6.09-06/mac/Info.plist000755 001750 000144 00000007444 12246405674 017024 0ustar00techwinderusers000000 000000 CFBundleDisplayName XFLR5 CFBundleDocumentTypes CFBundleTypeExtensions wpa WPA CFBundleTypeName XFLR5 Project CFBundleTypeRole Editor LSItemContentTypes wpa.xflr5.sourceforge.net LSIsAppleDefaultForType CFBundleTypeExtensions plr PLR CFBundleTypeName XFLR5 Polar File CFBundleTypeRole Editor LSItemContentTypes plr.xflr5.sourceforge.net LSIsAppleDefaultForType UTExportedTypeDeclarations UTTypeIdentifier wpa.xflr5.sourceforge.net UTTypeDescription XFLR5 Project UTTypeConformsTo public.data UTTypeTagSpecification public.filename-extension wpa WPA UTTypeIdentifier plr.xflr5.sourceforge.net UTTypeDescription XFLR5 Polar File UTTypeConformsTo public.data UTTypeTagSpecification public.filename-extension plr PLR CFBundleIconFile xflr5.icns CFBundleIdentifier xflr5.sourceforge.net CFBundleName XFLR5 CFBundlePackageType APPL CFBundleShortVersionString 6.09 CFBundleSignature XFLR CFBundleInfoDictionaryVersion 6.0 CFBundleVersion 574 xflr5-6.09-06/doc/000755 001750 000144 00000000000 12250656141 015035 5ustar00techwinderusers000000 000000 xflr5-6.09-06/doc/latex/000755 001750 000144 00000000000 12246405674 016162 5ustar00techwinderusers000000 000000 xflr5-6.09-06/doc/latex/readme.txt000644 001750 000144 00000002047 12246405674 020163 0ustar00techwinderusers000000 000000 *** About *** This latex version of the guidelines has been initiated from the Guidelines_v604.odt found in the xflr5-6.09-04-svn branch. The initial tex import has been made with w2l (OpenOffice or LibreOffice writer2latex). Then it has been edited to be more human readable. This is not an official version yet. *** Compilation *** The compilation has been tested with the texlive distribution (http://www.tug.org/texlive/) under Windows and GNU/Linux/Ubuntu. Old tetex distribution don't handle correctly the png transparency. The compilation needs three pass to succeed (generation of layout+references). There is a sample makefile for unix systems. *** Edition *** The texlive distribution include a tex editor. Most of my colleague use texmaker under Windows. I personnaly use emacs+auctex under GNU/Linux. Setup your editor with automatic filling at 80. *** TODO *** This document doesn't replace the official Guidelines.odt yet. Indeed, it needs some improvements : - homogeneisation of symbols typo. - check references, and credits - ... xflr5-6.09-06/doc/latex/guidelines_en.tex000644 001750 000144 00000365157 12246405674 021537 0ustar00techwinderusers000000 000000 %-----CLASS LOADING------------------- \ifx\pdfoutput\undefined \documentclass[a4paper,twoside,12pt,dvips]{article} \else \documentclass[a4paper,twoside,12pt,pdftex]{article} \fi %-----INPUT ENCODING----------------- \usepackage[utf8]{inputenc} %-----LANGUAGE SELECTION------------- \usepackage[english]{babel} %-----PACKAGES SELECTION------------- \usepackage{graphicx,color,hyperref,amsmath,fancyhdr,keystroke} \usepackage{tabularx,multirow,rotating} \graphicspath{{figures/}} %-----CONFIG HYPERREF----------------- \definecolor{rltred}{rgb}{0.75,0,0} \definecolor{rltgreen}{rgb}{0,0.25,0} \definecolor{rltblue}{rgb}{0,0,0.75} \hypersetup{colorlinks=true, urlcolor=rltblue, % \href{...}{...} external (URL) filecolor=rltgreen, % \href{...} local file linkcolor=rltred, % \ref{...} and \pageref{...} citecolor=rltblue, % \cite{} bookmarks = true, % Signets bookmarksnumbered = true, % Signets numerotes pdfpagemode = UseOutlines, % Signets/vignettes ferme a l'ouverture pdfstartview = FitV, % La page prend toute la largeur pdfpagelayout = OneColumn, % Vue par page pdfborder = {0 0 0}, % Style de bordure : ici, pas de bordure pdftitle = {XFLR5 v6.02 Guidelines}, pdfauthor = {}, pdfsubject = {XFLR5 v6.02 Guidelines}, pdfkeywords = {xflr5 guidelines} } %-----PAGE LAYOUT--------------------- % http://www.ctan.org/tex-archive/macros/latex/contrib/fancyhdr/fancyhdr.pdf % http://amath.colorado.edu/documentation/LaTeX/reference/layout.html % Lot of other ressources about Latex page layout on the web ... %-header and footer- \pagestyle{fancy} \rhead[~]{~} \chead[~]{~} \lhead[{\small XFLR5 v6.02 Guidelines}]{~} \lfoot[\textbf{\thepage}]{~} \cfoot[~]{~} \rfoot[\today]{ \textbf{\thepage} } \renewcommand{\headrulewidth}{0.2pt} \renewcommand{\footrulewidth}{0.2pt} %-margins- A4 = 297 x 210 mm = 11.7 x 8.3 inches (1in~2.2cm) \setlength{\hoffset}{0in} \setlength{\oddsidemargin}{0in} \setlength{\evensidemargin}{0in} \setlength{\textwidth}{6.3in} % 6.3in (16cm) (1in on each side) \setlength{\linewidth}{\textwidth} \setlength{\headwidth}{\textwidth} \setlength{\voffset}{-0.75in} \setlength{\topmargin}{0in} \setlength{\headheight}{0.5in} \setlength{\headsep}{0.25in} \setlength{\textheight}{9.7in} % 9.7in (22cm) (1in on the top and bottom) \setlength{\footskip}{0.75in} %-paragraphs \setlength{\parindent}{0in} %\renewcommand{\baselinestretch}{1.1} %\setlength{\parskip}{0.2\baselineskip} % 8<-----DOCUMENT------------------------ \begin{document} % 8<--------------------------------------------------------------------------- \title{ \includegraphics[width=0.8\linewidth]{img-01}\\ Analysis of foils and wings\\ operating at low Reynolds numbers} \author{} \date{28/02/2013} \maketitle \clearpage % 8<--------------------------------------------------------------------------- \tableofcontents \clearpage % 8<--------------------------------------------------------------------------- \section{Purpose} This document is not intended as a formal help manual, but rather as an aid in using XFLR5. Its purpose is to explain the methods used in the calculations, and to provide assistance for the less intuitive aspects of the software. % 8<--------------------------------------------------------------------------- \section{Introduction} \subsection{Code limitations and domain of validity} Like the original XFoil, this project has been developed and released in accordance with the principles of the GPL. Among other things, one important point about GPL is that : \begin{quotation} 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 General Public License for more details. \end{quotation} The code has been intended and written exclusively for the design of model sailplanes, for which it gives reasonable and consistent results. The code's use for all other purpose, especially for the design of real size aircraft is strongly disapproved. \subsection{XFLR5's development history} The primary purposes for the development of XFLR5 were to provide : \begin{itemize} \item A user-friendly interface for XFoil \item A translation of the original FORTRAN source code to the C/C++ language, for all developers who might have a need for it \end{itemize} This was done in accordance with, and in the spirit of, Mark Drela's and Harold Youngren's highly valuable work, which they have been kind enough to provide free of use under the General Public License. The resulting software is not intended as a professional product, and thus it does not offer any guarantees of robustness, accuracy or product support. It is merely a personal use application, developed as a hobby, and provided under GPL rules for use by all. For this reason, it should be noted and understood that XFLR5 may not be default-free. Some significant bugs affecting result precision have been reported in the beta releases and corrected.\newline However, XFLR5 has been thoroughly tested against other software and published experimental results, up to now with some success, and this permits a limited amount of trust in the results it provides. The algorithms for foil analysis implemented in XFLR5 are exactly the same as those of the original XFoil code, except for the translation from FORTRAN to C. No changes nor amendments have been made. The translation in itself could have caused new bugs. However, the code has been thoroughly tested against numerous original XFoil analyses, always with consistent results. It may be found, in some cases, that one of the two programs may not converge where the other will, or that the path to convergence is different from one to the other. This is due to the different manner in which floating point numbers and calculations are processed by the two compilers. Having said this, the converged results are always close, and any differences within the convergence criteria set in the XFoil source code.\newline Hence, both XFoil and XFLR5 results of airfoil analysis will be referred to herein as "XFoil results". Wing analysis capabilities have been added in version 2.00. Initially, this was done at the suggestion of Matthieu Scherrer, who has experimented with his Mathlab "Miarex" code the application of the Non-linear Lifting Line Theory (herein referred to as "LLT") to the design of wings operating at low Reynolds numbers. Later on, the necessity arose to add the Vortex Lattice Method (herein referred to as "VLM") for the design and analysis of wings with geometries not consistent with the limitations of the LLT. Version v3.00 introduced Katz and Plotkin's recommended VLM method based on quadrilateral rings, and the VLM calculation of planes with elevator and fin. On March 31\textsuperscript{st}, 2007, XFLR5 has become an Open Source Development Project hosted by Sourceforge.net. Version v4.00 introduces a 3D panel method for wings and planes, including modeling options for fuselages. Up to this last version, XFLR5 has been developed specifically for Windows, using Microsoft's MFC libraries. This is a limitation of the product, making it non available for Unix, Linux, and MAC systems. It has therefore been decided to re-write the code using the cross-platform Qt4 libraries provided by Nokia. This version has been released as XFLR5 v5. It does not offer any new functionality compared to the original code. Released in a beta version in September 2010, XFLR5 v6 introduces the stability and control analysis, and a modification of the 3D-panel method for the plane. \subsection{Changes introduced in XFLR5 v6} \subsubsection{Problem size} The maximum acceptable size for mesh definitions has been increased from 2000 panels to 5000 panels max. Since the memory allocation increases as the square power of the problem size, this new version will reserve more memory at the program launch, and may take longer to start on those computer with low RAM. \subsubsection{Stability and control analysis} "Control polars" have been replaced by "stability polars", with evaluation of stability and control derivatives. \subsubsection{Batch calculations} It is now possible to run a batch calculations for a list of airfoils. \subsubsection{3D panel method} The 3D panel method is now processed differently for single wings and for planes. For the analysis of single wings, the full 3D method is available as in v5, with the wings represented as thick surfaces with uniform doublet and source distribution. For planes, the full 3D method has been replaced in v6 by a mix formulation of 3D panels for the fuselage, and thin surfaces for the wings. \subsubsection{Inertia estimations} In the inertia evaluation of wings, the mass of each strip is distributed along the strip proportionally to the foils thickness, and is no longer concentrated at the quarter-chord position. \subsection{Code structure} Five different "Applications" have been implemented : \begin{itemize} \item Two direct design modes which are convenient to compare foils, and to design new foils with the use of B-Splines \item The mixed inverse (QDES) and the full inverse (MDES) foil design routines, virtually unchanged from the original \item The foil direct analysis routines (OPER) \item The wing, plane and body design and analysis \end{itemize} \clearpage % 8<--------------------------------------------------------------------------- \section{Foil Analysis and Design Modes} \subsection{General} This part of the code is built around XFoil and its main features, i.e. the design routines, and the direct and inverse analysis (OPER, MDES, GDES, and QDES). Except for the implementation of the Windows interface, no special feature has been added to these modules. To run and use XFLR5, no special knowledge nor any previous experience of XFoil is necessary, although users accustomed to XFoil should have no difficulty in recognizing the new Windows-style menu options. Since the analysis engine is very much unchanged from the original, users are advised to refer to the original XFoil help to understand the purpose, operation, and limitations of the foil direct and inverse analysis. Their use in XFLR5 is basically the same, with a limited number of necessary adaptations for the Windows interface. \subsection{Direct Analysis [Oper]} \subsubsection{Foil object} \paragraph{Foil Database} Foils are loaded from standard foil files and are stored in a runtime database. Any number of foils may be loaded at any time. \paragraph{File format} XFLR5 recognizes only the plain traditional format for foils, i.e. files which contain the foil's name on the first line, followed by the X,Y coordinates, which run from the trailing edge, round the leading edge, back to the trailing edge in either direction: \begin{verbatim} Foil Name X(1) Y(1) X(2) Y(2) . . . . X(N) Y(N) \end{verbatim} All lines containing a \texttt{\#} character are ignored.\newline No special checks are performed on the input geometry. Users are advised to check the file format if the foil is not read properly by XFLR5. \subsubsection{Foil Modification} XFLR5 provides the same options for foil modification as the original XFoil code. These are: \begin{itemize} \item local and global refinement \item modification of the thickness, camber, max thickness and max camber positions. \end{itemize} The modification of these parameters will cause a new foil to be generated. Whenever a foil is modified, deleted or overwritten, all its associated results are deleted to ensure consistency. Experience shows, and XFoil advises, that refinement of the foil's panels, after it has been loaded or modified, is usually a prudent measure to take before any analysis. \subsubsection{Analysis/Polar object} Unlike XFoil, an analysis of a given foil may be performed only after a "polar object" has been defined and associated to this foil. The results of the analysis will automatically be associated and added to the polar object. Any number of polars may be created and associated to a given foil. A polar object is defined by: \begin{itemize} \item its Type \item its Reynolds and Mach numbers \item the laminar to turbulent transition criterion \item the forced trip locations on top and bottom surfaces \end{itemize} By default, the transition number is set to 9, and the trip locations are set at the trailing edge. In addition to the Type 1, 2 and 3 polars which are unchanged from XFoil, Type 4 polars have been introduced, showing data for a given angle of attack at variable Re. The purpose is to enable determination of the critical Re value. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-02}\centering \caption{Type 1 foil polars} \label{fig:type_1_foil_polars} \end{figure} \subsubsection{Operating Point (OpPoint) object} An operating point of a given foil is defined by its angle of attack and its Re number. Always associated to a foil and to a Polar object, the OpPoint stores the inviscid and viscous results of the analysis. Any number of OpPoints may be stored in the runtime database, the only limitation being computer memory. OpPoints may use significant memory resources. To insure consistency, any modification to the foil or to the polar causes the operating point to be deleted from the database. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-03}\centering \caption{$C_p$ calculation} \label{fig:c_p_calculation} \end{figure} \subsubsection{XFoil analysis} Each time an XFoil direct analysis is performed and the convergence is achieved, an OpPoint is generated and the values of interest are stored in the currently selected polar object. Data is added to the polar, whether the option to store OpPoints has been activated or not. An XFoil calculation performed at the same angle of attack and Re as an existing OpPoint causes the latter to be replaced, and the polar data to be updated. The "Init BL" checkbox is the equivalent of the "Init" menu command in XFoil, i.e., it resets the boundary layer to standard values before an analysis. It is recommended to check the box at the time of the first calculation, and whenever the analysis of an OpPoint is unconverged or is very different from the previous one. In the case of sequential analysis, the "Init BL" is automatically deactivated after a first converged point has been reached, and is reset after an unconverged calculation. \subsubsection{XFoil errors} Given the complexity and difficulty of a viscous analysis, XFoil is remarkably robust and consistent. It may happen however that the following error message is generated during an analysis. \begin{figure}[htbp] \includegraphics[width=0.4\linewidth]{img-04}\centering \caption{XFoil Error Message} \label{fig:xfoil_error_message} \end{figure} This error message is usually caused by a too coarse paneling of the foil, or a too sharp leading edge. It is possible that in such a case XFoil gets "stuck" and fails at any attempt to perform a new analysis. The menu command "Operating Point/Reset XFoil" can be used to reinitialize all the variables and reset the currently selected foils and polars. \subsubsection{Session example Direct Analysis} \begin{enumerate} \item Load a foil from a file \item (Optional) Use the "Derotate" and "Normalize" commands to respectively align the mean chord with the x-axis and to set its length to 1. \item (Optional) Use the "Refine Locally" or "Refine Globally" commands to optimize the foil's panels \item Use the "Define Analysis/Polar" command in the Polar menu, or \keystroke{F6}, to define an analysis -- for instance a Type 1 analysis at $Re \approx 100000$ and $Mach = 0.0$ \item Define an angle of attack or a lift coefficient to analyze -- for instance $\alpha = 0^\circ$ \item Click on the "Analyze" button in the right toolbar to launch an analysis \item If the XFoil analysis has converged, the $C_p$ distribution will be displayed automatically \item Check the "Show BL" or "Show Pressure" buttons to visualize either distribution \item Check the "Sequence" button in the right toolbar \item Define the min and max angles for the analysis -- for instance from $\alpha = -6^\circ$ to $\alpha = 10^\circ$ \item Since the new start value is significantly different from the last calculation (i.e. $\alpha = 0^\circ$), check the "Init BLs" button \item Click on the "Analyze" button \item Click on the "Animate" button to visualize modifications of the boundary layer or pressure distributions with angle of attack variations \item Click on the "Polars" command in the View menu, or type \keystroke{F8} \item Use the mouse button and wheel to drag and zoom the graphs \end{enumerate} \subsection{Full Inverse Design [MDES] and Mixed Inverse Design [QDES]} \subsubsection{General} Both design modes are unchanged from the original. Foils generated by the Full Inverse method are defined by 255 coordinate points, which is excessive for subsequent Direct Analysis. A re-paneling of the foil is strongly recommended. Although foils generated by the Mixed Inverse Method have the same number of panels as the original foil, a re-panel is still advisable. \subsubsection{Session example -- Full Inverse Design} \begin{enumerate} \item Switch to the Full Inverse Application (Menu command or \Ctrl + \keystroke{3}) \item Select a foil from the loaded database, or load a foil from a file \item Click on the "New Spline" button in the right toolbar dialog \item Select two points either on the upper or lower surface, but not one on each \item Drag the spline's control points to define a new speed distribution \item Click on the "Apply" button to register the change \item Click on the "Execute" button to calculate the new foil geometry \item Use the mouse buttons and wheel to drag and zoom the graph and the foil \item Repeat the process until the desired geometry is reached \item To store the modified foil, click on the arrow in the top toolbar, or select "Store foil in the database" in the Foil menu \item Switch to the Direct Analysis Application (Menu or \Ctrl + \keystroke{5}) \item Use "Refine globally" in the Design menu to generate a coarser panel \item Proceed with the direct analysis \end{enumerate} \subsubsection{Session example -- Mixed Inverse Design} Steps 1 to 6 are identical to the Full Inverse design method \begin{enumerate} \setcounter{enumi}{6} \item Click on the "Mark for Modification" button to define which part of the foil is to be modified \item Click on the "Execute" button to calculate the new foil geometry \item Check for convergence in the text window\newline In the case of non-convergence, it is possible either to resume iterations by clicking again the "Execute" button, or to export the modified geometry as it is \end{enumerate} Finish as with the Full Inverse design method. \subsection{Foil Direct Design} \subsubsection{General} A crude design module has been included in XFLR5, which allows the design of Foils either from B-Splines or from "Splined Points". The former gives smoother surfaces, the latter authorizes greater control over the geometry. This design mode however is not the best way to design foils, and the other possibilities derived from XFoil are far more adapted and recommended i.e. : \begin{itemize} \item modification of a foil's thickness and camber \item interpolation of foils \item inverse methods \end{itemize} This foil design mode, however, may be useful to overlay different foils and compare their geometries. An option has been added in v6 to load a background image, with the idea of digitalizing existing foils. \subsubsection{B-splines main features} Upper and lower surfaces are each determined by a separate and single B-Spline. Spline degree can be set between 2 and 5. \subsubsection{Spline Points main features} Upper and lower surfaces are each determined by a set of control points Control points are linked by 3rd degree B-Splines Two intermediate control points are added to the link splines, at 1/3 and 2/3 respectively of the separation of the two control points. These two points are added automatically and are not visible, nor can they be modified. The slope at each visible control point is determined by the line passing through the immediately previous and next control points. \subsubsection{Leading and trailing edge} For both methods, the slope at the leading edge is vertical and may not be changed. In the case of a design from B-Splines, this is done by forcing the second control point to remain on the vertical axis. \newline In the case of "Splined Points" the slope at the trailing edge is determined by the position of two supplementary rear points, one for each surface. \subsubsection{Output precision} The maximum number of output points on each surface is 150. This is consistent with the sizing of the XFoil arrays, and with the precision required for the application, although the increase of computing power and memory capacity of modern computers could allow for more points. Typically, XFoil requires at least 50 points on each side to perform an adequate analysis.\newline In both cases, it is prudent to "re-panel" the foil in the main menu, to improve the convergence of the XFoil analysis and its precision. This can be done with the equivalent of XFoil's "PANE" and "CADD" commands. \newline Upon exit from the design module, the user is asked whether to export or not the foil to the analysis module. \subsubsection{Digitalization} An option has been added in v6.02 to load a background image. The purpose is to enable digitialization of existing foil images using splines. After digitalization, the splines should be stored as a foil in the database, and the foil ought to be normalized, de-rotated and re-paneled. \section{3D Analysis} \subsection{Wind and body axis, sign conventions} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-05}\centering \caption{Wind and Body axis} \label{fig:wind_and_body_axis} \end{figure} The lift and drag coefficients are given in wind axis. \underline{Notes} \begin{itemize} \item Up to v3.21, calculations have been performed using a small angles approximation, which means that the wind and body axis were the same. \item Sign Conventions for moments -- Quote from Wikipedia, Flight Dynamics : \begin{quotation} The most common aeronautical convention defines the roll as acting about the longitudinal axis, positive with the starboard wing down. The yaw is about the vertical body axis, positive with the nose to starboard. Pitch is about an axis perpendicular to the longitudinal plane of symmetry, positive nose up. \end{quotation} \end{itemize} This is illustrated in the Figure~\ref{fig:moment_sign_convention}. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-06}\centering \caption{Moment sign convention} \label{fig:moment_sign_convention} \end{figure} \subsection{Object Definition} \subsubsection{Wing Definition} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-07}\centering \caption{Wing Definition} \label{fig:wing_definition} \end{figure} The wing is defined as a set of panels. Each panel is defined by : \begin{itemize} \item its length $l_i$, \item the root and tip chords $c_i$ and $c_{i+1}$, \item the leading edge offset at root and tip chords $h_i$ and $h_{i+1}$, \item the dihedral angle $\delta_\iota$, \item the mesh for VLM analysis. \end{itemize} The spanwise length of a panel should be at least equal to the minimum length of the VLM elements on other panels. Divisions by zero or non-physical results could result from panels of insufficient length. Twist (washout) is processed in LLT as a modification of the angle of attack. In VLM, the twist is processed as a modification of the wing, with the rotation center located at the quarter chord point.\newline Up to v3.04, the twist has been applied as a rotation of the sections with respect to the absolute y axis. From v 3.05 onwards, the sections are rotated with respect to the panel's quarter chord, i.e., after the panel has been rotated by the dihedral angle. The results are impacted for wings with panels well off the x-y plane. The 'span' of the wing is defined as \[S = 2 \times \sum l_i\] For ease of interpretation, the wing is shown developed on a horizontal planform, both in the wing design dialog box and in the 2D view. Only the 3D view gives a realistic representation of the geometry. A wing may be asymmetric if the foils are different on each side. This option is meant to provide some capability to evaluate the influence of flaps, but should be used with caution. It has been tested neither against experimental nor theoretical results. \subsubsection{Reference area for aerodynamic coefficients} The reference area for all wing and plane aerodynamic coefficients is the main wing's area. In the case of a bi-plane, the reference area is also the main wing's area. There reference lengths for moment coefficients are defined in \S\ref{sec:moments}. \underline{Notes} : \begin{itemize} \item Up to v.4.15, the reference area and the reference span have been defined as the planform's area and span. With this convention, the winglets' contribution are counted in the area and in the span. This is not necessarily the best choice, since it is usually convenient to compare performance coefficients of a wing with and without winglets, but with a constant reference area. \item Starting in v4.16, the default option is to use the planform area and span projected on the xy plane. With this definition, the contribution of the winglets to span and area is zero. For convenience, it is still possible to choose either reference area; the option can be set in the dialog box for analysis definition. \end{itemize} \subsubsection{Flaps} From version v3.16 onwards, the automatic mesh methods takes into account the breaks at the flap position, if both foils at each end of the wing panel are defined with a flap. The recommended way to create a flap is to define two foils at the same spanwise position, the first with a flap break, the other without. The code will ignore the zero-length panel. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-08}\centering \caption{Flap Definition} \label{fig:flap_definition} \end{figure} Triangular flaps, defined by a plain foil at one side of the panel and by a flap break at the other side, are not recognized. The flaps are counted as one for each wing side, e.g. ailerons are counted as two flaps. This is necessary to calculate separately hinge moments for asymmetrical wings. \subsubsection{Body Design} The modeling of the body is natural in a 3D panel method, but isn't either without difficulties. \paragraph{Modeling options} Two options are provided, for two different purposes : \begin{enumerate} \item Representation by flat panels : this is the "Analysis" purpose. \newline Given an existing body, the idea is to digitalize its geometry and input it in XFLR5. The resulting geometry will not be smooth, but it is usually enough for prediction pruposes \item Representation by B-Splines : this is the "Design" purpose. \newline The idea is to define and optimize a body geometry to achieve some targeted aerodynamic (or cosmetic) performance. The body points can then be exported to a text file for further use. \end{enumerate} \paragraph{Import/export of body data} To facilitate the edition process, the control points can be edited in a text file and imported in XFLR5, rather than being defined directly in XFLR5. An example of the format of the input file can be obtained by exporting any existing body definition. A typical format is : \begin{verbatim} Body_Name ... FRAME x_1 y_2 z_1 ... x_n y_n z_n OFFSET X_o Y_o Z_o BODYTYPE 1 or 2 \end{verbatim} \underline{Notes} : \begin{itemize} \item The keywords should be preceded by the character '\#'. \item n is the number of side point definining the frame. This number must be the same for all frame. If the frames are defined with different numbers of points, the frame last defined will set the number of points. \item The frames are sorted by x positions \item The points in the frame should be defined in clockwise order, on the body's left side, when looking at the body from the front; this is the view which is displayed in the right panel in the body design module. \item All points in a frame should have the same axial position \item The x position of a frame is defined by the first point \end{itemize} \subsubsection{Plane Definition} A plane consists in a main wing, and optionally of a secondary wing, an elevator, one or two fins, and a body. The body may be described either by cross-sections located at different streamwise locations or by NURBS surfaces. \paragraph[Surface assemblies]{Surface assemblies} The main difficulty with the construction of a 3D plane model is to connect the wing, elevator, fin and body together. Without the help of a CAD system, it has been difficult to implement a versatile and robust algorithm, mainly because of the number of configurations to consider. For instance, the elevator may or may not intersect the body, it may or may not intersect the fin, it may intersect the body only on its bottom or upper surface, etc. The only surface verification implemented in V4.00 is a trim of the wings, elevator and fin to the body's surface, and even then, the algorithm may not be robust for all configurations. What's more, even if the wings, elevator and fin are trimmed to the fuselage surface, the body's panels are not adapted to follow their contour. This implies that some of the body's panels will be located inside the volume, which is not consistent with the panel theory. \paragraph{Tip Patches} The Panel Theory requires that the volume on which the analysis is performed is completely closed by the surfaces which support the panels. In other words, a body or a wing cannot have an open end, in which case a numerical error will occur. To try to close the volumes, the code will automatically create tip patches in the following cases : \begin{itemize} \item Left tip of the left wing, and right tip of the right wing \item Top and bottom tips of fins \end{itemize} It will not create patches in the following cases : \begin{itemize} \item Gap at the center of the wing, i.e. if the first chord is located at a positive span position \item Junction of the wing and fuselage \end{itemize} \underline{Note} : the influence of these modeling errors on the results is unknown. \subsubsection{Inertia estimations} A calculation form is available to provide an approximate evaluation for the CoG position and for the inertia tensor associated to the geometry. The evaluation should not be understood as anything else than a rough order of magnitude. The inertia is evaluated in the default coordinate system, i.e. with respect to the CoG. The tensor in other systems can be computed by the appropriate tensor transformations. The evaluation is based on the following assumptions. \begin{itemize} \item For the body, the mass is distributed uniformly in the external surface, and this surface is assumed to have a uniform thickness. The body is divided in $N_b$ elementary sections along the x-axis. The weight is concentrated at the center of the cross section. This is illustrated in Figure~\ref{fig:mass_representation_for_the_body}. \item For the wings, the mass is assumed to be distributed uniformly in the wing volume along the span.\newline In XFLR5 v5, it has been modeled as point masses concentrated at the quarter-chord point of distributed sections along the span.\newline In XFLR5 v6, it is modeled as point masses distributed both in the span and chord directions, as illustrated in Figure~\ref{fig:mass_representation_for_the_wing}. \item The mass distribution is independent of the wing's mesh used for aerodynamic calculations \item Parts such as actuators, battery, lead, or receiver should be modeled separately as point masses. \end{itemize} \underline{Notes} : \begin{itemize} \item At this stage of the code development, the results are not used at any point in the performance calculations. The inertia evaluations are provided as a convenience for external stability analysis to be performed with codes such as AVL. \item The mass defined for wings and bodies is not the one used for Type 2 calculations. The mass for type 2 is defined with the Analysis/Polar. \end{itemize} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-09}\centering \caption{Mass representation for the body} \label{fig:mass_representation_for_the_body} \end{figure} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-10}\centering \caption{Mass representation for the wing} \label{fig:mass_representation_for_the_wing} \end{figure} \subsubsection{Mesh} The wing is "meshed" into a number of panels distributed over the span and the chord of the planform, and a vortex or a doublet and source is associated to each panel. \begin{itemize} \item The analysis may be of the VLM type and is performed on the mean camber line \item The analysis may be of the 3D-panel type in which case the wing is modeled as a thick surface \end{itemize} It is recommended to choose a panel distribution which is consistent with the wing's geometry, i.e. the density of the mesh needs to be increased at geometrical breakpoints and at the root and tip of the wings. A cosine type distribution is recommended in the chordwise direction to provide increased density at the leading and trailing edges. There is a lower limit size for the panels below which the calculation becomes unstable, or which leads to non-physical results. This can typically occur with "sine" spanwise distributions of panels. Ideally, the precision of the calculation increases with the mesh's refinement, but so do the calculation times. It is fairly simple to experiment to determine what is the best compromise for a given design objective. Numerical instability may also occur in 3D Panel analysis if a panel's lengths in the streamwise and chordwise directions are too different. The panel's aspect ratio should be kept low. It is possible to exclude from the calculations the wing panels with a spanwise length less than a minimum value. This can be set in the advanced settings dialog box. If the minimum length is set to zero, then all wing panels with length less than 1/1000 of the span will be excluded. This is meant to avoid numerical errors linked to small mesh elements. Panel Methods : \begin{enumerate} \item The current implementation uses flat 1\textsuperscript{st} order panels.\newline Ideally, these kind of panels need to have their four corners in the same plane, which is not possible for twisted geometries. However, this is not seen as a major issue for the low washout angles used for model sailplane wings. \item The surface velocity is the gradient of the doublet strengths between adjacent panels as described in \cite{Maskew}. It is therefore recommended to have the same number of chordwise panels along the span, and the same type of distribution, either uniform or sine.\newline Ideally, the panels should share the same edges and corner nodes. In the case of a flap, the 'trick' to connect properly the panels is to define a foil with a false flap set at $0^\circ$ flap angle, as is illustrated in Figure~\ref{fig:mesh_disposition_for_a_flap}. \end{enumerate} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-11}\centering \caption{Mesh disposition for a flap} \label{fig:mesh_disposition_for_a_flap} \end{figure} \paragraph{Panel arrangement - VLM analysis} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-12}\centering \caption{VLM Panel arrangement for a plane} \label{fig:vlm_panel_arrangement_for_a_plane} \end{figure} Special care must be taken in the disposition of VLM panels to avoid having a control point of the tail's surface close to the trailing leg of one of the wing's horseshoe vortex. This would lead to a division by zero, and inconsistent results. One method to avoid this issue is to have the wing's panels aligned with those of the elevator. For the same reason, it is a good idea, though not compulsory, to position fins in the planes of the wing's panel junctions. \paragraph{Panel arrangement - 3D panel analysis} \subparagraph{Chordwise panels} The Cp distribution is calculated as the derivative of the doublet strength along the panel chordwise and spanwise strips.To achieve this, it is required that each wing has a uniform number of chordwise mesh panels along the span. It is also recommended that the chordwise panel distribution be the same from one wing panel to the next, i.e. cosine distribution for each wing panel. This is necessary to connect adequately the mesh panels at junctions between wing panels. Mesh panels located in flaps are not connected to the adjacent wing panel. The remaining connections at the junction are performed using the method described in \cite{Maskew}. \subparagraph{Wake Panels} In the VLM method, the wake is represented by the trailing legs of the horseshoe vortices. In the 3D-panel method, the wake is modeled as a series of flat panels which extend 'far behind' the wing.\newline The idea is that each of the wing's chordwise strip sheds a column of wake panels. The doublet strength of each panel in this wake strip is the difference of the doublet strength of the top and bottom panels of the wing's strip. This is a consequence of the fact that the wake cannot sustain load. In addition, being a thin surface, the wake panels have a zero source strength. The wake strips are modeled as a column of thin panels. In the simplest form, these wake panels are straight aligned behind the wing panels, as illustrated in Figure~\ref{fig:straight_wake}. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-13}\centering \caption{Straight wake} \label{fig:straight_wake} \end{figure} In a more refined and realistic implementation, the wake is aligned with the streamlines which trail behind the wing. Since the doublet distribution on the wing, and the streamlines, in turn depend on the wake shape, an iteration process is required to reach a converged state. This is usually referred to as the"wake relaxation process". The wake relaxation is a difficult process which can easily diverge. Numerical experimentations in XFLR5 have shown that the wake panels are highly warped at the wing tips where the wake strongly rolls up on itself. The convergence requires close control by the user of key parameters such as number of wake panels, length of wake panels or time steps. For these reasons, the wake roll-up process has been disabled. The wake panels are therefore defined as flat panels which extend behind the wings trailing edges. Their length is 100 x MAC. At this distance, the influence of the plane's panels is negligible. A difficulty arises whenever one of the straight wake panels shed by a surface such as the wing, goes through another surface such as the elevator, as illustrated in Figure~\ref{fig:wake_interference_between_wing_and_elevator}a. This will lead to unrealistic, non physical results. In such a situation, it is necessary to modify slightly the geometry to avoid the interference Figure~\ref{fig:wake_interference_between_wing_and_elevator}b. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-14}\centering \caption{a \& b : Wake Interference between wing and elevator} \label{fig:wake_interference_between_wing_and_elevator} \end{figure} \subsubsection{Symmetry} \label{sec:symmetry} A symmetric calculation reduces the matrix's size by approximately half (exception is the fin), and reduces the matrix inversion operations by a factor 4. The code detects automatically whether the problem is symmetric or not. It is considered to be symmetric in the following cases : \begin{itemize} \item The wing is symmetric in a Wing-only calculation \item The plane is symmetric without a fin, or with a double fin \end{itemize} The problem is asymmetric otherwise : \begin{itemize} \item if any of the wings, elevator or fin is asymmetric \item if the plane has a fin \end{itemize} \subsection{Performance analysis} \subsubsection{Theory - General} XFoil provides unique insight in the behavior of airfoils, but is a 2D analysis, hence the results are those of a wing of infinite aspect ratio and which is defined with a single airfoil. The influence that the aspect ratio alone may have on the wing's polars, let alone the sweep or the dihedral, justifies the need for a more sophisticated wing analysis. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-15}\centering \caption{Influence of Aspect Ratio - LLT Calculation NACA 3412 Airfoil - Taper Ratio = 1 - Sweep = $0^\circ$} \label{fig:influence_of_aspect_ratio} \end{figure} The wing may be computed by either one of three methods, each having its own advantages, and all having some usage restrictions. \newline The first is a Lifting Line method, derived from Prandtl's wing theory. The second is a Vortex Lattice method. The third is a 3D panel method.\newline The originality of the implementations is their coupling with XFoil calculation results to estimate the viscous drag associated with the wing, although this is done in a different manner depending on the method. \subsubsection{Viscous and inviscid calculations} In VLM and panel methods, an inviscid analysis/polar may be defined, in which case there is no need to define a polar mesh for the foils. The viscous characteristics will be set to zero. The LLT is necessarily viscous. \subsubsection{Lifting Line Theory (LLT) - Non Linear} \paragraph{General} The 'classic' LLT is linear, i.e. the relation $C_l = f(\alpha)$ is linear, and viscous effects are not taken into account. In the present application, a non-linear LLT has been implemented based on the NACA technical note 1269 \cite{Sivells47}. Quote from Technical Note 1269 : \begin{quotation} The hypothesis upon which the theory is based is that a lifting wing can be replaced by a lifting line and that the incremental vortices shed along the span trail behind the wing in straight lines in the direction of the freestream velocity. The strength of these trailing vortices is proportional to the rate of change of the lift along the span. The trailing vortices induce a velocity normal to the direction of the free-stream velocity. The effective angle of attack of each section of the wing is therefore different from the geometric angle of attack by the amount of the angle (called the induced angle of attack) whose tangent is the ratio of the value of the induced velocity to the value of the freestream velocity. The effective angle of attack is thus related to the lift distribution through the induced angle of attack. In addition, the effective angle of attack is related to the section lift coefficient according to two-dimensional data for the airfoil sections incorporated to the wing. Both relationships must be simultaneously satisfied in the calculation of the lift distribution of the wing. If the section lift curves are linear, these relationships may be expressed by a single equation which can be solved analytically. In general however, the section lift curves are not linear, particularly at high angles of attack, and analytical solutions are not feasible. The method of calculating the spanwise lift distribution using non-linear section lift data thus becomes one of making successive approximations of the lift distribution until one is found that simultaneously satisfies the aforementioned relationships. \end{quotation} The present implementation, the non linear lift behavior is interpolated on pre-generated meshes of XFoil Type 1 polars and the non-linearity is solved by an iteration loop : \begin{figure}[htbp] \includegraphics[width=0.5\linewidth]{dia-01}\centering \end{figure} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-16}\centering \caption{Induced Angle -- Bi-Airfoil NACA3412-NACA1410 -- AR = 14.8 -- TR = 2.0 -- $Alfa = 5^\circ$ - V= 16.7m/s} \label{fig:induced_angle} \end{figure} \paragraph{Limitations of the LLT} It is important to note that the lifting line theory has two main limitations. Quote from Technical Note 1269 \cite{Sivells47} : \begin{quotation} The calculations are subject to the limitations of lifting line theory and should not be expected to give accurate results for wings of low aspect ratio and large amounts of sweep \end{quotation} In addition, the wing's planform is expected to lie essentially in the X-Y plane, i.e. with low dihedral. \paragraph{Precautions with the LLT} As it turns out, the convergence of the non-linear LLT is not a robust process, and requires careful use of a relaxation factor. This factor should always be greater than 1. A value of 20 is usually a good start, and may be increased as necessary for convergence. \newline Usually wings with low aspect ratio require high relaxation value. The number of stations across the wing span should be chosen around 20, but may be increased up to 40. Greater numbers do not improve the precision of the analysis, but tend to seriously hinder the convergence. The relaxation factor should be increased with higher numbers of span stations. \paragraph{2D vs. 3D} The LLT assumes implicitly that all the surfaces lie essentially in the X-Y plane.\newline The only use for the sweep and the dihedral in this implementation of the LLT is for the calculation of the pitching moment coefficient Cm. \newline Sweep and dihedral are not used in the calculation of the lift distribution. \paragraph{Viscous and inviscid calculations} There is no option available to perform a non-viscous LLT calculation. The reason behind is that the linear theory requires that a zero-lift angle be defined for each airfoil, and that there is no convenient manner to define this $\alpha_0$ value which depends on the Reynolds number. \paragraph{Lift center of pressure} Up to v3.11, the position of the lift center at each span location has been calculated using the usual approximation for thin airfoils, i.e. : \[X_{CP} = 0.25 - \frac{C_m0}{C_l}\] From v3.12 onwards, the wing's Center of Pressure's x-position is calculated by interpolation of the center of pressure's position on the foil's polar mesh. For foil polar meshes generated prior to v3.05, the foil's center of pressure was not stored, hence the formula above is used to calculate the wing's center of pressure. \paragraph{Downwash} The downwash is defined at each span station as \[V_i = V_\infty sin(\alpha_i)\] For convenience, it is represented at the wing's trailing edge in 3D views. \subsubsection{Vortex Lattice Method (VLM) - Linear } \paragraph{VLM General principles} A VLM method has been implemented as an alternative, for the analysis of those wing geometries which fall outside the limitations of the LLT. The main differences from the LLT are: \begin{itemize} \item The calculation of the lift distribution, the induced angles and the induced drag is inviscid and linear i.e. it is independent of the wing's speed and of the air's viscous characteristics. \item The method is applicable to any usual wing geometry, including those with sweep, low aspect ratio or high dihedral, including winglets. \end{itemize} The principle of a VLM is to model the perturbation generated by the wing by a sum of vortices distributed over the wing's planform. The strength of each vortex is calculated to meet the appropriate boundary conditions (BC), i.e. non penetration conditions on the surface of the panels. A comprehensive description of the principles of VLM analysis is well outside the scope of this document. Only the main features necessary to a sound use of the code are detailed hereafter. The resolution of the VLM problem requires the inversion of a square matrix of the size of the number of panels. This inversion is performed by Gauss' partial pivot method. The problem's size may be significantly reduced by considerations of symmetry, detailed in \S\ref{sec:symmetry}. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-17}\centering \caption{Influence of Sweep for a given CL - AR=10 - TR=1 - Symmetric Airfoil} \label{fig:influence_of_sweep} \end{figure} \paragraph{Lift force and lift coefficient} The force acting over each panel is the vector cross product \[F = \rho V \times \Gamma \] $\Gamma$ being the vortex strength x its length\\ $\rho$ is the fluid density\\ V is the freestream speed Which implies that the force is normal to each panel. The lift coefficient is defined as \[C_L = \frac{1}{\rho S V^2} \underset{panels}\sum{F_{wz}}\] S is the sum of the panels'area, i.e. the planform's area\\ $F_{wz}$ is the projection on the vertical wind axis This formula is applicable both to a chordwise strip and to the wing's total surface. The pitching moments and center of pressure position at each span location are calculated by summation of the lift force over the panels. \paragraph{Limitations of the VLM} \begin{enumerate} \item The VLM algorithms first computes the lift coefficient Cl and the other values which may be calculated by integration of the surface forces, i.e. the moment coefficients and the center of pressure's position. The viscous variables (viscous Cd, transitions, etc) are interpolated from the value of Cl on the previously XFoil-generated polars. This obviously raises an issue for high and low Cl, where the Type 1 polar curve may be interpolated either before or after the stall angle.\newline VLM results should therefore not be considered around angle of attack values close to stall angles. \item In the current formulation, the VLM makes the assumptions of the small angle of attack. As a main consequence, the trailing vortices are not aligned with the freestream velocity. This means that the influence matrix will be independent of the a.o.a.\newline To explore this limitation, it is possible to experiment a calculation of the tilted geometry, as explained in \S\ref{sec:tilted_geometry}. The results tend to show that the assumption of small angles of attack is acceptable. \end{enumerate} \paragraph{VLM alternative method} In the "classic" VLM method, a horseshoe vortex is positioned at the panel quarter chord and the non-penetration condition is set at the three-quarter chord point. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-18}\centering \caption{Classic VLM Method} \label{fig:classic_vlm_method} \end{figure} In the method recommended by Katz and Plotkin \cite{Katz}, only the trailing vortices extend to infinity. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-19}\centering \caption{Quad VLM Method} \label{fig:quad_vlm_method} \end{figure} Since the wake must be force free, the strength of the trailing vortex is equal to that of the trailing edge quad vortex. Both methods are implemented for comparison, but give close if not identical results in most cases. \paragraph{Panel disposition for VLM} The resolution of the system and the determination of the vortices' strengths require a matrix inversion. In some rare cases, this matrix may turn out to be singular due to a conflicting disposition of panels and control points on the wing's planform. The problem arises when a control point is positioned on the line of a vortex. This will result in a division by zero. In those cases, manual re-paneling of the wing is sufficient to fix the problem. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-20}\centering \caption{Quad VLM Method} \label{fig:quad_vlm_method_2} \end{figure} If inversion problems persist despite re-paneling, it will be necessary to check the consistency of the input data. \subsubsection{3D Panel Method - Linear} \paragraph{General Principles} The 3D panel method has been implemented with the following objectives : \begin{itemize} \item refine the LLT and VLM results by a more sophisticated full 3D method, taking into account the wings's thickness, whereas the VLM only considers the mean camber line. \item provide insight in the Cp distributions over the top and bottom surfaces of a wing \item provide a method capable of modeling fuselages \end{itemize} The principle of a 3D Panel Method is to model the perturbation generated by the wing by a sum of doublets and sources distributed over the wing's top and bottom surfaces. The strength of the doublets and sources is calculated to meet the appropriate boundary conditions, which may be of the Dirichlet or Neumann type. A comprehensive description of the principles of such a method is well outside the scope of this document. Only the main features necessary to a sound use of the code are detailed hereafter. The 3D method implemented in XFLR5 is essentially based on the method in reference \cite{Maskew}. For those interested, this document provides a comprehensive review of the theoretical and numerical aspects of the method. \paragraph{3D Panel method in XFLR5 v6} In XFLR5 v6, for a 3D-Panel type, the wing's are modeled differently depending on whether the analysis is run for a single wing or for a full plane : \begin{itemize} \item for the analysis of a single wing, the wing is modeled as thick surface, and the full 3D method described in 4 is applied \item for the analysis of a plane, the fuselage/body is taken into account, and the wings are modeled as thin surfaces; this is a restriction due to the impossibility to generate appropriate connections between wing and body without the help of a 3D-CAD program. \end{itemize} In reference \cite{Maskew}, the authors propose to model the circulation on the wings using uniform strength doublets, and to place the Neumann type boundary condition at the collocation point, i.e. the panel's centroid or center of gravity. The alternative is to use a VLM method, and to place a vortex at the panel's 1/4 chord, and the BC point at the panel's 3/4 chord. Both method have been tested, and the second alternative has proved more precise and reliable. Hence the 3D-panel method retained for planes is a mix model of uniform source/doublet for thick bodies, and horseshoe vortices for thin surfaces. \paragraph{Problem solving} The resolution of the panel problem requires the inversion of a square matrix of the size of the number of panels. This inversion is performed by LU decomposition. \paragraph{Wake roll-up} The wake roll-up process has been implemented and tested. However, it is not considered to be sufficiently robust to be released at this time, and has been disabled in v4.00. \paragraph{Boundary Conditions (BC)} In a VLM calculation, the BC are necessarily of the Neumann type, i.e. the velocity's component normal to the surface must be zero. In a 3D-Panel calculation, the BC may be either of the Neumann or Dirichlet type. In the latter case the velocity's potential on the panel's inside surface is zero, so that the total potential inside the body is equal to the freestream velocity's potential. After a trial and error process, the recommendation is to use Dirichlet BC rather than Neumann BC. The latter method is more sensitive to local geometry changes, and leads to less convincing results. This is also the choice which is implied in reference \cite{Maskew}. The type of BC can be modified in the"Advanced Settings" dialog box. \paragraph{Validation} \subparagraph{Infinite Cylinder and Sphere Analysis} The theoretical values for the Cp coefficients of a body in a uniform flow are : \begin{itemize} \item for a cylinder : $Cp = 1.0$ at the leading and trailing edges, and $Cp = -3.0$ at the lowest and highest points \item for a sphere : $Cp = 1.0$ at the leading and trailing edges, and $Cp = -1.25$ at the lowest and highest points \end{itemize} These values are calculated within \% by the 3D panel analysis. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-21}\centering \caption{Pressure coefficient Analysis -- Sphere and near infinite cylinder} \label{fig:pressure_coeficient_analysis} \end{figure} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-22}\centering \caption{Pressure Coefficient Analysis -- Sphere and near infinite cylinder} \label{fig:pressure_coeficient_analysis_2} \end{figure} \subparagraph{Wing Analysis} The Cp distributions calculated by 3D panel analysis for a near infinite wing, and by 2D panel analysis with XFoil are plotted in Figure~\ref{fig:pressure_coeficient_analysis_naca2412} and in Figure~\ref{fig:pressure_coeficient_analysis_naca_64A410}. There is general concordance for inviscid results. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-23}\centering \caption{Pressure Coefficient Analysis -- NACA2412} \label{fig:pressure_coeficient_analysis_naca2412} \end{figure} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-24}\centering \caption{Pressure Coefficient Analysis -- NACA64A410} \label{fig:pressure_coeficient_analysis_naca_64A410} \end{figure} \subsubsection{Analysis considerations} \paragraph{General Limitations} As a general rule, LLT and VLM are adapted to configurations of thin lifting surfaces, operating at small angles of attack. The most questionable assumption of the wing design algorithm is probably the use of XFoil transition results to wings with finite aspect ratio. The 2D simulation proposed by XFoil corresponds to infinite wings, where a laminar bubble extends indefinitely along the span. Some authors suggest that on span-limited wings, such bubbles will appear only on a fraction of the planform. However, theories for 3D transitions are still in development and to the author's knowledge, not giving total satisfaction yet. The method which consists in interpolating XFoil generated results is clearly an approximation with no real theoretical or experimental background, but should be a reasonable approximation for wings with moderate to high aspect ratio. The viscous characteristics will be less and less representative as the wing geometries differ from the ideal 2D Xfoil infinite wing. Hence those results for non planar geometries, low aspect ratio or high sweep should be considered with caution. \paragraph{Selection of an Analysis Method} The LLT method should always be preferred if the wing's geometry is consistent with the limitations of the theory. LLT provides better insight into the viscous drag, gives a better estimation of the behavior around stall conditions at high angles of attack, and is better supported by theoretical published work. The 3D panel method should be selected if there is interest in the Cp distribution on top and bottom surfaces, or if the body's influence should be taken into account. VLM analysis is preferable for all other cases. The comparison of the Cp distribution at two span positions for different method of analysis is given in Figure~\ref{fig:cp_comparison_for_different_analysis_methods} and Figure~\ref{fig:cp_comparison_for_different_analysis_methods_2}. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-25}\centering \caption{Cp comparison for different analysis methods} \label{fig:cp_comparison_for_different_analysis_methods} \end{figure} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-26}\centering \caption{Cp comparison for different analysis methods} \label{fig:cp_comparison_for_different_analysis_methods_2} \end{figure} \paragraph{Core radius} In VLM analysis, the velocity vector induced by a vortex is singular on the vortex line. In a 3D panel method, the velocity vector is singular in the alignment of the panel sides. This can create numerical errors in the analysis and in the calculations of the streamlines. It is therefore highly recommended to set a minimal core radius, which can typically be of the order of magnitude of 1/1000 of the min mesh panel size, e.g. $Core radius = 10^{-6}m$. This is the value set by default, and it can be modified in the advanced settings. The velocity at a point located on the vortex line, or in the alignement of a panel side, is zero. \paragraph{Sideslip} The simulation of sideslip has been introduced in XFLR5 v4.09. The order in which a.o.a. and sideslip are applied has its importance. In XFLR5, sideslip is modeled by rotating the model about the z-axis, with a freestream velocity vector remaining in the x-z plane. The resulting geometry is analyzed using the conventional VLM and panel methods. The advantage of this method is that the trailing vortices are in the vertical plane which contains the velocity vector, i.e. are aligned with the x-axis of the stability frame. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-27}\centering \caption{Definition of sideslip} \label{fig:definition_of_sideslip} \end{figure} \paragraph{Trefftz Plane, far field and near field analysis} The lift and induced drag may be calculated by near field or by far field methods. The theoretical aspects are too vast to be detailed here, but in essence the near field method consists in an integration of pressure forces on the panels, whereas the far field method is based on the balance of the momentum on a control surface far downstream of the body, i.e. the Trefftz plane. It is generally reported that the drag and lift results from near field analysis are significantly higher and less representative than those resulting from a calculation in the Trefftz plane. This issue is not specific to the present implementation, but is reported for almost all VLM and panel codes. The implementation in the present code for the calculation of lift and drag is therefore the far field method. On the other hand, far field analysis does not provide information on the pressure distribution over the strip, and no information on the pitching moment with reference to the chord's quarter point. All the moments and the position of the center of pressure are therefore calculated by summation on the panels. In the current implementation of the 3Dpanel method, it is considered that only the wings shed a wake, and that the body does not. \paragraph{Linear and non-linear behavior} Traditional VLM and Panel analysis do not account for viscous effects. For model aircraft operating at a few m/s however, the viscous drag is not negligible compared to the induced drag, and must therefore be estimated by an alternative mean. In the present application, the viscous drag is estimated by interpolation of XFoil pre-generated polars, by the Cl value resulting from the linear 3D analysis. This assumes implicitly that the foil's behavior on a finite wing is not very different than on an "infinite XFoil wing". There is no real background, neither theoretical nor experimental, to support this approach, so it should be used with caution. As is generally the case when transposing 2D results to 3D analysis, the estimation of viscous drag is probably too low and may lead to arguably optimistic results. Because the VLM is linear, it does not, among other things, account properly for stall at high angles of attack, unlike, potentially, the LLT. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-28}\centering \caption{Linear and Non-Linear modeling} \label{fig:linear_and_non_linear_modeling} \end{figure} \paragraph{Non-Linear Implementation} \begin{figure}[htbp] \includegraphics[width=0.5\linewidth]{dia-02}\centering \end{figure} \paragraph{Tilted Geometry -- VLM and 3D Panel Analysis} \label{sec:tilted_geometry} The baseline VLM method uses small angle approximation for the wake's definition. Within this assumption, the wake is aligned with the body axes : \begin{itemize} \item For VLM, the trailing legs of the horseshoe vortices are parallel to the body's x-axis (Figure~\ref{fig:normal_and_tilted_geometry_configurations}a). \item For 3D Panel analysis, the trailing wake panels are in the x-y plane \end{itemize} The advantage of this approximation is its simplicity : only one influence matrix is required for all angles of attack, and the matrix inversion can be performed for all alphas simultaneously.\newline The disadvantage is that the horseshoe vortices or the wake panels are not aligned with the freestream velocity. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-29}\centering\\ \includegraphics[width=0.8\linewidth]{img-30}\centering\\ \includegraphics[width=0.8\linewidth]{img-31}\centering \caption{Normal and Tilted geometry configurations} \label{fig:normal_and_tilted_geometry_configurations} \end{figure} A more representative approach is to align the wake with the wind axes (Figure~\ref{fig:normal_and_tilted_geometry_configurations}b). Equivalently, the problem can be set in the wind axes and the body's geometry can be tilted by the angle of attack (Figure~\ref{fig:normal_and_tilted_geometry_configurations}c), which is a direct transposition of the physics of the problem. Both methods are equivalent, but the latter can be implemented more simply, hence has been chosen for XFLR5. It is selected by checking the "Tilt Geometry" checkbox in the Analysis Dialog Box. The inconvenience with this approach is that a new matrix must be set up and inverted for each angle of attack, leading to longer computation times. The coefficients Cl and Cd are almost identical for both methods, which means the small angles approximation is applicable from the performance analysis point of view. The moment coefficients may be slightly different. \paragraph{Wake roll-up -- VLM and 3D Panel Analysis} \underline{Note} : Because it is sensitive and difficult to use, the wake roll-up process has been disabled. The following explanation is provided for information only. \subparagraph{General considerations} In their base formulation, both the VLM and the Panel methods make the assumption of a flat wake, which is an approximation. The wake tends to roll up on itself, which can be illustrated for instance by the two vortices at the tip of each wing. A wake model more refined than the simple straight line or flat panel can be of interest for two reasons : \begin{itemize} \item Although the wake carries no load and therefore has no influence on the lift coefficient, its shape affects the induced drag value and derived coefficients \item A flat wake is inappropriate for plane configurations with and elevator, since the downwash created by the main wing influences the flow field around the elevator. \end{itemize} The shape of the wake is determined by the flowfield behind the wing, but in turn, the flow field is dependent on the wake shape. Therefore, the shape the wake takes in a constant state situation can be deduced by an iterative process, in which the wake geometry is updated ("relaxed") after each computation loop. \subparagraph{Wake mesh} The panels formulation implemented in XFLR5 is of the constant, flat panel type. Special care must therefore be taken in the choice for the wake panel's size, to avoid excessive twisting. The panel size is controlled by three parameters : \begin{itemize} \item The wake's total length \item The streamwise size for the first wake panel's length \item The ratio, or progression factor, between two adjacent panels in the streamwise direction \end{itemize} As a general indicaction, it is advisable to set those parameters so that the first panel's size is approximately the same as that of the wing's trailing edge panel. \subparagraph{Roll-up process} Ideally, the lift and drag coefficients tend towards limit values. However, if no special precautions are taken, numerical experiments show that the wake tends to roll up indefinitely on itself. This leads to highly twisted panels and to numerical divergence. Since the roll-up is not a robust process, the iteration loop is limited both by the number of iterations and by a precision criterion. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-32}\centering \caption{Wake roll-up iteration process} \label{fig:wake_roll_up_iteration_process} \end{figure} Reference \cite{Werner} provides a comprehensive description of the issues related to wake roll-up. \subsubsection{Moments} \label{sec:moments} All moment calculations in LLT are strictly in accordance with the formula of NACA TN1269. In V4.00, the definition of the moments has been modified to clarify some ambiguities that existed up to v3.21. From V4.00 onwards, the geometric pitching, rolling and yawing moments are calculated by integration of forces on the panels. For VLM this is done at the vortex middle position, for 3D Panel analysis, the force is applied at the panel's center. The geometric moments are therefore the total moments applied to the wing or plane. For analysis purposes, it may be interesting to break down those moments in separate parts, or to isolate one specific contribution to the total moment. \underline{Strip Moment Coefficients} These moments are calculated for each span position on the wing and are accessible in the Operating Point graphs. \begin{table}[htbp]\scriptsize \centering \begin{tabular}{|*{4}{m{0.03\linewidth}|}*{3}{m{0.19\linewidth}|}} \hline \multicolumn{2}{|c|}{Moment} & Sign & Ref.\newline Len. & Nature & LLT & VLM \& 3D Panel\\ \hline \multirow{2}{0.03\linewidth}{\begin{sideways}Pitching\end{sideways}} & \begin{sideways}Airfoil $C_m$~Airfoil\end{sideways} & \multirow{2}{0.03\linewidth}{\begin{sideways}positive nose~up\end{sideways}} & \multirow{2}{0.03\linewidth}{\begin{sideways}M.A.C : $M=q.S.mac.C_m$\end{sideways}} & Moment of the lift forces around the 1/4 chord point& The value for the pitching moment is interpolated on the foil's polar mesh. It takes into account viscous effects& Sum of the moments created by pressure forces on the strip's panels The viscous part is ignored \\ \cline{2-2} \cline{5-7} & \begin{sideways}$C_m$\end{sideways} & & & Moment of the pressure and viscous forces with respect to XCmRef& Integration over the wing's lifting line of the strips self pitching moment, and of the strip lift force Both sweep and dihedral are taken into account& Sum on all the panels of the moments of pressure forces + pitching moment of viscous drag forces \\ \hline \end{tabular} \caption{Strip Moment Coefficients} \label{tab:strip_moment_coefficients} \end{table} \underline{Wing moment coefficients} \begin{table}[htbp]\scriptsize \centering \begin{tabular}{|*{4}{m{0.03\linewidth}|}*{3}{m{0.19\linewidth}|}} \hline \multicolumn{2}{|c|}{Moment} & Sign & Ref.\newline Len. & Nature & LLT & VLM \& 3D Panel\\ \hline % 8<--------------------- \multirow{3}{0.03\linewidth}{\begin{sideways}Pitching\end{sideways}} & \begin{sideways}Geom (global) $GCm$~Airfoil\end{sideways} & \multirow{3}{0.03\linewidth}{\begin{sideways}positive nose~up\end{sideways}} & \multirow{3}{0.03\linewidth}{\begin{sideways}M.A.C : $M=q.S.mac.C_m$\end{sideways}} & Moment of the pressure forces with respect to XCmRef& Integration of the moment over the wing's lifting line. Both sweep and dihedral are taken into account& Sum on all the panels of the moments of pressure forces \\ \cline{2-2} \cline{5-7} & \begin{sideways}Viscous (global) $VCm$\end{sideways} & & & Moment of the viscous airfoil drag forces with respect to XCmRef& \multicolumn{2}{|c|}{Integration of the moment over the wing's lifting line.} \\ \cline{2-2} \cline{5-7} & \begin{sideways}Airfoil (at local span pos.)\end{sideways} & & & Moment of the lift forces around 1/4 chord point& Cm interpolated on polar 1 mesh& Sum of the moments created by pressure forces on the strip's panels \\ \hline % 8<--------------------- \begin{sideways}Rolling\end{sideways} & \begin{sideways}Geom (global) $GRm$\end{sideways} & \begin{sideways}positive with the starboard wing down\end{sideways} & \begin{sideways}Span : $R=q.S.b.C_r$\end{sideways} & Moment of the pressure forces with respect to XCmRef& Integration of the lift's moment over the wing's lifting line. Dihedral is not taken into account& Sum on all the panels of the moments of pressure forces \\ \hline % 8<--------------------- \multirow{3}{0.03\linewidth}{\begin{sideways}Yawing\end{sideways}} & \begin{sideways}Geom (global) $GYm$\end{sideways} & \multirow{3}{0.03\linewidth}{\begin{sideways}positive with the nose to starboard\end{sideways}} & \multirow{3}{0.03\linewidth}{\begin{sideways}Span : $N=q.S.b.C_n$\end{sideways}} & Moment of the pressure forces with respect to XCmRef& N/A& Sum on all the panels of the moments of pressure forces \\ \cline{2-2} \cline{5-7} & \begin{sideways}Profile (global) $VYm$\end{sideways} & & & Moment of the viscous airfoil drag forces with respect to the plane y=0& \multicolumn{2}{|c|}{Integration of the moment over the wing's lifting line} \\ \cline{2-2} \cline{5-7} & \begin{sideways}Induced (global) $IYm$\end{sideways} & & & Moment of the induced tangential forces with respect to the plane y=0& \multicolumn{2}{|c|}{Integration of the moment over the wing's lifting line} \\ \hline % 8<--------------------- \end{tabular} \caption{Wing moment coefficients} \label{tab:wing_moment_coefficients} \end{table} \subsubsection{Neutral point, Center of pressure, Static Margin} XFLR5 up to v3.12 has provided a measure of the quantity \[SM = \frac{(X_{CP} - X_{CG})}{MAC}\] incorrectly labeled "Static Margin", where \begin{itemize} \item $X_{CP}$ is the centre of pressure's streamwise position \item $X_{CG}$ is the centre of gravity's streamwise position \end{itemize} The conventional static margin of a wing or a plane may be determined by an iterative process. It is the CG position (or moment reference position XCmRef) for which \[\frac{dCm}{d\alpha}=0\] This is illustrated in the Figure~\ref{fig:wing_neutral_point} where the neutral point is approximately 67 mm from the leading edge. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-33}\centering \caption{Wing Neutral Point} \label{fig:wing_neutral_point} \end{figure} Illustration of the way to use XFLR5 to position the CG of a model sailplane are given in \cite{DeperroisStab} and \cite{DeperroisNotions}. \subsubsection{Efficiency factor} The efficiency factor, referred to also as Oswald's factor, is a measure of the deviations of the wing's induced drag from that of an optimal elliptic loading, and is defined as \[e=\frac{CL^2}{\pi.AR.ICd}\] where \begin{itemize} \item CL is the lift coefficient \item ICd is the induced drag coefficient \item AR is the wing's Aspect Ratio \end{itemize} The efficiency factor, also named Oswald's factor, should always be smaller than 1. It may happen however that this factor becomes greater than 1 for numerical reasons in LLT, VLM and 3D Panel calculations. In LLT, this may be corrected by increasing the precision required for convergence, for instance with the following parameters : \begin{itemize} \item Number of stations = 40 \item Relaxation factor = 40 \item convergence criterion = 0.001 \item Max Number of iterations = 300 \end{itemize} In VLM and 3D Panels, a refinement of the panel density in the streamwise direction is required to reduce the efficiency factor to values less than 1. \subsubsection{Wing Operating Points and Wing Polars} The presentation of results is the same as for foil analysis, i.e. each converged analysis generates an operating point and adds results to a polar object. The definition and selection of an Analysis/Polar object is necessary to perform a calculation. Any number of Operating Points may be stored in the runtime database, the only limitation being computer memory. Wing and plane operating points will use significant memory resources. Type 1 and Type 4 polars are unchanged from foil analysis. A type 2 polar corresponds to a plane with a given weight operating at constant lift. For a given angle of attack, the plane's velocity is calculated to create a lift force opposite to the weight of the airplane : \[V=\sqrt{\frac{2mg}{\rho SC_l}}\] The angle of descent is \[\gamma=arctan(\frac{C_d}{C_l})\] and the horizontal and vertical speeds are respectively \[V_x=V_\infty cos(\gamma)\] \[V_z=V_\infty sin(\gamma)\] \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-34}\centering \caption{Speed polars based on Type 2 analysis} \label{fig:speed_polars_based_on_type_2_analysis} \end{figure} Convergence for type 2 polars requires that the apparent angle of attack be greater than the zero-lift angle. Otherwise, no speed whatsoever may generate a positive lift... \subsubsection{Control analysis -- Polar \foreignlanguage{english}{Type 5 and Type 6}} The Type 5 and Type 6 control polars have been disabled in XFLR5 v6 and are replaced by the Type 7 stability polars. \subsubsection{Interpolation of the XFoil-generated Polar Mesh} The code does not recalculate with XFoil each operating point at every wing station and at each iteration: \begin{itemize} \item this would require lengthy -and unnecessary- calculations \item XFoil's convergence is too uncertain \end{itemize} Instead, the operating point is interpolated from a pre-generated set of Type 1 polars. The wing calculation requires that a set of \textbf{Type 1} foil polars be previously loaded or generated for each of the wing's foils.\newline \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-35}\centering \caption{Polar mesh ranging from Re = 40,000 to Re = 300,000} \label{fig:polar_mesh_ranging_from} \end{figure} The set of polars should cover the whole flight envelope of each point of the wing, with regard to both Reynolds numbers and to the apparent angle of attack. If any point of the wing planform operates outside the available polar mesh, a warning message is issued in the log file. This happens for instance in the case of short tip chords of elliptic wings. In such a case, the "closest point" of the mesh will be used, and the operating point may be generated and added to the current polar, if so chosen by the user. For the interpolation process, the code uses indifferently all available type 1 polars related to the selected foil. The user must therefore be careful to provide only a homogeneous and consistent set of polars. The interpolation process of a variable X (X being Cl, Cd, Cm, Transition points etc.) from $[\alpha = aoa + \alpha_i + washout, Re]$ at a geometrical point P between the foils 1 and 2 is: \begin{enumerate} \item For the first foil, find polars 1 and 2 such that $Re_1 < Re < Re_2$;\newline if neither polar 1 nor 2 can be found, return on error\newline if Re is less than all the polars' Reynolds numbers, use the polar of smallest Re\newline if Re is greater than that of any polars' number, use the polar of greatest Re \item Interpolate each polar with $\alpha$ to get $X_{11}$ and $X_{12}$\newline if either polar is not defined up to $\alpha$, use the smallest or greatest angle available, and issue a warning\newline if only one polar is available, interpolate only that polar, and issue a warning \item Interpolate $X_1$ between $X_{11}$ and $X_{12}$, pro-rata of Re between $Re_1$ and $Re_2$ \item Do the same for the second foil to get $X_2$ \item Interpolate X between $X_1$ and $X_2$, pro-rata of the position of the point between the two foils \end{enumerate} \subsubsection{Streamlines} The streamlines are calculated from the vortices, or doublet and source, strengths each time an operating point is selected. The calculation is incremental, in the x streamwise direction. The streamline are initiated at the mesh panels leading edge or trailing edge, with a user defined offset in the x and z directions. The "Initial Length" is the first x-increment for the calculation of the streamline. The "Progression Factor" determines the length of step n+1 vs. step n. Caution note : The velocity vector is singular at the panel edges in 3D-Panel analysis, and on the panel's vortex trailing line in VLM analysis. This may cause numerical instabilities, in cases for instance when the streamlines are requested to initiate exactly at the panels leading or trailing edge, or at the panel corners. A minor x or z offset is necessary to prevent the instability. The use of a core radius, which can be defined in the advanced settings, is another possibility. \subsubsection{Comparison to experimental results} The code has been tested against experimental results and against other software, with consistent results.\newline Also, the VLM, 3D Panel and LLT algorithms in their XFLR5 implementation are totally independent, but give close results in the linear part of the Cl vs. $\alpha$ plots. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-36}\centering \caption{Comparison to test results from Naca Tech. Note 1270} \label{fig:comparison_to_test_results} \end{figure} \subsubsection{Comparison to wind tunnel data} An experiment has been carried out beginning of 2008 on a model sailplane. The detailed results are given in \cite{DeperroisResults}. The following figures provide results from XFLR5 v3.21 and from v4.09. Results from v3.21 are marked as "FMe", since the calculation has been performed by F. Meschia. Note : in v4.09, the lift calculation was performed by integration of pressure forces on the panels. From v4.13, the calculation is performed in the far field plane. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-37}\centering \caption{Predicted lift curve vs. experimental results} \label{fig:predicted_lift_curve_vs_experimental_results} \end{figure} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-38}\centering \caption{Predicted drag polar vs. experimental results} \label{fig:predicted_drag_polar_vs_experimental_results} \end{figure} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-39}\centering \caption{Predicted pitch moment vs. experimental results} \label{fig:predicted_pitch_moment_vs_experimental_results} \end{figure} It can be concluded that \begin{itemize} \item the VLM is at least as reliable as the 3D panel method, \item the body modeling does not improve the precision of the results \item both methods give reasonable estimations of values such as : \begin{itemize} \item lift coefficient \item zero lift angle \item pitch moment coefficient \item zero lift moment or zero moment lift \end{itemize} \item both methods tend to underestimate the drag, probably the viscous part of it \end{itemize} \subsubsection{Comparison to Miarex and AVL results} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-40}\centering \caption{Comparison to results from Miarex} \label{fig:comparison_to_results_from_miarex} \end{figure} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-41}\centering \caption{Lift coefficient - Comparison to AVL and Miarex} \label{fig:lift_coefficient_comparison_to_avl_and_miarex} \end{figure} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-42}\centering \caption{Induced Angle vs. span - Comparison to AVL and Miarex} \label{fig:induced_angle_vs_span_comparison_to_avl_and_miarex} \end{figure} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-43}\centering \caption{Induced Drag vs. span - Comparison to AVL and Miarex} \label{fig:induced_drag_vs_span_comparison_to_avl_and_miarex} \end{figure} Note about induced drag : the heterogeneity of AVL results is unexplained. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-44}\centering \caption{Center of pressure position vs. span - Comparison to AVL and Miarex} \label{fig:center_of_pressure_position_vs_span_comparison_to_avl_and_miarex} \end{figure} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-45}\centering \caption{Pitching moment coefficient vs. span - Comparison to AVL and Miarex} \label{fig:pitching_moment_coefficient_vs_span_comparison_to_avl_and_miarex} \end{figure} \subsubsection{Session example -- Wing Analysis} \label{sec:session_example_wing_analysis} \begin{enumerate} \item Load the foil(s) which will be used to define the wing \item In the Direct Analysis Application, click the "Run Batch Analysis" command in the Polars menu, or type \Shift + \keystroke{F6} \item Run a batch analysis with the following parameters (make sure these values cover the whole flight envelope of the wing): \begin{itemize} \item from $\alpha = -6^\circ$ to $\alpha = 10^\circ$ \item from Re = 40,000 to Re = 160,000 every 20,000 \item from Re = 200,000 to Re = 500,000 every 50,000 \end{itemize} or use a predefined list Checking the box "Start from zero" will cause the analysis to start from $\varpi = 0^\circ$, going upwards to $\alpha_{max}$, then downwards to $\alpha_{min}$ this usually facilitates convergence \item Close the dialog box \item Optional : Use the "Save Associated Polars" in the "Current Foil" menu to save the polars to a ".plr" file for use in future projects \item Switch to the Wing Design Application \Ctrl+\keystroke{6} \item Click the"Define Wing" command, \keystroke{F3} in the Wing menu, or "Define a Plane" (\Ctrl+\keystroke{F3}) \item Define the object and close the dialog box \item Optional, but recommended : Define the inertia properties of the current plane or wing object. \item Select Current plane(or wing)/Define Inertia \item Enter the inertia properties for the plane or wing. \item Make sure that the CoG position is where it's meant to be. It may be necessary to "cheat" a little on the positions of point masses to achieve the desired position \item Close the dialog box \item Click the "Define Analysis/polar" in the Wing Polar menu, (\keystroke{F6}) \item Activate the Type 2 check box \item Define the plane mass and the center of gravity position (the moment ref. location), or select the option to use the plane's inertia \item Unless the wing has either low aspect ratio, high sweep, or high dihedral, select the"LLT" checkbox, and close the dialog box (\Return and \Return) \item Leave the LLT settings to the default values in the "Operating Point" menu, i.e. "Relax~Factor~=~20" and "$N^\circ$~of~Stations~Along~the~Span~=~20" \item Select an angle of attack in the right toolbar which can be expected to give positive lift equal to the model weight at reasonable Speed/Re values -- for instance $\alpha = 3^\circ$ \item Click the"Analyze" button in the right toolbar \item Change settings if LLT convergence cannot be reached, or continue the LLT analysis after un-checking the "Init LLT" checkbox \item Click the "3D view" command in the View menu \item Use the mouse to zoom and rotate the model \item Use Sequence to calculate a complete wing's polar \item Click on the "Polars" command in the View menu, (\keystroke{F8}) to visualize the polar graphs \end{enumerate} \subsubsection{Non convergences} \begin{table}[htbp]\scriptsize \centering \begin{tabular}{|m{0.18\linewidth}|m{0.38\linewidth}|m{0.38\linewidth}|} \hline & Cause & Fix \\ \hline \multirow{4}{0.18\linewidth}{All methods} & The foils' Type 1 polar meshes do not cover the available flight envelope\newline [most usual case of non convergence] & Extend the foils' Type 1 polar meshes \\ \cline{2-3} & In Type 2 analysis, the lift is negative & Calculate only for higher values of the angle of attack \\ \cline{2-3} & In Type 2 analysis, the speed is either too low or too high, leading to OpPoints outside of the available flight envelope & Extend the foils' Type 1 polar mesh ; The speed will tend towards infinite values at low aoa, and symmetrically will tend towards 0 at high aoa \\ \cline{2-3} & The tip chord is too small and yields too low Reynolds numbers & Either: \begin{enumerate} \item Check the "Store OpPoints outside the Polar mesh" checkbox \item Omit the end of the wing in the definition of its planform \end{enumerate} \\ \hline \multirow{2}{0.18\linewidth}{LLT} & The relaxation factor is too small & Increase the factor in the "LLT Settings…" dialog box \\ \cline{2-3} & The number of points over the planform is too high & Decrease the number in the "LLT Settings…" dialog box \\ \hline VLM & The matrix is singular because of a conflicting disposition of VLM panels & Regenerate a manual VLM mesh \\ \hline Panel & The results are inconsistent because the wakes shedded by the wing and elevator are in the same horizontal plane & Offset either the wing or elevator in the z direction, so that they do not lie in the same plane \\ \hline \end{tabular} \caption{Non convergences causes and solutions} \label{tab:non_convergences_causes_and_solutions} \end{table} The log file will indicate which points of the flight envelope could not be calculated. It can be accessed with the menu command "Operating Point/View Log File" The "log file" is a plain text file. If the document does not show up when called from the menu, it may be necessary to manually associate the".log" extension to Windows' Notepad. \subsection{Stability and control anaysis} The intent of stability and control analysis is to evaluate the time response of a plane to perturbations from a steady flight condition. The perturbations can originate with the environment, for instance from a gust of wind, or from the actuation of a control. The mathematical representation of the response is a complex matter, which requires some simplifying assumptions. Essentially, only small perturbations about the steady flight conditions are considered. The theoretical aspects of flight dynamics and stability analysis can be found in reference \cite{Sivells47}. The purpose of this document is: \begin{itemize} \item to provide a short and much simplified description of the flight dynamics for users not familiar with the theory \item to explain the choices made in XFLR5 \item and to describe the analysis procedure. \end{itemize} Note : the mathematical concepts and formulas presented hereafter are not absolutely necessary to the understanding of the physics of flight dynamics. They are provided as information and background for those users interested in investigating further the concepts. \subsubsection{Method} \subsubsection{Theory} XFLR5 follows the method proposed by Etkin in ref [1]. With this type of analysis, longitudinal and lateral dynamics are independent and are evaluated separately. \subsubsection{Frames of reference} Three different reference frames come into consideration in stability analysis : the geometric axes, the body, axes and the stability axes. These are defined in Figure~\ref{fig:body_and_stability_axes}. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-46}\centering \caption{Body and stability axes} \label{fig:body_and_stability_axes} \end{figure} \underline{Body axes:} The term body axes is generic and refers to any frame which is fixed to the body, and is therefore not an inertial frame of reference. A usual, but not universal, convention is as follows: \begin{itemize} \item the X'-axis is aligned with the fuselage nose; \item the Z'-axis is in the plane of symmetry, and points downwards; \item the Y'-axis is perpendicular to the XZ-plane and points starboard. \end{itemize} \underline{Geometric axes:} This is the reference frame in which the geometry is defined. \begin{itemize} \item the X-axis is aligned "backwards" \item the Z-axis is in the plane of symmetry, and points upwards; \item the Y-axis is perpendicular to the xz-plane and points starboard. \end{itemize} The geometric axes are a special case of body axes. \underline{Stability axes:} This is the frame in which the movement in the steady state conditions is most conveniently described: \begin{itemize} \item the x-axis is the projection of the velocity vector on the body's xz-plane; this axis therefore points forward \item the z-axis points downwards \item the y-axis points starboard \end{itemize} The point of origin of the frame is the plane's centre of gravity CoG. The stability axes are a special case of body axes. \underline{Notes:} \begin{itemize} \item In horizontal level flight, the axis $X_{stability}$ is horizontal \item Since sideslip in XFLR5 is simulated by rotation of the structure around the inertial $Z_E$ axis, the wind axes are the same as the stability axes even if the sideslip is non zero. \item In equilibrium conditions, the stability axes are fixed to the body, and therefore are not an inertial frame. \end{itemize} XFLR5 follows the recommendation of [1] and performs all calculations in stability axes. \subsubsection{Coordinates, position, velocity, and rotation vector} The position of the body in stability axes is defined in some inertial frame of reference by the position of its origin O(x,y,z), and by the rotation defined by Euler angles (\textrm{${\varphi}$, ${\theta}$, ${\psi}$}). Let V(U,V,W) be the body's velocity vector, and let \textrm{${\omega}$}(P,Q,R) be the body's rotation vector, both defined in the stability axes. Additionally, assume that the plane is in equilibrium flight, for instance : \begin{itemize} \item steady level flight with no sideslip \item banked circle turn \item looping at constant speed (difficult to imagine, but no matter) \end{itemize} The state of the body/plane is defined by the set of variables (X, Y, Z, U, V, W, P, Q, R) Since we shall be considering only small variations about the steady state conditions, each variable can be defined by an average value and a perturbation around this mean value. For instance: \[U = U_0 + u\] The subscript 0 refers to the steady flight state conditions. $U_0$ for instance is the speed in level flight along the stability x-axis. The purpose of stability analysis is to calculate the time response of the flight variables in response to small perturbations. \subsubsection{Flight constraints} The stability derivatives are computed about equilibrium conditions. The conditions that are considered are level or banked horizontal flight. Using terminology from AVL : \begin{description} \item[$\alpha$] angle of attack \item[$\beta$] sideslip angle \item[$C_L$] Lift coefficient, calculated from the geometry, $\alpha$ and $\beta$. \item[$\varphi$] arbitrary bank angle, positive to the right \item[m] mass \item[g] gravity acceleration \item[$\varrho$] air density \item[S] reference area \end{description} The constraints are : \begin{itemize} \item $U_0 = \sqrt{\frac{2mg}{\varrho SC_L} cos~\varphi}$ airspeed \item $R_0 = \frac{V_0^2}{g}tan~\varphi$ turn radius, positive for right turn \item $W_0 = \frac{V_0}{R}$ turn rate, positive for right turn \item $p_0 = 0$ roll rate, zero for steady turn \item $q_0 = W_0 sin~\varphi$ pitch rate, positive nose upward \item $r_0 = W_0 cos~\varphi$ yaw rate, positive for right turn \end{itemize} Type 2 analysis in XFLR5 only considers the condition \textrm{${\varphi}$}=0. This condition is relaxed for stability analysis. \subsubsection{State description} The plane's state at any instant is given by a set of 8 variables. Four variables describe the longitudinal state: \begin{description} \item[u] is the variation of speed along the x-axis : $U = U_0 + u$ \item[w] is the variation of speed along the z-axis \item[q] is the pitch rate, i.e. the rotation vector around the y-axis \item[$\theta$] is the pitch angle, i.e. the angle between the stability x-axis and the horizontal flight line\newline the angle is positive for a nose up. \end{description} Four variables describe the lateral dynamics: \begin{description} \item[v] is the variation of speed along the w-axis \item[p] is the roll rate, i.e. the rotation vector around the x-axis \item[r] is the yaw rate, i.e. the rotation vector around the z-axis \item[$\varphi$] is the bank angle, i.e. the angle between the stability y-axis and the horizontal flight line\newline the angle is positive for a right wing down \end{description} The position defined by (x,y,z) does not come into consideration when studying flight dynamics, since the behaviour is not expected to depend on absolute position. The variation of gravity and density with altitude is negligible for model aircraft and is not taken into account. In lateral dynamics, the heading \textrm{${\psi}$} does not appear in the equations. \subsubsection{Analysis procedure} The stability analysis follows the following steps: \begin{enumerate} \item Define the geometry \item Define the mass, center of gravity (CoG), and inertia of each component of the plane. Two sub-options \begin{enumerate} \item Enter the mass of the wing or body, and let XFLR5 estimate the inertia and CoG \item Enter those values manually \end{enumerate} \item Define a stability Analysis/Polar (\Shift+\keystroke{F6}).\newline If no active controls are defined, the analysis will be run for the base geometry.\newline If controls are defined, then the stability data may be calculated in a sequence for a range of control parameter, and a polar curve may be generated \item Run the analysis for some control parameter. The code will \begin{enumerate} \item Search for an angle of attack such that Cm=0, and will exit with a warning if unsuccessful \item Calculate the trim speed to achieve steady state flight \item Evaluate the stability derivatives, \item Build the state matrices, \item Extract the eigenvalues, and will exit with a warning if unsuccessful, \item Store the data in an OpPoint (optional) and in the polar object. \end{enumerate} \item Visualize the results. \end{enumerate} \subsubsection{Input} \paragraph{Description} In input, the analysis takes : \begin{itemize} \item the plane's geometry \item the plane's mass, CoG and inertia tensor, defined in geometrical body axes. \item the parameters defined by the stability analysis \item the position for the controls : wing and elevator tilt angles, flap positions, etc. \item the type of steady flight to be considered : steady level flight or steady banked turn. \end{itemize} \paragraph{Inertia estimations} A calculation form is provided to evaluate approximately the CoG position and the inertia tensor associated to the geometry. The evaluation should not be understood as anything else than a rough order of magnitude (ROM). The inertia of the plane sums up the inertia of each object and of the additional point masses. \subparagraph{Object inertias} The inertia of each object, i.e. wing or body, is evaluated in the dialog form for this object. It includes the volume inertia from the structural masses, and the inertia of point masses. The volume inertia is evaluated based on the mass provided, and on the geometrical data defining the object. It is evaluated in the geometrical coordinate system, with origin at each object's CoG. The evaluation is based on the following assumptions. \begin{itemize} \item For the body, the mass is distributed uniformly in the external surface, and this surface is assumed to have a uniform thickness. The body is divided in $N_b$ elementary sections along the x-axis. The weight is concentrated at the center of the cross section, as illustrated in Figure~\ref{fig:mass_representation_for_the_body}. \item For the wing, the mass is assumed to be distributed uniformly in the wing volume along the span.\newline In XFLR5 v5, it has been modeled as point masses concentrated at the quarter-chord point of distributed sections along the span.\newline In XFLR5 v6, it is modeled as point masses distributed both in the span and chord directions, as illustrated in Figure~\ref{fig:mass_representation_for_the_wing}. The mass distribution is independent of the wing's mesh used for aerodynamic calculations. \end{itemize} \subparagraph{Point masses} Parts such as actuators, battery, nose lead, or receiver should be modelled separately as point masses, and not be included in the evaluation of the volume inertia. \subparagraph{Total inertia} The total inertia for a plane is the sum of the inertias of the object making up the plane, and of point masses. It is expressed in the reference frame defined by the plane's CoG and by the geometrical axes. The transport of the inertia tensor from object CoG to plane CoG is done by application of Huyghens/Steiner theorem. \subparagraph{Notes} \begin{itemize} \item The mass defined for wings and bodies is not the one used for Type 2 calculations. The mass for type 2 is defined by the Analysis/Polar setting. \item The distribution of point masses should be adjusted to obtain the targeted position of the CoG. Otherwise, because of the approximations made in the automatic evaluation of volume inertia, a strict transposition of the "real" position of masses may result in an incorrect position of the plane's CoG. \end{itemize} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-47}\centering \caption{Mass representation for the body} \label{fig:mass_representation_for_the_body} \end{figure} \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-48}\centering \caption{Mass representation for the wing} \label{fig:mass_representation_for_the_wing} \end{figure} \paragraph{Stability polar parameters} The"stability polars" replace the former "control polars". The main difference is that the position of the CoG is no longer a variable, but is instead determined by the distribution of masses in the plane. The Stability Polar object takes for input \begin{itemize} \item the fluid's density and dynamic viscosity \item the type of reference length and area for the calculation of aerodynamic parameters \item the selection of either viscous or inviscid analysis \item the control variables to include in the analysis \end{itemize} \paragraph{Control variables} The polar points can be calculated for different state of control variables. These variables are: \begin{itemize} \item The tilting of the wing about the y-axis \item The tilting of the elevator about the y-axis \item the rotation of the main wing's flaps about their hinge axis \item the rotation of the elevator's flaps about their hinge axis \item the rotation of the fin/rudder's flaps about their hinge axis \end{itemize} \underline{Notes:} \begin{itemize} \item The positive direction of rotation is positive by right-hand rule, i.e. \begin{itemize} \item for the wing and elevator, a positive value will move the leading edge upwards and the trailing edge downwards \item for a wing or elevator flap, a positive control value will move the trailing edge downwards \item for the rudder, a positive control value will move the trailing edge to starboard \end{itemize} \item To represent ailerons rotating in opposite directions, the min and max values of the controls for each wing's aileron should be opposite. \item The initial value of the control's angle is not taken into account in the analysis. For instance, if the flap has been defined with foils with non-zero flap angles, the initial angles will be cancelled before setting the position of the control.\newline Similarly, the tilt angle defined for the wing or flap in the plane definition is cancelled before application of the control variable. \item For a control polar, all the parameters vary simultaneously in accordance with the value of the control parameter "c" : $$Control variable = (1-c) \times Control\_Min\_position + c \times Control\_Max\_position$$ \item The rotation of controls is not represented in the 3D view \end{itemize} \subsubsection{Output} In output, the code provides results for longitudinal and lateral dynamics : \begin{itemize} \item The dimensional stability and control derivatives \item The non-dimensional stability derivatives \item the time response for a step input \item the eigenvalues and eigenvectors for the four longitudinal modes and the four lateral modes. \end{itemize} \paragraph{Stability derivatives} The stability derivatives describe the change to a force or moment in response to a variation of a flight variable. For instance, the variation of the axial force resulting from a change in axial speed is: $$\frac{\partial F_X}{\partial u} = \frac{1}{2}\rho \frac{\partial u_{0}^{2}} S C_X + \frac{1}{2}\rho u_{0}^{2} S frac{\partial C_X}{\partial u} = = \rho u_{0} S C_{X} + \frac{1}{2} \rho u_{0}^{2} S \frac{\partial C_{X}}{\partial u}$$ A usual convention is to use simplified notations: $$\frac{\partial F_X}{\partial u} = X_u$$ $$\frac{\partial C_X}{\partial u} = Cx_u$$ with both derivatives being calculated in the steady state. $X_u$ is the dimensional stability derivative, and $Cx_u$ is the non-dimensional stability derivative. XFLR5 calculates the dimensional derivatives which are relevant at the scale of model sailplanes: \begin{itemize} \item In the longitudinal direction: $(X_u, X_w, Z_u, Z_w, Z_q, M_u, M_w, M_q)$ \item In the lateral direction: $(Y_v, Y_p, Y_r, L_v, L_p, L_r, N_v, N_p, N_r)$ \end{itemize} The non-dimensional derivatives are usually given in stability axes, and the derivatives w.r.t to v and w are provided instead w.r.t $\alpha$ and $\beta$. They are : \begin{itemize} \item In the longitudinal direction $CL_a, CL_q, Cm_a, Cm_q$, \item In the lateral direction : $CY_b, CY_p, CY_r, Cl_b, Cl_p, Cl_r, Cn_b, Cn_p, Cn_r$ \end{itemize} The definition of the non dimensional derivatives is : $$CLa = Zw \times u0 / (q \times S)$$ $$CLq = Zq \times 2. \times u0 / (q \times S \times mac)$$ $$Cma = Mw \times u0 / (q \times S \times mac)$$ $$Cmq = Mq \times (2. \times u0 / mac) / (q \times S \times mac)$$ $$CYb = Yv \times u0 / (q \times S)$$ $$CYp = Yp \times 2. \times u0 / (q \times S \times b)$$ $$CYr = Yr \times 2. \times u0 / (q \times S \times b)$$ $$Clb = Lv \times u0 / (q \times S \times b)$$ $$Clp = Lp \times (2. \times u0 / b) /(q \times S \times b)$$ $$Clr = Lr \times (2. \times u0 / b) /(q \times S \times b)$$ $$Cnb = Nv \times u0 / (q \times S \times b)$$ $$Cnp = Np \times (2. \times u0 / b) /(q \times S \times b)$$ $$Cnr = Nr \times (2. \times u0 / b) /(q \times S \times b)$$ Where : \begin{itemize} \item q is the dynamic pressure, \item S is the reference Area \item b is the reference Span \item mac is the mean aerodynamic chord \end{itemize} The evaluation of the derivatives is an intermediate step in the calculation of the dynamic response. The derivative values are stored in the OpPoint object, and can be exported to a text file for use in other flight simulation codes. \paragraph{Modes} \underline{Natural modes} From the mathematical point of view, the state matrix can be diagonalized for eigenvalues and eigenvectors. An eigenvalue is of the form $$\lambda = \sigma + i \omega $$ where \begin{itemize} \item $\sigma$ is the damping constant, unit 1/s \item $\omega$ is the circular natural frequency, unit rad/s \end{itemize} Any eigenvalue with a non-zero imaginary part $\omega$, has a symmetric eigenvalue given by the its conjugate. This implies that the time response of a variable for such a mode is of the form : $$x(t) = R e^{\sigma t} cos(\omega t - \varphi)$$ where $R$ and $\phi$ are constant values determined by the initial conditions. The mode will be dynamically stable if the damping is negative, unstable otherwise. Dynamic stability means that when disturbed, the plane will return progressively to its steady state flight. Other definitions for oscillating modes : $ \omega_1=\sqrt{\lambda \bar{\lambda}}=\sqrt{\sigma^2 + \omega^2}$ is the undamped natural circular frequency, unit rad/s. For damped modes, i.e. $ \sigma \textless 0$ , $\zeta = \frac{-\sigma}{\omega_1}$ is the damping ratio, without unit : \begin{itemize} \item $\zeta \textgreater 1$ if the mode is overdamped \item $\zeta = 1$ if the mode is critically damped \item $\zeta \textless 1$ if the mode is underdamped, i.e. oscillatory \end{itemize} If the damping is weak, i.e. $ \zeta^2 \textless \textless 1$, then $ \omega_1 \approx \omega$. The frequency of vibration of the mode (unit Hz) is determined by : $$F = \omega / 2 \pi $$ The time period (unit s) is : $$T = 1 / F = 2 \pi / \omega $$ From the physics point of view, the eigenvalues and eigenvectors represent the natural modes on which the plane will tend to oscillate. For a standard well-defined problem, the modes will be: \begin{itemize} \item In the longitudinal case \begin{itemize} \item two symmetric phugoid modes \item two symmetric short-period modes \end{itemize} \item In the lateral case \begin{itemize} \item a roll damping mode \item a spiral mode \item two symmetric dutch roll modes \end{itemize} \end{itemize} \underline{Root Locus plot} The position of the eigenvalues may be represented in the complex plane, which is a convenient way to check visually the stability and frequency of the modes : \begin{itemize} \item Roots (eigenvalues) lying on the left of the diagram with negative x value correspond to stable modes, those lying on the right with positive x-value are unstable.\newline The further down the left is the root, the more stable is the mode. \item Roots with non zero imaginary part correspond to oscillating modes, those with zero imaginary part are non-oscillating.\newline The further way is the root from the x-axis, the higher is the frequency of vibration. \end{itemize} \underline{Mode shape} The eigenvalue defines the mode's frequency and damping, and the eigenvector defines its shape. It isn't an intuitive task to understand a mode shape from the eigenvector's components. Another more convenient way is to animate the mode in the 3D view. Since the frequency and damping may be very different from one mode to the other, the time sampling and amplitude will need to be adjusted for each mode. The mode amplitude R is arbitrary and has no physical significance. It may be adjusted to any scale for display purposes. In flight, a mode is seldom excited alone. Rather, an external perturbation will tend to generate a response on the different longitudinal and lateral modes. This can be modelled in the time response plot. \paragraph{Time response} The time response is evaluated based on the flight dynamics equation. For instance, in the longitudinal case, this is expressed as : $$\left[\begin{matrix} \dot{u} \\ \dot{w} \\ \dot{q} \\ \dot{\theta} \end{matrix}\right] = \left[A_{long}\right] . \left[\begin{matrix} u \\ w \\ \\ \theta \end{matrix}\right] + \left[B_{long}\right] . \left[F(t)\right]$$ where: \begin{itemize} \item $\left[A_{long}\right]$ is the 4x4 longitudinal state matrix, \item $\left[B_{long}\right]$ is the 4xn control influence matrix, with n being the number of control variables \item $\left[F(t)\right]$ is nx1 matrix, giving the forced input history of each control variable \end{itemize} Similarly for lateral modes: $$\left[\begin{matrix} \dot{v} \\ \dot{p} \\ \dot{r} \\ \dot{\varphi} \end{matrix}\right] = \left[A_{lat}\right] . \left[\begin{matrix} v \\ p \\ r \\ \varphi \end{matrix}\right] + \left[B_{lat}\right] . \left[F(t)\right]$$ The time history of the state variables (u, w, q, $\theta$) and (v, p, r, $\varphi$) can be calculated either. \begin{itemize} \item as a consequence of perturbed initial conditions: this is the "Initial condition response" \item or as the consequence of control actuation vs. time : this is the "Forced response" \end{itemize} \subparagraph{Initial condition response} The input required is a step change from the steady state flight. For the longitudinal case, this input may be provided as any combination of values for u, w, and q. In the lateral case, it is input as a combination of values of v, p, and r. \subparagraph{Open loop forced response} This type of analysis investigates the response of the plane to a change of a control parameter. Such parameters are typically a modification of thrust, or the actuation of a control surface such as the elevator, the rudder, or the ailerons. The modification of thrust is not considered in XFLR5. The input required is a time history of a control parameter. XFLR5 only offers the possibility to simulate a linear ramp of a control in a finite time. \begin{figure}[htbp] \includegraphics[width=0.8\linewidth]{img-49}\centering \caption{} \label{fig:} \end{figure} Although all control variables are set simultaneously to determine the steady state geometry and trim conditions, the variation of each may be set independently in the evaluation of the forced response. The ramp time however is the same for all control variables. Important note: the analysis of a response to a longitudinal step input may have physical relevance since the plane may eventually return to a steady state close to the initial conditions. On the opposite, the actuation of lateral control will lead to divergence from the steady state conditions, to coupling between longitudinal and lateral modes, and the analysis will not be representative. For instance, the ailerons will generate bank angle, modify the vertical lift, and will lead to divergence from the steady state conditions. The same goes for the actuation of the rudder, which will lead for instance to bank angle through dihedral effect. \subsubsection{Session example -- Stability analysis} Run steps 1 through 8 as in the wing analysis session described in \S\ref{sec:session_example_wing_analysis}. \begin{enumerate} \setcounter{enumi}{9} \item Optional, but recommended : Define the inertia properties of the current plane or wing object. \begin{itemize} \item Select Current plane (or wing) / Define Inertia \item Enter the inertia properties for the plane or wing. \item Make sure that the CoG position is where it's meant to be. It may be necessary to "cheat" a little on the positions of point masses to achieve the desired position \item Close the dialog box \end{itemize} \item Optional : Click the "Define Analysis/Polar" in the Wing Polar menu, \begin{itemize} \item select a type 1 or type 2 polar \item Select "Use plane inertia", if previously defined \item run a sequential analysis from low to high angles of attack \item plot the graph $ICm=f(\alpha)$, make sure that the slope is negative and that there is some a.o.a for which $ICm=0$ \end{itemize} \item Click the "Define Stability Analysis" in the Wing Polar menu, or type \Shift + \keystroke{F6} \item Either decide to use the previously defined object inertia, or input manually the mass, CoG position, and inertia properties \item Optional : activate a control, and decide on the range of variation \item Close the dialog box (\Return and \Return). The polar's name should now appear in the top middle combobox. \item Select the control position in the right toolbar -- start with 0. Deselect sequence. \item Check the "Store OpPoint" checkbox \item Click the "Analyze" button in the right toolbar \item If the analysis has been successful, an OpPoint is automatically added to the top right combobox. If not, check the log file to analyze the error message. \item In the polar view, check the "Show Point" checkbox for the polar. In the $ICm=f(alpha)$ plot, the point should be located precisely at the trimmed condiftion, i.e. at the angle of attack for which $ICm=0$ \item Switch to the stability analysis \Shift + \keystroke{F8} \item Select either the root locus plot, or the time response view or the 3D view \end{enumerate} Carry on to define a stability analysis with activated controls, and view the stability properties as a function of control position. \clearpage \section{Code Specifics} \subsection{XFoil, AVL and XFLR5} XFLR5 has been developed based on XFoil V6.94. Later additions to XFoil have not been included in XFLR5. Since the algorithms have been re-written and integrated in XFLR5, XFoil does not need to be present on the computer for XFLR5 to run. No special links need to be declared. XFLR5 does not use any of the AVL source code. The VLM algorithms have been developed and implemented independently. For AVL files generated by XFLR5, the foil's file names will need to be checked, and it will also be necessary to check that the foil files are present in the directory together with the other AVL files. \subsection{Files and Registry} Running XFLR5 will generate two files in the user's directory for temporary files : \begin{itemize} \item "XFLR5.set" which records user settings ; delete this file to restore the default settings \item "XFLR5.log" which records the output of the foil and wing analysis \end{itemize} The location of the directory is defined by the user's environment variables. XFLR5 itself does note write anything in the registry, but the installation program will create shortcuts for the ".plr" and ".wpa" files. Users can choose to associate the foil ".dat" files to XFLR5, but since this extension is used by Windows for many different purposes, it has been deemed preferable to leave this choice to the user. Registry shortcuts will be removed by the uninstall process. \subsection{Shortcuts} In an attempt to increase the user friendliness of the interface, shortcuts have been provided for most major commands, and are mentioned in the menus. Typing a first carriage return (\Return) in a dialog box will select the OK or the default button, typing a second carriage return will activate this button. Typing a first carriage return (\Return) in the main window will select the 'Analyze' button, typing a second carriage return will activate this button. \subsection{Mouse input} All graphs, foils, and wings may be dragged and zoomed with the mouse. Using \Ctrl + \LArrow button in 3D view will cause rotation of the model. These options however may not work correctly (or not at all) if the buttons are not set to the "Default" in the Windows Mouse interface. Pressing the \keystroke{X} or \keystroke{Y} keys while zooming a graph will expand only the corresponding axis. For those computers without a mouse wheel nor a middle button, zooming can be achieved in all views by pressing the \keystroke{Z} key and moving the mouse. \subsection{Memory} One of the characteristics of both the foil and the wing analysis is to use a significant computer memory. Operating points specifically store a large amount of data and lead to voluminous project files which will slow down Save \& Load processes. It is however unnecessary to keep them, since the important data is also stored in the polar objects which do not require large memory resources. \subsection{Export Options} \underline{Printing} Although XFLR5, as it is, offers some printing options, the implementation of more advanced capabilities would require significant work, and has not been, nor is expected to become, the primary concern of the on-going development. \underline{Screen Images} An option has been added in v4.12 to export screen client areas to image files. \underline{Graph data} An option has been added in v4.13 to export graph data to text files. \underline{Data export} All results, operating points and polars, can be exported to text files for processing in a spreadsheet. From v4.12 onwards, an option is available to export the data to the "comma separated value" format ".csv". This text format is meant to be readable without conversion in a spreadsheet. However, it may happen that the operating system's regional settings need to be adjusted to define the comma ',' as the default list separator. \subsection{Bugs} Once again, XFLR5 is by no means a professional program, and despite the author's best efforts and the help of all those who have tested it and provided valuable feedback, it is most probably still not default-free. Main Bug Corrections : \begin{enumerate} \item In the 3D panel method implemented in XFLR5 v4, the formulation for Neumann boundary conditions was incorrect leading to inconsistent results. For this reason, the default method has used Dirichlet BC.\newline The bug has been corrected in XFLR5 v6.02 \item A bug was reported shortly after the release of v3.00 on September 7\textsuperscript{th}, 2006. It had for main consequence to count twice the elevator{\textquoteright}s lift in the calculation of a Plane with the VLM quad-method. This bug has been corrected in version v3.01 released on September 24\textsuperscript{th}, 2006. \item Up to v3.14, the contribution of the elevator and fin to the pitching and yawing moments was calculated with respect to the point X=0 instead of X=XCmRef. Corrected in v3.15 released January 21\textsuperscript{st}, 2007. \end{enumerate} The author will be grateful for any report of inconsistent results or other bugs, and will do his best to investigate and correct them in a timely manner. To facilitate bug corrections, the reports should ideally include: \begin{itemize} \item The Operating System{\textquoteright}s identification (e.g. Windows XP Pro, Vista{\dots}) \item The project file ("xxx.wpa") \item The sequence of commands leading to the bug \end{itemize} \subsection{Open Source Development} On March 31\textsuperscript{st}, 2007, XFLR5 has become an Open Source Development Project hosted by \href{http://sourceforge.net/projects/xflr5}{SourceForge.net}. SourceForge provides a comprehensive set of tools and methods for a project's development, and a documentation may be found online. Potential contributors who would like to help organize the project, correct bugs, or add new features and enhancements are welcome. \section{Credits} Many thanks to Matthieu for his scientific advice and help, to Jean-Marc for his patient and comprehensive testing of the preliminary versions, to Marc for his natural ability to debug programs and planes, and to all the others who have contributed by their input to improve XFLR5, especially Giorgio and Jean-Luc. Thanks also to Francesco who has written in RCSD 2008-04 a valuable tutorial for XFLR5, and who has contributed to the development of the version for MacOS Similarly, thanks to Karoliina and Jean-Luc for her help in the compilation of the Debian/Ubuntu version. Thanks also to Martin for the German translation, and to Jean-Luc for the French translation. \clearpage \section{References} \begin{thebibliography}{99} \bibitem{Sivells47} % [1] James C. Sivells and Robert H. Neely, \emph{Method for calculating wing characteristics by lifting line theory using nonlinear section lift data}. NACA Technical Note 1269, April 1947. \bibitem{Neely} % [2] Robert H. Neely, Thomas V. Bollech, Gertrude C. Westrick, Robert R. Graham \emph{Experimental and calculated characteristics of several NACA-44 series wings with aspect ratios of 8, 10 and 12 and taper ratios of 2.5 and 3.5}. NACA Technical Note 1270. \bibitem{Katz} % [3] Katz \& Plotkin, \emph{Low Speed Aerodynamics, From wing theory to panel methods}. Cambridge University Press, 2\textsuperscript{nd} Ed., 2001. \bibitem{Maskew} % [4] Brian Maskew, \emph{Program VSAERO Theory Document}. NASA Contractor Report 4023, September 1987. \bibitem{Werner} % [5] Sophia Werner, \emph{Application of the Vortex Lattice Method to Yacht Sails}. Master Thesis, July 200. \bibitem{DeperroisStab} % [6] André Deperrois, \emph{About stability analysis using XFLR5} Presentation document, June 2008, \url{http://xflr5.sourceforge.net/docs/XFLR5_and_Stability_analysis.pdf}. \bibitem{DeperroisNotions} % [7] André Deperrois, \emph{Quelques notions d'a\'erodynamique de base et leur calcul dans XFLR5} Presentation document, June 2008, \url{http://xflr5.sourceforge.net/docs/Survol_Bases_Aero_et_XFLR5.pdf}. \bibitem{DeperroisCtrlPolar} % [8] André Deperrois, \emph{Illustration of the use of Control Polars in XFLR5} Presentation document, July 2008, \url{http://xflr5.sourceforge.net/docs/Control_analysis.pdf}. \bibitem{DeperroisResults} % [9] André Deperrois, \emph{Results vs. prediction} Presentation document, July 2008, \url{http://xflr5.sourceforge.net/docs/Results_vs_Prediction.pdf}. \bibitem{Drela} % [10] Mark Drela \& Harold Youngren, \emph{Athena Vortex Lattice (AVL)}. \url{http://web.mit.edu/drela/Public/web/avl/} \bibitem{Etkin} % [11] B. Etkin and L.D. Reid\ \emph{Dynamics of Flight: Stability and Control}. John Wiley and Sons, New York, NY, Third Edition, 1996. \bibitem{Deperrois2010} % [12] André Deperrois, \emph{Stability and Control analysis in XFLR5 v6}. Presentation document, September 2010, \url{http://xflr5.sourceforge.net/docs/XFLR5_and_Stability_analysis.pdf}. \end{thebibliography} \end{document} xflr5-6.09-06/doc/latex/figures/000755 001750 000144 00000000000 12246405674 017626 5ustar00techwinderusers000000 000000 xflr5-6.09-06/doc/latex/figures/img-36.png000644 001750 000144 00000016710 12246405674 021343 0ustar00techwinderusers000000 000000 PNG  IHDRE gAMA a cHRMz&u0`:pQ<PLTEې::ې:fff:f:fffې:ffff:f:::f:ff:::f::f::ffff:f:::ff۶fffېfL+lLl+LLl++lLL+lfnHH33H3\Hn3\f::l+LLL+LL+LL+lL+L+l3۶ftRNS@fbKGD- pHYsodIDATx {u +֌]n&[KvvӴ;ۦM?S\I@p{ǞрWH|`IN",",l٢bw#ȅ߸//d[BN|~P'cv'E=8܌jIJÎZvbiKWuX"MY><0jGlKfM!ڨf>g)R!YDž7m X,-r= [~```[ğыgf3{!oCv̢ya>g̫{owoGED(3w)𛡋ᄒ /&F&&3KVӖW]ڈi^>UmYgRH {߼߉0H*cqUkynA1F!թ9ahÊ~=VDE(zOE nc&q.8Eq xgp"H a8CɰEWuSOCkgW  nQZ3Zɵƚ'1MQ7ֱY<ml徜D"AsZq5:~yF{9S]_ )!@T(Ch =c]E!6B+9R',J`U"(]FZ!X(!+D`Q)t `QrN_H!"̍joS1P`<2ĞR'γѵ瑴T^4( UPy0壛K5C|hQQbWѣ59X-7kYwX< ,R-Z˺ⱎ=f'H?Ru-`E{׿\-bƺ)uT6:E? Er-Yb:ve::K2;֑ z[X8ў u4[Wuԏz[=Z˺ò6V0P&O%߯h\D:Z7X}9"kux;EXǙ*G2\E5tS HtEq1](R,)uEC Xd Xtyn8$yMf9nf ]u; HV|ȟ@! g"RdΐAcs0(6XSh+բa=GU'Mu,XGyF%r9f;+E\P|<ج9-(FX3Bda1nl{m+1aG XdEMI_$֨ǛKA,jAɿN|?w=-۹ٻEY=;g_ +{O&5 hQ'{NX>6fmX1ۢq3bkTכu"R%"6a'CFuQG1ȥz,kg Ųkܻ֩ -ܽ +D`Qx eJ|@mRG&&(4CXq.}tKP, @]Ǘx10hYk8hI q`r;t ,Z q`"#C+D`" q`7]y2ܕ q`#wQ" )`+hZ`pH9 Ld q`YCۘS,:,w` ,˰C>EC `44c80E,";aY<\-[u!jߚe,|[4Х+F,[DFv-CgEՉorZDR':4 ZdfVU[EM~kYAE¬!J_巖=Rh ҇7hE:p X\EA5nS zDPh6EpXTwCЙnQO"48t6[!klcJ-2DlAY W:WȃL-!B>diQ!?2FC4YԹUț,BC,q:YY DCEhBEhEhEhBEh’EhEh}g l"<5[m[h-]LEKVqwM #Z ";ߵosqEz/ʇG  њ,eQQw]骑zAw]omQg% \-]\оpAjVJw^_";,gsw l"4Da[Y3Ħ,{ Blɢ хؐE2Fs3Vfw?y$[h َEil,Zތ `Ѫ4D[6E#盒Wq6`щDߣvhnͯ4ވꚅ/WP=Qbyǹd^y)1iQ"Befw_N2,jU#|gNIw7<$Q̈}e׷Ӿao8E̠e,gǻS pe۽JleQ;F,VtwK- h|W#ۗȨzbKn}xr춨VQ#2b!qQUծ8WfCqM/oXG>o(ڢf,MpG;4^rJT(Z{ga|u$#\B*wLWT_ދ;lX$n pNv٢Ol;!Qwc:`Q 7~ , d$, UmrW `Q_&/`Q L"Xj-L?`Q o?>6oQ'kյ~ ;c[ɚN+ K|-XcPrXsHw}OZDYăTDYӍ,@o>!==--ʳ%:eܴ|!k(D!-U"}cL)OcD!-Zg&њ0ADF%> >nхf-Y~+mK^zufX4eL'Ek$ZhE<9J_⯼gL*`vd =-t{WNEYCh \"XD.,Z-a6R5`w?E X`o@"|+1`_qHĀE^!ncVM"H0Yb^HfW)e^M 3'h3'0R/4l_̌>xGk }z?S UbOջ7܊JE997Ԗ,r%#X] KMEOh>=?ª-"}"&?'gPE^ð3'Yghu3}CP5&)qjXpNH!HPƢgXSS9GVDI̵}Kc>Q;N3~ΑDgZ!9Wt ͮW ۋy/3Dɖkj=T]Gbht`S)HdJ &z`K!4E&wn{X[wyU$غE|ĺEl$j"3A˼Vb,j)a8H''u,hQ'uaeviEvyE'󕾙Z{'q ]G$"J4ah0E#,J,DEh&С%MDAdEX,B2qX(m`%L)JH,BdQab!QDbI???QXāEXEXEg|{X('\-]w_m[tFѱǵ46ynQEâ$7Eg&䮟Ylw1.YlrE9bW|bZ YjϴȌDŮP4##,JhZLiEHǗ81Xש?X&00Jx,F?QXQDbEX d?!Fܝ+L*J_o_|([\G춚, 0m4^tVΩ2^:e+)EӿYdYċϴ?cѫm(eQO9=P˻ѵ\VH,"5,kZw.EӣVcAy>'{dM70~>_Äi3&ڱS^IxRLvhEMU3_'F9`ڢi{Vީ(hp;1^u-= x}(kBZԉzIE_:ޕoJ2,",",",","gE G0l%tEXtdate:create2013-03-31T17:10:31+01:00%tEXtdate:modify2013-03-31T17:10:31+01:00NUSIENDB`xflr5-6.09-06/doc/latex/figures/img-41.png000644 001750 000144 00000013724 12246405674 021341 0ustar00techwinderusers000000 000000 PNG  IHDR.i)gAMA a cHRMz&u0`:pQ<PLTE:ffې::ffff:ff:ff:ېfې:f::f:fffff3ff:::f:ffffff::::f::f:ې:ff::LLlllLLl+Ll+LL+lېff::f::::f::۶StRNS@fbKGDf |d pHYsodIDATx {6 *eY8N:lhqI4I88 >BP(fb86 9!XcBu9!XcBu9!XcBu9!XcqE]+{ Q9͍-TF x{\-ʑAkr^%_tQ*㝻G%|ᕽcmGQ9>|"*5h%;/OY cF!:rCȱ!:rCȱ!:rCȱ!:rCȱ!:P?9ֱcFE~ao!nj_}sa{A"nj'hwr'ϡ8w2O)I*w^״2ݙr) rCȱq.,_%p#hٷuZyJ1tWaf(Gz5G| *OT)9kC;G`'="Ef5x3q_Z;:x%%*qV5)}OXgs8<h ++CϪ̥%%{@y5rHS;|د7PԾ[`ʪk*{^.M|>ehGs{Z.CcU㧽c M]v=,Nц*?+OثĂ߈WG޸h2N WZt~ q9zu^odHwalswHW47T}ޣ1'bwR`ī*1SRˍOɑWuTN~ uei=]Og2GPgs^5]X# 1@_m[rF(?dPW]-,|aMtq=Jm]E8 3H=RDM;W:N+7),yk4/"*?A IKySwAU{I.ޚ׾fQj8_d"X~*ʟ1Pb^ζklMY$#w, yY4GVi.k둷IUZ3^o-|+$:nHθ2IҞFx呶dBƦy6x*[W>O#gN=1$^C~km}en^q8>|siTb3>ϾPH#hF'qkR[H$=Mk^+RK}HzIy{zuD1׀gOy+:h\'ʟ5's{;"e| #vOş<=FFjE^r0.Oz qXZގ[2d! Q¼jTUm L\IUsn'JJmt$9x^ G uM!Ϥ0pdCήv9={GP gԤov>JYHyԫg]ž7őF!Jk'_ DwDr9&T\Dݞӷ@̱@MsX쯾щc,&j}c,K_uxlrL8QYzD ,y;DƱ`r=XxUG$7 :I]±J Xg፦ Dl9gOG$nEJꚵR8{e}9jW3~*c^%O c`=}5ѵp07Bgt?&++o# '5sr<)SܵOT_$ Ȱ3$lՋ'ht/8*/s<㝻G%Ց7?fI7gG>bɝrL.R֫Пvczq{OWGd;'2dښ*Y'P غƤv]91%ukؖlyl6MR6HDS.D dwdH8D8+w,CB' gQU_/$8Q ;+÷?De9(8Ց00nOőX*18{gm>Ց00P#8yH?`?Ǚz"U.! Fdqj ˟Gyշ8FW%.v!us.8J8"WDZ 0oArD0ڻ ,rd.ra_]lѶ:;VOR?9"٤@&Wim!Sr4NAП|ڟ|%aURy}*s^u7E'o;rשQ瘆\RaɅ˃#{9m KyylVlwTeqI'9洓34}Ꮌ~nP"UǓ5GY#oorG.gX^GSk%) F-F";2rwXMjJ;s+wdQ#αz:VN.O,=KI#~͉[y<@Dm1R%tcJ !V1AV {c|gbcMMQZLrpDtInUqYd/cfEK@"xf5!JL؁r`k"W8Br$xG%J>F.N]NQGrQû%`yl=Y'ʟZ۟ܧtt_7tCqO~oV gydPN-N?$0</f6N1YiG)5ʟ|g=h÷( U`ݒtIDP %6vUGT<޾qyy"7t)ҾrQȱ!:ÑO tx{(c|߁9+;sPD [|2n<<<&GK@;9q'=gQ [(bn01q:L 5 x׊qN؊J䳅w 6Ǐ1ǘ=Nm5bTGRuE=?&Ǟ_Fj0OܥU+p|o/|rTGޒYspbtXSvVvUXb5-8 $ E`ᣘjČi!L;bnÉX29<3ߍ7 r,r"P bn(1g29j2Waƻ+kS-"Gʲ`}Bf2Vb*ۇ@`be_#8b]!E5tU?9 ԚtOE|zY"qFEs\f?9*ZYu<[Qɡ]dG6FŀT 3dT1ܱ H'w{% DmKKQt#k_G{<5G>t{ W;_/٥s,ѱf(zH? *_:p32=-_đT@:֬vr#nV\vqj1;bu[9X!:ta@EPvO-nKr7V34x0ˤƭO, oϱj<Çf))zO<knv Y'P#\B IB-h`q Yr*\U~.)څ5#GS`ֆ>Uˣ5%cYV*=ռ_e!GiV^Y1g//r5M#oCpyXyjEpMjLjK+r?\q-!ҟ\sD1GyDScN͟QW<x!!ǙUSLL2$%0(׻fX .'p\QݦMX 'Ex]3;ړPB|* 24 E] i*YᗺpO H(|\P9/+Nr*#C_W`E NṠ_jyϑ!{>~f؂ٻ>Lis>A$ .L NIQcS-<& Z|9bFGbƧL)8& Z|9"%=6AJh;J ?!XcBu9!XcBu9!XcBu9!XcBu9!X}BP( UK #vOK%tEXtdate:create2013-03-31T17:10:32+01:00r%tEXtdate:modify2013-03-31T17:10:32+01:00OIENDB`xflr5-6.09-06/doc/latex/figures/img-15.png000644 001750 000144 00000015046 12246405674 021341 0ustar00techwinderusers000000 000000 PNG  IHDR]xPLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712HsIDATx^YE3:2-$N lRue C ,tUJ@*ٻzҘUw]ץ1dꁻKcVw]=f?\TRSk%6VcBhd]l|4&ol(d/eP"d;u8V_g*'|r"vPIPγPgy@]B%RJv}F< ,oK), *5UtQbvt>YsNqa:d~7h*~o?y/[ʞmY˭@dcʜRb%_ቜ)/># #xp#;,,0g]:+ xIuDɒ=4fI[AM0(X`l]* ZrcAc40(X@El,dI M֘%m,@2C{ IA$3t`P1h0(X@*Y:PL \ ,楂CAC00(Xm y h5]aPUlbؑ1{jW?  <,]!0(XAy\Uud,@ Kۄq?Q5#a1[ 8av4P@ (n JKyq0(X`_qEHFaP@1;'ս^<_l&,/8AYKQ)ETWNQ+EDOyvc-\aE=<_l)&x"4nt& (l=E/N71wld{VX[S&$#1qsRs1DLGf"v#:src#̨MgJl+QV4QMQOH*4NuS]y5`$֝yq,m*ǔ]Rؾ_K#XycjCMɶ.Y,<Ou\9f[Z/+s& +EQg+T%MkK3ǿ>: ؒYY$ۈU ߷ ۫@EnXw~>xc k;d{`ω@e#glK^"p;ffFg Np%aڙ2zR 18-g r7s:Z^$RK Xik:2UΦTke&XZZM\1Fl894wԓ٘C:7 px0JmZ?\)u)!Kv'6ҝθ(y.GbXxݪX8uԌA=bKEN2;[dW ;U Ev'[ Y"XKÊ}4z.C ?2*c+u!#Zŀ)zu%lHb@=l@%UIC2vv%K /?>걗 wuE@e27v_׼rL7/EL\*VI}P{(GDOx"Hl>x2e{:6S$kk쉮uIf2)dv/\^ZEXڟbĬo86dD6;Er2潨}*uPQF_y{!lW`6;8ߝ5Ȟ ۚ`CQkGl?\ʣ"8dO; %qލMp" d\V} Y[TS՛0Ǩ969h1{my̦Ux%}F3ȆkgAmsd}2Wzl9qz*2j/\YqU;l٭\1EvP"I* }J$9#GU] hCŀ)z`Fd`စL4mwPbuPl콹GW$[K^E6fC..=bQLX{JAdo8"Hl[@™d~u֓58u#;`oZl6#\Tr:fk=wOOz$}Ͼ_A],^)\-*@ɅA-@֮YuuvX#HqŰ1V ;֍X "6PCؾ{1لx޺7&'dO!k#l=buXdi` dC2>&q-VS$A!K@])RȊ+ﳞk[㽁~<@=o~$^\2:\ֽ̐ے !LLz{;؏5<ܤgcwR%8^>?`Ro}j`&C yϏ@W d0{,M%^ɢ1#<pm,x\xwg2Buּs9^Pk -^ׯ)JYd:}:X w)AN#bVG#gdd'{ͽ߈ G>tHVi;`%Zn놠Ǚhڮ1)%KVO39b_&wUYOP(:nTMYBd Oy4)uyqvO_EE硺SӐ&1E_$둢dޱ1]Ѝ #f]AuaM~iS<*B־UǷyzӽ ILl/.f" ,o&n\Ф#d z:tG+ƛ/oGlpr 6jЎjA%]-hM0(X] qAnAE rWŀ)bzZ) g7C-:*=rۡ.55p2şaϫn9Te&g `6?-jeuVM(lM:Ik.fկ߭2aK#pUh|8?->c;)^ m)tU5Gd[QE౸!Ma%UO#G:SsP͍yc"dF0Ā)3 N@ [] 4<3w焯 Ț|IXAjW!G1E{k uhk.9@g)R!jGV gu)& eINJ`w`mG{{ ,v}[ZE[(uֺ^Vl+DL7o\&qK \1 bM֦iѣ ?Zp\6aaNinlI;ӣ`; ڽJ[=p.ݏG2@7MSrXyS:[pE[ V"Hy!#ʭmYY g=.(YmE ,p?3rS$ `YöY 1(>-*bQLѳlݍm*[)YJ6iQǹG1 bM.l}J66:.(% .s`de 8*}uPlېMRβXySn5޵>0K[gà1E {VƛɅc{+DL%ȞVlflvftM՞ ㌼h鱏8}mx]AֆJhu{JxFrOdKu qݘMsUu7ƅ@x6O0@jR_|Mk:K]}S:#lTۇW:_ zY|6ljĤ$5`k' YV]! 蒊ϽG-XV9 + Y17: e׋r<4`%fw`u40(Xkʍy ٧\`\6Vuk\iZ$%;}7ɊP%5eP . ho<˸] PJ֣r1`:F0(X@fH ¡>D`%dnk퍵7foypr3à`gwaPvPctM PJX{c''WX`ڞ=3 x h5FD`%dnk퍵7foypr3à`gwaPvPctM PJX{c''WX`ڞ=3 x h5FD`%dnk퍵7foy䚌[=@(z@6}EfXud?2uCXɒ"&J1[f* 6Y }*APQ|DUVyT I:Td"bqJPDLR"n\P]IJVč *Q B1IɊqA%JvA("&)Y7.D.E$%+(dEܸ% Td"bqJPDLR"n\P]I2IENDB`xflr5-6.09-06/doc/latex/figures/img-16.png000644 001750 000144 00000011527 12246405674 021342 0ustar00techwinderusers000000 000000 PNG  IHDR*z DfPLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712HsIDATx^[v( sz{MibsGRNdT~#~*'XM%X)X.JVJt .V 2VKpR]\`eDb+c$~~pt%U%ۥ/V{{Eql̊=:0/MYMhu =/|fie5nX(҄[ u+:fj3\ +C믎 GK6\ь `0wt@fTt" ~@P풽tf"&]v'ƚ Ǧ^tϾ;T4;:ڋ%y?꣓SAu ng㣾\sRp"&+X+%X)X.JVJt .V 2VKpR]\k*5ot7v(dLDfAjTE+Iš~jF,{mn t/ !9[<|t9{L/u_H9GȌ}{TpmoXէۦ&\}mJpmoXէۦ&mƥ =WS vzd2W‡Ɨ4rq't}ƻ*?0;?nA[rpE ֩7qje$[]hC2݇^#~hӵjL4 32D]덇0ʹoȧ $5 ҋǦ*,v= Cf?JMd-^`Eec?](3Vp%ﳽ7ђ, +y)䦂+!JK義[}[,Y 'idX"缺d/]6 畋uˍ2Üo uX1ql|_ɸn[3L;p4\v7WPM&M̉h lQh2S6² T\p34X!=P&ₚPGe[H4]8v~ԚkRjלLEa׸ l.K3azl.ߋ}50$պKpzPh WhM~Ve:l}˚pSpmw#wEՌg^+V-#`#Ue+7ZZ F&\aޔrZ Xèp\M.u%Wq5`ۚ2p]v . 6X׮Rޏ}KsEU /d\[KG0ݰJՉ+S.j7?+P40vKh=ڷ\¥gxNr@?/^γŅI6`uXѕu!p?"£5hlZŸhY7܃xB5ngich=.Dt¢b#b {Lh32q.2$¡d[&ᘄ+vZ+qaJ&8¥Lq!2)ߛ4ݝ)C. ZMCG<%fQYװޖbzV\WB_ [rIᔅ^RJkMp)e2q]q3[+A9:Cb2,bYO- uGO|`jC|c;qys YK2çb8oM,` /.C\%ZZ]¦Úkqp*];pe7y"Yd*o_dO^t\|%i(* 5^>\˦aT\ \B+ J@\;Buگ\QJ [;^noY[q]{pg6LAߧix`MvVm1ZpmGζƫ S  lƵk! `P\C˿k{p^@\t9k7-D\oW)o^GS R` $)rxNN :.%ppѩUsBq.k~ç 78_у -D\)ZZ )tB_[:>-t#-̃dP1EX4\z߲7"E+"") 5?!Ԙq#(9Ď.j~]d8WW9Zȸ9Z8". EOE+Xaz!i6Ҹh 2Eu+p$px`<6ՙ>tJ,.ʴ_+^\tB<{pEth=ǟ;p11Ǿ..6^Clpy\ hƗry8N\b\6'7@ۻ*H:[APUo&Y yMCqb{,75!&yJMe5.y{_c[T-vg"jU"2JЧDِWe ĥP+Ԧit~񮐷6Fj㬆ieכXyڜuZCt^C{׳2,cV1ѕ؁eLբ(HisE׀K75ysD.0]t /+J\@pT{x,$\3D;VX!2G1k(HtȸJiqq][˭eqK}B`' (fBo7C,4.y",.K%]H- ?"Լ:>-R%]:ROkݻ(:u:[VO '83LO: ht zc݉„QKp5"b.- (v3hj)Մ^ɲ{?,S 0ʸ0%6\@u|5Pz4.BPOEZH5x&SU3/BpeEǕn Ŧ ~'u'rJfDWf\h2/{:v<5ݣ]v+*-sk}BRG-rs> V",{I!x\reCKq׷{ޅ5u .(j;$3r6\S'!0vDchיj.(z;u%zĴ{"yzꡝȷ08Ì/9WH}af3gyABslf*>γWe!}pU#uiV7Dom2a\>lJ)a2,D/hTߤO@rbU@p. \3%<>S\gvVE qхQLp5"Ԃ15B򷚒ťoֿ附gAMA a cHRMz&u0`:pQ<PLTE:fې::ff::ff:ffffېfې:f::f3f:ff:̙ې::۶::LLlllLLl+Ll+LL+l:ffېfېېf:ffffffff:f۶ff::f::::::::::f::ffffgJtRNS@fbKGDf |d pHYsodGIDATx]۶.'cǎIӮ{oݣ].벮C@DROHŏwxO `0(C0 cX(G`iyG`iyG`iyG`iy\WəY`'s[x'csgC;J+Ɓ0ZVp'w@&/x'82ywj;A?$1y# 04<H# 04<H# 04<H(906^X*ad%Jぉ<QQ)u^<< hC[Uu!gɪS{ȩ(eۃAqҢ]5Y8,[@WbVKljКxq#ǍJto;miэ_jL L]STYf̂Vܹ0(.`m:rH+D<>rDv¬Psg{[+Ѫ%v:$Q*䣆S QW5r f`i >0Z5Bv&Q +ZZ}\mS[G?cu: '>Lru՛ORj%TbXZPN0NE끧U7E޳vB;YZ pZ7F9ʰZZ#.E=$MKkUTԳΘͺ.-G7vy]%OѲ::Ƭ4gυ$ W=\LC#.eDt&,6mÏ (S*h#8P?5*u7Di,DP1-jݬAylAkS"95]! Sx1XE맾g~j@_,>,CxZ?q4j'xZ"!N<1O*Xem2.W) -㡁Z7FWwF'6TV(CTQ5oftb\Ķ7(g]Q# _7EuGi ߾NM~\nډ"8G3z'Y/NTx̺ԹBTSOxzt>p<kLO5= ܾSV;NcG8\vN' naEI8"; `a#&XO<j +x~u&%]yX:# fU+a#>)x:^CV{P^@Gݦ454,7kC:Y/ _@]?<"IaxxCxs`+6Y#E>:߱V#ϓD~%"by xL^< =c`*oZdNW3BD|zW՟'8 k=Ϟ=^&Tzm5z|ΫkyLSI +]t,_= jc߼ۈױICǧ>h2>Noݥ1t 3caA2f/]ﱫѮ*z%߷jbvS:2׵Q`wڌp|އ*L4I9ÞE U=XL{cOu}wq` vU =.M?A]+5>7VR>7#lٌi]xb췧3casx}jcj % dz6^L#}*c .[aO͂_؜53qx+Qy^`>o6}<+杦tl4w!}H0k=aD.?4M\oNمy7oϜ)Tmjk:kRoM'4]C0hykz ##%y\:L$uHf ʏRX\z BVG' j<.L \aU Ys]F\zLJ N_E;q|TsFA shVp1Q/@w;Ǡ.c{ }v5p$ƱtVgB^+~x-p$n7+y9/NwH]9BHoc!YR7/e9^N2I2n!p.ZXHѼ};gAy&vAv-x [XHqXMzYCeBsj ZHH]l|-/'@αT< w,'HsD#E?$H8O:IdΓHj]Xsf짗֣ /z}>?*ma))*7+M_ּXW8䉣S6HÕN#eђCH]1I6ɤ!s܁{ `LøHzq1dž>7 0K\/1 RW `LΓCJ9KpR>|Rf#w) $uuV&%6_NxmVN6ز% H+j7CW'&% )Lw7k4;`Du˴*sX!% Oce4ezh:,>оg 2 ʎ<ڔ X Glr&#HAy:QS,6_L'"%y]UKH'̣ q 0$<Hq:G W06{A1;-/>]ޢ5"k;(ณ8%[)t)[4ǟ>Z/ |[>֐!FsPN紫E7PxT4ڋ x\2]@#ťw[Z(%< )LmWBiZ/` H|fʹrF`kt(?K?0*9-(onb"(/[-׷i X̅AqzДG`iyG`iyLlrU%Sv霞c[nKc~N}1cV ss.w? 9WyLB?o2Q=! XI%{>e/T~: dfeqf/Tb$~+#SiX:c/*b}L]+oҮ*INQZ%3<H# 04͇JH̓r%#"^#}C$hMb>9.tr4G`iyG`iyG`iyG`iyG`iyG`iyG`iyG`iyG`iyG<2O `0HxV'%tEXtdate:create2013-03-31T17:10:32+01:00r%tEXtdate:modify2013-03-31T17:10:32+01:00OIENDB`xflr5-6.09-06/doc/latex/figures/img-03.png000644 001750 000144 00000021315 12246405674 021332 0ustar00techwinderusers000000 000000 PNG  IHDR@!_PLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712HscIDATx^]َ* _1?H&f &=Yz0.4O ~&jUEHI0h >RL!.t{GԔE؁Yngv2IE`{iڌLPv93m8:κ 0nĕ c}N **t*-ӄNZhr Q umqᖡ]\}ylI?@9cS 8GVer_*nQ݀F2֑cLJl6k=UWge!Up .9yQh`ԧiM2Xʗtv& ESNSYeSkP+89ȣO`4-͙Mm72B( ?ꀞIT-` (!`M~8$?@bFMpSo_E6W F& Y Ż )[նn[SI 82.y:#s/=s#|V&C6P8+ WWV !X0k,@"Pq:?Y܀' ?!|5e¡^:EGzCLj[A@ʧV*q,0NWrH ú˦UawC?B<ƒ^WD R}aWng&P{%+;m|lj!_?E n$MJk@"n]ѱ>v3?~{0)lv<[О $#Nsvɳ(P1:8 t1#Sl˷@N*FDSh DZ|F)ƙJd qgማuϮD_Qx豜qsE[.D jil!4!151&c%,_JRMhƂ@/`O$6(@h|'W޿_= 'X \,W88Ώd]DC0ۈΒgqOh7+hU 4@Uh DZ?D+ϡk ty ԋf{(1= K>VoK 4L^u>% ʑBGګec1@،0qKQ_ TBYr٠Y8V_EXZ0"gZ9~.3DbM w88C]; T ی9B8~R(WzNj6Q 4}BE0"yg\{ !°_vr-8 SE A9_]neop!@o#@E1CA jil!4!151֓JY@AA-w-]Y8p /JL l9(\ A#$—J9U뜳0p1w˰p$'+EJ }EF6\ޛ)8N⎅&@ª@a`#B&8di@-pC )(%49 x?MTҦO`=+Ln݀hԅ(@+ܟ!J..e:R&ΨKI 8͹c~UϢ3/JadԆ .ޡQ#0uXo_cz{ XȠ(<# izLK螏Za͘G~.L0,@%Ras]eo#;@5*l]N9\Y= Nަ~2[P9w# #x~oϭټ?OکRTw:@3%P=LtLmgaJNP^oÝN|9\M: Isf@Ι"pa&RWiڂUL };={, {ˆGPhͬ6/.Ƒ͠AUC`@6HJ?]#ivp J82LŐ{PY\ @3p82@9)~?O| *U*$5u)P qe>Qx@@ ?}x@bGFƝB:982L*f%P BE < }3p8t S6y;G*1)l#\ rBmc+Ƒ= %P99l.Ƒ @DEm 1W#hӣbpb 1qd6Mb,x5öHj 1qd=..Ƒ2iBFr AbG6(4H bB}i8@'fhc$fqdmK.%P9P*+Ɠ)lM <9} #6ޭ@@ bbph]#w J9$bӓ62OMbbG&r І4H b!'FͿbW͏^)QPȒhS* Z6흭sfzZ=a> مlh]#(櫰aOzf@M/.Ƒj^@AMlNtp2kR \1(PMj8BBu8BCu ze ́N<~"$fqH-8BFTbp!i<)Xi \1P*PK߹FQ b!&P:8BMlpxE05fBc3p8B@e2=B!1q1<.ƑtBRU@E.Z3p8Ur!L&w1[/A\  d7oLZ"6ͻ:Pͩ˅F%Zoo,ouq1(ԁWj>M%NKyBQ†$PAu$. %ХV%ьLjF9Pڵ=$P @) DBmV/̉(KaC 4LJTyhl;Z 6*dXT|RqD@aC=)ƖK [/SD8). %Њ<"E+lk@c#B(lMa529&4RP'o"RPm! mޟuB(lj:3O"%D TJ@P͙̮v8z@[4[p'R̈ρ@yuh AiM@(iiX*pd O ;iuQ )gK.# `=ps]oGF$!PZyOGCm ;f$#&Z\@1Eu - Kʯ%Piw) QY[mrK6?zeKA1ZZ'Ij́CXc`6,ƈ1mGd oF BDSE~ԑRY.$Hٌ[8 GOaWsLj[ e#a 7%BYv5@Kƨ˃4b* ڏ}]A#U_629a Tfr9z,r4hy6efFs^h9uq.UkXEIH|Tΐ )@k$hQDbixwġOLcD 4 kV="9Qk%?>a_+5CiH(,QۈF6hyǍfbT1aM #6{7h49Pf%ƶã)9p>v4 T(/:[aX  w\0(Iprfhdd%)4|hhDzb+j!F/9Aaƭ{,j|y֟Ld eDP- U)=RSj)ɢgEi䟿n~L=U/2w$ga$.}>{a֞LaU6(PTt3FU2!ȁBҦ + dSkY '@=~pyF4A#fOM@#>^#V0Fl$bzPzZ @nG[ӃO(@L}a>Rj* ݵ-Pc|GUȀ=չ+u=ƈ5y@bwiR ʝ:vdeI@ \bP'6ʿ"f [- hx+p1R};q;@P0*s@t2SX]i0paR7RZ&8+'NdMτ4` n&bg$_ee|A% i1'{ȯyN)$rgw\ZdA #807xiGXC wCwU ݧ0BaDJQF:0˟)668ذ(y3@RNs 6:{_# 4pd>Lh+{ݑ^xaNVIt`z{uW BVN_bp)и@hӔ^@eorik#fqdX*ɟ/1qd3 *8@!wGV:r:8 MZTo"6u@3 mnh  \1d'GP!A=AvZ)KaZx6 m1 %)lldHCYj&PdXbp&џTԶUm40@aZ&@bp'@ުyذt@h#h z]La6`:{UF#1=@;ؒQar)@A`D 8Qj)^GP @' "M\ |&܅B&64v=3p89,5y/w1!vlGn_oK$o-W59dS{ \1P 1" dBk @g FCiL'C 6cj6 b{YP.Ƒjřb/w1@"@et\H bQI\ NOOLajO @O#Da†*3 J24}Jg4"-́BGP**PPC)C ݧ0Ba59o@ I@h*hZ)t [*3 $w12uU U Zm**lA4rZN R0C64|4JF(lā-%4zևPcJ|+k:6Qh DZ/ل} +Tո`*旀bp 8j%k/L%EY(|̮m' IV%@绸4} wc\#\#`CVk_ ěٕ6\68J4_MhȽ"n74'Ꭰ0d~z>{` *B~ )%K6vLHš_@fJJMmr 6IQZ#έ%I[/2T.|t>M'g\oǡ_K9'/3j+(5V-[QɈIqۭTd)`J *>cnzޕmyW6!oqn%CC|*C $X'Sd6ЂgoYc@xtYaw1F*>ܹ2_q)ːDp3Wa3caեuC e {,  Dԧ9@s}}m%S`%~__[ #L/IENDB`xflr5-6.09-06/doc/latex/figures/img-32.png000644 001750 000144 00000040301 12246405674 021330 0ustar00techwinderusers000000 000000 PNG  IHDR&:gAMA a cHRMz&u0`:pQ<PLTEffff:ې:fې:::ې:ffffffffffې:ې:::::f:fff:::ff:ťRtRNS@fbKGDf |d pHYsod?+IDATx݋vV DZd3d9ܺ3sؠP kr$q ]wxpw;;>S{ 6jQmè66jQmè66jQmè66jQmè66jQmè66jQmè66jQmè66jQmTO_S5)ry6WWuʹ"+1_]*ޛ:8my_˯^KGGS`u mZ]jਸ਼avٴWg{jM-r:T朦Eu]^\g}tiPmR}Sʼ;>l5ʨ69Q)!xxh`y*DN6.m\*dxZIEVR//dWr1fش3y=//S#((?TtmB~\ϟg;߯,mY|]Uɳ?ڷ˥WOW)4b+7^^iᒢڴMvdC$Kؗ$j>UN{s6,ծNVތvgџ:BRzf>F=$efdٵ#$IEV=JxCSn-E;iGzV92Bx:.mP-nï|yoL::miݞN18\Ejϖ`m#L{r[)Br]꩛Vz^gpdCкKS/n7ō%F׽PwiT۰TG\[ù+}mj >x5rݯzͿ~նXjKюnZylڑI#$o%Fݲ]چO5'itsШ9jG- YXCde5o54ra}Wf"l(E@Mܜ~XF ;W+6c`j'[z$L|+':} N8[?:XIDYv_xM,Ka競xQ.n0BTleV }Ҕj?|L ~~kT۴T{8`)GqS'ǫT]#e6͟3Sxo¥mZyRC\;?AT|7k?QmS'ёɇT$6hё%]#6]b͓}oǵSß IHZG ;KtnUDOAP~ʆ|ڱIE/> )7T$`Q!LbjDy_IM;KwU3xl=~v᫑I?WUȟW6ڡI,ܯTΞZ$6,ծ]HE3b;{';-^.݀Ƶ#%o_Jr7+)7yFF&odR{i햵vE1UJzMm?յhM*2wwLpA2iSDsHҪ×~mچ}ч#0۲ڣ?*_;8F.N" q[[#~ˤW;/ Z$6LơW#m?<;OT4.'z)o~ڦQm{]Nj%T,` K6XB Pmj%T,` K6XB Pmۚ Smۚ/5G`okj|6]L✪=kq_=6T'Sb5k֜^shA lhk ^shA lF-(a7C Jصd|] P%Z -(aTphA C JصZP®Ђv-@k*8] P%Z -(aTphA C JصZP®Ђv-@k*8]k? _ |6(rj=N>TB ڀCT0 8D ڀCT0 8D ڀCT0 8D ڀCT0 8D ڀCT0 8D ڀCT0 8D ڀCT0 8D SYϟֿ;^s俼\^]d/CKY چQ_~]5y>E #ei8櫳M'TG #EdT{Bo{mT0=4ho+OR?!T0=T6MSv<\Tlje.K O`*J` U b2,ʼnVNf0Bq[%*F Zz2kT;PC\-Htb<! /|UРچQB>gkE{_/~NG!7sJfnՎ-T9zԏEFՎ,5m՞h.'80jS,2t%L,IOuy L8zVdE se+䳇u.aꜧ7 9Ksd Ms}cwmjFe6~} <|x%LP`uS&]nvpv6jŜV{00[T;xT;jFîe蕲T;q\{T0=4'CG(GN|cǵ I^jFt̢jRߺIcVOUy=$˓-ǫp QmèPy̅!2M,=MvWқK[9R_{y2ڠjFGJEsgtѽ Q~okݼw '{Jd SaT{WTچQm!mچQm!mچQm!mچQm!mjgm'WOiߑKEgs6rh?E:}f:i6Qm,W;۶jT:ŗY6hsMb׶T۰T<ȚHRc٤Ot&0[__Zpۓ=kͥ ԿxEjwUg#u+'8\zq)>?<6isavXM<5V{WMl{EdE\^'&0RՖi&!w#ݟkI~5,ag?LdVA?CW5'^Ϫ7]~jf~g"G"<]r;Y~#{HbCRK?_"iv~ ]>$COܛڑY2_Y^K]nLH߯T䗪]_=ŵHmiodP.;tՎ<ȱmPmINЍJgi)$Lvl%5E3ܬDM;OcCv}u<5dtH;{ /g{*VNu[#)it.H&nnXcCVGKkO30jvj7P[ljM8n_~G9 W۩vI_s*XYD臜^䳅j?ɵHmjîjg'YjFjf'mt#;wPmè6'^=.چQm좹CHsVPmè66jQmè66jQmè66jQmè66jQmè66jQmè66jQmè66jQmè66jQmè66jQmè66jQmè66jQmè66jQmè66c|`[cx'ġ%Z -(aTphA C JصZP®Ђv-@k*8] P%Z -(aTphA C JصZP®Ђv-@k*8] P%Z -(aTphA C JصZP®Ђv-@k*8] P%Z -(aTphA C JصZP®Ђv-@k*8] P%Z -(aTphA C JصZP®Ђv-@k*8] P%Z -(aTphA C JصZP®Ђv-@k*8]k?.}{˩w;x:ΗSզ 6jQmè66jQmè66jQmè66jQmè66jQmè66jQmè66jQmè66je?Z// ~O_Zgr`6jdn|[j7??'@ e|^kMXOaT;[]]׼jkVmu? mՖ ۺm参jojFee?4 y3V-dNFHʅWN>.z䏄UZdVA UMj9IG0^LQmèvH!Ƶ.4#,luϦdKcj7QHM` 1Jpd#S~d ԫP>~(6P>0vGvMwaT;|01_W{6@QY)bRpL\i#`# UNmge?U8D 1c j=V|u|Pdv>[fX'7V12Buډ?ȨaT{I&e;Vf r*Kvo̫nh*Ǫ#jF (Q vlPDT0- ROeBR]8ǞksQmèlxA*(Ŵ^+<8ǎkjj3}?mՖeQ1݌!HiN`wӆp_4u{HBSL&PT;G 6jew&ܯ]wNUw<~`4uCS߯Z-#jF[ٔFV/eA6 t4՘]"7Z/b5j>To2 -N@@ !ݛl.jMv^KɄ7@&N_.9$Lj@!xSPmèvXkaavB~K3TeN`|;ܱU~d_t2ڦک?Qmè/+n:ęQmè/T5mjF ھPmԨaT6jQmè66jQmè66jQmè66jQmè66j-}#|چQmcT0(  t[ڎQmèvB6j'W1T1mN0/'%wcXdEo,_u6ڵ؂N`ڈ |e 6j'X}]{dp?BuJ?>κ2mAmoF mNEb꼰[-Wlj>ong:,O|AS^Z-zmH`aT;j,?CEd6OK j5POX1d֞OYI=+)r4ڑvlA V;L^8)XW힘k4fs۸FbۙH P]7@C VV;vUnᖉ-u x[oɗN B]Ѕe~tf\6j'X_`c6vseMo+TWo#K *҂.,UJPmèv<}m]!\3|[9կ& $,r{mNps;Tv%|$eAӖ9 #+QmèvkkkZ]$5կb4m2FI֠چQCYV{HnQxXR3E$6j'~j5O0>Xٚ-ޯuy'-ӏ9o҂ֳyk6Tu T0`&{#]=^ib)枷BӍϰyY{#ҍx) _^Uq5aT;AC."CXl՟˳nKp$Fv!in[5 ,S{?#C2|{xG T0("j9LӢAkrj偊mV`Mҥ27^jFeچQC7gaTPSm<6jJ%5<6jJNT0}(_^GچQm!mچQm!mچQm!mچQm!mچQm!mچQm!mچQm!mچQm!mچQm!mچQm!mچQm!mچ]t/sػ^ qhA C JصZP®Ђv-@k*8] P%Z -(aTphA C JصZP®Ђv-@k*8] P%Z -(aTphA C JصZP®Ђv-@k*8] P%Z -(aTphA C JصZP®Ђv-@k*8] P%Z -(aTphA C JصZP®Ђv-@k*8] P%Z -(aTphA C JصZP®Ђv-@k*8] P%Z -(aTphA C Jصvt;^Nӱw6_aTpjFaTpjFaTpjFaTpjFaTpjFaTpjFaTpjFaTpju勿\^7\>)M_].F6m/kSi\36Șچ9[ϫ^LT0~>TA s[^7MT0Ֆ$\=ǵ"M|Rݿ,:֫ ] -@fB.d s6g5//s#((>T&z.&?圞?w_YKa~]ȕXV; ^,(v U% n(U׫j^pB4߄jG=4X<%ϫ`Ȳ8΁je ]uOT!+(3^OY 7Q#.jg}djwU_??Mܢ S/m7ad"N=Z?sچ9ء[fCEC!ۤvjjGgfoլ?kLߞX̦FM0?CNEV{4@%6mŮ z7;_W[)GJ{H䜆g2V^s>J ]߅h'*D1(\P8jQ@6Y@:sa^"\\oJHvly& WL|+:} .t{-qM~;WG+ngEW9˝Pm8Zfy[ߥaB7Ƥ~[|8T".Tx T0Ֆn:x|;r [|H6O/tS^!L#~IRP ^ڦyv`<¹vv /Z:pEn9~ekGh~jqY"i^#)þKnhʻxg0g"o%(L9yFF}odZcmOGR_uy6mC7t gfw7c9=;*4P]'3bnȧb W{~A2ujG&?/|E [ dsW)AŤGYj3эJG>7<з9Nwi /YQ䳅jz-jPҏzxf'mum?OT4kӥ;!wPmè66'^7!l<<ʅd)px}qN.{%6l$!kqXI24Pl܁p'a#akd~r/caSF:Fw`\b$͂ Pl  >lh{큏x=8p}Æ](6p֐lp Z`_8_}Cqyݱ '8ǧ^Plp\iCqXo "8:wc%Pl*܎Vp [r;YMCap{XGI6,sp}:'ppzi9]3¸c%\+CqR W ps;)VPlppi]Ɇ#' iV0.2Vr:VmeXOry߇c!X:6WL):]] z8mxѱՆ"F+vjCp[\fc3OK.Sx|yC/D/ fTӹ\~u`v\땍-WQO{KU\x&aSnKuNPJ}<ԝVɍ ?^k~x5]HXqf%D ,"9Ibi<2 VACT:s0 j'&^5Kj}*gV;=tH#Wυ˨EC2{HҖ>Vre:*v%9jmΩ Uu\n&Y.tFnAG=>Ba3a\;!)Ww:#xKUNyҸ`N߯W|\U:)뜸$2:F6oڑv]ʡ}E:'O{#_-!Cڣp\Is>;Yk~:RX"7Cw9$]>E]:}ǫ>f'T;Tv#,qQJMb*>T5;Nʫ^" OefT;TwpXIS~znSnm nm8 nm"۠>c%T(f6pSC$8rS؀ 7>&NkuMbF="ThH6`z0.X > ^!p )7TORO'UW:14#sPtM;k;&\|)+(\Y/Ie .yh^}Q}|5{pUo_9}mϩT;͆p$o3ct]N&t)tILOz\|W`>ujQFW(8{1$+T+ ԾʓJv9.Rtτ7,,{xUPdN- E jwċhj7wj\T;Lr\/XZ~&?[Ȝn2 ܝM]K!Hjpn-,{pUB_^'^Jפ4kf}v .=wkD(orGƵߒ^3zn=$wkw蠇0uj7={yt\{yN pp!)"w_MlsbK[n5l{H(6n<;rv1|n%_\_{n"y =C+_A1vdXQUfPJm0.!Ql<8^7ƾ70V`\GB(q"q t8Ɇ$nFac%qXF ņ}r NqGq6'FqNn ņr8Ɇ'Ql)7$~nC!$0V 7bsr87bK7di+!)7I6EI6 e `c\E! <'#n|pN$ c%Xq`o(6p rc'nDPl8冄l7F(6p|- XkϚ` Xkj`G{|B Pmj%T,` K6XB Pmj%T,` K6XB Pmj%T,` K6XB Pmj%T,` K6XB Pmj%T,` K6XB Pmj%T,` K6p:o}>nUB-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2'돁׽cO_:X3q]Mj|y:$)gB-sQb_/;U{mRwȿꓺkٱ_ys8jO͚gS𶋭Pdd<O Ϣ-[f./m *85UT۲W;a6gY.ՕO V~Mk4jǞ7jO+/W[l %U;4SBJw '٭nmj/?\Mu.)_mIo[sWڋ2pl %U;4SdvTնj1KnעH H ˼GHb.BIE.5μ]PmT{HC7smjT݌eV!IFjǶ]pR!JlږW#^5r4mjN7vwO?m}i8ډN-DqםIפ}\;8~'T۲W{/} ک`\;γ*^lM^0\Uڳ %}m9%ږڣwoTj_H7E!I 3r:=$ZulðgZ=LB-;?=*~vjf_ [ O@>Oӣ_;BޯEvSltT2ծ.YՇcLv>m{U4/>>{VZyodx6{odxj3 T8]!I_9`OttФ&znǾ0/mFsHf+V5C2EڣB;ajOQ, ٝof8{J<5 >5#)gyB.Bis,03DmQmu@-ڛ0j[F7Aa նjojmՆ)T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T2 C-ڀ?T۲ n`{v?ɗ`%tEXtdate:create2013-03-31T17:10:44+01:00Q%tEXtdate:modify2013-03-31T17:10:44+01:00sIENDB`xflr5-6.09-06/doc/latex/figures/img-37.png000644 001750 000144 00000022144 12246405674 021342 0ustar00techwinderusers000000 000000 PNG  IHDR"cR gAMA a cHRMz&u0`:pQ<;PLTEې::ff:ffې::ff:fff:::ې:۶f:fff:fffff۶ېېfff::ff:::::nH3\\3Hn\33\:flff:::ff::ېf:fffff:ې::f:nHHLL++lL+lH:ffff:3\Hn3Hnfffff:ȁɩtRNS@fbKGDf |d pHYsod"IDATx uMjvgfw%O2R6N֛IRݴIw뾛_P\9G+BApq AAE !. 9D "C@r@! 9D "C@rJY<{Nw/؛|PZf+jѕ#¬Ȼ,+_ey{Ls{˯e/Sw>zM8"D1b ?p{G }D^ F1y$r[ ?'^H 4fC*e?!u4Q]oЇȕ0ڗ{Ո˗BWEDt:MDVI} D$"ڗ˲oV k"Z @! 9D "C1"BNK[O]F6ffe8q7tmf1c|D .#DdHD_c!PHfm>erͰWswXZ$K /ed~cy-O7qi"+aE"HnO bxEId[([%^ܬEHy"3M(/3!^kaaz7=scVĕܝ>Nߨ{BD|Q_q;ط+Dd+w_o & #E;w|}M-ʋ5_ ӟf[g6 :adʂU-O! Qqi?qe%MtpQ4Һ(ѧx,1uE"7Wg}xGC.54*ԇ~Ǯo@DĕEiSwWU\FDD! ,u\*( gLXr*D?=aEӛh(HQ#R549$<\ $AR$"@Ǐ'?b)G2V$:"XD D|%R N% +)ruD,uvE묥K9") D|%R N% +)ruD,_I b J 2#q;bjK^+r$cER b J@ĖZ\U/#XJȎgk>uD,%l%~ |['@D05fD>F:t9-ؐ/dLE R Nj0)tkERQ( Gg?V}_`HD󔤁miG4hb\lZx&ʨI"JiD҂CwI]n$]MG!ص2h/5SgntLDG "r!/ ܤ]gΤBD15D̖ECZ#k@Wث$㡊MEKzZ@WTzT[~ :roʲYfrN"f-Jw]Lv?LBԠaB8"ndʱnD|%W}=ЄԆ-@$*Gݝ 'mKk_I3N A;?HkR a{- +ir45"•n>HK^kr1IؑDZJZ˱?Q'7Á*Ȁkj9Mݓ#?<VWRrX&\"H@ti)}k,~fB1L>•52:lc`D NFdG @[!~(nTW_"c3rI fW}O1i҄z_1L2LKqd^D eQ)eDz"xzD|Iia(eD""f 57cdFD ̄0@DhY)a)eD"<1fIRCLsvzQ!4q!"HR66),c}ˏy#e+bEu&eEajc^T#шZOR/e-\E>D_o6";c~&!D*{g1Z4" K@M[@WҘr̕z&d\ P')8Dž"$0" (j:7"BeަsAd8^Q29΍:`E|% *1OM&cE|E"RAt. P'a1΍:(L5΍:~& d!1Wԧ ZHJ^zB|n$D|%u.XƎ=+:NǩfAdR/ A;ȱӹUN4p?+SABUB:x  qi "Vba!Su2"UR +\n 2oF==E/!;"3"( d N"{!52DH>2u yyT! -oFuJjK+ 1"iBS1MHD|%5H7&$"jiʧsǐ"" 4"N#B&$S&$oҪ +I"jHrP\@WJ+JM"NY>Hd;у;qʝ$S,DiIB,gHl㯓p@xS䶳 6:H)ƹ|["xzˈ80N%̄"wf#bfy`lM2\!D_~VAL>D:HQ^Hr8jˈ<0N&:!@_nlD2"~I4{ȴbp'Ņ}2blE ]FHvVGV"rF74thHl}hf#ry`ltNA!y._>Y!Ýt}]FETPHF˅0oY$.< N:%C%[8F"ĝTB!3x9T$I] DT_,Sn*" QҶH TtlGLX"vYC`EńT2 rP'de 龘 mu ^<_@[RiB _HrP@SR}r!@ "ݳNI+$okcc"ΤRt+dr! r\!'L嘭:BdnGw)M N3V(Dx9Rjc+E>(" ~*3!A_'2rpBz &[6:QA!+WdiEdMċl#d;!"MHDZs=,nsGNn0$d:9; Ғꆿ^_DɽA oi<"⹦%!ƒB#TK1DZr=Y^6{ld;h'rW'z]g1U?@? qCie,"r\[DZr&YYƇ)"HY2,判:RY3wjQ8_H2v(ƸD.+nhvdDZ!pTGM@DG%↘&$"DdnGbWwbC/G$Ѧk"'D~pڄ"^6" a"XL{B/d赀HT7t^B׉{1"RFl~usuR*B29w-"-FHV+H:1V^}ֽK)#Rm6Bb{tj!@RʈTbAx爻Nh*($ u+lp}Y7=)[cōn_.kk˂&&dp aE"DlD"9_'8U~e@%׈6YsR{P {\cFH_HZDZr$D1}2 Ғ!eMa:|\ g0!DRGDAe@% :Sɷ܄QHŠN -iQTytDhiSDŽ\GDSձQe@%)?kdhi5qDRS2 Ғkڈ?g]6"O@YH)¦ěZ\z֥zWuZgu偃 ^0QfsvB`EZrMx- *"񬮿2 ҒkN|\DR\SDD"ZDZrM2jt @$Ytقyl r,H" uEeBA2\.s7H 8]":"t2٘"t 2͈e _̱KmrDJlyD5b5x D lejy5jG [R)e[nCZ^rjA[go|ad}G?{/h rZ1U -lJDgV?Ɵ7|e(QD͹OLy6HǍ[TS1BlK/Vr_پ|}U&"Ow_;_Q_P>""O&$EqQ\X[]4YP+ ێȗ.Dz*MDWEvBo;"_WAo_;5b\޿I g7~!hF!IHVfwE/Rwi|G*%uc3OqInָ"#$Bl6"/T~E^'yFAP~Ԉ&)3Ox0L^SW3)9D6Q vPYQkү/7j#,͔v;~{O}V4ӻLAtQ?Y~juPKIgq6kٷ^=Y=V^יr=޺1q!&xV1bߖח0 Ha3wɊq_J\1aB&GD`!"}%m +½mZ9(EE!IQUǮsυw襎uo>NoȾb!ژCt=}GpF!_- tKg7}bE;%O!Mr6F;o>FʕZ妭YAJS4gom0!=)quDc'}l"[ҊH=w{sGQn#SyyH.}Wٮ$:&g3;!rDs!av2xYTn3xaSvԒ7uD "czU Ґ-Pc6@D)cW?;"r 'YΤ身b{ŸurZ7"G(bղg spAJ-zVFoB!K#zaa( :#O&Ha_ }PWp2\[>u|yύ7!E+{"䋨|=)?Ȝא0s[wUFȁN ]-(?倯x /ܬrr_4!Rsӛ|<?)Á747/xxWړo{y!aY+0:?#"O=0㜧 D>m<=z+Rx p Ѿ_]6}B4}瘟&VΐΜeJxvzWj:? "QikFf#dwzWI]+f#bt&P(q|}s4"SE*'B51Zsv=6}Bh:,n5mY 3[:h"cÞȬ%9k@R63I 9GC`V<=3"vFmU:.ꋘ$9f2 CO8n?"L~-q!G49}BIѰ7_>Ԉj%}#¼GF3!-Sv"U5Ф(?GCo4VU+zzQ~) 1E];G#8x߲"3[rQ#Sz -s4A/BqܺGD F"hdѨLǭC"wP3[2!uM?=u?Qg|{nG&wd\QgNihr1LED"b@0BmwS9]ED8Q[us%D$ʼn:ܺD(lܒT!r'p^qKRHޅHluuP/] "|h'PQIE[íELHa4oq>rJD&>ʗ:".NG!!rYĻ&u Ԩ)DZSX# }3 V$IGm$* 43DJ+OD IsI{1<"r`EvN 9@drvNt1S!+2[u_I b J@$@K@WR,"X"b) P'@WTxW[JZ#+rK@WR,"F,auD,Hو|U['@RʈT |% 2"f#rq+@C1RFlD." bi*D'Yo?Z(b\A$j]8zci(hbŌ\s%׻Tprdj V_*jDD "C@r@! 9D "C@rm(+A"'y|n`\q k˗tHDfr& RyIYRR}jiKR͌(ۻ"5kHXCo>44@D!]o~]tWH7z~sFRl5.D "C@r@! 9D "C@r@! 9D ށ  {=<%tEXtdate:create2013-03-31T17:10:31+01:00%tEXtdate:modify2013-03-31T17:10:31+01:00NUSIENDB`xflr5-6.09-06/doc/latex/figures/img-23.png000644 001750 000144 00000014256 12246405674 021342 0ustar00techwinderusers000000 000000 PNG  IHDRM#v|gAMA a cHRMz&u0`:pQ<PLTEې:fffې:ff::::f::ې:f:fff:f:ff۶f:ې::ې:ff:۶ff::fffffff۶f:3fېl+L+Ll+Ll+++l++lL+::LLL+lLL+ff::ff:::f:ff3:mf3If VX:::w׬!tRNS@fbKGDf |d pHYsodIDATx {ܸu2Jj-9nعlӴM6I/RͶMm(H8Gcrxs> BP( T2OGIQ|u|!|}~A.^\N}(c23^J <=;>Yo|̙2>CCQe;0_]O}(vղKbן]0Ф'J~z2I L^i} R<>!j 'dy|Rf;ZQv|}~g"EY |.Rd I9x-+s7^gMsiCBZZS2+۫ #v5y+\4w5yס;ӭn/S!-6oƝ^h#įh)E^HoaC*׸[t/7zܝTA@t1ezKiWơ3E}qʜo7.'Kxʎ/Υ0Fȝ0\-%!)[ MsUǜnwrJ˂%[dƜ:oDq}"Nk%r)mABh5N5>s_$)o0!lz}N k+979ya> &,|qSv>Bh 惙͝;^Z?@-8x--׸ӴAf?MϜ(?Ӄ!sz@>b"ST2Og VOʒn{2Ogє}+?-c].&θnK(Ĝ#l9y'=tdMɜ>v){ž^;I1d9 TP*Y*<mvN;)ڋ}h9G|$hI:?5zQ?FK.[F3sUfΜ#sHEў;JQC.41ץh=89-c V:عPs? C>Մ$YaE??ow_~ϿW?3H3a4j>$crw4UuzoR}^If҆0GQ ve/iTq<ع!nRym: gR u.R(v3gm5GΎ=cļu/sz̙aC8]C# f~3=cEX{H]KCב\C?^h\ʖ5ء5i{fjZ\,WZ@"aċct72P6l}ucnxq.KQhR ˕e=x{T2/T4Ti?JƼm jޅcedG q~6^Xn<.6s Zn,c_ss,6"`ccldn,3/}jc/>?8+{W 5{'Q/Owx<_v+-i{ݹO g>.rfm[Om)Hi#v_;).Ӯ[69=!vhXLbE7 rGckEb>-r:v{Pyzw|u7iIȜ4P2vD]XꊉmN_m/$ _SF~ Wh%_W)s)v>y+3gXE2P8UlKw R] yZV3uj4OK ԱzWۤz쒟Sj;$X<N%tT(3d^ љ:%+.AL -s'$?]ۣ 1,<sv3uLƼu/cz$`aƲW4ćrR;Ub3u s#I> 2<81\f`NP:}Wτ}(Wt=9>Lr׺j& 쏷yY(*w aݸQ̆I }K,x]fOT!US7O6Bb<; HgV$S_gIzʼ^<<8 TG<>;sy5hby)vc|A؃S];2g bZOo~ӈ+@2j92Ocof<K~+5_+26E\[qboN| ~2ն99bJm8~+ū<'vwivbf ykLYaG vdC2wLS(pL!cG2wd>D |nW ;2#sk ;20#s ;2/}^2w"}(+]1v &y:#sy]RYI|Įt872W6vǒ<8 kɯt3!02זGؕgRnK.t չP(SRY&8j^>y7ɹt)ժ9;0?R!Sk[M n"rdϺvQ]ږ1)Hv{{SGuX8dZˉb㐵i ث]~Z@]x4^yiO["!9Q,, saoN=K^휅Q9o֦jqZN 7=}07̌x/Y}Nۘ!ir?ߔw>zh3KSDpH{8N-ReΖwDpiU\ކsf ~^mZp <=#e{MGsZ|WoMw `퐩=mӂ8;vNth?Wp˓l5? s=_ ]07-ԇA 7ܜ4fmJњ~nC25zC˼Ʈ[FC`܍s1|eA<} ;L͹wZ-t\ISF5~+bWe϶"{Us!(~PWC"Z}?8O0~{װK7k_Cvd\h >HTy}h!zERUZ񒺼|ӳd{*|ԘׇW9oU^K3'=$̼qpƇUv_aU?ǻ2`t{'s""Qi+ȸ/^1kv\Մ"[?NоF wnii!U4ʯ$K}NӃ[YyWSfӋg_:Vd^s!ng7p v%Θj`SkӤ-îRO'e;C:'&ba>LG1`~u-~ۑ[FW v\?ץypH/^$I֧E}09#F_qa@]!o}c@Nnyt;u^?Kթ;a]j)YYF}(=Bͻb~F sVn9"ouKg%eȝ}Ё79"W=% { {q,U׋vDwQ#!F~W¼-v sDn{t#A2/Tnd-t ܍4祭e.͵E٣^WEO j\[%A?,1l79u);݌P1tHR;) sm1!ѤbbG`miK؄AإN~^R7ud>Ouv"tW)2Bmԅ #U0aGW޷Бyh{ֹe$ʻWs 2|9VS)X9"]y"2AG*o]rp*o[9"Dy{+tde.L%o̱hXyҡ̅cdb.Lϰzj|:I2bN|}T^5g2Rd9Ly'ī!DjPS)>0^'m;/p$EcA6s]α:CWMjj)2VM-W,2O<>!4>sǛM)4N)NT/kB(R #ď]^%/%Y};Kn#y2X]`goOt(E&^'M#{xQh?޽;.x0[-Ӈ}1] kO`((IyOpz; DK?DO [931}CdV+v7r '?2/7box˘9w'ܺ3|1-bD~/cwl)Ɇ\Vܩ7U]k'PNB,-#.DKQdB} ڤk,)0͝陝{"r҆[Ю,Y5*Ld ]1v djm8h &6!s;kI{2wlGBȵϜ-a~!D-qK3M/͌J̡[fNK<(۩+CP<CcN7X}H3?u}|{t.<G-nl 9prO*sZ߱"0{`ɠ*вā<,7=2y}gkꇏeͿJΩ+LJK/91_Z>»LsSβ\ L̮?)3<2D};{!sN^jTGއ2{=m(sY ڻA&* }(5XRd8s(%rd3_oƫ9V3W3\@HމQ}dNf|"[>7]nceE2Y1@f˼ o#ϩc rL(C LSqqnOlϚy'Eܫ"dՉFQ'w?!3ǹ*9L<>9fɇU<>Yg.yL[9>?FKUFyFSB^./nl_vc}3uPy|B 'WTB 'dy|B 'dy|B 'dy|B 'dd( BP(*P?]%tEXtdate:create2013-03-31T17:10:31+01:00%tEXtdate:modify2013-03-31T17:10:31+01:00NUSIENDB`xflr5-6.09-06/doc/latex/figures/img-27.png000644 001750 000144 00000035572 12246405674 021352 0ustar00techwinderusers000000 000000 PNG  IHDROgAMA a cHRMz&u0`:pQ<JPLTEې:f:f:fې::ff333         33f %9% L ^9 Loo ^^ ^oo L L9 L:f%^Lo:- 3! 3 - 3' ' !3^ ? ? %  9 k  k k% tRNS@fbKGD- pHYsod9IDATxyqd{2 &;33DZ=B$&k, +#[RR%[V=əsfzJRrI4V_QisH3C f049!`isH3C f049!`isH3C f04H3AikN6f0DӠͤL `4hr_x BH3Xs"`i4ϑf2f3_>|pI3ĉN/bͿˤdV4ʯF.4f" f qN6oDvB3i8i޳L 6Ҽg4@4Zh&toI3ĈKsk[f NA@Kv J]$KH] }isH3C;4>p49!`isH3C f049!`isH3C f049!`isi@ f049!`isH3C f049!`isH3C f049!`isH3C f049!`isH3C f049!`isH3C f049!=<mf>4p rh8٣4%!y% N.q.iv(,Ftm{ٟ 9NǩY5NƉeci&d-<nfg"NUNKgs-KiVxxE}J{#< "ͮDh%~OH':/" SّsWXsWّswfH'BHD#nĞf^HUe4{A$5Ŏw22SfH'yyO#>ğh~ a4@"Qم3s,#E 88;PU\sӢ vM A¹)s1H}{N6NЌs24Ӕ]0흁DHuN7|}po 9IByqss3a&!Qf;{u-8yQHm;7Nӌv6aٴg'jFi4xiHe8|V4wyHeف1̔PٰݧjF;;c sH]O:֌&;;焙24utH%ߦA:pq3 a@4[E}0/84uͨy'̄|٦C''mFf\>lұ6N ,lĜ2ei6aUȏkoA53fsB<6TB!̔ٚS/"Ϝyf"lz[qBٖSoΜO*lJ7srJӺGkB-uMOY_Y:w1ڐfC|Ӗ3Xb5篾~Ca !f9.e7*+׾_iwUc !V)s*)9^liEm_+ܯfi·4J_fҜtw-ѽ^䕀fM".x"i֓90r6,iEPfvcUG#G,idENeNCf|8˗GɿC-A"J9mNFRdH?+Ҭ2[O Kk,idDUH4(Iܨy T,iD_̩ͤ.PQe9"QfKq4?#r"٥(eg;3Yf!͹Qf?_H{ Ҝ@G9_<3y#Ȅ4E='@9+2sfۏ$ڻyߚAyҌ=Hs6ip0_x4 T|ye8ka!ffl y|;=076aBEif⬃]~\07&SfJOs31mV?*O2PW8+`َ<-m΍}@i,e64O?sfݲ/Pf3"krl]sV.Pf;jH=ڜ{z0Sf+L3qΉ8lJir`>hs.HZa̖(ޠf&ΙhT0:iVO3,3:io3 T(Eէc#ͮ\ebrfF*ma~Eyv+c؇4GͻԵ,2fd=S8Reiރ8ǫg3e4Bղ3fom&αY¬> a*4s90R Hm8(OfCJQFL AaDi>6*y/Y 3e.4;osI}D\$ssBWdF= AAv̔,9⼩c˄49ڼc(̔8\F OB I9%ڼ]c)̔@?Lc3hb0S28/)dfd`+e8/(b !,6*`K %,8pC3r>9m{zE`@ڃki.͞cAiD k]#͢8xّfay瞰f\L#1q34Ksym&W0#9ێB48$ ynB =9J0SzA43qn<0CIsmf&&LkB~c 3ԑ*om7Vqiِ8r Hs~5vqA̎)RӰ6l:.qIsFfX|$ITfl6̔ZG4QfXwIs*5 3e\S3ScgKaXӓ4'T]m0Sf9&ƶ0ÁiN6Ta6:6l ͉U5qV_= `G53'fEql>)Hzlc+Mw2c4%0çg.iRG7C֞YJg 4^>ÃgHgN ڬ}g|x0aYB?q:Œ",q4>>3|Ztu6z=gH۬]g}|0i&jۤ9RۜyaC(tugaTs6g"ٳ?Bw}gMsO'ٶ0xL%̶/_S[98!“O(9æ8!ڜ[Yms0D8JvfTLb&k+͢&>x.4q0F)fնfm0FxG3+c,>ƈ_ը]B%63(Q5窟Ldz(QsY>Ωc(Jw֨ۜvN >FdÀk#w1J)o+7?3mN7p'0Q.:WwM,?|hnqR6rXrh9/D줰B{9^n`qCus hF9̐ .98n B;jq9&n ؍B8Gϡ3RM6G3R`y,s=wo#VHBsn#xt㳺=f:uc:lq}~@$[osjb1r1c64zYّ!T nw_8GCRc#qy: $^TWm^i@2yyPsZhq^ie[ ɵM6@Հ8p@XK;ͷc' {觹a <2f@s #in: ϡ줙3Pbc[TM۟y@/ y47Ey~ ii3qQPÛgi&@My_6UF2֏) Jͷ |Myn90yLs6O!yϥVg2(˻Ҝ2op0oؓd:0VZiN'v.7< CQ:@B_ ov9Ň*O@SĄy!m߼I.~@SO67GWTfevtO8ͳ~dZu@ T.4Σ<}]= ]L<_G0O8$s`p DpNsZ>@ Lۜ,[y6pm#o@Hw y-vnk|Ё,7oR5wPy\%uykqytg]ѩ b=]$ϊ{|h~ qAgsoXd b</uL RJǶ-Zy^u@!|y)6K}a Gb8~F%gmțm st!D>_Ї=aNqnd18UFckc$,5}|4O#aӫ<;q&ywٳlqNRg?S'87 |'n,P$oW8Oڻ<~3{Y>[؈t>s2x~)hh3 oe<~8s<}NC*n*PB.F|?}n)PלLƹYgho(PL]6z{;Kq.V_;Om;|Bx0+tybmY`]X4]U12ѷö0SqqyI5Ա3Q[vO+q}= ao 8=f% 1hӣ^qy(zui8;9x?AyZyyKp̮= ÿks%qv{ 9q 0ފsqv~06.Od1b\p9 sݤSq.8l\i]nVam!W`+ӭkTe=@(+Ӎ|xisq.E.O6g m%*WQ[<\anU.6T_+<Ҁ0Wq쁒\Fe.]<ƹ#8]y?3p9<6jmg<*sti~z35:zèeƙ ]^1nTseTe|sqYy*]r"sT:nŁ8k (ԑHnw0Ύ&OM mnƷ9ݫ<P*/{{k0HYnl]j'xra]q- 8st\ )&mn@@*.XhLQ<<(qYH:"<99} On@Icq>ː(g7g6GchzRdT0SpCa?Ȩ:'cFm>!U#S32Tv˳A L bstVW6x4ww gbv貚8hN†eem%eSl|tـs}F~+W@2Z_!C]̪Tgׇ[V@MY6%j,=,gcl8gd7ljȲU[m>#:74A{Keod8kę<#fȲ}m։3yFF S? e'^r>#8?L1gU?O۬gLq}"l1dٛj3X:co t٧6+ǹ`n0-˝@WY?⶧Ws d]H-ęd!v5p>}8dgjL'\ye 3q%Kǜ*ؚ89<{2p3qg:,MsZFi%C#y&ˀ,kgM?dfnLh*8 S3f =8qf`Z3q?23g'Q74] $$sзf gXC48HsDi3ɉ3qr<ǭf gaRy]&̀<3qa.g;D9q&΁g dsL5"ϴGbzq޶>G %`щ3quZL,NnCpN7LLLD9ͤę8/qif gdmL$&zi/qu䎷#m&@Vv'yћ4y982$ͤLj qN-Iof dgxLҥhę8L3f<3qNGm=4:LOs/QCÿxyͻ׿<~az̝tUo>FI3}~{?߈YfsI.7j;i|,i>q>';ܐfԨ]xHsqN樟$ͨduaQۥO`e^p\uSg$iF}Ƌ NsqNppgҌ*]Xq8OnmCOsqN;4B/wv"}xyYjĹ8sn?Ҍ n"}]x| myW ݭmޓĹ8f v|(ioݵr%Js}qV-3iF͏?~y??uI,z58;i&ͨ߻so۩r?'~|*w5su4{8g2fT6G_S:L/]ۿLӥĹ5H3m::n.͟~[]ޑ.Ͳgc ɉfTzCu|}?xۍ|_8T48Wg2f2Ggj8'wic\~'ͤuov\[`,4qN{984N}p9߿{iv2q.:e^Ig?_&(Bp׺.f'l:/]_}Iyfʼ+_4É֗7[I%%k8 \tg;eHW4"3H38IsA2GL!m{u8?JyE#r=42L߼gceLuE#b=4RL2o6C~S3i ] L[2o|cszi8$lM9%'175f ی2"I3i288_9-'jǯ4f 2kɁm/fD/gf ڊs|onȶf _.OoBosqǻJMxyoi17ݒO׀{Ef>~M'fstcyw'i%'@B];7Qt>?vw]x{Z^O|}u&&; /XfnD==NvGmf< or-f݉󭫟sk/V~Z"OG͒fҌԑf-vyֹI$eOoiAK|N4ZbWW'ΓAo&&aӄy&E?Ye֚}X x1q\竷>8?*}%L/|TҬ1q^NK%9YI3 kZ4O_6χM_rfwqu${)_ż827ifAHex{Bo͑I\zR'Γ84Kk\Qf}|wF]Ez{#4g8z xK[&9qА{96׷<|wMv?ѭr[&=MAҜw<(4wW'aIXj; N lo'i8O/޽mmΊoS2j)toyTٳjM`']ؠEY ̗4_ͬ4||_Y9(;E>'Ӝi=y7h?s>q02Giy'΃ Yg i"go &OwangEq5q~s8(J[oL!q~ sk;̩a{VI3ON#|g"V']ř˄5q~JI3g#],i3wt]v]|9iҤZZh&..AǎܹԩS߽{k׮~kא~„ T]O$kԨќ9s'N>r+f͚5.]:;\//Btӧnjժ۶m5kV.]矒%KO?E5SJ=J]eෳ~ʔ)]gj<=nbO1^^^4*G5etN<]ʕ+o=cs x踏iQLlٸSdItٞ={(Q7m%~dʔ+E;$J':yn__h.CXYm7l2A)nCG3f 0zHPbEG,I$kdxɓ'å8+ښDɓ'^=\8zivfxHDYٻ>e˖aV!>3vPgΜ9 4@y}sȒ%K|LP/_~rit4;vԚS5HFo瓝;w޽a֬Y82e" Iܧ=kenرŋ9rd4iܹ3CҥKXX{׳gO܇~Ezc00aї_~9fd^`7oF1|-[vՐ@lt>w ǀ c&p|c3Nr2Wlc:kLP/^0^vɢ3sdz <ٸq޽{{nO}2eO>L2˗?t*UЋ]v=FRdذa;v N:?w0$ґ;B#O yv$~"CKv |/;Fua] 'ÐoZ2v %nSGek~^u25 W]GHֻ\!CD(PJ-})TVXTݹsA׀"Ν;c$x"Rc%(88xĈoߦ͊)S轩S;N0!Ocg]vv2ꫤIvouܙ̘1ŋٲe;1BFܹkժj*R. =y>wx{{өs"E .XZ[2'^ űw޾еvڽ{%K&L^cFI|f:h  dT)/#Yzb/#!dBZؿ1c6mD1 9˗2fUveRNݼy󐐐2eʐ~$<<un:dHL2eDpB Ν+HЩS'jPg*WܫW4i] fE"gˢD'-E߾}Aƍ7T̨2fC/#{n2@ǓsVv.A)lcYSnH>P*Qڶ901^u7m(AlݩHתkSkXDyق H?!-XN!%< ۲kg:vCaw2E3Xr`3\t^N`!AA Gd~h}ݻGҦ}@)%\-4M89@!C2X'umΝ;~C|S՛$v %K2w\I&whѢkڵkΜ9Ȫnݺ(^zhҥK&`$&;ڵk(qٲeZȠo{1aM |ƍZ>SLln`` G U= Vؾ};u}EER  KE*0{|D ~~~*Ȯ3|MG|M_:v䀦p~ $qpDԬH1v~=pӦMuxE.rTȣ P{ɟ b ޯG=zP/ Qׅd b 2ezھ倿 Dfՠ&yü,v e#!dBǐ~P˗/o>p|f3םE6->6m@ï_>ʙ3'~Y곋gp"&Ziλw&5/ 294/P`Afb!ܡo\Pڣs )G#٘ĉ)\Un {H%dB!dD 2@ϱm>F @nAFXXX\'NSrCŋI&$$ϓZe5]udw-MQ5bPG"g1E %b4w@څ8h n)W~_lD" kd2 !Cxعsg*UȟaA )7*Tw߽p}ws7ʕ89]ٳg/0e)a 6ѱc޽{>M49p}k޼9ꡀWd*χy&2R㲊͂NVtΜ9Cn vfxtR-PfGCṪzv*Uڲe ]sq'Os79ڵkoڴ%P;%lAhuU\͡lٲ!(P#ݻ%ܾ6HwhrvDMNe0m4???  {EȓIc [o*@%P: 6$Yu٥06˗' qAf@ J_yO\BÇ+WPf͚M>}sٺu+zfTV ߽{|cܻw (Ydrϟ33 Uڞݻw)ŋo޼IR, O8zl 'O`5^Q(=f͚U)Jd?<? ?dJC ~m۶OvAw,hq- O0aܸq#M~?Ͽ0^:N 'R%ƴxM${ >~odzҸq+Vpq5o*Uj-֦M֭K{_̑#GH7cuBʪUFoTR۷oOMOlSj.FY c4獬EQzf͚|NMo>_l@Zk#da,_>)s>42 Y |q%!~~`}ٳOڏ NAFj^|Fɓ>r:w˗z-:GQ|XhI -[>5kG.xxxt(1pxI0zlZPN4ׯ_ϐ!CUTEܼy3cƌrA !bӧOrj7A, ׮];j(:w٠AYf)?JS{35AMСC-1lذ̙3.]M ˇ& cƍ/Q7D!A:tr駟8I; |G 6mڔ:ujkW ;MgH W)ʼnYdyXOaPME@ع5P~i 6Ѕ! 'r^WKu\ϣ8I#Wl%KYV?rh$h\z m},Q_ 7*.k֬/VMZۋ'ҿxUX,dZYY f1ټ? ?WSC6?"0%7E\_!K1cʕ+l``(ɡZeH!TwK*EƜA{$黂Z4aTiٰa-"%b-bѕ+W5W)I$jx vuƌ9޸qCC gsLfz N k6ecQ3f4EL,+,l1ⱺ/yLyAYz?԰Y L㕴gɇ_x%p ׷zo$In߾ݵkWrE?"E Zܹf͚[l)_W_}!C *НJ*qVNJ>}HHH6mP]nݚJ5k֠AȲ-,,,<vٿC+x%p+Wv%3KXZLZn]3'W Ȝ9kΟ?+W.HW@e>}2qUSΑ#6x{8[2e`aLvi&Rׯ&M-[_CUV1peDXd [\s QP!եC[hxbrŰy?#YdX{Tg1͎ *mv` ΆÕ(kD40AuRPү!CJE͚5gΜkݎ]RX֊)7Bs1?@ґӓsmWB0h>,&JgCq%J5a_j%KvA2f̨7+VT\ K D-=?bgfK0G{@5ob|@W=Ah.qX U ݨ <0*7~n2:_W]%X͉0]au?ekhuxN,Aٿ_ "dx3ٙuw$ʝ;}|ptHmCs;󴽜 A!T/ʆ̫ޕ'~ ԪUaÆdLU2I뼵,JՊ\%>g#MaaaμE[̫\?a4^fΜ6^$7I6u(Vg&[T&:^yGP6~jK)ST+4igUR_-2 ܳ? ˥5Ӌ/~ʾ\$Hdɒ͛M(Q[fbQxqPXH;v-hi޽tx,g8,^dVϪj'bO"S|.B*I$xj8"אjEXݻwk-:: s0&sk~[A ,dU>'\ DZWN^V\>Cq;`uu7l&SA[ǐAĒ7n>QJփYC ~HE] 2\xp6>#,Εʗ(QñX?$I rȗM^uє,Y2aaaAesG!Y;gGTӧO)RlnR~{Ԑ:۴vZˇcaT f͚5~\riUbը5g+j{" cyY7t fxb+x^ Ȓ%K޽U/̚fzjժ+W,Vؑ#G/_=`$@,ZQ wޭVxEg;]t.\șnnjf\߿C=z֭J/d߿iӦj???t|AZy7)'=feSsxx8Y ֭3^>poS&I:5yR|/O>Q;f\E7?}vAAAj=hH4;Vժd8{Hʇ68^5fO가i~LT#?]lR|GԎ~..]J>>>;~6`Za^ybŊ2!c.Oᇬ6vC!~? >v옯)S\9GCEںu˗0D*UD;G?7irT:vx=zL4itoǎ왳jժ`x%<|qƔlٲTL~|ǫۧIM!!!O<3f~I4Ezon)[4;(^1'.X xO#l hW7eʔ1GfO8q,Yf͚˃7cǎ7o.޽{5jԠ9qFn"?ݻwdz5{[&dGUOAJ ~Cq+C!~?_ CpeC *p˗߼yEAΞ:3~Rfߟ̆΋/ho9rʭ[ӧ<(X tf:̛7oܹ۶m8'Ξ=c(4ٳ<͑eq=|?@M6=~ OV/_bpM`s\ù΢E%J4|NYpZ8ٳg3fH2%ԩJȲ\=Kpk׮M!?ԩZ4%0??RJuؑ}ԩxʃ8u^"Xp_&\7nٳf~\=V5jGA\Ǐ?ߡCҿװ Fu%e8dj:.bѬX3 8~Q1Ͷ(y1njZ P,_'0Tb(7ׯ_}W ~8@!?G4B@!x>?V\٪UiӦu1eBL@'OҲ"GS~\v{`` k߾}͚5lRreJ١C5k֜8q"_|%7ݻG:bYd֭eHA:TD .-[o͟?Q.]͛7ڸq2ep4 #طo_(ѣGyhh(iӦ QnI$AÇO.Ҡ¥Ko_jUKT4Xb=z9 ~X/_pq?//&J 9s̙oѢEZ΃ J:ɓ)Coذ!NodK>/^1cD7K G< #5"fر vI</QFmGQ*Ri_~Tܥ ~L:o׮]/&;wN/үj? )SZIշp_41Yһj攆*1q\%K|'Ca1Dj77o^q?H\RZli7dȐu֝>}h#XB ^HHȁj׮"Zh!$荐sDB,Y2 觔[\w;wvQFm޼Hr9 ?E}}}#A@v17-@u540ƫ!ٳghg;%tq}ZL*f΁ʪ^FZ#A軲El~g<$8PH.]:1sLj/m[n}w ɓѣG <2-bŊd1>^fJ@^WiӦZ2:4Q, CP@"& \ ?qFCc~]u>,_y| >Feֽ|z#}x*2Vg}BM/51)t&]y(6] BjׯOךW5~2TϚ+Gu?, 1CփCۨYf̝~ @!?$~XxK} #\ &*-br X悜1V<;6m4iҠ5|6mڌ?jժ+Vd7hܑ#GAj^ΓL (w J92eÇO,͛-[۷sl2w\a c_h~̙3oQHoqPv(^S8XرcC^~… Sݜ1#~QF=~8$$nB{3gN60k ̙/һ@nBvi8RC=ztjV\4! 7: eZ)b~T\1աzM/rL8z*F*x@Сmۦ Lfs ÉPKvQO5 vK.ݨQ#cY/iiѢՊTbCQWҝ &\x믿V)%:uɓ'Eu)/dP܄Aj^N}pfĂ)ƫF$;SE{jPءhr7G6ƀvKJU״?<CC 77 ?A*~?ѯJ C ~8Aϖݻ5j~90 k*UN} ܹsg޽jc%cƌA=RJ:hDj׮a Leh[ٲek֬I ūѣQ wO)6lJ*iDٻ̊jL? .D#{4faQY?ӦMΎ8p'$G$Ƞ}/q/2o޼~iPPЕ+WT?Q(P@}t>q0F͛Cs ~i/Idey8Nz{L0>Xxbh~tW^I$S-Xk2PG7M4!! ~xb[vpr8N=)RϜ9`8:e"TS>բQȨ4y>q6Ȝ.z8/vaJ]j?eʔ?ɓ|bZj*Lf@k>C[pz@(dPgW @4% ~d>ڜ١ `kLԂ|p- *tQY}(9rG|!oJ ~_yҔOCLe?G|GѢE={KtMt1[WEIKte,Wnٲlk׮MjylOwݻG& ,c~~~; 'tzp!Ivn޼$IaP:%B&۶m#Ci a9s &_֭[}}}-ZD 믿|ځ+ wYfMC͵M=vaaahOL2y@O޽Q3pBWYI= ~}>}RtΘ1'н{TRD>N6oN2ȁm7Պ*TZU{D?iܵk3 ~}ԩ?~>}Jżf1} R):҂ZQM_;i~hʱc/O7 -Ps,6pkHiz!~,]|:TR-[ld!Kzɓ'kte˖aȕ+"F 0pEDYT6Wi>'ХKzad#~T7uj !#ZiPQCdɒ۷ixgx>B>_Uz~+eʔfS{sl:׏.f|ZT\%J|P pY%KGP=Ri3+/# imY8ڒ]!642Puhh(Gi,y\̛7 9_z5vqT;t25cGV˖Z& "۶m9c>rS?,M95іj+ xkIffADbʭ[9J5!5VY5l#$hJ9yh]〚fg(F}7!C ˭8o?_J@+@!~\UVӦM#ۀ+ ?*[&.e8ߘq1@ڵk?޷o[WTd]pa&?6agi z6߿?%.Vؑ#G/U|=zįQεutP7looD1(Ģ|1[9M٬ݙ%[\rt֭[FIuqVkշo_}wfԩSшvjԨ[97ڔTq3Kx׳i… >Xn Z"nvjeYgyM4)Vgsn㥁8;wy=>?W8SM͎mjӌ*7c|xɜP Uq9--r^o(8(k¯N[ hѵ!?@!D3?ʳ!Ee?W4,@frC|ӕ} WE}#et%(((uN֭[w+;W(dfx?\D$15fѮ]s5 2pMVN_ТrM6s!Eo>sAÆ {ѣGs\(Q"Jc8,.\HL5̙3'Պ>ĉ-[䐓Im"rܚŠ]W8h;v h9,{-2%8įcRoN~z22at-J53eʔI&]~}ĉ/{rR>sk~,_|ŊoT]{ըQ#sh_ƫ^_ǔUjc ='?s%!qG Qs]khV|Az=9Mdn "2tӆ`Mw&;)Zea9I WGɵ0Wp wh]d]k_,F97KߍpV!sC!xW%@!?~fxc$!?܍v!lhQlrpQLw˗7i$vC l5ƍC'^dI͛5kF>ƫAsEAkժȑ#TjyDP8 k׮ʕ+͟?bŊ $3\k7*3$H`CU \fϞݷou֩8>pb6?fl\C61^"X(-Ϫݐ9C!qц flܸpvچ46ԩH >SdtX-\kŊ}PmT$P-莥אhx8x @6IsDlj?4EYf•>j@?jjѪT톴I-N£jժP&BҴrͅrjJK7Wmذ?ݸe3^#i^K5UT9yd|VZ:@ǪUʊy:";:TD hXFÇCS&`Zbmݺskrmpp0}bXTF СyϞ=رcxW5Zٳgŋy=Z\DkժܻwosvozJ5L^Y5g;^4sI3g&vÆ 4[zn+oP %/6SLhL/)]d}6ja [Z\Ѩ_~l@eGWV3V.8A.V!ll86.]4D dXznlU jș:00=NZ{+hAIgvkV-hO>7WV9c%@~8:Va!,gb(aX:QzKϭ=,t54Lcے^,֮]Q?kV-W24vM ԑj}ګL{g@n]CXuX1Dhc湕oҿ;5id].W9adgX*T)>>}/ $>|x&M&Mzyq<~W^Zh_'Id֬YGI&n:QD  ݻQ;v/^yϟ?s̸I^x 'NxgΜFC֭jժ5eʔԩSg̘[nClxEmذȑ#2Ysa˖-kԨyfLɓ'?v8߳g5kրO>J7p?<`;&MhV(9g! [7mӧfY=sjk@EVgGX@ D<@C x-Ax7 ]r%x"@扇l[y\f*DD<@C p'NիݻUTiԩy5'{6ɓ'?zhܹ#{!"tW^%ϟ?GGC͏޽)RdsՍ9qq?O#SG,… ^jÇ5jZzʡGЪ_ύᦫsbsʕ ƻpg֬Y)pӽr t̘1rBT+͝>|8,}o"d!ˆen ANTOE"qر+9sL&Sc/ \8Kڵk9rkHt)LAp˽ XAu釨ȴtAdӶ\aH#6Pzf͚m߾V)R=Pb_ύᦫWߠ@ۦMu4iҩS'(c5{!K /^zjc'GfX ۳gϠA,pSGt"[lM':_Mʔ)]wuc}}|g9":FͽD k01֯_7c·2ydl=Ŝ5aT$!pP̾aaO?!ezh#7 X#ў/oNHx"@ ! ?WS?Ws%ʕ@ !x"'m偫si=dD J D< h1ݻ̙3>|sELE2-ު[lmغuk&Mϟ8p'((~nE>2`s>\D .*ɖTxhj7+v[<ڵkwAISJgĉ7G :~iӒ&M 2,]ԩN8yxիAO>ɒ%1cFDO^paH+W={4'*5kV"E˗pȑ_~3g]۷/Y,R Xx͛7F{G8gZtaYs-mf˖ O,Y`ʕ+;#ps -TPݺuǎ[X1ʤ@fMʍP1ZUAK3f'Fy#,|={֫W/<sb-Z59RGtU 8vXӦM/^(-Xͱ5H?ڱu7?ϟ*jlٲEf\:Ww8C#:1rH nüIZѣG ̱5 ǖ<2dHz 2gvX6E5+aF̥+ou>q1hɠAtPD 0!Жe0\[j RJw[pȍ p~M=5+aF̥PJВC#z,Y.wpcرiҤ_!moزeKʕ\p!ƌ3 '{Ѳ9\ 5nAKzPh"ˋ,8,e~j%K<~85K(0HPX1kG" 3b.]M-q%hI\!rĉ"@ !Y!!= b"ʕ@ !x"ൢiӦ$UQ<.C D<@%<}::W\I]3<<|:y$.!C4~4l[D 4h`"h4 Q`)lG !CC 4!_Tb_D;9skݷl%Nq>zȾ)r =T|8a "` `\g,}aG>=RLi}ЌG߾}bŊ]|ϝ;g#WZAKFƌcvJ kfBG模}@ /tѾQ).V5/_-[il۶-~۴ic8\Z<{~_m͛?Si1lt<2ehkFFQ rv2.N:`SZ7lذzjd ʺ>;wn->|ǁ >+-~+V@B-JB"Uz=/^} }۩SpI"[L ܳgO97nx֭3g Du94Z=x`رF>C i -#Xpw(q߾}SCjՠ}gu-Ɨ=z_07bA>qm_+5QQѣ.\ 򀂴}=zhѢt9* +Uqb&y{{fl{,+fFF{"SL$LR°0H} 駟0Cʮ \,]iIh\/ ysV6[*+s5j(+5 syp0+Ńlh|-11 b?b;]t1 Mrg1kb4T', s4{ef+WHb-`h8p իWbޱ|Y4 42d1n월3O>}*U21*T|6XƬE<E`bY˷i9[-Lu˷5e` s23F#9fD@kF71(N zcֈx"@OC\y@ !x"@-#dD<@C 21<@,wGWmy(1Gcu 3qUUEZT\Y+ȑ#"0y%LիWϝ;7qFd[X-[#X:t Zٳҭ(kI~6o4rTL~@gйzͷ~m* Onyw&' 1a&shӧOwxeԨQ 2% Zٳ2mef+oEyA}ڣG'N3gάT~ώ;/>o޼… [vܩe­d{n޽׭[?ԪUkʔ)SΘ1cnݦN:tP???޽{Zb'OPDACCCǏ{?xE_u$I?~رM^x100s573gΘ!@52gΌ<ϟ?߷o_ ~7n ޽В ˎV˕?sȡ4iR cǎ5j0UT۷_dɲe3xB#ОQTqo/"P[5x 2{!=&G1S]JzY2eʠתoE/0 ͝;#!3f ʕ $8Efݪ{'@ w-_~'OnԨH!seBH !33]cFYb{L?ŎҥKKN4z b.ݜв 2Gnن>Z%} 4nX MUҜ"HUXtի- ČΝ;>|ڴi-[LyfJUV۷o/Rt t&M̀Eu6LL6l}:tgϞk֬+Rg'VPAڵk1JU\ F)ٲe R^reȑtS ,)anÍ7VPJpphlߢB!NPVZզM?P4o/FiQKwի (4 69 ̌jJLV\$k<,lk; Yaj={͠e~dɒǏ;\e·`YW܆+u+TDKsy\.>h8늮\6v̚5. H];@C D<7.]ʖ-dϞ]!@ !x"'3Y7{n@ ʕ@ !x"Aq$CDgKF'p֭&Mlݺ5rEf*+r|av;=<$L,]Tb.]:;wлyyg޼y9N8qԨQ/^1cƐBׅ %MPc#! #OM_F6zoAo(6bO6H4;ƂDl_s|5޾;>w~{~~p:JHqL=DTMTOf h[,t%x<]pYT5sYFI2 ruttl6xP#s lyB)\%11QTL3~Z,TRg1WcA0-p*RHe$< :mTvj~WFU&?jJ!U$ AVFFG9)dǤbRyWA1?ᑝ6f9>>~D$&J*\+鋝&''Xii27l;цy333XODLJJ 7uyyv,!!\@e%߾>o! ."xkbbj"dI.N#w+"A,jkk>88* 6$u#򘚚zzzbnS>Α+++QD59">WWWch!a&2222alǃFQQ3]LL sy| PKoqR$3uľ2'NTa40Ì00< 3( zy3 SODFyQIENDB`xflr5-6.09-06/doc/latex/figures/img-30.png000644 001750 000144 00000041374 12246405674 021341 0ustar00techwinderusers000000 000000 PNG  IHDRk]9gAMA a cHRMz&u0`:pQ<PLTEf:fې:ff::::::ffېffffff:::fې:ff:ff:::f:fff۶—:됗:ې:f:f:f:ff::֭ff:ffmtRNS@fbKGD- pHYsod@IDATxy$]^4ZdV ƻ_=3ݣ0i|`îF6`OוWdVDfD||飺2#MEeeuƨL`Ne s,fSg6:˴@V~2mШ8L4n-,fm̡̹`jYD8L69칻gui3f0VYDcW2mОk; Vf0Qg6hm{mvYe 5߄:˴@kh3sL46=62mЖkPg6h m{IvYe )"fZj$,fMq-fPry~2mВe BY4,f `jqVg6hʡ6r7G -1lͻzLmH6I=zf<,7 ɎEl$Ob6fS @"KQaJɎEl$h;ru_H1?.';z^;oŧ?eG"64n8E#ov}-b#HïmoES4fG"6$\3/TD:E#ov}-b#H"OQ 6sOțu_HRX:q>{.Yk @ m>~w['>:`ZF_]mIfG"68J|uQ 6_!ߏ:`ZF@6OшVQ 7hO}VOțu_Hos͑Oțu_H l]pb7;DkQ mFZF]P*ZF3Bp>E#sk @ti|~iWmu_H[yw[Hh`4H6o{֨hgkz6o{֨"CW|vtO_g'?5dA7=Ϗ%ݕ|q7e쳟H͛)_zz78͛Wp#z\񓟛H۞7w?y@FmlOG- nw^WU=E7>/V5.kȷ|4f2y]]8 {o$Y߅ESpN;o$YEOhg{sQtLm0B> !fyr]_,/E1}o6m@7?ų;k~[?{gkhg!69.h3%y]:S?W6>)g6X@?ۅwŤ泛h33ڼٺOcSѴvy~PӴvycq|i3py_.if;϶?o{Lh3hg{Imz۲Eʹ.~5v9S~vLp# `;ogtP `;+fhso{O6O6i nswzpͽi\Oe06vtf C{;x:ye@f>*?VE}\., mnAE+ޅE=;}L]XS̃?H+ޅE=<L]XS̃~K.zW@ B{ꁛ{osV waQhsO=psmn}\., mnA Z+ޅE==#BqԻ(}8]g>z67'A]XS샞4Q waQhsO=pzB+ޅE=?Is>z67'!]XS\']XS\']XS\']XS\']XS\Š']XS\Š']XS\Š']XS\ɠ']XS\ɠ']XS\ɠ']XS\͠';]XS\9zW@ B{ꁛ{]jޅE=:4=>P¢z1\FwaQhsO=p3 8an/E#Ի(9#Sy}_}o z6D5ߠ_,iGhz6D5Ӡ_+iGhz6D5Ǡ_+iGhz6D5V%lf., mOXI-#]X\3Ϭf/["HGԻ(Zini~]X\Tan8ʹy?., mP0fڼz6&eN3mO B6m9YݟR0_'f7-?+6GF9ޱV?C$m>ǿ5/~}?2oa|kwOmN6WbG;6X6?;znA x=t}ZM.mZZZڜm0wmV?Km<,'Mm~tfmN6ow?%S*q?_f!cMN|V6B%̝OT/zG~0X6"^Z.=qg]X\daڬ~V ?6;]}ʟw/?< ޅEHnmFj|çU?1?y~vz6!q6a<7 7pPaUbt?A ]X\avߜ4 ?6__/_0cQt\~r9Thuy-Y- ~^m~q'_;?qGFWS]XlZ0w6)aocaonT&|6BRa/nȗ4M\ lT0z6bꂣŠ s`M|57om^~ٲ9m6GTos†_4r(sUI l.m!l?yHup,{99ʇwaQh!0Ozc6ڼ7 7iI!l:̓ ?7]OcYN-u&m^y@>X9EM0Wo†_׮C~o..-dסsOhջ(Yϯ>ԛĤ7_3Ah_x&6ov:J6 nŦTΏqGIݫ"kon}~Fh2YTRo†ߎ |3hkq Lݯ <R;'lUC Be̅ro cU9QӬWQ󛥛rW>g{~ꚓf a>ߡzӘ6|هM]tN5s5)Y\iz梨9i m0ӝ7]aϣͿp^ \x,On|=7KWxXJA9aԛǰo\-|p}Hb~jKh~*6l†O{xtżn6/=GP46C6~OϽ97~߿J=ɦfW{pISG0zu/~J͏i6ofW{tcǗ<b{]x;[0Oػ!zA|^]C hI|f;޴L໮,~|]x{i)fm~d}<0̮hI|e޴L{X8/Kͣ_an_<2zߍs0n87-*2ϧ_ϮyNKߎpiv4|5+s0OfO/j W+ѧ#˫#㷃ͧqmYܶ,2W߻ևqVoZT&h :yo~viϾdu7\ W|v7,av2wb`tmi_1huD^xkgplU¼|YiQx0Ϳt/Ntuw8-ez1y6ozӢ2aokV>boqvǚ$̫ h87-*0^j0fg;_;:hvaͮh$aEf/vYiQ߁7Z^,C%ܹl|dAG8:K.0{(޴רQ෍!p8'Ydch3=Ɨ0.j4毾foI쭌6ozӢ278s+ޝq3aQHYiQ6 >Rbf6ozӢ2kmķS[7aVW5sbgEec^_cK{-pV5.96YiQ7p'{03'm)CiQ{1ߝ@~_JWTr$]i:afN)́qVoZTf4\k3WGqí6?t2=96~٫ͧRΙum>8̜̇ ST޴ppy/iӹvfw΅AW5!03'Ô87-*3\~i>t>8ϟkm~w反 *_X 3s2LamzӢ2EdZk8̜ SZ޴q9}d'=kɯ]0jzcu5V̜ c>DzӢ"sYλzF 0ԎWEGrgq+0;MZޏ 1޻ޘݿuB_sM'vQfdgE1L+6=C[IsS 3s2 m=,},놿9oox1$103'Ôf87- 7QףR5mEU03'f87- 7 s{_o<>iui bQ4g.ɧb,8d8@.0wyhK Eq&5Kٺl 963t c*MJ6f;gL("z86gߌ: 6)8ci|Ah3*59o9HYm&θ)fG%,{9Hm~.bLc 6ߎEx4a> 8c+eQ5Y9mFv\]Ο:1((E ,殂6|Ah3 ']mև@f⌉d*i!mN'!`m&ǻJd*5X؉4U69wsC5͉HN]mF^eahsISQg1|ꕕ68,jHHsī sGHԜR<.: ]ahs +ks- \s;ڜ@^dG[sCi;m/*jm@ ìD6G2lc #x˵Q_ؒ{Pd,/go635F;YJ\ps/2gHͩ-͝4W0w9o(ͣ`1̉[` sGJ>"5fR-~D sgiޤ|yڜ-z/zdo6b;K&WdGV~#_?Y4oR>mrËW0R-f|U{ sgiޤ|ڜjVۼzi9?RoUgE 3Wҷ9.myꑕ%ׯ*Va,͛2y]do\Y=򏷴[U"/3$\I|W7q*ꑕ%ׯ*a>Sϐ)3oy#ul6I-/Dks:WwGS6Ӝ)m6_xS._8¼%Y T6[wδvEEE.4Gk亟6ǎs]g{a@]ӑ5f0DZm\?61v9[Knoc ogCIaf˨:u+l";5"G6_?hsi&1wΕxm=a+^ϫsH+%0<1ߝk[bm~_m>9 S\ st#xoOG4h4oZԐ_F[qξBfœB&~r<vҼYk6#Gw)*,2'888jx:?-jD8SCUraN-l<<_D8|Y1ͧ"7PQfœ^p>1=Wؼ 2ڜqt͚W梶/7ʢLΧ O*|Z{6[hE #iX/i&̹ e4/_ ܽa&7fҴCbAm6f3yu68pÌͣf9s"tl26[YØ; =G(o 4fś,jhގ6{2f¬4]m@m6ٻ}UWC=\l&"tlw/i~]f^ e2̈́Y&h8Ρ,-Ǹ6[ ^wn0wC` Rp>WUf&iV?Eq)Y,l<7_6λMYc| ڬ~(kRK3zay~*]zbͶwiqͧkUw= Si&&GpwsN,jΏi'fͧv:Cgf+}&tL )6[\.a4Xl a !zڏ=AI,pmsM)ٔ=>_O{{֝S>Mm6ێs6~aRM0[<WwYni44 9p?g뀄٠1}qb;w]V#fi&l)bO?1v,O36mԧw]^;jt)ex y]} Uf3m0m\;?LvS>6IoI6V46[i4̈́ٲW+dQ#$6_93m=GK.66ϰK4hd0B]dmVgWpH 6,H3a.,Osgvնif("k>ae5ڜ9̈́4"[k(;6;Qobn&a.,IsƜ6ߎsGsE3WڜyRFC4bgY/͆MYL̈́`"+m n ms,i&eSϐm.j^HlI"1m.60J=CW%Fa>i0Eedd;Lۥ!y抣|惕ŌqlW96=Eig|/~ EnC6oL3anz+6;-wE)u@h/i7 mQ09<̈́/3$\yfhjc.FB ![CLq!yʸ4o|OhKa>js)= 3WmS[u !SCL1!yʨ[O0 cv0cB=C̕a<a~mgV?Hg fSIm6̇|m>{9l.z+n.wja>h),2qw~ gHriivl_!e1kOi&Ug||=UɤVoq1V }u@]myVO^gy]-76+}LIK,O;ˣv6+aWLS*K,{*h=C5Yl[az$z%̈́9z8rfy0_=gMu sY=ez)NZLrzn:Rif9*,rͅ(OKnzg'iœOEku[lsѫE 1f¬@Kз==ՙf]!zGPςQgsR݇h%A%zYgV۬BTnS?Dvٙfoylj }!#!wl焉! P@MvZy,@DRlsҳ,l3Ŕ$-#I]4G|HK f@r̀&Cd(Gdj>{$8MzW\{TPgj=4t :o ȮE3 ;t.t]bSlBrm+`٥.Xvy렩hZeucVM@%'LtdQՒbTՓdr8 !#e%F5P,6Z|ڴ*6ZtxS}va]#6#ʐ ՜"dl;Ql$ٸ0ۓlz""s.YENƲj|eZl"ILe&w$*-{(OlT?=ޕNh&'Ta? zdC8d$[5T" Ol>C&!ϒlul"~rMx/ }8]&yٲ!Glz&T#i8l\rYV\([/y!:hpmEzaϮyՒz3J!xuf"(Hq7lruzegZKڛuwדH> lHz @!99ɤ&t=dҒM@:dƵ Ґ VHB6\!٨odõ- H@6\"zpmeB"JI/%W▍U vY6\[&bٸMrfeõm Udǰ{J/80=^@%XŰZRXi_6ĝ`X+elȾ?Z/v׋ջ*K\i5[{1`X;|:hOثM]_0 -Asyjg#4BW߫ćcyz|_.Wv lw9.<ȩƆYoͳEp(Lv͏<,fV>\#gӑglpsN~ϣtqڅ6,+~y.R&dOQWaW;3F_N4W+,yʶ\U$__Wʞ#">6t6GpSqsJ6Ϫg?OhS*kG+mSeO=l]/D3x#f ʴŅ}Hwd빒n7_݉vQ&Qoxd{9cSi`dbNGǟWRxt&YojMv㹿K<<ڍ\ V GusK]u*׽R+o'pD#ϥlfW&$i~:}DdDu"G5?o#+0!.|yl/ݰ04)N aT&;?^ӗ_.ԣ@eO=lc{ Ȁx lD"8d?A ~삈AF!پ `nanS%5eRfF20ڎ9¤bވ=F6B/lf,>c-xU9SoiCR@fكlg;`No<$5 l^"Ef6=5yHjzߥGFl~ :⨇D렵EE'dT9j|[Om(Kj^MZ6W"uE:hZTb8zŰZȴY-)\«uE:hOE\1EȴhaZ\^ZvqA-!=>=Z6\{,2yv0V 9ʙ(.򐃃9%zRBOcQ$lGq|qe/Gɡ14n$ldR :4#Ohٞ2v GJ[wVۘe<Ȯ=R#l-W~)s(ecR[uzJPCѤ..']Ae(q噲dQgSqCHOjg~l$/V+2SҲC$Bc#i2eMqjcmL|8#[K;#?Z?׏H_!l×dddD8p..Ȟ4S)K3FQ6ݔ-lm}˒ڹi#hg{םk4*Qdk{ٟ_nVv7>tKC~^˶2I.IbVNe- *~?6wjղI.iX} ɦhȮ_⮩69w_=ȅ^6̾w]>/u7r׿_X)VKO1);"o!pxV*.Uu+Be#a;ٷP.ӗ0+z`~ѻ0lce>;yH@ Ր..`i ....pa;]] (;ҋ~wH΅f 1a%[a]mHl,|f#p! YouGd׬3!j2qj.}+P6B7]]]l`l@vAASfACJ꠩Gr<ՒՒ ;u^ *RUOd8Ⱦ?ٻlk$ͧE:h:hbfuԣuЄW ~)l1Ty d3$/q啰^lOo &,ye4bYNlnqM5}>..DZBr_:>7WӈMc0O;L"1_?|緸O+WN\Dh: fj14H~y8u74krJr}:r_f;}7ӈMG[\oy nfL!՗MWltÑ=;Ez~&"^!+Qgl=Z aa$a$V ;x^ ;{h[.W?drdŌǗKYqF)Cۖl6sˮl _yrpnSGOL1&V?ݮy-NJ^i?[)2ի/ـ]Q}tddmۻ<+ġx1l-hnwWh΁y$zdg鿕Ptd{nF٪n<&oiAv+ 5M%,Zb6,TCH<+YְGvYLl'$ohۼEyɕue,R?p_e@~$ Vkz:ʤOBlaHIWhTFб|1il }!;/!;6dc|!;Xds<نl`Γ6d a ^l[W _$dz#V>|Qma4UTjswFdћ[L?m9H/&Mf #mWK: ŤDuӶ렝U,e۬&b;K矽$hRl렝bf4հo/&MV_ !;؂ dks w| ld۶Yy W*X dXݚ>h)BʖUTX {O'OA NzUܑlAe^,w$۪m} 촭d5dCmiE+'`]TKW%"Y>wI2[     ]Pi,9xSS}-F nZ>tx%յ͖Lvs+gk_}BU˦LJg?kmyiljɦl 5+M64F&Ȟp$/y&L@N ٍg vKa^LZ T ه'ovۃݒ4͏]YZAi+g;"Y>wݒ$ݞ렭x:h4Z0:h4ZM[-)&V렽 uܖAsF#6bۇJuX]sT i41˅^ $l]]]]]]]]]]]]]]]l7?U' %tEXtdate:create2013-03-31T17:10:32+01:00r%tEXtdate:modify2013-03-31T17:10:32+01:00OIENDB`xflr5-6.09-06/doc/latex/figures/img-39.png000644 001750 000144 00000025532 12246405674 021350 0ustar00techwinderusers000000 000000 PNG  IHDR>T3agAMA a cHRMz&u0`:pQ<nPLTEffffې::::۶fې:fffې:ff:::::۶fېff:fff۶ېfff::fff:::ff::::f:ېfnHHn\3Hn3\:f:fffff:::ff::::f:lffff:=\V.=sm"VH".3nRnH\3Hl+Ll++L+llLL3H3\fffff:KLtRNS@fbKGDf |d pHYsod(IDATx흉8uƱkzgf+Id9v6 1gV(0& Hrr俏۲Kd[v*˯\~}BP( B@‡P]""""""""""""""H|y.ʊxJOooƒOZ(-gwzG}̇P)7EAɡ^0C?JO"dSH;g`җy̭yӏ5)N]. o}׀E`-9xG}ok KBᰖe/yGy\sGxn ϣǻbž }#D/}=VN}Rio^d+#~ٰJ5^71jS+Sїэ-Nav$Ⱦ^Eq>;ȃ qs}qf 3ӝҤyP^G_` |1S:qΚ\;~]g-7w(.7L@?>d R<p & }}B7^bNԩK"ֱ͒5_N8f4!>LBōQ]"""""?>,ˆAmeѪ|#pLktTF!!&"ڊԱ;DcIYQ>9|RJm5/ U>,:9ʟ *>bC'3⳪}[})D'vܲx2-Nr_7L_B~s4ħU:SER9B9=_䐵7 gYgϧȖ&);z˒)N~z_` :U~ rBbeJWRǶNCS,H[̺>Y'yO?yvUNuKt^V`)ԩ2PRUΟXMjJ|7O-gU>h<ȫ@pG |T//mʲ(;[(O)r>4A(냷˪xie5^>6 [-l/ߘByҹ#6sߧ&U}:[uΐtcSKb-z1[  k}}}i2PGțߪsY6\h݋QmJ ?޶(;tZ҂4 9+ħYY!>!>!>!>!>!>!>!>uN o˾ KLpؽ\yކ0|n<0T}`HŹc4 c!d cp:<͓0 p|;Ei|~HFٽD¬C3>oy}kZ9{|6|C;>Yfq}7l:O_җ˯|k]T$b͢}߼ۏԬi ~sO|Z= }u-"}kZrا/#K^/ 881|3w#?}8*>Wd]&%A9Oٲ 3v ω\~9,R# 3k 9}M@$T7Iz,T/.L,P{vY.bw ~s߸8 _2OeVgcm (xn^{x]4)I3?ćcS?{YOf0t(B/t4,^- 3:}Ać9']N >E\5|ي魅ؽ+;2|A-Kvf+^rC͠s"/޲ Ecs@[u6gcVp`޹em#9}K]@O}oJos狏V}~+g_V }isaEjtE]'z5ve`> k9dɪG%ȫ9/2> bu<\w?_|p攩=p/@(k|p+-t 54^jnμ9B q }x׹7: Q>25~ҁoXhfyޜလ {b2J:J_'*èsJe9 !zOSTx~ ?3ću9?UMpآҖ?NnU&~"ƜTvQ3'v--`?b~݂LLTo\zų^$D>[w16M)||-ؾm ޼z:Ma=eRO[ ,Ç1Dz΃N@ #G} Щ2SM=oNVFOԶ S)|ǕS'sx nR3qvОf3;ﳑo'b@ʌ{X;މW=i10?nA&CZԉ|V4>P'|G2G: 3 ̣+{(+?p1eG^~|> Lp葽:>KZwu5p|$ʹGvPDT2?{OL[;O>||{5!'*g1;=bpXN!K؟ԦH5> ]晿83qx:T#+F DVrD^CYrOe) P÷r8 04}_uψ3*ozLݡ='}D~) -s^y; 0"vTV)3vxIOj*Sӏi7&v't]g;~*/P6o +1ž{rIXų~:z-F\뤝2rj@fcqvWyMZy_(b`͎^C`&Rgwٌ?jCZMb)i<H$s.>ŀ՝Z#^w|7av^4^x+ 9_G)^}7R)>U\3xY?CSҮ>K|`^/z5|'HXӖSyN2} @;8H/mK#H|^_l>u}'>}$4{ 9sz7G,ߑP5=b={˦O{R8HZWID6Pms^; XáP>͓G71yYSf<E.-xIuƏU| *z¸0|zdv2:@v"+ 􉿩 c '- 9du1+ԧ/C? m"r;JlLX/h2|e !ߧe6; Pۄe$`0>2N7>|e%]LTOd=teOI ze/:_>}zF6lh/Ov|RMZ_|e7|IUs`u~gaL[țq+ԧ/C͊B-(k0'դttƜP 2b'0Z> P'|Bv#/qsB}2Ͼ p@{~2gl ;_>}i@GO0g 7O#@{փ&!y7[}W4 >cix♬c%z@P@OJ6 $!^,'˧i)kذ^x "rSzCS(`L<8&>ʲ2оƔ$Px yC|Ƈ:AtN/>9GAiOjcJqA<DWa(/Os&$PYc$vg|;꺞'Hca4ﳲ:!6IOJl!|?}8W'ŋƔ$P9z?;W\yPE6 R6 v=hC;@O3f|/>8Mp OO{QӾOU]VG?6,@ژ*|jH*}WI>iƔ$P#w {@7,81Of*yͳԎTOjcJG^v% HG|RS@ ]x=ژjv@2JoLIWXhvdPtah'HŇr99$1>G9$5>Ode59$ ω#u϶後˨+2%>?_59b 1 ?#^}6 $߽?uHC_}SL>/ſ aSX>4<6THcL?C$`}I`% T?|va=m#͍w"`=\<|1 ;oe |eg6)X&,6&b^9OF\ւ).ta ؓN$P$7߉4Ql$U뎍kIcO:WZ@4ns?.>D64<1.hO d|Tlq1(t %eLI |r O$#!ħI% ,:%AĪ-I0Θއ"9U _&$P G: Q) E|VA'B%AOJeCC? !>ć; ݜ;& ,㠃2/& ,,U鑄cB '#z& D*jJ%B/h|\ /iCL-8Qr֛$㨊Z Ƚ^hLZ`^ܤ#첚BbB@\ԫǵds7:JSXe !>ۂ^֖3I#5L2`cA!'@m'gLnr{GM ?}6\52 ħeO}ϲ{np-<աljf(gӧ}Xf9o(\@"l d\ֆYoQ]ljWtC@mqk9CM3zS@Qe7@"GeïW՟1>M9CB|V41@C P[y1h&X՟9> eLبEOf."G&NT2A7Xg}p@a4j߳FP2E,bL"'YÖ(&s1FS?|t0@}*=M:@|.E cCG`qF6aC|B"B-z$?ɪ5l3uD#Et:HFU.iH|zb!|fTł' =1eFL ljG(ЈD!>1$3-!>zԢ G]Ճ1 />N (KՃUO1DG] ӳl.DF7*َLǃ G3~&1P^| ϟTTEJc&].OD|VR!<.҉@թOED|V1Yed->4'P3YUɊcƠaA.Іt׶A消@O|& 9$RgL2 &sM6t >nއ%Z̰E+>}'lVRa=h DlϣG|Q&]}8pu@f&|.Ўu?1>zWy5/Yn.}ʎn &-7t8cΖղۧ:?Vb|ΪdMájM *PiQbw'xoRppR] #6Iy1LD'@U>nI8p^ SGݘC*cRúW׵qD}>}@GO{ODJi,ly0iG*O|MRv$FJh<᝞݃f9W0q7#} 3H|Qtu Mz8@fa%w4B|X#>\r e&ЄĘ潞Mqտ\|dZ^"j=*%?s[KlDQ qu/!ߧQG7a[Osee#=靭zf 꼵"OD$bĠ >'Xu O䍘>4_>L`<ePIg-R/nF|"o1&11U*W">7bn45` >jFYt}oIJ˪gV&P=jaÐɼ8Z0]@|'§6/0l,|\č0'Kƒ1?Jl 8O@0~@ =Pħg#U1Rө,өC:+|atҴ Ɯ O*l'qKylcloŠ:+aS >Y0 vH%C|ze84NJ%C|zeoU$cԆ">=˲§8?꼪=+5PsVK@<=Og(|D>癳jgIe1D "~"OHYvǚP:A f+zy'&=1C|iT:?DtIOú4v^yq@{1">ڮdl+>5s5ldz+glqWFz>|PXUYe:`gg"OvZi(*{@9Rڋw6tf$S᤻w*~]Ԗd:=;iCOO>D&ov>[j2AD TіOOz]Ykv Jr3 kz5{|@Q7@ק~¢Ύ@C4JVtKӃ#R>PgxT VO% >egKDlL% :몋KkXLhTO%QUØ.P6Civ@T2Uՙ:}zڅ4R`g5^=B|H?\ĠmۀS|&"sA7_TzMd%T29{'ڦdSrǬfѓNSǐo-޷pvEaC>!e>!xz@"H(9;.ґ8|dzEaQ%q|jeT2sE!yO3G瑹eT2PgLxE8g|6S+ :H7уDVN(MgOC"+ojg&&'ӐJM58@L)LIaLDT2XԘ5z2+h7O`OiB#_&N\>Vєb  DƔ$PObCcir@ ń-&ty@|1q<WG >eKDg+E4L))IĆsd?< 牸S1% }3o}}}~@1% 4OO&<&̀ ([ >y2=8O0!>#/?`~ XaC c*[+/0?LOK&}"v]OcJ;n3֘/(f1𱟬r1+<@p`6ۂ]~ZϓAgb=R%A% TXʳ]ze"L""RɌ"˃2J(U>ɍ߷qr*=}ǭǧlyԁ<)t^@#_ݎЅ4^zWyG0?䄏Dt?Ô1ЅwYfn2/.eǧ!v.aC|g!MȏO"џa:çۂBc 3C|"bIQs5^MؖVƍ)]*~ui)C31枈g/) lμ13]:Z@!> 9E{֙=>kaN$PObCG4;|xh$B|:1@8gF|<7)Q:p|jgn$¸̍i]M|_2>cjh}n=$PObCl Ilh؏gn}$PObCsG!A|:#V‰~~J('ClCjm$B|:|lX}T@a򌡙bF}L|Ϩzzg? Ilh@6]@!> >FO:/Xwa$B|:|(y aԆcnk$PObCgmS@ar77KǧzQ m7*IĆ|$P3-8&mN7>QK§-8ڹMi|$PSխħ1 WI?>mic۰4OCU@Om[p~Yo$P-xbC6--8}FamXHS@Om[p֚ݼCCяWI?>mOe#)If2'3P4e% ceBSV@!> >N!$B|:7|lC$B|:7|}fg 3u"TxR>Ɗo8?8>=jh1$B|:o| Il ]>KB|:W|HˢӖ `z:/r?ObC狏 Y'$'3GSS$6 P9ćE|R*P'@Y1"'>B0~ĆPB u:/*Dy5%A|X|p`:/XsZ@!> 7>c-ԙ: Cc\:/YOlϲRMIOi G*Oā4lCcgU5fN)Q;l'}Ph1⃊⃊⃊⃊⃊⃊⃊⃊⃊⃊⃊⃊⃊YtB|B{x|S>9{99iІeQw5w9Զ#ǯã/[صud @_➨vtu1[I $/x~W "/!l !> :O\y-pl a^߯(!>AZKsXU(!>!>!>!>!>!>!>!>!>!>!>!>!>!>!>P! BP( 66/VL%tEXtdate:create2013-03-31T17:10:32+01:00r%tEXtdate:modify2013-03-31T17:10:32+01:00OIENDB`xflr5-6.09-06/doc/latex/figures/img-26.png000644 001750 000144 00000011322 12246405674 021334 0ustar00techwinderusers000000 000000 PNG  IHDR/⺛gAMA a cHRMz&u0`:pQ<PLTEې::ې:f::f:ffې:fff::::f۶::ff::ffff:3f:ffff:f:fې::f:::f:ff:f:۶ff:f3fffff::ېf:f:f::fff:AQtRNS@fbKGDf |d pHYsodIDATx {۶C]cǔ-n㴝K5miҤNJ @H{JIīrp BP( 5w<5u^S9uFC A',!OXBv-W! ҭSN-/S 飳rbW_dV<ݓWɃ~eW',Ɨ"φ''2Ϯ(9)~X|h<I&Ί.|ڊZʎ%V6;^dyXDjgۜ_Ay.b%M0k1@+qS|hdj'j?;E˞c'm|E2-MvZz'yfYy ~{4YJXo.Z*Rx8v$M?3GGd}>yyͼJ1a'OZT-SBOש\~)m^Aȳ&>v%5\CrŚAjko%5\-i^Gs60wx\s%5\C A]& c!r7izr^ER^K! ೠ!7\= =S!7[g{"OnCnz᫓^9 O\,Z8RN3UULY3jsS[.֯0y٫TyDڧ ‰3Ͼ#CsʳayzTz p&F+ִ1Vk1#φM*Wd#CaDUM,0*sIx秪~mr0ΒB-MFrq-Km7Xh~#N%>B}U,e2/E6Hg*[TlFlKYh,%OyM^E 7ɤK<*Fd4.ȓמHEeEYrrYj+O O(9m&C"9 IZO3YԷ5j,qٷ y:k*36k҈5_NٴMn>S`׬m;1T+\OM:-tI{e/)z-+'&|%fMԎ[_BQYal&ơy`2E qӺq(u<>s9…y`j4͂7|~,G<>4ArD]h7In',!OXBg,`y&jRbCAp_pqR繠+MWLS FkG9+^6Qa<(-Kh~q2 ?`f-sЪ&X"z#~~๰<}mߪa#omg%2Wg{O5@Ofj P6`2L4 ;QEI\S ee)?M@XP)5xI(x)(xCָ7&`|yaB2^0x[@ݴ8o]:ۓЌY(7 [] rT*A&Q:p4aKeD{(qۥ:hUYP2 ҎҔONԃ;+l)MpZ %SV]@@.cQ<%Q[iiJ~ʰ(R)5=-~!φ ̴LS&Ťxi&s\EjtiWW'34Њ䡔~K̎g,VI4\! уC:umDC>ciPm2%ȓ?WDf|(E/3mekIA2<YKzlwV%-'{Ƹo>p<o#F룒_ V;_\]/W}5+w5\Mhߤ~ l7-WR %f+ks, eP ?GWtK~G$|?\ߺ7Ŗ Yhfry9.[ / nלkz0Ws \7 l3劥,q׷g {Wά/5؃ez϶eɷ ߖa/BL-\9ӂmYrb#i~Guvq^-|7c|Y3ċES 1W^sMyo Tޠx&oEwczӟEJp jYSxoE8W!1w V|y=LXYs$z׼u/L喵5r,Euǐd{v#zHN67w[Xrod-.W/BN-\UoU-[ؖ>0:b65+O _SZb|6˕Rg4(ے^>=DT դu/K q}]>|.T)U\_vl>h]qiHRHݔ׸˕_QmW)~* mи+NW"8E\qq)S+NW"8E\qq)S4f3WZ ȏ m~=LcҀ71rtGMRhغ K#tBYtM8mbXjk8BAs isM(v-ZVċ)W{<"%,2iquA!>ظ"Y\\]F?.|LdpxȢ)ⱀE_"E(udpF5LʗkX/@3 _`{u3 PL)?O-KQoc\CG6I=4ֺ B*祷Gs݆\DT\wr[h6<60RHA% (3:  ,)ק\Rp=kغ R|ظB+2Z\\al{1q7# (j-Nb0 W0f,\+pxFb2WhbWQ2|ci\G(NйO5:|ًkhz\QM5-tGM 2q07ȱ-8\.q IFrm H+t Xy½pE5\1ק;9 m<Dk>: i4sDDX$WTXq lE!%Vł)V-VE#4ez.(-$ȱz- ,"걐`NbWu$:69_c"XTu\1W:"zꩰ\zz꧸zWqWv=6BxW9|hmX)}Nr=)ru_hN$VqX<0b%XaN:ixN׀r\''אXu.ډ2$cgAAȼvP\`O[d\=`5'ㅭHj{nBKIe38d$!t.͵Z ȏU |J:"ă@i&b@Gq"{kuޯKՏl! ,VGC6a\[:R| .XXpZ5WQ.ظBjɗU^#;JՊhLՆ?` HbXh61$j9n#:r\T[ k|T\HqR5p> RoXO\G7Y Guة-`":Vz:)d[\PU`}pO,\|ZDuFuDs=\RuDHuxrS/6 1Yǔl/WTL'mnh-'6 p7Y6cߵ80ɕk;: nJ '+rd7Rk\tx6={ܚMo6/d}Nn|'r}86I.˝kĢ\gCG Ճyӧ[k>ݫVq`^}t5"gg!_e?}J/nyŻ×Jlg?ǿn3E34)Śͺ`z7WrG6B16mkvOy& h9W6lړM.VWŎb}>3r:X4C=2fjik]_z8]5fN$W[~& h&z=.EL.ϵH/w2NU) h=Wvs'j7|j|}^w H|In+fhsMwW=a)'emNwU1hWc#H-J_CJ5J?y> g(ofWo\Hl20klgd|)Ѷ Z]%; 4΄YL/w kCХD*ӃKrjM7dqRk))( E%w|2X\1NK^ɣ[oe"qyHT=1S$/ŋ"o Y#O@Oē;g iws%O)1tmɟ^ U<"f_38H }"jm1Ƨ=/|o1+lAOtn{&|zbLcLt2:)i5<ުi}V|2LC#df[ б|X3ΐO_lXoĢ%/w#馰h #l|}ɢB=}H7EKa6)a]et!Xv՛:,4n![o|1 nj~읏l£%t{敺|̥&ճq&hHf#}˳I2FyN[MN"R.%qKDAGOx)LT?h/؍=]T\- 0b:Q~Ӄ#yX,MӍzg"]==؍3=Gճȩ5dוIҽ~O~_=G;W~G^rԻ:N /^#Cp)w+HV 3 哌>`4H2~r%ɁNW.͊X]:[n&RHo?1>6U ݀nX CR{:k!uK [:;&1NZZL2-D;f;tCql2oO@!ȋ *Ww olbDOCz ˤ>l5^ezU: z_,k<0+Ho:`IR]dɥ΍tljxH+)@)};+6AHkU9E"y> g\CH*%ӠC]JTヤ2'kڵDY~t1M0b$CYLҗ `M?Bje~qJt>7MqoeF&wޙt6R{'}SL^ŗ|ǵ|?oyI3 v2c{,f1NQ?b{L/> ҍNQ*|scX]Tw+@zH7d]eǧ3 t3 54ي ? ^?`(U_b!}o91?H7nQ?sh ~\60V҅vTH¥`>0ͩ!]l#EZh(}`$>RT7׎@+0#Hi8_;Skt]`$+O -t-J߷@ ,d@dky OJF"/ Zf#]ILg^rHH2iV\j4j+g(PG7풾Iն^?o΃6d[tAzVߢ F'=c#-n&]g6+yVV qR:feDI:vWeFô&HN[ԴEM=XwBz@z@zXJb!C##PƁ1^Lj@z./'q =hzln1x_҃Xe{f=aB荭ڤ)=pL7)/ Ac؟ 01UV֦zhtBz@z@z@zXIG=L\H&}!b' q"##d= GtTCD'=۰EWU:Fj#"+[tAzhvvH^٢ ҃[[<{nAcVW1^ݢk`Os0i^ ._ ݚ>I=< l)"̤W1^ߢ TCz@ epu߃cx>׎6AB;] ׎=0,åvJ !a+K`L=LzCoak'{n`bt<0"z0A1>"zH8aV: 0^˥Ma= L8a=L7q;Q0otHLp/Okj$vo㴷c ^ߔtPp`7n;~#gnW֡#a}l:x_xnXҺ}bNHOw#>k|IOxCm^.;ю1U6CCKӂ|hfҳ+K|.I<6I6,]:)8OH7+vjoTO_7.K'ZWtV&={/Jܮ4ջ Xz%j5OӡRR۫orrz n72LPz޳MѣR- Z~NY˒d$=':NAz^ع6.\iȋ}UC_d6bϔ^!E1]d!ۊ!qM W>X=M6n{ .^M"]=tF#zK& ٦g|by]Φ5%7+轢L;; zYNҕġ?yvḾ}lyŠrS{uz,SR_wI5^:fCP梨Q| Pz%zlC^=w]Q?H]Ӄc@1z7la<$u6g I%pJ/ua[~iѕ(]5n {,)W_)E \sWw ̏#=">~?CȌȬ2ә>^ڏKUW7͉̟ߺ~?S+Nt!]oi#"ETU@P DU8K eRTU@+p2#lWXk~U@P&V(di•V{6 L4 i+s)B4 '~`QqQIP@3q:)dhe`@98ÒROiR@' (:1Dn#JWX䐛&Vd֬ h$3h 4Wj5* VzƁ\ O_PTANUXFTUXfĕ+YX,jMLeEQW fh 4ZkPTU@⠏ H<|^rj@ _q7֠ @Nҳ(B/8(6Wإ*= ]բaIQ&̪@W 賨Ѣ3}N (RI` :U"j@AT4l.8aFWئWs9VQkQ_ˌETD5N\ͭ5Cgn26G5U k* JOiS\cR(TU@Jғ@&a ڤFQzP@E`}QzHVM'VhQ6wCjqwS*R\1mW"je8묔LZQ,#⪅h*Е郾2 .c;m`Sf_PYʳ(ZBʮ@ g킆V4i)U@Su :+5xz-ըPRT (׀@Trkx]|nF&.v \n@Y"\ص=m!I @ZJPfQ(C0丄ߴdPW\I]QTF H"+\qz)} ׀-23,jJgie" Xf-"$vPQ_UPD@LUh 9 hR)LQ} Pu2W-@TTwWI+@dCe$*9a _APPQE^㤄îR,Ȉ*U :UU`xK,Z٨+`6GFWP-(ϢVgQ5NJ>Z)h$[W-PPD+jƮ-췎>~S+,>[X\XO",]+"J GF4HKQYoEqYg̏Zq2b *Z8֩ ODɮ|W Ad\UTrzj *0ˆғ0WvPe5jauשϢm_3ғ*01 v(R*j~U` L(= 9ZI`k:(U^4װzfg. gزP,ɪݛZ\P}epSqQ[!8C@SE-d}e$?gU n/lAU XDE(2DlW}h1@H]@1[ +-("jAƢut]LкR.E^:ӕdT`##V|[k BZ%kX/* @ Y_Rӕ شbL3*@Ggh1`'ՙuSNqTYBh _C> l2 WuVX澁##iyVR@k\p8>wAa@[Pq5Q3?Mmƀ]&Z > ήD "$N NyTv L(2b5N3@_ !82jhŷ֠ G 0W( B}KJdP~XKQj/ʁٺl?c'PEZb;ȫ_2o1Iu+ Qe ՌJy֣ V, 5EuTQa3.LgȈjFGUgzh4{ΎZA%|g ׀-jZ(.`T[Ȥ|C۴>,J\*GQQŚ _h.V4ťQRJv[O5EE!ozҕXJd7*fUDqZh(|[ 7'g㷮c\2 Soӓ@)zV@Q2M^&qikT~=+pPe Ռ[NU`vф@ͷWIڨ j>Q[}F+TR@H-!YT7lAU`n.k_:ma5S|t(w^C9y)_Zwph5t%ŒX##!V(_Pu 㙳 5E-2vNߺaP~xȸZkPʍvkj9z9 4RI VaߡK|l}BqŻv%BQe mD@l\M"&Vؕ=Fu qdDЊf -Hu P|)~sC1V5Ǖ>3.TzE> ωZ+sJ9!8'dMy"ʎ(c< aK>H [OW",7Ȉ*KکNOGQ(eF'~[vׇ|HD|fF@PEMtz.vm.}`n1ٔ؂+)k=#(H:ז-8ò;XNPVhPήtx쮹D ayħ\^NF_Nz+ߟF@"tڸ8C@@JE`A@*onO֎s;ĻJdE ׀-W()GrV:rC(" eBu Ȟߧ!C@ET GN碒$tIWt`.-U'ՓD luUȑUEhES΃Uݤá\6ؘcdgt.vA~Eb\K?+ *ZTR=,{BQA[[D@[PqXgMX*fl]Dy)>0ct5DrNaeaagQɃl4 tp7ي'R?|b8^akfs$rP>@.{F?'9/\%LTk#dJpEPW"ᅭ>xG˸zmopDQo8#;mܐԖYk̜c3DB\Tuw24'"UG+zP7XU4l>´,V䩕 {X$YE-D ;j~Z!6CW"p;ZϬ\oN >"[E%EXzƕTՀ>A0f`6+d0y +ΌlsQqhTy"mD<B`%f>PUQuPr^ϵ i-6.7$OrU,\NQU&Pv`W}®D8!pUgÑ55hRۃr\RʡyjVƉ.kB0á փ}C!u!D A[PqY$ >r[&DprKpE^D6'G@tAaJ~+fry~y%><  +z+ t8N6`\JPvmuXŻ cUATnXm]CDd \e%Z()" 9³u%vs;RqW*?H嵾3”WN3amK;쁗> [Pq%5 U]hmUU^@`TUf>b0ya_h( %jf@# 8.3o [+pXwOEEqE6}N: 8Q0[gSP؀jZC+qo-(5|sH)V,x6{B+)E-Ra-֩90YFlAUեQT«( r[&R-lNR=Rӕ'a_c /yDX;.%V8OR`NB>"9(X~ /e}-Y\ >:`]@d0٘q6GFTY Lf=,6puB tEJ=IVcZt.v92!'FnKhod6BRq7}]sjh/Dv,$]%q%ΉoPӽn+2x 9FV@f`)E=,#iUٯ7ސsɕ-,B;DU$1'P4־-8Lڈa4'"JV8gQAv/[XlĐ~&ןyYFTaC*sƪdsBV숒ET'ai+!;j~T+dJ8C.kV7W,D9ģB ,'q|"Aɒ*"Dܧ9l:U+&LBh`^Ԓ P2m)l4\Ѧ)˸yy7 ?y۲9 &L8Qe ~OՕ4y9C@M`|2ҋCzuy0 |XVA_AV[,dސ<9<V(Eu`M s|)[" !(_+'Ċ܁k?p87N|*,b>P2d˚> zh Tߚ*<( n[ =MNWP a@@S21"ۅ [ je?|㓋|8x"Cڸ4_SgewG_gjU`/_~%5.-Jp¦p\(Y>XaW"pp܄7 'G&E8տIJUnKRS_ᴅX-_X&]!`j{Q"J=( 74aaVc n;0W`)M?y}dd#&2ٿ|=ynVUˇ9^zt"0%m++s+>@:"OW" çMO׷|2dɑMLO.22 }We`v*,~T@ev W4[q@I`"hK(CTHf,+,"_f=ۦ=ᓃӖO;29>2|zꯞ2{ޤ hEԏ KT$ۂ3Q 7vD!" $EC4sp(.ȶNӍهDWW4d>,iNAd)&BTatڪIPN\AV[,dR^끕;S P*t@ ia:g}(#؎3dE;'C),|D4{Z(ZLR 6WuA S}9\A\kb\`?-:TRo?ws {;J|P^`wr7L"r#+/̶PN\g\E3h _ ĭsNj$V=IG`AK+fX-<[W"p>dBxgU2Lp*mHA߅ Cڑi˧n~ΝFV,,L G_2m1 d s;b"*>c!.L&`O|$]dO4 , rHD;dh<t>|#(%?OuX%n`-Z 57e34,BVy e?uW'?i_\5A%BjmlӮ6+B çΜ٤D!S.8|N5j+('./!VCjēk&uk\qGžFN> o.yښj ]gl]Y%8>N~M|ז߄|szOtMj!`M}c%[ 4嶀;h1B'rm+1ɑ 'ç>yOg"`~0UJ03肭078$'0NQg_>p+'K&^ oSP h,DU]݀M?`qTR[5! ¸{u\UDp2+ KcO?5t ~hF䷻}=W1,989288 F|bXEI/xV˺2'haTHe#cU4HW!ybY8#=rdeDn@:"O"`\4z ds&;,LBPaE*꭫`5"T$)f_?ʓ;"PqAJ_'$&N29>ƅ*E0~Hf@qQTW"̂{6x2{&Sp%ӖO |PY>QV52y WڢYWAO Ajr[e.7oN aS9rJɄS킧&Z'*Q53wxes&E0Sd)&'LCŞo6N@ϢZ}#7~D#Jn4GnBIX/y-&ǂ/T'>/9J6 _ OpJz>F+NF[,;P+Z*؁&;1$O Ku\U \T~.Dc=K&'ʸ13SVڍ>>@F= )O>y'ӥ7/4ih{=1Mܚ"RZMj@)P]9hB@f2w}<KDx#S9ڞ(O@ X-4D%w0 B~ߐbӂ'C,Dte>rF4\:甯E*rՕWIbGZѪ+'Z< ~a,QqgrW7#;KU>tYD ] (Q}&ugcbGXWa9yIϽ!' KL"p g[ P BlEt>~dDɓ=0xzG6ia鵟O^uoy#&Br@ ff<\hamJ/b a~#'V[q+88\6!)SZ滠FpڑiSD=޺tKO.g~f9f_\JiR 8ģhcX/ 7A~N" '{7 %8ĂVGQZ786+~Q+J(Zf%A\*$SiS@!xGNO6u\třΜSOT4'S' P|ӛ&6A:ԅZ![M 5$-e%B>T>^>ֳX?3`d0ЊvtvENi╧{d <m˛t_o<](2N 6NJ.Ub_h b)ݣqT_$40i\\U+8~?mUi7 y5`iL'x:>~,`5Tmț[Wj5s W. `3TOU KRwQL1' [%O%˧Nq>9s⠯7p]%0J0u>evrC,q>(I&4gzv[zԩH%yb)>帒| 1V} <+h)!7@FαjssJ(?];oraSL&xdʺ>vyYD<+R ^픓nบQ3$rGw1SLýL)H߿mi>> kHYYںZYF@,vhz(2KDQ˙QCֻdʶʸQq,eg3{i9S2 {6`d)ݾK3&Q;śn[,͍&46jzg׸3z(rc{SkAVOwWSɒJpav-]j-͋Q\ U׍cuA_EKM :ֶllFǺW7w1SO^޹re\d~0N4mŵAߛWۨ!dq\e~ccBdD +p:{XWu"*O;> |옴oR'{VB%qֽ$<!4(H\sT=}8=FFTS$@=DW!-L\ ;&wQ5he}7l5k%8yzý?S|z… {W~o'p(٭S#o]-\j]mj/[uC(5 ʋjsO\Mv:h{$ {hdDS;3p d#!xiC& t;&jxaw쉋蠯yle,mJDKB+*,v/룽 )9.c2oöEƿӗpJ9$*r%'6)@G&ǾLI8\pO;֯K4cZm#L#,"R[2s Jq|჋/md&?xi92p֧?OX5>JzX786攅,Suo Wm#B vc@zkU=YoĹ5SN|ڐ1i_ܽxQ863K ~l 검m{+jݻɏF]=oY.d]][寝"'O㰩<}m{WӎLO1i  d^`ڸ|fv˓ -ćy7h O1~Ȳut\UD $/{c2k׾QN0\㻜 ,ʷ yv#(6|$ş>M7x,y"(x`ɦ_i󴩲g/s 쌸"4/:<[)GQfj0{~2MN_L^ҶiC,c'KI>rsOX/1vXjl9m:\M8QJ5lRFm[-ǂq|Ni>瓉8X]TAƙ'3V{ tD` H#*ѨV@slѴx{A <2%䑩|3W^pŶB|sp0( |W:(\(w>dE/4ӘL=C!|z ?^wiý4&XH`$tF6~VG B+*9n&P2h?GN$B0}$ klfNLOIK.|2HyEa; NY@#4c-9N2J4\P8}?NR-0݌4cN~u/?QFfiSKEqIJh׊ֻ`EoUhTqpi qՁU1`CF~)9mT֙) SLmTSýXOtk!9);#8ƛcE哝G|cUSJarUq?{̶iu} pڑ L߼t&}֧tSXK8(_\I+oڵ]NYȈ'.q Q`Y5#7(%.%iF=b85t+iӎLndrO3qgod6\9K;!|IJ[eЅrp¿wܘRؓ@+|rrrUee&{WNɇRå7/dW`깐̱5^{V_@!aF<[ M3 B8=ۄM92_zRg~kY8[t̔~3*<`rQ(Q2֫B *lU^ThktU6DG&NvX#aNe/@}q*O+c QSLh8"ILC$ 땢(r 䌸.[s釹/AM!tOt4ddP c ~ÙH31]]UҺ؍z+h8svuM9]UBćSK6r*n`-M}pU,FkGKA^%I-V& qvЫzy2Aξt]|0N}nHYNLpF R5f%Djs']yJNG Uy gݟ1Lt{`AHX(o)qa{Uo d'L8Y2æ1,L2򓍜pLv-Gw}}Ί)RpA`#UK ]݃eiiK K;2 p%%>`{إ NbWYXM0re g`Wd[$S9XFN;8Lã#/m#z|C'|>$Z1_$S>hq Ahe?ܿU9G|^L>ɒFNI,m#'*;A\nUENSnrzIJM^ʫ$8̌ 4P-vl90(߆@ eT SLNY2s;W NWnWXiYA쌘,ւͱ,zje<prړ{?pp\ؔK6 $ ')@%pL[>8{7΂xheg\i0p] K擇 B _3_y0`LN,pyNzCOr`⪷@0 Y_8 CzpHv6lL-1NgK~FN\䄅iU[ H1jw,d rj'QooKN_}0*1q( NR <-'.p)߆d4iwJ.m9)R r%}WիzI84#\3=ytyY )9"9鱞b(l}8$p0 UVdC4g#-3@:> HPi /91L-db&C&XFN{wzc8)]S̈r]OV@79S}eIȪq,DzN ME+cB?Gi2oCdN Em~dL7?spR>1Ox/< LԜM4g>ZY&&!Q6X!T@^ny.J FpJLRp\kQGDp%{ȜϊI5p[#"ӻWnP|8 8iQbU  AΈI= A\ݹR3d&3t2${`0GM;2UdИ Y$V;9#r3ԍШZE?L14`)CU>kDmw7ڻL*DN%U|Bf$p0e.pڝW7/c,3!hdi*'/Z2L2 MXdwVi^pvs.\ %²\ۘL\'&%كWZ一ɒivLr?؜P։(Th^-g[]& ,Ph21hӞc8/<2\Txδ yQp ^a`d $fzGsKQ\ɆVW1)2mZr?|{$w1/IxL/h&'9D(a I`Y\qJNdJpn?&dMq̔#SM92s-~Œ[$u]UuV,pHDW' jwFLI`%'f̴jXB)iQtjgPD$ d#!I9 uBB+gFKՀ]23 Sniw<\^D;ZQYUqVni㬡3)"x&)\ѕԺ5Ƒ UsP (N|8;8k\egD,$ ; 8GaC)wö rG&s|Ԕ{ϥ(U '׀H&7gA<V=~%i^xQ S)%K@/~ y[ *izbtUDE7GWz㙰υI>W4ƒLӼ&dz{PQSL3=?`s(kxN4kQ I J%F\D(gђ|_ܱJLɏ,ɴ9KciöꕫҸj2ERDȸ8 iPcsE8Rx1©JD9͓";): uMf&xrJN =iUVOW1%)!UZA6Q1ө/ov" =6`Mַ8SJ촘 נWȆU\}t_N0E6g]?!F_b?s& N2ɐi 5BPAj-hYi3 K8 t-g =3b]21ȔRyC$G&NS~N?uz ZT{9U b8>" PolɴL)ɏL-FҸ,+j-*z; 1L`cʲ-s&`$KK.r2`%-*֧δz2ȃ+T-fbi|$/Cb$/ak4'WYDյY = !oxN. C9SLـi=jyi2?tC3ٟQ])K"j1ZīK`I iΐe+?^тLհJ&s*f7*F,ڭU f9ͫOӃ?C?$Jpz̙ML0ɦޖLQWfPZ+jp 'z=|g҃_ݣ%GnoόG.w0æLɵ Õ [͹hQ6_U\ْ& M{&c_89$/<ڣ1)*q֦,,i@ÒyA{YQLo_b8a&ka~§۔9QS=C[r1.Qٗi$8=g҈F`2J]8p!]}I޽fYzԴ#S }t0|ĥ_V`AEV'ʍV$7Ϯ3"K[Y 9M&db6Xrp2|rɊ_!`rENϘ)xKDT!i"[ӴX$p+춇vQC>hai!$8vGyφd2d" 'rWBu+ЇFn.ru|9Ki^h8lʽ} Jm'r JV0UQ+po!NW]ՇFrڥ/R@?/I:w;7w?xQWil 6=`pCa&it}B9|Q>: 'U+i$O,T&'rpn XNGt2|!z+XW0azWuPQ^d6& {߅?LIpH@[\J3Q*?=t>yp2 B9ǁ,߫m(ہrj;C}l!|z_^OO^'NR7'r!MvibQ ~ S_~ynw~tƏnWL2~4oOAQmjO޳y"*@@'QW|>2ַ*}KQE1%?{Z=s*"jNѶUzEMK-NEL>PKULXn(*09Zj2g-U@S@%%eJ*2 , ZL W)frmVPT^'RD#گCRTױ9Q #i&U@MyXkQk_imQ"2*uQ(ifU@EET/hETKunU`@o,*EU n3T(tZP*XR8Xd_uWRl-z=[իm_R?5\*PPD!֬@R TIURSD{`eN3VU`- wu\15U5: _"jVQU@WöjWdPlSETΩ@NE*}#8EWD:(W$PDIuKݞ˞:+Z (ԪT)QRJj=KU@j9U,pn+PrifU@EET/hETKu^խW FDجŚN;T@W4`]_E6V@6VXW)j$V;3lm^P@%ѓ3d}]HCqZՍ)#* cQkP@7kAPDS,UR-V (RinЧMݘbΎeNj[5NF]h5h t[V)EԲu1Gh%%Q`e* T@HӺA^uDED%PG#RCjU` (iZ5ȘE4=Scfw U(n*ZV[]nVkfSi&mG+:2vEPTUW@Н;$!U`&Q3 ͪ* PDWT.hKwJ%,VQ@zZVXt#RD-xuUj J)ZjQU` (o @_>n_Z[,]ztRW(+r:+/o,fXdrghP5dU]}iUPD9F"ͦVDPDʩ*S+S"jy6;+ք{D[\ELVTAE!"cTV"jF:+UU@XH: apIENDB`xflr5-6.09-06/doc/latex/figures/img-07.png000644 001750 000144 00000010336 12246405674 021337 0ustar00techwinderusers000000 000000 PNG  IHDRn-sRGBPLTEkف5¿stRNS@f pHYs+IDATx흉U(hJZVz03ldIPbJAz(Oq)Wom;r3;1ww7|Y}++ S:8U}0W* R-.LA:@9A_ +m;:etsi tb01Ԇ9Hn KƧiJp'CN مPLNd:@XN,P7 Φ/ ԉe:X~@sR9@]O`$ө#y5C:N,P'YXod׭^FN:1b(Qt ub{MR'uM S_TI0WÑ)/e-\X|,yhnZ kr4,-jKԫFO>mjzEy6SN-Xm8SpnSP^ZRbs罇D~R7&6dq}sD=e:OSBƹ ^l=b>VW_ץ_|uI㜺s͋}Pא%Di5]MΛ#U=V6k"s/{'K`OI9\jh%V⿼ ;ʋm@79|E*lN^WLj{}i.NoU]g+.mݫGt/š.u</̥c1D=<`S˞|O3i*h;$;-2s=kb-;uGeZmYT\S'NslljnBڊpIt_f^-@|lAcO\Etc'BK 7K}JRp^u1nXW6l8xr<{D5P}drwELwGr$#jnIr,|H{DWVh3pf-xWGmju>Yկ\MtY:.bAD[/Mb IA}<K\Ӕ9uY[]ݿxMyƐ$UUt#nK"PMMI:-̅´H&r{]=;1iR}q>gͨkV(ڡ$gr>4 =uII}` f},Juє Ju:FC!7sVjՑzgjfPŒZ4BԽ9;Wؤnp::?_&sؠ(m.0gnCNrhԩs  a7׽*+Ei!mzIbrUpq`:3wpu?SJQh(eaC Խl(JJ> Ӣ5S_]cԝ9̙%_gDNu}r5w}ԩ!Janh^] [|Q# j2h/Lh}8+:~va>xQxc+әXJ#JA[~ kzmڶKcP(0TCP~~>,(£XUc1nq蛠 ɓL~:^^[u9u_eGrQ c|l,ԅe :r2D:tK={Ka!z8%u+A}b^BAAZîρ2DWWWjdٯp6Rx8fsUw {'@%ܴA08Vnqi(b=l41mz!7`xo-򺝞E::XPUuZ@0ν(Y:-!2vwEq_TٙTk#]-k΅:ku4>Rs~1DzK.{N1]ۯU7%PWx,Y$nFK rx<ҏ:u=?7E/sю8w2nzGڶu6;K܈|t΁7[Mo0uu˦HKFTa5Wfbhe8Aa$ԫ>qs/.DzDؘV4UH*F-`n<==e~9;MbR:',q]' ԉub:@X;ub:@XN,P' u0{BPBekԉEU6u2QY-Laܿ^0PNEAT9@X`4Dw\WIENDB`xflr5-6.09-06/doc/latex/figures/img-09.png000644 001750 000144 00000042064 12246405674 021344 0ustar00techwinderusers000000 000000 PNG  IHDRz'gAMA a cHRMz&u0`:pQ<PLTE o o $^ K$ 8 K 8 ^ ^^33333 k  k  k?  ? ? kk ?  k    k8 ^3wtRNS@fbKGDH pHYsodBGIDATxyF`hmͲ)lEuxØs~o;K}RrЄάf z z  z z ͠ z %PV_z u\{&i%PV_z `Vy6ch9&ch9&pch9&ch9&ch@1@+14V0OM{<h'@#1F0MM ht&pch&ch9&ch9&ch9&pj4@14@#1@´14*ZQ(?a@J]vQ{?vfe}?5p &,nuÑ1`׉)fl~u 0u1a@I1aOZ0a{2hj Ͽp\1בp !z ;b|7~;a@9SbC;=)"7P <@1s*EPȜ% -6XAc(H>2 `8'udr  c(xtQdz %,-YR@*.!2="ę G"Ap6'w qV\@^*L/c( rJjbGII6!V{ĄZtr )#ZKN ;L ^PcPۂ̹nT ScHe95U5 M1dr ccD cHNUB;DV1$w6D$ϚS:edr i._]2˂@*5 /O6cHxZdp=(O !< c}duٕcz i_^&\rw`gؕzꀵ 43* X{pB&V^Wp8as"#L@zA.{rc~0@,1$ xb :Kw!kL±lNM~ѤijA1$Hq 2 1cv7"'V<\?"9Aww"[d\C{<4(ȵwB[z<iqڻGq8TL bw@ w?{p bWl =1uu&z}cA8t dصwAQPo o~dصwA,S|46AMv <䀱VZ2]\E@0C2C]@'ك}>90a {D Hc/ wc qr1ȱ Ⱦ5Mh]\Bj&.zj7:L@XJwnOR,w,yz\{?qǮ{[9nDD#y*azWyLutdz .M9^/1>D5C{JzZ)kJj)4M qZ3_SYWYI=) *`u uc0|2o\no UrxFz>-n A-ض=ƭ#ȧ.;|e)r s_ EvAqyLtoM~ղM|h]mk cG+m!dz ADs$de< =|D4Ѕ10#qeJb+|0QȽ\ae1 GUKDh{y.X8ߑqɻ;_=/QO 8_na["qy#GTK԰oѾ_{ϴ.@An_b㾪 xyKC'>Ą2ܸ_y鱹˻.ǀ lK/'vY|@Sؕ0!J8ȶd‚L#ܦ5d c9ȝcJߒc (C/ї߹Yɱo/1`CƗALY9y4=,rc%+v /=6=9rKO[^%Ǯq1CN"A=4:%YY2߾yoOdz Fpz#6D!9.|:ݝȶ1\ ' q -"p?$tȏ 'qlpy4yym&@9ZpKy꫹Ǘn.= !ȑ"r\2k4Yr ADx D qX1PAAT"(AKrocS? C8`{1PAmWk el/="aRμ=ȟs]''i-5ȟ!¾ ['9#~Ou!YIOmu^0,k$[rwr)  Avt^ƈ]=-0m)@uOښ;- a}@mϺ!2yb9BK['n{*_:bBy-n}@m W8D7ٴ>z ,}䁷Ȇc6!MiFT[JA8<3MacwRA AV0.IT$zA|43@]9ϹmkAK z {A!M`ce1|TW}7< r=0B#} %} O3l|u;`Ȉ |C%"'x ȩwXRH=^^5 E9+˘Ab&ݖy vT۲_ؿ-mħ bW@ r\3I0 rt}36`V@!%/H+{fqX@veP&VoNYe_C 'ر=s7 Y oȱu \e[Y#[1 w-ͻ> d,7hQ!rV˧U1G [ zH|]esd-yt2{O$7Nh$[`f Mygw r?[Wd薂;ޏ1eVs;A^mXi xLw:k][CØ>oŬ2r+A]]CE]`tAV2\ț_D =\vUn"M򖡻An" (n!ȶ&,-d \n!Ȏbĥew+f0 =]\PIjw<s";dw"0Y7(2nܹ<̽H5ǽ<w>y}]r@ ^|qy0=^e9\7~nZ/,>;.z7_xGvyXņ>39宾_\y9f W>MYczdUdʼn<4($D.^|/ǃEփ|-d}AD_1 yZAV6)rIgٰc +ǵYiѓuˆ 2g rL ]+y9$La-z A&;;i#oY+خˢ}u!2A&;;g5e|9ΰYhSC䇰dSy!\pNvx, }^֢12{1W ? At~~1u^?+=Vkp̋Diei}zM 8Juq⦚Bܺ*`ov0/rx~V7+ 9¹W}z9'e埦1_?+ +&+y7_iUX sNaLqPC[g 5X cTaAom,g(գ'_~֟UQ~ֶsڄ'u^%si=&>GH u SZ,~"j.*ӖSC ō8W 䈏;yNm^$9봪ZȲgWN*A`Q3;AWʗj1A*2a?!>L IqM|@mKo wc7ۖ=+[0yL(z{g[]7&gD!irr7!14qfhՖc[ dq!ǯ냼qB?zlcy#9ORyA-^y~Yٴw8o,85p}vc1jLgZN&GdIQ @ Zr;mz_n~"^B2NŚO.Ro9|a}<LClp[ v`o3wI'>R'2Nlr'd6LJc+FpNW{16\ xscbu*tbh'G5o,9=Єoʮ`'cM(\'o$kz eA|~O3;X.(y1pn r@|~9M;TﷳZVO/_9<NHA!);98y7Pd=yﱼ'S-v{2ưMKqV}e 29ѓNI|`OlZ {&O4*,aԷpx>sؼA:JCT>]GE;lp #$M*+d  䂎& rM'{#>C9"JEmxه t c(9drE噢}O0<_z?o?_?E.RDž1׾I\caW-|QX=֝P7Q )' -1y{B=:@cT.9NX+,8$7_/K(ABɤۂ&pj:}cZTq{.i _%wkA֗T7Q {% ?͋<I,tpBGs_E==oP6H[.[ aIe՝YJ[?Kc7 O[Gm=k8njCeʰ+|t~3bReA[\$yu1^MK󟟩--![>ټN搵%)yܼփAN:"qq./v#ǹ1+/x>-cy'ox:/ZXG mam BK(-P?x72gs]r8> _˿/qP 1ˁ0 d rij)lEX뇿,/on9X1l CQ<~z7^TaYraR#C6+(2dc~^_Y\1^&oe{mrKʟ C},q1/4Wo]on+E;I< VD ȭѷC^\[2|;r N]X[B(גZǝYAYBl2# -9}y68[vqV/Zej" A{ۗMO}62ƋUߩaƯ%ɴ;a >Գ)ʟ'pIxӚs~8A$yGm˩1A#^]J s)Ȇ AVvdP9^ANJS9䜟oq~ /d!:ႬD o rΧ%rXr\>e+mB)c3mNY]ۉS$Xjt]"\_i mFJ:cROo \$+"  ^nj/cR=JI5\:-.l ZxwKN<|bKT'ϣ_v yPAVOrnEQͅo9ae#R9v=+_oh;:t!i kK~Yp1.;yĴ%<О-y<8QUne7Orw$+=0s3>a+ [Ke˗#U7M7՜=ARLZo),a9a)nIwoyŤG[!ACoLA/x/ uI?/V}(N[tyz>Uĸ>#Q<b KchͶ@#*>/7.o;|#(7t}:L=cL^Cy7H[X[Q9a>ڸN|OoN%Ll Tەy*I%/F24*vKǒTdrD*n ADueT 3P8 qqyI ߦVne&9`Hsu*lO !rP q cnM9_FL1#X*P9.dr r3VP 8 ΛDE~6c#1#+_&.p  1{o"ϕk*>EzJ}g%OO5̓>M#Şi2nr|N/;GRO/Ov3J VzYL'{ rܲ u=.x{G Ժ7ܽ"/JA6x[C DCI_K {\!N%F ǭy,[2; d/Ӊimaq{_u5? Wb\m~彾=iT9O"޲S[En)h Ϧ wi5Ƶs^Q齺=yğcv7qғJ""o³d)cSW^8 1?JǯK{e /D*5Գ;_gfʇCr%p<.;qsC32RBmp&ٝ9܍A޴;6/kZ9y{CX6BBmp&!2o,}7n`B%/Ad_gwh//}/wmⱬXU}daJ[W-WCS=ȾpTaLy?9n˽t)ox2E"JAOE{f$VcY9/ M{u8ST{]A^~q>& [$R^bL |ڿ0de5Vr?_rG9> 71K={h/cY:X=$(_tv r`Y^A&3 2ڛ;b\A\/}j{9`1A6x #1M[>fǾ/ уټ3,A^e[Buji Oy9@au=Ǥ{鮚Hx||#ӆ#du5/`A_Nxl?{P#FN~MӒvt1 ScQ{yy]n38/BWƼoM9q~d GL8~빹U {RBF 0#P1n}\4!񯽿K7-:-'[C.sxCΓ&"Kx캞' [ _ꩫe x]< LAx{<)hkENnJ{]2y}2_H=YbɅ1 TkɎdr `Ń,l =*9p yLX AN9Ox%r $%RfV68gAztr/!ȖE^N?9.z1&d =5™n%=W$?}قSՌ*5вTd/ <@\3@Y~YAVch>B/Ѻ1иQr)9SLVC=1n)ɾgE:cZ Oq |tQc㏷{cZ ֍sYͻh=/M)s5՝cXs̕E5vz)dpW;GU][B8@IF\kIwnC<Lr$f;gM3 8 kx@Aj/c(,A&P_r 5- b `r tB/V@=s} cG 29ch9Fch^eQ{KFdC\ F 2Ij)H2T#&$@ErI2H=#H2d{Ʃ!$ ?t3.JkbϢP=du.=6L>dȇ`h=&1QdY9T'+1$>yL @1@#J@~Ï@~A&UbXI2䖜U z cQ,t 2G @#ʅ@dOi>xdg s!1$\v$I*ImFdpٵ$v#IHBI2T #I],dPU"AY(dU"AGЈff@5 J _udyt 0cW|n z G&r ڶO~u\~6}@3Nh[]Y̳87ɟtݏߌ~Q}w'X^I)>^ 0)˜Żu %n .;$y>|ߎ'WeNQ$<>1J<y8|j%X1R!'Pƾ{&p:*C 1!sZ_NcŲj < $.I!bV1;TTr@OC&ɓpPay:nMJ.؇ =m EXcG6:jv}KJI$9*zX %?'P$ @Q=7_HQDS<7LϘMiUc УùJ2@Y[+ccXgCX8ʳ Aa3)C_$0FN0 =pi%#R` УAfz"aH 0굎a>JXfw o.|t‣t:/G%瘸L,[Ges4\K.Tq+wr>rhSIKe!PsJm..~tͧN?.7~?ǻޮ[/OkCBk[[P>ÓBF[N0Ѕ,-ɨ|C^Gceqb׏>yz&OUߧ n]?eYgϛO.о]3ߜW3D) *e[qQRw+meig.z: ~j[Xg[Oܸᕖr[۳|_ =R{/UWsyĵx[$>*+Nse]i {%d;ΕVef+|O!yeY[֫w k֭6imYv-]:]neW,?t*U U1̪9F4nXtJacQ_*ǹ9ݑՊacׇA}?&hNnMeTu+jT<'=-쩌l2BݰErkf%sK:nbv,)ƌGDNה6=!OiAw?;.JcD/9TYJt2:7tjk$h=b#ˑLkJCQyIvCt9Ic+ϡ$'z\AՁ~AU=Y*I$oe_b+n9Am͗mMtP-\)aͺnBiմyԖͳxU|?nЗm7upK 7  xw)f[w-{Ͳ}?w4}PmT{צ Q6tM^7fF/̕ay}i i$ ,mgsCYȂ$ sfSs%{)S0p.- E?nD@2U~PYn v*Ӝb&U'e) 8 Z04~YTvx# (\mk9epZȜ-FdVV"b%C9SSt/@t1Pq~EV  a9% QBEZ٭y4SΎr=Y"SC_ӖTT:uqCt+WMcaVkgjPDō:Em<`3vr-}'yb#EIxs+2&"'̷}n#8ˀJ4[MI#RY?er?HgEhƳ s$kf$c{Xך96uD&KZz<}Y39yX.)^Oԁ8lQnS kc-mg"ΌT̞==.Y`D% .ӇɉZc1s݆cڎcb+yI~VrWt +comfA![, GFsx"B${̱DojslVrDP h!\{(ZV\x2k<ԙТzF ٯp* z-1טU) Aie[  ĉIHJyDor 3Ȳ/p9bK%9^`JLUZ4ǚg2(PIo>ћ`ɲI+J}gy| &ȇWaU AoIV +Qpl rH1wJ.@^AΗ=8&2j^5IyGq "֞ÆQQ“!/‹&`]# |Q(4ᖽBRkU\#r0c@)_W$lUAYa#>Nۋk|,Kc/9>Hά I4˕ 9emPQeDj xp9du%♓bu\ir\lko %\S;\\,jh}֎-kP8(g>CɓeMJqȅaKHr^t_o.է=T d$FQQ.hZj{/KUrZ@OV.,+Dfp|jZz2%ϔ#vGnVG"8O"Nr\k (89 gjG-ok'?VLp<dDJYE\%,$3H{s4&[PCUWQs.°6Ksm 3ȋ0SH1| Ҩ̈YC*<1rMZE0uܿw(X;wuw{2ONͨ]sˊW?7e<LQ-rm}SwjJ(ٿI[CTY[xmr겶T?y{x9K^s0Q.eA\髞:Y3^YX6ٛ %#S]YeAPw5jsxըU8x}0Y"kEy89xv#fY9ñf8$p C8^ @2%l~^8bX-,oR4,2Z/PG| "A^?t.28^.6 Q+X^'J;`-0y{.,πt yӵ~T啣LM4ut`w(ˆmY`y}(麯z8. UfYuYw7F@134r =ݳ [ he3(P 4ԫ>F.r{^S8C .bUf<ebh.\1fN\r1ez*K}DC導OO]eKj52i3ͪe|K4{2Th6 @D&\t>|pБ;\i<}4]g`kK=G>tHN0L&kϫG>X"sd>r yo8` Y&&JښC>H4p]9f`lDd>s \Kc2ĈW=bgj3@zu$U>ju)}4PS_/7:\P9pX7a>o+i4y\aw:u={g}%)/8yzX 17S uo^doyKs]!4R2S?w4w;Dmdyl$3Ds|+c~PHh6fFI,(YHh;H}NZ2XDsfH|,m`QLQmX5-@ϙ#S@4w[' 0xF>h~ю ($Qh2|h>QtFa.9^4{ۣM\?/9g0 ShJfĢrȴhN!,Kȸi ќ´䋌c\AF-Zfz),L>ù!\͈iќj4<7n2 S.|Gk5XDs %G `vőt򸡚+Аb,V3jeڡ\|tG XvFՐ0xU3VeA4 QHiՌRvJgdoU3@eA4twf9eU Ԉ2 KJ a*h+Y4Mv5-xV7@7U4:{BhS Q)NKh>]uXOhNl?L0(I[J|y6 :yv ME05f%j<}Smɜa }^H-9lNm"gjY|5ME05-޻kH(]ӎL`v*&gvے j93!_Q0,w4W0,6ZE=3y>q&F/kxr] |FB:Zn|:2ls[+u2IYvp\:#E[6~f<7sPHo52uAls拐=$514Cڪ(dfы͗jT>KSJ ~8d(TK%h JnhE}/il6(Fߦ|y ܖ{l htX(EYm9QY`,f ބ왩v<(tko0{f}67-&dJOPn볮dYͣ~0Hӧ ;dWhBUN@ N2$ rQڬNg]aҎ6h6؋ӑ|p*7UZWp|J;y7ݛ,\u'˗?nC1JԞU5pѻٺ*+8Yb;*pA]tr>:D4sPzr;Sih|tδ|fPޥ]J;f$\8s1QqY"U)tqUm lpTŶ-qDCD,.z4́ M0!Ds!D3ƗViIJxڞ)D3: e[q+3B;Y|l9(驪y4gt7ﱊ<(c2G gzh~Q.Esߴ'g} sʼVkDB'aPYVG"&/_&th~yO^lgUFVD ]l6~~L5'MN \oȭ*fMYlCJnmc_4uB{\ewV$|c? ]@}`Dəú*r k?]u*CL4KХy'< UI4wW DH/]4O/,}>ZM4SxU~%Uߨy֋#;>f{81Sumi_΄OLV[WW%|H41*e~]\{c}4h>yT/Y+'}$?ηҺ*̢69S(3T+晡;G4f6Q$Rdh~,l8| prx4|4wf23l.U4Fy 5gN6gn2"!]KG#Io;Rq4;(qh^=fB4'q/96:*}9bfskW*@ADsKu?[x f'n?Zu ̗\{cs5A lYHőʹhN`d'8 $ W5:uZl]A[ќ@DɱC\ 9őͶhNaOɚGRŬTI4*d({oh0 ("J9k ߾ő huc$p՜.lumr|͉dUdXiD4l#] :NLVAUfإDs-ٕ?vJ,76W4ݧan+1˗⸆XWA4twޒDo4s|F\B0J5],s8̖Oy#g%- 8Rm>DskA3~/WO\f(w]i4}hv9l0GP].)Dsk- +}1IW>͑Hvot 8됇P ůkٳ NOh>ζ$G9~$E62&!O?8dz=Ljvȷ@.A4'Q򹳌MjjoFN=Q0d2R4ĺ 8MZ&6yt79t°.R5ĺ 8G'8źv%xf4o&A4'8mi &DKs!h&UV4/sh;1Su b]|v1GhN1HԔk &mMr9_uh?J̘XW0͊}SIsGsc;턆˔ &dٍ#r"tYVh%]]mum]%DՈ^QPn͓K<εώߺT hsE˕?rde,sM+^|ьň;ͣw3h6C$DsKЄщKϞڎ7.L9zD&ќÒ]5\;p95w碯*hNaޚp6 (͍tOR@TA4'dMp)/^luihNa>)w?Db>2{vVvOQhD4[GѼ%J̓{=:͙Uh>Qm@4qAOb1D)h~IGpnoAWU=$݊HmGa3~ ѼG2x}ctiBfd=U;ɠ熭(phI4_p@8h³ wu,kYQ\5glg /̈Xvh>M0LMb"B4w.ںJs쓛h>0$4"&zBI8,g*f; sї h9 %lhݡ>v@Ѭ$ DdG]"hNa>(R~c>xZe?I8,gfUY[Q*hN`ɹ^'Uee>$ʕmuOѼK}쀕|H4 k@4Q|9D<qO:*hhvX)\4w3 %oVfc4wD*h)+ xp.[F;Uhvͻ:X)M4Gu0_;LO答hށDroF==ߐ]4 =7=|۷fWWӴsb4Y m;'ۀQ| U}ζc)w+4.!wqK xKeu".>KUyQOx͈F4+8"/ܮ?c{f%D4#h/0 -gy~EL4#hfh;=WG4K<%NhN%f:BeaW7.>e]6ONlB XU:NPEhޙ*|@{XQsF1/fv.^+h9QDi˗xы8ל|d}s8w$^f4os=ItoK s9d<挬/yh'5dBG@3OT5G\4:u+3+.Co1į!4nXϬ<f/_75)zF19mc+DYbw|{XK杓bC cݶ^ɕdCK,k 6,bUuFnٚd]Eۃd X$=E@]>zhְ:ҺM)fdm4OxiJŢ9e6kSiuќ%ݽ\[XD4ޢyXcڥ҃{_+ Shn~>)Vb|s~.@4#30OD!Kلy%n_" pX&ͪ4PC+h SpX&T>,qG[|4ĺ 9%lѬJ4ĺ 9%lѬJ4ĺ >zhthM] 2fPc47]/]bL+ HՎt 9n]h$͙>4hVŻhEqTFh{R&s_nRф*%FwACh갌K5뤨~̷B|4hV%{f="quUuk&kiB|!iC4褜ٜoiE4R IhV@4>fV|}7[ҳhNi ch@4ۀ5 C#צjHfh\&k"e< F7a37];U^q4y#*f N7 c4{hfBYAFb"쬿hyќ\,hC4W8+7gsDs a+@P+|-$s D!%Kv3NsLlC4g8,9ʣ9u{}@4MqP,S-=2|Ò7!5:ќq9S2|Ò7h]e"GM?~ڑw#8hN m4 Di 2 D*f" pXr&T}]sѼ!4eI8,ycN4k;W94ĺ >z]'3\<;-iuDuhN jgvikݎs*5Wpr#[N4'oZ_Ydkq\g尰ƃc*:e?,/̦BBt?\QXՈ-E>rl4x}dXWW%0T%پzoi@}ν|A9 MrzҞzoͫ۳ޫgv >r}Mzg`kG*iCcoF 2X*pkǑ:OUy4;|Z܏6Hc?4WY@)8"g<=֓=SYuk Ѽ9rֺI4m&S#w駂yt>RbP\փk}ybO%S-hhn"2hӑuuV%xi4|̬8-Гa=[pgi[e\X#V4+ǰ6 sD3+Qu0C4CKhnء+~8M3 Vf@|]D3l,E4_ #hWE4ˆ"edÈ2f@|MD3 h&F6_ h#/hđWD4+"ud̀:f@|AD3 lG4_ #/h͗C4WC4WC4C4C4.B4.E4"]dè.f@|UD3 h*PF6_ (#/h͗F4K#MD̀(ʈf@|eD3l0PE4_ "/"_shdA4@4@4͗@4͗@4WE4"eDÈ4f@|MD3lQ$̀&ZfRfRf Jf Jf Jf Bf Bf :f :fjfjD3\3ph xE6Wh"+F4^ E3}j̀_Dsf1VD3\A47f RD3\)pl F4׉h|#D4U"߈*̀sdsf9FD3\!h G6ׇh#-'@dsuf?:kkΎh kC4 kC4 kC45 +C45 +C4U B4U B4u B4u B4 kB4 kͥf`G p"#3N$yD3zÉ#hVXx8| 'QDgf`G p"#3N$yl$) WgmRh~{յpD3 n=,n>ych~q4-}cgyK2Ϗlrŧ2DsS 62_`}6;n_~{J3 h'Bv Tv@bX ׯ#l\0ZςϾh-Nj߭wxfũ8{9Ճ(l9HI4/0@G&1q"̓bq,i:_?ƅKOhѼX|~b@ũ:9&O[י c m;}F˿41vi<G?v:WOmR4ڵ˿KuͿua<|.V|’9`#XK3<3ˏC6~&皛Cwt[c?lxǶ%cE&>O?xԟzô=> +\?];*68rgly۷(B?}]+_޻'{lD3ki&ރawy&_61h[GA_(\`umOd}ZyPh ,=fx׵}?f^#f# ~\< 9́^zˠAԞ.K&ξz6p5ǵ|ə[mFK=vOy[F4vD[nϤ fyt0Z/cǨ:oa =u.X(l`g=A4?.= 颯kwѼuK1؈f LZnOy*ycc p7ӞyqsFp?cyʕ ts?f}]+U3|Ϊ9G)ږfۀ׿Q<`5^$>(kh7yRF>06]4" ;/lN1؈f T^fye4k)ͣDJ W }m5yj45f!_DGwf@Tl/ (q߿Dts̓3q<ǵ9>¹k<{<_/rs~tz4DZK9Xqky:/gx4k^q^oܕ9B]tO4GܻhZ㛂 n~\}o)gk_7/<]`yG}N=V.Z&5NLo[5w= 5oD󽢯Èf@d|~m=CjF~h0:pvdp-\hO4jyV2Gͭ|puOjlD3ke2NA1(8Auw/-1:Ϳ r|k .!b!&6{ht\|J?m\b@8'wNۈ}[13 W=i4OX[g5O/ WlnsZڿ=Zfnɝ~ ִp&>b. >ù{yp>J&3>n;d.,-Ds"guG7nas5kZ_r3Oɜ, v;DhޚdPJ6|.H R,G߻&EN1xX#!ˈgq3r2njϦo3 9%K_dNS[oڥbEs$u<<Zu #u<|/]Ef2F!:donMzA4G4&ZupD3:dI9)h>^XL6C4:%T Lh+!'<Xa=DG4+gJGsXx8| 'rDYx8{ @zÉhB3ND3p"@$" "'KX}̷x@IH4ȉY._GOke--@$P,GA4eENYUH4ȉI4_]X:*f915f`N$.$*9-!?a6ෟ_˪/<}|ejEA÷?o"W%=ܗ/?U{]kļ\*yJ36{Fqu??=c=qXß|8gAڍ6nzy͓ÏcYH4sfRsgs Ciǩg`D2/y x\s1r @4x׮kk/ } O{ hn~^u̓h? wؒk=*f4?4m.'B|31&%&-?dzDs禺w.JX:m8ei&v.WC91CƏT[ .+[:1(}Pl?EcV퍢D30gi&iFQ4~{\A4?;F}́sc=Wpm Y}o_m}6B=w?ux]pG{虋F%'!>܈੣+5f`d|ҫD[Ng.kq19MS6[_uҭm9% {}|QwAu}w1'@$ ;*{ @$]ƙK=f t`]~1چK=KG3$}K!@,D3|82K9k=f th̗{ @D}%/&@$" g<=f d=DH4!'rDYx8{ @zÉhB3ND3p"@$`$ Q ̱p"$93ND30zÉ\X4Wg<5f` ̱p"$93ND30zÉ\hXx8k'r @c=DH4sg<5f` ̱p"$93ND30zÉ\x4pzÉ\hXx8k'r @c=@=h+3NXӈfC4d h9D3!@ rfC4 h9D3!`K[n4h+-D3!@ rfC4 h9D3!@ rfC4 [ h h9D3!@ rfC4 h9D3!@ rfC4x{U)%tEXtdate:create2013-03-31T17:10:43+01:001I%tEXtdate:modify2013-03-31T17:10:43+01:00@McIENDB`xflr5-6.09-06/doc/latex/figures/img-25.png000644 001750 000144 00000012500 12246405674 021332 0ustar00techwinderusers000000 000000 PNG  IHDR/⺛gAMA a cHRMz&u0`:pQ<;PLTEffې::fې:ې::۶f:۶fffff:ff::::ffې::::f::f:f::3f3ff:ff:۶f:fffl++lllLLLlL+lLll+Ll+Ll+Lll++lL+f:ff:f:fL+lLLL+++lfffff:fېf::::ff:ې:f::e-tRNS@fbKGDf |d pHYsodIDATx ܴcL.@I!dsiB z-HHMAu%Y%Ȳ=O2##:WP( B\Ps3G[3-!ϴ~]a7yiu|;^<ϑKLK3-!ϴ<LK3-!ϴSseb ҋoY ,(yk`; @pvf/O}/[^4\bɠ6+t:$b۟Mg| ҋKlA6YX)?:O8LĖ>k k`= O5[ YbOsƱ~ pV{|+zSlAv'-Vxsv+?ϴ<LK3-!ϴ<'ݮsz!ϔ4O{I)jnVOyt'A8y6M/cW>= mxR7Y?P[(X~8BSiѱ럘tZK )i8N9!D@o<#s*<'" s"p> sA'p" h"ADyFy9'+h3vus ySm']38gYc 8g 8Lo~\Oi([(N2_yt춙%P8Wl<}_f!nyvj s4l~!9v sB8gh_ 7@Mվ CyQ+JP8':IR \U[>ҬJF=jiz#|y,ưMYV 蛏DeƃyWHL:W`is9Ǯ}p)d fϩʲ2A~'|ϻRSc@BX3v- ,0Ygv891EMI+ D:7aZh3.yj-0cPMu 3iYiǒ*=0#3u(MJ*ÌV14g/Tff҆)`jl ,a aIq4x0bB!x XR͜m@ˋ@T +:&\(J (;/3f|6rC/3SlY\3y+E9=OphKtx=smCeQEwHUey3ϑf/k66j<_0MM'&|5E9Hz O;L)폦 INC9*>Ϯ0yAtS|gW.W><,9fxzJ KTe7O~kR}KT+x"_&痵CșPe=Qh?O9<`WIw8GROX'McDisD3v%< {Q'Wy"Α'[Ay.Vڨk嘆j^o+u:[0,*x5Yr-iD* % ֔=80Nb?s/<{'W7Ό<?ZKxNQɐ!(W!Sd9`XW,;q<8ļ5lYIdo6IsO3[?{7{>`ċ_mYg/аF/<󂹸D,UiSy9(Vof+^| _F>ia8-#yK#,V\(> ܬ/}~-^uCgkAv\<)hgp 32}W4h{Wd}zSU滞%L `13vm")M9%!ϴqNA`<;yƮ8H3as8 <ޣu\ho+2Ohd:Q|d/2RH\SbP4zh[\&^ZJ3vF<1l3"ªEn /}//it\(\d<1+'bjq-?t !'~cf֟TIK4ÿ0[Sȴύڱ,>`r4^?E kBy>tpY&Y.bpH{>By4Q`Yĸ~zU@#;6ZnK ֌yfHzMtbF)k_z\ĶTvmOboY;)u 6 F*Ccg&/ԕ*aW(訯."bNS&Eg1;?'YʎXRoGD:mU`y6=מ^wID/7ʿ,or]-"Y%F;:.xV=O'= U1uϜ^+Rƶϩˑ2jX˖Z\XEOJ%9ӱv "O*U^?;+ұbKN-.t]gE-)EUkkSEU yR'b*ִd 6jZF9ݳ-˚^Ui<5z@.4,bol/0ٗgw|BGTYް,b~ӛ'_9 Ow;'xxJfU"r2Fe?=suXxlQw|O#z\-/}F23$g):iLMmvO8z-[ V@³1Ә: Uh=!` j  2j'񯟴>MRo/.h=LxT5?1KmG?n%AſW9,E*nR405ߨځDy.U}X%]q?>{RoDL&ؑݞs-G9sxoyJ[<`P饖+.{!rA1<1ӥCorˋr..[3f|<懆zBi y)`I9[>/͈eϺ|!򴷺XBlX.,OfDhdo"r)ǜe%/yԅ)}֧8HdZDX\=enW^eEq#N%>ea-,)8, f6*Ss -qY[\#7BYJ嚉(i_.ВNϵ1iγi} \BKykh euV:I3F ER3"ϸ5.J2vK/y:$j(hcPӉ*IGo p%9bXipF2۪n#\QzPKDc!J@*;$ľHtСCq ;YRNqG&R@aNq\Z;"o*#T8ejP"YʩO)bN\D8Z*ϖ˙!5g\|'!;DvwB@5%SXʸU<$F즩Wwn+bNjT8#Nh4F%S8 ,Ů w'%g_R&խiWQ(jebdG"btUO8Ѻg+t'`$HE,ZO (?N3%]9˯!K,@,+QV@9!8UF%"E0m5; hqu:M(aIW E.5ՐDҰL_KY`V8|]ۥ8\sͶ?~zM_ KgffhB*N d" e n;HN\^6wl VɣEJL=$,a5iސ^ S>rr8C]Rqz 6+W.##KhMA C:xWի'-&fY6  .C Jz w5}>|]lf&K?T*E5*ose2\x,!-.(^$I< _K58pWʹ"]_L*WO\[D&ڵk8G(-Ƒ#{Jǂ뱝%ZX)W2,,ERpBI2MJlŤBwre6U*[ew-[P6jԨrH9ԩrJ%-[rV"g͚5n/_D'{!C[@0Ho jp[ +v%ʕjSpaz&ghYKsJ+\_RN%r?bpNq06m0aO?tQ3ΐ+Vعs'R-Zf͚~xȑ uu/9_3gWR{N`~π !ʒ*m/\4Kg'Cr%]O+] W½T:@c>b"H@Ǐ߭[.,ѯj7x'|U+hԩ]tQ_|E5jhӦ*rZPP}Ϟ]֭ݻ7n۶m?޽{e 4hҤIVV"IUDa˲By6~j[L t(q҅;?K7R*JY-equͷjĥHU :& ##+CiqMW^xR]*}tP26gTMH 1vlhX߿o߾"@)`;~>},/<2cpKAD,HJJ$XFwzz3+KOC` $]+I(,_|ň"Ͽ{Rܣɓ'Ϙ1#R .@\{O<+?j(l=pzGkݺ5K/R ʔ):\ f0}nQݼy5kEܹQ5cQn YVdan uXXF>rT&+sTrt,&(DC\>([ е $e<.J =K.=x& {Rةo G 6`cG"SČjժxVű6S*ש@#F48Jٳ_rMuSY6w-ZsדeV a"w]pDT eGmD]9)C] }n2y,3y!Rx2 #F{g4Ć1a8aӦL׺ߎ;VV=SgL6[&p]ܨ*.Q>y+qQ^wE؛K!ZbO0|x4ˆ>tÄ0qD`<1"ĦJ;0qyuQVnnIމ1,}DHn 'IڊoU7y]"ЧtU>cr$9"KШ AD(qx c㪫R=:NYMDϫ#:$NLYY5R6:vkVsQ'R,䊊nn_t`c-ai3e|OLHFق,Z5-;GqՏ`#{7p+D/2#u*e qGZڳaIr1cFɓT5;߱`bOV]Vw渒2#fW ]_dmx B)VU]լBDm]y{ =V]999:^FƅoH[o ~G8vYҜ~) f0` hn6l*͝;B۷ի38ۃgN~"ep|A#l\Oc-Z#$PYH$@0,Т]" qj ܈1)|ZOG!j.V*INl ]v}x;lß۷/(㇓YjmO?%Ck_`QX+sh xwXL̛AH|Cq.VaRݖ9~rT NTy݂)X,]Kw_[|"Q,DҔR?$Z;uK݋ԫwV:vqXW_fj6nk5jljBX k3iĪR氓Nȍ<$"2tw"~g`d: "Jh¡Dpb0å/#8Iɦ2x]RJUmgP )gi۶C5⊿&[aזRSDd-3Z1ɪ vFPǏ f` 0[AK"w 4 pb|' _1`B@ժnk'҆@q͛7V:8|ю .+n[lċ&&g $w\qTc*8D +]|HڍG"\P%vzK \.1H,:C8{G38}lD|d4Tqiܭ[oA<ѭ[M]tJ?'u ҅S> P##XA P?3c)YJn&RRnL'l\5?l) H2xccB;@k>"5G $9)UV5kkiӖ/Eݻ?ԩUx*^j޼իW+.D/\Ud2!1E-HEo-?ɬH`]J39^gF6+N'~-KƱGc&mk|#Be㥘 Cs^Eqݻ oe*ѥY>=zi:g' J &|rwp[Vr7bIgU6sP+ݻwoժ~JHq _bn_9#1]^9W8ތ싵sx%G?[R4Aw.[{O ?#( 1,C1̾:cDÞ)fQh$ox=E9;?D͟^02 qOQ=%_aNoh/5huXZK,uвВ3%fn]1,a[a - 7 T-\1 1l_^ Fx/pl`3Z  H AtւJSwqnLki+dXQb"VaVT 81{8l"`慖 )Dॲ*8C 3=%P3aJ` vCu d))ej@D^s1VdTHS*ȍC7ymaUkXMcNBװz0Ir8tArQ>ЗaN:0h0`;;}ֆ zJ]b AV >'-`8!HtJq>0ءjJW N1xBvø^D kbj(]O ְ}ppXV%A< nΡtlR92)`X +_ҩkX/,5@@V3߃|ۧ#D H sSĆ04_=c^)+3[eX bbrJ6A_Yt;sݪxz3 7 Acuz5 j-,b"5 Ƿtl وAր݈ğƌ=v N)?#N`-vpsS%7QC;A'@dw<C%[a(w^{ b3prDa2vJN >)}ooDjB15h86LW‡dž NwJȡc`R` 31)\vcf JAR)sM5`(0"F0(lq p ع ~l€cMcC%6Tbt')\vƆN =)R߷z(SrJE1` 5*67`6O 寧1ԕz C/vJ)0M1  ]~ 3ɂcPI1̠ Ƞ0 izmɡ6`0/!듆{]B~с@ Zz`0(alapv½g" _jTXPq.cM0K:jCJa\ שڬz|'~-˼y?T<5X aA^1h_a*[cH}s% q]|7&^(:ӨjleW|,9 S@ƷM=ODB !r $a,ZE!h0~]8]`~sɳ0apbuHc^6ALJG7pJiµE_F% |\|U- qiWƇhQ qqu9yiqJRNq0 mZvQ辔oS3)fJ96,ͱakb `^}=};L# . |#f=%0KBؐbܬG0z`?ɔ lHo0\yS2;>hɌMK0-3ưh1la-j` [X`Fآưh1la-j` [X`Fآ,fIENDB`xflr5-6.09-06/doc/latex/figures/img-12.png000644 001750 000144 00000035533 12246405674 021341 0ustar00techwinderusers000000 000000 PNG  IHDR}'gAMA a cHRMz&u0`:pQ<TPLTE:ffېff:::f::::ffff_tRNS@fbKGD L pHYsod9IDATx݋8R9CU]3dwI{K֬5$,2}3hD@# QgЈ:F4u3hD@# QgЈ:F4u3hD@!>|4u3hD@# QgЈ:@l4ux'7hD@# QgЈ:F4q3hD@# QgЈ:F4u3hD@# QgЈ:F4uj!-Gf>fIoX)L y&5F@9B iPPnt"IUFB G!FPnt#5F@9B iPPn:M =: t590N FLjYjЖ: @EGȨ9#qFTs< PHbdH͝;0B 50: บ``N5w@4Mj>PX!/NVNFu#Ԁ]55 N|V:0B P1[iV5,u.u&RcVExh8:#;pdIܹ8MɧH-_fMG%ع>ֽjMF,eRwq"_.coV}zQ,嚁"g,5AO垭qި \:ϧ5mK8Sg4\dx 2GE3u9(r,Qg s9ڰ uV%7sa uV%PGcS%({dER U/AE# OW38mmuFZu\(JoS]O,f`EDkE{ DݝkE D; wm, 5v4`S΁t|0h!LuFN1MoJ# 2Mb>*9Hb͊:+*|Mu@?Qt)nz]븶@+\W`R#?ڋj^uvQ]:`g,X+ήJzCoQ,pd=ūH+pΞ*Rwek[a?Խ1*k]mSJ{RUTUu- 6BֱPg *_ uv/ƵVxKfMFV@b_טjk=AOZΝ嶂:k`dwv-.glA-#+ E :P dR^QަQg ^lC7Kt>]~W:(6(߭="uW [gtG^J:VzWmΒ?Y^+Pa]3]Z/ EcJo4A+Py=yif:kP Xk2~WI3A+`I|Qg unXXY2E Y!#+@: (ց:k`dsRP uݣ+E+ug##O5\u{6vG~#uu6<b^)t+S Pg;u|A:#5={2Χ D:S=R-jVG6ԙ:{DMILP0K·TSg{JC:σ`I*}\u@3RgCE4:#5;4ę:A3RYAyUpf:kP nD5{3uރYԽԙ:,Qg ^L`FV:7,uu P熅FY#+@BB50Թ{Uߨu 5r}7Cuu.j:>7 Rg}cC9uV:k0^Ue*$ԙ:qm-sYu#ԙ:a:Vf{:SgR-R,:u.*0KY ;PgD5аαsC~,Qg /Rl7un]lB5(l cO :7ZlȡKuVԻӗдsq4mЭgcL^ W ս[0/bw:Խw^:V?w*,y%rvս<\;h9wζսiQgdCm.~xj0Ȇ:7<ږT8<$ug#& qφ;ǦIQg#_kUcH:foJokH:[xU0YZ:ǮiQgϊ|5Rzd"%u{ĝ"z}L|3u#,[~le/u;RsnuVP熉>N,-\NY+ @&ۄŦ XYܰVv Ծ\w;r<]vsjz/l?F)?*_lxT|H8uV\wރi Tԙ{6`7ԙ:,Qg.-g5NMuV NLuV:s3uރY ^g>yD3? ;Pg2/Ts PgHrquV #?cb Pgq?u6<j>&uWSg;4Qg*={0KY:S=%@/_guVM0KYܻǥLw`V_*2=rèV_ry؁:#l8ذuFjJ^|YP|P"ԤSF}s&Qg&]gkAߨ3uFzԹWu\F3ң%Y].ߨ3uFzԹ:kE:SgG3םՠH:UgMB32pky Ge% BQgyf_~w1r]6w<3/k.WF<3/. 3RUA#/u m8Sg$G lHuFjԙW:KQgGYVJoy _P`NY*Rq,={I:S]bϒdvļTu:u{DLqSG*g8Sg=*Nz:@coDY{-`]2.k:{7VzKJ?ZDY+%v VFz9 UAa^-`]WSl'p\3eleKw.}PRU33鮾Jw2;JQw"=]v{mL:88vc^VnZދVm|[Z/3_Q\uYŭ)R13y7V5;ŖU?uN:[=]/f:Cu9һ]f濼F1;X)ei#J:I/]fn<5lRʙ;|6Eҽ%e0vew;-fn< \&3`QvG"^vew䉙93;FyJə61s@n<3 6S1mݑgpfv7;+@^vew1qEHn< cQvG i(#+@jvew䇑f ;Hs;r^j!vewG7d"B6w㊆G:YH/;Ht ^j!vew{1d"B67Ft 'hQvGca+dO=n| 32ğx3;Fj\ј%,CZF:yt ^j!vewke2Dzmݑ/"ͫH'bQvG>+kg݅|mӯOm}qw58_ߏ5K-n|i^o'|;m_ݯ-ֹKsBw9PBnui٭mx=vpWZ t{mun7OG>@@zmݑׁ:_U3;ͽ5wR7Tl<մgWwo׽{uvS?뫶7uЩj ޼c6vv͡MSTӫ`w.ou._"׽9XK_ߗ|c ڌ`╍@+:ܽUA;;F9q23i}s0rM? ^7y:Glm{ýy:r3vr{~u`:or³?qYuNMp,4ru|GGtw?SOy'ws2AsO?Q5'>xKQ^v| ޜvם:GSܧ-˰=[翇}0w3O}IS/[з:Y_p^x߿2Q[n,nqvunՓu^~`>oӭRgvewc>(:M 6xo?T^wO&🆩:[Bmݑ#Z ]Eۙ;#G)чR͝vlݑ#d=۷n̨;#Gz׊>u9N֌Ϝ9vG8e;#G2ĝvlݑ#dN;u6t q:`wC:YN ;r1ۓc.&?svlݑ#ٞ|~7N;u6lOU}_Fٝvlݑ#ٞ?v:W,B6lO$\xM?>]6q?lWNzmݑ#ٞL:G]3|jC&B6lO+[yE]_Ūܹ;m4< ^j!vewc'}ouozߠ}ɥs!f/?K/;r1ۓ;e>Bcrf:[iw:VJ!P[;̻`+xv8>K@RhtT;%Q砏|%} XJ)4:4GP>cGI1-vIֱR |ǣ$qX)YFN:4:L3C`+ u4ʢΞUn`+͖ Qyh*ǹB-} XJ)4:>3Bu[lpP//c~e<._lIB<2GCև7~ |;Qg̒yF ~JR'{tΓHSURCA <'…͡^O'|Ͽvu{gW_x㍟!0o7Ǐ{^|6n6d$d&y^ݟN )wgh9o\_?<ӹtOG?<ΣF3oKuH*G$fBڳo$nUDϿ}yÏ9 nv6}ecN.̇`^m2oIqY\8S՝^ǷcnShYݓ3g6?}sC5dž'B0/F2tHÉi#6i݅Z;}s7ڊ^)/EgAW[hg?V>c(#_Os{}j75󸂃3uͽ5_'sPxyoTVʆO{ubXc$,ڙu:>Z֑K'ֱRRf ̺:{Z֑K#ֱR& ̺:۔ Z֑KֱRvf]cmXiJOȥ X) vf]sMiJOȥ X)->މvf:[zZ֑KֱRUN-iJtU^[;N6t y:w64nqH'ːfWVucPg#,Cޓ^QֹA/8F:Y'}FO1A[Ug;8F:Y'ӺRWUu?(ץLUu8((Hs*4_s@q!Szopߨ.o3PTju JSg8Tjf<g@qS~4ԢfY-z3P)8M<7B+M&j_j4u2*U4u*UPDiT@ IТ*T:uޞ2"M*)o7I=GEi)́o44%dW:g[dZ[3}f~͕Y7dZ<>KT-[i @u@L4u!\^Jg<@q 99;sd:C3P uࡢV:4uY:5)"Mh΃ǎX騧>1^\/tHSg[F:Wc9~[2:(Xi `7: \Xgzc3-"ం:O:O3-Y]?uu^wnUzU 4e^_dB `lH*`;W:[Q*]0@#;`=K`T: :ؑ/Pg+ԒOyUp@qOXړi Ztu-:9zvǽ:w&MD>R5` .͑_n:H8RO3u HO{Wԙ::Re@N3P #տ#hg>QgINl_Sgʏ[UwY}3Pԙ:*H|ﶿuQǑ:{>YFqd_Sg b6 >gG:O,)ΓYzૠΓ3r\RgꙬ(u3hD֫D@)s3P2\/ :׋:(u3hD@# QgЈ:F4u3Bz#7uP \1 :W:@sŨ3P0\1 :W:JA@# QgЈ:F4u3hD@# QgЈ:F4u3hD@# ٭3hF@# QgЈ:F4tq3uP  d W@ :(\Qg2+ vw60\u3hD@# ٭3hF@# QgЈ:F4t"H!t"HP  d W@ :F4uP [JaQ@)l5:(Ϩ30\u3hdu3hD@# QgЈ:re`c ]>e`P QgЈ:F4u36n@ 6gMԡu3hdu3hD@# QgP@ @} @ @} @|shD@# QgЈ:F4JaQ@)l5:(F9QcP Qgn@3 QgЈ:F4u @ @} @4@# QgЈ:F4JaQ@)l5:(FQguƆ 04u4u3hD@# J@)3hD@#  u3hD@# QgЈ:(FQg( En@ 6n@ 6FF4u3hD@# @ \q3hD@# Qgm@sQ%tEXtdate:create2013-03-31T17:10:41+01:00%tEXtdate:modify2013-03-31T17:10:41+01:00׋\JIENDB`xflr5-6.09-06/doc/latex/figures/img-05.png000644 001750 000144 00000041762 12246405674 021344 0ustar00techwinderusers000000 000000 PNG  IHDRggAMA a cHRMz&u0`:pQ<PLTE::ې:fffff:f۶::ېf:f:ff::f:fff::—f:됗:f֭:ې:ff:f:f::ff:ff{:! itRNS@fbKGD- pHYsodAIDATxkcXV8M;] S:)0@ sa@ sg%ٖlɒ|rұmٹ)QPH'=:j|cI'=:j|cI'=:j|cI'=:noo?'=ƹ[mR=VI߹L>̩([c'9e|K zgN}@B>̩([vn3̨>s.gN}@2s`F}SPƷ =ƆO?sd 3Ϝ2E1L}SPƷ gQ-J1=O@s4 X5g7nq|v[S`frW+WܟNk_vz|ޝ1h Ӥx73zzS`f4:V[|Jvbz{ioX<͎k yv6.)1eYteâ묛꿲umf̓Y=ʆ$qշMA)O:OsR{4mgas`cAV0p< 4e/W[p<~wEj#AV0r ޡpܮhpݝ=`uSclHʙs?pIۺcc|4ؐSg讶ueڻX1>_ zsg]L__^k=Nی[]d| 7zâ}qo?uI7WGW،Jez\~|\w;g8V-]==t=PZ.3$?6=c gI<Zպ tN{X0>oF^؈*[ʗ=X9>o&x8fRϠOr{g7ccÍcRϠ ce􆊫fϡ/̻[=x|F YUɄ)16!$nPqo3QWX2c.J[{2;P^zzbĒ6,o>c/ zku#MNepqghb0x1zňEӽ_ͣ!bo /zxɃzbĢVU_=0J}DZtaNwx)zňe6,~sv[Gj/O^1bx}=0]/7;zzb> 8OC?8VPWX8S=Nc֊=/p{\`zb6ۏg4=0>[+ UPWX:Gz`|wnc# '7>q'zbzTk_kwe/b5ï%7]g1+F+N5VK[}pq w =xg^^ 8__Zp ooŠӌ򵼧5qw?uz|S_;דl# ']kyw~Dƻ6S‡K'zzbz{<[y/mc}lrxǾ+F+N0[+OB?Vi}oѸǾ+F+N0[+M=> q%8zaŕŭNDs\=}io:ǎ+F+znh<mQ_3{S;c# Wz|}V4[_\,?5 JO5zaߵOxzWTTczzbzʎ?>n._1ǡ+F+5zw.lΦDO"zaŕ_ī~wCQWP/V\]pyWz\m Ǟ+F+xxHqZ[2ީ+F+Fz|zSޮBzzbz\U__q;poŠ5pO6_&_Y?_L^1B@Xq~y[Fz|j1R/V;GQWP/V;GQWP/V;GQWP/V;C?\Rr}=ՇM/uP# 䊫oRq7}ݭHw|ۂ3@^1B@JΛ *}Vgx͋| qJ^^ %W5=o7XAC@JQwX?%c )>L=wu~>Hi# I_~-oֱz\qW'J~-oֱz\qc`|B=<LJ{#c6xMVY~-oֱrXIVYkf+ =dEo{f8Jw%zy~{%ίʢ+p4:* =P7z cIVY}=R%wUuV{9}o0QjΪ:s zFz KŢVyUu34³z< 1, z`TuVՑИBaI3PYU9Cc>6xΆA1,znG:gh9 o=73o8m~;\`W=~}APWP-,jENҪ㛡1/>xF㞫ڪ_߷>x|U~ sKfzV"'qi{|[g{[ob^ /˜Ņq+{dy1 hwqrLS[-`1==|c>cz zL[1=0=|![7cz `zL@11=Ccz `zL@11=Ccz `&zL@11=Ccz `.zL@11=Ccz `6zL@11=Ccz `>zL@11=Cz٨G \=V?/=&|y1$=1`cr iJXa|1==|0wc>cz }.-==|c>ʇ KKxG11==|ϢWc>cz zL`㫿T]Zz ;zL@11=]zL@11=YzL@1/zL@11=QrL`=|ǣ90c>cz zL`cA11==|cA11==|0cA11==|XI90c>cz zLrL`=|ai'zL@11=O1=c>q=6z<9Fcz zL@1xzSz,-c>,cA1"X=~dA8O̓-wz `Ub:iز=~%dzrAVOE;=2A{|Mz `%1=CrظϦցc>q7c@1R{<3Ǧ=>cz =~d4lY z,ssL`Dg zc>D{ `z<;F{ `1=C z,sL`Dgz,R1[Q -KqB-vc 8=1=٪zLc9&CO1AWO1=v뢿V\}|Xc|c9V|;1=:|=10^rL=1@y=vcz `u1@z >걟cCz >cG9G ׬~8O0mzń3z)ǭ_,YEH*UzO(#QGer]ŸFaKsߐP9xTxn]=9.˖{|er|9Ϗ{|CS9xTz\0dz =#az<*zz29&uSGA2BOHr@9i ]$9uSGe^sL/q:xΩǣqj9q:xΩǣ"qr5:xΩǣqz1\&s\$ٹمzNo;>U}=xT=^ z<$;6?Qչ_:ǣ"HIL*Q_^'u<3PGE}SdX|:> zo,$ٝHw'ֻ[A{.㙸L%R 5QGEEdG*~IaWԀ!Ne{_߹!cŭtXZ2كN=nB\*$x ,ةkx05)cHTjmVpHNr I3cs,v+f~WzWf'==CSuȱn؇=;)\ڂV5;ọ>^Yl yM*u:US}SLJ<𵽿zd= :R=>q %tQ{ؘ;6O=n)Z>\J?c{#dž?7=λ|Irfn0}wؗSPwކ8/>_|.IM/_SxLJW;zBg8qKIS6;>4eߵ{|mKlQ)'3=.|Irisny5bzPt>XVwUcz=X|I!wnػ?=PN<ԅR|ٔ1WxNZz,[$Vwt"^}\?޽c?(k3X|Ibg|[wX}]اnG'+=/_>xCRo=vcz`N7]k3)oz\gス@g>I鱋KSYk}U__>.q{Y$9xh}dӡ{\TWONzh̗@oa;c9Ζ/IIbSG%K %sWsq;\p1z8J9K'RQqc˗$O^1ΩǣbBg!=|I(qN=:KSQ1q_$ qN=G1=|) qN=!廷$/\,,\ f|b6⅋E=qr\~v⅋:Fr< {,;xYv0"/\,CD=bXwqsl|ϛb6⅋e>w'VĒ+O=n.7,$30$\0Czjٝ8JrlXh`nCI.^Xzt9X{qaa|h lȥ@m=0q{\f=2Ersv6O=nbnYl ɥLD==p=ɥQ(X7U'tv;8AT+.r3vzcg=|ZkK.IpM8NqjI.`&Ǖ](ﱏ-ߠ֗ҁ fq,[ezDKrŲhzoQc;f{+ov[|W&P.E+`cc8dc,Y%ʒ'M'QӅLJ`R"+"Ȓ'AzuU9],wKh. wżY; `8&z,a{l>ew|_$Kk߂ Hs|^^g1=E>n)o\zlw ^$BD'UBypGY3\T y=^|7c+ƹ9Y wj3=^|]+ƹ!g[&nblgz|n"Ws#.0Mqfҳ/_)\x 0OLNzxn"Wsɳ-:D&xo2=/(r; 1BXkQE6wR5X] IEEv{[<Ɏ8{q_^pQdk}||cuWq 4굶\$GhrcP?il(I3kQX].{o:zEΠTC n2GOCDQ/ՠ9Ir}"X{l>FVȟ3qݥluOtZG"ǝ5:*sz\dFV"g3g=s~ӨPL|;6p&8X`EV [,k`7#;\֢ǷLQE.Vx#E\=*M("UZzs P?ihݸ"'"aBydF֎"geu_} j('xo~Ot2Z?z=W|69ǕYMV?ihq.[5Zw/xorq2Z=r zkp8 #As=ޛdI֎@/ ef\&cXq㱘(1M8V91.9rfyoah2 lͼ2.r"qw$X ޑW'Ir5پ{4Xf%rӂW>yz#b IY&Qj9{e{4 obJr_yWv=# &~[3|\oW{2L}g<udgOBDh1L _ ;Ywy/Kx7%7J"NjX/*Akiw. xz?GEb.su:XyBpwW(E: !L?>[#wX"7||aJuA0g,Y{=I~+C0жgdùjǻ$Su!Nj~ XA=1E;:exW,o6Y]+yMȱ'3|D'{YdF>IC{L##Ǯ+2<;=KP>y=ȱ/{X';^$Ȼʎza(rx+=,Ó%Tw.C"CQ2<)wٵhLPc 9G}vd')غorS@C{X';<ʪ'Q/iLB=*|ϐN~'͇ W.Ӻ^G]RWgς\.MV"9I]]=Lr&"FRWooIE;[+uuex)$L1&S)r얺2߮_w)UV7$@6n8<6ۍOB$_.Od޳{ʖw㙴&"PH7{[q]jv=NB$){d㊿(o#ɛ}+2{Ի3a~=^JWeYM>鵙{{l=6(o7ɛ{«4{y;zlHUeMYm=՚{{ln{V{\UY%y;tf/~dʇʂ&o+x0{]c8 E$nUD|\Hݦ_◷7γ};=.|^(?}f3~wAUO~9ÓCWdWu>JX.l$gxQ.x$mY>Eүy?5d OOQŚ$l^m\Aj9Óӕr yEO7i=w, t},=`4y]I^Qڪ\K\sc,2 ߥ U9'9!KV'Kr(߷c*Ij'd鱩UE3c2f9S#%9dqA9B9LH O/"ɾ:, Od}'Oc*f8ʾǂ uuex؃,Um$;`H]a,=#G 3~XSWoyȞ~䠮.=ynsd/?QW46Mog@^c1Ʌ"䧮.=F/*4CKqQ_(-&K1Φ ,-29uu1&3&˒L7B]]zWyA5x+եHM.drc,ʩQ.drc,b9L7D]]z +UNP񖨫Ka+ M.dr)cXy\ECx.=F>iU|I&[.=Fv Uy'xsե(d~49CKQ*hqK!0ʓldrEc̪&%obs<-I&ۤ.= ӫ< L7J]]z GFypKLJ]]z w&VyɩE&Ǜ.=Sz dC1 =Bc ?)1PMz Dq= @KPǀr4z 21M6z …vc!Ip&o=G+۩=dpD{=(z:cJ78ʆT=1`lDeӉV=nYz:cW)D@+gmwRO'z XQ8_-z:c:l-ӉVEVO'z XQ8oY=1`E]9MN =;;ENnRguIӉVMr =[#\dt"ǀug 1D@+jrbӉVy-"=Z)AVO'z XQW`Nj&.z:c:Yy!z XQ4Y=1`E2M| =Y0 AVO'z XQSdzlVk"ǀu1۴zNe!O|uE=1`Eʂf@=1`ERM=1`Ez:c츽5ڟ.Hy!z X:i}vϢOC+34%H1=VbXTK丹NR/ g)Nl1=VR*lKX]}OT=1`%)SϽ;/-cJZv,ouːbz<=uٱho+7OC+jv,NR<6D@+:ދV -SO'z XINKgByz:cJr;Ϟ'mH=1`%U 7N V q>D@+ buܱxUO:t"ǀ%jvsxGǀEz6wx z XYu[ݾ$^zPO'z XY֫C)B+ uرQzX/}V ǀjrv1=z XY֫qwÂo=,UxC1`eQ}o=,U>s񆐺s}"_._{;ݪϝ 7}==V+A^w,/?=zqxzSD@+jZcO;驾[?ۈ?3N=1`%U͇׳Z~Bs\]z sV v=VSܾ}U:^?7ӭigԿJ=1`%T_t،h6ᄒתݝǚloxhz:cJj^[ϝ<Ay >քLet"ǀPRq{k^V wnx9TU]A'ǀN=_r|}_܎>ݯz;WWv=V2ķsڮnF^Ǘ6,ǓcJUw|>];_C/WOC+zl5}Nfk={4.^/D_SO'z XQ'xz XQ,ӉV=V AYdGGw=.@\Uo߾}@m`, @\<@Qo:0 ލ|7 ou%l[X<9!7|pXy}K~1 38xŤiZnƩ)J6+Mp$h@g .yF@N¸?7 If\W#ȌY`n$ge)?$ۼ%DK|uMͧ kӆ^ך w5a\r Ʋ kޝH楺ԩӌ] 5dޕ>u㢳gAq?ѩH.0 UL8h-2g6(mGxSO.,ХpS;{es kTᖢ,̠+٧8t~dk*˨,2xkSГb2J"IkB`uTxBFr -$'k zrK414K.@n GlK(4'bO 5"~%Drq׸ۆynNR%sFm즎Ke껼{v fdeݩ2vwOmwƌb(>Fr8b䖸dViٜ}u$^=8AˎN撴']Eط@Nfj\ #/[YS _\mơrj.اt%S.E"ϨTOi)4 1s-aE;Q +|]^KY0f&:xS#I%I: (QMsmyR׀Lmv"{%d[1n2>Y}^Y>&Z)%PJHycm20٤h![#Ҭ()!a\hT YKOk#?vbނIO7/uw|#7NM !\alĚh@Ͼg @K"P // mhs -h,tt~ZPX^or2DX5bai#K3ؑiZ V%/KFEQ+?P,(/ ̰3$>Ywσ /)MƂm"P_B&eț$rPEr R)&u&+¾dޚEa)2kl$2(<Ԟ [ᖳ~k J'? f&z"iSd'.-4q;ϗkqhX錆vS@YHS.]{dtrL-QF?65O25hH32Kv2M:, jeK@<Tҧ5TLEb,fbgٗLD5 9ib4#[8 >(|,ޡ2ds[s']<; ΃b&,7N,Mk;87%n@q @ G (KFx  @`K~PG]#()ºaE"lK:l§KspΎMQ "=U`,\ []N;<11ep^F,\0%"k&o?~N$v 0E`E%P td]#ID&$)6Cۘ O ctQpK$tNS撔ЃSkpeI4ǁCm!5LĮY3f8]",]xmkX^`iwwiv,@oj)M "y{fW2O(a\R3zp}NR𽕼2兵xn[XrVϊڮfKJ6%vC IKa2a{-*ڜL2#3yM !5,5dnJ@!3J4p={],#:#KV4%_8䂲jxp3. K p1@ G@`*B9@K^f8 @KߍOI%)>RΟ(>/$]ht #NfL1d:%DE(La،E3ٛ(k%NwtFlO*sv.DWLtLiM,֊|sÊOPP1鎎<3" t<h>J3lio= !Vt%YDhIYIY1#L: I]zVF(H7,4 PĿ+E}ʥbCY+1rE=R$Wc1d&EG4{Xl,_U^XyENVUHRY52Š|&x@s;X#hG[aC\%4 ފ䭑@8qGMhOn% 32+VJP/q`Wa"򢜥a/͉v("k% (ߛ 2jdFK?m~}n [FG!ψ8·dR013%6d1xXYGAQmi쮕FZ# 2Sۛ75RI:Şʥ롰̘ʥ#{=7YMw^!%G F.BN2o]RΞeg#tT A9<-^ˁ3OaH|ԍn۱kieAJ=`3]5'X+Sv8/߲G%aM<}Zv84I't]v [p9h?eWQ4t lwoLEyl=l6O$:KZ(uYk /U}N~ EK$n1C Iow_ ),H`/z\c8h] ڢø bE,lbWtX_T]o [.I>3r֘%fO:ǬvܩuyQ klSE'[{MZl*_+I[4)P.KTc͑b =!/_ @B\L8C pMcZ <(p p .zl5!_,W|]pٌ}F_xbj SpK+r}JX,b%_Y|X@\\>cxݸ^mW ۭ$-=Ռ}̀?CEOM9)F撽 )Wu(mlƱp]J{áO9 {nX<]i:H罦| Ⱦ$4,V7z*ŌadZ+] WzeX0/ %Ԝ&J[QKFQy4Lwsy$z\`(*N{Xy2]\^/"@ˍ5߁ъQ;\RK<[1W!ݾ-31 2E?'I_CPʍx=%4ix|ye==-,-g|9m8YP4[DƸ'zt*λ5@v$o}Ļ I.X;4xON{CX錆bj) , P{{x/iZ"a R3?1Hb4lŖ.0͘"|$% \E3{4rV)z`A]ûGmpI"ۺdM y(}"-o^'y᳤`8"S}ϼcV2xݒ_1fԙizd:r(#ꢓl)p/pnRs1--%fԌe  P} 4qH61#ʝyc6(*2ݭЛIXU8`;_mEc'&fuBVV-F`0n`W4>}0g}pgҴ%U8)Fiڳd' DzEmœ~gWh['zQz$,ay^y!uɜ>)lV׊J֯Q\+>|v3k n3F5OkMXK?~=FZy HyD/g%4 Kvlep pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@3X  pn=@?*5ރ\_.b#_7%c 4pidf#p1ATN2eԸ6v璏#7up1eK9F|,-ŝp 3ʃ#wܜ7V||7"(1V]@-͐A.>adࡍoR"QzHsZ_: HOGu? "u#;%מ"oTx4c9ո/kDYd2sK传G0FqeD!}Oqƨ 'UdB Yfy֗ѵ?4kCxqIoY'lGq@p}%5*/S.4ZIsYU4֩^\U2n 67(&o Wp)S'n=Dq|%/ק U5%wrIo^˖T'݄KA' K{-D\rd^q(fEy}kL1|H^;į..Z ,4CNK<ƒn}Wn̸ C?lU@-[s ǥgdxv(D?ƥ0بyq_bJV]2\)Xb}gVL*͙^EfEHw޻6q57ʠ^0_+.=-z5s\v jq%C%ݹDY"=ZٵYGKpƥh.j=|G4dw.Qr[EQSجwK%.K[~El.SeƬ%JSOZRn᭹vҷ|KZR%3v#Y[5{["3~I;OO%ſ޻ ,+sQp pIsD!\LT]EM72K~,.p堖f'p6n'y5*ʽ,e1p/z%:%8~P\_o5\.NTAx% Wm{]^R-7ϸ,2w\(@!ds\>j{K1ήȓ vo58'&4$0ޛh!<#, AGlw.9Ƹڗ$i7)D%MvI/eA̒nbk" .^xWpˮ֞}%˿(t,%Mҽ^aM# 荔 P˼ּ5}\z\kϝ@s4rI}NaP˜.%GPˌޫ\̾7- jn4@~/gpe[ǎ )a2U)EEJ */C,5Ţ}Pg\!g\9\)4sKuy'YܐK, [%]h3zwWIv,B-;ߊgC$s۞ d']%@ Kaf܇*ϳ%5Ê׻Ry@% d$^#r$=W d(ZZI|MKq(4ਉ#%>mhܑԯSa<ٝ d(⮌$הte<́% .)/_h%$jJFaFٚK(*2zS.r|wDSt6Eh_% ˏzH#yRپمUt.ٽ/o,͸82ɷڕv# v\v.)lbΆ5$`$2F̸Ʀ%_%%r6mA3m;hi$׌3Wn,o-+ijKSH /|靛? ʼnpg ⤬UH,.#>Gۡ!p, kLP<;ٝK>.eX9~'\anIhYO%NåkmA Kdk.>Ť?I$.I;T,VCY{C2r8Vk7ߍ g\:? Me_Om~qJfߠإnNc9}XF5n=e µoD]g\zyfx5dEwnFfWRo\ՓcBWrpan`W [V'<aL6!@i/Ab1KCP[݁_zSv7i\B[ʛy,U9 ,`>QpX^`q\nOKpH渕{SoPD's sؗ/_F)jk q+ I%n4cԸLJW,r;C'{GT:>^#&-fg$.zKϙMO]`mfcQ8Ҽ~g I繷Oky,%rE(z -vSKxQ 3[8ʏN Kߗ {)6K*^I=I֞%h/WLO=Iy63.|( $ TSn}HS4'p4Gt3of&]P @O2p跟ァyrX z0Ah׾_}, P:ٝKfDP3(mYM wkXƂDfbc'1y]q=Vxѵtտ_l'] 1$b?^/pnf=ٶ`AE|+++e$YX0DT?ot0JpsRݏ@d/+) qw?i&oFT(ɉ A[A(fZ.,9C["_u.jjG7E/L7 nVL32 ԰; ~WEBc:Ixn!DE*/pI;}_OÕHIzP؅>d?}mMif0]s˩!>y84/o,&xK_[#Y̱gf-R}I`)KZԒKzX3( lP-.{l&>Xb7wawX-ѣoѼ-i%JBK;*˹%Jfb \eXJ^YS_jY. k Jt.IWdq܎pd|J(Viv'<=7 \.\GU,yVX$eKK_X\_5r Kn:"]ey} }mo_,W *`ЋfvU" kۇ;T,9ccڮ* 5ʌN"zlr"I4ro4=`!T/#qV]$j$%BPUBu % ~QY/$#8nF q42zKXwIKS{ b`ʎD9TBRov9t("9ix_ a}_]ݱtEr b .Yd8,E?^,t⋒"U-l֦&/;G__%*fIQj2c8\IW|ĸ Uig.i"#頟kU*y'(-1JҟyጫQL\.Y@KzRCؗtU3ͽ8%kd~{!)b7OpIOKVҐ >z:NYtbao},ήŌSJ ~I0E hFpI3ЗX!r ڰz#7`2a~c_,n#2 pyj_Kzďvzkۿ_▥kgv sk%v7V4+T;"OMA_b)?dG\T'_\gREM@fgP/ǓUq@4+)ӏᲃ/%].VC3 ߨ2 N/r&vKC p2WuKmUʕhR$vsu'E?d}!oy%>[`Ǥ@` ;NMJTDlQNRN*WRÝJ8T d X7T,ʶ;| ?@ jIKk'`Yl5E$?!|0 lVkћ =ݎbHfly,O93Up{ۢf@`)}b2 ;+TLO+.yc8%7@0x+:/<( G g:^Km%3Vp*KKuOr&~ /@.!6ܝK2ks\kp%=ŵ+:j?d\dCh@'+ů50nl `BS! 8Bz (s 0 #;G3 (Q1 p9/E@՗dfߠI)/z(RĤr=Rg$7Tdm=W*!ŗ_)Y]n44ú ? WˀCJ9;]/ǩge]& _3tU(z'RAy]BYԗda`ѯz&.OsCTrYD<%%fl8}I#V_]/4TQ p \Hv||ާD[Zϟaӂ a飿^ܜ_ee9SL,qQL?PdPhH$%B 6nI\4$Z%:(kUgIgi }YlŬis@1 b %Ui3)푨1mKE]o8dgeŭЏI?ӽ?Y^+{fD@VsR?nuL·%tȨƚrD)X$Rh{QRۗ @ %Ph1 #ͣ] ]oGg@#.oG\ @qvkCh@/0 1@Kf# @#.y~!@`6C?@%Ϗ <@\r F%o:|@"* m@7"Q@X%xB@Ku E\' ވQ@X%xB@Ku E\' ވI.ХIENDB`xflr5-6.09-06/doc/latex/figures/img-28.png000644 001750 000144 00000014312 12246405674 021340 0ustar00techwinderusers000000 000000 PNG  IHDRc9PLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712Hs`IDATx^ۖE~VnPOWwJwLVDpӟ?~>?7GDOmV'϶g+Ng[-يOl? ; )EN?z' f.ϨwϏ.]_ Pp9[iq~m"Cؚ}xnNM 4E&+>oOrvp"B h^җe=@Stt2y'&3tOSTŭqpFWzS:G.\EX0)ȃx"zNޝ#&:6ţWˡ=GM'햘𕻐t_қ(aMkZk{:O|B/o)2|kޜfq'z ЛRj?N!lc8rӋJu*E/J7Cu`PV*ո^~vc|D%%8an~X.z,INSA0^t~uH #{m8olW\P&raTC;KNo\wEoҼbcuU6Oq8ɶ i\dkbXS+)͋B!z;+>~_j-8;]Pӥ#;|;7>C3Vw}T8 {ވXxjaD(]f@6& C4VA+6sSqgz .5Bd,y3w#Xgv&1ႬH7GT9_T!#{#AToWmb z-y؜sDoЇ䡴 x69|i_ 䡴!&rwa{@469z,$-޵nCiAMpE$:7;Á~IaNG8+oV:& i"uܻ~^w?l?nb -yw&ڽ21s+)>ۜ=~/A4OPw+R*Q tYzIe;CiAM>޳z^/Q̘i^[K߮TcBH5K} 'cC 5F):izgxGNdHMOp䡴cHqXG?÷ j̝/$+ӌ3j!'I[ 4M ꀼl1"N< /)>". h{? ꀼp h/9@^@SDG"z0zڟl8eћ~,tqA!n hi^sϟ"Vytk:|C<T]T}nTᗐ*,+"O /#OˡY{; =]u_L_Lى@MQu];"*"t 95KER+T[W-`/%Oܛw3݁]H[io%'Oկ DD*D:D?*z7 J+ܢM=8wGtדW-z}PYT^W=pw|}i~xNkj ݢyVRv/m}*/؄+XAܛ_,3o$lb`/z9]v8 yM}vF3y{*©<ω@D O3/8<_0F")ywi-rzcNStŽ0<}#$.}9/#D_}\ff&ϿoToiIڧuT\ .QE )+*I[E;z`%ws9F/E{Jɇm $V#)a&O8j$yw AkXŌwy&4%@K::?R@oiGQ2yʘQUD]tϷ9xVM]FƐjPy`3cGӷ3.up.XfH_;%x8y9Vhjs'K}dD%z t`gg_p2Y2~&#S2G0ߞkJؿz7UtjGؿ] I+oB_8+]qMAq>lBաu^_r& ^JeSWW}Ο|ezz}UWW},3Dx -!z?~ᇓ='r4moCȿ^s 6FgU^wǐsܡ:_zDL6;z跂F?ND@݅ ލ^Fw)c[21;zOW,*N^Ϭ3y9[S}ۑ3VӼ.~ai\o}ܙcJ~T HͿz4ZCh?BAU/cX"LԢozK:o#kB"?o%p\yW:|i>I^z^ `ߓ'z!yhEG~e!3͸q -zX~b,G#W:|1*2? 9=>]:'jϐwS>[FT"Oޠ K7I7N"An^}F>}MY wzC֙XOl\rGl>rRǙuҷ賶. Ys2AˡӈW>LKQ&Y\+b9.TY AltKD}'1aU7yRD/^J"Dj6#k03GhI C|&=WOetu`>u^`@wO(G~ UލZg"%H$v\B 0ߔ !y:|95V@&X/?LZ[К0vSBX^=svE ;R/Qc};.9W ^/&tem"h$<_ٻ~Oysy~ãw/17?<&?jm>~oAHxD|rG |; /?ܑ|16D?AϷ w$A@<_ #bm>~`оXL`IENDB`xflr5-6.09-06/doc/latex/figures/img-17.png000644 001750 000144 00000012540 12246405674 021337 0ustar00techwinderusers000000 000000 PNG  IHDR/e7PLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712HsIDATx^gz: EF*KΟɨKA) .Q$+ϟgP]&{  5z`XavX +̢a2j?oo"fvc=히-!FwЎvSdh S=y Vkz`sv>v];*[kF$M!kڢvXaYa=00ZC@߽oਝ.w@kQ}ZCkh$봍.ϺCg^6ˉh0PF ,򞙯E{!zV=QevyVEC"oyq[$E QSQnϑ:6PGnvF@\R$tV -0(\x K4eIq+U֙pkձ2f$IήI ƭ/_KNrcDqF$RN@.C!E vZŻH9)YGΦ]"EaLGe6I3A~I_qkKCugWY#$2FZM̈ǠoY(>CJȳLO_c+.Q 4K0$EK9 Y[pv̭~͆]2j;"r 9:D}+s0%ZLȺջ)M%|ys'-ї V ݘ/.d ]gP?#K!BVPTbfiexyA[oQۡ 75$" 2(eJx_5VDl-Kn,M,̵Vepl[tf{UKZ糺JZ2kQ![Z'oG9) ndz)a͔tKix3o9Hb sY#BEl6kG6 &^jN qOֳ/z L'&Ѫ-LCTJf'[U:"Zh3qx_^m+dMn%.f0&Y9`Uz-f+Gutvz$|{n)[m:!+9 In"An?5VZk\.Jٛ"O*3-ɶ$lIDބ4\dtF"ZKuqJ'}Z89uкw}.k6s :EW5UFolڨe/zv<~h~#%y~%[yF%]Պh؈QeFRLتmD!G>m,1 ,fϩSBj[s[-rslfhC+[<ZtlmT"9)[i5#kmT*)ТF!*lhFcQ.HEcBA %#M#sS,: -RE&r/kZi_xuVZky^j9{vWVDͨ=o\wVj|ˠ≨\l8lthUcVՊ$"ot:MS>Nܭ57EZr@JVTmAN^JkeՃVI@OERaFVC.N.~d:=葥h/^>ZZT*{Y&6QmwDj8X;]}TAY#w-bD{& (F.Jk]>6\+3#km!3nW&Jh . Z2Ad ؤgF&(A=응YAyWex 5zvMT;Rr◹m3l\FhmOD0=zw1C5KZc,XadH$# k>u>y8HF6 戽٣Qe2?}Te>[̅Ȇv*!7;Zh74#[? ~Fk m;R++w&X|v0ȿC\+ h&ƙPum-,-qCOX9#WҨ]2E(׮<8ŖyW-kr/kamThgCel쉂Df>,a*<0$ìodh%StQ[:u96 [{8]o#Oqghws938GxF;ƻ91ljw^ptk^mƢE 6x-s ^pC[FAжƇ<9 Y-dH5Z-M8 u d1uZv!Jm-B0?5vz2 RjCsK>8:KwȆV1+G1 `vyՏEW=jmP 2,jZ C DfDF RIݣݱx*ZR"ԾZ5oTv#a 6s8ԋL(?Sa:d̵7.b_.FOŏu(haw,0*j)ZN?IfntL7((磧6n- Ii<يQ~_?r/-LQ+Bz8 -P\㣠ݱ풉ZP :xnF:d# qihbh?5ު( +   >>3" Ph -hOؒQ C .!ںI-JdЉJl0 Uk2xO?o#VwȆVxG 00'D7]ǿ 5}g-RGT c|-9f챷=xU}2گE|:I4a&# 3)9ȿc$ q\^d3`u{;k~% )Z','@~YlԞDrJhIZʁO1vVZk:Bcoy:ayƞZvQߨw{ 3)9! LmC3B s4ja6[t^\ɤNXT<J~eq+^[QXaC$h7l<Ԭ%:7W 9io#Il֚~O{6[=Z'H!ўX<HֽaL-,Oy=ZUMc#N;J$K-X'˦#J9fHɲ̂ ڻ TeC3B s4ja6msoyCBU)ZXyuf l#R! ڻ T nϑG{'`i%]H -颧0O%GmhI=u}*9nCK SɑvZEOHloc  <{`A=c:g3(=A6`נ}}A{KXQkh>vKV7rXa.Sn -!67H%jw@ahoq;bSComꆶ+ZMov 1Vӛ]eh¡ifWkڮphch5Z+ZMov 1Vӛ]>K )qIENDB`xflr5-6.09-06/doc/latex/figures/img-45.png000644 001750 000144 00000015773 12246405674 021353 0ustar00techwinderusers000000 000000 PNG  IHDR+ygAMA a cHRMz&u0`:pQ<PLTE:ff:ې::ffff:ff:ېfې:f::ff3ff:%(ffff:::::fffLLlllLLl+Ll+LL+l:ffېf::ffffffff::f::::::::::۶f::ېlLll++l++l+l+3fff$tRNS@fbKGDf |d pHYsodIDATx] {Her㶧ۖL ,{ =  2RyNrJ)^Ef\G@ 9@lQ yyc@<<1 yyc@<QǹPE y-8-u Dy 8Ǚdqy4=PXq:p"GCtgs%q }5RK5[eMn "C;"ǍSp C18-1"[FmD'5 yAHqCq@!Hq3Ј'GD<]'a8>q}& c(2KC8+퀖 UP^*Q͐V|Zom4X'p, 8x<P g_ГfA#VᷓxLKv(.^}!AA:PKfl# ї7?ɗ7鿫/Z +HJQe.N~넰!F3UQ"N ᑹט<+$A=kf,OVVǥ-eaљjOe$y v}ؔ屟<< Fc,q]p؍FǕJ n0ӈ< ^yddyP;F@5hP#u2ud+OLG@mxV?"eCr,&EƔ*_ Ix4AФ!7 ϥ)C!3)WK}+|ueN:1Uk^Qiq|9M'D1~c( +ϣj{Z/0 67̕JQe/; QM9x1;˜/uBы QX9;I<4y!j`4s)q5.~LG<6nP!V#Oշ1ֳt+XGH1Q_ Yq[Ś"dT K2x w PjnC5x{s+_K,PcrΏߛUW .GVkc23tRF,dC%&  2.ܭ`Gj>˔~DDmA5qU AdXAZ,"QFcq>yy.ܷlS@8-ݤx[m8^X,'Ez r)zkŒjk5ǤpR<򒀯]+:| .{M۔PjŒWXl@Tsi\GWEI@+(| ][+xiniPPؙO!D.ģȼ[ncEnԄKXS I Im`!=G ]@8քKI['&I}cc4Gh̗?z-Q=XXϸս:=de?{m/ њ0!Ɖ%{z:2y :9<&'c3ɫJ4I7%ړE q֨iHc4|fPft>PtjnO)ؓKCy=XvmJ/I:hC MxRy*6,*F{\`@cw frI9.`CC̈5BS1 P9=>CC$Ѵ/]Mct _͊NCẗQt<# ͑,7_OlGqm\=9'[ej9ػqUo}[8,ڛב7=%SV6#?#J+Fi4 cCT/ޞgx9bSㄆ'Q;.)8SN!Y˸4sy G X~ԹX՗oe{uWV \Mo iNTEE߸R> z18 n;C83p? sDћY[r*'Bи Uz><`p(\6VcVk$ֱ'eZMA ifT(A駽{N\'p gѣhbt|6+qo:Gc8=|J&Ѩ*6M3yd] '0((׬&Ggw"!8ILD.kpjߓ̣\Oi)n?b9a"Fѵe60%Ž/6R}=P#S96 ד`<φJ,1%[kz]Y(-J3b@3،^Jy RuS2W`%<ߎ)#K)s6XʐY4^kxT̈kz[VQoN9 HE5Ƿ̓ )qzMKcRL쫦픘eR(!SMA"6X E+xLl/8$܊>nOiE[d|<5׍ћŅUyd;SlmCǹg)$b+'TڗB[%--{tADSQh +(6*PXPv={>m~D`LM#.]|<߽9uA*Y{znTNni yaHV P'Q񕏚B+Pʽ.~w{hSR$#)vJoXG) GzJGlW yib<;'/m/?*&pR<2g($6 y7.du_Hҋ\Q;ť^8i6 =G:m`1GJ%ޑP:*{PQ\z /w ^}?wxFٜ CQ [G+ꪍ[0ԁuvoҳslx4"Ǒ->W!jGرK {=R aГx~oYEXڏ椊Y?J5q_.0g_NKB';^#!}`>Y jib3Y#Hc=:0>F m leԤbYdpo]<#<<1 yyc@0lN"Xw ctt"Eȣp/d:E8 w,F<'Q_G;]h{$}PGp"tRဂtmPuGRqo(tdtkgXE2_#Q٭>I_Tq=N?L =-Q*dģ z!̗xXYeoKُ@>=Bǰ;fz;#'=fM8Zg=z; Pf27 eo(3xC Pf27 eo(3xC \(38C Pf27 eo(3xC Pf27 eo(3xC?927~xC Pfp xC Pf27 eo(3xC Pf27 eo(3xC Pf27|ԇ`O(3 QgrC'9!ʌBY eF!,@N}2u >{BQ: S=(DȩPfԇ`O(3 QgrC'9!`EȩA+,@N}XQgrC: SVYԇ ̳er?y^WSVݏmV)squrmU+eާ>alQflQVOi5`M)|>_g>.Hԇ uQE󣯫{/L+^f'/w߯_k|v>H2[#&ί6_k< kW!^i,㑎y o,y[uUnoe fK eF!jryYgͻx?lyɿP/C'﫛 `Eww?w(wRY?^/9r멹ׯOz~j>tn/Շ`O(3 I=}WwZS :*u ?Oqu*eh6_7|K z/5&{t-rROyRo,s͎K>yGԇ 7x7#>geyj̟K/,s*xEn7}42wߓzhnU F]+N<<VVROٛfhbb?iaWoX:nVVCro#~h=Z Xܯ^y؜|>_'ϏEO?|~x;/nD/xN}XI?oD޼ǣo,{z[O^诿OM|zx[@Wuv݌鏋D~q'Me?iI`% ^LhϏJx_{e>?V/;,eïיUd|ߒ}՟[|ɭe~ D9 >>%7X}L2{r,,;}o/[跀kk[C}X9qFk黠>9!~JQgrC#9!ʌRYeF),@N}v2u >;BQ: S(EȩPfԇ`G(3JQgrC#9!ʌR..@M}v2H]hÎPfv;GbG(3NL5ʌ.Œ ʌE<1ʌ#.YeFev: SȲ$̔ꣳ#.e,@N}v2#%' ʌ,fʌ=#2#r>B8pZ(36ŲL(3.C2cr;.8j(3̝ 2ʌ*?f6ʌ,f:ʌRaL?S^k9Y&̀<*?q'0AsQqeg0F(Dˏ/S/s0˄8Z'd@/_ɹ,f(d e2aØzSeLBU~"PBkV2˄N+Z'd*^X~zQ.T2at(sjT0BmU./<hM,f8^f0@0AЊY3d_' 8bp)S%D(vv:db'.E7!v Kä3agTAvx p~t| POih@kP* DE x cFxX%}X-HYEXiO v ~*"k~V`U)җbZőh'XH !zqj#F]EO=f0FMF=ԋi9*mif0޹GiU??v|Xz"\7|  <Z<#NE{3Є\SOs@Oe~PT:{^pIQ5S˗`Ñ2Z%Hr4:875$@3eȍu+^#MvyhZVEʼ硐#M-sMtt "M/꫺jt FJIHW̫o&wbߩH 3К:e^Rxw= 4vWNU(u@ve^F`fVU賷ksVطWotmn pFofhO>ʼZE#jaD[ h jK4:e^-^GK+Hi̫otCJ)TWˮxC!<9Hc' Q>6gZf=OepOB7y2y*E.P-n<3FFEx)̘[] n eÞ%nw}Dy2{f ᖈ[yLh_(exŸ2oїy~mwHP-2~i[ypHeV?Z󚌏2kQ ORE]T_($hBhq27kvx$GmcQ+ Nz T$GƵp>غN4 5S}AK!\hͿӱԺHx6c{vmQS"GbI׀O6H'8|R_o6:GI+47xt|_-E(s!])3 .犟Ӌ 2Եʋ-3kiv|h Ǿ O:)g(3s/ƍ)qZg&fʌ$EZwNq n*eƐFsz=>ۉvf'wth'! :fWC]rEhG~fPٞF. '\8 BR7.Y0 eEym&]vR{!f:āXQ2=|Nvϸ%E~*LVP̙ݾe (39P-F_st~AVUn1p#| o؉WP:@{(ʌ*eU._Z\NWnV_~Xas_xaQ4reJe/<2cIPkB-- u#d;NN`>S854s5}}gO= 9oeCg.y:z_-gpj9u.ު^i*k/OҺuoNVP]e/P% HQk5,5v[kHbj{f[4`3LR&Ϯ枷z@Ί-sx^=g]J6ZĊ(s@fsρTVǨshB̫.Vq]kk'EE92ԫi"ʜl ۆ1>?QL<-x +EE9ө2e&R "ʜ)\IC~ߐZcQL?ta̔2g:^fJQBF(se&EL1fv@3,3m#Whet@v̙=5G=-ʜH9[ "ʜ@9[~ }9,*̙ DnQLe,.K>3nbC9Sf<_7մVr.ʜ)#64^׭neö eޔU~OJ&t#E3y}Rδ8P{(u#pm2͔9Sӹup9LndyoՋVy\OShs3ndyѝuw=P!Y 1׭4fʜ+w/-]jrx`)s2s7D9k,\9Sٌѥ١ʜH9SPȮ2g.3Y +QLeV/vHrxWD3m.`Gʓ)xE9SVՋc-˾2g*3Yd )1"ʜ)uH`_T澠[eF*ʜ)%vqelS;؅4w̙7.aȎ|H)2gY0g׶tlFꕍIbvRps:eδUfD3QL5 ErZ47(s& ܔ8/\NPLT<kʜ2siʜ21m7RHs̙(VgccӔ9elz_lNSLY>E'WӔ9ejL}qپV/-{>2Sf15P3,2_=.j$ȝo,f].hWhkz_j2_)3(3*o(9.voʌ?b|-M.CAA(eH9ϴT5e>$Ktx9N>A1&Oj9!̔»N_MTߞ2(@K^(v2x5M3Qf-j⨭6]ZSmY(,eNE(aY2gZEE9SqjO;EE9S7/̙.<2c9Se{G΢el|(3@35lߢ eD/mm̙)zAh+̙-s'\en}NkeQL ~Π~/*̙Z/s먁싊(s&ʬE `_TD3Qf-j"ʜ2kQ?QLY2gjQGPLY2c9e֢eDz-s?.ء̨_iʜg3PK)e~! eFy{^eFikiU%]3oyfSfFr>srhSf6;9V ejId;N<1V%aYqXkY~x_x{j.t{a@u4T] 5w3o(5}Q24%A싊)6<"i2'l^=44POՄr2ʬE1q˼o_iw8VPf 2 &3ec9u]Ql؀Xc̙|Bp#ş}ٌ<|!P+k/2g*&Vo5ȑX̙~0%i.5rR!tv-s9 }Afd߷=lC/y~ʼ7[]wZ-X[T2o ׋L3B/snV/ }Xϸun;ۡŶt|JyBm}c_TMtr hWXz¾ yS}bQf F.[Qʜ,h_Ta@uwvM,e. Kk Zߩ}^|`A! 'PQ~\4zi6/9E/s浦5ܭ#O*`啹|4ʮӇqqMczI;[zɈ9n#ZE@3TjEk09Rj˺iȠiB{=(UqjW6ǧ!m m$clY>I< 37;KvW㍏2ǩA4̛^DY-9A ;r4][ hכ95t2GI(tZ֓hW;Yz q\}7L xq]!1ry~S6Ρ̙(s6h׊(ʜ)Y/z+$%Yh'ʜ-ɨ*L]Fc 'Ded^eyؓŮ)Rgsy-s}SO o6No>ʜ2mq`ñh# e4@a]fNs76;seD3'%#Ӣ̙(sI%^ʜ2[̞hGQg9eD=3ػM*9eD=s/a޼ _wv>ll/e2{|_dp;(sx{)sYٵfENK |,t20ommʜ2[#%ſYcϦ;ieV/j72gJzPn0O4# /eΔԜz`/)x̙~̀bq2̖g?8Q()2WD3QfK<5,e}QQKeh1e2{ƾ2_L-QfSE)%"|lQj(g싊(e(YY(kz(e(YY(3p%̦(3N>^fiP' Я:<1ʬ̅1O 2g̖kY'PH9Q()VD3QfK3\eD-lg"ʜ2[yf`&l2{ƾ2g̖(g싊(s|yRfQL :^MΒ'~/*̙B#hk{i̞/*yY+eFij(srEO>B1ʜ2+=e(sʬ^PƢgeZ#fRf`9Oe~jpm(wyZ.md-< ojK=(sܔQ'\k.e6v?|w2WEPfSc<5~#}eCMQfznl9-6uPfSc͟t_xAPfSY4] /(slj2l(s2ُQ4Zʜ+~0*sZ- eCMQf]|ʜ28'_(sl*zWHAG@M1PFG(N#̦go2̔9e6@=kmeCM1PZ)$ʜ29 ʜ2̞.uh3Phۺ}qM72̦(gvWK:̦(gE_!*XC@MQf\&s=[1)sCMƗ2B=/K٤R(o>vjF>uEPfYެGNG]U-neFTzb(&TWUKsp/z>S&m]]U-i򀃉>0؉z;Z#K]U-CwpKlCM{d'hm^gSl@Y*w})[IKlCM:RHwlϨVRs7͉"CMu0PuVuO\g)s*lj聪*0{OO( z:Rއi͉BM1PcJi͉BM1f*Uqi͉BM1*;rPfS 3X*M ' e6@1ѪjBpPfS 9OUBM1PܹW-)݈.&ƻ\houz:ŧ/2[w2b0]dE0Q|OO8/IDDQ85媧& dtϪp 3J0<e#妩ީPs%NaFEꮵOA>u=)3 #@ +| Y`.gY: , y`9='eEvl u)3`;[ܕ, E7u^s4P]t _fgcVf+7t92tWf#se/QqNЋP5=yeI腇)sJ.1v92b#NFC-q<œ2PfKyt9e̖(s`NFc(%;œn̜'G\r桧T aAc(%f3d1aDc(%f/2PfK̲W\01a>2PfK̲OtC-1.C(s e,;ĝ(s e,C1]>2PfK̲3\0@c(%f|e̖eW)92[b=!P戄0re?qe̦e7i92b5qPf[̲\0yBm7/R:O)kH)s_0r|R]F 3e<:TYפCw2>vK|'^G5KuZt8̔9R9f\w2uxS*,ՙkω0S #`Js9~'zoyuL_T1L3:O)kԵL)s_0r|R]vKhekVEwEPfSFnX{۟2DMUcQm(se6kVEٔQ[5nD9l(խzoyekiy\?E:/x^o-ӏS/uz{{%ʬ^i|27v%ehB,pzoyekYi8tQąvK|'Pff^a?_:}\^]j ܣ-u(G@meV5~͸[.|eQ:O#6|2'T䗳͕^Yyek9UyݭvLJ^?f7_~>Dy yr\[e6>ܡ1,m|_=[w7˜`r%Zgʜ2PfK4ٜ^o4]<ƞ W*7ʜf(dyEQl)eW]_ Ols⯕]椟4.m﷯~nFY92[JY5|6YOg/#ZeN2_'?~|e̖gnƷXLo4 ɋ2oV~_js} 3e^1R,mnidu?[8J|?eze}MDO s2PfK\FOY;92[ʙeRtխs2PfKy ]&UcQ|Pl)wC\խs2PfKٳ8r Yݪ>w(s et`[-񎠺UcQ|P戄0rtխs2GPfSgy*VE}C#(*<guƢ>ܡTYUcQ|Pl,Yݪ>w(se6UwqVj,AMUeVE}C#()YfYݪ>w(se6e58[5e̦ gguƢ>ܡٔ,wnX;922eg42C87n͡f7܊r;2GQfc 3'M(yv22c_g=qNQ xٹr;2GQfc 3`vgv:ef'n92cgtE1̀ gtE1̀ggtE1̀h 'v:ef^xGЍr;2GQfc 3 هr;2GQfc 3 8?ey^IwDԇ0(1Xv[=R*àf@b~G;*ە2OladN'Wev怠9!Yʬcs@Pf:Pf2d!X}s//Ϳ'_r1f} |˿B>p=zJl 8Y2N*zkeWͻ|f'8ޢ+bܭ2b l 8Y2;)aǷndz~r7|'--F ]2OJQ?n>ڝ2ǗÛջ_)ӯ/u|jsާ+t6eȬV L-o|vA~|.nI/CehUk>A9 (3@fz=,?6{ȝۗLWٕz2?ט݅s]l 8Y2>lc~.%,r2/'~_vWGf~XD7x~h' .oz?6eȬCBo׏w3ΔɳMQf2daof|DƷ_{<2da̯Ğ.k;u~i{p̏w_ݚ?xns@Pf~Ȭ~\>sSsϞ=5GyjnS^^22C/)̟z]t=ROeïT &2Oe4Yswft2cu/ǩ y3软<ف*r:{vd 62cuHx6 >~C(?wy߮ۿfh/hcݫ?Ҭ>TA1̀:<|>Zo}?A\%Y׍߯UPe60jvM} 2cx<z2 lasy>TA1unvLz2[f:7{O= ~2f:7wePe60ԹA22 lasdCe Pԇ0(1 aPfc 3@$S*àf:7Hfs@lasd6́5un怠̀ AԹA22sd6ePl 8 p@$9 (3:7Hfs@Pfun怠̀ AԹA22sd6ePl As(3PlC1un怠9 Pԇ0(1 aPfc .laE1L(1 `e60&]2cvQfc .laE1L(1 9XPf27 eo(3xC Pf27 ewPfk Cs(5 92cvQfc .laE1L(1 `e60&]2cvQfc .laE1L(1 9XPf27 eo(3xC Pf27 ewPfk Cs(5 `e60&]2cvQfc .laE1L(1 `e60&]2cvQfc .la7%tEXtdate:create2013-03-31T17:10:42+01:00>k%tEXtdate:modify2013-03-31T17:10:42+01:00cFIENDB`xflr5-6.09-06/doc/latex/figures/img-48.png000644 001750 000144 00000012452 12246405674 021345 0ustar00techwinderusers000000 000000 PNG  IHDR ˛WgAMA a cHRMz&u0`:pQ<PLTE    ?  ? kk  k k ? k  ??  kk?  ? 33 (!-33' !33-!( Y--Y'B 3o '33-o3 B'3! (!'o-՜==tRNS@fbKGDKi P pHYsod4IDATx] ۶%ZkmNuImiC;M'k?$AR8 R8+8fR/5w b(I^u'{աXݱi^TM;+BpQ$BJ;ʰ-~ro@^-eP DK-A )n rLJsXv@3)guvr@)dfX#\_eX%O%gPɰгR}8ٿzvPUU| `Q yj5{\Am !:*ِ-)lAt^@)k˦z&O4,t>NQ$<>1J<y8|j%X1R!'Pƾ{&p:*C 1!sZ_NcŲj < $.I!bV1;TTr@OC&ɓpPay:nMJ.؇ =m EXcG6:jv}KJI$9*zX %?'P$ @Q=7_HQDS<7LϘMiUc УùJ2@Y[+ccXgCX8ʳ Aa3)C_$0FN0 =pi%#R` УAfz"aH 0굎a>JXfw o.|t‣t:/G%瘸L,[Ges4\K.Tq+wr>rhSIKe!PsJm..~tͧN?.7~?ǻޮ[/OkCBk[[P>ÓBF[N0Ѕ,-ɨ|C^Gceqb׏>yz&OUߧ n]?eYgϛO.о]3ߜW3D) *e[qQRw+meig.z: ~j[Xg[Oܸᕖr[۳|_ =R{/UWsyĵx[$>*+Nse]i {%d;ΕVef+|O!yeY[֫w k֭6imYv-]:]neW,?t*U U1̪9F4nXtJacQ_*ǹ9ݑՊacׇA}?&hNnMeTu+jT<'=-쩌l2BݰErkf%sK:nbv,)ƌGDNה6=!OiAw?;.JcD/9TYJt2:7tjk$h=b#ˑLkJCQyIvCt9Ic+ϡ$'z\AՁ~AU=Y*I$oe_b+n9Am͗mMtP-\)aͺnBiմyԖͳxU|?nЗm7upK 7  xw)f[w-{Ͳ}?w4}PmT{צ Q6tM^7fF/̕ay}i i$ ,mgsCYȂ$ sfSs%{)S0p.- E?nD@2U~PYn v*Ӝb&U'e) 8 Z04~YTvx# (\mk9epZȜ-FdVV"b%C9SSt/@t1Pq~EV  a9% QBEZ٭y4SΎr=Y"SC_ӖTT:uqCt+WMcaVkgjPDō:Em<`3vr-}'yb#EIxs+2&"'̷}n#8ˀJ4[MI#RY?er?HgEhƳ s$kf$c{Xך96uD&KZz<}Y39yX.)^Oԁ8lQnS kc-mg"ΌT̞==.Y`D% .ӇɉZc1s݆cڎcb+yI~VrWt +comfA![, GFsx"B${̱DojslVrDP h!\{(ZV\x2k<ԙТzF ٯp* z-1טU) Aie[  ĉIHJyDor 3Ȳ/p9bK%9^`JLUZ4ǚg2(PIo>ћ`ɲI+J}gy| &ȇWaU AoIV +Qpl rH1wJ.@^AΗ=8&2j^5IyGq "֞ÆQQ“!/‹&`]# |Q(4ᖽBRkU\#r0c@)_W$lUAYa#>Nۋk|,Kc/9>Hά I4˕ 9emPQeDj xp9du%♓bu\ir\lko %\S;\\,jh}֎-kP8(g>CɓeMJqȅaKHr^t_o.է=T d$FQQ.hZj{/KUrZ@OV.,+Dfp|jZz2%ϔ#vGnVG"8O"Nr\k (89 gjG-ok'?VLp<dDJYE\%,$3H{s4&[PCUWQs.°6Ksm 3ȋ0SH1| Ҩ̈YC*<1rMZE0uܿw(X;wuw{2ONͨ]sˊW?7e<LQ-rm}SwjJ(ٿI[CTY[xmr겶T?y{x9K^s0Q.eA\髞:Y3^YX6ٛ %#S]YeAPw5jsxըU8x}0Y"kEy89xv#fY9ñf8$p C8^ @2%l~^8bX-,oR4,2Z/PG| "A^?t.28^.6 Q+X^'J;`-0y{.,πt yӵ~T啣LM4ut`w(ˆmY`y}(麯z8. UfYu@WJE9يխ_~ 땺 &rJ[6 3@P:uL"5%+_ 1@P$}+&\͒3$LIxXVh=8Tv蘇1Mp]Ռ/{t˾q~W?}{kqN1"^[[XV Ze9/lCJcP' 5o%Z˖S ~lմ ;鸭71j*Km m,&Oͽ:ԉvslC~Z?)QhdO:՛R0_E@ %υH6Cw7K;ԉ%῝%%o7v͜ziSIxVO)6V£F ߵ*h;5VYj+dz Q[RNX|Y}Cޛ0>'K'ٴ $^e6/Tko' jR[!4+PO+@otLw7c*}&jBIo5 +yw3#H5RR[A4Hxa7:ԉ-p1[bE5{ߡwcJ<͇VUK$l׎TǖR[A4cZx(ڌ_k D:5{ >n[Rmnѥ3LЩL|˒]#Y,,v*Km \% *$lbΜUgGtw#Y,,{PL}h O7h@< 꿄7ok?mwp>ۻwo7o[?VU6ÊHo \eFshc=:>P%K}OY"hYZ MfOķ2f]ScݏG%ljVYV.YU:P%KWWxYiC}"0_tz5~Y|b^ろ9f Wx\%9@ߘ7)SԚʥ?6Ԉq^99ytE>ޤLW^}jD|ī{]6ܜGj7ӗuzp%?%jmcB$lHgO˚,6@{lhye8<]А`W"sh1>r3XhӼGa,Qp1⍾p|< "Oy?iGŏ{蓔{|{[lS$H~ ~_SUS|fmW[1#vN1;f0Cއ[h1'Ԉ_kMk^imm -.vP>n˝79S3cf4Zͨ_~R>F&N@wU[[oCc8IxjF.2,`F٧\Cx*Gsآ[öչ kM1+|!.ﴶцW- o]`7}28%tomաS {zX^A8VS3&Gܧt7cʐU wQY[jc]]E$ {;^nJ;:SZM(k*g=&IWgͭmv] )SԄVD%E[73eKjUٔ E5磓 ]gnmF ൈ)a.ݐ0F8.5*MKMkyi_%?Go}?Vh!L 7$ קLQ?{^B?ww3r{bvwWM)s1 =V' XR迃/ՆHE vei0xW3T+.Ը,iCИMKMk_:[?n+OLk?1/ f݋FIڥ/.MzS&KxȄkD /t녗I{*fRZz\,P&5հZmIجFofu ۝k47˺3 &M~TVa\dbYVSK̗ O> gckmwb4μWl6yzwRf{߭?ye%պ:bPXp6Ԅg3=YQAnT#?zKxG/^oӳ{ V$l5-c7L~7*5 ͭ1田;Td aB}D؟~3߉%SnLJe&5ͧ:|:1Rfc3\vG/`YQ" xTM߾^hPi©oMk~%VOJZYmytƄq7n:WcM7.WښA?k!jC[FgH q̳ߧ0zYp4X}p>heW@Ԫ60^Z7-!s@>X=m2pI |18~TsQ82a3%LE\wl\Rp\$ ' d㉄@x>0@60@>H O, ' d㉄@x"a|<0@6H O, ' d㉄2x"a|<0@6H O, ' d㉄ N <9gK Nf}N# !#ab$ eR lHx6B$"af0a {عY$ M*67"KxKf0@ x,H(%I-5;@vNsw /IX*aD sD{ rE=9%UΜ8Hv a2$2!Dx =6%aùG 1$R0 RxT ar%0.aù .%k8xD =b)Dh a FpY0(LX4 a$"JpaR% 0(XŠs"N00N&)]Xx a( $\jܣ HP(H @<-r xz۱hW% @qKX0 q"ca(.jL @uPqrt5e, I 'pELRXJ7$ fSi%U^Xg4-KT@dcau2q]TSh o9: 9p]u  *ǿNr\Hxa/IA`X$5+2; =4wULF« apu^g%A^L+F䙝dv0^!``{r='%Q`&NkD> Cx`wM4#E0(ǟFK CX9I©wUt#p0ygey"aƄTO伻,$ -i'tb?;wdFI&FH߫Je`\vHA0)sl e9 ;@•X8slj`$l< `a<]t6)vԂEp0ea wI Vf;Mpp;4MpwXj࢈F;+ K`.ȕEaHXgX0~a& .;lMHX_sOI#1`$k$wY ()`$P0ip;.6 W4 +hmSHX_a`BtplHXa00zR"Qa` a4`"!OO#amv;v"rwq|y; j! >} Fƀ=Cui sl=Coj.\ŗ8(x #Փm _}DsA|, F¾"4|+sKW?cv`#ᰩiu+s+?$kvưb"#ص bج@ٵw)?Ӌ]uѢDMٱ+w*y\^4!!c!yre?op9; N : ˎ]O% VݫKKh:vI0DŽDKTK;~?`IpnQ_8tN3G vL^[+Hݾ&Ne a̖+uKK8V8vI`\B&#JIvpvr4_:@X~FSU%$U{,`Be ?c*m(wW`"ܯ{4`D7q 5E%˗:Q.82`򠄣U@+a-,HB8XK3Cqpn 1%%8D;ïù=rN '30>RI9fr) <8JK^j܊p}[긕s+[I?1igjcm ,6+`IG_XF?u"YYzu8Ab 7^+ ! \5yYyp$3'QzQNkn_U}.؏CEnPK xp:ql.w`7'> $Ue'k%±;zQ$\9uR:EWrp^a* ͶIWО% 9Lx;G88VNC{!?7f^!p5-qV;H'GxI5~`G#Q$\/b߫8د|Ԯ_UCO =l ׊k;#UE8U1灃p-usp,sέ?8<)("wlaHBp tMkaH>pLiqH6 RpNױ*튜,a`ϻrK$ikK#p)`VzvQp]ChF~B$pUZzU]$\*<W6prH8:8%l(wg!K W֥ڜ^@©(G,🵡ܽ J(OU$\8GRB\pg>Ct ((8ƦrbOdpp >Cu 0K +$\CJpw0 ܝd) #sAdF 4$Ϋ <@;sMkSX8,s*_$\%+!9!s]?\o}{?M87Ƙ=6@ղCϧsw0Pevoo} 4?H^B-߹;N7mFq5Q%cȲgu$\3aW$ Wy`ψᦐO_c Y̶WX81AWPm-.o!˞Aph8`D%;#ĮN zỬr$r "pjp)w6J:-,~_N&jRάd4 Ǯ{f +=6Kȩ #+i IXl]c+#6c4$o ˘[X4| g6pK-^b͒f|oKx1 (XX"έഃw!2ᖨbD»Mb[×p 6AE0I܈-:ht7wjˡ:i,V+_kSfhcaY5#aI*N 'a9 >-KeFSΊ$G·yVŧCVՎ@ZVMoS?t pm3CV1`-)>+jw ;FCڲ%?6@ƶp]Sxoޖ 7+s{7 B>,KX@vSMM2d3嚘IWU{xUʅAAyhpy$ _HXĜ)$^@y?5U +SԚ^O~$'ᰱIUHXO 7&^drhی>1"Sֶns?ƃywIx}l!̬ $,F_O=>SSe"<ݰ"4 ywƨӱl{[Kac !yy;b$Ϧiu|XӨLR9՛Sbs{=;cTQeg OIIjNr<^ S3;ģS–%wVxWucfj>Mc^b&H*0 >fS*A0Q)8L4[m+HnJ4 og>i6G֕Z*a9shrp&]Hi2# <KD/@iFGx8H %aQ2&P$N㋃0CEx?Hf+G/wAbsD#aɬ@ Qa&uP0֑a&w)C<G1 kNQ 1l~r$ `IA,VH"Px"JpZH2Z3,r8z$ `Y!AuX,J C$N`HP+lI`^J9 \_8*> z>N07LUBG+*KxC4DNdPctܽ~.WC"ҏpHۉ *i||_T$:j8(2m'2WsQ$(0 _M#a +G- :L$:P.f&aaIz ,.*~m)};h-n9'M*?y 2>;IKq-z>>iyH=$uˌj4L'Ǜ~@?}$iag^KBeu 5|;!m1jS]{锦XB5GJs rN0E`&wejs|糗'IJT>tڰ6kߪjv^ح? z-FiN?Bm% kOs5#ܜq96[ETF'Q){CU]I.Al۰VV111>^i6jb:ah=>A-o,=,}ݧRjqj`H5t'g>Eާ6FZy+)n?" !?:^@מZ6>1C;IGfs !>tΰA~aIq <[z w?ou?[mX4je S6ݧw}SLiPgv9$a;h͐sևqq%݁bg& ii/:oôH*%?Xm|Q4P$mTޙ۲?~8ĆA[-opqqqobS/E}ouj1gv%IEEQwfm$%<8ާدi?~1Blܘ7BzBD#wgɍ̠1,3}Wk}t]­T nG 7|`ǚF m1BmonHכX2}$72Jz_C&<:_IK)_K 2Ix(2ÏMxk/#ԯ`BVs !I&qq15r#[qySW˭Ku(2طᐰ2אp>N]x%Զ%C'j'Gk9so,nr: G"d,MSZ{{W0ѧDӷxGSf8h3ԌOFʴ!%'6&9s_oo2f,p7C|MDn>݆eFI2&KYJxta~ڐjY=Yjrc {"cI}Ysg7L78$< Աz:aqs62{ އw- wOǥ_O^3ކq,m6 9AHt90A9k>lXωVA[66oo8-"T ^U}ՇI:>1C5#h9wfȹ $YgCX ͉*&=?dC}̚F]m|?تϷ6hR!}9G_<9>1C5˿9g1h9gVȹP)G$y8^ q KغƇg(E|Jb|܈3TC)-[A[͹C..*95ۭºχǻs ITsp: ɼ ay5gnBy6)~s*nvsbY h+":\qJrl /GbGrlyqjwJIVX,~ vTDwI>|>4\|[EU @]Zξ]^OO elb\R5[ XltWfx??k cK]Z Wlt([_%tlFvdG |c ;$;:Tft.OZOFc @Ev<)Ɏ!Jq:Wc *>j/%KY@dOKr} =>ɟc=b.⥱8҇^tpWId.84@ .g >wB *$!gQ*Bp;'6ӳYbg2>w>}g D|ct 연`JŃ`k| 9-G/U%liJ Q?} Q 8)a]\qk[:ၖ+qϖ;q?66 hҋ8@ʑ`$3pm=e0OaPH" wm+0.4 3qE,S$t[ K "8M!V8ګd K{XW6+0QB/byR_$č`exLw-M@~Jr|;[zsl7P x֝* e; C`CAXqdk"l4TDԀ"3MB l -(^A"}Ücww1Bk Ci_Eo%}%.X+7L7'lR;842یWp觋xyKh_Ax(H@l`81e_݄J`, !Z`KOVbg_1bV "EYjR)\éSbVe 9xm9]%2gs"FgwK X #M}Э"h(؜` \e'Ba-( < єl`udt0eaI1R wU9<dq9A&u.I,?3{/Ye짷&0d%H[XJ9!i9X4-^&>8"s#zwIA H7L wkcxj)O+FDr,d&Jw+<|;05&s(%"'2G u!76)B#kϜ CjGιaf$W6"<@* )(~҃E\J(bԇz8]$¤l4YݸjBL* (@.׏K8MgE$¤QĞq:A* Q( j"NK!0A<;G[_A-HI!e{%.w;{UZ;z=!00@U !aRaXGC0K)g&b> y0FK,ŚXP7,RXj>eEj(ř، 5a&5Ğ{=RqbY]> UH7ɻ " -sTvrޢ.RayVގyTl2ܫ" }Qq0p \t+0QƒstX S:lb)2޵Qp&¤ !TQl cR9WǷ Wd1u)q[p`5́0s6pr\2|MoLG@@ <=FGЂ/M1R2de#ϽʮFPN^ȳ]TPE|eW#Gd'!*MFBR 'T#G'W q@M#w[R@&N¹54YIp Gx5  b^@rx>ӋX2B^(,37\Gi("< '"A=B XJ,zp2#Xgb1K%` }ȯFPJA8TB.;K%aRY񰿉8Yә{R)$|!U ߶M,OITaa#-XJ2ߡ vU#?( KfS7%)"Q0lOT#dǻ rJH%TD’񕩷݉ɇssiMV(^P'& K';E R#"W:1v="L9RVNMAF={]Wb7zmAĄx9 _;=|Q0G $0.>[( t#Np`*̙ BDj՚ SAnMBĕbp9pBg! =쑰_)D$\,)4^t_p$Iue`AjꖢKQXhxt,s sZ⨇[d\΍C+8"YugE `J® E0EZo[ gKu{V)Y9֐pF̹c wHRP_ ʞjD8o 8 'Q) a@N {1plaΜBH3z]NHAHD%SD_Fxx(6ܽ@uƉʕo&.-^(qmB>d. YGat s'A e!USlέ!8VH c?TGvk$| 1EhA01){Sr԰-ܝܡ@(3; ~԰i_ܡ@DDyoF"w(P0I0="5;E IʉGi 89ث`5,-(T\$ !&i-|q;?; ac>1@%\@k'n7pDRxoE w_,HYGݤp?kCp-,G%<%,QqQŸO_%d= o鸣ogѽH!V~UvϝD}ԃ7dlA޿#ѷhZ dQ^ ; (okxc ._)_J uaAdžd#:{CIJ* wCIQԲA Zgclj(B$,F. w^cT}ޒpQ_6᧢, p@ׅE8D=NMMn6'0e!=nًs -bKU]+) x2JPR ?W& QNϴ&F7>i6BŪnpJ7\zݪ<-иq9@RaIP6غ3"t4 {M©vCw7d ́eGAj5n;Дfnͧ>?[Wzk-jtPppBʓON a/$pSLؼYrCr/^pc/mHwk",󋺒~l,jvPOHRzO`JD$·yN, ,.OkRQC/;M"-aJ3 i`L˟N9:hD`w>%'sw; qpT8nվګSP_ht*ԡ|?G׵d MPFo?|;*޵ڭFmcmQV7I)?)%\玉p" 'eGn4Q.&93MjIxzռM[ir!Cc 篝xbqC|i?}LA33I)RAA n1$NӺkލ\pJf'%;.f1-ohZ1>i.SۚI-ccZU|NK:Q¹w̄\S#hvl}(Ybfpc~7h~?iTU)UbyEXg*$чLR"|mgKxp͔V{NRKֲ iZ%yÍݶe#k4"w6<1(+-Y , 82oSku ϥYGg3kl[33,jvЈbԔ*=5w4 NvhՒ"Mk73kC*P/jWoYM fA#zg`sSSJNd:8A*|$G_Y?l rHP7J>\c{WhJX,̵5fҢFpf띁MVONF»LU9%ݩp]X|p*O_^e?_2WcRYT c=zmQrvu03^d#Kw^U$ܪΜ1{tZkYCߐ*Q@:OCoX\TߘOF{kS'Zؚ0 o>[pgp'Odž\.Gg>(*TU&`-NEUc33 *HxpILH8>]t^PUJ =L|86^S?'}ay6hA33An"\^*/bM%۟ܗ$O{wmHcn, ;n6nk] 㴰h#ђOSK:;aiQͅYZ_; M+mrIxm4xw 6AqC9A;8Ge; DT.^ SZS'=iw--|L[z)2ߗE"0;[ؙp# M^hv R͹A4ԿYRݜ]~x$󴀃  D2 OT$\ˤ§Ky3Q-\¡CFJv"|Tl ϿOFJv"|4=¾#~'Q.)a*H8h'IO_,\p@IO/ g0x/J%_H"#[I81'D= sS.L)@J'T8(aܥ Y!q*H6)UHJH0@G93"$:9(`$ \%—4P"\0HD @mU8hc `Qe)\$ PV"L=ꢰjDS0ja~O9ՈisH8*On{;9$TI="탅>X}4? Pe$s=G䀄QCJH8&9~Su;)@#GHQ?} >$z( 4Z{'؅DkKMASB_SKCx5bYGïmW+mh /)ziڄRqC;Ré䡱[GJeǼ63-lJG|E. [`9;~7h1 6^SƢ_YW۾˯c9;XZUj u6Bن;_UV#6\cQdTl3v]3bV]IV2a0@ dV#6\c=A|C?xPcWFOoU۹tlZپDxAo,Ty RM%UcHcPmgվFg|UN S0H`/ xs$k V­Ӕ)/=>,N?kdթ =k/zh+Z|>ϒ5/t+g\=ޘ7LT$<Ә[64ڷhʳ9;)jNrIh^֔ ? fsUU|!_ݷn~ښjFݮk݇uGpG#\6 _- IzNxy]Y_M/ɠaC .VҦbE $#F~ܱ/[.ܛ #aFd vЄ]K BT glv {y̕0bYxG98?H@q,C͇Aa`'\ ao0([8IH$ -?k7¹w(&YX0 50n )5ErhXX0N >=ZO;$ Eja+&;AHJ'¶v E`@x[eOS0 -`$ 5ea[n՞`@ l[ৣ ,S'+ @%[;=YHja,|vHg[_SG,0<$%j$ 5<6CP  9 Du"t / Ap @Ur0¦]0@B6|Y.#aHIJѐ0#aX,JҐ04 a| X2…. a %tEXtdate:create2013-03-31T17:10:40+01:00B%tEXtdate:modify2013-03-31T17:10:41+01:00׋\JIENDB`xflr5-6.09-06/doc/latex/figures/img-43.png000644 001750 000144 00000015004 12246405674 021334 0ustar00techwinderusers000000 000000 PNG  IHDR+ygAMA a cHRMz&u0`:pQ<&PLTE::ې::fې:fffff::ff:fff:ffېf:ېf:l+Ll+LL+l+lLLl++lLf:ffffffff:f:fff::::f::::::::::::f::ېfL+llLL+l+LLLLL+lL+++L++lL+LLffې۶fffې:f3f3f3tRNS@fbKGDf |d pHYsodIDATx q j{vRvڸI'N=;njmZmV @ vHG|-D"HH1#-T1 4(r9]^U+|y;s_Z {2Alw[=F,޽4n-iA9V<^m%^Q0R(t_"#{\ G^??Btw?M+ѸQ/O -WjceʷD_đT/☆c"i8!O448*7234hMp 9>[ʬO3@{~O~Zg=X;nr >Sg!#~̟|xˇ?oJ O7+ap|ں> tz}rܞ}ܱ㭱mhUBYҵuߘn&h1aK9(vnlF, E)XQiYjK(SVu_YcbXW_[GRc"i8!☆c"i8%q=˯w uX4+,#MjɌJs’8~!.6ABךL&3CwQ=-l;_I|ZGrXhs+=5CMf,1d{y_g2-c&JiL  2ȶGjG1sٟL (j pɌ2cCryBb~nNb!#ݼ'_?iҤJF1bnXq$r҂9ϝg"☆=DV0[4j`V $8*wi3f))z]q-m|6 G݂p0 /j dГJ1l9F]`0 C9ddƛ _; ,)P8V3? ͑q`֎Ȋ+|Q#\1*`\9Fqpq-8H>?O~;< >ݳ*3{Q6T6gzܔ/dC[^SjD.\Hأٜ40#A>uDIC1 4DqLC1 -x%w-=+-D-TdQ[ ⨖䎆]X(O9YAMiucZGXkQ>)ܕ>gx 4uc[evIqI@~zS05%Ǽռu{֒8⒀^Qqe컿nX 86 2 ${Z=f#6qvGs $\(wS(1C?~!ǭvFW&\'E H$Uz~qLC1 4DqLC1 4DqLC1 44:r 4DP\ip}kw8>zwLQsC@2/QS)p}m?w8N!?!☆c}r8F~^@Q$=1` 4bè\J-a= 䩝3:qHA'Q3޻8Ʈ6{_|3#+jG^^3$}8ZqFǛ*qJ-aU8:ԏ9Ru s|󟃖5$Ө!8Z6X4jmÞe2jLu)VnO'Q@?qDm~waqX{8N923F~O Wr3|'a弛kUW\zWNO>?.SZu?8rA3V\-'{z*ggučDr8y|{|Z7 p;\q3z\@d()Kd=8P5n1G0ig(UQ9S59DL(d|6 BԒ{&lZMI88Hlu*qP!DD=T֬ջ]%8t>u)|XϬy?G-Q[.¡eϴQ{р%=thoW>(սWQO Ճ8(o~ѳja/>=ܽW4\E( G&'yhW~9h)B'ꛬw++\SdYMG=e؏*9߭4VYd}iՇ{3,#$Ǣqܗ*nOCR̨p߻>7!Gv<ډd$G)X o{G]BߵiU7GΨpۃ GFJg_C ν5Z>zr>@8Aڞe|}}ɯI}?MSPW2~dN$7%Tv-~uv&_N~RY(҄S@V^|Y]NnEZ9dldrn5pqVC#,jOcQ9cG,z[@^¦ٖՆeʞM٫ru;xGͱ=k %N/}'BRa2JBEqtadآyB< s474h'/!ݾVI0vEGdWC~CZ@+&wx--Tk U(c8ee+Ac:ZrH^;A!~܎gqzi@S+h@V亀JT3&:t yp ]-f~k}Gg=w~,5i3Yai.fa6ǩe:;|P5`l y:>mUڛXz35Elo~%YrY,9xw)$IZ ]o9?pF])U8̨4>|E)^X>@Q|x{Ow:W[)7+xiNR5_i Qa^^ʿ~C>kx'5rd .$>/mjbٝnPAP(mμV(_zc GΑ5r8E19O8qog "xR lș5@R=w8;;?ΪPeS֠nFJg#EcEF5l[ :@2hÞyTG2eNmگ^nne.KUXQhM5 { :m -0bKSFiV5jvq؋cy=zMҽZc5@w+'Ra𨕫NjK V>y к m'azFF(&@0ԏw!\NNU t};UIFgA7]U W&t9h^5^:V|GD:tϞUЦ)%Ua,! /?T/XjQ*\Japyqtƕ/e;T*\Jθr%lJ%K ql2:q"i8!☆c"i8!☆8pz_'E^d%ZM{ܝQce02 3Qڽ35U6~*L8=3Ok>Dr[KҜ.?bC\rTDn=Sߝ 9cާaNW":a%TĢo1-xY+y1|l)QqPq 9EekNz wݦ+onc?S=9֜rW[ח eaiV?lufkN^yO붖'JG'P9;f ı(?L.rU:*ͯ$_P8]7}F,qyBs6$ Gu~}g{7 d~rv_~-cǜK :O.8rܣ(~-[\Ossԏ-W' %jn@8z6N2:~r= 37*&uO't˘rv=87c޸9ƪrC qL#714rCȍɑXE"H$ C"{g%tEXtdate:create2013-03-31T17:10:32+01:00r%tEXtdate:modify2013-03-31T17:10:32+01:00OIENDB`xflr5-6.09-06/doc/latex/figures/img-02.png000644 001750 000144 00000011476 12246405674 021340 0ustar00techwinderusers000000 000000 PNG  IHDR5n?lPLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712HsIDATx^풬Ǿ蛜!(RtUyg0$֟~FQgGϷ'Gq<ռRV(0Wj+8k??ߕ (e5+ IYg)+e%DqܸH+aKtn!`?x%pCY" iPVHB(+! 7 &J e$pCY" iPVHB(+! 7 &J 6#K#; Yoydo^Wy6տm^^2玲 _ 17?ɛU$V&tKbEdYf&+Y"QVW$2̤t,S@ǫ:ޓ2b~n+ͫ"o~paGl@d>k^R =UW;p5sN*B{^i^!>! "#d,a@ʡ =̄v@\w,* B"ZnM Hբg^!.wnc= oDB-< =_2QO$4{ yIL޵Fntj!KWW!ER'a"PY. /\#7:^]wnx*^쮥yb:,vj)UvoSxA&pb&WQ{FۀH A2ê;gu6* /a-"R' u8̙ҼD"L23x{#5$3ZD_F)x*uξ|х$3s$@ @bW  P]5ھ}gTWвtL.6T#euѕ5pS Y"ثyE!q6=X9)e*ٟ,I*%#<85uY Af:lԑefVKdLf VˤvWXg0lJ"E,3:U?,Iތ*c76+an `&7)2H,LjfU tN+Y"8Ej ~ͻN_]\ y[5-pUV^HUGA5p#'=SbgX͌bW^asa1[:`=='+ t2xްH6@*e]YJWo"4<8@ tt)+Çho@'7YfIjjzxm2 `%+!H Wׂy;IYfgdVK$ogUAdZM;,R$23A^`|f"#ΰh; 51% y3I^1"#4lTV D`xLBƬBa%<5eVeLcZUX$udHu/iW d%ɛRVObjWê /?G^9V@ 4dk3)Yf:K^msAeu@dEɪ/6҉ՒXW䕲*95p4Fɫ~5^i^ naJ2xw}\^-iBH2ӱWj߿2h^]EϼAbO)k[+w@+΋5ěMOV@ 223a \_.'Kd7sbA$3/Fm:WLV . *:(+ l]pkW)ea{X%22*$%tx:ķ?AYlo<\9TżZBW>E ? E,3iV{Z VW?{o8O(~+]Ε*U \GR}e+;(-Z7p*˜D`ۼUVTV_.E++.5 ?iŭUO;u<1`z`j&͒eثy]%2ɛ)X uBU^QU0n TC50Zs_({N=`]p/ Ō313;:aFBZV֠7XP1V^ޘ=dЧ d6)c;(+o:yU!jf3g:vǡϝ~-1'<ATްs gf .1xv'xozLVA LrWBd3zV`+G;ޡ;Yĉsddd;@ȧKq:WZΟen{?}+ۿm~,ti[rE_Q9GT^BXm˴ҕ=iYuKFpMVm+o,3Ӱ{R50l++!HތWv:LXeLfRVzV?^EF''E,3CUxm'D&y32<&eU*߀j/ٗ)`vP 'E[ض@3NmC~wh>qѶg d6z"/+q)+e5xyR &$30.KnOXWok~-5H;֭O }ne18dەI=q[,ymo頿CsgUX*Z鷧쵭4м2/l+h$vye9 ˊ4& n,awm3TtWGy IdJV8\Y}@ꡋ330G!J<Qye\b MzjޙOГiM23Xe53eQ`O5UJҤdfFSͫqd5*2=ɊTHfdJYY۷W}HFӱ8 =Y`{=}=1a)HѤ=Yyg1m:-"M);qؚULtSf1_:Pj2?뾰w";(y<.qR.D}y_ 敽o"f$LJ?'Q>YՑBYqMOV"ӞHm<IdeuIde5x3VTHf1ڗ3s"{:`=һ%#T<3 [l5Hn}JOG l3~L@FbEJZIVpyeG0 _: q+=]+NJlBYUZXY=or=)Q:5S$IfUIPV$!;QVD&BY`FYut eEeAd)IfUIPV$!;icK IENDB`xflr5-6.09-06/doc/latex/figures/img-04.png000644 001750 000144 00000023050 12246405674 021331 0ustar00techwinderusers000000 000000 PNG  IHDR ,PLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fDbPtRNS%bbKGDH cmPPJCmp0712Hs"IDATx^]nW K΅/ R7KB#R7;Bkx s!C4,~NS~ 5fwxW_թ>l}6t>_t~x`'8/Snr?N^|gly (#{X˽TsŘI ]`bh6,*7[xUUjjfժ:|bt:t;=^âuZ;moAob} m {p0s0[,1MFܚm Fh:L&d3tl6=Ml>c>[3-?>ofsj0IUՂ`,;imu;NÞ4-ҥeGpŦ}Ņ  Ѓ5v` ve`׈vc0>A{MZLaɛ c>k6Oc:n c@m}X}~D856M|k%UCHtO@C+12,51Á [@iBdt0Ok B1 k̸5+zGU,*[(Kjҽl=m\ | [2\ DCQ{@kDpw][[؃KxCc=`AP` 1ov Hٜ+@qY6f.sN͛͗P|ʃ$@0Q5(١ 0p0 z/C۴2İ"@a _PA[cL!pqL8k+bA"ah-߉3|dWư<څ;N8DIri?"AMDI ؂"@f ۰9SW\~D $9(vAT@m0c@4Ûc !9B[ MES -`Pɘh4E1?{䉍jnjfx"wBMFπ=mBg [o2BՀp[-+l a: бC `004v")/Bd9!Nf !q/a+[p1ybjN.٢%NIН&MQDfPKн؃h0vl;0#jId(|>A@I W 7sLGM1՟DDR1sz gM캔c4@-b%>w\^2tb ik B E x4>;C!gdPwR G$KP 1$7IbO@7x1" ` Xv|CXQtژ^^5߃Lz.aD!#'!QPB(V0@O/ĚC)O *ę6 ['3r:$ pp TXtFqtIsFP3&+ P&1Aw G%ө{Wb +z70G9\tvSQDs @x1G L&?” |# ǰL䘠`@K@(tclHX- Y 'H!0VKo0lBof1c`}"ID ʶS{ &Cx $\ L w[ +B1C O%"p<Ɉ6e:Sn(DEb!?Aˣ Esx99mT`̩\go(ߦ(KI Edb{eL,z=X;Őd;x"KB `ALA LBKD:y c9fsl.p߫ L'Pm6Y1*(K$ATeHJ:c\D&ѪEY&S A<Te$)6, VW8Ϥ_ |0P*Nnުvvw~0p4[#QCE 9PQ9l@\BO 8\1 DsC/΢$7fh0]E0Ȱs"br bH hCS%RV`B+hQX̿~rx`1jsM!x(6*0&O5c h5@B "Lr~inU-B)(CGp!R+Mc1\c&HZ2 w:w]&u ާ>`S$Ҭ`CY (b/T.TF]MT*Ǭ;KC͓WP'~L9+g(1q ,aM) [D o]x8j/groWJTٓYq8*hxPF:EW=O_'5#poz=(P!_Lc{4%QCyZ zD-ojVV: U Kw0az~.XR\ ;6zeԚ%򡫗ң!řy^QvV)R]Jan,qmxeP2@!//H,_Lp;N65RH-04 *x>qccvws;ZV˳ʹ 4{- vy\kA;v̱v2= q?=\D0Cԭr9A[H}y9zho$5+}N毩_p:4Ho:.~ x/I:Gմ2a+dsd/];$ZEO[Z=v5BԒ~`N>8*Pbļ7;|Z#E ^k'͓*]Y<8R<)f$C"ՉO]A)zFNm^+R=* ZvxAa#<%Fo GXrsxJK|8!DjՎt<͠FSϜ(CaUp*1[)6cDε b>$0AKGf4,Laԧ#.;*gJ5}m fc NɈ6ctShRG*Ǭ;wN֝ovɈhh`/x7=n6#=2lۈ谒&*&("<s4IIgy1wo/̜ 硺ȃ'Df&/ٶs:AzPe4[V(9U-R ځf"ӺX@H=9:]&-h"T?y }4b2{S_Rn9~$I'D oL|a(TDnu m#RЧ4]/]jB\ SK}}7^F嫥#;A?J GѻV҈;3t8L;?jߍy:BB5rEQY2F#oNч mF+u H|A*RZP8/bBZb̸"\ڃ%;dXQ~p+'zhD)LWt?\>Bt@ű^y7zzy*VB-AkCލQv;sRަ%DѹM7Gl23Sfџv1|4V~‡Ej¥ax+桿}hK.y7zƎuS gGI%ntX"F,_tr:>(!FOy7z)!FOX]G~Ȼ3 r-F&"]{a]#7;Xy>y7z^5a&VYBF1Fy7z2&opCF2.d.p?I_-,.+a!#?y7zz&+湍9x-yl,ʹ>d{7G.snpkxx4?!;?!d;LJGGx?*;a8gx4>!C? 9ԉ,FIȻ7v{[ۻV{ޭkmWݪ]on w^=7fGfܭ@S*s/E)Kw>i̺{v78}wOe~[Ư3eSZ}I%KzW/Yu7|6tΚıH~q78D}7zQC#hZ(/qDy7zfvi}[.jpdg6g7nѭz_wCH^Sk'BFM2O?F.~0s}\=;\J[ifq_hPiAݭY{a/G(4B pHs-G(\q^, !>=q]m^, ~ r<3ZE`qOx?[I3PiToxo7VM!"FQvtY֏9כcVp idlz%/zzz kyw}wuE^.xlI(s(elYzX*ŏ7< 2s@$;OėŽ*`uŞR-^&ݙΖIaFM/qHsMBvҭ/Wn~+ir2eq a/"[ ( U c/{PIe^^{h,j%(yL c0_~\|~,!; iK.ݼK,/%4JWgm2"lynmΦ4͓2ϑf ϩ2i*p(4W'x'~GI~_f@Zo&FetWHG$@qWiw6HqY'?f@G4D⤙}0N&̀Ei}!iU~"RfI~{1zp3i ZA.͟v3R?}ߺ^hCf-i~%?M-3$f :4i ZKA$o2\fI̎^x=A{gefqAx ^L{|Hͱ{Q{vNݎH3`O4!ss*j݂bY xCkQfMԞ/ct i)OncqvK]ϧϷmfi>1j56sz?\x1~ Xx em݋wz#OH3`M4_nhTY'|%Ƒ%̀5|jR,r?4,)jR}^_ ?ʄ4.74obw3GOc6柈6Ew4>%4f,<]h>m݋{ǷK[|8km݋{ %̀-yӜ,}Z*x S"}]XO4 C3{F= iܜ{Afva9z@aڅhFk]XPiva9z@ab7ϱ3>=0\ #5>=0\ ~w)`iA?zNީeAuU[Hs ѻ"\ ~YH7\ ~34@ { ,!5>G8KHs ѻ'\ ~34@ { ,!5>G6Hs ѻ'\ ~34@ { ,!5>G8KHs ѻ'\ ~LwA譧8cHs ےf=#5>Go[i34@ i&-\ ~68cHs  H3q.hf"Pf!Pf⌝!Pf]!Pf!Pfڌ Pf⌽ Pf} 5H)Ybav >"@n>}PH}4J9 hG*Ck@ i ,#P34C5e H34Caf( 2\Dِ h(dDNQڇȉ4ۧ@ iv>"@n%4Fpf( 2 XF2H3f`i ,#P@e 34Caf( 2 XF0H3f`i ,#P@e 34Caf(2 XF0H3f`i ,#P@e 34Cef( 2 XF0H3f`i ,#P@e (34Caf( 2 f049!`isH3C f049!`isH3C f049!`isH3C f049!`isH3C f049ɘAڻ `isH3C f049b@ f"`isH3C f049!`isH3C f049!`isH3C f0Npc !`isH3C f049!`isH3C f049!`isH3C f049!`isH3C f049!`isH3C XKӟL isH3C Is6 `isH3C f049u4 TӋI3 `N i4 T[f{Ai>i1Qf@i~ 4 Y{@P]iNo l4أҜf NiK96 `Ksb7l@i~xf f0nrY{1懇,misr9"@V1 `L3m4i^+3iдJLdL4f 3b `wH3C f049!`isH3C f049!`isH3C f049!`isH3C ԟ q=bHTe;D,͛LT4wBJEi^-}Ќ  rUyhU,C|oiy8 >i /mܥ2{hgVM󵒙ވ>jo,s%F(Zɳ3lU;Ci <T383L,ٝ8i :P=u33av+4M2foլ6x @4VCO:Hg$͏ 0?{JJjJ:`#K, 4/434Ҽ\*|HJjMQgӼV|byX Ӽ|(yCH:-j% `+4o TCi>PgyJs3?4o S{i>PgӼ1JM@,K"uࣖ5j8 I+KvWGP|82iD'!CC*iN|λelFʳ4ig4[*cY&͖Oshqu+,fK96;L:vI%^}0hvI%ݦ@wF;ˤْiI̞|{elI4Gei>P2idByL-)Ȭ3nhvI%|EelI4G4Pig4[R61?HǨsL-)&,fK 9!!م:7H;ˤْ2iNiέ2iHAsSL-)nEĹY&͖Hsb4H,fK95y,fK99y\=,fKr9y3\7,fK2Y96jelI4K4!2i$kE@Q:ig4[32i Q#,fK2Y( 9uvI%,8E;ˤْliiNsML-ɕf4ԹY&͖dJ`Hs2\,fKY2YuvI%Y,, ig4[#Ͳ4!ζig4[-bF%QgôL-ɐfUOeqa,,fK,I8lvI%i_9lvI%i_ҬT6ўsE6NsuN!ζhϹR[Ȧ9"'9QgCǛ>aah,pҜ63Ͼ';LsM#6M/! 3D0͙V6i.:4Af4AKsUM f'ӳJ<ҜmIb)2:M~3\ͼTg\uV8EFpܱQѼÌP3e\qV:G>ݒ!qߜÄLs.d\uKpR4[C3 $}?pb+4C$_2pr˒4DΑԇw4\(,-pޤY+wS4,,+lߤwZQi.HeYP I24A6'aLl[BE'"4A6{4P2?0d.ihH N4?y'Jq2?"4A~.$?m[GeYÙaK@LS14o=is],8'>;/$.ih14+<ۚ;N3ΉS0,O4?/O;5;mJYeM_({Yα\[Qݔ I3#5һYqݒ\|դz,YVu ,70'dz* JO4_,rs-u`vۘw~uy{LEi>Y"gʼ[RϜܜfRS/כ%~sf!XݒJf4=_f]E=)괳ԼsFscVUi6 ܤ3!hgyᘆ'4k4B:;;Nr{_f[3sSU]W?HLq^&݌kZ[Ҭ;?fݝq^F݄{g !k4_.6>K4,L4k4\z;y%Vin9EY xmvlaT76vw0B'4X6YyL;;w1Sm:C ֥4X3 Avw0'ڨEfB,6N{YnILR՟f+44#,?HReyI|^{3V_, gҜV0ˬ]Ls4FѸ謝]kz\ 4K;y˝fљNo[ >,[߮㬝]i)4sU4w3$>R;߳5nqr.ۤfWGOJswrY_igywFO9|9iֶȪ}Y;ϻi6i78Oslo?,)ݕf3_"1Yn~M"ꞥy-4wgH%3̻ben2r4G+ +m/"U5yü:]s-i\g=%`Wm^o̻1i$a si~l|Q8݉$z{U0egi*sK$Ў,fØ DwKs06º,s54@wwkǼG&߲GP+}FXSe~Hs;9ۮ~.S,8X4}>d6|6Msݫ$]a9u2?et ywStў&ĹcΚkLn~.ڳ8:jHh|Kg]'y9 ul\l7η4dɳStўq9\\WN;H4Y)hOPnid9Li:i+"e/wL䜭vRK4_mͤ,NhGD+$529m뢝"m|LgC8NjutXfXqc~OOG{bT[5b,uMk+YhO({Js]eYQai z{5Ĩii^l菅۸7ֹ3D{bԇP\l>5V`W\l=1C׀uLs<ǧ΅IQ.w92[[;)]F%%F(Qʼ]'U~^.~iv aҞBV-v`g =a7Wh%|\sgE{ׅ2ohvְ3PhekKqΙA^WDF[{ʯ4g7dZ.G_3:vjBix׫& x\'Ѣi>:,=d ڹeީ^vp).pHy8wioݻzʬ=.3ڽ<^$m~9|< :Te^.OTGL|4^g^ ʼd'gU~,W(KqY6TeO {(tB5Ǖ:^ 챫.OlNH3oxTevY9sHE6=ի@v=Y:/.棳6>=kL| 4u?*Iq~ÃVz(޺|Is?X6?Y{Gn,~mFw(3a3'lj~SՕfleP:=#5qzs8A1RrhYlq5{>Ya@Z܌u]ڳsCi>><g(s⦄FrMK6l0Y̤ qsB{iwY1|_6h2YenZܤu]oMO|V30f⬆27-nRh:m.[^5JmMC~Z!ܶY=ѻlzAb4[TF̍ڣN427%n^h:m.d/nm"./5ܖ=ѻCU8_h8r}`~P Q%Y;ed/ϾMܚ=ѻDk:;ˆ۞#\s?5(ssFۜ;_Ln#\ uZPMQ% Y0Q22+(sfFA5Eop|B nSMQ%3Tn8:^՝kC[xǞ9enRu]?Q΅ڼ1̎!"wiS6QEwM;D@g#΂&;H7AG6zEתs'Y h.(0_@Ev%enWu]\]6d n튛#ڣNd5(MQE8͇Y9_#GBP}%ڣN|:яXs ʼ3qD{iwɒ惫U^|N, (Q%W:+9ia8qB=ѻdLSwo[ AB=ѻM`y)9a2a".of"MQޥ@okLϑە c z|e6!/nh:m.|[hzyV ae6!/nh:m.%ܯ6>OiN7Bɢ=ѻNmiyRflllf!B^lu]T|[x4$Ϋ_~˯~y) m7]G6z4iY3u^Xf\Ȼ77_T]t|z<ݘ%rIsO_~IE?g.opPg2Rl;ߜ_HOY?8|]QJQγ?¬̤MCOΣ/.;zi>S<:/LK4ϙ̯~s/4Ysm96:o(3i.5Fţ_Oo/5&gj}l&w]3w4_iE%ӥSˏޥ4)yIV묽ە 2Rk3Q?\fEw%g< -[.4w |y^ya4GFk:ӜM&N&'??779-||};6eΓˁ۟.ɼO_>GDfgѬlf_~OԵf=zv BwG8¯~wjڭsNɣJמsnoqZ,iETK_|;ǣ'i3=ݼyyDgcrm{[M-Ę{e`sL77:o.s4O%$uźU闟;N+<[׿S#,nftWζ{$J bfSs*,yt.wVMOt~Wont]mmfs=G>=^x?hq'd ߺ|%`syBFmeO84J_Zt6ӟyīF??<ѿSzv{}N.i|/Eswɝ/@:G]ئvQ2Jɏ|3JMwW״}5|?jѯ/ͬ=wiDwh7;>M~<|o\i ]IY>s,z_X*sT c6&og%3 Oo3og_պ{iD'5/lvxq )Oiu4/+2WPڮsX8Nz8 9nf8Ov_~=LfOo,nlyA[bwi1g<}ylaeΒ޳i~u{Ɉ'\0{i4 k<nuwKq(d 4K\]Mc@?;&ڌs`ҍq }W.~{mra4͌~`zEcx=cᑇy]oOg!nlّfwKi>+N-X2gI,=k}kO# j7Ƴ/oэמ0ۃxZl"r9KN/.8zlƿ8Ojsܡ1?ۻvK'Gcr9> lfU?[{1yw5͡-t/K\Rϙ˛sxsw^;v|Y5{}F\Kf^}dw߭m&Q&Χȣkok&  FᛩsDswyRI?_Khy|_w;gxFxsոYs{^ΤIQCn]/ Fcʜ#os:4/c#*_oʞ=rDG!q(l7?Wvgү~C<9̚i[J_\?;_]*jc|)yr?J|} 9庆u;e+s\U/O|9S,q)p#|۝Dx_>:巁rK4w @g~u,rߌ-bEyK:.=>*vAcq_oͤЭ|3hwٜt{ C\\{'۟Y׀GX;a_Lh6q{Fگ6;GA%sO ;W9r4>v<2yۛ'Km䳨"nzѠ?#~;V6{yW\҈Kyߤ4ye.Sۅw /mҼ0P2=\҈L1[ΗG-6r˃4/Ds|_ 솟yi47sMSGiy}^YMč[y]@gy0qN(s4o{C7ޮ̮|~'ifK̽]pOkIާMfSFȭҼQ>˞WrR,i^xkM5Hm2B~Ѹ73}m~4?Vć $WGp5y22*[Ś~Rz{4ofs7?[{ya7ih@|A= ģYsZ3}6b ?m,+{GIͮ?i^?s"nBlQ!͑2YL:'ǶNO&/&}d>\;=f\W^ͶdO/;ͻI;`6Q)[$FHs<z(qN-s4_7i'{qkyhGf>_zn}*΂e6!!^Hi}9.|OocYf"=# iL-_lf!B^3Bnѐf.@G\g2YW[4q}_{~\s2YW[֤}w갮+yu%M_MK ιlf!B^3Bn5քqUݩlf!B^3Bn!6ssJBg& ﯢO3Bg'ͭW?9c,Dȫ{FqҼ 7Ʃs2YWy?<:g-yu9NfsgwBg'ͻώe6!!7I~mҩ#_f"=#8i޹ }|mF2YW>n8/yu9Nqg߅\f"=#8iІ?d*%Cf̄vp[[Hvn}NL8]LQc'Q*GLQ\X>L;ɤ*h3lN2i L6%f$̀< )]i@( )?^=8.qGi‘fF`LUq{44~VfƋSUg`i , PD7 e۠4΢3 KH3pFa iNH3NcH3,ie"0bH3l`KҌJf iFM7iȄ4ZD]"hiFvfkf2VfmfϜE g4j h/F+H3CҌfT4M4SiT4Y$ .p.@QҌ}pL.ҌEݨi.q3l#'^H3vu2Ҍ#ΰ4cH3,"Pl}̝y~׿޿|qU??~|>o{[ķ?Ҽ\4 034ޞg~߳¼~l[5x;cpGkK0Faf 3~~gyӀ|8ﷺ폣|qw'f1z-~O?$ if_a^{? =<0GL8և ?q%Q@̑t}_v}ݣ{}ko)_[Zİ0o 2$ Y+:LK??.._ewv֏q(1,`K0#ygbϯ_vV0 qhq _^_+)FLO_N 3ǥ|/.bfK{cfߜ˭0~>s%Q@̑L/Nۋ 8_1frf#|v~$g-8ftooݿsi %ݞ/bfVf rTa{ga 9s%Q@̡Nߏ>WP? rT=uܳxt0o[{gw$ 9TG'w?[*1Qa?4znֻ(?4$ 9V+0~^͏[=}r\=N_Lq#ggDa1Xnڻ.\#}p$( N}p$( N}qڧsڻ0NuN{ii>8S9}:OQw`)>E}qڧsڻ0NuN{ii>8S9#N}p$24 @ Caȡ0Pr(LClhCaaK#! ȅ-8ā/Q640Һ/lhCadfs7)QeBaYel363R0* ) 3gm`lf_.}0Q?4DI`6.J\0ȋF/] 6nPvZ.#Q7(}-yj:-C{J@eZLy =',ehvVe8(QhLTi`[(u _]s5"JZ} =o)L ;Eכ&j8؇i ΅sh. 7 /Ҩ %˩lS[hfF/i FCVIaIo+4SbqI.y$5Q$,W ͡Z ARbiCw+1 R*4M龎,#}0;UDBs{%7m 0QZjR_( Tޒ Cs&H#I;`_.m/y.LoGH~Xƀwt34'ilcy^״/=5),ARs^+T38u WV^F?"Rd]\h]0joafдMaLazi3fL+4-_C0j0 M/+?U~ѩhz дUX( t }~gNB14Y*LVz) Fh( :Smw< f0|a.4-}K4i :So nJ ҳB0M]zqPO5;SxoCPFlЌNo>PFΌOcŨ4LR+0hh( p#^Ôt 2ӽ0MtggC$0; ngBST~}I0yM)_ P,LBtV`~az峙 n0 /Ӆ-js۽Dh׶03 Oa lQιO6,3t+Y)3s Qk'π0ND/r0οq/Ӯ0 "T3V^x*̄ѳ^a9 \r]gWt0vO*t80O&t:W9M<w>u,+{y 81~ƨ@X?S,,@?AJXy8.Ҡ9qp^*^ Zq]tNh ya׳<@hfy>A}n RCT$]ʽz,0G4A0~= <@hPD0%~.]Ek53(I 됎Qz ,̹_guގdg9NM So_jU`0>VY6!Xw:L wȫ=[3AG0WS \:ܗIa!49)c'0l.F<4CazK0!<fq.E : |an-_﻽ 4/3.҄d0wL>X,fx]3}o&Å;]>^inlfᰡ0 l3.Ҹn]0hF#4~,\]ˏ0FoԄƁ+p=IԄƍ+#o pjBckI'52+84 SRSIBl4 s&1Fmj.XtDYP_Ba&4^ o ,rԄƄx=ߠZS9k#4w]6ozy(&B/P>[ #4OMw'*fjX6M3'BEguDt&O&i< V#4rZ2m^K, #[0X 3ݗ0F`kjBSD0i9 I\ >G0 (L&4)f瞙ހ$ajBl쓹 5v$ >59QaQ ^m S ~;䚚4f-0)&2Zh/,2~KMmkT;" 3? uUE[{kI㝩K) ʞ3SeNن޹#i7<+p#t?GavF|;m-+LkF'fEayG/a^q<516\fZ_֧\q<5mn. RMRS0O"Wv`lT2sQ޶ujygKٻ d-L-3WŒ>R75*Ta1geဤ00 3nԈe02sQ E&5 3BGC0\7SUMM;酚Z㧭#.iSEa*fx5RX_d[TOm7Ea 3|(Loup|Tz:iP#O<ͷ`´,`a]i*F{.Ca4 3|Ș-LO װ0V/07).ka^&Iy|u3<,fyqRjWhVMr*Ҭdds|d){͂LFs-Q0 Z|d) Y_}:h}4¼lfxKSh J:d6tڥ4aF=Zy:va(^څ|=s(Rܳ‹ș`Xʝ0Ç0\-.8rx.+kj. 5 Pʝ0V?74׼o.f2~R ^\vfu>KZn8Xɹ Yp(LTy@zrF3f\)H( \+)7i( Tn:S(\! 5x*LWs~}NCaZ-Zix_Z7y?L;0x; &^ vۄ)XYjq1^xRCa(& 5aFۿ (5&0Q0 uj 07:YZjq0 %%茛Z{RsQ fDEa(&* Ca^08+Lגciӣ& 0^9LkQOC Ca´40fu^K)iHa(̎47zj Ca,0Q0 uj Ca,0Q0 uj 0q9n2Ya:50P( ba"m_=X`0MXŒ*L+&4D\Wa2Zmya s].Fy40u5(z(LR[r͓0H~J7WL 1)z(L(uAaXPMlbj(̑+Ĉ%¨kL]. SZJq6+I&aj=ɡ0Dr29~) uj =;璒:tBr( "0ꅙ]49Xj=&* c0E.$RkQ1Zu{`̇$ƅ$~l0WEބccܜ{T0 86V'<RBfHMͩyamn]3 3&q,FS_)L{ 3Q < yBatcsI'5CaLaSZziROr( %ŵ0{]]43nԼ3Baɡ0Q05 #Л,IgiLaNMa 3M(+++wia DEafk&HaƖ>@aX̥ԛ˜[è0irla·f^=wu{o}f iLŒ]%'D37+oiA s gV*9u7Γw =}Q{f-œ#A.yj._rf Va&iܒEUn93'V={qK 3ͫ:3'[fro!0-7.ԍ0 F+ 30\Ua䚱 "nleL˅&2n cŒ]Hβ[kn8- U V4p HF_y s],^&6qQOÌ0uj Ca,0Q0 uj Ca,0Q0 uj Ca,0Q0 %(Lԩ) DEa(&* Ca,0QQ cAy@a|&kI$aa.|ўh40Ƃh40FP (Lԩ) D:aa&(> uj Ca,0Q09%.za߽^ Tԩ)L\.\0Q0 \$1 S^& #Vd)L,OIQ28b0R)[eOJzF¥)L\aBa"\3X܈ס(L |qJt clXކS7=t( NzS c}k?)> S˓\i s0(Lթ/si@mˊ?( )Grt5SRjL]p3F+LA %(Ta2ő qIa/̗ג 6-Faw`Y^+ 6ugn[YȍXS=9 E(lwڝi! Sg yZW_LQZ%sYȮ ͙ 0 8M¼(́-cixL-Fid svgbvpMmǻFvhuhE,Mgrc7(hPyΡ/Ps}Xm) cQy/qPs }Xm#K,Ƣh@_0Eg7(<;R@ƢhB_B0Eg(0&! ˜}8CaQS`(> c GaL>0()ڇC0F1Ep0hP}! ˜}8ﭶ˜}8Fa,0hQ()ڇk" c˜}8Ca)?won¬0¼u՘$,f>%y!* F0>붞t,fg!* }a>.??Q(ߏ?|\wg uCab0jI|lo7(LlFM¼s޻lyuqy ' yG~(+FM¼^ 7_{{r]af{D0u-Bs/}O'(?h?׮03 iKaZ+O3_z0nT{F 3}sZObO[ Sס|kAA|0~f1>PI-Paz^cT;ra~YxyuY-kz?_7͗ 3ҏDI83-?m)L]=*?vq?7 3s^-WkQsR9̤0ov7iXԼ0Wo/(Oìf:̨0a c(1Ƣ|.񆷿?,z0OTZ/Wk9,̺*5xU+'of0{ck^~9?Ƣnsz0x0Q '\Rffo=_c<_JzZppXQ翣;F΃ofx\0QS(E5 c1EppXDaL>\0QSvwFmT(E5 c1EppXDaL>\sX@aL>\0QS(E5~#E5 c1EpptavR{˜}8Fa,62fu݉60Ey/c 61_>8FaEP}:3;)  mCaEP}:F_ymCaEP}AZӿQ̓. |0&EiY/t-˜ja;VK0$;咍 hKv%ЖK6.-)l\@[S.ٸHmrQ g6(3ut}1d" x0(;61)ȁ˜`D䰯0h(I FD^~ׂI0"r0&%9P& Ia1  cA$ (IAX˜Da¬k%e x0 K^CyB (I7810&> c'@Ȋ˜hk cI턤0˜DaRtE2FnbXGe1,p{rd1utS SG\aL-Pzl SG71utS I߸KU . @pNS  @ @¬}nPr( 9@ @¬k+ZCaȡ09o4@JXv҅;! XGaIuҥ IjXT']a=~ޓ#46A}x8 F,0P > 0jcaY8) sQY8c0k_0? @ CaȱPu-uV R^Pr( 99~s?+:00Ҭ֭tNpQrRt,Huҥ IjX@ @ Caȡ0Pr( ÜQY8) |_a,1[ Deݷ +pQY8o) va @ BaT{ 0Pr( 9FuX~s7 =2PVNxc( 9T']a Rt,Huҥ IjXT']a Rt,Huҥ IjXT']a RtEVs[aXj(e0OG ['.bqsY(Btܜn uP7'9q,@͉f:nN\7 qsY(Btܜnx"`af'KxQr( 9NT:R XK5,`A.հNT:R XK5,`A.հNT:R XK5,`A.հtP Caȡ0Pr( 9 @ Caȡ0Pr( 9 @0ЁLm|P%tEXtdate:create2013-03-31T17:10:42+01:00>k%tEXtdate:modify2013-03-31T17:10:42+01:00cFIENDB`xflr5-6.09-06/doc/latex/figures/img-42.png000644 001750 000144 00000013637 12246405674 021345 0ustar00techwinderusers000000 000000 PNG  IHDR+ygAMA a cHRMz&u0`:pQ<PLTE:fې::ff:ff:ffېfې:f:::ffff:ffff:::::fff:ff:ffېf:L+ll+Ll+Ll++l+l۶ffffff::f۶ffېf::::::::::LLL+lLL+Ll+L+Lf::LLLlLftRNS@fbKGDf |d pHYsodIDATx۴ǑJ^.R}a6k;`l鿞GYvb[y~^svoYңGz5D"HHXf*☇c"y8!☇c"y8!☇c"y8!☇c"y(9i:"4iY+oڈ._n%4!} AӭEwNuFԠB9)ܚ/6czqb©3Jxv覨P.k[*u碿IP8u%a&am&׫`5>[Ӄh_]1xb+ԸJ|\{O]Fz#ސ0>j^* Zj(D) e8d$e8X N]ab΃ݮBJN(; _$v5NqLT'tzIOcp.^ձ#R01Lܛꖍ7* d@Y1ݏ=r4] =&~6*GuK!8`HP0mtc]ŒA K$H_n38G5-lBdM->5p h0C[Z|"10GffJE5yGF jf2t!G[czuPpw1RcEx5?$i7)[PQcc·IejV7_M{0tjw>đ찳A2Սl}#QL6.p@>(&F81ʵY g9t9x8>5a 5t>ʑA6u>ɑ(XǑqyH䈷 wAJql  FO{$׫O^1 4cQ;L"#qUM騏d@k#pٺɡ=?Z0|Ń lr`XA⡅gW3HX0. y Vo3 s, 576:Ro ⁷"2H;t9)Cg qnZ:!2qƌ$qA2퇬I8M$q`KGqX@ . Bp$Ph,玃=C!fx.%N9O;)W#0 u!kpf/Ԛ3GNe%sqs9k0j#._Xz^WIϩSkg.*ܕN}s䐌= =ݢiyC/O~nKhzzN-^:}8G ;q4qUqz>o?{~}A8_ޙdx\BCDj{c47CiRU =Q8pF:g4?gW@hy(<ƨ䍕;fgWK{f*KeKa'~2GZg+ϽP4;ljE {,^ӭWWeQ߫?iSE, YTeJuf찲\8;1qXm{<oV{ *[Q!@OX18sjuf8鲱ڑعqKG`s;G2*O Cƛ'E,GMxR[ۆ>Z4OiK YXc9l^*M6W|L}^lU(Z5 U#T=l&(1o:$ns|1e'omՓ?lci+^ǿtG' իӑׁݯ;۫eӳIq k+;f%b9*9 sezd\M(+e4ds1j:w\GjXQ.с !%r Ũ$Z)P0\? !ꋛ?^oKǖ!Csm>\)ºgrDAՄˈ~9\VbWG_ Q1j&F=|'%`"_>gɼ~l/?~///J'2V,GP يQ3))]I'X$v5`,2=^h51fR`DE솝|ͯ/~@"٣z0M$#@8 ʱM`SlXKr<.)D*4:ܹgzU;߳GA/ ~ZUc3(xН'/}KAǭccp4u!,Ml%#@ŷgqWqF#^';im3G$\(w0/ʧ+/D~i*uCҞǁc"y8!☇c&Ig)☇c"y8!☇#UYs/82MN/8wx?;c1iOI[,sAcQ \[jx*-,ܒ/h.9G-HG1d* ǓNy#ύb U  Sȫ=~`^m\ bƶg(Mz/.uln+w/2|ۙsOQ6iO~bhμ~?1ȫjǐt(G;\qdhK^9K0nbprtOK|Z]vK/uu[Xj̉@9b.{ܦxuy_%ɫ[TQt٣e1yg'>>>qFoL'or]8i1{;?x_?v>o0M/6п=nɆ3nAN䦝tRv{`'?#JO` -}6Muq-rmUnW[2vnw~ gi>]>nmMĕ_tpH+ս@э]i2_o8?F'[\^xvsgt3/|Unӟ[ϧruz5Gϑw _|q/#CN^rWpX~+m7X Kkn>,C8^{WrXMna7K^hN 9Qh=p ܃bHR~=\D@V %`<䨡CCQTP 6 АbHMqYS Qa[tz*9jbxZ_=y@s7XEԊW,Bw SXʙS9E)zyo{,ڶ'9֭/bq+DӛZa% !9:1{zz~.qC|B@kvn>ZlD1$1lB0&ùC{ ܒ܁Wpo|4 uru/~֋^:*"'pK(' GDP /W~vbLDC8(9imŰ ɯz3Yǵ z[P I iTrTbHJIfM% G+r ,"za@b( @/!F4͚J@ʕW I :IӬ\yŐ4͚J@ʕW XE@16 @9P.@^CR&i5+% Ћb襇m@r\ (>M4k*9*W^1$%`$MrCRN4k*9*W^1K`@K C@zP I=|6iTrTbHJIfM% G+ iTrTb( @/A (r ,"zl4IӬ\yP.@^C/=lP XE@1$hYS Q!)C'i5+0tYS Q\ (^z('% ЋbH$M@bHW IfM% G+ iTrTb( Pn3IENDB`xflr5-6.09-06/doc/latex/figures/img-47.png000644 001750 000144 00000046723 12246405674 021354 0ustar00techwinderusers000000 000000 PNG  IHDRxVgAMA a cHRMz&u0`:pQ<PLTE        33  333             KrtRNS@fbKGD70G pHYsodLIDATx {6bىđJ-u>9=~ ,i);i @a*{GEAAAJA7"dؒa L`+91AX6! d؀)EqU @1 @1 0Ze`JA (7M@!2@!2@!2@* ePz P z @c(P.RcP+ | (=Bd(=Bd(=Bd(=Bd(=Bd(=z@>B @)1qv|~o߿|8ty>}}}U[).M/뽴j'IƇX܆ 7q~Pl9*Ԍ "Oyk/ 0 U3 x r=#cdg4WY0 N+Df7j.n=pX9Ȍ#׊Ass@YV~&}ލd0ڦ3ϵo6oY;o<+Y X'l7/HbpEz7S|o?=-5qTm[p0v'dX^eNd%D`]cXƧ&= kq W]c]Y$2us*!/;S+r 2%Kr{L /<0xS|"rr$W/r? L% @VvVd 99L LڴW82A+E&0ZaVH2{ /J/{ ue! 9WHEn6> @"O$& 2r rWdm>ScJ}[/n/-Y_dswy{|ww]E&&=KF, dwIO @zSMz×қ |I {s=|zAZcH*U%yGzl @bvW6}ډ +z R3E%}xRVwV$RIr?A߹ rU,)AQY1#;cߤk.N\c)Nr"K o} )A~c+[<ē1 hAZXKo}$E&=zv?Bf(FV]֭!G+"/A#Юx3}E @ ޴{1$MZ|ADw O 2dY=Ao]Erz*O2s*d =AU*7=<9nL oMoUr1$pE&TM#tL'L {@M <dX*(S,)t|>%f~6)@`"bd rQ-ur5k Ei\@=;B2,2|}pG=%mJOnj KG U'Y%7@B"}{eX"bGQ wI6Fe1,Uۅ2,VU&Y``̐JY&Eo]"Vc v[ E<+L`p sV_1,4 @j[B|F1,"|טRI̠}'%՚6|=%O2ABnѓ'cX qژ`#Ȝ 2!7bF, 􆉕T!z K @&rGE"d·cX =mk DGTCO tǟ7M_q s-~6L`ݛdM4 z 5vXӔ_dohҪ\Y NiTUo[gwG;5TiҨRfD罽I,2,`֚M5񰲭Igdz "U @}BEV 2dٝdN 1w[ֵ"y .2A{Bo+_MlSN 2$6uGTUdz ,7a'M2=٤ QU&M>mC] -z 9)MpY䊧X@L _B"s 9|EmC}Hp,Ȟm}HOӧ-E8A j={\A`8y+,1ZP)%{2Pٜ:.!#0ST@L`uO0&`4}du֌E&¬7Mk+0ϼZcKN`9?"0˜J#d.؝ky1g{Ub )Zdz 3܅ /-2Axx#4Mun}`7j<^Pd v^Ť,2=xAEWX7_ EM1oFUI~ֺH (r 2=hr:wdH$,C1ssj @ZGmL -ߣE&Q"cHk"dHj2"cHj "dH)z$z Ud }_Gcgk`?"i?Wdz Qi?Sd QQdz Qbi9L F'z"SNʚbzݘW)kCgwvk["}Y ~_d)j2ZǛ:80k8.Gz"7A0yV[I"d&^_!W$c7 <*+Wb 2SlHfT߆ k! zM^dȎ1Do mL^ @0-Ev$Y_!=0=z1o3nA%o+i+fޠpy3h`dzpb/ u[L L =.R;D2p3S߼c fP+z ֵwG-mU}!z3۞7E3  `#>glO ުVd0d0\CW:`9UdX_=A rp&V`\yvȢ?F&E>`zLCIe]z`7㤸:,+rP0=E1AF(ꡃ)OVމ"OlyEuAfJ-c .pHue [ l}S.\P}Xnu_~P>'7k}=gu=W l}Ah)igP'ȷJ_)$1 } ۹F\YO򚱇'ߜ+In]'UD-u8~Unlnh/E"cDt}d}qmJL~i]ܬꢬ=2l{gEeC|Wdh ?ЧP#.&W㺶VoRMyQ&տjP[褗xL)ѯmi{ZYF<fEtų"8},2'؋߽[(U5 VfS{u\,r=DdU]j_EWK%6uo+//(߽֘EcLgsۮP UJqE"53GUdz=i5 6Ε0ZgtS~즱=ặG Ӭ"?c<7d+z1vVc޵O~z?}~ &Z0"-V94c+[*V'ψkneRzsc*\$?wSO<=ƞm=EHnN洹_:𞽋UӜ(,1N"fVA>{lq\׾\aJE6Ǝo>nf>V E^q?^?~[oCQ}\ ߾N_VN-rgw 2"lk;:'_#7Sqe#>yE6;)W Udz `bs}U&e>kO)} s<`p40KAh/|꯻Dz߳WxNyr_deDYZ#=j(8Ws!m/ZZwQ^d>Ev,1EpN$6Ylo\-g&"Y(=O%Ê?Gn ! F2YǧcOZo_Y[&:h(P kX'L@5R!Ĝ @݀";* n}P&x(=x͠f>x(a^$WB@㺸"-"hma#8( rq+Ӿ&?!'ǹ^AƑQdԱ l 'cM8}7W2"P%.gq =ƑQZ˸~ 1+n |oEi2\-i+1@w*]Z(|Me F:)if=**O { }|ǼWQKRd[AdMry"WMZEwM"Oi?Hooo柧/}#@"Tv$/͋-r&TO1Ъ( YE~\ɏREQd c?Z"cWQ?̛"U[| : s-c% [&B읭n[8H6tE~{k%*dAI(F8ǡ"d %=Rogz@Zy}Kru/{1s?۫E(ږ8o,> !Ks+4jPTFה"c1+9I:tGDדb|OXȀkItVa6ġ Q& 8tî܄8=!dDWcE4{ dBK{YBUKE,E daȆ"g"R豵.{2eWB#r!Qd Mv%-rP$d +It,rXO1Ay*W" ahP+icQr+[R YQM)tj "usMP+,J},L9 /@bQtgHr"9?+xVS-,:tە6ˊPLϡL[*>]wwe`c_\OIZYAv 3 lዜg y_2׃991g)@NYڔasy7Nd ,쳂/GN]z ,U=`s^ me0'0$xEWIvWX$ݭ̸2٪p&^g[ʝ,5 $hEN$yI@>EI2ax";F)2$Oֻ"UdqhS䢂C9^lXNCegPYs<7ߺWw"hD>XU;.p8*!9_ܴl_1b!=_6U߿PVˋ!EVMH,8&E G_,zEV5LHSP>LbrߛM~{܈JTd ]=9x,jDbr^+;r#JLE"S}:F*]&=y +&|6cru${Pd{/rdW,DgɎecV)O+Qd;/PJ| E[ӧΏэzmguT~J . Evئֆ9JtHEPvoaoEEβN]_~G<3g3=g{c,w5YmRWS}^+[6NW)rƸ]ySD>񝠟x 7Bϑ"/ҋGZ 4T凫W`u&"y52_^"קgeM-f9|E~ ;ȣc`ݯ"E)/"iV𿻭%R΄)ʯP䫵v)7c?*{}avHz溦܇E`PeNr8*PZq[:i *>=Yݤ^kake~YrZ3uY?c [o:nT; M 8f" wzՊ.ҶHƨުJKl=H.IG7{g&kV7֮U[(^d5~gzJ} 9Ud}by޶v_NwNiEf&H=VvV,n8׷9Y[^ծ(EnkbՆ8OExfդXAv~J4I_"'"NBy18x~ +r=~c3rklk3gk-uMyܙ:  ȯ<y]12Z&eYi}2'H5jъl:ﳷ"?-Zyۢ [ wœ="AMJ/wc]PAt~Sd_VZnf :o[%1.wB[W\c>e+[9 XL]~r^گŸ Edms~uQa9hآㆣ{{၃*rsz)عn]]9ަRWkf_uodE5^Y"O$r܃8dIƑ-/{:瞠o$t*l5ºElj"qCdWZ\9gܖvG8AHȵ> Tl\aվXW|y#{+r  [Ay^c E6.mK"?yoG:_DwZc櫱J}\fljo1o)NAۧ[kqeA_ OuY?vflSsM rG.Z_1[#wy'/iM9";;K{oX6z>.p.-b;*Ev ZO̰ /=GWl\QnV.O_kQ跩쵺|3mXX8?&mkOU黨]dS/\vRdg2O&e)2=ޫoR(;R9,DktAlWW>b('Ry,ij#AXjE-]佺q.AS[JR8ԊEKN# \EO} `sKkIeF,Cgw .8ҋ-1:{R@EPdO [D+SZ@&;ca O9~2=T"O?l!(\ss>$`O/]tEf*kÂ;lAO O-ؽ4]^fliºJ-(U9丽 + _ȷQd8z=rX#Y:/#oܠf'Pd8YT- ZY;HǵڤװW7Sd8[䄳E.# eNzQ`K,EF"*GǏ0''YQdS%98V98LJx9՚<kbMR4jv^Rm+7[ KnݚoNTڶaDԪOǽ rJєId}3qj/ߣuV'iVl{c'{qsuۖ=l]@Z-kCѝ]IVחNI*Zzg%B&Z+^䟇YMEVgE⾇ 4ޥG\>Msk8c%Jùm6O6A}VV~'{Co_2\ana"dmjYtg"R]4)Υ 2үGn-ԞkVO Vovڛͺ^M7[)W\- rȎsp骔:?4ksi.t9'=SoٰV_FhEVo+;gWEoy(7.z˃KoųѓAV]"ŭ:(Z> +Pܭ@SW{|REۆ_"[кE]٫DEN齹woP*_^c_F( M i+6ڌ+P}Ot7m|y}ħF_M."+Myjw,Guo]2Cw!qQ\% Q#7OhwnAo9B *rtR9Y' tUS6\"k 37ˋ֦m7~P#gk?ǯ e*șOdƫyW_dk6Ҧ"}$Oٿ."+M8z"kt[shE""?b<#YK#WIN} wt<ؤWs\$]|LZ_3"IֲʽNI8_Î5eyfǑ]:"?B +ȳ5kJ9䜽$ICYrijY͔nn.B} ?uX5X3;/MPٚ`VH/ mrIMʄEgwO'!RoTZAYʾ&xyIfºCey%~mޱdO5{|EVhmԗ_KӌEVnvqօھ "鏊b_6Y\iQkBOZQy6b\ZʢʥXLMiߍua6/r[d>}&u+nYHUcD8,]1 WjE ܴq0ya"+2AWI8͋bcO8E>M's (2A2~mY [ Eذw Xd"*<=N^dz `- -2'v+I&Vq"d_ޕTSANXdz `̷',2A_Ytر)t}+"d'^KZwas4rޟ?޺ k_JKt=W%@}Y}xA־C$[uQ[T2W-4Z|ES+!9s49~LX7kNUjnu[wnxW`Xڹqۨ#(cu(-?vn`E)ߋsUSOW-1X hq0i>F]LEVъVd>^o&bl"㸟kN[;Zn!i-a$SW<@ w^F9h&tEDo Ci$9l0 ;X8Uz@(rء܏Uz1 y .2'[c]AZw>KuWZwI+S~Tu"+UVnV,b-5톻Y[ɵŽ/I.b5n }3s3{<y]=ʥ~ka/P3RXTsJݴ"+i&.rq>}b|O0eۀ=?JaQhc^_dSv "5=ss_g5J͂7:lӞ._(4C2{8Pa:'!{kN-I7lQȵ~s6f&Wu"ݥygU׀&.M#.??}~jst:L58s)l+xf]ǚ)㓷:~}1r7ي-U5Ut׾ew$׻Cĝտooo$7EKٴNii^;@w/M$>s=+밮GVf ЭY'Z'ep:4^_ ʤ ;\=/F^ȾM,͑ZtDƒ@.Y_/z-.MN^~1sYXiKJ{,ӞKU]N_K7@j}UvmYulqgKd?E~wZxM` ,u8UM}IF7H^՛:|ԯ/-b}V}"Q%Sdͦ_&[ F`tBug N]cM\KYUdij;oWwu 5n_O~uu[ܝsi+y"j߶\Z"K+I˖09Qdid|mY1?;L쿍ԭ)c4kmqw?f"7)*E&i//tW&EX\"[b E> Z5׳*ztJt9}~w;_S=}SenS}zeg㿮]dvq.O:^)ΐ",V9/$n~DIڧno(Wi"OJ鷷7G{ ܦy3SE ,5b |'l3A[^g9p-O# ))2Zdz1E90jY_{Zs/칯ϑ-&^ŵV)r@N}58o ֊GjQ(quW=pJhyưi,x~T^|Z!M *LWεaʭYZ }+Ui=~ƧCvݝ$q*{"wXAYdꍻ'ָv| s,W+Qbk5GʐW` E:iϭꙞ"Gy\o"Yx2R""ԅ0/gO_=W]7]IxB{q{wQQ0ԟFsôQ(oqinşa}iIrMzEY"0LM9Vj~fYZuso2v[\r`U289z\~1s˾^{?Eߓ>2S?j=YcGj^+k\{+̭> z5ߤ4"IeYQbNH a+ rqQfM#+ 8<{Z7>YO <|de'p|0f{%H_5/TJ s蚥:/svkVՋS/Vo ˩z']cow?s\k!l),rx wq9둯c^"wV s |JD]𝵳Nk:akA]m2BT6p[D:|JP ǟ${ ȅ~;~ǎe,rWEq"PdI"ߓ9$PdI"m[RyCkqi(2$g_ͮ\X"Hry"9l!8LE//rL_c*.=.ER61=~PXJ "b# MNj,H<E_>#=mK 2̟Ь"cPd$4f?K+$_;tic[8ҋ|K`a8ޯC[eL8c ݪE\f SAN]"W 9&8yr)"9ݔк?DEO} ?Ep)$>U"O$BO7$aBO%M)'_2Mx5`jMvûP#IJjA\ys= Ǐ\"E+筦[c׭weSF,6Ȏz;!U//䃠Ș ɩc BzA޷k{śV뺋R e[=fQblGEJLx߆k''^긾Ol<_\W' 8E.9ea!e2sWIv*覷WeB\q,FJIr^ nWmPa ٽsdQvOjoE]͛ቦՓ0WFS}FZ?ƚd#&"7s}a(cMue_*yLƶ9[U f=~/u0]E~4iʤU*T9'n[{D}ÀCUV﵏qn>lS*h;DB[GLgeV8Wf\oqx[_ȡtnk-ch/PwE~RcunVc[?(Ŧ[׫ Sb_kH>M`"̵lgCohWdc7 ɆMNSߎkz%7Y"#vI^٠W)-^I؎55JopuCUot: y5=~d箭EjW82EhOR9`c[Rr| zϮ"kSQg{?nnd8l[ ,(Es_wٚ3VΡ Μ1CAnO/"޳7 3ԕq'yy~tvVTVrR'Vs-V >3I^51֓Ægm?̶q3>U]o3Vܲ˞ΑURrB{[s .T|52>{ۛ^]>^"kj%=cN_dvK>ƚM;O/ci;DZKc=,r?1θcQk9&EVc,?]kZecEO^|<yRNXdC@}4/ÔuS=EΈs1wQsGAp<ӱ%X1,҉y2YZd kr7@z:K jbd"~!Lzn#@P^XpJ5B@vaO i1dz k(sN$s [[uS(2lAoSb y 6Vq P z PdSe؎>`A`;FQT/ 67d&ڌ$bEW{0'MT"dX !46!r$@>&;t TEdu2uEL^F`WSdXCȭ "@vBSd,2 ~2ÊCKJAJA?ޫU^|T[(<m\΋G2 ṽ. ;`ĭe#`xJAJAJAJAMT8/%tEXtdate:create2013-03-31T17:10:45+01:00R%tEXtdate:modify2013-03-31T17:10:45+01:00#xYIENDB`xflr5-6.09-06/doc/latex/figures/img-33.png000644 001750 000144 00000013310 12246405674 021331 0ustar00techwinderusers000000 000000 PNG  IHDR.pPLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712Hs^IDATx^ ܬ枹dR a ﱅ/)BX䁡_aJ #>̨.5:qI1{"uõ bl \"1S֡V*luӲl4!CU Tcw%vP\gCs:T]Y\{. V}ֺfw9cu:w9X.̅rawy´~Z٧x}9!NfPp !<JMg5w-:0]!02͚# ᩸0tOE~bi-kRj9aj]Z79H w)0'Pz"gC TO¡?ᙸ~S^dS K[x#ogP\`<λ"kW9-]CK_VlC\ɸ^"E Xfh^3.jPem!<`B!Ĵݶ*3z}Vs+ w1i]cC 3 "4~W&Mv Gŕx%^ H7v`jGPʊyR%B%\р94(\LCq ]"-1I.U_4M\'`4 \CqfTkX| H0IS.UAIS!(. ¤GT.>CݼuAӁH{=} uB*.ZN]v=wup:+BLʮ' ]:\<]}`袅9ԛGT;ң]ʒhw;G2TQ|iWWWtkWJ hir4E/?~1:043y żh;O  iR`KR{ƵТC˅v}W2> ֮C!^P`_tաfMdR1 Chʡz-j*FnO=\M` ל"\.mu JN609MBz9I1\}|2$ k7cq_4xZ9\r$GzWjK[4Cڥ{qШAV9Vs]LE΀+ѯGpJsޡb^e\]pTxwu/0z3؝fJ4<0 |dͥopnvYwC5vPeC; xh3YpA^y\ai=.׃BPwzFB\Y25eU^Z&nXxuO|; 'ˑ+݂yJe!j?_2Έ|׀0, /;r3-3xO` Ǵ?2 ծ445\S).+=s{6P޵j%>h#^*^8rkmPruI6w.X^r[kb`֩#ΖJJW'Rr_"U,6” Jiݟ0Dq&+^t 5WdtHUFzo쇄҂S\o1,/&XJ'-LҼbd"^`JܴQINm}^L-F5r\w-*.)cfhi<ǻZ\LB{+75 p%D3*5fsJ$u%QxӮě]]5N oB{+OWmz!p~0Y2D<$+A ŠZ{Nܣ5W+c J\A d]`bo 4]Rߐ|dW1JڗtqNX~apJG}(fTPtD=Z1>C؊p>u9Wڥ a)..Z̸ xI̐20=a)ErWrK|0.Jdn"0{"My gqChpeu_=vuTd,DidV3PvQH1z-빱yމG@E&O$-3qhW9-]jFb|W-Q`Rv ϧ׮tn.J#r]7+ɀyp09(;<"!|Wi|Y̻H膌afD58~Pr\.\qY5Pp *m/]]v\R7-imܴ\$Q퐉+Y.R%ƐD+0ۘC5 [mK|VA:vE^'wQxNݸ4/1ZݷL a?.,q! t[߅vkCFQV^wi$Q퐩Wr\A_I^rh xZ:pArEZ%qՁ6zﵶLlh߽dsb^b ˏ7b*SB0{&5 БaC1MռtnyώE57ծ̓SB4k SF* 8.t @/lH)"O Wv{{ )v)=Bt>C 騭%\2BPI\>@w|`HW&=]@N[1YB,LEcA=~9t)r\>#kDɵ UZW]de w,OZZOYcN򶙅Fko -a{0MPqCP#-\ށgtOu(.#A4^ 7@hN6뒾jI嵰#\a˵cp[yCp#g\Iڵk.Ш"V4К׿xyOB\IVtͫ}dZ+auua\u=+B{eǰvega\KNeW\i>տ19&5EF.qa5͉sл9wF~LBW=`!複r|B"N/.T8PO{2KpY`b A_̼+,'o1uIp t.qa}8po{I {`xJNǥZX>Ս'1, ӄJEl'>0%.=69]v]gggsZfwCQŰI:7zk͸9v~w;ލzn[LdZG {vs:Ӷߟ?Ƕ8Z ;W~Tˊ9.oֶLձ#-+s%C#+߼+l.,r.upa*•cY:f vv]`+ ;Wu?J u0ʹV,PDxb\98W<_i&u>." V 8.$ Uxd 'f+k1s\Ldz2jb&ͻӓYk\qUq#P.NZu}ÏK (#i&vcry VAp}KˮVp-5GEC\DQ22QsT$8 L .).+Cp-5GEC\DQ22QsT$8Q5WIENDB`xflr5-6.09-06/doc/latex/figures/img-21.png000644 001750 000144 00000360417 12246405674 021343 0ustar00techwinderusers000000 000000 PNG  IHDRa ~gAMA aIDATx^$Wuk'mޕV9$$h0Lr &o``mm @A,&m9NTnU5=Q_}tW~]]s=; 3@> 3@l|g |g 6^># 3@> 3@r{~3a40:TgPP>g 99Dȯ|!BΗ3p$@&@>9D8C~3Cg I"!#ar07||!‘8"@> L !  3CI93@_ !g`g 9DgH"L10|rp$:g 5@>>9D!B>G ao 3C#!9Dȯ|!B8f ~sg " !!B~ 3@r09Dc>`> Hu@k |&}rC|!¤g GBxȯ|r_ 303C"3p$@&@>9D8C~3Cg I"imo/|49DOyrpBHT@ٿsI;9D83pf Ak$DH>u@!|&}rpA@vhFϧ J9Lqrqg ᐀Xn#tId='B$ !]/3|2@&DhKd YPHkej+2߭!Bg@>-f "4# \M@(`2NH=,SxذS&CI||pg  H爫FX- R!{rdiv@;c 3vr09%ZvfJ,(cE=g2@g`3CB +2=˧d2 1a\ӕ@>Yf Bz;Syt_-Bu12HFǸ%H¥[3&Y#o"yi83CN lOS9;:lzq?:>U`ȸs++[!="'*-|@ˆ~k  @b dwC!)4͙xH DٗX%EC#+?`>{r@,PĹz3.ա':ɴx2E#7H(ة"g>~>G $܊s"q\~0!hd";U2X^?[)ow["q񯠅 #<'$C%cx@3 r:2])&g-VB efID,7EyS7Myӵo91̴M^jQ`p0GbHN(v?o>@Fp 3'T[mdIT$UOaIw sw6@cQR6?xMvhih +X6" 4 'CnQ 1B8730R9D&b$w@®d:K:/ `LT6J*CMw\e(~gF8O?$f6l飀 bYˈޭOC'·|;nhg&Oh *>h3+u/UE=s3p O$5= haQ)`C By iK*z6^b6d6yFŘ`Hޗs`ܠ1AF2hC:8g mň'(DOCho`\>$&rlߚKs% ;|%K0 A ˕RyOQS4xx؁ƱΦF,V+A k>PNAy]#%-30Y@y"BBl Sk(8@;l ! h8&87=4@\Og({򞭼l<؇=8]$s7x QD`FvxC6IODbe_gBzD&o!&Rkl \dr \dW³ m h{򞯼({V@c ')a]6|FTsXa}" ?| 35"QVP͋qr60 dcBd!L@vh(Xy/I*l/7(ef{~_7F`3Kp #1UC9| Hd4y$t(w#BD,^ob|gG(3c>~ H1Z\jE: )5, \VkGcyy'KlZ?lp'Eɐ0?>A2ptp{:> 3ZƑI" t'8@AU~o4T(D =2" $)@*gA)8?␸L\(!x·gbڵ#"!MZڅIX 8u,%Y*:pb(Ȋb "/g !H(4 0аOP1z@N8'w)ާy7#gk^b8NadZZ@v\m1M|23K9J!!xOO)I, O2:!)l#"aZ>;PYpmKdo;x[C[4bl jSZeN(FϤA:w@lf5/TMN' WA}HyVG~q@o`"h23'"5hP_P @0d, $_@ntP'  h(IMyRާY}9@<ٍ9fc)QH8CN~ >cU=iyx"_\~ $g 1;@?UfDy3IeL${p"JNA\Dh tNAtO7Q*+&? X;'<>`4:  P*ᅯ}Qy/++<%*|lQfgQ`HCyٍKtOȳ0?DarG|8X2Hv~C|`E0QXfؗ:AJ k_">8Qj |H"==>rVd@ XY `>i4! Sהw򾡼o*ol YS2q#EXnR|hi!ˤ7ۧٗef.S4QfAh &(AB@jD݄P oAe:}"1kwVf3@@P pownRʻEy*ﶆof,hg97 9X*$al^p*C.<'Xn/Za⺷ÞE.buc#J); []6*<`q`'(Yy$RD PÌ*5p M@U M@ ~bqfhCyw1w9~^ݣwSL)~gƈ~yA#0R`RI~THr,|=Y:QB& FH`¸ c W,{, >|KI5өY Yh"Kh~ I+@FmmhmɄ4>A , KD8} }An)Oyy{l<>ָAbA `xK L#sut!a'S}a{B+=Ut*QlMd9b|]dS.ĒdO A(-s2ZD־FʃpX(#{IhS@zAj*>dTA2d` Z^@6<v88`}Zߠh&Ё_6 lm~=Gͱ T-TߠodX؅+@ukfGE 0`6Hܼ:A^é;"<NQȩr @$A:S#]p iń|O4%b3`?(FY"K[2 ((w …%Q%1őha?;E`#EDDMϐP0ad Tݍ4 ̶(X%ѶTylɓ ܠ|$)8 ?0C*|b|,̫O1Oh>硊rp~5=agEb|*b,ޏ F10kd }P1S%@Gj\]pL͞H1Ƀ4~7JhT{1.ڄ  HBA`N!Gd@H ˔'f[n_ѶRy ϳ;7}%*$I\]V.m2LE侥_;S"6 H,2@,oD:[`*ɶZykm9>nG^l ) D0A քb 7T Ws u袄E~g`?a2 "/ma>M >h^qv٘s%U@oiȃ24\3q$hf@Ai  58@( @R,X4 P V̦ݠlmضy؇CkQod$9an7&e(&QnTz"_J~JO8hз[ # |/, U6gcDž)V7D<8;j` O CFف$ڣQ ,aDS3P O$`I " ÷*mʓmvMqA0 P1pN(3yF YX-[srĉF'=f \?Dt}OR 2C5SgHdMA쫊(!f3~HM#!lق\DG|`=ËfEQzAc—G2rhMf۝%5_ $@u!8![ p@24vEn퉶c0.s0 J*d e&;W_0ᐺO:y"̀Фu+` uc%w\=V'Y7i"lKB}φ䅘;ŔR ʅMSYQe\e-XktAIAcCfA, ;lGsH)Y6p V1p JC6 IJbK},m_ *O! GۨF! halzB  %bF MKc2":E~&G BF6!c6&N}/ܑ!ύ"/\$ı-DhѲG{6p*R+ >@(bXcm>83nHo1#, 75 :NfdV0]H9z{t^f.8 s u8@Bxn pblƢ@6 yJR;>o^}hZrpOw( 6Aߗ~YS[3n(e;rYn qU:l3Qxn!>[#ʌC$)[@Ek, KS2 6zH@ $ ` lX¿>\@A^5jc&A=܃Nc97ΜOGB&æPҞ\12g/"?#r&iW r mufow'-FHᙃ:N1Mô >dno򃏀8'GӜ`n,QϡR,EdIY^7㳆okU؜́'&"p"fO , _T5nUGU;*]~U AW%*MGB':A> aC%ሌL:3mWΓZD"|, Z,qQkrR rAo/RS"}bn)Q;\n:[KL9J'X)@$yf!D3B)X Q#a, b $0h9"¿l,[*mme^*(/BlU ƂѠkDͅ:pKwЯ27< ՇJ!A% a3ᛁQWvY{HC}/621I1D%@2'>2[L?"P ĹZGFxJ\ g$\HȑŸ)i@ry)3,6iu2 Eh1Cw| D<ݡp"5 ARhr BQJl ' ~ "jDijmކfAf}r`P jEVՊ(P %0FύJ>ΪF h<^ؚDA8O9X3Cb|vCAxC}S~fm?Akax7 >8tf2% z|G^j)Jc8彠@iDRNrᣑ["Di,#&2<@8Qsv|| jDPC@.2Ed@ @H'R^;" !^{QBVD$!"趋\8;% T1 YvhO:3Ar/mN5֔0/Pܘ*>%ҧQJr.D V b|pcd>qL$%>RaE0@.2Z! j K$ODծj1jDZjqjI^cv{β!i(hBP+(Tݕjw]vU5JI=hCwISN YtC@?bjÕE5Z}bPHǤRe QBH\A$N ͕MrA8>I5^\h)>Э&Jق4+p_8] N| DSDD~,I(l5H X ! "dALpr|tx ?yyxliׇQl“oJ7( PUzJ`4 SDIm1{ 9D8q%#`Ÿm$9[SjAtD 7phߙ>Iq")^|@Q{_ĉP)5H >@ĉ4'L+&ߌfL!n0}8)^q9? >@ Ed JpS2@U,L I HF .&8U?]=C9S>K:[X'OijnSecUF($)8s ʽ~V{+r9D bF t3ߏ%WG8`3P̮Ť֥R"0#rpM+^I1f4 MJ2ƕ8Q Iq#> (3@Hҹyh' >TԪ+aY._1oR('q26||Zjc"ATN5BB@H@b<` Q+S]^pEj yU`qO #'DR_W-@FzFANA|!wCy BxAC;8,-O%/B7C]&Z۾"[,D3 pJ$A| zWg?*xF( Z9#7&¯@(D)k̂(R` T.X|&|@Bњ@#S0lD*r`k`5ᜐOෘ"bR2||zW cUh`!pσxSU2cXm:ƞ}d RS頡/);z6،Cow bn\5~AvooH17NКH%H>0eA I>7J?HqN/>0 L8ZHقQۥ"KAL  1S0<$}T`Q7 Ȁ< [E8 Ts,P\"r r᧨|zc`30)`\1Cg0BAjRgJt)*EZGc:me6U_RD "D0A  >ge}lByo3z)n'S ōR`v5:4"K(48E& l*a2@H" @܁f5@R ꗨ$@v'@ uUgzc_\u;;X708"c|81BR8-(%J%PiF0hhsV9D8V~{bQhb㒳 !uUn?!se憋ߪ䄶^ʘ_H.PJ BODDHZ! D@?@)k1Cc~:'j}8B+ec ,m 4 \'d BAT D` OX@̆AJmsW b?bS7X/Uy5?y%F^7Xn A@>#  = )P}*.δ{@a|5ivP-r0PBw?,f tAq,xg3ϒSȎK%OU)ͰakaW*RNG`kr U"@Q\|`මp_ )~i;_@[OzSK($h;ɪEL A,pN%hQG@f Lz|U1@ /R7 x%귿~#ԯ^~ WJz9Ͽ720%Qv%N=~H!]8A`H |7-zݬoDMxxA[ ^mB,^GD\ +Gpr zTT14/X yA7b~`@1n2f Rhk*Eg@6! {$ eC&ԍA_,/WxY4 xkՏHT]DZ~':y^m,n`ia`88X{LHGzFhArPk?J!-چض;Ėnx,:НZ=˦61ힽ3O:#7:Z~%;'V$ѠO,)G0t|T?F/7?i "m6s6HjiNDg@ʟlpIy-'p?gWJ]/85ǯU?#~S {oTe3T4> n!b~ɁԂdꁂ I='%&eAJD  JuD 9D84W~Vubq75 mwxbEБiOQFh)|~;b2G R~THBhQ&e BCFU??xD7[eֲ;DyU"}  @)a#[ڀ-h|YaB666w >` OT30nb@S |My[ߪb?R_kVN< ܐ !+NUR)"`DzEPK'K?FKM&O9D8bX~2iRAjhh}'/8W>xg6Oec(J1 9kP!4SIz N.>DC?@[8zUOQ3w^g6ʘ#_ݙ 5GCx&bDI lL(XZ|P OڠWUUY"1YhiPǹ@ ~mh4 #{L`}j D8w >._V>!ݸ W&;N8A(r/vhtd|>[ wk_"D uE-4>Rc#9{^;o:MQtJ'L DZ ѓI6 LiՈrӄKP͈RD uO߯>x̓n/< 4pXP ?b{š^ADY:5CÜϏܿ(!H$Ocg 8hbDԓ2ű#Xʞ{ m;&*?!y!$9Ikk zfE%'P8-jmeoo+[_ݼQ*dmn9pAlDJpP@z+F́_ğ&Yg@b%Kj0fy$M(Ȧ 05bCZm 9C|? D`@0P@p @p>>!X}_>>Q<8.hvX!d%1$A 쉣I3 !J%%isoJOuC8um-nDcoY }hu,<7:9tAҕuݓ)tL YC (-  X N0,Y gm6w >@3mفkDf,y@j=*F@N F>1|Ոa("m X26`(6X]ABm`aF}ZX&I‏E』>cۇ>>I>oϱQ(ٌLv@f,Q.k T2 F3YA)Dv>d |SHAMR(j1RmM+w/ @|X}>8wORiO~Fg?~Np,x3@`B,h80 @"G4 ),@ *X6"O!Qo%"k&Ο[*,¤Oi>Tp} K@Z0"mUۏ+X_oq"gJ5*~tSѹy(@6_̇X ßiPH-(_|->lfL2 7\qoLՑYc)ՌQG>e)`h(kU"ZYS@$6ϒ6 #@(N, pO8@8=TORϫ/VXI^eO 4 8 MX'eOHPI (XJ1$nB@5)@m>r 9D8,I#>]*2f4P#sMhS[w-0K#c7p`OQ.]a+ R&Zd4"QtKTy%8GWW?0\@( Dv@AYR\++cS+#+C3sj{<~|@7cd4bu> rB _aTTձdW_Y5進G)>Pph%\YŗK!ckY,7C z@vGZ0z C$Q '`˟4_6`G[&(i\bƔFF8VJ塙Y9=GWwͭ{lsoYw;J(:@шEgԈ^,h Ǐw+Dg*x)yH BgZ Z9P/DWD r >-"| %zOKSJcZ8 >0Iiވ9OD> ֙1EnzF+}c)ccSK#KC3f]uLeWX|Rm)ugk trr$ >D⢈ >+ >@vϱ|;ҞEHpmIhbq O@'\q8/VgUozUzԟq, /;s1XC8@=D'@%h(J JK5O>J!g5 `\zlavXdmA1/i~S#>~+v1ư1 AO:^I 0B 3^ ,^ Y!/ϟ0?ERGqN|̓\ ۽#1Gj=#Ҕѩ#džfUSsty1V_zbuM6V[wFm͙Be[ eqPHقxfDk`)ڠ6hwC'Z!  z8\:?H5?Q^Ul˟?V#16 p xN BQH@ņx+!M(!؇TPWE%{z&_9Y,g̀Ñ5X]mcag%.I4LU#"Ԉ: 2{֨&m4Ɂ " dg5Pe}r]Ob|OgK X$tK:Sއ")@Нc̑o6aOD@~C0wWKSFF O9o=GvSq\i'7\xJeiugTלY[}vmeK/ Gia| DY\_-yOCbw(RDrqB-m@&f `# ̳ x58z~^3?W _J8yٍ9Jb?z%Zc#}RV%//Sra|πmClbod׵7 :R)k0:*Ψ9sϯ-". \7j| (I8 s8%{O5HYD;X/U@& pK^[U/AFbݬ^;B6OU1p Ha?} tLTph4 >, CD&(2/R">;кGW1)׎CI|I{}%O&β >^mwkGL.F)}Q7vFoTSYx3R\qy@d%` m3 'H~yF/J3.Q#8(J %G[`%0"}2]ۂAמO7a?:!,C!-<&*>..I.\?zyȕ1Sܨ񁼣I.TIIEH]́lN œ> H&#*O+DtF0 #{Dԋ"[ nUgM=v\;wܥͱ1";#v9ZD Rݫc~0\C"Lp΀a^{o&?=c+,0"yH3o ; f?pՈ? ՈsӪڳ:/]vъOZebO޿!BzB%BeV:eH쓱/J A:R 'r $Q-~ Յ)ۈ \N n }~ZZǪ@eu徍-% Bα=cSN26JGGƙvϻL;GհX~*8LlLl!奎t>U*IXhp .Ȁ}$US>q`lTc\!p " NOAwHE %*3֊(E\.r6>;8RAeF1@ bjDF~{cP|Ԉ~;F<ѕ -hK.lWl};|W ҝ"`?0W(,6"><:8qGp)Tǘm-d.5ORH#)"#6Ea_Y5 uCusP/uϫvϯ,,.+(*-m(o66e=@C#fVE`Y`с-ĿSzZ|b@D.pLt %& I.P4H(:F)bd+E 8I| D =7m:Wp>''(%(+k% DglLHYAbRO}ω0DH3t?Egl~B5"4 iFMN͒N&WhՈܰU#R8@p8xբK-|Wn]>c}W3D7i#49o- I|@ >е'FS~: bx 6'"rxo8]h pPT{Tz.)VV7M2:e#SF ӠaZixzuh9( _pH~idL.&OiD=EԈ2 <ڀHEvXg:nq] +pC8 NSEDIށAK5BE3%HƁWd&܊{? AǵsdG[,콲C=۫D'Zv3u9捈O`-U5l~FᄎQN Ʒ@05?<5AF,QP=-̡7/rE4 WdlV1|>'agNuwu_Px/Ԋ j )U޵M-cC |0upDヱ镡5 GX| 0rAl&Dv`o4<{V@ALy`5DnF@"x;uLr80N5vec7gdA$NS̓2F;BhE SMh1%yoChY۳(ۆoϿ FteګvՈP#>eCO3/@= 'DNWA}_+;{fH3˵L~A0B. /TR(I!8FIbrIbz$U %Z* =kU;KHƦ ҽ eTbW[/VuOL/X/X| rM.`; l{$B,Ofd<p%>F}fڗ9Wv5=r@-'I9i$?ݮ  9D8Dm@WQv|K z:8ᦧZ{35uoĺM޻^*8jK,jĭ{=v|.0ǃC5\ew 4$ZHZ5y @I(-`.,/8'6fېn7PFwH"Ƥ|DM ż1̤H>2?f Nrpvb>"Ae_ 2@ԌLH3Flf15b7Ck48XTW#>y|FUW#G',)Qhsç_546Hث!O  ;7;!!$>*G" A2JeT!${nS(K!bWG;GVU~a_\_+n 1JK14J)+a#A`CA !>8_-`109N[>1!SA8QkD:_ % &HQaH> $KȗH?cʃ5F~$ @;)tG"d=AHqDx`Ϋmuǔ"trp$Yb/5ڋYpm{`[dt^3qo\EH<p*4#jD:93Ffވq<ިF3{VH^dghDG5;MvY59 = MeQ BjhdF Ai@~AN>`;}T8"K!H;H]}Ek5H("A(fh$242OƼ0]0hp~l;kv(.vt-ptm }:>9*=ݱ߈4.yptZNT/UΈW?Q:7 m?U u0<(tbQz҇ɶo&Co0 >@2| >FՌ%H-p\X _Q=q WUc;[ Q>H:%FJ"9D>4qiTz@c)QhzZwߣA=Ciq΀Bg9rh/:84_ةI16FujT;6aA&FjgN تK;wx(O\Xp"eABf9Bm@_S`CX @ȕ߂D}I1v6oפ_BGK!\b\ Җ * 6Q&JFL|@0?1Zp E $ ȀÛ ,,(PSE6_b@BtWؿh (3!a "ReOf++Jz^E rKJ@l8AI$xV!8hFlakUҝSjتڏ(~wab89b͌:nnv(O2X&5 d|><lb`ǚCA-_ޮ)J :<(+O5Y a~H!xkٌGu ]CAa/bE[O$}dՈQF-Fmf P]1Xϳ DB-(V eK( `E*@9!b']80"J#&J` (_xNNav`h`Ҟ uhchHM:ncވI5⏆h(jco^?@:Fdª{Q{1$C}iڻC!bk4(嬺 @(("APZ),)ɭ|t@4$R7;B- )opxHU ?{!,%([d,y@rZ}"J& Yw&#% >`OdI2DA 'IZ9%H > ĕȵ7R`d"ڴDHc \  TSUOU<@h8"ҟ |$/ HSqI7'3W-apKE(}b*,8X#  lm03T @<5QOxjؠwNH:Jfc%u`0'RR1ë1;ԒĒ')[%C#>r袁f1>1t#&.*l{mɃGpCI8![i;5qrS5żHQJ1;Tʡ{Qs,>Ft|';f7v2JJH` z1"z#Yhgu./uGGQ!$)mPB!xPݪJf%Q2 .y@kS,yZ;m>tn䒲du> lF/0>@ڀ3'KآD \ᡀ{@&GlA !O zj D6^,J|FzEB}C$l%pV(&._Ĝ!@PJgDB"{E,T7 md&;m1{xvK5H.Uza,=\]뎃1Ӯ}qV#ujy#Z#FU#"6RF-9*rn\ܙOV&"wjz(yT&tZ!^HOAPDI7w@hS |.Џ\ RBWEwf-B ABXt ܮB%]D|@YxP/p 5VHql@O?`4k`-7(G’ORVbE*+H j>i(Xz[0puR Cz ^OnO2H;^w%"p1##%0 $\@Qh5S;P6 8O҂ٴwg!㝱#lXm=Ao;T6voo;81;8fEYHeHDd{qNFjD#5ѿEozҝt7i(cވqKF$w*Vn}ŏc~Aiw!BXj!#>H m!BJtnr5TVI1HwN1B 5"Zb}Ni 4ݲweoڋw8k4(Ya!6"& !:W{$BC ?`(^HPY 2ݧE,_@:;_{JF ZRd )aU@0.% ,#*U1.,P;=S=ȃ]v(!jN8\F F +`dO ?E2 ?b!f ;GXޯORLh`/X:5HN=U 5'깦kG4cx#ވ٤{S#r#7 +NtFJ}=}孽" sf8ģn#DONRF vHciզ%XQ(A:J@%b I1_&QTP4*E*v+|T-'Jxfu >U RKTYXvAR ?F$ R>h1j$D5i>@Ղ8Q6@"IFpA7@|@΃vy8a FR@tg>$S[utj>g 퍸SN15"@J\5"+jDΪT+ kpPl-o-ﭬ,,

u_B@ `BB(B!"ޙdH;Y/ t!&E0^IkU)y%BGZtm [ZqW{og3R.U?[@h]`/DMb(ATJy`-"ĕH|@f|@|ys86 @4 6;Y4RS<& * EO  )Ȁ.,Pkqoz#iƘT#~-cq{S5jDQԈp'ՈMFEHQ ʻzz˛z+zBpHki+X/epfi}RqF o2#GJYD$ n9$2Xa|(vկ~Yy_3^IWotTFʠ&մڳ=l44trG"A .@.D%.ˤ)ϤX$I \pI0$l%P*A'y8@g̰1DfhI|@{fZ=SḰ<hXFmޡ.߯Z`:=NL2KoOP(::0/s0:v`{ij o_N6vkDu'XHHq$ވb#eF?V7M.}_R!85 njDjԼMfIoDnڮ7"Z1n15"KAF,ԂFVT..`w~IWU&zj"~'w t| DI D(!>WbB0>>c~|Aa_XW׺U7V^ϻ}{KsitjUG A tyA;c`OqQ. dy  $R€D W-qg$r|"]jDj` iAb(4J x<^GPI``WWjb }kj{j3'camL!E &\o4PtQ8%HAj y(p͚-̱#C;'G!a3p'7i8EUsh҂RVAD(e?vp/*DҭQ"KwԈҩYJ񸛷սjM0jD1^5|sJwX5"ԯԌS##jDHjD TVTTuW>]{XXXu@+Dg!.ufS!BOr57$JDA:2 Q1B$kH!h/ѾU؎Az8(, %ǫݫ=k*˽}J;Q7uxtȴ4E) Q,/#*EI1H$AJ#E8 >P u ͖,2#{?q+]A !U( l蕽 @uK5+ts`ZzTo@8;@<ؼ#ycP' JZoGt% II7R.l<-xrFuwoY_6"deȺ/{ɵӱwrT$A7/*8fxHdҿWHY;ιow*mM^oľ:5Ax&ވtjވOm 5Fqt;5KXjDJDj -8 "q3EY& #=$L`Z_#c\!*>|@1vZP#O:ҎfKQ.ʮ{<8V\X^\YVYQ]][WX26e]SL62<4DXiB|E *"4j,\H1`!!J4A$n -qP> O|;9Uj"mCT-_.B0v#]aU> w @VI C ~Cu'{O=yzSy@ 6 2Fw0@A M1] {d+nE-* v6jYɣkrpI?O76mcsbitؤ6$ՈjtFGr5gõ"J* 8p5"ވ15bވdcjDbpҩ97"gMuWwWEwB]¯I$SzC A.>z5>%nrVQiͳ4}]!c4]wCG= *=*K}K}JkǦlyt궑i;ohЌ}3}:@SGa2WBEhY5AU!r]8*)Ap%n ;Bkb$HJ @ݵJV.JEB0 v]aRu:ypB~OaP\B]8'" @L *^AH( ra^W٩θCMڽK~.}/U#kdԈM{~Ty&,G}fވNvjFZ*P#WUVo.- A.zsG0wz O@ХyojSl#h WAm-$2BؼTRF!JQ1(ou[~3;ܻܷԿlؔգS׍L82mCw ;8sp̑}J{Dž22Id@=BEY,b)qI. ⢘ ErE)a@KY#*(S뾿Pr待cSNY>:uȴ5M44c̝f7kc{Tu`lrXfI1H#.˲tap%"A@ |>Y"DԈdjo[)TJ=hwu:],kڞ*; `{W p.䁈Ej8 T g@ b9~`o#vn1o}  yQ'J@Wk- " X "h0Ѩ-JېЌxVb^dwn;8:o~MFD\FkKy&Ǽ?2Gtj> cNDH5b+oDQJՈ!8E!+aWpmW=%OZ}&R3zyPl1m1D* hwh@[\ru|@f\L{i+Ҕ!^v>7,]Ap_|pJJrRUcS֌N]?2mP3vf540{t/{s!>,Itg@1 U Y$uQL,'%"QdY,}埬KվrWopOe:].vk;o-[].\oBFJ 6@=@X~naw~]#,>AA'`P80QBkF ]Έ+3 !&T*EtId$SjfuF)c4YuamWέT\׹ѡ;bjDMcML(ijN͎x#rNN=7"R$a]5֝7b]荨ՈTAԈTw? sxOyꓓw)] 8>N},CH^R/2\| c,2TRbM3$tt3?ÎJqiwyweoMؔS*{ ìp_FܗQ!SR /T#W̕bxE%O}mԄ ㈋$.7n%X Aw.b,)@OeoOeOOuWwugwuGwm{XZMcPw뺂5]0:Jf_Fj@?@=[Oko\,XbL`G˼C܌uUtv0n%F"X1.P1'%^E|DGhgVͭuIƐCuwEf mm{o̾W}H+誺7bKU#:{i~֌ [:fde}oSf %BEGnxk~PXť՞)t*mcSvN=2m`x0%3J3zAɿ](cMQ)ҔA=[#b{gm*G a(qI"ׅA\[ E$B9'D @ASC=[u[wukwuKwmsXXm( ڂ Vu+`A6y8[h @KOS?7kbn0#6 pR`@YI%x=F?h Ƒ\% ;"\kE}Zl3qnk@'&ވf-ԈѢRF{O$A^Md ͑A-{I^C;\]|@ OaLd %eekd?#2/4vx!x%ݥ;>Aa_\Y+^I=+[ʽ};KǦ N:224lo+G; l{I$cBA)qA@?il%⢈ =@!HCg %AR>hX[[) ʂ,  u&Q_B1[r B8O<#O~C33 yhBv>Arwv@h[HEA B @HP$ j;`gI)L8-hie}dj9e>;"AuetF35"ވ[ိ1i޼.8xhYW -hK.|Fةy[sd㨒!tYE jDjD1N͡7'y#U#po>{<+c"f~qAFXzS3-9jJ@F > ᤺ AZ7Cl*R*bD+f1y!ra_XRVY]{)4R#c[O 6l8=QTx%A!Q[ ZcFP%QO- K(K[8p{%Q sVg N%8A @0 4E V)"D׃@5ݵUbmE/+K `qW+x+7̂YD_pg Xp'X6)'Kk8Zs  PBz1kB6 J"1N{%eBP J0>XHa`s L)@ͫ42ZsW}eXF!,}9pu(~iqd ADLG{YԈ,ʨmvj Y5bJ3Eq#Fd\oD܊)FlT#D ԈO{_=QOw{o<"t {G^V2йj>tg6QqȀn=fuJkՊ;kݻ=r]t&Mf/wb{B`35g+qbBK1I!b~Q-$5.B Qppţe,].8] ]!!@q[(BA,/֖mI_T+ Ѯ`~uѲDYmd{J>f8Ytfyz\h1oĘtz#6Q#^SsQ17⅏76coѻh 0W,FPDE,$+5b_jވu5RQ#G#jF7,,(ڑyJ5l(ķ `|77LA:b 5tF  JUݨ@Ia}ct=sXG#P\x:W]"d,tfk4&Op ձEpq#?F|NXZPx/Y&jd3F 2ñN15"2Fd1ƂU#Fl,ɮ7"GI5umԈ=kOSo='SN"M&^qm9F@Iqmq@ৠC$cML&R;;̓+ !c@] U#/ ]]}]=]mfޙu_6SFP ^qBfQ(}X8 !C#A>5PLI(@ݏ@=3V5x /,' s!,}:7,=gqvlF$/]L7U3Kujnh}VXoبF|Fbá`.8ବ15"\WbU#jF\ԜBQ=&OW{z^xX%D!3CVȱ !I!BGK!ߪPT1b<*[',/Z柿a&3ic5XFcEQ%)vBME_ETK"0?P-wu.:ښ̂=y`/J€,9^2mv=vy3>h'e% +ZRqF QKF RAn%3 T}laIq>u˹7uIU#*N[F\ԠF 8x4c|vHFG|j(fވp3MՈ/7Af 90)~dmClRIw;>MΘ4ވѩ9捈ө9T#6c4ވQ7c|ތu ii5IԌjD~Ÿq{uҩygoyk7">)UpԈ굞z^ 8x%avgp]z^"-&&brw,.8A ӣGV~8p|jly {O(3텊jmR:>T`tTuܪ&Nm93j<8_NEK|M\<_܃2)>]jGG$ߎkvB ,a'T1 AC8/xS?ȿxr\k'ov@ܓG7rQeJ(imA[ PԔ0R@nC!Q^@xفhYdDt8()n&!Φdb@8 Ɨ;}­潨D_II'qK]hc@Asp9~Siv[wLuiUܙ -B5FfQԈ,XTؼS3*"iH&WԈR) 63VNjD:5hשAԩۚFRFSO?K="O=SWpdO=)X_DxvުYkko"aW轵ك a^MM#7EVh"</ 8jFIqp^XN.hM;Sn 1wOaa&x;Ԑ2Fw0 z; #4c*63HURD@#PB.}#M;[P\<˪},'q ػ 5"4nFjDuN͑7b5Yfވ]sFnY1#>y[]7"5H_iՈՈFd y#K՞zb @S& "e}#;=bLXL3:- R(ݠO ΃rEHYDx^M->Z|?`R\Y0AYy;WyzBէ% ZXێP >x}M<;n}Qp3 S`lGGB Qݘp,W3>R\\8 Yڙ@S7NV;ngm#թi3c]iL#G V݈A{-!P4PJP`4du~p ؀av[ݨ6} ?0Fcp;" &)v%P 8`W%6 4ƌ9&ZeK 8c%j!8eCv3v&C*hک,Lbx;@' 0eA[5ۨFlԜ1qCO{3:5GY#YljQ#R@ ,y[I r/%aZ\Hy{N͏N&:5FdE]oD[R935s @'0K^@jS^agb׫I7?A;JgR /2,Z7E FL];D-Cۣq.gi7VDx,Å']?ze)_|^p (ed0ǠYZeK!\^R\ĉBXOr*,k} 2lz=93A=Խi$-`r?6QVZv @.8  >`'&}@P( v6} KcL:w !y '&g4H ݀tamĞxT' db# +(mxYSrmM b#۰vIζK=F/KfވVR-q&Ո;U#r_E.t]$muQ4KԈ.0LcU 4V㍸F|8:5ވYYo(F|zFRg{ ppN :SN"؁Q@ԘMg8{ۿ-`"S%!*E\+"6Mo~XyTgu&O rA#2S^y[Ky6PSk# K)R :}6 Y5b#* w{9P ȌE>!j0!݀(Ej Zy[ r;|wИN5,5*2"`H,z\ni^}a iM0UϘ&QT4SnqzJ?&v%^Ih9X%FIac0qN#8uBW RPQpbw0^kp2FI(a *1H*b? > D_~ABzU >P3cw2PzVegڜ7P w{GM8 F:AwA~. JH>`5hqPyb7Z6S]]NJuG)WWZ@)Gk!6yugKk|w̎ٳ|4QP#6F{'F4]5l=ݩAz#qwYAJ3FU#Q#BQf1Blh7bF5 ׅ _P#>5Es 0=u|@̉C >}e?<@Z?H RQ-~f% (4]DI/r w K9D:wH+w Oϴn#0EzGkqO=Pk}~i?BGv NQ!E+$Y*mG cSB@j - A(ơ${S1Riv!ਸ6GL )^"ړ 4yB&!V @׃" $~Ä^@u8@p61nvCl@9??$ ]!P/R 'R&a1f6hG!AՉW]98O.@,B)ʲmoM_}f7Cd7P? FdyT#DyFTdQ#{vIwl:%NvV#ވҌQԈ,[(ވzPy%dqEo6!cވW#Ƽcjfی USF Xj:8809!8P=5u5t2s􀉢{i{M',Ĩ}x(Ih*!FNw#O`Lr\z7c/Cxwބo5,2I=bИk(~_Nf{,ؤ;2e ul /v Cf:BfE1B`QRP\1hp-8Nn(YFjSb(մ,Hw6f'O`Aڟ O  gB/>? EvCd@K Hpa;ddCnF!Pd{@N@@ AO1$DR !bqDVdAcL['$Hӕ#|sWZKC,`9,!6 d'!G-#_wF$4DFā1+LFtՈQoEةZixeX,ވoy$FDݬ#jDYN,B!vN4{L념```s$8k#E t_8Z!8Q!l_g{GMd\PDa!dov4&d:8 xx9/`Mۛloiު[K X ai8JoD |(># # jQ!͜K~#'=7s!B!=jC{=O#UhYRyʺ l捽ZUy8? K\5")UQWߒauDEU#J_荈:8hFAL!uQt|Z"q0q^aR D!?EJ 8"%@lKUH&tgiD'@ƃX!efA v>,%/U p\~-[m 'P3fb(պk(^oD)]@qY 8\TF{æ)v!-{/!$iwD|y&aO(uJ*( >! >G $#`OAcLv6MAp@nIMaKtf`L~&E`2*_4MvpB$@?V6bHDrb$TK£fʥ#G?'U9 mmClI]۳o^LޫיfjĘ7 M-xբoā|*em3F򳔀7b[5"K)DdFtVTiP7Ef)UԈgD "8hT#@3)́p4!wE}~PgNrM?<{ۗ;E?Sg 2(5h@@EC,(i"Pp~dr RލQM'7 S^͈U_ɰǨ֟Ve`)J!` K\Thk?>jk)ˡf}td F;E2i2&*ri,jŌåO+=CKwʣPOeiRܩ!(J E8 >6 >>ZddeRNBbڀzݕD&۟4ni#a! @T@Cԋ8|!PhPU,s1JOT q52 !tUQ"TfN9DDݔ?Sp?;fܭcl\5"w׶jDfhX,M81Etj^u .FH8+.YF$!OR쏬$B"AB `~uBeHiؔҐ1Mwv׶u;,0JҁJH $[)qX % 6}{ϛ+C878&!*Sf?~#@p_jY.t6@H/!"rGSC(@|\ NrbX͋?I-eiC,~rJ7 mR"hݶ8g&>BFZcgjHpPFnxOޣ+FlF\إZp`"ފy#rtՈQԈH]5b1fk8ۊ> 7_u? ~ЅJNL󑰒15":"m(4D#y5D7$R8T>T><6mddѡ) 0 Ջxe{Ou[wuKwm踡]*Q0|߸ > /@1(-D)hAYa `Wc@7uY;ҁ@rq>( ]Q`(]qD D>>6e9? "BXq ,I9Dh w چdw9gc&8Bs5FDE7j?T/7,jD Ĥ<8I5}OOS#^%5U# *F$]AȪFLK#8{ǃ.ED!7:N2܅a8xISs7 ވmՈ hrE0ċ?<W7B:!^K\$tccjt/a<|)gZ[/[T4h]CtSȟ"6ֶ p"M*6kdXQFPvH1 =3F O6o=SFwO?OCC6kȮ;n2lKis_yIA[]][],+ (ӱJ$XmMHApngiu Ζ.N(8n? dO\"RMbj"R3XRb[%v<ƣ[!D6N!8!刱}RMUGG;Hc^*&)̇FHZ0N.V\oDiS]5vmT#*)jDtܶSsF|Fhq8Щ5n-80t9u Vk5jēƧF|ֳe\p@ 1Isb"gL4;r?cO&D +qZN#}Gĉ?``/W5SES}I B!Q)Zk7IZ6~qg{O{sTy5eAjK1/$ A>zPoM 2jIYFvO>udS6m/++魬GWWtW-+K n!\"јD1*aR2M'6KAh#ف47O ^`^hQz.JhY"uK$@$k JFj\#%s_ S_1,!w)췻f3`GF)Zo۩ٚACVwkFlxafԈZp0>oDK]5b|Zu:zVjDjDjDWp`ԮΖ%jw8a=_=tj~j'ވ@JXHp 99}8ir!vǘ`=*7̏"tŸ])!bQwG=RBGy:/7ֺV{vTzvWz}å>**@ţeR!+TtUrVg84uG Pe``"АȚ#QD0o*M!l2q)ckKJ+{ˏj(X[XGG D'(*!QVD2IȡO >0?=Hv X`d:kǏyX~cl34X!\22)@>rn$Y)tz!~ &H"agVgcbM ̭uQCpϣ;+b#ᥘCv!0io\Yn$eݟdChՈx##mQh16LF5?JU#h;5S~ȅ8H p{H0DRR+.u/,)/m*o96eAJF׆D T< Dp~OݔQ~#< FALm@[΀i H @ѣXj}m}M}}}}好EG{+{*T=T=X({ykSe](RXH+kd $ 5 "K$@%|eC=`THFYPB?%Ȫ"!nhzJ'X\ퟩJX`Z#3Nyⶖ~Oz#ZZQ#&YSs;5/jćֈq˖6wm3?P﷨klb OVJ-ԈҩYԈYS1&@Ѳ5Y 088,HK$-ۨY E \ĉ:>B'>Y4 I"D+^ ;ed 5#T\&떠p_/W~pgAwQwioyX)Gncdit$DpMn?E'/vpWWA WVTh|PyzwڽEW!+ R%H(UE$d  $` `gy 0 VQ zp+ ],p$*0de1.dY4P!D 8xT?kأG+SDHLkr]%nb R?<8l:>Vri {NlhMd9 ɂ MnjeFԈ- ;5ǼihՈϻjĘ7"9VVGnfl`HrKW#D]oĤ] Q7xCp!/)-d)Ţ%K*@X@|rbmqtjnV{/EϘ fFd=<0ND'{ fH I5>p:! #|1s[3`I_1N|pSP_}gJyGK}My|tʪѩkGmex黆f 7st߬l/c} " B¢vzDd>q Q5duV{sb?)#(-G@Y-"+_"Q=6,k Fk1:!R S3 W*ք[5"j-Q15gǞoTS;5^\W#NS#VɑN(u(沝)1捈7Ś1ZoĄ1^d: 4 > hQa,@X#GXPA(S83zKOXOt =T;5:ԐvΈjZc'vџdK A*jD)U[z[ N1JW(^-Ոܸ#|g>+_KP#>{.;ҩU#ZoDE^GY-vj&ʝMF+J5clFCHԈ1#fS#^,*Q2!FV{! 浓P+M iA!~OWh@S|6B3;-8&ѷ $p_}_AC!//htґiO_94cufmu`woQû}tuNq };DFG~'oS_`GwtYj٥xgC2"D}Y B9a`!B"TGսeY)n2.I (֖b- Q{ BpsWۮW]X Ǎy+AT9&(-5Ƒ\p2??}]f bp$ф]QPLg4$35xCaA@RӯY<{guV_(Dȫb]"H+'r;"!u bbՔh7IԩprՈ4c7CoĹyMۏuIwn:UԈNZC>{,-cjDVAx#Hu;5O5NvԈa3:Fs/"Je ˕і*?5"e,8=,Ɗ)7޷L"XP+"*>N}5DH$<<&N(A(t=;h X/?7j(=#ӤF"!`tA 5B_]X[\_:6eԕ# O_74c-fms{}Ю#;8b;iO !hI¡M Նc ^BS(RPR$"`,ަJJWW+p㺑@H#mA(jeQAW9>K(wu)u=}NQ:槕*NLh, a<{01dq]h @~I8O'?2_7 ?ԍŦ_V> 'fZaM x4!Ad?5O[nF7I[%jD_P#!V۪:0g\jDS#rsՈIoD@T ssa[5bN͡#J\y#"8hF"kQ#b+}` x#fP#$]* !N18B­L}2Q"NxAf"̊ `b*8¤"_E (gxKt "jqLnPm"P_|hgawqoiV!~xơ[gn7k={ 9jhѣt_G Rz[kE*"Dfu/BqLbTRh)7PPzaGCj@ZX+ l([ 4bpY w CL rlM!vMɒbx:$*E <]g,\A[v.7Db D19B(qGج icvZ9~c-T,=@"p+ &W"ۧF2dzWPoq5NƷn}z NͭՈ8\5"Y bqo>ݿN?T!ᆱoĘ-5꭬ȟR'L!74nhFt1?/ࠅFlhhՈH͢E? @馎=́* 8 lG D~K<rdAcBeԈF.Q6)wZtx|P,b_G7eڦp @(B*GqI&*1)m@h(qHEF d8q"$ﻦ/"<ֺV{WzBUcS֎N]?2m-C3ž>;x+I1E@|uՍ48ltwG?~!" Td($ !F!eqW"HG 5BVKDt9lԍ{XsAlaX"%}1BxP\zqFʂ`=u9B#>_=vF J2BD W:@D $:CY&+f~WH1{Q,"Q,Իz72sJmz"_D6@]Nd=+}w{5uSUYW1NFeS#ˆ'FwՈmxFtՈPԈ諸!֡1`7bNPԈz-.jD+88jD}x|7b[5vya#Mj ƾ sJ>|ЖBHJ3C$Ll$*"qS gNJ$9WAq-g{nhiGEq\z,vj+=*k}JŲG!*ţwyǶPrRu)  ;mRA"POA20KR)dBzU!@!аRUܤN6N= Dn%Sm2^⩅ziQL2,Q`(R z~8 M*3p4=\ZǚdZ#hyDHƎ$.r 3䇴uD 1#z7CF{mc{" @4DC3jĴB8Rrު1IGӼujnFǪ]oD0,{a -* Tns7jF-D)= T5P%$@8?6)XN3ToDr X(l0ƣF1,H|TdRxC{1 AYKa!B}? ZCمH{Be@L1u> ;mT$(*XaO.3$!?x=HdpS\r0k?b.CUFX׃Ќ#I몺S1ա&Zr$&lp0n87CH15xjHp}MۥXco~m[Nk?Cսq[~*ވjD2Т15bAQY5"Ѧj=}坽孽 [l3jDcl2]D3QY쏒jDl?jFw T-8@RПSsjDn\jD]A!S)c8A" WIƸJh/ň1j| ^IB!Xў2Lt^*r3ШFծ Q#7jD}  P_mMnhQd޵RՈ"80jDO=+8N tGr2 +O:'4 {JwXQi Mcx E o̧NQDt*{VqegȀ ZW6Bؾyv¾-' m:yx㩣O/=sc8ZEqD ܑ 3rBB*,{9`j)""͝P$7R)TטBB&*~X҉F@xI@J@~k\nk@cr zg y3"2n8Lȴt,Z i 3`8"G?aw0v{nc'$P>C\Z$Ik@(`N5(Y|+M!<~ {F D.HBOW6WjÝEpn3}sE%fsxPd\oDF4gѩ[4iވfdtjy#Ҍ&ީ7".J\5tjFX-z#fԈD`go_:};5b')KEp ́ E bވ0!GHU#AziԈ/q ɺvil@Qz,ƅz2 AS1tcyi}5$"AHߧH4AH!hl" 3x @u~**E:6M44sӾٛe1[w};{{72ug 9sdc+-/?iZſT_pD@ 0UD=IS7,Y ._\(xipW !J ŽQƂ~5 D1" =Ӷ EVH<!ϯx4>ffQ6S7 w'z%S!0\??·5Dzg>X.R,Rar>=cg|ډtr$"%;V{y&?\ԈuEjD}9I 7S#~otu37{ͮoćҼYpJU#rˊ]oDʬcUv 6VtU)UjD;{~>\W#n#FDY~ՈajD}ԈS0|a݉$'V/EɁjď)줇cv[vOݕ%ա9&" c!~\\1#>Wmt>=Q?`d65 GE/6 ov(w:HhI D0܊_+[-T"Dton*Ofo{q܎m'|򮍧Y39kh#+[~~i?AkqDpc<4#vI n{Wg<]b#O县~S377kdՈ/3}k jFBf]?0SsLQ5"1捈U5U٢F#f-3{#EQ<@*~?b#t"cjDxG7FT!FDp0.8зkT4DtD zQr ܬRHp`;57x#r;껌ࠥN:tNUitUYVyCoy[/zXLDWj"HlI$YhvGA*+"D18*j;H0"g~B4??4pU<en=ǔ\yQ-ޭmcS18kQ; Nس佛NXڳ:gpyÏ?Ғ+T}R#ૈVQ<&9 dpDt!:$ m| x@ǂ'- .??ev]F)e7"4@", n0N?B ^42`` B)&#ZX ?T"6>%:AT KwFl# i Ţ.j 5^P=9۫ р1d(Tt%EC "~P5 mwHFqft|{owŶoz~ꝚU#AVe1b‚ǤMHyhH)UhF?!7bԎB^TMĊ\~Q"|Qyo)O3؊LJHy+=+};JSw4ks{dھp=t"К n69>~oٽ!C}wy-!(8pX7"h)s( <#3~<8g{cnF,NYrpK)U,5)X5"w!DQ@V)Bcjφ 34TJ),4J@cdO"¾~ 6C w,Jݣ&b'%)w`x|DyRy Dw.M3:}̽hp>p<ÛOp3G ҋ*/.5bRMUAe3xD//Y_$EKb j[=X1RZaS"l5+3A BOR,# BlBtr(BUB0xzA BFX.! %s&/q\lߧSgXS՞כDhi) FƦ?y@`e`x`8m"qbjDPj145"9Ɋ:5R5"ވ4ctՈ{#F*H=6 XbՈtjnFW:5Ԉ8ymE*PۑV' " b#c}NJU#m2ܡ۩͒S0RQg aBo RԈ$AjďF ҨF4FWBp+I!.֏Y(o69ž{owoy4ڋ1#;v6VZ +έ.!hWFnT_EH9G Pd+`j/vΚknv<aOmξ4 B֭/뒁 D&X?6}e챤RjL -)؜Y[e -a^~B! B}FQ)viMQ?`ICr iuiW=ܒ@LT {EK^6Ը?CE|rptL)jD bjėN͈(Œ,o1F4X}u7O!8hP#|ɚm|#던LޓۑU#U[TvSנF)7b7ytDGV^n;17"L!|!aS!aLB(8R45:FpeՈ5wjDpbx!A4u&$A0 /#q?L X?SW)wDHQZlGExJ-UH+L ֊ǣx nRʣqxV+ov9¾Z`#F=wlqm_zᓃW(wAUr<k3k |TPhBX_Jaq" ڹkg#aGݵ4DNG[Fa@m"6k D@[/ D@DQ!|1SԿ cP|L @2ĦE"d2.2|^>H\(*4%\ [.}oěn,mzg0OGݣI4U)H;kW cC@1hRH$Fr#AF,WࠔF7TwRx._I2^ $Scפ'*pr Ǟfhp Сo~]4t%F%P$AoRdI)mW>u_hM( pzn=gw.o;..Pe7ORH(be(#& s)w CuU!E E@"Itgv'#r?oF"1519\;;F"|HDeE0m"Ԛ T }*l/B"kW %"k&a4wA24V`DЗQW"+Yov?@oBwo900ޱ {TOjyظW.ɗx#+ӈ_axEb4A#@EN1o4 64 z#B#Ҍ1hhD8iĴR=DHQFdv{"B8 MVS]:FD1ԔF,҈iDLkVǪLy Dw$y/Vg R 2fSEWu谇B,b, $)g DxODI?RZ"D=D3S23]GdXw`x~aӅ :A냥/ 8X/ 4HejM[)"B"P7HJeC`7:DQ$¾0GD" ۳P";ۍDXc$&N#n#n3DA&֗2 5Q"~< T t@ #`N2iBQ ӝXy%HJ hxtDLQ~~H$JT3ai(3ˋ#l"=.ܱ^7p,,ztrs|-O0*LÒ5Jo7I}A*b L57bhFT@IX]\oD2ـ >cҩ7b*pvj܌3Oc*LU0d!NGc!QҜa9M\4"aHK#ShH"&r+aHhVovhD> -$PL| FܩΆF$C%&=PHjaF"觝)[_%'ԟfuQ黇8E hQ|0E_]93XS H)AC~P}hprojgFsv:'mXXia!,Cz@s$ mw H!Y­@!ò:*b\B(,]8yH#]齹)l3E HRE$)v+H#z_OBR@HB~tD 43LM$5pbB(Ba#T M%peInХs;[D!PHDS_@"l$`S&f%9Ͽ#%8fE}C~>$}*?} T};I-v/d!z&SV8ȊVa"J&F#bf\izl bGFpumOЈz$+miD]e3ZF?CAUvjFLF$O҈84"9(r4!B8 IRuo3 O~ åjIZ[oDhFd VB#PqTއcވ4"](UF4zrL/>(Q3XU!F A7"LpiDkd+ЈL$aj?׵|* \9Z=r˾ *q]%DAR3 HQunAmJxӴg}E(&,`^]$¤ll̬C9ݴZ:pyAgy4Y"X`8a 6pBK'[HPm!$?94"f}g##i E HbIȌ(+x/g5e<: UCZ 8*Z%-RP0 b=Z_"n7 4.dB E"⿔2t c"*ct*a@+( 4"n*)g(J[`CBBFf$C*AJL'` $yɉY&KD ""ȃHSͨW\ &M/ I' p~ ֮Ȯ{b{֋.RGRGNbPMz# (6-b?zxߙOf88w喢ΕW{% :fz|^ hK#uj~KNFH#F8"OJ?&:5T8R^V$+uj{oDL#Pg4"q?*F&4"SF*VK6 4Wc#AoV<|br2cGqY3tp7ո9! Qkfn7Fэ}K^Rd K#91Xť]⍸W쏆磎7bUc(hDʕ*DH=B#~1%ވáW+ \"8Y ,hDn bK)¬P>)a_:BJN ^r* R辻&NNn!"Sm8\ubt$m/ N.M/t*=p¾3 )l?tcaẂ2Bg-xr>A+pE$5EI.wB, !hP17hnzS1L6jD=hG": cfFTD3($@0RnURZX;qevТـz/j(a8`PI_jIDAT"FmGFD#Wi%=]$x/ ROA"A%(E,hZF>1I#ZoD'!Xlhh3ۓϮf-K2a PMr"<3(=_bވUhă㝚GIP;5N#  O~,fȼ[j$ [GI|RA D#T" R8A],"'|X'˵Z$& Q.cX#<]a!o(\# j*x#{S9e:5[oĦ*5c|B7cL#xqK#`$F0 @12p5A4b)WIӈa涒N1DToDS4"KmK#J]d.Aq@YS4"HLi2҈*eӔB PkЈw58@Xx Swӈ8aFVH4F5шTO71z8#b=k,kjhG6af#"(/cTMe&g꘣WP:XmE"\ֹEJ*B$B(hQ"lʟ%w"${7ty10{HI1/" vGq $Dxt"@"H#!42DؕQ{CľE3o@rࡋEŔrxd@rcbz9 K$B?3Dwgj?>;poG8S8ʀȤtjNiD&OJ; %;5'Y񟌝K#dhDI;2#v,x2[/LXiG,pЈ' r(iG)4"K#bâM>K#fMhD O҈OhDzsO , IUU"dL%="' C}o+S.U!Á=D84{6 I  ῍D;R޽{HyK\ykH*@, (j+^(B9@ZX $DD7x#D7o`o;Ms=-H"0E@"$’H"@]3GmdlxdiI-+ύ4"0 J\JtkLđ#HP*7BM9=af~ٰwxWF?Al@w2!뷊D8sFL(_"NY!6}ΦU6& ػ^^tFĥMIoDj@#6,YXFt1-Q5ChՕ1GB#Nͷ7+Y0bb4"9>4z&GUЈF5ӈ:aiD|F2>x#"lYҩYG4"ASčވKvЈfh+RH#XJ=ӋǤ|Hb>fQRX#D(B$nWޝ$j#vEa=*UeE"P6ѐ"X HL\V"+K4$&D؞;ggݙ3u}3zN<3.-++M@8('DF$H4D0bGW(7EH7"I(pn *azi,c-D(5]3,%LD>E!-h#j:~j줖-D=BЧ&JsF7 _,P>e~imd3hRTwbb UOJ(b4ϩ4" o}Ft>}ciD (OWW F1r+Ҍz#rFX7bUUxFKȁ<[`ٮ"<19BFTcD#@K#vjz4|"8F7K#_L/ڸvB#RKc>[ PF:ȌD8p'{;Ǧ&4UZ$$!A7ѐEHJ۔H"^" M4@$1Kh5=>}wtUdXLRVJF2KC!g22:d SqERɺ"p55E u05٠@ LL '6_$UTn":AV}Auqj?u9PFn8BhLшWX8Ƽ]6Dш:IlQDò<,]zTk7QXS&zFO҈g=(GcH#DT٥H#ө9Fzҩy4ǘ@ 'ЈoTٶѽ=B7"*TDA?tjH0Cv@q@rRߥ(pOYC.hI&рןL1R, =ǕLyQy;F"xcr"Hmj,I"Dx'U"PZXN"H D8WL$ i7D"tMv滚N#DXID",}#%6 bgТe.2ڊD21Fk0P]J(T%-ȯxMj !H谜!Z@Q MLH~1-ᗦG6*jb`H!L֣e{4גe UlU}z+Gܹ\57tj['?> *uVi%oۻ0t҈4c4r>HF,iƈqE_e-ވkoЈ(I#"vaf8P.P]ѕ m-,ޞ?'M$x-QH"Lngk$ =B2"0׾:bUŕIU ]SR,B0M# RN%F bºy6PjDMRP"p2x{Y 4}wWs[we06vU°N,UEqPFD`Xk_vjNF,KBJktөeG1 ވ1te9騚%dC8ߚ%5cFc-ވiDyғ4I&Y>B#JJ$>BoKp8(81Y4|YPTFI:ȇJ҈xvj~+0)4"f[Ј{M[񮮢7{x\%BHgtf: ߪ̊2K-AE4Sc:D`6k+f"R\$[`5JZ E"('~:EÊ@8E}]Qcy@a \8O,Epc,` Y"fL;ڊr!'B,$Y>–;>n,ZVH#7IeqP@d 彸 : `QΠ}-^aUCU}AvQbqF5wjH#f7K#D.I#҈Nߗh7&??ܩ{JDŽF$ @j@!+K(8KF%Kc2)RiĊ>NhbWҩy"R&pEa1f`yYQ` b#_޾\FRC-l\!IheV0F$-ݪ;sݯ{|aA^t&=&"P?DCYGF"i_I+gʻOy*iPzEi0Q nsա>L X'M4I/h(M 4 3.Q"H!dXhG" v w@N516Nd3{MޭWLeĤAaX?p7G8'J0`>fh-}~Du7 %3̎@R"Ǝ^B; eB2Ȕ9Z$Bk&kEt۽f9~S|G/#+/>FtAfhD1oӈEq0j1֌oDXFh%/6cDi(,U`|kpo/E5`F8x#ߐԌ6hS8Q“-U TPcLb&[`X 2(tiDRqh۪ujcif*GRiDm"F{#{ϏNa،Q īP9cb$ G"S)T;.ľ⠂DC[TqTEJ=6(3H$'D}SyW+*4{D$T4$AC'I3hbHbaD{V&$ SL?HB4 H]NEŢG#JkbqE|wm$9uL{h@y'IƳv%u2kk3l?~2>:}SU[ .8Y 5$```,6@C()dЫhQrǥC&qHM , 2`9}d1UŘ룻żFxҥ҈ Tg9z=M*ѥ n iĢ7/>*2<vFN ao(]iߥto4"ψ1X҈ hDNHz$)qP۩3(5bI VK9 H6s,F$%$4"2!n:5@P%t64 |v8N`,{4#`]kRo0ꊃ> :,HE KHkfG\15sD~+=b)O45i`AW5DuHTޏ: -HmHU)6H(Yhy$IcHȇa'00p};igB5D5NSˇD`\Ⱥ٭{b \kh|’5D=gZ !J%T3KvDM~AKMF}@ 7HB!b(\4QU&ֲV ID,{ڠoaF+Գ 0rY1OS]U$4"ϩ;41I#>RFUF=uW9UFX1Ib3(AD#W7k)F*Tk}ctpUQ҅, 9:Q4"O7#1Sџ 4pFM|5ЈoS_?S)V.޴xݧwpzF4 b-ch('TO7<Ђ|75`w/ ]`HE4ҫ6׎DEg}Cy1`i*Gbmg||DR' $S7$l?To$b'E"H10kkӊoJ$0""H ȏp lĊ~]&D\M!tV@b0:P|o/Hv9Ts2B#;ja:K,҈ Gb3C<Nb ҈ XFSsQ(iR$1Ԟ<yD^oB<{o7hD0\4"\;Hf*wjNЈemf"Ј/~}+O4XU13@ctVcЯ`Yf$vN[WF?ޗڒ# f"v[A$5j4͠_'9sD>A"p,ؤ 0Xމ,HB5B"$ &A7 DNz06 3NNپ|_kH-jؙ#)jX!I[G 8B6 `FNX PU L&js @>dI,I.h}e)2^f}Ӽ&BX_XE~O)WZ2W8dN>(h(7>)'RYRaʠfH҈<E(4cLFp|(FFiF 7PVԜF9҈DS~ވ4҈4bAoz#WsksviD1Iz\Q3FāP.,>4" hqӅIЈ :QQ*z#mS3z#hD/.\ghGBюWWZSƊa5!,}DA6%EpA26 ;$ߤW%B aH \&ExmfXKH+J WKF@"DQ$#\}  lƜDupC$]!S{&T$BMC٣Q΁4M?ln?=Q?զS&Ꙣ[ hMx>C61$Ke-BG7mr J&C' ͩI.h}@u v 4a6Yp nO=?h̫f^@09 }9m pXJ4>׎`w{<+FE> gEވ!J-4'ވ?0}Fϭةy4ވ.}< XҌ1F#"yf?nniK#J ^h&84$ J, ӣRXS#9UT~-48e#Ӆ'ȟ/׍\0c5@4BQnXk:4bXI@.9Ť>JhHd%l+-e\b\\ m\f`gA?=@aG"@-ܠ,8F"ЦE}E"~о5NN[rfH!Z<݃zLhK7Q.,F"ƴ!VLwobXG~f-SrE/+%)k`Ύ JVC 'D BXT> @JLëR5@fuؠqH ASNi: sH2_?KWpF<6avqA*Fs;矤纴eI ȥ=MSsH#Fވ5҈z#%٩{f i.ӌ1٩,?hnfb~UiDLG|XԊ+ӈ !_2pOP.!*C$Fcm4"K#JfrCx9"g9nH6ֈs/8@))-+.oB!NKEiXG)}3SCunh\Q3!~]#A sbÇqHiHuV<гtz V"@BM[g ŌCs 2apJA#H"PDX;Ģ-j=jTJ,&)1k`Qg6`K 7@-vC)f(h}AXLo! ABɌ:Lu!h*m}/ YgL!7m6 Հyӭ}F0al #'m[W &ވhD)?~g̟u̹p%oD݌9SF4"Cc1F#$thĔNn,L4 `65S|Uъfqrq0Mt-|(D"҈`B̒1_N1KK%hDZNЩR0F|x#/k C##+ORZSɈH -_^|7M9q`W$9Z8rEU5uz5}Gy?P]ʻWy)I="ؽID"6{t45"GxIi/d=VKp(AVua}ᢍ 6LGp{g˞~ 3Pf̌iCS& S4lDgelX+SHc*hp'}p'FGgOQzGH\iBFCjآ \ -\0$8 1oW R$\ȼPHS)~!;@V .|T#ũq$>zoX aCW2H盘7b 4Ta;=-h1NVAVыN5шfRPX p`iD vaxH(F#G<\q)q Lj &x#8꠬7"#  )D2,\b/V^d*A# N|IGimj7BNz#}6jSx#iģFܰ;a:5O7"DD6E \c@|C!Ɏ5#権#8zAhWBcs!BX@bZ XMp|qﱑAY`v-'kG-0r4"4:4"sBoDC#Ҍ ӈI3Y~(FLvjވ4oĐFt1##Vp8Csc#ЈLV0[q@089Mꁗ$'Tq#''Xq (4 q]KFT!p7"ш;#^D(V?5:=J# zXL ~ !%4؆dA"1(hz'W9AZbغG6Ϻ'bӃ{By(ow(B[ L zg#Mo߸"%>iܰHF@"Xk$BJH(\qlsvޓ7!7Pn|@>B#f*>> @b҄L3-iA HP6J Z -QtH ^DžeH^2GE0ܼYQ4IV.J-T6(K CЊc/DgoENd8vDqNվorj}ߪo])OG[:5#5U:5 H3FԜXFID#Vw {֓Y]㝚.?crV+CSLL y`Q1BoZhĤ7Ј .-p`iD CC#SiD},pJ#`4ވE~ +D2\@2ɣaAFt|7Ј5Јd)+-hi=AjkRF4":B#"XXY'YaXTڎ!6p7%ECH8Hh`41I;Ģ>B1$L{$&4KyEm~f?0w ,Zl;/|a`ʫgtQCi5[F@"Xk$B]VW\vGM9; g./CG;r3szsSstg}&~~0}za0ӬWfZHxOdƌJF%@j'oEPa+#Hu>B)|&LH !ԟ[$ b.d^h2))gBj"/د/ŨP,"sx_p UUB-o-#@-<ЈRcNЈRFF157bFF4A/ވb CJ`#Ė0CoD&J4"3(<2<.Y9nވS(G#"Sb4"g^;xy# Th;5Ǽ9[ R%N#4b±"dt}cc0Uar!=@c[4"ߪ$" *ٜFEHe& # Bfba`jAK9y޳]m/_꯹_y\KɗF?,0W 3!D% "*HTBWA<# B"wD=0M.DNd"A!%"_67 PR<1@rA{$2ިP] xrB~$1( )"I#c*8_U$7 荘)l1nnɭo)z#&1ޥ;oİe!#'0Ј8)>/¨TYܖ*HNa9h+iƨ(؜;;B 87b4"+Kb$r%4MP\CWa7ک`Sp.lfNEo.(y4eF<klXB2PN JA"0pPX,;'uί٫uO̴ip="V)oc$:7`i1D%0N9PBl@ >X3Z zGwმF>@Il0+8yΗL=Ly yFC)v鎎~17g֡`@0OM;:$CtEFP|9H S"+Toj4b'9ވ`e7hDjވdaTN#4۩i"4ig[ɆQj )p 2D.X`C n&$#b$Ha|Z"n }HD<$?™&_#}~`|$e86RP((0ჼ&HKIbxZ0:a`Lv*&R_P< 4"eЈ҈xϑF2H#f5L،nb"+ӈS 1F4 ncO#꧀ǡ"o1)H8p@}D(,ylGI#J3edgr[[/5M/3ˆ/Y>l$ RF] F(Ј$NͺIH#DCASzPA"*1PJлDm"سEh~ Uk` 7뫿VaݣX#|Z{5E"lW>YOMOvv=pF6\xq~e@B` aN  SCD,N QqzJb=tap{J Еޛ2ͷ&@!t*%([LΞi H 1!A&]A(z$ZTLmvgRgøVpÜ+ He#>S' N5C'2% Jac>¼Jôk*4 &*`r7 CKѳX((ftJHf}4iD(ičãI]hD=r|4@ZfbnveOGH##Nш:U'4e %+>7~1Q-p@jވ1ឤɘDH:5sqF8ةyZ_?MNO^_ӈaK:5=T,8YrZ&Iw^i1oRkQHd"HQCT5]\yd4I/.W>/j3RkД+?$ pF3Yj+D Z^>ɧ81?ҏ!do2Lo7r$':z#hVn`Ƌ7t4"O4MR$FAU5F#+O#VB4s{ 1F$€xd05,!Yx^9Qӈb4"lNF,vj@L($/=ՔsD( (&syɌ^ZP9*8JV38"r"LC􁥋{ă/^ 5'_ 6[55'e 6ϕD" & MꟚ陑霕=:7{h~vo uZ@ o tG@]blqcb6"JJ(vmT.,~0hAG%Kf>&T ~M=ltQQ YPZ8Y3|=`Ê.r!JF}E ,w^0^#FaH[s$ c((-Whהo$ wPGlRoQS))3#V60#ȃIЈWN͵Јbl:5i:5d0x7ЈT]N$ _NIo$xo#u8CYc-4"pipoox#_m9m JQFcoyFd$W,ވcu{hFL:ٻwFy'L&k *$_S.}H\H ,h]Jo5[IQ )'`$1X\-ay~kL$Dst ! 7_X0? $ٗH3 s)C3l+x07UJ[,\@ nD"&ڳVz,p Q~"?3xrLJ.,pЂ.J U$Z`dt!JF}IO "87xS#??F<)8DD~d>)a]W敃^ot !u'`P~i>%FH4hEq <-4?җKJ4GLNЈQ7W1Pڞ:57"Ԍ7"xKI(̣S}U:5XB#}Ku҈19 moɑqrkI0hDr ЈuI;ZD4▖.smE H$HK):!XlFЩٽY1aLs<$B,H+ÓrA Y{|߆h'\DF+s@GG5 IA7sFKh<['!}>?:w| 9H8++ $6Gc`$%~!8~m7oA,+ Ģ,h\'+4z~02K=htpk UBD_/Q4DΫHD5u@I7iT2≯3Ks]D%EQ A׉@wZʅIF_+  q$y/J*gO߼EE>&wɳ h$"H106C Mi4! {S(E|@Ni%F%$cqOF,FMNI4U{C\_F -N4J `J@xĠ4"F80zE)jF"t=L{=f )1HЁ_W\%H]I%bhaZZ>0=EOJX* v䟏GCܣnZ?,=HQ.p#nUH^ T10LT,(% mɆ5k|c'b^xK#G1tŔifsF)K#2K҈,CNͮ7b Ӗ8piDV'ވ1F݌ fIQp@ 2`,hDhhP=?qhD}C*P$re8]|4"A5⊠i%qFLzz#^\sZuJo/8R;~|*#]$^8HN #PנK#)G]Y߸w{@Vq߼=߶#ӾspҮ{ힱss{мw;{醳v3}2/ȋu*"ĉ91,8u (mТzQR7"#k2H.,5R K: F FqЈE;;=lApr"s?4"W(\ !F9M'Lwވ|><:87HU] F])ވҌ1SK#H%[F|bwS3{Xt%B1 Q!`1w-)p0NaGr %iـ1ԥ /N~)QPG`}EyP)5m-lϵ̴G~k!nq΃J{fv.ڱ(ܖ .7p5غkHcX]9o[`m9"*"7 dUY @Npn zA /Z9LC04 `C!li64k `IChC`Cp_Czg~kd  0OC:X8ޑ&DC3ip;J|Hh('bJ6RjW!m?'ɿCXYVgrd/BH`,A4"ͦ h{|OFujε?ⴇE#MJ#RCtSXFRT!I#]7bU`4"=$DfAEQ?UiWQ~nf5x\=K#R#A҈UxYZo$xŮЈFw.M#}ujX1ND`EYVp@,pXM)p0fzCiQұP۵AEdppGV< jb"lJM[^ SL34q}J8=H笎s>4s.j m_\z^/S5ܠzzTlmGP" .iDԔ@$xP kJ ݀Jp t iGr "Lw7F_on7k3Ӎ#d^JRS4?+u'PXeq~I bTXc7%vcl f;+r1&w὾bqp,ih#q % MeSAH1l*[6ů`ఽ ocBqޙ#N(\oD!{FL҈n3FFy#whoQ3-6c\1bވ4" &r4"υK#R[9*|kSзR{̬I;6I#R҈/L\1F~ވ4 J;5sIX (G[ZވmoDAC+ш;V]n9l_^1>s`2ĉ\NO(" M [-;r'rwў]3:/{fv/ %j-RVkJU_# oz(c@GT=5[TyC%/U%ȎJ  }MѦ¾®¶Š3:Z″0y1xM4x/N G!0 56kyw#0+u1͎.,L"rq4A j۸J0d3A1}`CQQ*Ny_(bS}0H+\e 4"x#҈h?FGB#>v2S.4"@yw04jذ?uj&GRrix(G#7-FL҈8iZhD|(UxmEoŚ’LSm*4cl*ӌ1TA?A]jciDP!R$å(ѩyOhmbr`a.4"8ЈO{#2V#6U5y~*ԨND M✝.V,}W%U bD*@ _Y]FK'\6X*j5|95`fQgƕ~ӚB||˖\lۮ̄CN =?|gs-V[/R5cLA b-[M@ G" SJq*@TWm$'ТD2J+|9?Ԝkw5666w6575i3 j/nNh` Ce ,O y 3ӃyFFndp٨Jp7.Ѧw@Dr$ aɸQz<*qƤviXT U gRHBiſ3j|,G c(فFLFIx#$φO?iƈ7{إ]%lƸu 4#>덈zFaaINhXo4"7K#]1#ވ1q$#ŭ%TJ;5hǜS:Ј|F>)B7?*>%4"pHMV87t?ug/ٲN#`ܨ  .U+Ԣ$FL`Ũ2C [J%H(kTk6룖K~ӊB|˺\l̄mC L?`N ѝ1{̡y{9jjjYk p-׀ 'yjČ0,2o㨄$Jt "5 !k z[r]-#--$5Vk-k-k5KpU~1N O8 cԻ܍a jݐv#` )KDx 2 A~z)q\Z (<"}7E>ͼR(i AxLAɅwԱI1C^DKqPF$1FQI94bԜJ#nV]jCx",Hͥ]xNͮ7b45NAf* 8P4 iDTw3 !TLOF Ϥє-쏦E]*҈H K#uj4"!cX#?n i$k;5x#=CЬs7SSs ~/8a $P R IQ v 3)}ĉY`MbZ:}Kyu OOM˷ʵͶL4Ծup⎁I'rwiӻ~9[b,͠ lNL6 vcۧ]&GOF@/V=? HmK#Hmp 4b-iXFԝ|Ǫ+NY88Hz#r1IkSseq(7A6' 8 ?Eވ.<i0 o&wjhZ4oLå:$JpvႽ lXވn3j4" ވ4l;Up%4"ێu`t#ω"Ĉw:ͰR p J0ybZ蟸E>85Zd-4?o~2߲4׺<۶"3aP&moީ{z ř}S8qvoZƏX?-HA.d=NJ"E"#DX%j *LL03acС C' 0}Ж ml-:S%YM6=l0}L;0F`NA:F@6|٠ ܍<Q3Ux$1'Fh$(J hh} A8Tpy Js'Y"ȻK $_\F$7\hD݌1C(ChDΖWtjш qhDoXЈ1$ `1HJbvqr9q@#r$nkhEL ;56cdu &&B#X~5ބ4"JS34"˶:8:5:F`ZPca)ԡS qULJ!+5n _pox`|'mK3r}`&m럼oʞ^70kP\,_7F",T;5\։A $@nՏ>QbkC%%tW"mD x,D̷vm<>}pWV &dvjMXhԮ ۍDF 0 7'o1ul0v)Eg]84A4"R "I)PD*PBQTL?,R$rDɻOV}:nH-b-A$F7".r2`n< .,YXS3 'q6h_9iD[`;5F88`A/өSqqoDDT23ވ47bHxvjoD1 VԞ'd#7!7 &:5t[eЈ+Pw9!HB!1x`_ܥOSV> @pxH5|^y_U- ?66Jb3~sUecuKm{f N<20ro䁾)ީCz:pp J1# Ar )1wE"PJ)-0`6IyFU4 3qyG#UN#ٖ̌*:5;ވhD7b xЈNfmk˸mHl Q\VxQ H7Pޡ[{MF҈:5K3FJ~Ҡ*{#J»ǚF l8NWujT- wv 4jת7bqmyxQIxj?0$L5*Z$BR4A N &Ѵl $g1z a#-1[7MHv[Z;mݙ~D_wE"pڄ;,x(VI5X8DC $%3k`%"z))}lIthPjٲ@sI[55}  걦YN(;T8dL# NFFqʫF,ߩ9I#rq]#`8SC8hMx#8֩9N#Gq aJYy{1#8pPш WG0jxo.}UɦrmJEhI3ƁTAhDtЈf )7DӤ%Huwj/Q9'Q V$50JV1@ J.8? H @a{iha#0nE}(}]y-⤄M]q}-S U&mw]~SoiМɷt7jutOE[ԀD${ e`vnHR³]<}- u |j*>m@$u34-SA   6n-oe[mSoSC Ά`[C!Xt\<вܥL?F5c۱?шNͶli6b|/x#~H0_#܍$۩7be7"ɸ7b oD>G❚i;5ӈ.0Nߔ?.܄X`FSu{Comk4 uqp”ƵD3('RV|xFhGSxN}HjE>5 $pŦFɔӗ4}SHETݺ{@y*)-W*WT>V^W1pݙz,`l]10 LZgrl|y 3H te,`?vw??paΑlY=I%BwCEzk#JFHzicA6z&Fl ۀ)b\9Hq2pbVGN/ffT m./@We&68Ԙ*rJoF&ˤτF8e:5ӌ1x!݌"xmiLxh\M;\%)0;ŁFO#FcO#~ш#F< `~\FSA7RoDhvj8y9 l7"4ckswaNB#B1VW(4qo:x"F Kq'R 2#1PDUri^'\E*mSe.'"kP"$ ^- @kD1c N,dWn XBuIBٻvg/`W8}a>ہ¼ӎg#%D~Օ>aw$6FFl:`ˈ)_6ٰ9؀b#\$egYK$@V b*x1EqYq1*Јd9ވ.$o-$"(:O |[(E]R&fNrc@3}IFP@s*ߖ6DXJ>h! @ ,jJ%ߢ@ rgfT EVtÓB2ul냋6n/`䟿?os-sw.)tHElSaۤ%‘A#v5M>qsz'Y{lf B$`@B߅  )"` X"X"WpBi%~  ZWAVFuKDZ4b7b F$ B#. ;5VˤSg8Hx#V J#J3F8ȵ-7"44c\^ no$Nb3FS34"  ǼFq`lOވVS‹ߊ;|4?&-Txf*K#d(,U4"\4"Y!\+шTMcI:xZI?rW.J ;8#:eKQhjZ$w{qGq꛺ 8zslK*'kh+ڢR\12dBaJ;#9-8 {VkQ~ %(H~.~@I'̀`x%`k E%ࢋ/ۊʕV/e[_ο_L,~>hHDhmw6466w5755oo- [ iDD4hA ;D@ zAN (h&6{Upq#Ͱ&ŃP; "뗵FoИ7"x#F|x#+z##\3Mtmq1jUPz$( å_hԮoEq鞂 шzw A*p9>{-&vjF Ssyة䧍qf۩s%PNU0BlgN\qGtfK#ӈ[78-xΗݰAY(*e6L^I5ȀK5ίGqѯHb A$+!*ʰ^"46?3;\l=?tq` 'B |oX!Jp,A;g,5lW?_Ŷڿ,]"iC|?|30ags~wN7MӋfŐfcc( @6Ԁlh0_n3ؠz0b `DY,Ufū@XTّˋ&J)xq`iD^шho-8n0F\Ԝ]oDi(4ی[)FtiDT-U폤Skz#.ofUj+Jވ3 7N#\MFqPF,n% [Ȋ$>YF썸 v@{#(4Qш"4e;B%ejd$'O-kuA NJU9٥\J{Y@ |~]3櫌A#o, O/HT4`$z0@XEh/ <\3\l$X{ye/ |qm@ }Ʒ.̅){i\ۻg[d§؞_ܿf%a"@/JJHCk0Ԝo:Zh;Вow8lԛt`;܀#):@6'H,Ha dum{DؘQ80e ,> š鍬 jM9~'L땆FވI!nlFq0ցɥވ15tfhĝiDtz#6c҈EoD80NB/kCL| \o/y/S.J;5^)Q+}4"0 ҩjqGHTɃ`VcaЈF\ߒA%[҈Hd۩YhDhCqyVt{t4uq0hĪgK*eA췩*!!  @G h`>«ccqe SBfba`JwFsvȼg7_䯿_s%/ {y+#%6 ,8-DvKpJV1cfi))/˻G=%hH= .M-XDÞ !1NfL DZrC->ݾ!GZGe+t4ɦ!;ÞAWZ"  PDȗhi1P(L4$z2 nah9NS$e}(*Hv 4#҈x#3jF4"kFao94b҈.ppD^hS_4]\oT={Ɠ&Hb4"aK#9F0hDeaS3砋&HspbhN1I#"~ҀrHBD#r@PzBoDDeEpZuI+$I J|9ePX25 N3*tQ HČWɮ HF)"@E`qK$рNMOw,t-_FaŽŅ6^쯻_DZO$H)I'qJ}Ű]D%J2&$ "(s@0O$BO0Օl_D8A'z5פK"ͦFlskD@> G`'N6D@1Yq@@[ ,0,| ?xJѕӏIc҈^FLF\{;09oiD=ͬ74c@#1<\3FF:kqM#SW r@mtjNo_ވNF4"ވi4bSs)(ELI I7jUz#4O)N'Y 6aLT+ RECIbBTU { ̢7I´ iO=u qZ 3f$d wPDcogS]GO(™ݨEHwB쵁##.R ~JV%h H@/t@(r' cgc%4DY5m!jl6m0$i-6&$"$}c #&He@",b2 8# | ׄ*&0Lr0kx(tj&K4[DRnFwj&XEz#&Fe!N#&1҈G5pPB#f7y\I4HƐ_3xe)H?qhD>K#ԬĩO ?u4荨i}GEFkZ48郘,J RT,S pQǹVp0gȔe$&hPF+<|N (ѲޏД>büx0k8+sJ@| s B! -^KBA=SljA\mC Rb L!CbI3g%nO 130#rz4P[o !NlƔg%+`9sΟ׳>ܤ_ ~(pO J$jN҈82x#.xl۩YG{҈Eor4"$,nf^1\3ƍ-0X4ȥ}F vj//-: \Kp=U0.$!ʨ(iDFt;5 @n@K--&˶`ƅK h+C#iSH%L!UEC9(!9J(p*t# -Ay$H7Hp-m8DNJa/MK'lH#{aTCo8p¤BB s ^Ņ"ЋE$7%2Hx[IZ=Y鶂d%q81K N38Wxv֧n/ VnleRU:F DHC&@9 $`,ȿk0PJ .#ҕ{\ZIi4beo1]'_K3djfFD]ujNkoXJ#wq-p`hD-шo2GI7"1N҈D2gz#hD N?kD?QX҈ ЈNf<<  EH 8Xru)k;ʌUb̏#R K* g9PǣALdUgPtS (Яl84;Bs_eP{P0EN V(Bߠ0KF ś9iAX%dCm4 nr`f 3B130%җٚ&zl#`_+$N`5UKlEWI0"JA42?+T+. Ғ}4;l=HTo$'Њ!m.o24"Zz#bA NXvrhuj>q;5W艼ЈwFވ.hH=R1jvjFHDш82%iĿ4]%mTNHEsiDR+FO( dQJF-z,K/U 4>Ȕ_M#'%v# zPh>4 M G-֞lk_m0L2l%~Jg;KJJR%HkDXb TBugN mIX tY@gv@09uce1j $pr@ Ŏ^3e8DJ8LD-1Qm}m`XA>O7 F|vy+njFDMrX¬pcҩz#l}f$1VFt;5ʨp["no'SHFHz#hDiH*ĥ\hD TSVk䎖z# N#'bezNS S T8X`]Ҷ+{q]t{E!? XL79BX4nM ͻ-{s-smG3& N x Ƙ(:8:b *K }hH*=Q܌J>Ox!*@4&i $S bl L XTؘљڙ Rƿd5_~w'vc/ )oLZn!L⒉\ Нv9%PX$ЈwJ#^ ط%Ca3F>r-4"`;5F8S34mȲOD P7ވUiD>DшLC#ғFL҈IoJ43S_҈i`W/U8Kj'D(*˂Z4A5E4Ҩ2TB38[1 "6 ܢI nghm>X4<477[Zwdvgf&j?<8c`b}S2EP( 3:GmOvU NTtD%lJ br ā:fpB*- #WP )u2ۉ?3%ʀqL1I.XBϑ4'LoLdR`Y A%VPOtjy#hD\#KuhĘ7"%0 NJF8 \Q쏨E}YQKh{#単J#Nhg'> 8:XotKipwjࠣ-I#Ƽ4b|4":8. h9Y%˜TAPA%_q^ukt\ '~ [gů};LuF"<4>7.W[VZZ7d6g&ls}}O:?oJwԾ=2v曫=\(=Q =U Rq(Tr 1:#:^L|'ssX4ӹ&x )/Mn a8 Q9OLi/)kNi/hx0h|ozм$teYlLL L?ig=}SN9;Hϴ=]f uvؓEj$J%k_àQFa/~~$̸+L(T{$H$]V|O EHؑ׈8W҆ Ȕsd,xy|FTd"koOA?j4v;-~XhDDވçvjNQpŁk-:Hå9[ 1iD1ҁ&J@ihYS341z8:?O4ToDY7C#A:, Fc\C p]E\M Asd^n^B +3}wR*Bӓ幖ٶu &lj>8qĽO>W% LvSf#qp,l)⽈_?;b@L% # ыb1,nV(0Y 3=bH6OnF6V,S^6`-E`I^,d"(F&J[%~%4"G6;5vjw(+jXnToaӈ{[s1.F#:5[oįxJ1~B#ZxI4C/14" m34QAN6P7"M#?F#"$T,ވUuo88)S 1`UEC9Pю^"} Q H dH}#3.PG3o1SIޱaI\yUymeCusm[mgfž'o=D8K@EjmXl?5/!|`dys,;ƈ#B)#P`7 l =C Bݙ%OA!͍o6WUҝQ8m2 p \(d\14_T!}m?7C#r4"zHQHRFDY6cel7"G'#6S⍘GM3FFchDz?ވ,֣fgYPNe!S3]F7bm4"Mӈ4c$ %KNJSs&lH,\7"';&{N#>5A 7}*d\*8;8<3@)R䥄p'@XcdE.͟}BDQ+ S' @X- ʆ2aK6z6 W +rX \6.T;O2Gҩ u!$&%-cF#lg[p^ڊіD#j%mX1+tjvjoT16cLz#ш<@TcζB#^ &{wG1x O hOD&^0wXڀu𗣰_țwA'I '2 FOF @䆐F-XS&%u I@?K -͡H: ׄa"#P!Fo`"Ha 'PݏߪQ |P}JҞZMA&Q* sq:Or4"u &=%ވ$tbWFL҈x#ghOaogElq@ЅMґ8Ǐ'z# Gcf.8oďwMЈ1fҩ١㩳 -fF` ɵӈB.84"ť)ĉƒ_ FA#qhDhF$r Ffh"4ϭ8 -s0 )3BG%h2pJc󂿊O >*eb*;w@y8`[0Su V; h'V} 3KVby]Y(@1b-y h0S:5(fz|&~M^C :AFm(/w:a6x lܐo\I*$}bwwd>tj&8a+٩yTވbvjvJjԬ?T:[HN9uOԜFd‵>+~ QKr (ҁiD$ u Fc1A#b3*4"4RFD iW tj@#(lx_Wct^Z Q "X*3)HƁ,V %`D,}e+!-36Q ^_1qT] n `>CuJ8VN@+\Z#$` n" 8,1ݬFA%!AYRHb`1vOB$H~@H)SN?A6C$7xt?ɇ IJ#:5C}NA(.U]Kw FLz#V\7bY|GZ D 8F$ AC]oD1|D7L#b.e2\J#/biDsK#Hgyaϓ4P%1ҩN# Ya*:@A(m?%-:T .2HZA.! /VS Jح4T ! k4 TBWڗbH+X׫T {?1*aP4wKDAR?2rV1@1Lϔ"hۗ;;%hV2`m.y{8m >~HvAQc?vO24"Y"(Ss-4"}4b-{ih7 oĐF#u(bx4"Bz#^^h!874m#--HF7"v84[QދԀCsP@|L}U pSso PWXz)b6cF#\\x]?JvjF(I#bTA҈*z#FXFޑE#ҌLfK#BXzxѥW^qdрc/x#6F+7:eB"W"H/V%"@ҁHp $P @  ^qK%K@!P g"Mawа/h<7)l(4w{-\k&ۚD+%1> nDܪ@Pr !X2]1̹x&{f`wI+MGԇ>>A8?rD} KzVQ@g xe &?}hF㰝)=&ވ5(keO}.Ff1oH!@7bH#/O#5EDpPq44"|kC#ctocA݄B4>F˭D#^XNE ވ/*vjSf>Q"JcLhtM `Gd^ы1EdVm&3Jy+oP >4l۵RӞB|r$ڙmb֟084!}VY^62"ƍLAG!(Iy4 >#Mٽ(pZ}Y :8@'q8ߩOG}~N3y5g=@/QhLtRШ]:S9UAR"!}c@5TDhyX͑ 20NfӚ#hƄ7"U6cH#V\F ӈZ"ވD=@5&1HO7r4Toğ5rt3' pU-JN͝mQhD\Aqtw .X:54b{Oy~IT1%OIC &]ĺ*%c *AP vT>aEа:h\77&͛[-;Ol>mv83ЄN;8`6lv߳& k h3RMBA<8jH\IZbFfpD'؝xh t\_ 4qCOOy(hihKRC#Gȁ[rGiDZ?*F#RAf-4UE),FL H$4bM{'|=Oy'\s ^1h^M`9ƞb[U復˪x/X%T\B(~+>3=Tи4lԴм|Zk٘kݒmݖmۑiۥ;?M7~pn4s`Rw~aZS 3pz7a|RhHQ d" h֐0 Dx/ߠ!PD m|oVsu˟o xT"3$ '(b$8ޡ0xީ?HF(w~IF̴R<2&1^S3GTRHcSs-ވڳ6cL]8h*h@䀃Tnvj p0-xQgbMn#T#iiD@(յ4" 0 +hDZtӈujTOgPGK:N].WX b,ed2=TD+δ^}]{_5_2KƇGM%LU YC*awm_f G;{%Lj?~4{9?2784/8 {f``[9 K,ܥRFVpT@@ ,0ޑ@4Pvh  5*SƛߨnEy0QHתeTo ~ W0 TPSf2=,\o.5]r3c'7XIi4"?k'^NdY[Ǽ]oDAi^q4@cfrQ6(4"9|S7"Ah$Q1kiES>vux# H9ȈЈxde4B/A#bOE{ṚI>%lV#P }ÙIEjwipqnqϔ63PthJHJCA#A~>ᄦ兦&.߼!߲9ײ-ײ$geڎfh4ghBЄ!=LL)N+t(t.[84p`LB"۹ / ^2XqM`Y90# nCR ,H^{Uw@7Խ @$@ Pp@o=ۣ$¿)=O;5KBqpwc5c/4b7U`c%u8Hz#"7" I#8jp҈ ѡ;5[q:WIQ C l_v4Up3/+k:Pb`ihaMа>hSддд@CR0%;-=31;{ r{Z۱( /ί4pYa+ 36π)TrF.wcw~D bj@ A82pWUXmBD`9UZ}mh%IiD87hD8c8i$ T,U: aiD $HNЈ?Ni4" F\9 i5biD vb4V^H#bf`ˤ9:G'w.ŵ0!† T78[(AWc%ӳUA$@V '? '0`야 ʆu\+h5!t)CSze(vw;:;wdN0i`w` Ɩq'@ttƾ 51A{H'ْ V1v&h>a8шFfoĿ*^)1Cq< L4 iPJ#*SHԬ%K#ilZhDiЈcBH#7"T+FJ\hDx)CJ HF$Xj`]DH܈ pvɟp Nr Z%!30^L'}S==1XcB0ً}m`b ЧU^&Ԕ/2 @уyyY@ FR#Xd ?ԛ<#F,r6*0.Ԑ%>ZD?AF'9'ۜC#fZ $:5rD>a>x#B\RpP#pP8x;5-kCo̸H#sM irxL!<@]"Twtup zpB-c$0;HC1a4 Ua*#u1ޮȊѶug‚ʛ)%8Jb8lpѠ ~%ȵYiL$5Z워XACBhiYp9(^#Ʃ,QUFDhĤ7:5WFDI3NwjA\B#~f7bF{vb1o=qs[|"FIӈw_D.\r aw4! 'XwayHԠ0O5xMyW+ <>̵vO)o{+L(K[@Jt^" -j7%6l&eϿ|YXqdJCp0\oӈ8͐>I5vjL#r nfJ( A*Ztj ,F@#D#~U5Ii6VF\|tj.҈ ?ιN#&`f5tA!6y@%6$#C4ưV3pcB .=Rx#e:("op7f_'7Bvo7څY} #U}|)%A1z#;MUԜzG٩6ct:5F@#Rrވ`x#`:5[o24b-Јx#$ӥc^F`F퍘a~]_ x_DDHwN;&h0ə- mbx@ףb١x̨0ROD>j|~drw4E2EI] !* ̜D^Fv@Bx"CQH Xa# M@v>G*ݫ4az҈Ҍ1F8P9M*FܩN55Ј%:5 HԯDNЈ>7"JhF\wӈ ϊ8ScSeu0 H{ftjpk8i($+ h*-JB_TWL/(*$mrP.ܣ<Q Aͤd"` 6IU0333C9maHtpFEcw䄑;XRI?ވe1RSsRhDJ-\1l̠z#fiވRNfFF9L&Gq泞5/F%N#VO$u0{75P!QRPB$3LìhvBQ" 1tPxw 439:I JHC]uNҧx$E*|S6}`*TFf{# ֩Y5? S3ŖS3iwF3(Jw6G O5nU6c:5Tg҈>H192ܳ҈s;T ]x8@]"V"Td@%#b(8De(v3)y 7%:NDP1KTH~2<9 ?T&LQ1n|H!# B'LLL< P/[^ ~Ը%Ŝ輻 }[z4PΧ}ċq۩yX4"9)"hD kcވB#>4b=]l @FfSF5౽s=<IF<&OKaŕ ZSp $' P Fhf"8Z!!B9(UoL:3K>|.}”?迒&qn H@ `tfi(!!tA#jooOW_yJTfVԻM4|०ѵ"@VR8FM7y e:5sRӡU4x#VoTCЩYӈ˶>:5O ;t9&uq5e>ζ.X"TTM @DZ4w `{^F,UG)0Z fFjޮc y,H|/;F}J$7D(bd<ǜFzʝ+z#j}9D3=u FzϿWwi7"쪴P٨ %±IR58P oazAS oҋmЂ!b C z'DN|&Ҁz`'7EHȁ L^ [ҩoF|z%ή7Ј(҈Œ2_S %1+d\'grj$ LC,]Z5h, 9A{On0VL|P/Uxs}unLRe͑tшT?1w*ЈH c'7"4"0 ԜlfN,38خΑN?SMfnշ~_X.S7AG葩;Z3!00XiOUj姾L?@RI@L6KR\1b5HG|e2l 7#4 W`@ @6=j ~U aݗ HS3r?:4">KE,XȫN%SsH#54fs4N#ӈuA<up$BlHB nh^ MIՒ #_\/?1wTDxXڌRYgj$rPڌة٥9INNͣF,G#??1oK ?gNuy6#WK3^9LL$+')d 0V 1Pt<# pc4b Ëم@E)[ra_7o,Ap02oDN K#BNN͸8ީF8UK#H7[,ވ]qsWn1N#_1ic +PQ"B~9;&KN)SQ2fJ 6qAoRK&+P"^=E0ԝEFBfҩSL#҈wшYOЈq|{tFstNӈy{aKF\x>'Hr4-UЩ9Cq`-*R@!iTFDX<ө9F#&:5B#x#6{#&hDp?Gw/@#^!wuGhĩw;5[:x !=ϰ.N'as=6p2>9 7be=G1bP (ވjF6oDL}ؖF\lG  HZ휺88Eē'_~N+PEHz# Af) F|C#b<F䍈oDh?Vqž'9ҭF|jH/:ߜQƒ0NfS4TԯpJ$m%@ qqF<4bw[&]oDK#ҩAGv7hΉЈҠn=vg2W.NaoO+P"UAcU#FOSo6ujFsDS3ވB#>PSsEoNo{dh%4ⴟt/Fӈr %B]"ԯpJ$BF$ q>@#"8y#&iD\\M3Fl,xoNM-XFqOw2a/J~^=p*'?O.J WD"S3Fd"$r z#F\YSfu޳M?UFӈW]v¥CSsFyx2Ncs>vW.N#,WD"0[Q:F1%m^7"ЈNOA#>⩏zSg=UL} ވ.ȹYqރFt{6F;N#A %B]"ԯpJ$B-I= #tqL?qQR2O]c;N#uq(;Ů@]" )vS?@:)it?4y7=%m3T-ވ7V.?ѩc4bJfQ*zN>jկqup..+P0'ԹQUz^TfS3Gӈ[+шQ&߯>excߒbވ:xP>+p|@]"%B W ƉN{t쏴"ވ⍘?YM%Mgs xz.oR \/MjWW֯@]" N+P"$`/ԵL#ST7Ј(4/oTCoD_Wu>@կup">-\`4{Ki/VtjވO73Ge-xzmx#҈w,VbW_~&+p@]"%B W n҈54bn]K9oDhUx#ޭ~oIJ4eW\y o[N _up*L~JЈ/uhD1QhD1i8\q:o+FFzFS]5x˶N~?ׯ8uP+p*\ _OWO}S1vӌfqZ^]7"4KyG_1ϖtjJ8'C4WE8&}\'YѩF(F#OUN͖F|4c֩҈?Tozg{M}էߦz#^Kq8_quQP_S Dמш҈iFhm==)h:5_\?:q5OX\D?+p*\nOAO}Sԧ=(lG O{ 6"oDM#n)lcB#>^='_Qo[HQǏzb7(TEB`D,I b!| ( Ð""SLZ4"˖ܖ/;gUMY{#\F|4$%Cy=w" Aڈ4Nί㍹cOƞ'5ވFa cBi#acM{7FFf\,V6c65]s8lRԩeEڈk;W LAI{#a+{#b/drRKPHFz<̻}{zpboF\M7Ё#W?+D~3وfafĈǬd K{xrčԣMF*j 'z#:lģ% 8ٳOyH ## @~FAyqFYWut/U6bn8#Cyo_rE%`?'5l&l /Tol6Nڈt-30 6b6cP*m˨LZS6 >08%TB(X]z$@H@l~2̉6bEIF#qJڈvާlYpp6[N="_$@$@$@>' |~.HHH#7 Fn    Ͱq(IENDB`PK>-Pictures/20000201000042610000325C969DCF28.wmf\ pT>oIJ@@knӄ1Jh0S~B4"jǿ'2vDⴅBTbԩH@RQLyٳ toPv" PeEJAQZoe>toP~L~a>~6BSu|29$1Z[}>&fc0>VˡVB%,~:Tw#([Ϥhjr)7G[X4Sգc:[SFN{j$tN;-ԘO*D+/mVWַw#F( XƼ5Wo{j_/p}ƪ\ z}MfN6{zN}s 'luu9yX˸1E,&GZKk麮9ipc=z.‹qN"Kՙd<[UVކ7Q7c=<냱Vc=${QmD"!O<Ǐ w |(R <[ٗN%ZZ.a<>pM|2f)Lx>ES>DC\=Ǐ w |(R <[٢q4`Zi/ӻQ_O~bN|i#_0iƲ!}ߍtxZw0-0]1_Ho0dd<2'[_gX:j|#G_|=D?Ot`I}'}jEL-1P|SwME"fƈ3KO\bLbV ?tS9fh1󞺦 53,ˌkX@CAj`ȯ`W25U0(a|mq;Dp B)*ѧD L|xן|rLcCާc3H1ibֺCڢg7[|'xGmk 7[ &<֋u-aI^ElR<{=j^҆gx1[KwJT}} K"{H>"O z66cOO }<"vu\((0mXڨicImٶQ>B цzA-AJ~Aqϋ!Ðo Z>a/CJ6)L ەloSW+l䯎C~_g%J|%qϋ!g#xe^Ԟ2/+ўx'xYcF9Rǒsk}mdj-Y9(K*9شq06s)q^I38Pm6,9lX|m8;UJ6mT%͎mRr޴icWBmql㤒CWɄ`%gMqQmx)/{~D >F>H1_6 #C|ԷWC>X#zXQ?ed{—֑=e}{kk3e#3ARA;ca7`K}LNWKNGiMk^ Èz+ . 0TuY˼uzQ=mu$ۏŧ \ױ^(PcaԈKͷC>ȱeQc{^crӾx~ :}:C;go>y_1]f}<`7y?2(ǞhO9'Ca r j8AZљsTf+.劣"s|O}?ث9^,00xs</NÈG^q?+:eP=/})rrۣ{Ǵװ>vz))anq: *`!΂ >ُzu9㔯et^KT}t;s,=usRީTO|*Oa@z6y$u׆EtzW)hKiLqp{m>Ʈ띿~o 27jrc 5$av,D!98/0VAby҉HgRxqY6:vc <sa_Z.2D+uIw|F63~3 V=T}>JB+ͰчPpg2i9+QPC7Ow fXߛC!-ǿը-H`)r+وOb8^,|1Ӽ>\cuzj! V98:k8mPum3^@W o/?ʭk_-abv'L֚[hs=vȋ'Q uS=? h֏ٻ{%7gjJWu*ZZؼ3<ڕ} w;]#U>>}_ ֚~}d'Rm#sߛr] Y`nM̰CEϢ2ݣwO- TTU?PKн MPK>Ofo-Pictures/10000000000001AE0000012EF117893A.pngPNG  IHDR.pPLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712Hs^IDATx^ ܬ枹dR a ﱅ/)BX䁡_aJ #>̨.5:qI1{"uõ bl \"1S֡V*luӲl4!CU Tcw%vP\gCs:T]Y\{. V}ֺfw9cu:w9X.̅rawy´~Z٧x}9!NfPp !<JMg5w-:0]!02͚# ᩸0tOE~bi-kRj9aj]Z79H w)0'Pz"gC TO¡?ᙸ~S^dS K[x#ogP\`<λ"kW9-]CK_VlC\ɸ^"E Xfh^3.jPem!<`B!Ĵݶ*3z}Vs+ w1i]cC 3 "4~W&Mv Gŕx%^ H7v`jGPʊyR%B%\р94(\LCq ]"-1I.U_4M\'`4 \CqfTkX| H0IS.UAIS!(. ¤GT.>CݼuAӁH{=} uB*.ZN]v=wup:+BLʮ' ]:\<]}`袅9ԛGT;ң]ʒhw;G2TQ|iWWWtkWJ hir4E/?~1:043y żh;O  iR`KR{ƵТC˅v}W2> ֮C!^P`_tաfMdR1 Chʡz-j*FnO=\M` ל"\.mu JN609MBz9I1\}|2$ k7cq_4xZ9\r$GzWjK[4Cڥ{qШAV9Vs]LE΀+ѯGpJsޡb^e\]pTxwu/0z3؝fJ4<0 |dͥopnvYwC5vPeC; xh3YpA^y\ai=.׃BPwzFB\Y25eU^Z&nXxuO|; 'ˑ+݂yJe!j?_2Έ|׀0, /;r3-3xO` Ǵ?2 ծ445\S).+=s{6P޵j%>h#^*^8rkmPruI6w.X^r[kb`֩#ΖJJW'Rr_"U,6” Jiݟ0Dq&+^t 5WdtHUFzo쇄҂S\o1,/&XJ'-LҼbd"^`JܴQINm}^L-F5r\w-*.)cfhi<ǻZ\LB{+75 p%D3*5fsJ$u%QxӮě]]5N oB{+OWmz!p~0Y2D<$+A ŠZ{Nܣ5W+c J\A d]`bo 4]Rߐ|dW1JڗtqNX~apJG}(fTPtD=Z1>C؊p>u9Wڥ a)..Z̸ xI̐20=a)ErWrK|0.Jdn"0{"My gqChpeu_=vuTd,DidV3PvQH1z-빱yމG@E&O$-3qhW9-]jFb|W-Q`Rv ϧ׮tn.J#r]7+ɀyp09(;<"!|Wi|Y̻H膌afD58~Pr\.\qY5Pp *m/]]v\R7-imܴ\$Q퐉+Y.R%ƐD+0ۘC5 [mK|VA:vE^'wQxNݸ4/1ZݷL a?.,q! t[߅vkCFQV^wi$Q퐩Wr\A_I^rh xZ:pArEZ%qՁ6zﵶLlh߽dsb^b ˏ7b*SB0{&5 БaC1MռtnyώE57ծ̓SB4k SF* 8.t @/lH)"O Wv{{ )v)=Bt>C 騭%\2BPI\>@w|`HW&=]@N[1YB,LEcA=~9t)r\>#kDɵ UZW]de w,OZZOYcN򶙅Fko -a{0MPqCP#-\ށgtOu(.#A4^ 7@hN6뒾jI嵰#\a˵cp[yCp#g\Iڵk.Ш"V4К׿xyOB\IVtͫ}dZ+auua\u=+B{eǰvega\KNeW\i>տ19&5EF.qa5͉sл9wF~LBW=`!複r|B"N/.T8PO{2KpY`b A_̼+,'o1uIp t.qa}8po{I {`xJNǥZX>Ս'1, ӄJEl'>0%.=69]v]gggsZfwCQŰI:7zk͸9v~w;ލzn[LdZG {vs:Ӷߟ?Ƕ8Z ;W~Tˊ9.oֶLձ#-+s%C#+߼+l.,r.upa*•cY:f vv]`+ ;Wu?J u0ʹV,PDxb\98W<_i&u>." V 8.$ Uxd 'f+k1s\Ldz2jb&ͻӓYk\qUq#P.NZu}ÏK (#i&vcry VAp}KˮVp-5GEC\DQ22QsT$8 L .).+Cp-5GEC\DQ22QsT$8Q5WIENDB`PK>-Pictures/200001C9000038FF000026007119B2D1.wmf[Uu?&d)cbvAVe לlڀv]]&G STTr9 kЌEL4!#LS~{e~=s޻,Sl 2C$:Z$9E9T&RYnqĕ 渼YS *@UJ(k@"hqt[moWڎ,ˇEXJV<\Y^ƋK~=]w=PRwSRa÷>o/Wvn whƸM Uqr;LNxz[_]=jJzۢ-c}K,?_g',BxX\>\s51iQhq<~1^o6$طo_o}rGJsR:t m\bɭLt@vd(32ï2*ï3:h 7[ aƆ_ڍqq8ޤc9*&8[z_ƺ&9/32ï2*ï3:h 0OIo1sA}<7X!Z?f Lf_cAG5o||e.~%nڪ5ѿUZC6qy怶)yGJg!oT-_&<^nEBRCJ/~Fi'^ | v*.a6ٴi0} oҌf3=n1ZhucU=d(=.Op<'{vak-r]ιkAz'^?#[T튿Ox'oR ǫo"\ۄi?z\~³K& xk  q1VZD/>EP_QCg&nj<ަ40lYAxl@A°U0Ʉ1I MS+ m0s3>O'؇9?mZ n06av»gt`|>|0/$ csM+1 k HqO?&\cj,O 7sȟ tW#?0 #$:a_;ɶށ_>Xf{Mv4> 8&q-Grכh41`b&x]\I10bxaR˜ cTJ20waؖk8\F[L9kr%c,\n30Our#Gs vԀFp@ y,5 Scc?n;`|9'Om3jϸ%\opw o0#x=OF|sBs~u^\N6f5&Sf|WejBSjLZmjVɧLjjvSvg&#!>\}9ԥs"_]4?%\wʗL ~U'oU<{/%huu~XrDܤߤ6!}u}|)91>t}Μi\[BXs}+O>Lt$JI@a# ֺ^No(B';9ʟ((!E$-Q>O:tlݧ%H%>7Y{|S^/d!>D {^wGϏQf.3DS"j#8##C۠cfL;gjfjݓETx9*Oro|\{כtO7Y~*1M,/Cƿ$dc A_,U8<'k,Jf ' ե+:P8٤flﷻQ\D;[f3n9 tngh\a0 YsNqa:d~7h*~o?y/[ʞmY˭@dcʜRb%_ቜ)/># #xp#;,,0g]:+ xIuDɒ=4fI[AM0(X`l]* ZrcAc40(X@El,dI M֘%m,@2C{ IA$3t`P1h0(X@*Y:PL \ ,楂CAC00(Xm y h5]aPUlbؑ1{jW?  <,]!0(XAy\Uud,@ Kۄq?Q5#a1[ 8av4P@ (n JKyq0(X`_qEHFaP@1;'ս^<_l&,/8AYKQ)ETWNQ+EDOyvc-\aE=<_l)&x"4nt& (l=E/N71wld{VX[S&$#1qsRs1DLGf"v#:src#̨MgJl+QV4QMQOH*4NuS]y5`$֝yq,m*ǔ]Rؾ_K#XycjCMɶ.Y,<Ou\9f[Z/+s& +EQg+T%MkK3ǿ>: ؒYY$ۈU ߷ ۫@EnXw~>xc k;d{`ω@e#glK^"p;ffFg Np%aڙ2zR 18-g r7s:Z^$RK Xik:2UΦTke&XZZM\1Fl894wԓ٘C:7 px0JmZ?\)u)!Kv'6ҝθ(y.GbXxݪX8uԌA=bKEN2;[dW ;U Ev'[ Y"XKÊ}4z.C ?2*c+u!#Zŀ)zu%lHb@=l@%UIC2vv%K /?>걗 wuE@e27v_׼rL7/EL\*VI}P{(GDOx"Hl>x2e{:6S$kk쉮uIf2)dv/\^ZEXڟbĬo86dD6;Er2潨}*uPQF_y{!lW`6;8ߝ5Ȟ ۚ`CQkGl?\ʣ"8dO; %qލMp" d\V} Y[TS՛0Ǩ969h1{my̦Ux%}F3ȆkgAmsd}2Wzl9qz*2j/\YqU;l٭\1EvP"I* }J$9#GU] hCŀ)z`Fd`စL4mwPbuPl콹GW$[K^E6fC..=bQLX{JAdo8"Hl[@™d~u֓58u#;`oZl6#\Tr:fk=wOOz$}Ͼ_A],^)\-*@ɅA-@֮YuuvX#HqŰ1V ;֍X "6PCؾ{1لx޺7&'dO!k#l=buXdi` dC2>&q-VS$A!K@])RȊ+ﳞk[㽁~<@=o~$^\2:\ֽ̐ے !LLz{;؏5<ܤgcwR%8^>?`Ro}j`&C yϏ@W d0{,M%^ɢ1#<pm,x\xwg2Buּs9^Pk -^ׯ)JYd:}:X w)AN#bVG#gdd'{ͽ߈ G>tHVi;`%Zn놠Ǚhڮ1)%KVO39b_&wUYOP(:nTMYBd Oy4)uyqvO_EE硺SӐ&1E_$둢dޱ1]Ѝ #f]AuaM~iS<*B־UǷyzӽ ILl/.f" ,o&n\Ф#d z:tG+ƛ/oGlpr 6jЎjA%]-hM0(X] qAnAE rWŀ)bzZ) g7C-:*=rۡ.55p2şaϫn9Te&g `6?-jeuVM(lM:Ik.fկ߭2aK#pUh|8?->c;)^ m)tU5Gd[QE౸!Ma%UO#G:SsP͍yc"dF0Ā)3 N@ [] 4<3w焯 Ț|IXAjW!G1E{k uhk.9@g)R!jGV gu)& eINJ`w`mG{{ ,v}[ZE[(uֺ^Vl+DL7o\&qK \1 bM֦iѣ ?Zp\6aaNinlI;ӣ`; ڽJ[=p.ݏG2@7MSrXyS:[pE[ V"Hy!#ʭmYY g=.(YmE ,p?3rS$ `YöY 1(>-*bQLѳlݍm*[)YJ6iQǹG1 bM.l}J66:.(% .s`de 8*}uPlېMRβXySn5޵>0K[gà1E {VƛɅc{+DL%ȞVlflvftM՞ ㌼h鱏8}mx]AֆJhu{JxFrOdKu qݘMsUu7ƅ@x6O0@jR_|Mk:K]}S:#lTۇW:_ zY|6ljĤ$5`k' YV]! 蒊ϽG-XV9 + Y17: e׋r<4`%fw`u40(Xkʍy ٧\`\6Vuk\iZ$%;}7ɊP%5eP . ho<˸] PJ֣r1`:F0(X@fH ¡>D`%dnk퍵7foypr3à`gwaPvPctM PJX{c''WX`ڞ=3 x h5FD`%dnk퍵7foypr3à`gwaPvPctM PJX{c''WX`ڞ=3 x h5FD`%dnk퍵7foy䚌[=@(z@6}EfXud?2uCXɒ"&J1[f* 6Y }*APQ|DUVyT I:Td"bqJPDLR"n\P]IJVč *Q B1IɊqA%JvA("&)Y7.D.E$%+(dEܸ% Td"bqJPDLR"n\P]I2IENDB`PK>-Pictures/2000062000003EA10000290A705B22ED.wmf] xUE>\@ZLk1(k AeYAOĀdETPimiEQvN^ h}3|S=nխUD4.a]"j'DǞIݪ]k"E-&&Q8{ãhHLBt\6;[)::pN,:>\G{ytTC  oFe]]*׳2:keY w %;Vrc#5 %8~ 4?H:NOlijܧr&|ojN_Iaߴs Qt#M!of-9f=S*q5)㲨xsN!ܗ(K5kA>@%j=kXjYtM3݀|1QsY!䊆G-/u2AxzTOCevpx]pۨb=^q&XJx;v0^*Ts;"PU#qm{I7}ҖRB #ݽk4ػF\'^VNޫ5:^3n:^omnpY}]\]r {ցDW'xuW'zzu*N\Չ^DN4t8A1r{n}JfP},* ;qk/Ii J9.21Rp{pW24F.2 qa]Mf#p{ 7Wrqu d{\ e$g[<τI9g"'rg{vGE#C\xcN)R. 8쇑rXo#=2H$+{ yL5R.b qg~;F.b qV湨}ƍB\Y{ϿA>)y8eKc"68^FE!.*b"!.<'?rH\JeֵmW\d(ą9t c) qa<'8c"siUYi.l׏séʎpزr/%j$&iu66,Uy\d"mCW1vleR2id^3o<_+V BPc's!~\\[O3uعEid:o[,l{@c7&M~wX~c~ci,7&R~"o-'S tjdH_O:ȇ,|N=C#?Y wvD[ thdmO_sOg嗫/nO*}n%dCeF:JJ?F~*Xej+#S] u#?YKsƊY~_W@ñ?F~6.ď1^{}h=\uws0<BfݞM`uKw.r3^k;B~9iqwp++2{mEr+!C1ro*82 "%d+[j#GND#5#$s^̀s!/>W9ʷ/B̙4#: d3h#GG#ydVy)5cIqmkXqqGJ:z- dΫŐB1q!/G~E~M6ٴ&IkSjN;Ziz*IZ+V3;l$iͮBZMܖڴ%IklҺ 5ȦuKU!&4o(6IZӰi"V[/-ѩJH_F&:܋StEir,ߒFM$idF>e7iC楲~:X.\ԁOfoz IQIrfsU!)w8ENSqsT!$mO$_tkژmWk;yIp*ɬjH{U$۽qWefq5[a#C9PE7Rh}wXzRrZX NEtMV)cFf`s7BBR9;~5.#n;<%Ѩ6eїvČ_݉^F<]6(|ٜ))ѥ!dӧ@_א˛${=n$?=AN=\R|/*Hpc?Om^o|R~+wwY)Un@>*sR ζaxM$}Us ZNKeTθTl6YWzF<6afH{-z!u)ukTCfM2!~X3l\yOT":c޸\cԒ4_"D#1NvK/d]?ܼ7HܺiuI~F7gURٽK!Ώ$e} }ڟn/8e[<~JH2η_A[xNmj?D8ܼj^cN;Ull7|N^WmC)i+鶏)sשdN탟'8bȦvh1f_g;NSg6mg{gP6mg:d3ϭ{qsp/|e-nxf(e4I`I]p?(- SK?!?LRHX~R?Rk/}HG(i{>תsrRWC-^،^t|,Us`>7հq6^Nj_tGU?+fʔ"Ǒ[.<'9" ֝ZIz<5\o^ko/P/RcM/G9G9_d'̻>71 ݯρo0'sm [_(,~7ڵ><3mʹ W0-Pictures/200005BA00004F0B00003DD43C539478.wmf] ŕ=3 00eTP| #hE Eʀ;(1ncD J6"ˆ#X4jV1(jB!FͲ]}6UߺU߭=]kRzh?ѯzUqn"F"Q3R?sqe1  G4_ tI&uG{3ǭMZ7ˆڄ4=ZZ}8>ꢜޒTJI5mmۨ=.7A/=16׹2[qY,[We2nGf]Ǧ8FϥNj;ke%}0^\$~s)DO_-l*Ve7 0'gq\7 9U}mV+hTA˲KɁ&Yqe{;kIm) v#_c0\Xn{  i{\kcwSm-me/q?;s^qX%[WJcJtҀy|糕9 > cOg :\aUzpU߭fbd=Uq 9缾/1<_)u IqŷSBec ms4JλJE[7dwrl&ΗFus.&՘ʜknsU\ !ՄrϮ| u9'.q>sœE~mmoqQzOQWxQV`Sx?QxwWxwwVxgwPxSx;Px +X_+V>Y?T [o( \LDKT#TLOS4_>\~/S@T ;1yÞ牂9Ύø3U}VZVxoUx[oToTv7(Ac>F5 /nnȞ;G6{gq|jw  _E _ ߢ- oq  _ V*|7+B_q}w⶯vy$bX񒹯/ m0}mN+l"cj#+Z*{+*\-VRpnA y 1 Qx }QꇏS1T}^%N,>\D^:1uc5%fĖ6v/懯I>^|\r!_lH!c6Nxޜ*dn]&PȋL}gB~Ť' !o0!c.L2r ?2rrM`_k"&2z y9>DȘ%減1;Yb2zrM%/FN+yȽr;%G|=L,ð:XĚ!O4!Spk0GtNCB^^I&dq& (V u|F{BIB8sT^B9OJ!w3J؇=!i9>Kȿ7 sIxjSs|wz7:Zp1r11 c\12Ƥ2Ɯ yI1CĘXo,g<>%9r (dGK9c|u |.?K_qB'' ӄ>*>k|@%G |!rn  >$E:U>?*J܃h9NRgx;>+g~G3ay`]$tM˗@l+^Ȼ}&ߗcK];EŶ3{>\9b-.6k L*? pĶ8sHGs' OQ=48r3&t^yߛϰ7S\gpĶ8͎r.23#"GGX;Ɯa[B9b[\aw#ΉYY2&mqq(m:?/+I#Gl#/wk@ {1?m"=+ >`B_IsƜW˽oH#-bLkzG]q}_(GG% vwpĶ8jc{;omg#7Gv{ϏpĶ8{q>[YrQxEG=}+|w;[Yץ`_oIF7:wo#n1xO?48>MTOZYQ?o[G gG^ox|՟ExopaO済) mqqty征GQ?48t\sB9b[\aXnE>:dg#CGIIzޗB9b[\MUmcM|j >"GאG3m; -.n]>+mg#5I^Ϗ9<Gl{Tz4~O ՟E8' /0tlGU븥11?qLV=iq'$mqqjcK?ɥ*/?2xC ՟E8v1 ^5^0 _Gy~8O_YYIBG_s(#ѻu,bωߍ?ѧFtiGv3#1f?qu!zIE-.ߓ0d\p\_Q8> [m]?#⨴_ y߂xi "G@!qۈ?BK-aGyGyEXY䈿GAbFLt#/l0|h >"G5^?2Փ-48oK4-aGyGД|՟E4ip#am\(GlKX #^.?7hac m ?͑E 7_dg#S=bYFc m ?83 4_jg#C %4 8b[seWZYh >Gϑߗ֒ߗ m ?zԑq,_. ^7qz/Oԑqa~&#"G}48BԐ#%,G^7?Ɔ,r1* Vc\ m ?OG^Ʊruy "G48B-aGy޸W#p\刿iG?|~#%,UG^?V<"G48B-aGo92D`\8o>O~g 8b[>peCFcV910?BpĶΑquC-cwGg9hkJ{;Iّq}[Y䈿%G?WG^?9%GxX,q]QY?*O# GmpĶ5w8O[YF!wG'm ?a77rY6IA/ 8b[t848BtLؖCv3"1cV9G?Z⏺$m ?谛quWXYRG=pĶuv8⇺G 1KV9uG?BNMa7:%-_gg#cip#!-aG=v3cY&\!?ꛀ#%,݌#~|c Yj8ӗG?Bѐ-aG:f\(_Qo'⏮6t]ؖkv3xi GYeWM|l_/9aKY.t: "D{.ϡ!.u<|QuiǤs(f@Wut2Z14ΤFHW4&%~sg8ni[M,הkP|/{\;9ashR͹J;;*sjSӱlgQ/JU.OZnkU7[B:6Sye[2-~q2Kqgw]QvEkM8Y|#/aؿƇ5Z;׶Mme eq5$ﲺǖu-tGY'PŕҖuyu\0Ǖ(kX|ʧ^mYke-ϻz!cl[Bqm+ z"a˘(cDet,-yqYWdK篑?1ō6Uni٦#7炥,Sas>i=Pz![a|-[fieUjj*6OR߰懬؟y7׍C]斗ݏs CjΤ;/!Zk ][wԣ~|i{r߭T5|r|?}=7^֘B2 uyM?빆<'Qauz\(dj̧6+vRU'ikM{N̘-[S{u;qSoxͮ=n(Xa711̇}r1~}SҠ"-?ݟQ |W*_OA_OI|^(|ౠwQ>r :َ㛾D1x'?`}LU^H;35aϧ5H+2w3DY[;(W6^JK)OA_˧ " sՏ;5% v`H^wG菷:~t}Q>sՏ6~sMُFR~h$i$3+=y\ })gCA]tcDVO"҂|)0˴;.lƷao[~%E{?w̘5֌WLÎ2GW8NSc3rX_ɼM({6ncgt(?FAF;o[~C{ ~k+<|w۶$ԑ/>ms%%E6˲e5G:KD}<+O:_[3(2{- k3W!s}Tgǯ_=״6⚢2[Y8PKzehPK>h-Pictures/1000000000000186000001155247EBC3.pngPNG  IHDRӬ:PLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712Hs5IDATx^ v* qV]3\c|NOcϿ|l`6h7xc[4`50-,E#X a lVÅ0ݢ7nDS  pܑa rtA1i>w.[{O ?#( 1,C1̾:cDÞ)fQh$ox=E9;?D͟^02 qOQ=%_aNoh/5huXZK,uвВ3%fn]1,a[a - 7 T-\1 1l_^ Fx/pl`3Z  H AtւJSwqnLki+dXQb"VaVT 81{8l"`慖 )Dॲ*8C 3=%P3aJ` vCu d))ej@D^s1VdTHS*ȍC7ymaUkXMcNBװz0Ir8tArQ>ЗaN:0h0`;;}ֆ zJ]b AV >'-`8!HtJq>0ءjJW N1xBvø^D kbj(]O ְ}ppXV%A< nΡtlR92)`X +_ҩkX/,5@@V3߃|ۧ#D H sSĆ04_=c^)+3[eX bbrJ6A_Yt;sݪxz3 7 Acuz5 j-,b"5 Ƿtl وAր݈ğƌ=v N)?#N`-vpsS%7QC;A'@dw<C%[a(w^{ b3prDa2vJN >)}ooDjB15h86LW‡dž NwJȡc`R` 31)\vcf JAR)sM5`(0"F0(lq p ع ~l€cMcC%6Tbt')\vƆN =)R߷z(SrJE1` 5*67`6O 寧1ԕz C/vJ)0M1  ]~ 3ɂcPI1̠ Ƞ0 izmɡ6`0/!듆{]B~с@ Zz`0(alapv½g" _jTXPq.cM0K:jCJa\ שڬz|'~-˼y?T<5X aA^1h_a*[cH}s% q]|7&^(:ӨjleW|,9 S@ƷM=ODB !r $a,ZE!h0~]8]`~sɳ0apbuHc^6ALJG7pJiµE_F% |\|U- qiWƇhQ qqu9yiqJRNq0 mZvQ辔oS3)fJ96,ͱakb `^}=};L# . |#f=%0KBؐbܬG0z`?ɔ lHo0\yS2;>hɌMK0-3ưh1la-j` [X`Fآưh1la-j` [X`Fآ,fIENDB`PK>-Pictures/2000074700003EA100002973EBD9240B.wmf]{Vŕ?=|$)01QCXMV L Qa4>pFEԌ&f]jY5bj*YJk#[g~}j׮TsϽ}uq-fWj^Et;mN[Dc=Aޏ_.E ~xz#I9btrv,tUDc}5Zggb=:GXy'{+WVh9M5USouZ{{;ʬrg mOqpvëc9+KF9I,#?_!9Hc O" {>_L/9:3 ZF i/I|WF"uơˉzr1hfvp"Lyb|_Y~6^HfEt"պMcL4>u,XUF^A|>h ?~|=N^-.hXEӋ}z_ ~:Sۤ#ߐޒ\tIoito{qEh?r i[k3%:'}l+Y3sPw7,)Ңnn<$l$N%w4˴rV7V^:ݻ͏ga5v#}ޟa7|EYg?Da>8x7z{{*_zS>e&sLqZG: nCb7֡uзzv#zbO|8וU ]L:=z&8L_72}CcJޠ뵟1[O1ӏ)hߟo<3Odb[n2C?SeƧB?2S巯+i4K;x/T~{|ױuOGЗƟpݹkr@եr4~K4ti6K^ i0i?+i(n9{'r 'QMqQMBO1t+˙+=_}7Q&-^=2eM7'z:a!p$ p<AO'y:q{:1ӉN,tb@'x:qy:Ӊ{:ox:[ڶJ51uoq=Gcg|˷E`eovI~wi9κHH_-Zub~f /-H9u9dMX‚{XdlDx"F,2 aA;,Ș0ሱx6e+*?3|HPqb0pߵw?_xvB&ggRv¬y8#>vVX<ϳy@ ’uŵdqY’(uVX<k){GVXiLje_|yx)|IkWR۬ycim`>Je?6,TYaIkl1 Q<(ΏKZ e)(F,imYDuX+w?8wwLb. {1:l c3oLjO=l[d&ݤ1⓽;!|\J_n@-ez9kd/R-ߩ1y ?F|*z;@z ^>wNk‡Ǚfß2=yӴ?F|/o2vgN;̛1⓽!|`qřNdz2&kde$b>:ju̫elGX9h1oLjO†ao X1ƆS#>‡2;g2s9kW1⓽!|;Y~ƦGN{.#7Rc'{O27ZYw621⓽!|+=26΍L]5̿Y68w05]c'{CF|j"_Z8À0p]}lD/<%!;I!ۙɼڟezzi[(=44  n`y-#>9"xs6O/ Oezh䜍4Mo^ ɹ!icL73g<杧1sPҌWϕf2 ̛1s]!$jG3oLjOΩIEO;0YswK-N.Ù7\c'/_\KSHcv>ԉ?络pp3hcGNi7R5N}ԫ)5NYa3BXkϖSkϲ"g-&B  ^lIeŲ5b,r>WKŲ'b,r\"+%Sߧx˾'PuQRb,X^!,eT r|3LjEε al1ș!,C2c"牆[ STkγ"g̰.69!,*~~~|VX eʌV(svHXcGf@dE aY[9%F,rnqgG3nc"g.Ǖ߰beX7u2{4p.M{4"t`=&nO#"g`M7je{X|`x^_DEvaf)#"҇ ?G]3rᮋ(usy N8N05YMu&wO *d%L]ɷBv&9XW1 />}WV2~̛1 9̧?H;2u;cķ%%--|g;S)܄{{JȢݗ:y_{=9bv2s}1vLjOUOksqLOb$|{'O)8FdMɷBjᯔ9EPuLϼ?F|m>|+z6IL70Ac'z ᫴0LuR1=yӴ?F|6pV[Vf0oLjOWәżY#>Xe֋U>ޙj&s7Gc'J ᛧ̚1>߆@fz>ko!|W*~jeu^b-a~fI |Y\8~>L/c2|/f e\kwLjO5‡spk+_mwknf^Ljs;kRO鿕ULʼ[?F|-ud!7uL2Ucć9R.~wӛIc' ;~12߶[Uc' |d&lL1Mc'R C:#3 )WLjO 2(| 9\3}y?F|4m*NV+Rf}潯1!.m|W틌^2.q XN{>XWp۸*q~XWF*Qg[lw׵W7鉿f=kKZq9/ѧe+:/2wED/'WV4]'R04\V41= {W54 Ornڎu}ޜ>bÆL}~}bFv-dt邵{-U4H~5Xtkq_h:e9nY4ea-~)wT㙤u( 5LƼ۴?mYE,JeNPc%R2 ovnwme!pݴr^(Bv:?8VZ,t?16-fcGEd v6.xεB&[tۍ3~~K?9e*@7qZW\wWFC֔c 87L6f:fv=+{ˇ,R*RH~QT߿H+ X]F}J/=f;w{;ιGކws&չs%絛txkD7?8m*62fywD:ӳ"ƒpWx;Hxb=Fet)BݾOvU4s?״rw[Y;7}v}~:rΡR)_H+_9W(~Kf֡/dZTKRϡݍۯlpF?ww\-4k{:#EYBv<ԟ+%}+쉮&ӶQn mߥ?IuVRb9چi8Ѳoz'Dsпs 8nٸN?9TwYPKPK>-Pictures/2000011C00003867000024DFC0AB93CA.wmf[klUmKyZ.R*K.-4D#" !B` W H DZ+!*1DA1 bQ KR2;޽posdwv9sfϞsqh>j'=1s:G&4uT;B!KL ) }7vٮs0m i[ڋ]ߴk`69~j2Qx8!ϓmnVHW>%(\ͱSt XK`9b(aB#w߾po{VWW7\}/>Ƽ~KNjwc::\'v@;2 4 Fμ.z1 ~b'Nkn+7>/w}__z+% |C:8G|y`}y޻ξ'ֶm=bbpR|Lj:~{b@ 3 :=q]W\$J}o%l.{rDӖ91?:c=z>N9$/7dq1_߰!ss"/7n{05>kS<N9Vt=Re_V6N+[ޢ&7)|w(A _ Rx +P='2?yPdTsX69am%~Y麬? oQx›ޤ ߡ7(|*JU +: qrT៫%KޮvtLeYVH.$_~wy+\?Y?Wr=_Vex،EE%%iM*US2Nπ?Nπ?N}K-e~[}Am=CSϿnss Z/ sQjPqx^B-IeSqPֽ"m\46@m8ellq*V$ێ_(9!6f7dFgXnDάѿۢ[D!W/X,D|Ƣ~DBO5gXOU1oXEҒ- OLɶ8YSl*xv].YEr^  ^0TA:͙u\1gozB{7c14<Jxhz[▟x},RrLHȧLC~=7%յ/wA9 3vv2GAb 7+gSHc/(ׁin3Y{2[c,h]9_K`ka(JU?* 1h]*'Abv7YW^bFtͅeno Űۭ-lRJoW^ ܕ}Ŀr*9E(C~C.,6N퇍(bNr ?Qڰ>Gh2 ޞћxx22",oJx]Np.H9RԘ{ SNQo%Av(b.9zO3\ɾ8OTj1cwBp/]WlEEoWk 98/YFx(6l~σ!h}g6Ye58zn-Fx7[87"gwOSpxaksqґ;.r'J4(2F"<[#$?3mrq:ش/0PK7Wt4PK>>``-Pictures/10000000000001DA0000012FEEDEA63D.pngPNG  IHDR/e7PLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712HsIDATx^gz: EF*KΟɨKA) .Q$+ϟgP]&{  5z`XavX +̢a2j?oo"fvc=히-!FwЎvSdh S=y Vkz`sv>v];*[kF$M!kڢvXaYa=00ZC@߽oਝ.w@kQ}ZCkh$봍.ϺCg^6ˉh0PF ,򞙯E{!zV=QevyVEC"oyq[$E QSQnϑ:6PGnvF@\R$tV -0(\x K4eIq+U֙pkձ2f$IήI ƭ/_KNrcDqF$RN@.C!E vZŻH9)YGΦ]"EaLGe6I3A~I_qkKCugWY#$2FZM̈ǠoY(>CJȳLO_c+.Q 4K0$EK9 Y[pv̭~͆]2j;"r 9:D}+s0%ZLȺջ)M%|ys'-ї V ݘ/.d ]gP?#K!BVPTbfiexyA[oQۡ 75$" 2(eJx_5VDl-Kn,M,̵Vepl[tf{UKZ糺JZ2kQ![Z'oG9) ndz)a͔tKix3o9Hb sY#BEl6kG6 &^jN qOֳ/z L'&Ѫ-LCTJf'[U:"Zh3qx_^m+dMn%.f0&Y9`Uz-f+Gutvz$|{n)[m:!+9 In"An?5VZk\.Jٛ"O*3-ɶ$lIDބ4\dtF"ZKuqJ'}Z89uкw}.k6s :EW5UFolڨe/zv<~h~#%y~%[yF%]Պh؈QeFRLتmD!G>m,1 ,fϩSBj[s[-rslfhC+[<ZtlmT"9)[i5#kmT*)ТF!*lhFcQ.HEcBA %#M#sS,: -RE&r/kZi_xuVZky^j9{vWVDͨ=o\wVj|ˠ≨\l8lthUcVՊ$"ot:MS>Nܭ57EZr@JVTmAN^JkeՃVI@OERaFVC.N.~d:=葥h/^>ZZT*{Y&6QmwDj8X;]}TAY#w-bD{& (F.Jk]>6\+3#km!3nW&Jh . Z2Ad ؤgF&(A=응YAyWex 5zvMT;Rr◹m3l\FhmOD0=zw1C5KZc,XadH$# k>u>y8HF6 戽٣Qe2?}Te>[̅Ȇv*!7;Zh74#[? ~Fk m;R++w&X|v0ȿC\+ h&ƙPum-,-qCOX9#WҨ]2E(׮<8ŖyW-kr/kamThgCel쉂Df>,a*<0$ìodh%StQ[:u96 [{8]o#Oqghws938GxF;ƻ91ljw^ptk^mƢE 6x-s ^pC[FAжƇ<9 Y-dH5Z-M8 u d1uZv!Jm-B0?5vz2 RjCsK>8:KwȆV1+G1 `vyՏEW=jmP 2,jZ C DfDF RIݣݱx*ZR"ԾZ5oTv#a 6s8ԋL(?Sa:d̵7.b_.FOŏu(haw,0*j)ZN?IfntL7((磧6n- Ii<يQ~_?r/-LQ+Bz8 -P\㣠ݱ풉ZP :xnF:d# qihbh?5ު( +   >>3" Ph -hOؒQ C .!ںI-JdЉJl0 Uk2xO?o#VwȆVxG 00'D7]ǿ 5}g-RGT c|-9f챷=xU}2گE|:I4a&# 3)9ȿc$ q\^d3`u{;k~% )Z','@~YlԞDrJhIZʁO1vVZk:Bcoy:ayƞZvQߨw{ 3)9! LmC3B s4ja6[t^\ɤNXT<J~eq+^[QXaC$h7l<Ԭ%:7W 9io#Il֚~O{6[=Z'H!ўX<HֽaL-,Oy=ZUMc#N;J$K-X'˦#J9fHɲ̂ ڻ TeC3B s4ja6msoyCBU)ZXyuf l#R! ڻ T nϑG{'`i%]H -颧0O%GmhI=u}*9nCK SɑvZEOHloc  <{`A=c:g3(=A6`נ}}A{KXQkh>vKV7rXa.Sn -!67H%jw@ahoq;bSComꆶ+ZMov 1Vӛ]eh¡ifWkڮphch5Z+ZMov 1Vӛ]>K )qIENDB`PK>-Pictures/200001C90000391C0000261DCE22F4CC.wmf[}pUG?兄֔@bD&x(XJ%iltbJGBK@0 2JсEq?Ff͌N(vl;maPT$P@jyw79˽y%=s~<}n!cQ+<:x/QUEY]|9P}:JXXԣ;e7jsTs,ҧ|-TXi$n+GuSK3uRj/gLr Sdqn[б[L[fuu}1SĹbA }ޜ'Ǿ`1:ωr۵edxhO_~u>y:KWzq7붳Ͷch-y!(Gk~\- ?_ύ,QxlwCX<\il4 a)\Hn.Rsn_"~trcYTx!iGב~gwUC,~ ciUugɍɢg ̷0 ` \ /T k1/[AܘLg coYW~ڻ hh>G!g4A|p o;D\e1o|ct 91 XCca$h~ct{$J981%9'9F=%Bb 9& rOȽ~?ɭ0(,9 K’c~Bc*),9F01:I9?),9F(1:'%w$sP:p]<la~|6b0 x7ă}~ 03wG.<r4 '㐣6x}A: 9 1Q-N|#uB|*gp Ny)Yj/^,:y [*<3k Xn9صhvgn;MaW: ^@Kݵܗ&Ž(!ͦ]7'Ž(^c&Ž0!M-_L{a N{,̙L{uV%cdme’6?6.-ou81cĜ ގSD\ןe1BX]2cc,[M~QW3_M~I}[]2'د66 _/?nl`x Ʒ/Nߦbf/O۔gɟr>cߩw2<(ԾA9b6} c#ɿ' wY6qy-mʣ27sgXg?c [])q CpIݘDJ9O#w;w46|gڴVwcY}g>_/#ir{̶z-~%.aI?*>-|i :GٗD7RƏVPu<% r}'1wzʥ;˅}sݍ>Puc*ot~ 8[_aB+_Z.2˷T+y 9OYjaXCV7ηmQnE/`Rʍy+On:Ywʹ\~j,y|YwAE0Ann"|GD 쨌#JZı=컩l}Nn4|.-SE B71>6 pںʰ+aNaƘD8] A1E/S"fѝB3QLI|ws)%S=:ml^X.35<1둏c-Pictures/200005E100004B2E00003DB154EC39F9.wmf] VS_St9d(D GWH!C ND(#t|T3bFs8f4\qE>rW>bti g짵z}vlg~Y{oS :(D?+RG3P@RVDPga[s-RZSNZAe::melBSujHvqvܩ񸢲AoQTsXQjګq}}ѩ@2ISz׹R[P~~o~ {6vE<Ɔwѱ~5t\̎Q\s bڽU_hQ]/>7"H9\MRi 'OWc_L}jn잵+]ZqT\ϕkr+>jɞF=+̻:t-c:L1˛l f*Յʳ*gf˂q֏xW["AncR(+x?\  ;^&|x9FkS Y/?,P >Ws~oUJ8H08oS\>T]ݿ6D۟K7S\7\ | |' | w }|cٯnmiom| o܍xk~oYkFA/u; d,)"Y%_(U_%Mugfcv9ߺC헯PM.-mv1l/}Q/wo^79=szDw(/LJ |>ԋ/r|O$x5n?|!?"pY~i |ś*yy)ͫ4#j%7e(DwscǪs+f24Oa2b3yNG1a2G{1cnLO] 2cb&7<_}lmGE@]{Ƀ;>r39 \-iy61;|1GR!"UB^HnUwr!aBbeG5 _Uӿ18]|N|NL0t䇬\oL\26W2y7-n'M$>>g|Fwœ䯙|`uZɵg3ZBKAxm-_Ov2L3 |a{5j?uNyӗŸ>w?6n7? zHoOt[?(:O|4MӥŸ?OWB?_W8#5Ld#3^uTx`e2 Ll&әb\pi$OԘq)8Q*\bN0y A9 erL9A>VČsw&߭k+rیqbnSP Q3vL~Amq_yCv餘,ac}TOOm:&qtd1Qb 1.c%1SEpob4GL,&\3q5L#$jJ8b>7E*H& W'ڰ#cڤ=ѦtmF&Xy?[:0::QGbIޝ>5O-'f~ywtLE?zӄ;Iޟ>P"|ϥ6 X"|{:݂Nogdh'PUq[wz\"|`92FpU 8\ (|RaL[|ΤXȾ}}x0K Cs*Ca2P2s(}s(S9? -3fL">Hޟ-Csm#c,͙4 }Õ3?h2}Cc,rDs)iptNl]=.Gd#ᰛ=d?ѻra<ޫ1#Cv7 ?|՟Eh1 0#0s&lqqyj~՟Eh]! 0#0=pD8ӞO:wXYh2mylqq4_9'YYx7G-.T][m|π1Q?!oJa^-K%r|"GGrD87 ŸXY:mPf<AwsJ_oxw,rD9skt2srD8ZܭKZW{6e#cGXZ"u]GwM*&<&?Ѿ48³GupD8BƷy GA 0kG /Gd###/߯sO >Oʤ 8"[\];F\(b~՟E(~) >mlqq4CcpngxYV948^ooʖ?_G7fϱKYowZYh~`<`˟/Gd7"7 ƒ95-%}'M-#̇vuM8+b9?ݥY?)%[v]b=V9Cޔ8¾Gs5,}ueG޵$?R9BFG^7<;V9L#% G_dGFpZxCk,rDɚGZ<%?8sy ߤ1d̃o}On#~G%l?oG^/}wqaI#/oYY䈾O: C!~G^;2w,rDG[{^JԑpwV9]O#]&l?ZKx_{{V9O#!Gu 8"[q%CO<?11g5pDD=K8'[Y~3" >GdKT=)8H~՟Ew<GA-QGy Gн1>"G*ip#! 8"[jy Gb~՟EnGі?Iѭ!~&G^?t{ >ÃϲQ!h2G&l?ޑp.T!{;Ot]GK8f #a_:ݢ3h9Dlle<֜:YLU駯G6: QOnƩj*Wgvk'c)_)OC*Z)ml*ݻ2>1`?1 -]3a]>W{m>Ch0GT}blXJvfS(orDzJuY;||*Kvj{슫:/Xv>7SlmM^'{׉9߫[F^aﵿaE1ܩB-\v&{6s9ޣ8Q=l{8;{ȁC=9qHp:%[׽t:(09#p2TjU6=d}ܡBD'Jtb:Q'u: 󕿇arr9\G@~[]`{ڕw]h[K7'({s9-Tr=~;EOY'L*#qz?A%ܾmwV.ܹeYֺ*پz6HumtS*m~ebVAo5glFky']M;h]@m#xN>k7c;svFx; *~J׻zϑρi6_a|+@}"(5v|7k˔Bk Myđb4(^h>p V&Q|nvl]m16̀6*$L݋R{p1^SމbΜ*K([ϋI\wQ1vw]wFԁtܖQ`&~`l“kNcKy]ԩ"m\u XT[7:WS]&K=:֣Q6%찛׃~1xGϥh#)+(-QV9hPh'gVZ\43~3k_jA=t o~H0x>L!?g.<}s?;jr*wUyb~nnՄ 85ENWjj,1]_ =\Q9(ΰ_|&u/0<(Z\\b[ȗEᶹ9sg;|v2>5a>vR>5&Uzg\?>F'kITΝ>{&E!N'^ۨsm3s=Yցʬq4LjƤc\ڈk *JYPKjSPK>-Pictures/200001E6000043BB00003899BF289333.wmf\ p>!ZhA| HS)AHK$PH+F PKP-V`EbiI)􇱀-GLz&gOvBfdߜs=w"ΆveKDEO@ж՝{=_W~uhm`(g7)vcfrN Cw6Sw@q0]tHwiJNJ#|3nLF15PsI766R/b1e4Fk,HR31~\go)K𐿼'"]8_F/'Ay:tԫ=7oa>{ͱXRZBh)U|R9r)2,.Jt\=uLr%;ߝ+/N\5sVN Xet/kL49?Cs({_yS/y9=}antϼmyV(62m>ub!öU&:5(ggtozsT^Rd!్ xGB+Soc0 e|Ap?p>eyO/(~⿥_7*FůR*/Q}β}' ;w$SA$M'RY_O6oT_U_%Wz򁟕RS%^[ۣ j{ ] WNK\i?6luLÝqdSLL8zkr^sLkz ArwVFb)oSKN |/[_> %^t@ ~i1=- I_c,Co2X(?ntIgN-elb^je[  %0l1C`ت\י>%LDa*k ,8}P;72Q`q <ʌ/,8O錯x㮃47]i?ƚ:͛lyц2rzO "0u&M";YtyUb#F|D/2x9]Tsy 'o~oWɫq)0?^%o~^1ydLC1 !0v-0b7J~D&oo!oL)MXSwۯX1myc Lw a?cSCLw|1(yc )4I3LF(c%F ~8\ ?O6^nW1L`k2&1a ~i7!A9Bb> _bjbLgI9. 1>'c- SoȘ89ruCZbZ%S?C"cs170侣㢙v)`e)p0&F} Vm&UxF6zj=URj ˹ ~_`WI Szz"}wTa9A~Ax@s ϳM!w 9ׁ?m&:7 &Lmt;yS#6~{\Fmf]`ei*ZFgܥ^WIU{u˺ۮ!O'wAO|a(:(O#㠏}!e&u!e O"cGƼ2idL12612 )ptؙHD6yةUmZL>[|dԥ$ PQGSQ(#q㴔ayd Qk#6%E2|N8};vo_65~{Gzmd?Qs|39oUY@}LG&3g? A,/eI*JÓd<;e}$8+Xx/gI]L֮oˈXWl@H;''MmH{]fKvT;b$1ܯv ^OLbVl!Z^ur94 :;bÞ} C5%ܻDn>WkFns%J<*HS0eyєe7]=.ncڎr{%)Fz]C?7x]A8 -1aHuMx^Ӛ|tHzF6r;nZ/+qx[1zұM{ؿ^Lc)?H\Tc,K7#deϦ ~kD߈}G? >^zÖ:x<)nxˤMPK9j APK>Dk-Pictures/10000000000001EA00000125EBDE8E53.pngPNG  IHDR% QiPLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712Hs?IDATx^풥(Os_PdGLDȇ {jiO.@P?L_SOQOSZQOiVd`4bU Ih ?*ȞU#6 YZ%n,6g D6v?Kzj{2)Y;ek@ZF|tԮ޿Pccxf:vLL:+t*z&i hfiK9,v>QQy.WUӲvtWweת:}w 4-6$w<]5:p3C;]e[A|G@kHH:ov{=ڋnsjIʱd-KFs[ f&nV>k璵27EF+m/B-vv { ]Ik +WG]эN˼I~㝭vf^+ aV۾NoyJGcok;[ io Xŧ7Mѓl-WֻO1lK֚p9Š.olw${zy[*Vև?]sy~^9qwR vsnU6<_u_W`Xxpm&dǥ׆l,+|>PFeϽˬA Dֱ>uE@>\۫,!BO=kg똙knw%JjXuMHn+\ &q:kgK,ܠ[0uxD5꿙5kgx+jTSF+m$qoujoQ|R5~lP'+Tt}+CQUr.;x흀n|ͺRsN1&fdꙭQU';ŔVw}P_1K*xgk/$ _؇m_P5gguG!f~R #[e=֪ǣ~me&^8_l5G+óO*zŸ?7_rd~/TWO~rnf}ܬ.d ij2|{/Y "wu5mg+,4Wwsut{'/+ @Ԡy8\r7Jo!#`Gv@^H9ҨbjvھG87_":E-NIǪxΑ>m Eh/~Քn{/.HҾPS}Y`/#(b(5@@}Yv t@@d_nBmǫh9h]rME@}.ܜ%ގ¾߂=P8_>k4b"ntM.-5}Y3s2Yˬ; AӓGYer_#YPH_E>/F7uPCД&FUo/[85~uӨug&FU:/ē6~ u/' QUd쳲싲Ǔfߦ^-g65}Nֱ}i~O5Ҧ!n#ަ"5 LՉB^'f]h>:fxHֳ蚀UE^ZxB]/f]*4xM@"oF;W%%9O L3Ԩ*.쓨I,k}Â~uȟuM@>zFki a$U>@ًd-$o@ԄH"%5 ZQj? ujFUJ@BdI"^&Q@@M \e};Ԩ*du`/̿$jC9敀U>Զu4Z [~6paTROTyT=xؙ :XS6$FU!cmP;^f QUHU3Uu/3_\z{bO*Md6J@MAnVYRN@Sa}݃e#j^ې9y*ʩ+jgjFOPUNHPuIP3UڢfC, 9TYgs]xF@pjKwN@MUт:?Nq`'$FpdVպ^5WEfge͍~'6ڃvo+eQdUM _'/cJe@wj2@{xbגּ+&K^[l!I@ݛR2ԣ4}8 *(%C@=Jg7ձdGilqPUԛQJzgpu(%㣶 \(m,ΔoF+ctQ*㔨t}f@QɅ&$O |i3r ̀d t}f@QɅ&$OO.5!}T}r!D Iӥ !*EMHj.u\Q)jBRtBJQڧKE'BT>]x១RIENDB`PK> ``-Pictures/10000000000001C2000000E5BE9F95CC.pngPNG  IHDRO`( pHYsodsRGBgAMA a cHRMz&u0`:pQ<_IDATx^ Wŝ^ޙw昜{75bĸIT}G FQ"(j Ⱦ4M/4;4[7CM5k>\nݺ˿ZUWUߔ6~" Dp!ۿzR]]}ȑ;w?onxuuuW]um۶'N\zݸɊI @$G@WVVn>;wn޽G~[@Dǎg̘f͚*#͚m#E# Dh.[x1-//oǏ_vAŴiӦ"&Hiy7TFI N-[7ߌ=5:z)Rs7i$tᘖoo'RF$I{.zsڴi!CpaGǝgΜSb[Ϡ&¶mny2r¦ UӤAspޤNFԞ%9o޼J<:ARX*87-:GbhRީtI4#;#Q'#5U4¦ G'tˣH#({n" \Tzp֫(8oAGj)lhP1EP<:7Ǎe0͍SKTYe8`P:t萣 GjnhHUvNxtBtra/\ލhҥKFlFzԚ cۺ%?m;.Wc@G'DxtrmgӉ<-|P4YfH,N X͎Dj1lh LvNxt"U<:1/\PEalأ Tn C-H d,md0NFJ ƣٿ4^ǑbqNfK.>"maAqXJJJ0JR,t㓀ݣDs 4ȔG'zvbT-DXҊ+bG[h۞шB*xίZ<:z7駠ZM٣ubPhLnNnTHtEj4r1C/:DVha+k2_4׼nOOC<)d|m45HX$щhNcKǹ 504(ړ'S˖- K >J|7u mRNGj4,{/GFKщ]xtbvB_,0N%bY%0ܩpS v!qĒfРWf 3Ry&;)9:!:xtFwڥTʠPʂRiM?F@iJ:\UzWF^HgE ~Cu Rha.z;m޽cжnjh]j٘FFkC9ŶnЌ3SL)RmK"'0U+9SقBj5)q:U剚ըQ%R~z+N a$@#D'yA!5 MS!Īj3TgKT:Qo7gz% ݣSF7K'Tْ y$dlviy\Po 6fX@N+oJ@ ztb'f%{ǎN99T4) c@XvN8J&"ԀDÇ;? ӠPJkpfOmXb4dd\6"݄yIH&G'.)GƸW{M/0^xӚe]#h`Ji~": :LJ5cOZBnnOK>n،Ԣ3+I.,0DAnrԠّFjij3_Gmytb`4!:sqv޷oDXEuiV]oAQ[V$"e"8N,_NmFjWD> ?`\2U9?ʣ70s=pca,iRF(hhR*XXNn6?#5uGjh6χi$ [4َGӛMjspZLJpXe)d߿XRԨ ƣI6r&L#xM'`8?Xxcy=͊8XNE4R̈>RXy24T'RR݀:Y te8ڊ|NR;/ԇd?psWpg+:+LP#F`0ǢM|yȊ#H @ mU>R(jIO8ʡCb\'[1qD:~~ƌ<_Z^xiSuZ%# ˉp|.гGj4㔡N~ L^l*0_*v]huE1oy= /WLynDjQu"9T'M&4K~~S|so{ڄX3DszEo,fk9 3@̶L8RtR|ӓKِ!C$ͬ$}\~}_MmB6q/6XuS'lGxڟd w#is?Iڹq WSQ*E(#҂7]RRmJ%KcȢ_ݗrv7S T'r㎐ 縇It2X;] nL7yfk;`M$xBpg}zh>e@A}]M?S 57͆.]v{K*l%wfdxr:9L ~N5PDi3*.  %ʈWAzًqG\6>3Ԉ?=+a-ƥm#r 쪛+|Q]9,qT=0yWR7PQ<|'MD*ٳG  r +w|U.lH$Ϻ+ؽ\IǧR72aMW^ U1bFC(;aD+21W Avpsa/ Hµk^uCxj&H\X n#=+ yۊ-SSSf*uSQečQ 1[/FmGe#x*ߥݫ;,33@Vn|Hegؒ찁sB#5'hMOy &{FbfXI1”)z]?c6?g T I{ 9xģ9pVJ;QFqĉ ~5{}18xS N}~˸XM2Gri}s9_Hݻ7ll_FͫQA=qGpa: |EOaa3tP^r 뽌uE2[1sD"agW*cD$W9"5jLZQFؓ?=h(wKX>YlItsUY!,r^S~6HiW~Rp]J8uFA =AgaNqy  0+`Ze露H͈l$^n-pP 8bSqٿp6#5F(#ܵޝbY]U&ջO\|DyD-jb#$crYN<'+(޷!3e o-A$wg3R(KD''cذatJεϧ UZ4eZܝy. olx:"n9;3t`lO[aW^@NŻTfC[ ƤQ%5*v%BzU^L[oJn4)FR7X{WM9Eod~m^mia]Z?lVk,7"sjúGݐf=b=6Zo"1s y#5;',MzeMyXooWt01:ԄK.1n =Йb$v ZTBw)%M]<O>ј6֟X'%?3Y?Uj=z9hH^9G'(IڭyZ=<2b&jDtgA ]v)i8lh)Q{Z (QcdV1 =C)2Dǵp7-[4ztbVua9>$P[Z ޣS})k(%!^RFp'QF2rR\H 95&ɋ*ĶK|,m_/]7'+rzjXW^1?˻Cr[^y:Ҁ(..֓8֐RW)QFZB"0dܴi ʮmf[6,.of ,'ua99rV{<}!*(}%I>hըСY`<%@v\|Xю*7[ա=<ةS Ǝ3@úYiͬ$Nv8<T!E\]JZQF}0PKnycS間9LE>+mv >'VC Z+?¡~Jo"sT8amMb@l/^i$jT ;E]u'ByG<֨;N>Z8Q+H8Qki9 y .)-v`a|΍7i ´ F8+^UVСN1Z Hcm^܇rsw_~4{eenըDqvxHڊ!o*duXOKs:TcX qY. L+80dF[\,uQ_/F1@r\'F3w/vQߡkolds?:j2Ok;GJ\L[BֳJy2Qˈ$MP"ֈqP_`^-[1зdQ`i%Ѭ2G,_}13U耩iz΃>ȏ<'Y @S сp"sF\53HVdX7}dg`uȑ81"Y@ wܑ!VN5Ci¸9#{ ,b4$3Ws]WwSEjl!i{ȨQJF%f I8+Y!#Dicp'2 $M2#L100qKVJN!i$;KGNaO{@0Cu"X~|@7WvDzs瑼 zh\{mi׮׫t8LR5*' ɉߝ5-l `::"qDv)>ab;b=hN !`m }n:i=p͚M937?C{8e1u03 s &Df:Tw>u'\֫׊pq|ĈNJR{j"=ٟ@Ǽ7]6k;ƪUT$,sI93*(X1Ä4>'e^p2YYc @+IbVUIEŲ3?Cێ {hq۪zqX;v 7Z~-G?x/ܠF쉹e:h 0FHj&ո#MǍ8螒sgmw9T pfǀc }Ĩ|(eCVHMG\Xc9~X#G?Ж-O4k6SO5<aw Azr|bď; b98)2(ZW90;߸#qs*8JpX-,b^٩y.+&!8Ge\Wu+\[L(Ñt \bcS'8iL=v?5| 6C{Y|IV[Zy]ӯfrq1itX4jqs'd {%6Faͅ@N!+ρ`8F22j)dC"BiV )rGMuHZ\6W+Esx}8Gߞ_ms2w^35\ߪQ8Hti(dVc`{>CS!g3˿1ZSRROWѧK.HƝ`Y\P`OnQ7/Rhe$pI'Oc?yo""͒pux-O@|RHMN9j0KZ49L͊TkC$cZ"Ϙn'kGj0m ĘΫ??uqKЂʝ.ꞛD@ vVُ?u?_Džs_Tʁ;O(%kR8ML/ G `ysXW2N8:FV{p~nhGf]~H5/NH'4KBf v)qΝnj9hК/C~̘zݴ) 3:=1]uU j3s[XB7mZX$jKS,{۞jo͝mwycȐ~h+ PK7})lq5˳E<~+~)BKx.[ Jk>>O9)zm@Ccp1sLSTZfT3o{J]o1,W& 튎C|X\- X=5|-[ʛ7~ W_]|Pjz#>-}iżph.Y?8g? Ba4B҉#/̱ 3 O[f9h|b-7@GC`'QWkݖc]H﾿cNJ>Ⱦ?w 9~g ϲuriX*^siGg) "/OtvfOr{q* ,[̠QGeH75+^sŮXQK+z gmrIc#5Hr٬~4e.ԧ8"T hm_4gŗ+%iK72R7?ohcAf(5(phS\aH<ɋ,u#Flxz?73htVNꀖ8ějrdn|DV_|E1d8qg7]b$]}|GiG-x!PA9V)7\bBcpڱiӊygCV?[P1{vìN?ꦼE[Wnu*fA(BN!qOzQiQ@$NXxjw֛5#+7P =.h3f 5ŏyVL|n$*xk:}pݎ/g xM={6fafU_]7p`ߨ'l+m3kɳEBu)1P82d_hY]3KȐdۇNwWϴ>}"GͻM&›0%B7S4q5)%y4 mdIFL!'ɋcC20S _W{ u %JB|sIAV,\&7yrҥs}to~3׿^|# Q@hˈD ZǻԨu=y+M `gm-_ gR[/O.ԧ#,fk ![\XEyy\ԳajdUPUᐙtѢ/܇m6^*R5)]2o8p:ޥDPy rc%.]t i\Fʞe{*zP' pjS%sV6})a%1Pjq%]uk>vnn`{.h* S^]SLI&EFf>Q;ٔab[-?7Z8GnkGz:S'/)2.@2;U]S_F;,+w5@M5|`!q}ɤ|ޥW4ሼKId-V K8p: '0`'Eᄡ_J?uj0bFƻg[7-|Ί\8w_]wͺe %^>ʹCzi;S@I^cjjjQW%"˩5?1i)IMƠN#$=C5Be^X/&ӧ_Uُ?NШ_ t۳.GOdw^̮4Ilʝ "R$F\_ʦvZp0u&6/}}qӦIoݵoc_|qAqNZ(hya~^#An;Ppa._Gϥ49>;`Cq0|c$i 9Q(](xWwBE/>24G?r#0Ϻ|뭳~y!~Ĕg!,\u_r4YF` ߶@Rv 29}-9U8n(ΰ>RR#P,.O|bՁK.I۽O⋂Gpw>DlCO3\؆1x  uF:B5!B4 w#exxBuF!1~Ng0\/n]?uꜪ%> ovO'*CPIDV_I(M ~zgr:NΎt<cPO6:>kؖ-[m^dJ= ,ȋ:6~}*8Gjm 41x۵kP1n.F>%]mZDb.#cd8B*#FzQ[ vҥڷ{ɷ߾M>/諒#!ɵg{Hv.n> 9Oj +jS%(pdt sIG3м1oG]zCV\kkj,~0gHCà35/dSgϠ,nJjyf̗bՍ?۽a|f  DR2jM'+{_.!ŋ]K/iU"̦xY3;g`ǘ^,4NCiO Wu£\֭[hD"~ƭɽSOV,JбF?]hgpCu-cG޶|'?9t|,9X~Υ q|ݟ1d~wFÂ6Nx#QiD8:k)儆Uw< k֬ٴi^naor!//VԺQ@ƈՄ5=5jek׮Uy&Oȕ 6p^z+-7Wo*ƠG/1D 5YU'O޽{S7|ΝSR# ͛o񹷄xSnL®;z^pH!5Ɣ"Lj̈.kP ޝ)J,/d^Sm'XZB;{f׮e=x=qGl7>Y'N/*%Ywc7~1|ƥk1B'4cJ 6 O2c |X]]+ӻ>n˰ -1@ԙ}eɉQ"zp1`[[CݺQm,T!E1hTAwGm9,nv71' !Y#XPg_fxq ˤ]v{;~ַfΜ?wnѯw=3[^^~rպ&zy=w A_ M,av<--A1nxڸ1MeF"@ao^.O-O9DXWc7pY Abp=uؒ%?<鍊 :sz;;\R{ܢ(%82Α9X,aJ1F4WU+[(..]s%\N6bK1L!Գͫ QIac%h:Bf7>vg5Kn£+L߿}„>H&}eFCjh)(Lz `ƁjܶlLi/^YP?i )!o?Y L`,6<Ak ̩}sN /T?t- (uzk7K2op $W裏0KT,c/ 4lb٨ؙ!p}@e]8|xav߾GRzugsOҥڶ7s&x3HmQ}"mL)`ݐXTxy; z,ը{|gGgq<5)t:S:&,^,>' sc.`ʧ8N~׈@x!k%,ySh1vЉ_4Xc:'6Tc4F)>`M8˗ ip\Q7; *8g=,*j 7=ؤkַ" d:;gh0C?Z~Td(QdfgX ,Q PBL1~xF'*@!ulh:a:SJ,K$oE ";Gٽ{9{n[oO.H-xp 咁7oРţGpfrz٠, B34yF9^?¸qd͘+ԙb^1ȗLT'MZx'{5|x:%Rź1˦OJBw^+CKzJ! R98LHm?V'ş0/u@CTU]CGx8eJ-4~u%Qf f 8?!/z]׻{[`1& ^xF2ٙ ̝lѢm%'SW6!387Z曧vs[ٳΙSo_۶nZZ^4j6ЊdǦtxr)YA& B\Ҟ'vul[ϿyYB#]LĞ˔9b9;u"9n ݘ5YxS IOdIoƧO3_y%ʔ?{VVn..ڴbʚM[l@iQC{`Dn2]΁uB}hOY;Gw7nY^ƛU\{%_fʹ\~}Q҂ݻuF-k࣯ۖfkxWصksMMћNVBwZ/xaa'l#(FlH:ShJ;V ѩӷӧ =7*;tsT3ջlzM{<Q =su}YK!vk#y}4먷;ba@N{K)jtWQђwapS7w*?ˋ'$Kcw\'>U̦M_xvvuUn>rKe^()ҕ1YR9zsIsRK% zӊQ#Z|_c[/?֟>(m,S0x ᫘ȹVZ׻wENG_hga|¥̥/=F&N3V!C}A>qaϗtr͚sr׫؁KL5K VlNdgOw)oPRY[ɖtS_~yiUD\PD-c_-x=T 0[k#܋<$4m1c6lݺM:m;KG~р;잛 f'$?hTz, L1L?`^}'G'?[ѱ#VgGK s⟫#G ڴuV{yFS$7e푧kYVQ0!9kxZ; _ܿGUw=bYU7fyUUߨt;!4gUP'Qg߿j}NϜ,+k:ADZx]/+s Ev>da N,ᨷůvp;gRoxLbwD>@NSv[/V:@99yF_y夋.ʝ0/yn=CF&*I!A:{uoՑ&$&$T=13vCV¦p\9r68vO_EOwڱ2!YxS{?\⫯ }mێz啵=z,Z~ԩ{6xnVUi{n65 k&6DXPi Vl8ܹtժ?oޒ yg]wM}σi6%09BpHb<#Ak{nJi]\|fy2$!~,nj[Z[Soyt괲wڬ,ܬܺ[.($HSSumXkY%vVѲbȐÆ|svmn X8Żr&k\ 7LX]n}~qƹs3Mzeuj{10;hpj)o~^TM,Yѳ'{Uo5嗃]_OhB"~n10XT;Wɘs 'T`L%^ ϦRЃ\dwq/9[Ϙqqp'wϞ.Ԩ:s JQ2 ;U'd3}m_VUe[|KndL x$gqiuYx9Lu t gA 7kݺP(Pz2ǎ'עEuMxO?rꭳg7+vl$B.j+lը忖u`)>z5}>_Orw~q>=Rg'h);jVJz-tq~?QUSoVGyNvOL] K[WIK|+GNeeu>ov̚Uo_EmmCM V:P1:S&i,Nt#rrgc7ҳ~+B{BC-h4dM++M.i~eiiq۶{db6xnڵOo֌vqn۷djfըԙb8zXځ~$ TY_lIO<1UI{ku̍nQ*ּ7oP9A߈r?yrum9qb!+w?@2{ڍ{ѿŤϜY_Z\MH/'Fv6LNT Sb9Fݺ~݆u[ճg xIͩ&e# Dșwpm{WW/5jc~c[sʷ.Xj NFj7}]s4۷sӀ6&Qd!<:Υ5U۱cKDz +tv2]^xx7qYϪW۫ŋws%|r%/ayn6<` ynf=mhg$ ^С͟|`[?ܧ.}ޮ\ڵkTɣMYB;,ٓMJwD$ ci4֬Y>hP^6 /WrC,[4 U"J_3eMN kժrϞH4M $Frp喉>[@N_1lr2YĽqi*~;k*Y/'ݳ7X&0rw2:V,&GFyۯka ~ܧ*}x% TY[.ːIk,'s߾})AIO:Bq]{/"$Ća;H&uFkzhVϫٹ3۷'w\Y?hPUK 8BC`N) TߋO??yۋjso>phĥ&Ɩ>}5n=ʃWXNXsJv2Abg obˠ0֒?_Է/n^ijp~"JLXE ꊪlf۶m˘D.QL] L$MH}6 (E )Rۦ@V?,Ngʽ1-w8#S<9%C,FjԍqUlb9Is&U*s Ck3ĀYs1]ΘbTIB>6ɠQWLH;;`if,(윶c :u9mZjPFņ`aXW򖽆p_D{үH[dBgol 6)=C7|2(Dn6e6S]&xG,Anf]g͞=ᬳ׬r4",)) vXŭH}#A…3|fa69!W#dϗ/YVa̘;y䑜-ǝwW5RqhCmԛ&a9+**L.zN#v@57%z`Kg&J`;)_&M_Ι7oNlbh.EƣG֖JRuu`3z>R)%РFqơRD4Jx'=.NeJ@y Ç9ژrl7saa_=zE?qϻE)5k_Mƈ$T júGgW::rF,$bL'I0~yyV\ߟծ6m TףGewW`|%ݩֈH{xbb./j܏; xʘ{vV?[i=Wwś>7y5ŃV[Wo_ΝռH%hfȕS5_^pQэ!ΧzױVz툜;>\gf Ag&AQ%Z#j0Z6uu?-hK›\xaD}d__.dӏbX fx"SISѵFXY0lTB{;dU"~7 [yg᫯v[~6վ=J*ߵ ҝ;,+ؽu<H(O۸4:ptT'cz ٘ZZzW^^zig}믟aCոql"܏"f3R9X h|洴 %~& ۈ$xy?$|Wxܹ|o{Uy͛l~԰a{ (kܶ Iil6b .jizD%IODiy1=dԩ۾:?'gB_?GWrˌijssa6+vg*ZgΠ1U%1Lw]M- 8Qܲn`6;fsZ>uݻ㳉;䟈lj#%Xe6vXMWyʄmktաT߸q}4E-[fkoqMUcV]1ƈ$VIb vŮBnH7z@E]i)vUA%+Y~sv3_]p_ᇻgr۶1iNT _%T)4sWHK:sɒ%N:2=i[ .dܵxŕ?>eݺ]0gٌ͈B$] $UrUTv6%&Λ(P=ƽ*Kn8zts۶o9 r/3xbF/۶lF̦E@ sM&Qq>}N&$GwERk^s饫=TW_;zLTe# DHiީ~˜LHMoԩSSeԗE7l8p-=z}y}]ѣN暝hDF$kϠÀDP7lؐP ȹJv Ӧ}.ssx`I /ޙ]^S 1Ѯ$ҠQs>q K^4c:b>RTS>wUW %ѣ+V?~򬳲.詧6Ɩ3l[쾉I&4j-Ӹ7Qx#aL~뮺Q1usyo9嗣?l?SV۶k-TO=;ArDfg# Y(  橪ܔt&tuVúw޴ł)}Wڮݶ_Uߌ{M(M j@X" D W(#ُЛSL!=wvO6SmVa^p<2w[kl-(cbI )Q7# $J܌}PIENDB`PK>-Pictures/2000085A000046120000174729721B1D.wmf] |E`ŸaPr(Kp9b$\$@rEODAwFWsXUDWYEd~o&'~~7]S]]BH!O?5X*WծBt!DR  auH!q_.'g?"D:a1k af Rmnw{䣣{L)!]XBhWCZQBgUiD{[G}wǕǸ!~dl w9pH?"U*0hh )3G8N`6591:R_l"UP-c/ǃCG; 09G9CS~<&T>3k { $@U;:y:ۑ*G{1u5P9< o3c`uqĉL^u,=Ϙ2 16(cǎE`Ӌ2ckPNG%+A9}w*1eÇ#0y51 6(CE`R[Ƙӷ~KNo[)۠#0yi9ǭ`L7D`;|.c3اcL;Z4٠vKNs:tA9}䴞72sL^rqtrڱcG&/9mmiA9}/Θ ̍C4Gr|>|Y\>Wr^7 spl8i>,hD ˷طp{7{¯`#YHW"=v{\d6Dc0z-'^ ! XtZu02R98B߇i=*>DZDjɯa;&4&:؍a1ޟP]U$A*4R=ho3pP8/nN0 S"?GOi{PscYhn}r/C{"OrGMDYL@Y 1 ib/>RQ(Tg'kgoWHH}`p1hL?|S~zЕw?H}7]&K^~%+f i](8MEꂿڗn枊ݠM.sG^jL@}e(؈VLϐvbK+f`˫ T 1li-1US4+nrIa_jy4T]׸:ƔΘ srҵ3e0^&%'z3LtH{k^rǘ0œtqYic:a{3as0ƔØIn˘F00)9y)1Șs{/F1ь2o_ј15fLOm˜0O `;1]ʘ>52tcZe߱"L `;ox2 `;71]wy%cRv3Ԍ15ɯM"1%3 `k1]Ř՜15gL `k lZ0 0dL-F٬ɩcjŘ6I.e`gzu&!eYvN ّL<`ȇbVm۞R^m Y`AAG*C41`LJ66lg"o0mAӇnR@%aZ/,[/ѻEswGkSe\wK'v3˧dv@ {é|>57b0.KtLmFg?Qfи/Jsq8w(y r\)S׋_-kxqg~r#yy,f nd*O a7t~] =@R:t QP<1O*_R:($}t4]B Qz/oe:)>-ڔayyh,yc|?~(BiyH9>צ6)C6~̓#0mXD9{x>rLvy>cg? MF;ij3 gbYHCir 1mHQ>! A܃ 0=H !M ?;"i0DacvqdG0H`>jSM$8g,1g5d1 47v|b>QRNK-0*L)*aV%%5y6bI`f Ia:=ybA n;ك^^O7!_̳cZoz8dC<}46)M-?@067HS1]!tqnQv g: : WHX集ҮQp2\2K8^sK[ [r]v =k0p'@ڧbAre/kQÒFK{0 @? Hprl: l:-wCIvXjӹ `(8! u<W0Cɏ.}A۱@hYX9 "R_Z [ϰ`6ʹ퓞<~; Q%9y aL+ӌy-hRFUv݈`tѳi_i]Qũ.]@Yu0 %XUnDωHWnT!QR؍pWj 98nW݈d"F j7痥ؾf'/"LUKԏe7zO{?vX:﷖} Nz~ӱ{(ҷ{u^9vLy :y+kB~fHъQ"dZ26`J#h H0;:/LyJ^=? UD_+yS)r<'78 qysֵΛrT_略͐ΣvB*" ^yj}й6zw;hXΫ.ҷR(.1kZ@ 1XDX8u6)~}d :<:F;0Vȱ. +">@_>PIBfQm?;[2o\?E)TsK(C0I~h `W+H}/BAΣuK+zZcK) '5Nw(\_]q.8wPNܨɜȹQE 47d,-O}+WOq)\ rK>"\"y?ޛ1Qe;=CG+鼖5; ֍5S6' Ӿ=<.v*3^ Gk_~{D\nx?b:4؏m?{s??=_GlZB(3j&/mj^ńgmʩVv9w9OzO~].e^X:l;?>[WϦڦ)mjMEۻ^=i#mSUyfgKEd!Bheڅ7ZA}y$|I~s̯Jױt.u ";*w[h2 =pR? TFh)B_ $}UxQmcjP"<λSLzxhyX0(!r?qZ^ycz&%Jb6v"N;/}eʸ}x樕@gAO}ǁ괏չ|p7dž#x0ѼAn`|;}+qǸww! ax?R[!7E`ܺn3!۠Bt@:L0 zA6,c n !>HV!J$z'VH~hk6.E6n R " Rq-E{{HH tyɵp+tY<:uHk׀܃r2GCHi/ qLw=&QnQPƠ4ɯlĘ1 `W4fL0S0&=.eL2O `;F1]ƘVw,{j23΍`LW050C^ɘ{݌15cLk `kHfLɌsnbLW1u0q5gLz[0iLJN6Ӗ%chSI6hrjŘZ1MbRyK7ٰ^Dk ?+EHzY:>'@>wHv<Oj#advm۶ԡWۦ1 ̂ "p4=RcRٰaC&/=Cn})ߐtm ">TwM/3M%wֲʸ9,]}C;OvgAO4ASh}~jo8a]Q\_|Gwh{s0E;:U=^ghՎt-|MVu5U;گ]5tw>xVrrS<|G+9ڟ;ZI|J<|G+9㉇h%'NIJN㸕ɄhvxVr=gJN1;Zɽv%xVr=߻MVr=JN;ZI\&3;ZI@<|G+9-U]-}&}G][qghUWX#hg vV_%ê×_ZS%d}xVrG<|I+9}x)tG_JNKZɽKN%z¼/i%'}I¼/i%'u¼/i%Ү ٲ__g2J-Ty-TyK5tyw+鲔Wo/ץS_^iuY|n}4_^J+|Sz|SG#AJZo깤85Z#)W_I8;|Uh<|U=_~XU}¼j%' W_{_<|U+9鞫j%'W_h0ZI{y¼j%'̣y_~U %xVrrS<|U+9ZɽKNSy_JN^rjy_JN^r]U>#%¼j%'uxVr@U]0:[|U'uv1c__ՄLZ U=e-hگ0گ4twOZILL<|W+9jxVr=JNgk Xگ%گ t}wx糞0ZI[LI¼ES}qv[]^"n7}WՁ]h,ۧ6}W{w1Z<|Ww1Saw߹Q<|WCw߹v<|WI$ nگ+گ4٬l]M=֏h#y2Vue|yede]Ҹȴ/k%/k/CLkkqeM8L멲%s)z}v{Awlk}S% ,Bt-!>Sw;~>.̓hOS+~>`}bW{wWZ9l?NT&w9,U&ˑO:@{wztxc%Tӥ"u QINRi u _8-!}Cք,`{B&R_A~wE"L`<8-<`}ԦLI1 Yc%H`kxxh?=\s,syc=y^0݋H6)70~)}iY<1^<1-L}bio?t!}0ϥjaUSU0!ìOKNK:j(l4&{iڸ?f(Sfh_vmKI&^mu'(E^m[/!ay:} gJOp_gpA%dY"g׶8OA *Mdjo#%H6ylb)VU0 ɠW:[q<ϨVi, XrDѳ {'B3Og!:`40=HBt2DcxahFg>+{jab71o+J{Uxpƒ2[W\. dHMS5b9 JL|%O|:z/6[4tIPZS7Cxd [=16Ͱ2#aF@0ea 41-mi/=?ys5 A0Kr;Vl{,[r|05|\3_6z~iњc6_lc/U% ז[#|i aJjkWH(>Z4Sv]ttѳ&Qi]Qũ.]EYu6#3%"oK/گ]~Ӯmת]k\v-'{gu!ڵJkFڵ:ծ5(K}L!G6_Dˮ<vc+]+%}j߂Ӭ=tpnJiѷӖu^^9=w|LՁ :Ӂo(kBJ_͐*ڇCkDdɴdKf)Xm֤$eH0g<:B6:>kUDr(lw>TցO:ppT:Y:^:A}X6C: /l3dw{ACMڦ)8v Ё?X]o6Q\@Kb"״nqb*\I[څ{鮹E5^!]u y\>2bBGL$6t E#U(y}s.\|ljhj-(|ū=K$|ʭXסh8q »QNx%}:y%Sm2ڰmߎ.n^rszJ~? Ocչ9mMqC"1pl w.U?~,Bx i)/|{:ϡ=+K.c!3΃grlL{FN|hos ۷0PIBVRFw e _# Rzϩ P*?a5WBA˃uL3izZcL9 75s=Nx'x[uͭ*쒱l<%^ɗ?uԳABe|QD:g{3" =V{g`%ؒfGҁ&s 7oϔg5o:p~Xaz퇹GֆcCsø9,Q|SxWqu5bBޙ`OCrQ>AoۅxKǑا+r_Vپ>).aoIErQR}zYsjn n -Pictures/1000000000000208000000AA90981B63.pngPNG  IHDRG pHYsodsRGBgAMA a cHRMz&u0`:pQ< IDATx^RYa&{\eaec1zݤT]1x*Uى柧߿-4z់#E15r78 }&5]K9"\ (^z('% ЋbH$MrCRN4k*9*W^1$%`$MrC@zP  PN@1K`@ŐgIfM% G+r ,"za@b( @/!F4͚J@ʕW I :IӬ\yŐ4͚J@ʕW XE@16 @9P.@^CR&i5+0tYS Q!)C'i5+% Ћb襇m@r!&?!0u\1Tx6=@`/9K.<1 & GW 1:Ҡ䨃!CP4u_1T`J+ Ci`rA|Sc( L@:b*0t A QCL4h09 b1 & GW 1:Ҡ䨃!CP4u_1T`J+ Ci`rA|Sc( L@:b*0t A QCL4h09 b1 & GW 1:Ҡ䨃!CP4u_1T`J+ Ci`rA|Sc( L@:b*0t A QCL4h09 b1 & GW 1:Ҡ䨃!CP4u_1T`J+ Ci`rA|Sc( L@:b*0t A QCL4h09 b1 & GW 1:Ҡ䨃!CP4u_1T`J+ Ci`rA|Sc( L@:b*0t A QCL4h09 b1 & GW 1:Ҡ䨃!CP4u_1T`J+ Ci`rA|Sc( L@:b*0t A QCL4h09 b1 & GW 1:Ҡ䨃!/C?j4rAq Ci`rA|RၡC(L@zB:0t1 QCH4f49!b!ƌ& G=W .`x/ 05[1d` GSf&+ hlrDŐ3MM@2B0tYO\%>G-HG1d* ǓNy#ύb U  Sȫ=~`^m\ bƶg(Mz/.uln+w/2|ۙsOQ6iO~bhμ~?1ȫjǐt(G;\qdhK^9K0nbprtOK|Z]vK/uu[Xj̉@9b.{ܦxuy_%ɫ[TQt٣e1yg'>>>qFoL'or]8i1{;?x_?v>o0M/6п=nɆ3nAN䦝tRv{`'?#JO` -}6Muq-rmUnW[2vnw~ gi>]>nmMĕ_tpH+ս@э]i2_o8?F'[\^xvsgt3/|Unӟ[ϧruz5Gϑw _|q/#CN^rWpX~+m7X Kkn>,C8^{WrXMna7K^hN 9Qh=p ܃bHR~=\D@V %`<䨡CCQTP 6 АbHMqYS Qa[tz*9jbxZ_=y@s7XEԊW,Bw SXʙS9E)zyo{,ڶ'9֭/bq+DӛZa% !9:1{zz~.qC|B@kvn>ZlD1$1lB0&ùC{ ܒ܁Wpo|4 uru/~֋^:*"'pK(' GDP /W~vbLDC8(9imŰ ɯz3Yǵ z[P I iTrTbHJIfM% G+r ,"za@b( @/!F4͚J@ʕW I :IӬ\yŐ4͚J@ʕW XE@16 @9P.@^CR&i5+% Ћb襇m@r\ (>M4k*9*W^1$%`$MrCRN4k*9*W^1K`@K C@zP I=|6iTrTbHJIfM% G+ iTrTb( @/A (r ,"zl4IӬ\yP.@^C/=lP XE@1$hYS Q!)C'i5+0tYS Q\ (^z('% ЋbH$M@bHW IfM% G+ iTrTb( Pn3IENDB`PK>-Pictures/2000076F000045F000003D246E880C36.wmf] ŕ= h0Bv0q@hLTPQY7hbPpHdPD\]M xj(^1*#I]4Zǯ~߿Wu뎈h 6l4?o'DuMQu&jOc~\WI$$@PgIn!n溋 Qgm@o0ݣ:`~=u*ҭjjXWrzGju5Ƅ=]Gpyyoyz{m_*ƶO/؞6/C2N6|55 ]D ^y-W|h"0[zk̜¶i|:hWE|28{ yYF-avŴ>͕kI-o_d3hvY_K׶x̴[L:vRs/ |557aH>mY/-Ao,x'0z?`Dbllm3WQSebue_g"GЖ?jv3er=s=(>m:tզtq}>e_%wum[|B?]g_n'h>i&.UnevZm6h l/qWj$WЖ~'c"-RzI}Mٴ#}Lf .1L~fM0%HښOeU-~WJY!/ڼn wnovxcƚ_AcUGIbWpOS ?Q*X7(A) TxOwVxkA?d7_RZU P+B+vߪ[>K>US>VccXg+lUPV`pȟD;"6ylwi}hKi Uuw7oR?ޢWp?en~u[X[6϶OHHOTD_~WS Jo( oR&x/U)(|OW _ OYmGuo1VOrWU܎THnw'yݴ1FSSSj{RQW|Yo}RurrS126|‡*|?MJM)1(E>\6 P _pyתG*|(VmlY]/ϛ3}Ӣd:itl7FzȄ [i1Bi©Bb7| _8&dw*y_!G y y,d̷?nBksLxQSr fJ- MxHȿïw,?`O?& d\+Mu}1(!gBҵF0~n· $*pWA!O,mwU6IW@e2lB&[(iXZ)dB^n_&G(iO2dUl,o:5iBe2\B{1Z)^j \UQF>_2B>4 yLe2|TƜ=K,_{ esg){JeOW*{B){aŸH{VeO6nʞVPV-3TgeO=P8!V4ȗ6#_$x s|hF!wӥB]|eO){Fڇ՞UުS.O$2k$ׄ n^&2Q!ϣdy &,r+%ۧI+{ s6m>((.Gjic=]nyye|2{q&T*SU`U' u~:B_G(Ar܋+J>H}|WJKݿPr]Ty*wr U2_ ' dI$߲ C.GbaOr^6u!~'d'r/m:!~2gi!2'lxm*hV MO!6{h?2BFK(nYƘA0&_"d\//m,/dyՉ{(K5WQ[f,?E1 #_ylg1 J565`pv &fOQuU2DMBW = èuue!xFSd8B8 r.1oXFZ󄼎ㆍsܴy1U 8!c`QFZkQ6ppxT>JC'&Jlu:#ϐ *e3 ̦x E`k!cܲTh .Ju!͖;ߘp(#?BeQ9%dPʼn`y1WcMPBnd\j7|( { ٷ<_2^7NS}jr %) ؀[).` \Ȼjq\||z=˵,¾9<>3_@>H_U M3zm!X shթ98b]\a5ȡ l!rkEpvsr9b]\͢_qe|>˃ϳ _#Cz˱Q4>ۦ"G'RG`r9b]\aǡ?~%gCm}1Ǻspĺ8˜Or̿>_e#;,#̭v=\XGX;[֓^X>٦*GΖn995Z޲?m!r{EptkSl~uqqkz˹z |d#>PGX#9l~uqquMsK> j#>RGXZ KH..xXe|PWx69AESxspĺ8}xECCepv{uqqs9+q2yp#>+_GuqqW);_qBgERgXG|#Q=I69b"89&G#ߦ"G"8:νh[.G#|ա7-&-69z@Q~|78qތϡ_Ưs(\ ~SMoZ7ӡ<{>Ճ_CM3k 8?M..pCoYOze<?(v`]8u-$~57i8zν_m*#Βw8ְ;g=4~A&/ y&XG(MϤ_Ƨx?s~T͖r9b]\ac#.|_?`)ރ7~WސO?o y&XGWq]gx?/`8_B&X3L:QL<-־M.igtĕg7Q~7Sq~7&p:J縌c ~+7Ϻ.#wo{3y&XG(q7)5~&M.}XJMc_ 6g2&`y&XG)y^?^JEh|6d\XGhC8;2<69ZMMG_M..|G\ƟTj|Y|0ųoySj|_g#~HaފouqqjvemJEh567uŢ&:r07G#Mwe7)#x>..3DI?7G*#oy&XG8f=x(\ ~gUy83Qrĺ8C#.xw ?Ԧ"G"8¹GM`]\Yԗ82gwy!Q~n޹h{W%Q|^e|lO%|lM#~^-b#..E/t\1*_CIXG7P7M..0:š7X38-уD@y`]{[>%[(\ ~wgaouI;sߡ<320)\ ~ja ?&XG[)9*gPw-wyvt0[Sm!rg]GQ<_b S8jv-s)'C]GooWsnYh>*GQ99%z2-'Cߙ^G({D&XGMz~o"GK8B9}ғm~uqq#G\Qw¯OT Gh?HDuqqqSSl!r)#؃98b]|;2>Mq|M?T^+,Go ^vĕef>уOt{ '5GK߳{)|M?D`k su<uqq>qG\adWzY69Zq|8cdX4q8 >צ"G8PAa^}yVuqqq~M?Dp898b]\_92/Ƀ/ ӯspĺ8Zbqq\xpV*}C#ڐ<`]\|92ߢ  ѷ7))Srĺ8wY踌?8CQ~aYaܝouqqqǸz~܂8zyz:2%<69º̂8O ɱv9'G(^qxggyP7!$pUAI;1ϝe2x"G.osQGouqqwYweS3. ogcΙ841G#ٹq<Chm[8:be2>ؖy>(۶pt(7/#舻gȃ7C۶p_QP.Gۣ]:.wz=]68 A1uχQl[*"m>od>U;Q_u.!C\kQÎG_& c9\e, :h85QG|vy k,^ehOۼ>}1C̵YF?\ЄsiѨ|t}|{\~&l,՛_濵յF䡝IZF\+:߅bwUHvj{ʪLӄq ctu`/i?\glKi{6{d]ǽN*^}6}|/{ԽʸͿ{`rc#v&+=~C[cel{{.y}{F=_=zG?{;ѯ{N} /M/1_zXO[wپ~WKYۗ{aM^v|eYe oV^ukeWH+qyJ>o>)>|m,Cpsx+c2G7C,4nloߡt>e(뿏g\eVTDnfY0YSђ wk^t8ߵֵNc'Esz|<`-=C>Wf[:"l{{#C*g>Xi~৯Qhr4⷟9|׭8ˉ DL:е 78#.illv3(oK.ui@K^jGa)\^?k%YrnOn#D9{ލ>E;ʓ˵fg .S`0o|lyKM^Q+%&^{ZE,MaSl3Cw\9m&wE'eyt]K9RlQJڂ<^{ߎn 0^wLqmy7kzq?x.6ow[/yokr=첽4ȶ\uXZ RE%}d~X)gP/^Xz#2Ŧ_J7yXh'U/Rn!m u*^NIx=%y y_NUG\ioe5MzpͣBo%_={ԋ(i6b7G MIÈw4u+ 1-KHwePEA0:R{~xF)v'+Q|U0߾Dgйf^7mB:FwG8=֐*U|v5go&'W6ή-~k:~xM]/0G,Lon/D{mse_֕huf6b^Ϫ6 lWJًHopuf!km$r-Pictures/10000200000001BA0000016EBCA0A574.pngPNG  IHDRn-sRGBPLTEkف5¿stRNS@f pHYs+IDATx흉U(hJZVz03ldIPbJAz(Oq)Wom;r3;1ww7|Y}++ S:8U}0W* R-.LA:@9A_ +m;:etsi tb01Ԇ9Hn KƧiJp'CN مPLNd:@XN,P7 Φ/ ԉe:X~@sR9@]O`$ө#y5C:N,P'YXod׭^FN:1b(Qt ub{MR'uM S_TI0WÑ)/e-\X|,yhnZ kr4,-jKԫFO>mjzEy6SN-Xm8SpnSP^ZRbs罇D~R7&6dq}sD=e:OSBƹ ^l=b>VW_ץ_|uI㜺s͋}Pא%Di5]MΛ#U=V6k"s/{'K`OI9\jh%V⿼ ;ʋm@79|E*lN^WLj{}i.NoU]g+.mݫGt/š.u</̥c1D=<`S˞|O3i*h;$;-2s=kb-;uGeZmYT\S'NslljnBڊpIt_f^-@|lAcO\Etc'BK 7K}JRp^u1nXW6l8xr<{D5P}drwELwGr$#jnIr,|H{DWVh3pf-xWGmju>Yկ\MtY:.bAD[/Mb IA}<K\Ӕ9uY[]ݿxMyƐ$UUt#nK"PMMI:-̅´H&r{]=;1iR}q>gͨkV(ڡ$gr>4 =uII}` f},Juє Ju:FC!7sVjՑzgjfPŒZ4BԽ9;Wؤnp::?_&sؠ(m.0gnCNrhԩs  a7׽*+Ei!mzIbrUpq`:3wpu?SJQh(eaC Խl(JJ> Ӣ5S_]cԝ9̙%_gDNu}r5w}ԩ!Janh^] [|Q# j2h/Lh}8+:~va>xQxc+әXJ#JA[~ kzmڶKcP(0TCP~~>,(£XUc1nq蛠 ɓL~:^^[u9u_eGrQ c|l,ԅe :r2D:tK={Ka!z8%u+A}b^BAAZîρ2DWWWjdٯp6Rx8fsUw {'@%ܴA08Vnqi(b=l41mz!7`xo-򺝞E::XPUuZ@0ν(Y:-!2vwEq_TٙTk#]-k΅:ku4>Rs~1DzK.{N1]ۯU7%PWx,Y$nFK rx<ҏ:u=?7E/sю8w2nzGڶu6;K܈|t΁7[Mo0uu˦HKFTa5Wfbhe8Aa$ԫ>qs/.DzDؘV4UH*F-`n<==e~9;MbR:',q]' ԉub:@X;ub:@XN,P' u0{BPBekԉEU6u2QY-Laܿ^0PNEAT9@X`4Dw\WIENDB`PK>-Pictures/2000025E00003B0C00002309BFBA58D3.wmf} N~%RRq1LHHIE"c%"CBDhHIH÷IR)_kg}T_~}y>{\+Ƙb99Bc6&#qdL&sH1.|پL&mYɆÜ64NpȍSNf4h\?ݪ~ۚSD;1i83c&ߟ? P 8͛}o tz<חCucsm"%iu|& _@9wh!zYEmmk`X~+ǹs)r $`<LajJ6SN^l-[}yZ>l1J-| >)?ɝL1cO;SLԐYbkn`'r72W5?UrW%K˘KLe଒\q^N宑e|M|s?4s,|K>yT>B+쎹mZv*wMls/G5}Vޓg^FK{Yv\[/(w+Vpnbn 8aOC&[`sOW'例o{=m1<ڊxx! ΣԇOy (-1\qV.E*E_Pa.Pnăm{rso=$y{83aRn-s,- *=/Z,EK~`A̽)mԇb|)Nq=zpn>䖌c. 1[))YRbfh~ԍaVKhԎi؏:rES8^1ssa?|m) 4sG3Lm޴Y4Q1!&NNܖ8iۀ1p6ۀȘ;!(MnSt+pK̝ Nw9vIfb1, N'~y ~Ebt]*N_;ڀ sz~Ԙ! GD=1w-8m`ש#2Qn1wy;&*ct?{=K/ݢ~w箨L:iNڄs_Xv*@L ? Ҝ;i^ltjcՖ=(} 34o_k|#a{pet=nsܸLj1]'}0Be2c\K9I}1MV5WZY ~{"vr bS~]{<ĭN)6ˠ{yOgm 犯5djK1RBS'gێ>NNWIy 5ۧs?)eZK)M)wqyNR"WR.N)I~l۟W3epR/׏6GD8ΦǔN] -P]M/o4[ }lᳮF q%זE->>[):S3:E}<& Sߡ>/rI^R 0]0"zclw5=@mt;擿> yߌd֏8ܸ9˧+PrQ 㾐qrxDps~\ 'G{P\O?"-t/~q܃;;Oq+͘6r̘Msxݸ8 % fYyr*buM16"{̵#&2/l|rܽaydQJpVʙΌ) 3Yz98'~i} 0s\܃a~VFp6J9) ?̫y) E"1r_28/KhGks?k:r E_)[?'oɼc^D`m'shO;g{~ׁh?.'mЦQ};GdͷkS(hӺٲuGS)?oC;͟iS; Săƍ )>c)!&a}0T D=U2rkZU*?NTmӘ ǵN<*߆*tb;(Am:%}a,Xoݵ0=]\4KrMjcc5 ϹJgj]`ރ,Rp)I/8vbCM]]`+s!PC2 @8 롱oQ@\e8& U}N8>oCL}8ؑI\>o@9Lm[vcj[#e,/$qpGsH29S2E15JKQr<lq[ibjƭmNP2]6=X+3`̌}*IZf`5xlY)s`>=ƭA'+d<,{`P.=b/K.}8׺8;S}Ȟ/,{.4OP#m~ĵyk ːe3Zb0[ߛyٸ5M=3aCj`MSk:~z s[H|~Y%qիp>z/2u) +]o\=ȏ#8toRԻ%a|cq-[-_ (Sbr,>Cah>C9JsÅ$h/~| ?:wsm/lqqn|h/1x_ a+?Gp|Q<++nͯ~w/QpM4 j|ߍ|vǑˌGCx |3nH7;84~|i-Ɨ0Em."_ڣmhl({iҼ\%ыuD/P'd^;csNQ:+cLw7FϷ/+b!c/7IwqC3٢\7tzhъ{}6)3EI0Nj3Q+bry16pFp9H%CPcVhC5L%ϷDv<l[H)1b }op틾/RFq/'R cm8^Uȍ@w\-rcqc5 ǰƍ7!GoBHt1}lG؛NڿI}vSsi{SS]H͏z-]y=,"NǾ7,`ƹ{%)ݬ=\}ZF ǒW7C@;dƒ(q(!f}: c8hj$f}6k|N }&MFjaNlWm=nq5 \Cɸ,r!Pg Zv~F:C܇L,D 9}gv/Ϸ/V(^x;>Bد3_{5ǡ'4^w?ﯩF \XEy-F` :Jlj(jzq'1^0n<λ\ϷcϓW6qc1[9]$\Ssg3W1+ "[܆1r1ݽ7ʢE=V6.WM{Ҁ" Q^ݓv_C}J#K,x4e@_ji>&MP[ {˥Ma5=2qh 5ȣ9^7:M}ط^i$-P뚣65G-jeC_߸yV@ܢ H+ qʝ4^-jZ˕ŸopDw9.hf&Ը>4Eʵ}(m=4."\]=Taoܽ:ȭȵ:@-Ś-j޷Wרo | 8ty4Sha]b:7Y4IkBeZI'r?j WZN8\t q%OƚڠA]$ڢ7Mt}F|D{#J'#MD{^:#*Zfw+OOH+Pr-Q-`[ӱ쫨cjG.p<?nnܺs-Kš)Pa>QU+^ݍ,Fx4Z8oyorOzc8Mp}ؖ/ qPJ kq}G$4='CIR5-mH!eKݗF_P(k}+}Pa$ġ,b{ }Jg+NiKZךp\Qŀ0RV((m>o_ 5FBMk>C Ƀt\\KjKn x91HXS;(@vN͆dv6TP\hɂQ/+:'jN&ԘLsX*YWK[^3B$ %F^ c~O Ms z_M39|[-{9}}j>22sȊơ^Zj/)胲w p*i? ȁ85?1յjj nnIn܉^e|ϋE^CCSMbyCY2= (rnD*zT( nQԯb@Q<7% e|%P_%+a{BgޗqzA{)vCq3x]%Nw~VwE*`ܶO9Em$ebj7\˯>uq%uqED7@Gc_OeSF֧gǬOs?>=Ԝ}ܯU'Hv>:c4(/ɇ{O>;#XNkIF½wY՗>om;l}{SX+yB}"ݺ)CޫƯ<+yL^ 8Z`alߨ/})ybAhIצڄ5{BV#E\x(ݚ'g qxPV*NƳ'и0}Vr|r|2Y"\ f~[}E[(]Ng~u> ̒{a}RsM10V6C\cmX_csfkkw-e3buqDZi2o=1ȬӷXa0VFpWFv+xd[[06R}v$4gG gi{ Uc0;{8alr {"zm0&IWg^Gp̓n[x}Rޭi^;\5q ,k؇Ai\>Wbsp%f:c }7Q&B>P}a|泟O7@#̧Y/i^CQsژI.S\(pa=DϟKapAɜppL҄8S! $ QR:!^S#)^(q4k^ļ΄& -J6x/ ,chu Wj&އڜz'+x'dhmOyL/g/3(񫩯1xNE\$?cH6P>ä~~4usfj@}@9TֆW^=5a T/MUT*Yx\z3՗>g*X|h^k3nx&1d76jC-1M}Vjv)SVpbCdFdL5YȭbTjy Ƀ:6o_r5MAE!N}O~sYm=+,3SD(^Ӛ[}XhZ?1ġ(\ Ե!FCgc. utK.Q](g@Z jYY﷣ vk1uy!ߪ|ו^vh̉{fNdӮzy 덈[$o)z{Go&0|;=;8zOzI5M)-b97zœ- QlCu}ڧȽ@MXvʫx}w~ﯯcJ+O|??+ŽXw 9I5y FcӘH1Jua4A'򱭸!c(Ƚf|d|sO' ׷p/d*ŤIx0{8Xgg=~q*}s|x}b<p+ּa|*Qكy7z=xNq9@V.kbe<,0~*qx݃ƇxSIH7xr.[x\l V<Y$a<x{K?3iXO[s&8ߪ}Oetq0qg0GX;7ab n|l6rvC1RGkC 8nq-Kw#'•i1 1́m1 )tއ1 16uh;e7G: q#i0N} KH7a,m𮑮W#UWYFXFB܎f8c3rkA"eĥr46č~u[ԗ>k,POS=@,{}UMէ6P[em؇q9хz"PIDƲ8⺘CU^ZI\!b}W\O\ZJ1L"׊V_^@aXak>~ xM$4d1_+[އ뫜_nˮOQԍ}sd-O6pDQ:Y06O O/ԔL5E؇bzsT* U8'f<̯WrToQ!nĹtq~^}ʡ\  5|bJǦ$lt1j=OgyR41'FsUmRU%^khdZV8=f8O1} )0C&B&tMqt~pcD'hKc>< }?A8]C=rI5{ MCЃ1>}N w;ނّ5_ֶ&v (7 ~3H½cX7L ؠkG9h \sބ{ƞ {C'wXx 7Xm󨵓bƭi}fk[JY =:geb?sMk a{f9 fcb a0%5xo(&hy ̃#h!ޫC=؛_ p rp0PQ =k`heڠx&hIAI>~5GMB{F.6h!Ρnj{C/;RGCM}5y-4Zh0g@n׷'k~ fGE؇I -^h;>?{g/}: z#p}ccۤ.L}@/9 jC{]}'*@́t@#M{z8͠.B5uú\8]S@3qp˯qR7a .xuq&VڠX?k;&x@e(PkhRdZE*B/[M^?RY8Tj1\Q^.i>E+)+9ڠXhUa%$8.5a,ΒyP0odº[nrKUɎE]ºfagv x lVLF]ݲ wY{FJAו {TNIMQ^}+%Gti;j!j;FsC 9-pZ(MXCc+"(0][# ~+P58ٺ k5LGgh-8=Z,9ӣgȞf=C'8E$=Z,>|7ԖgNH땸~Gs'MhCesN[^B(F_7SCJ\J'ϐC2a-^wڇ :3DS'e?vJ=o^4G>C5\k=߁yxG&1=ϳJxpvxm*0oKyc?=o^׼+Չ1d؇g f9k{J뚍4Okgdy\na![x {V x !kýܷF]ׄA+[ i't[陝& 6 b{{r艚MB7.q۵sC.P]aC\:-&h!wwngNP+q!>W'LBm3 m35j&ąnρG^3ܿ06PmPA 1NN=-4A8z'JR7A Aa"[Cit6h!iu{-A]Iqe-|I=]&h94Õ7CІ{0bReu>Cqmu Br衖@ hֆ=܃}D#M fC%@ .M؃CDA?mrtss|ֆ=r8Og!HUNt4ꩯUKdG*[SPmuЂEH Y$z|xЁЃøm6i, ~sc)jOUCv_Qcpο8&2S6bx'B]1v -T44Q4%Eٰ!^Z̕xMafJA pčW I Dӡ 4\K1%] ^.9#xX8ΈM>U ](!Ɠ$,rA 15bs3od_y-=5w`ڰFƸ K{#,&4CB 9"A A_^v@ø`;֚;6^~Кy[ZqAMBB9g,zYxMmƈ ؀Q!ącܚ c^ zX-6FGŌ|Y >ק=p}BKsQX76A?-g1`.üĺG 4<66'^6A?MgtN;L'>τ}fZ$W1KiيGXc|x x觑P'#VF&csͷqz3KZ4|D2rERC2Ȅ=} EiC1>-0!Swj \ i kqhڠ'M\mܓڊ:4$5OkAcZAo6h.C< !D fOiF\ڰ~ǹ!Oi*P)3V 'ޛu&ܻ\auhj֖}8nfš_}ee1+;3ņO)h@))>Q7]gB̪x% C\ς1+kU/[gmYQ4S_!χf,l޹rKj׺ tC?Ӭ-p.MۛӝHQv$9[2C$a82DUO x(ٱu`TƧJ^?ɣhbB1q?޳x8}3h>2GzEG>G*g|#|k7 2h>>!w3h>d,X\pdGN7.#M3&]/#➧^\Ɉ_ܳ7.f|d{iy9# u5bf|帖U&㳌ע%#_̑1 Iޏ6csqkؼ qb^m;1?sW-1Os"3b>^sʠH]VMuY g{' 68s8{Ÿi7?PKqZ/PK>-Pictures/2000012E000035CB00002600789D1BCC.wmfZ]lUE=R RZ,??Q EB@4ƇjB(HFF-`4!@$4 1JS˃Ƥ^g3=soLvgggfw]H#4+H&)Ze\#p1tD^b0^3y*LGJG({7Z$SEu>dѻ9/H>/Hkddzpkj ^淫xß:pR`3lqÿmP}Mԏgt~Zݗ]׳N#n^CtSG6^-w_"Dܾ##;.Q*Hzڥ\|qYu':*HBtHv9scQEo!#RNg G 7_xF߃Ts-VW!3|e7 %Aֆ&LXU9(]Gi7%ojii! H3cBO.KʐwNs 5P!T(x+^)z IMox&.w |Ⓞ ?q』IT(zqP_zsuB!/x+^/z7 Iox~Y%.7cn\> ޾ĉ o9ʼnxk~\ԟXlƬpbIX0Lt9!_U#]cV x8D<2cٸ2Cc~d|-ȿ`|CӐ_9?^ > o k/dRlO#0k^om.7ڄb.1b^1=d:&bE6C4)3~rdd|0~??+|mOX Ӻ𲼔'ۓH}ed==??ekR"#Ipq_mﺘ8; CK.}C.?P|pi֥t"nKm} TE.:FFy9qCt^#,MX?fN|.3$s9{Yþbo{<|EuV^=em7m|aS[o(iSKg"g>7}sAޤ q7 HĀ "} x\.= *0wRA2~T9*.o/ F.,r4:V%#tB:ub4m4v(pcO"ԗ*4V-oA\4~;![Zf.{]:F Ux'H簿">~ ܳy ͽ F3rqW nlS"֚Yen[JGOe(.\4جn;7..%TM:NqhPK!2qIH/PK>v@>>-Pictures/10000000000001AB000001351293192C.pngPNG  IHDR5n?lPLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712HsIDATx^풬Ǿ蛜!(RtUyg0$֟~FQgGϷ'Gq<ռRV(0Wj+8k??ߕ (e5+ IYg)+e%DqܸH+aKtn!`?x%pCY" iPVHB(+! 7 &J e$pCY" iPVHB(+! 7 &J 6#K#; Yoydo^Wy6տm^^2玲 _ 17?ɛU$V&tKbEdYf&+Y"QVW$2̤t,S@ǫ:ޓ2b~n+ͫ"o~paGl@d>k^R =UW;p5sN*B{^i^!>! "#d,a@ʡ =̄v@\w,* B"ZnM Hբg^!.wnc= oDB-< =_2QO$4{ yIL޵Fntj!KWW!ER'a"PY. /\#7:^]wnx*^쮥yb:,vj)UvoSxA&pb&WQ{FۀH A2ê;gu6* /a-"R' u8̙ҼD"L23x{#5$3ZD_F)x*uξ|х$3s$@ @bW  P]5ھ}gTWвtL.6T#euѕ5pS Y"ثyE!q6=X9)e*ٟ,I*%#<85uY Af:lԑefVKdLf VˤvWXg0lJ"E,3:U?,Iތ*c76+an `&7)2H,LjfU tN+Y"8Ej ~ͻN_]\ y[5-pUV^HUGA5p#'=SbgX͌bW^asa1[:`=='+ t2xްH6@*e]YJWo"4<8@ tt)+Çho@'7YfIjjzxm2 `%+!H Wׂy;IYfgdVK$ogUAdZM;,R$23A^`|f"#ΰh; 51% y3I^1"#4lTV D`xLBƬBa%<5eVeLcZUX$udHu/iW d%ɛRVObjWê /?G^9V@ 4dk3)Yf:K^msAeu@dEɪ/6҉ՒXW䕲*95p4Fɫ~5^i^ naJ2xw}\^-iBH2ӱWj߿2h^]EϼAbO)k[+w@+΋5ěMOV@ 223a \_.'Kd7sbA$3/Fm:WLV . *:(+ l]pkW)ea{X%22*$%tx:ķ?AYlo<\9TżZBW>E ? E,3iV{Z VW?{o8O(~+]Ε*U \GR}e+;(-Z7p*˜D`ۼUVTV_.E++.5 ?iŭUO;u<1`z`j&͒eثy]%2ɛ)X uBU^QU0n TC50Zs_({N=`]p/ Ō313;:aFBZV֠7XP1V^ޘ=dЧ d6)c;(+o:yU!jf3g:vǡϝ~-1'<ATްs gf .1xv'xozLVA LrWBd3zV`+G;ޡ;Yĉsddd;@ȧKq:WZΟen{?}+ۿm~,ti[rE_Q9GT^BXm˴ҕ=iYuKFpMVm+o,3Ӱ{R50l++!HތWv:LXeLfRVzV?^EF''E,3CUxm'D&y32<&eU*߀j/ٗ)`vP 'E[ض@3NmC~wh>qѶg d6z"/+q)+e5xyR &$30.KnOXWok~-5H;֭O }ne18dەI=q[,ymo頿CsgUX*Z鷧쵭4м2/l+h$vye9 ˊ4& n,awm3TtWGy IdJV8\Y}@ꡋ330G!J<Qye\b MzjޙOГiM23Xe53eQ`O5UJҤdfFSͫqd5*2=ɊTHfdJYY۷W}HFӱ8 =Y`{=}=1a)HѤ=Yyg1m:-"M);qؚULtSf1_:Pj2?뾰w";(y<.qR.D}y_ 敽o"f$LJ?'Q>YՑBYqMOV"ӞHm<IdeuIde5x3VTHf1ڗ3s"{:`=һ%#T<3 [l5Hn}JOG l3~L@FbEJZIVpyeG0 _: q+=]+NJlBYUZXY=or=)Q:5S$IfUIPV$!;QVD&BY`FYut eEeAd)IfUIPV$!;icK IENDB`PK>-Pictures/2000011300003867000024DFF7E85024.wmf[olE+JZATB(G"E0hC) Z4B -b$D4| Q5DAP!ununw^kLo~;s{8Pk ` g<6q.0T m/i4Ř-0n7.iCQ&*` vP:R-0{zSzI6޽(F0:9"~j<(vqB'tƯʓPaqW&tR<+` B &[+!Z;guE1W՞cn~ycح mqX.J@f7$蹸˹L>M4!17\F.rǙ8}GSJkÖ+7>n7ﯴyOǏ|? X (|?ƷL>% f±Vq f|O9fn'e]OL|}0'Gy3tx½xaw=-Ny8?4E,}h\* B]L{v9~6}LK9]T~\t ذ sD1l2ܟ{w/P<'´TNeR)+] oVx^jW(Q0c6٘nQc@}U;rڟR)+] oVx^jW(B /X\CS>_S5/uRپHqצ>Znpp㟏&ɼN#8;w֫X^.p.3^ZsNu2_"p.y y*P ˌ?rX\fAgMg3Dby*,o8 2X(p.3)ef2 P3{ [u;<]~.?Oׂkzty~miyz<= ~[]{Qtmm :>iD1{8x>1:/e3 W0=y"u ¢x TIE:*Bu2:>8YǴP7,:vE15TGѱբ>):Xt,S} qqc,/dܖa~;}%[4LL)9)lgeB26ll#_%H~i}T䛞kQCśW?#;ZX5b؂'xWA V⎭b=i&$S|:C-'|#Փ|gq??[#4 #}A3nV(t=6{[RY&# }_7|NmeۓPqNJc4~r맆SQ]6au |w;OK\Z9:W yPTuŸ7qwdYLuOzwi߇>n^Z#lx}tƲw%GY܈Q휞o%dkfz܄׿-6681_;L߆Ɔ.GZ0V3cV!U̢ﱳ[Wim/1F"V^u9dx#lNvR_~<iPKtV2PK> content.xmlێH _Ax42\r()j"YY5B.Q+(RMR~ICbzo=؅ƛDJ$%ޝph KǿBqgQ`y! .^AI,@GB7`6g .n`x!7̭ݙS7?2j(߸ ~.0r܇xMZNNyD/a;w.|: ۃs*+k4zYk?2pLM؁޾+XS?ow8/0۩ql-Y9S\8ݧ-*qu ^wN> MAe6~mGp[;rVT6@\zȹv*o?2ɯ-׽ Q)gly#{uƯ<:"anm"%iRo@aJ]~ʤ6YdT|Po19p}Peu\{>>b: "*b;ȌIЉnh ^jYyU5*CHF(WM2'{vPn ʫA l1 cklLcPPb% g^w"aGK&E&)cuSvOYnv85f`pz P}8e#~ #?)?އ :=[}j##W_Ή/D?32+0 o7v̵!P8\R#gr%ێ c{՗-J# ߂~҄@1kH4[G u;}tB -2/Pc's( <3;iEQ sXΤm= Ai2+Fֈ3=NvSR7;oN<@Ofq;=oQNCF][R<%#˛Y,>@>RZbc-`%C mtk^ɗ gǵMY rClS8"[`AI{/0ryxP--. ~FȤ Ή:XVXWN{jK3Z#mXGI`_0q_8QhWo [y7v|N 8^Gryieh0J"mS{rӚL7(dﱁIn۵w ˣr5R\vnh|iYm$d\?Ԣͪ/lD!++٧FRu { %_ÖƟ=4f(k3Kme$GY„y|2`-Ŧ_a:{/v5IO ְ("Ҧk[h?@gg?rWl؋=مxό^3ǁqKH/ՏRNzfa٭-%o?Fz앃r_9zKTm4l/Y%cb9YupհzWQՅW/^zOlG ; rֵ2fS5gٞ6|k}cWxKCuyd/ٹ3O<%RZĠ70i:-4K*3BȂ?b~ пk էx%OJӯOЯ0R}ۈk~ZaSM}R-_L&{XX&~}:c"nj7xd[I=:pUQ$jhy:i>yLCmhicq'wz^o:R_ivGޕ/Z k<(Z@kh-rGP=h:>ZQV%*=e KhrL͉nglǰkf~{nr߿q[;qxҸ$Q9\\'Lͪtaq}; Guqj]qͮPڽ ܉GƇ+Nۏkt\uWM=_l;qaOԶۚzr7vS16vvprcG` mn` ߿Ucmn`^XO+n=؊EͺIu:äuG3X]) ^eۺDbwr' *IKHP)'[-kqNMj.P8tvmwsBӠw x4:}JkճZ$Nvŧ7qhzug)CX[64QDSڟ鸽qX~z ^iya8vR&iqB6MQU9ݰ;j_星~ݳV9pY8X`yo~ռ6U*WXZώ*7뇫zbl؎-=-iToNn/ jZ^lIF.XoZذoZ8oa'11鴖GMn`2|AuՠNܢo:%rjJ }]UZ귮~ Y3ĦȀyK}~Bxr\]~%mz$wӠH1sp\֠i塲3;r Nt~;yjg mw{eį連fّaMG"տLJ'GAϪ>Sj-4N+C߀5jO3Kk>|ѧ-]zw8ƒYoJZ mSU2N.ҧFrv ]k՝~dͣ6;$IzêHbR[3lBkL`GИvaaU7qxJZ&?FZMtPexI5t o{J>ig1z F;iTQ{؅`l4KVYr倫V7ZSkNTYnɕ^P={T>:Ʒ~hMK_СiwhthOOGk[\޼~1i#vܾN*6kZ鏴M_]:;w #ox%LSnbeG>jzCk{TC*k>%U4zpYY!("|Ł;갉GfucpA`Khnܹ~`#tjP[Dhp}{ȿh%N&BEK9Pj¾\:?){`en^I ^_]981d `K.B,haSKF%*чʓ0n~e&JYonk4Fcw4}\±EdԺ1|)"~M1hjǩ'iۍe`3gO,f^FZLcaSzudd-o%?)xZ[—Tqo(݇qY\PRۿ,l{m|z|gPDƶWln9m}hM; Ӎ\ 'َUUN@/ۜ2w@lvV}}WW,YUYu`1WV֧_'rmo+hqMdqn l+دaMD"\Nz iֶgdJ@mKD e4-1Iٍ䇋МPerzT T3N ><{eߵ-M[?=[[><@ @aOo5[KЍܔQ o+~2j=VC h|۾ĸEf:s9Ϛ]^Vѫ; /DL|4jx wم߭o;qڼY׷!pip֫ȝY  h|gK:j1P4؇;|5˻~gvLznB)zpuG-ZNk|G-u>zm)=7 5BZ2urt&oaKGq-Ƌ-^gV3fUޚaӲH x٣x3;p/'u?ΙEKU;UѿkY^ Y<}ϜzD-5#Hv\U?`eTfdOPױLL^&Tf[60H:{g8ΐKO(Cevc2x8e8$o[fLE aNa atlae301,1n8h^Z#y˜Ęl cx†1fC#E/j"oc~ufG1î9vaLodǘ'+cI?iG'#Af~=.y YeC5P6l '9Imty3oƜ v5vxx4lZ~f v!ٸ[{D f&nVHv(Ɣv$m5JiKU#^H^O׈g! bX&tbGwm;ja7! _w2K޿EqsfUlDK%.%٥O8+AtX8x˦1 T]g爆TQ#_ =;+"0/zʈ{55 o(π174VIfOmO#ƅ\݇a%gB76jl3{y?r ׮7Bs[JEHu0U+ &FUY0I^j>5*5 usFn.Ι ϶x9H^_xJvW?";zǟ;K]wB`6O7f/$Y,6}zʞPkNdBQw5Se L6U&INMz<6#:ܭ y ' gy.(bcZJ_5ǵrz]cXIIIӪȞ4}|el3v`mb ݒOv('t6؁n'tk;aţChF;atx!C8!4zoW1ȶ"4D݂a̖9f|S$d9?z??:1zu&M〃jKcho`ن̔C49"# QW׮a Ťcfr slVGA/}GA/}G/:P#dn[(큘4DAq3}SxocQ`9.a `o&p=ǁM^.킚v4Гwd_Ƃ R-7ГwO{4 5bSGƆ#k54Ҟ;>JPnm d#l`kx9e>mc>VYJ&à62PZc&K*Y`*sp-.@tけ&udiv9++CHڃ#.UpZ3,O% FEVu}LldUj_iG}zibv$҈ُN87&x3Ӧ;ݸk`T:H_:sEoo^[d: #A)0֊"p-o!9Ghk@]Qߞ6^&3JA dдߞ3^)*% ڻkMtgvecf9@ CP(ϵO諛jz z{7hAܚFz-z)5#?]+a'sN"ۮɬ06$韪CqО8(vKBč63wwS#{בZ^= T%<68!G} 5b&Zk~s)hKm<_3+i3Ss@vۜ9.gC4-(4lGrؘ?2 4$v(}Uo׉謧1Mi(ՠ  =.;ɢ=y\VeKY1Pʏ?d}C@6HH 8'9 C q 8C{6S? 'LLmrѻhsÔS~L읿 mIQ6aJٚpff4r1V Mt++Cx%+os)&ȯDaD^_x`o߿I{GRpo/?j~Oɰas:S3gP, le4>0c'?L]Ob4j!|}(p8nL x/BߣZh$ )'v5HYp O8I8?×`XsX[ p)=F -$W *spn-|Alpj l-KFa/ϴ6se)8kKD38C`nq~F a0PLP@4^.lo4%N pY|mEֺXl8Љ;"tw&HN3dG0FvjIY{ ~g;oȴs;}y:|FahU&6U[-uK`XzlNXPL͙L"r" 6{џQn48K6^70ڇt x>nPCVp`pY,RU0.np8㻆1ظ<7^iڶs^ӕw>Dž bs @㕌&ڡs 6' <_NL{@Fn@,) ;%%<ƜM 8!WkDžwฬ[ШUV5#;K2EY N PЖ7®96I"7KF;\`QHTU+vغKmI-X׏@/ +&u¸ K![k8XſP%lQ Z2?w@VAe/T\3zQRƘ"݇ lab adv׳ 1HJ,0zo9)0$p@ŧCR  ˺Fߐ6ZN2RY,*{LPP";g PF޽ ,DY DsSCEܟ#3|wypX+$ž7) Ď%7 ĄaA y,F?;_ r~jhd4xdA>9kB#.X>A& O b;uT%vSEDs{MYDie'tԈ[x̔ݷDy}j˟} ${Ef}u6+Tn@馐̏vD矅1q0 (e"ri ?aAyDСj?tt8 ʣ 5 .}I @"#N$^'kkv#3pY=uR!;qL뷉HERd5>Gزy\İ)Kj Uib r92-Ϳ3mu_X0D2U; >D7D23{0Rj0x>70 ~%55eNz=mCvBTgk11_BRA +F]Ugrn9-gh1\q^8V%vˑW`}M[9UDRqB\HM+chо Tl۪7;Lk l . :RqΎ{#@$'-fق~,] mՏs\}ey{`ݼF}la42V\p~q\+*!7#!;f%&3fdBF1WI%|d,/:K t?tAT2UHMH|m/"|s:A \JREVc$ T>~Sw0$HaI .)>(GZz] hY,C3͗ 9 1G'[s~F|X_/U^|ɃZA[mmd\ ['9r\]S`He4lkf^sJ^+02tLdk+EkFWY`XsbGl?tr&q./t|K㺭SL00;gXqqZ"ɁDɵeQAoqJ^nFE{-y*$N4rHry62ˉ lXǏ6/.b}f)fRX[!a ٬g{PgqHsx+к}߳6UlT[c" Oa [(_# #6 ?Z28HejJ [s;a@LN&4.҉uI(}~6ll#R&OLS죂K0ŅQ\ cJ%g`ɤ貗.(;پ0͗#]!QT;GTAiυ{é oe q2#>Ьxzb]ZkL]ZT8y% MmXEP0fFw<3;4stf7a4pq3JfFMY?#a͝CWPBmv-%\ h,1 c.7+]S {]|r-R a Qptte#i :^T/~zOU7y!C#.G(cbeD} íp.G2?io}tŀ+xycu{Y? KVÙNA(kK/ x@{!@>g`'=Mϵ^Wb_*%5&dCF/C?k] r1t (?MYRM(`- sTC%>`ޥ\u"JרkRBm['O 8ngO-ͣ[b-\?H>qgY|1:ơ[_ioD.WS2Ł(0jMn2MTy\1$0 -ӑF?I)TO\< ') HW<+MILe6־j tyIމZz\7K_QvܐdS肬%>bRFC[1t^ڂS$GGL"(.Ssdi9=`RCUzX*顆J^la3i, RxPlgFCߎ*=Te& 7\vW4DWŶ[*/M;F~kz%ƍ劧IkaS0Ft]&1f$֣ss5$tC}< XTѥ'=)LXV}N^^E7wL( d$A2K(-3rEBύzͤ `>V"ynCu %2elO?UNEfڦj%'S4ë{{Ksfe1uA'\8?Qf0p>k;.#,NÈW&3Zsސ_ u$.T _mh c K/", (CFD;Rۂ^׈] "i Kb,\!@#  bWSQ un#O)&dT&%O5dBy2>es<ް_( +3z.2(JyyY Bf!!pԂ629d01͡Q,X+!L 'NVj߉Y=S"n2F.14L6PS~!mڬAZUHd *;[t<'\ܒv_֫L\9ه(m"6My&Cõ)f*VhKiB%B)5joDDb4eu 7).k•{s5`eyT@ 3QL4ȰMVUxrYj #ϨN>o)D%Ddߧ8$e2&:ӑ35̲ R9*}h$j֮E\EZEmٵ!*ET&.BO+MLbXbj\PRXd2 a,}#"asw6OcS&DEJU3V%?f&P++ ZX`/ {17vt'ϒ[c1͝ PTXρ2FU=T>8ØVFw>_3LJC*(q}nqC6iEvƀ&"DOKjq jE~FPa [ds*xa ,E?ګUqetIYz|k0T1Uz ﮫԃÅxlǑ/]J5(II)vH05lI~lhOL 8om{%YRfK"PY(@TӖs=E'bPES,NDQn)Ƌ(R H.cVRѵ]^J~a;Y5;p\y?v&vM7o>]0:L$!_A`=pA*`vN`dH2>;ʒ;8 خh갴=O&)wqSI֌#b3H2㰎2fKx 3‡{A>^«|vorWTC8]I68+j?IysCD< ~\^" ,CBă[.߿R"y˗/Sy[Ú̱DPiҚ0| e[\/,/PrYf nآm++r䒨 BޮV58%v\JWIɛgG ߛ$F${"ڜquX4UX}<>R@Okb6/U kzM[<zJqJqn.)tg!zXypP N1cS)h؜ s0 I-yKϜ;pfsh9wlA}2hɨ9lx\v &1)5󖱹3_c!iSbH'! &$HBf*:D^kiYyj\W+>V4 貅\Rۙ.ݯ)]zN)8}r l/V-1`ʵ-$1S)+六V>h45dϵ`\%08YkХy+0.[pV;_-\p:f&(|܆SV|鳆m n?95pϵ.پ|4ԞU< `~odcpj&v{ֆY ciG1O{T4 ڇ}doߢ_,yLi}p KEVrޮ\hg@@\% %`f<Ê;uozǝ&θ.\Uz}cG@Yȱ(*: VV0Q"nGUT2b喱"i&ⱅ3RBv)c g cgnjWMEΚU iKe>f"͟y_M^6?Vm,mBY]~T_me2`^ᒌ?}WR49-EW2zG(1 H+>hI`=6 YX2GKB(g;YtY/k_̔Pp#KױW5uw4ũQj93&}{xZ^T2%{on_ Btgð=y&٨l`_<@p؛FwG{>g":bal2 h9BTwՇ#iqI~D]E1= u脊:;&:5x\f :fx6JVp&AI 08XE#Z,C6 DAiR|nKFc̉'w ^ .Ĝ=NH>-uXނ",kʉGvA(x"KrH{Up YD!٧Yl|edi7Qn%LnZRբbVꕿ280eZ-tM!XĢLJ Cgdr[]$!^r9{r; Z-ؿS6S9<-*<5,+Fo@aRO,a؏IcVhg~C$ "g[ȳj O<DMIqU>҄Nɢi}g*G>d{95m9S֕4)Ԣj\V&޻;z9Shl5B$5e9ЗԖZ5|MJCB#7zȶfxmR X:URn& JW%'ZKf0\9R"M0 xт@:Je ~ߛmdEm?%eeuS/_Pb&kf|[(G3:;}wJENw&feF%@lu_ӕExۇ6??ZnqG땗Gx߿~uG2E\ǡG?`Mo-߿>j?asxr^7]xQP/t߄ ~ؑYsf *-1es+ӫW"͙UJcȆQ>~ o=·W5 j ؙ|u_E?]S{ub{\|6{ic\xv1+ǩO?y 3˵xܡXOaVã`CA UA3I_OV:5t]e'aYJl9u '*$#c;z*3G˯@{dQNA ! xp.ol̊ZE 6c0oXHn Lq9ǔҕ>ps'MgR!ð##ŘE%&/>Jns>'^ C{u:v#/ICIn`3oZ&+0̣xG᜷d\5>"w `,H^@!07% 2r]̿:xSkJ?f}ZA,26.VE4 0u}0/G?TtfG*V}S#u2~QJҖ0WYJqM4qG8^.?:!w%ϥ"ZZb s]g;T>bbs{rq :niDoXaH2/UBFŚYXIS#|wA^W&JPH_EUᵳ>XtYp@ Z-l)l1,6H !{0Dz.:6"t'u\~<9H9qESq",6sBA@aT=)Qu2rs3C i@>dr38kvR%c sl8٨^oT!h cc51"P3a0l]kΊ0U(ߓ8>M{p8Fldž]`BdWBٷYk,D.5_$Nl'!QYq9p xtc \mF3&Qo8&j VdaQ2 7ր4;xqg3ڢ## >Z<PD[RQ5+X$\8`!4ԱX숻F!T46a,{t.PcM ȒA׭E*p+7E 3B;(0~Gdvj_ 笊pUXVa1Մ٬ֹsOc< Fع9d>IǀeC[ucRB}Q."XՉb=MdTnPcaN&,Z&.4٦K7)򾼑8gfqf| o,!`B0S& &)b8)U9?ua{,+Me/cU\ &ejҽB|xCaҊ@ܐ1Bbc(iX eaEP3d;Aϩ)gI+q5f0Lt1 -6ⴄBKڔRjPX7ƅA ڍ? u.y 0E Zkr:t 2|'c6Ln2陦9 a]*eNd-bJ$F ;S{3SJiUWcoWZVK,Y5-T (ƅuɲXhYbU)DP-: sk4/[5% KYd9̠/LkHkSh*E!cn}Gf(3P4?QYT5I1.2Kt׃ NtN̒"? s5b&b}Qήwʜq/Tn@ݦ0'wk7Q sl=kJ& EGNXҾ.9J,h8)4 1[鑺D p"GъU-GR;lȸ<(((nP:[/ $cs+Y' ;(Nd7247W, ݬQ": [1BIIxȧŴHdl#k%,Q|ܢb_ ,^(9˱ 1ǚxV Bdq*e?DV>u(cb)̋7&gFP)%Z 6g&K>jO&FxV1A#@:v K$G*]}˸sCUP3w`jtueJbʌ>zץmUArrXhoedd|Kצ4ڞ>ҔNt: /D=,U~n*55bå/ G۬hQF&`aw~2DDKхخuPx#=޸pX!9yWLFse[WK@+ q=bTTq=#q~;0fͫ~\c[-k(25_Ը ~а @|.ے?S]k9G6q(tPAhpVZXz3lP/a:<7 @`ڽ򪫉x⒯jLOY"HZK68/= Sm:J"]N>bSYNV7xaad-Vtӌk },ahNaxc ?ܓJj(z's̅;?HA ]'z]qͪ %8św5. ~Zջ~e7f&cqFϬ7O7_םW Vj74GQpˆGEA@}!:>J~ ʮs7SqL!LAfv;׾v܄}Iœ31/,\b8^G' "Dɉ.T4^qƑxb_Us/\tV,D *Q*19[ؠ}:Sw|#kLy#zRZ Px 0?#M{ε-CjD#]_b ;<'TC3>PQ$9Z*>D1NIEk1"I1fqMN\ XXB$sH12ۘ2Qj0) #cus *'f_/}j| # 6kJ; }=^ }u.GdkJC_^]jS%0B|KSJC3!M*1[0ZUIY`p!МCz)ъc+PM7.hj r֙S 鷎 :g1H02C\A!xh/:ilYŐVq|>^o|gT6$}!u8ڬɼJ́&ĸ&ߍ«!Z$QUvV"vF{n $̈d~ bk~[ޕ՚ӈS}*~"poY"o _7O%$d~ İNy$"%Ei_'!L" Z ,q1_ŻR1\] ?H*J.~ p~=2U -o-bnD@E#oS31D\ZRK{DV\W_F/JhT)=.bzѬ>XoG.J,lfZtIGtjkaN?\%~h ]˯_+v֔wk.`: qSPإۨ .1%j)Ts+阗,G'la/cE !s˂s'#B%OeU;QT.6q,6z̝CS"u5(CAg\9MȨYKg-JF>8ԷLu8$L;3h̊,ɳ n)§P\Yb,HD;b&WRdJ1/1Uqyl[\0X{$t3S E^uD"߽@-t nZƥ`aB#Z[xa: Ca$p F~5p9`3P +ڔ9 ?tD2,jn( K?1@}f&}շ!#YD?᥆>/ˣfҚG-t@Ey8b04$WԤC3o6 Qr}-+3K"DŽWI)깫,}o}!MgN}ݑidF{h ~Q=V8~ B߹﷭^U ]HL"̈́cN6Ƽm$_:~,?OH<ށan9^uwu~?cPj'&HpGrTSD.CZ,*B~( -)+JJ&2y^<`ׁPHSUWVyDaU]@C4nn}o Lv"ٕa)PZ;{>`o+W| ]|V9,'QD&ƹ$J;ZMѬiYn;r$iث8h@vq* ${%8${gg=ܣ=PWs@jh ]I+]ԣ +"␙553@3}֋j㽎ߨl}٭Lg)b2Cu62umXv#]Y/ʠ`ԫ>9TͲPdNa @XrM|_"N td(XOt薊aKh6B^}w̫4HٽH<jV2u+nB;,yPS |jy"J]Q8RB%Zvt0@PtzeY&w$-͒k5sc,ٯƅ;ftSyYۋUۺ?d= C@ke՝x8&Xɧp2R1G%1`5 q*dyiGú՟}Uy }{2񚪍yd)S?Ƃ"D:ՂHc-gw03ЅD҇46 $ql5Teud.nFCBkPc!j :Ukα(Y6p%[=a'18<,϶?]ʶYi{ 9&5`h yl{w;pqgcIJM)EhQU{ I =E h|ltZWi`D{ ljCe3DIv2ʄyXaʹYƟE7t?o~^*Gh4*&A>d4eΠŌkL= V.1"j2r2JF$"t:"Yl,..1We,;GPVdABs,|{[̥ܘ*U4I<3gK".63, \:PME=+PG"2#H#["ռ_/:0[rQl<)L#i 0TN섐OT>S?%Z7&umҐa$ ɋ̟UTK51=SMN 퀒jPMG0{$(r{9-($88t8=JytQ C`ݗG(Nt `þù8j.Fhrߠ2 #^s{ 4z!KTᄒ]gLO Ji[-p$ P=zAZiLkhM]obƼmK 'ddm=B'0Զ`8u}ڶ<Ά٘v<LgcÞ;ڶ<7zld(bsG۶'c8<1wmY,7LFw۶gԝݶЛL&{C6Ꭷ#wf󆶭rG5m$XS޶s̾gtv<Fiϭm;edl(EvK\muS4J>-wLZ}ГFCũVZOӸñu$ZC&w:%UԷk@ZF<].]{wվ0~Gvax# 5ReG6mtpw ʛnAy3v+o3SnA2깻ˀyS *~n۩TfPgnueh7nBjkآ綶=ݶ硱Ѷx8 `gnݬL3#WCwۮSvî3?6ƈxߞјvރcݶ=b7n0 Um3|SOY#>~K}t xOddm2ر:Xn/oC$+ȮO"1yԩJW yLvX- ~aF".0VTB UE9DA;(0@CL!Pw"XD ðAM͜6/eY[.(=  "Q7a]QAb%D)Djrmbur\]brD!3Wݔڐ&E[UU[Ǹ=PTV 3yRC5$_OY[ /2HָtiNU@gĊ-ʡlR~X&Z†es_k ֲikHnZ6Իnv>mn7 Htݠm7X= zf{mg̦l,lݶg#mgShmly]vl7vjݳEHtoH:oh}R Jm7:3OJgΞMm-|n7;nujfcQ[k1}cx?42g?9Vwv V搼UdKYZ_O~~.Vඤ&_G;U8 CF:CuH-bfs1:6z $ƻ:&wDMen)ڥ$~"`6Arm0d6KKH%bHPnZA2 *naHNJ).A1O=U5ƹexaͰXޛ5rő2n 7!<]U@H,-tYA3zޝL0;|T^:cqV ШK=4 =c8]gF/NG ѫV3^DP< 4 d0G!'†VF}}"ʦV8B#RCML(.E:!OAM} 'V>v@ ;A&aF!* ǎ=꜔suz_TxJk"_#I2b&@bXYTu09СE>Ŀ5ԆUxoBsxFy*"C[]~ցi^t <'P4u\w-XDz&DLV.GQ(TmPB&T Yq -[0" 㕼!]P';L5!D (筸QVO% :X]LFY5wrb9(\芡PKoYW)슋J j!>NTߨvLO9;:>B_ b R >=d H_*P*CXsŻ @ baիF5h +Q/Z[) W4]9 Ul7wU|qLŪ\k?L Ph'þ*d!&۵[P(U}#'"$uh7zPa5u5nRV̕ ZmiO,eu3D}J ꓯr Re}~J7/bi됻m@K _?=Yqz+`!%.fvH#y"; @kc(lP`|xY-!1. )ĝaQۅnbRa|Sۡ|-̅ szm,i K K%fwL/ڹp(zFVHhOk0d>~TJb`ֳxa!00&>w}otA}xgy(T IqjN:uU&c*lQ-Jզ~bZih=J؝Fg8;PSd!w$L );{5Bg)@>-ہ:EJp:mz v4Lx= EFtO8 n[d6x;uo)Lh.8r-̍y-@mar0Nٸy9/^Wຳ !\Ү*9Lܱe2_&I byL`ozhYP 4q'-hb{f) K{5|ڕry:@aт'Cw/l\SCrNe}?R:{-P\*‹u"/8QqXPIW, *:pm0OCUC9_RBbx&Koy"%bs3#UBlP*ZQA&%z\ s+Y P9g3T8,D?8ePw}T(oh&)j  8. V+1SB9:4UǧB*  ط`W+B,iҁ)Icp 0t]!r=A1Ey@%bX퐗ZlTϧwW悩R+o#Ѡ>I;+c`Uإ3/ [Kvic7HV[LLJδ8P^*5J?PF;%Tb)3+g `C\g-C'g..p%.ơ:"bK GNؠ_]cm*f$H.ʼ<܏}|>; 1HU& {zXw w[$? /+;e~%RL. dby&ɑ֏?=!נص=莃r6Gڱ3TO!*  :* pO-cQP t$}5َi`)>1.&A\ BLճ楕% &AG}]0ƀ%4.eC^jj)^0XJeS )q1FU_.9a_ږ1}tl-,A+H>@Xl]IL9oF `)ʊ*1Pn@۾=]Ig!L9LAewUC j,֌vZ$* C,UುX^{O3.k3YSdc!hKÕr' 2u7OF'\U߅ .:* zSEEq$nTY-XږyƭGQ{Yzf"oߍK^M*[%DJMUbpPXv`xxoDbmWb4m;{x&(,v<3жs] GmwFvM{nm|׵|# iC '|5X 8?ꏇGLft?6xO2-P LT k[-(}^|缣sa4^JICH!% Bڃ#>(QH*\BBVq( aS{AR'-UXZʪԇ,1O1Hy :bH:a0U ,F-oZZM7wkiΟZy-.v-+ڵطkއmٺZ4v~Skmg.d_v&m[y뷶 {JEccɴvѹSe@ø=:W| a`=/aezԃWYڪM@9 12KV'sm+ ̼0=1-U`XYvJYvm%C1wFe3APlI#ES^2TC_LZY$@)͛FT;L=#dW=өRJŴ+ɫdEOi/ŝJƜ_W{Y\~<=jlP:vAsM;`^2u׃_dĕB<|Yzi6pUaRB_ݳ3+WfL-2ͶuH]z+;x8vZy{Ow[zKh5/+{»K[d4Pz7^ ~2Є|Ƅ gq}ʹ7\ Xh*-DmrɀI sSH* tzNX;r8d'}' әwƣz[v?r-{Q]<y}|iR. qVb'ouq]B? &OE G8U'HK#wofyctrQXViy=oU}2;кiz2 Ô}6;I.UT#NضQ}GYﰠ;>xtX57=$)1T4wcqDžQ@Ss+zPp4GQ _j 0Q@JM`-Fb@r! "tVr)Qw!,BEWelViFg u?Hӫᅪ&i@T١A'︃{O[j]-MJ wnnO'6K02\Vg!)lM" ti%kޕ!x]XhV٦cRub&w̸_|=;/]GWA=!XTR~+9>Urr*_x ej~P6Ouݭ6֌71}5lf9Z)e"p US݁UkfMZm־͚Uwz}uUsd[칓h7o+mUslvhKk~6v3"@Qzpk Gf81u42 7 l ΆHD`608RƆ(J8{J>Q <@|-3R1 ˚#ħytZ3R-m0+t9(N \Bu/Wxb6L% %&/ \y/J7e8~*`o/i0T/?! * BSbV1ɀtAAyJ+T:zw,pA<{5(/8MWb68,I˄^"gk)ތXAgO[q;?nPFLh~{JY=XFWi$N :H78U 0 XʱܫYjP-U m#KI2Hy+9?oEp.?/<>؉LF6!.3Kd#9 k[ܖtwkS 3ׁΜ099օ758SwA~.!}BWcR:/Ez#Jҁ띇_կu|$N쎰W;¢C_qc@|DPܝ{Om#-tw_׫>b*OFLp*ܪc׽u>wu>-n.4ݗ{Mt40V#6TJ=}RdC$LIsE2,- kzY^ԴntUF;`U"Xw@su6:_3.qSտ=] eP'|9]YσYб{^sy8 4i4E5ap@*!")%Y1 bЩi\fHҰ]]שc5'j)|͊Vnuz*F׳xz<[Og <' '`qp s$x? Ols B;"NςISiJo ?ވo3{h V~] pvJt|>:aLuo?Sk/[P~}83uW{_GS=;=N`'axHA$PA<"Krgc>/{!orTP<&ǵ[TVgIwmȚB)P6>CA;[7Tj KAHiTxφs9ai3md/{/Q5dz s5v~ dzc%S(N(ONY E?G?ϗNҘA[eyV#Y/݂{!n?K܃e . /G \>QH %"t~?~ڀgy1 xP^r1u Oo% ;c쏰>&apqWu/y.["aH\WcӴ@VY8e*";`[$'Lsr&y`OZQw=3RQXK{4r [~o^ysGӅhT1#sJ% y5߃̰솝2 4[t.@,[,GvBW{B/%kKxHv$~9].l[Ғ?G(k^vzO.qe*3  dUYj4d1u}`/ =rśaW(%VG|Ee0[ǿͧ7ΗmXuZh&ۣSA@ѱ@vM vՑ0!6X ;ϕ806-aţSC##o86|񎔡$\E.o>IIr%`sҢD#"IOs% b-z(L%h3$g{N%& 24HDK˔ $L!wtNmY(́,~((eidDV^.@%1f1ϡPZX]Sy_ e<_L!D&5"̃$ tvȝ6"UDZYⰧsK8`)4ЈtP>IQ}fLu&}s-x4l701 b!:byhaO~0u~kvM%3x wif +Ő9!F$q3k7v?=`揍OZVb=` y̨fn3*%tݖJ<//GCJO*ʤ;b,V*wcGR?*-q,S͟؄ ڼd VX)4.ҧ̵'Z _`H# +@ )&bKKS3yld&7F'ڈ͠Qi-[ff`Hl Bs\Uv6jp3Ҝ/0v6Y}C5,9EjlUE+a^>uo-9[bG2j! %ۀdf[Jb_-~\sFۮ݆^h$ݺu¨׉  y ՚??X=)ǚ8"˱EOH?8)3N,CIssTnSZK*szQ|IMfl<yuQڞ{FmKHEyξ'(W\ ŨޚZ=ʳzԯڱISHaXO@9Y' Ș&Y&SkǛ̩PH7ƦU3*1O-e~N%Slo<~7mwUցwa"CCbn qUƹ{N+;AdJ5Usim0rv4-Rl*@u!Vڞpr_mg͛WI:%]-I-\1AS|T.%ޏEJf^>A+ L9DHJJa'IĖT(WVqeX53|aN5!:2`*(9:W"`.y3qz2RHWÅy\yvp"-'7OR)9eIR3Ļ,H@  \9/]*{! niÅR d~Ui߰q] ӎ IS,#XR6Fd&>W;7\$eGY2@-,keEt܇חaR{2'uOKp' DXǛ;<͒2!*Vwt8m8&s<]b蟎ps8F{۞PpkBi2ט|wqM-|: `2,.Erb`FC\_\!ν0:v{w\̝ɯEHKB%hAM(ttU$B]'رrNY.FWV,C->ȰQ _ytܚ +BJ_;E- jw[awhԎ2FAR7'+;~o(~0l{T55C9)+9>9WvIG`VD`c21?&~ `c0xy~9o6_>1?S29))yS؜NwH˙18f: p&-Nvt_O/t ?9NOS9'֍Pgt :/,gtX)'/F7z3> "l6, g߮FjՖ' 2ʹ: oVqgG9}1UkeF&0V,մ/^+o8`w c$Z,ss|c 9n#oP&s{g|"1s p"C_zI^sաڏoاz-;7fF=x8yׁ0*0"U8¹:AJ*W*,oV} :Vq4Lϙ~=ޯyN}ٞ.re)a;b1k-O?\ ;@09é(\ͼJC2/g&P~iQ LcqXv٘8:E"xn΃9d!a6)BU 7kMmLb]t=e(:j\˟9,֓0]?irySXw 4xsEgYC{@ŜI0aB$ Q.4U#3^PH rds/ajPO4i]ÍIM!p KaH bVFyrs\ GNSݟpOQ^ ,SRh 㳴w6> %4@(IáN[˛=w<OD%d{!zӵ=8֢tZ <:/ӤYGϫ$ :3$\Z7>zt,~dBlrG&슼 JV\ړC}1ӝCaJy9Q|6˨pIP k2*GRC8g^P>  EVCJGC@sv SƐd gEE)3R`OJWSPBjN$א|]9SAT~. vHYei@v)Iۖ>?y |t|g{R T UnXwPt laL<6 :˙u9rҋ/߶qUc=`0_-#r a)tŴI.4={͛pGr8$:t:P5얒cL  ୱ;*,$4x}!o~jS5;|>À Dӛ YH ÞsQELB{w@.y/w!*;X釲kt(A"R!2(1qxA}9ćpc7soF58Ǐ$(n 9>A9kdlXdv,>E:/~?<_R-q偤˨Xy 7.4paϤeP L;;濂 k< {kY/RqtvS砪 *MNwCv0rҵߋQNDp!Y) ?M c(ٝ~-3DO=室j+˨?:-0#c8.!N2xsAK5lg[^A`Z64`-S f2܄ၦIO}fr رܪTrJȳnáD , QA1*KnI(:>n(!_ɂf/S&&.A1($0*rA.ot5E[r< n5=YBA$B~'S`sKo} OWpFhfaEs b_?)jqiYuEe0 }4HMiƬNM㸐7TmcmwLAkJ5x#-V]^Fp>Tb7FP?w-m^ ڐ3ǚͅ ݐ7Lwŷ˳&Tqnqut.}7' ~axT xCx+@{22VuHmG:('tv#Pb:yʵP/>MmlU*.w]5 g*{y=|_o{%dVcWVw> .xm8Z)=,) sw09 0N&۠9 /" !rOMl<_iE gj7jOXkhBuM|s9\x-Fq aAA=JԌdb6o@ 3b)q+N.CҎ`mcA~c s`5?tP!g F3Ӭ=ɣePl4s!hRdԮ#rXeD)CqiMrܦH,uaZK%} 5{NuL[6hTmt*q\%ncQdD5,Ҧێ6@oRKl%i^R)PWX nhT>Wg|SN|[;5PP\L=-LMA' 46& ??qEBex iJ4;z2^V𙦿Rl4#|í?~Q&$qub20zڴv6KfXRY(/SONmV<pL&>۝';j]}gB =L&,y'z:ׄ-h㌆o龤g Xw|.@a fۊG޷ǝQ70X@00Ҳ9-a#?T* r.Ȝ O/Q=N.N=s?arA;g)*睐K!-;`tJ'bW:ӼZ*J%o-/>Ҏ {W}|V,݈#T6FPAF/KWB^kkc& Ia:kY*iӲanw6f 2?d.Q!YX\a=X\Vf5Az3Xv9t Húi VhV`)@W{WMu77GHDJUd; "k4w4:?g>Uzmڪz4Adrc F֜Y*Q:5 C>WQ+'o>UJԝ!`3$r Yp^Ȃ/G|9b=z4)e^2hoWU` D4V,ҀwnhV!fZO,9"\ 8ܾ&4127Lfp:ƳnN *jp=>M9Q|).yNFTR)gBp\P%k2șˈ o:,Uj0 xK Mt=kٰҒ=^Bumx3m8a_(p(@B}2:/~j߼ _`E%QFЫ 1ņyur?@ic!+"q>*U;{!rhhuv>%9:{IuOwyc25cAhy{ -#'.T<-_c=ZP8ZbÛ.:q>w։ì9EK6 4J8{Kۭ5wg=_G()u MLFb8{1$V"(9 4Db;S&B~h,Wt\Ȍ7~z7+$,d.͐9#oe]jj 53uɊU{$ (ue ArA+ZPejC>K7ް/% }_\Dqe?=qȵxq3Y5K Ϝ2bɦ]u 2ƀflC=k~upXag 1 k{P-%X"GC>CPiAr[\N c}ťXYr"!_}bsW% UTf%MBqҒoH)UnWՎ}=oZ?vݎUؖ4!tE+V[:JXkvbH+ŢrD1tצ֞Zk ƴ4F"P#&vmY"sU//{rQB o2(7 kE2- ?Jϸۀ 0D[0!y0ƁvE%p#h9} 3I|izT\v9a䍘3)!pqqc¿T,].59>;_MywBl`8\ >(|۴dJ\I2jPEAh ֝:yJc De:1{Ǣ?e* %8Gt湓tFE- nVs* X9=ar$ =]p;Ռw+41މ 4DL3:ϰV{LF;B1z\'Ρ.`>LL^)Z3 իǎ\Ua#5e DT7+TNns[sM~ݥ?TP{p|-wѹfw[ZTF0Qjڢh|oR?@^䶡؏MQK|pWOFO^1b?<m?QmdA5ѭa/})\)CNkC%uF!ڨP$3|x^M],78?N0NhOcEQju1z4vDi1}2j]._LRIʞ(;e4i0  ʸ̂L s8!hy@Lc @%`򨗕Felmvsa{蕺;to4t(s M?w/d:Q,[/1&`ŹR@*ת\Tzz@kUdR'ޖiĴVWҌzͳ!Iv 6rpq!:+!շN>hLә)_<;NPwe8LKck"a!Y8DN( ndqLYxz~_D.()B8rz ɂ %hOR `F &QK)@sXh#e`sYK2`@9j*s\=!ZFBo9̥ċDdiPee')C^ z4PK„<eh>6Zٕp&~v~#{.mBm?esFu^ǚDn%,ˀBᵵuyʆYua[PА}-V}PT,@t(h 1eTBBx!? sx㦫DG&Jɍ#Dns@l~H:*}~u [Ⰾv8 KLAOUw H?<$uFE TnVD  /(;1u=9n٬=GIKRzs=?k7Q];8< 12wL.]So涼wo6kyS>~ھ_a3ozfFgz?XOqbPOYn&jyq<TmeݞPL4bQz1EG\1cmgBEʃ(Fσ5>ۆt7U#zuP>ss,L-{c]*OΩi,Oe*򸣷rsԯq3.+vo+-N.]֋c׽$]Ǯ{Tޕh\+;ȈVA 7׿0=5ν4>gŇ'庀[ܷp/Z ۻ]œ^ѡ>/wwg]+xjJtAa;a5vOxw`d,y'0/4ehLY9:?oXgaϴ,Č~!M.i+ %bn QS\*E[V/ ]SY٧L1WΐЭ+ N4$T 8CR4pG2C kJ:ٞ#s!<`5GWmEXfQxݫ/ԁ;NAܔwNbfK C qfHi3N8x`HO $thx[8?0Z|/X0vY }f]a8)aԮ\]k.5ް%1{I ~"5 O*v<'moum[)wvC.o[YVfE\j`]$3N>Ym怎}Y:c>K@?͆k8{f24 foAE+WzJa 3:To7F;Ϣ/:hq#%S[K\ 94_PqQBKS~F{c# Ph.osqlqfn"+k1{U$uۤBT&BB4f !;,6=UɸYADyܭͮeǨQCr.iz=]Uh>P9 ^t @I@.پpPaA{d.e`}Λt)N?]J IzRQqx#IA8k"z^Q.gq֊+Wx)묭#ȝǟk+ĉ|v\CK= ~/qXgF7V:+ns4:#Uz Y{eʋwа=H-Q]膋N6{X]rhl^їv%Q0xa&۵֮I wT20{A!| LA(5Hu.W1V$ȂckE`"#㥚lHK7)[&8HJl/Ex2DB߶Wk%$`$h&!KX v&Rl I?&Q>=,*28!t%)P]$yA@ԙ  J3׈8oL.-I;"oy/҄7R+>{%`B7[_C %,C! #rnDh"\&w|{4IjI7(SY :L ؕQ^ r=Ï5 ?Om㡑׿wFUM#&QWfX=SzUv *lU%1 E!{8k`~` qgܸj>ѕ b,^Up_+v8_ #ȧٸp [g:摑lޏl>cR6ov@Dehx-zgVKuW=gs2g峚hokY{ؕ]jOdϔ//_[)u`SFF؞HK&t%mExҶka&Mic5%wJvZ;[H*?ZlIG>GLs[4rI4K^m &\_j״z` 5 a^D TGOF-HX[/T}j>hLH{j_W I%+:Y:e? R̈́>hpĦB OmҺTg&149*G,jB9jG`" ]jFWNř)O`ĠEk7[sʶ[gmʝ1SF^n7~dH! vb )Rq ^t-6Jh{f%YIF,Һ=oVvՄ*ILW)"-ht]o͏0Tޯ 9Joh6'dWvSAwWbK}@B:Tc֓g$i9=|C_BoBsXYv|tiY4ē*q$E 8BJAA8=s?!r&b0(-̢UHJ>!o#se26Y(xQ:C џl6~N}N fanbxNps+ f),ƙv #1&'}1:H⼾5l`hx+5s1E0qH>]~~8Wq;6sӤh%M_g:>qj=1x5$7.ߦyэBa+}ήOee|;I9Yv$e^Ef"Ԕ#;NЅI!, dzF3I/2-Ԕ_5fWGwy%[I1VYFE)gX_$1P#pe,7Vψ+4>nB]:p?ʸ0yBD͸ Mbw.T H9/k< |n"eP3.#7ZGrIY$,ٙ$v'PG{A#_H麼+|ZP% I*y_H&VyʫVjLQ~SeۖdzNȭZKжW"b >уAuZD:M_$nKL'~ /1: N!Jhnn?V)x6SWWi$$o5c n")+Lҕ#sgþv [G7'y7evl_8 ˜~VU""g8*KҲZa I |; EPϕ(  P7Oה)AǐR%X"Bć(XzaX8!U) xp1ܕ jPmvr ;!1\ vئBwEb )!)wP* 7N7o?!t%6p/\,_鱁n rf210"H0c wo +ҝ=wz^B79lzwC0%IK|Ou+O a $fqV-@6%`KF?z (..U Ȃ IKSm K~Zd/@mqd _LNq/0$٧2=F uwwdm#_!a2K<|X+$, Z$”S>du|VUWSݧRj@6uS18#A |nN:![H3bq,cWȍ 3A3ݲ:AQJz7*XAҫT\!J|^tYաc; e͂:{5)4 JfbDp`[1W"G`!ɣi]Œ /ӄ*%a fqorh͝/B"ڌh'"ܥ F#+5S XqEU@9F`DnLA=mOf32R*L *7#I2CL:".#0}ыi*CҫAN"y }RhMܕ(SBo\lK;}@ѿqbҨa7u +dZ2JLG j*D c䏦&r4U0C"TuR*>L$m0fIQk|5T"|m=h/YV p5e/\\[&LARhC^9TT6lQQNmcTNLWR|)?hs 626B" _ncrYpD gK JfZ}o)ϧqxM.4AK5 &-n J8U^Lb]f zЧKU"ޮmCR\[R3쭪ss-?dSi'+'` 6)ITwɿ?uحF-e,G`w8Ð=>y: UYu阪*g)= νYL@(̑8TcQ3ƹZ:tWAa3>bZ8ESqn AHݛ -=*/Y:][sNTl/1C@xOMjK%aRM)Ƚ+SAgp/h]bɝ#v!LZ..) L ݽkckP,m7-g[T.ۡBqR$ (9C]mM<ļpM„r/79✏[XOΘ{G( IVM9(/Sntc&1"\sVl\R!1[hY_hZ#^l20YZ76s"ߤg,E> 50j=<*=s|Q Qdc:n(ޙ7jd՗Y~oԒ .Xp3dy '#j KfՄ LuN?33#B6I5 j 6z\$lu M%(sK@Tv71Q/Z5?Y R ܨr =׷ @kB X2qYp$R,ZY4?J̑YSE1_NcNQ&/]]]az틖F[S٪H73˽Yjs]o*_۾kA7 %T"0ʨ@pڣq>R}XE!˚_]ٓm:Ji2f)YqC1K̆dZvmP7?{@h犀: ͎=3(cIEb-dH5bqp%ӯCN RDM,97GWIE>Nxۃru3VVJT ~%Q8^1dL]&(F.+iʽ"Oӻ Ӌh)a$<$"e?eE]4)T (FWo 0## MAߖCÕ5_-h\8}@E2HШ`\h~k,uMHuaN(@ĞXxŰ`1P?EGkfY\SWB3G%臸?8͸i}}>bq_UwB6vA7ͰȻ:$Ά5%H)‡Cž[&䂘 &NOns6ީエ=H7:wvQ%٧JUS`2fki.1#Xʢq*(ύ䢄 y}`>:rOIH88w??3q DXzIAs?bކѧxG{?5hՓ7Lc__I~49oeiS4łK@~@?,-`j;dsBG²l9Nk1|~ 7V=$1CkyM'Nx 1ھzy1qm`z kbm$^r<|o%> r{sE3⹡gmX8׺qPw&to^um0 lߋ(kVdx,+mܡBz/hmדƅg\' :kK-]wDH!C_( $8 ]; ϗTMѹ1ohRt-HF)u%rGӺ2i]$'EeZ=Wz(/ӺgLҴ.-n(D+@ MyTgZܡ]#!02q/(K<_ZUrGIDn$Ǟ#}+v[Aho#k3}q'K4ՅT,J\۵2Ɏk)v`s58C r@ ,sYH$n!Z)Z:3~?]Ut,h w߿PKTPK> layout-cache=ҡKCQ߻'! :.DPpqi-I 6Y|K&%caMd` 믌k|9 ,vAI2[[U,}C8Xn Wڏw0.(u vA }``ʃ @:hSp #K6B2JO manifest.rdfAN0E=i tA5I#OqH{{L  ޟq?={:t%OŎ3 ֝kK>&jSQ#iG*J~ aT<9[H<)H>'0V8JS]oWTj4$PSG -LGM 0ؠf{#S(9-PVT4`]z_=K{YX'Mڇ[.Dg_?z$,-ҾU-`jPK>ū#<ObjectReplacements/Object 10J@6JW ;ApڅD#PP Ɲ D]1|xЩ֊H.|0^&w2LҍTT|gw|MzPTł}כ^>as'b6kdYhK,?IyͲ̟}ofdBθōǦ2`kVbX9Qw\/ E`d0ȔngI۝E{Vs> F:E8"oi"-r˥\c7m^]o/bF-r}({CW7~3PK>,XObjectReplacements/Object 11KAǿ1*w5F* A)B5xlDBWO/xs};l&(Kfmfy;)ک K{ Q%f|R{l]jĖSzFꌥM2STB2dQ1e|$A0sVRfF0*V5@uJQӶ⫸u|+g..Ͼ)K~f]>/\b/n}uV$9e|- {~ZbLhyh~ǰ$+0\bDiȜt^.18A.g }N|yۗL#XTObjectReplacements/Object 12|SӼ{I˰A+.ES Cn@YZd0`ÇZ* RE c öAoRfܻ?q?ߛIr=LI6 SAO&Қr^G:6AӘv  >+tް2L!GLcVa6i18_ ڷ{8J8ɛwZ}syQTGEV3ehػGWǴm;=L\3@{}?pE򹼄e"^}WWRs[zޒ-{3MYWP7n_65;SzrY1;sʥ ǣyTOH(2AfN &ןҵq:U帽WE_R۟otP()<=##j?#%BzEZdW[۟ћג_d]sʍ*6__wͻ}>:g;TmkZfJ+i?'s~zU5R^ɯ}-إW.AMΛ_~erWcz͠>zy5 /ɛd4er[qkWR_xpS97=y.fD Ɵ'/σv'֝*o*Ì%9r5N;R^"+ḓ}mEnwv/W4Yd1YK;ӉbwՀxfs->URz9;ٔŲOd}gߍY'szCw4f<)J9{TJyio}֞ʀ{M7M1<$׀~z8ޫ]{vۮ7g5S<)ߟ>cisힱWbvLq5N]K= 8uOU蠧 N=` R~2ҫ4sRNu|3`s#wEv |`+\D{X<PP7= Nz{N]q4;??_F%s(Q6_sPKhhMFۊn"~huUM߅f'=Ml;mȩ'?;'|5-DHىDtcx Aڌ* wF3}Unn9ג)z4;'砚{ķ_~=?E-9VʠwYW%_?ö"O=\sDUo3.RBT z5 wU.Si(%r{T^E(ߥW=J:8QH(@ E/d.s%p s1y6.ʢ8 (7zo^^|#|H}EfYAn N- ;d!eYHѓВdAN^Z SLP!E_ByZ)pDIAe.|bVz q N"zK/.2y׋S/&y E?vH-2E"_3}!9(~FWegtVB;b˧UWT%gT3&|3jgTqFxP], YUtPMB[Fd{ ʎuz} $H5zr(@(8qcɅCϹo& 74L;]|\!6s=,WjIA[*+9DamdFw؂<+s/_?O.9z}n N:tӽ!mr4;alжmq˄2'|:zgv"rr,\ bd*h+ҫDO+[5r=mN׾O?x=t'۝N=r<$GH%q SL&;Sa#2R(cE l"&Qc &D|Ew\~.eЗ/#A>Gד[G~7x1uU<|$dO9}~K?H"_R"_H| )$O9YvEUhMB>̏?s+VJAI2%ɖSn)mPM6Є)zS&oDϹZtd:@ݎx]9jw H~8GcCɅJ(j"Xݓaaxad.֢ȭ$*x!< G V{>CKĻ#8@st=$# M(H#iО=92x9O9@+Š(>t-{)&Ud} 듫G.8Ck m[kM5-Յu a׏L`:shQ0GA.(N\u-OnV0/h2dDӍu<]-j?@n?}΢O&l+d^}A%Wzj4*NeFZ9R ͊gu+V $W|z2W5&22̵jM %oNΟ?[2^7 #3d-=^:׾_0dBg(aF,jM͂0 YȌ /k_$2p2dӍ0P;NMnNpq{ȉK4-mxߘG7rh)~$I?5rV-yU&lɣ>VY,^q.x9]C>K//||xTeU%Vsk5&ӈl#:6+>R@ |j)` ;@,o,>[әOǟNno9-E[a",f)WL`)6Kqy;v䶑 }ЎB,rw~$^IuRZ - x7 {ί<@h)WFSi!Ue4ǥJpx"N.V_<_UZAUPZ^W"W|z} @}GztѭoWIunz0D߃\w9G!L&l0`!xU$k55LVUSOşBn2o!?<ͣ?ZhMj3fd6D{p;v'>z«~Q \ֆZPjUǫw$%s:w&ZUV[}eTVBV k_N!d'l6:5kP|}}}ɕ#_s_]:PjI&Ztk5Qft5U1wA;s__ ߛ\oZ0\}<o"N3CgE~YgZTklZXm ɭ#s^=o]dwEw ^uA,Gя9J6N,b"7!&E QMUE)Di2xeE;Q^QQr\4^)򛐲3(*Uī$F*b XQTDW޵o& }K[z8 r%VJX%j՜jU+ɭ ܷ};l䶒JoV8#pD}q^ԃAW˵& F_ECFxI6`MM14h e@OȤ%NZi?Zs梐l- CJȖl9Gk̵T$Sl:Vm-dGZl-Akڵ'zNٮt&:uCeW1 ]p!;C':ut훂>&3$:Nкuc "!Juڷ}|m F Z ާ-N)3>ص e.DKZ^_$CSxeg qZޮ}T_a+XPq?xD^5X>o5/ĵzY(ɕ"_^i.ChfhiB18uFd:H#ݎjHb a#0 Fx]&qdƒ Jw6oX&EX}%DqE u[VYEvUtWIh_}-oa8X5EUk'Mě#8O&9:&oѦML#54}J&$0kāYhy"'OmҾ9F7ӵ8z1( >|-[(ha.ԃbX a|y}BhMVZkKЖ⅋ -R!X[&Bx)0׾Q#a '7pzõ(h1G[) 1O[1 Qhx}b F҉B[F֋O['kka Uh+VF82Ȟs)mF7m6;&qW6rm=z׾W/dyFV}Y"Vm ׾BoBۍ[TjP]'j{EM}xN}diJ~ AgK? @ۏϵo(D~z,Qcb~RL0S?E;@0aShqxb~VlC?#v!8Sx']K#bsh xůEqnMG!Y׾$'{H!GOh~i"7 e.qE}ysOt3={!.&3\++qx /~&w=rwߡww L4X4i( grCJ>+lRT4,gcM\jׂP\ 5հFKVvdɒ^vRKzE3:eɈ /k*xK9dL-^׾`&dgЙAw%Zvr%\ k,9Zˇr%d8ZV}wN2;n'L%ђrxmE&tnнiɏ-BRe-(5k8?Z>}3AF2fZHkqYAqk1( >P0^!׾U2D=?k xd+kY@[kZJq\^񔿙DzBr=Zn$GHe(G[+@y}MIo`*L!7dzS~h(ku 1Z BW)o&ѷfDnM6Ykī%OY8֑3xēLW\!{W՗ϭ xim$_YBMI[}RTfk9nok!,hl͠)M5v+ Ȕ%[NYem-ZᵒMmd3𷵕mm5h-ZuELNt;ڣu :/` @Gu훈LƓOo3Gx]d\K!MFغB?BɵozXkɭ!Z[x#OQ'b߄,$&dY'1"RJD[J(K i)`hxЀ!z#diD!$c#׎|;zgO~$7z۾̡04GM {Ba>,`^1[ iڲ V 'mXhxpa#䎐?Ltw9%wYzgcO$={Hpm1\UcFsՍHXhx\5¹jDpXU +BDssQ/B"aOQ uïO>zB}m@kVZoEiAЗs`r!}}b #N~8Gg$́ßOn>ywn3@4~(QG'^};@~?}mG.|89 w'K$mIX^A^ɞWE[K6̒]EZr(8-/e_aBP +@ { Au\~mrעWjk'Oϟ~sϠso>Azy Bn!ʞa0f2B?͂n"A~8pGg쀝̻w!nz`۾S'qrw p6oon-}ϙS$rI%ʞgQaɤ-d"-88-/~j/peo3з?[Up\Oxgϒ=K oN+5*һJ\IT=9߃MK}BRO-@e4? e1ɍ&?hc aBE-&BXo5*X +譠=d>~#;gNsgɝ%Yؓp>@>{KԎKUەP̆ 0몣YSJw 9hf<Dvt@sʾqc! 1C?=ca,d^?\B}kW*V_Io%UY a#bw|ϑ;Gss}{D!pm BϬ>̹=y r}řAQ|r>}/ʞbP2C߀\Ճn16ɵ&ߚ^km!#o?w7yAnFɞQe>ӛs`^1GӋÞ1G?A}n2Ӌ=g|={݅;n܇#VObjectReplacements/Object 13|ڇg3!-'ww(VACqiChqww'-&-8|.f~d޿;$mtMDf|5?c&2hGAݾKUк[PY7l Qc>k:^I4}6W>݃ڦx mn?kWr7M}i;{@o2ZztѦgeOzolo$Cxؤ} nA$i hSSҫjnM{i(nn~^ۯ;*h69x FRObt?0 ۶5?wHf|P.|/ BM*+ebq~{F/>ܢ3F}ŗEU|Six?O_7%uӞN%+S{ǻ]/p^GKKofh oU|`ߞBV\1oǏ?2vɳF@nA43O?2?2lW7?݂:y 9{>͇ݵ|L\6KK]>ۥf߽`~حFE*Hv2?,iEIJKZ(5W;}[.yK,Ŀ{F6-M,?~~ݍ)Jgw_Wڿgw?7yǯYwXs>KNյYm57[⛮ϳe{-ƒkYtӯ}p}~w\K9>/мҗ'q}~O43"?3jY[*!nȬO0{|3[pmk}xvYvxάQKc79qS'=}LLGh Cѧiyc{e'5)eNW.$4Qh6R%XOhfnUsOO`Yaʋ|^3WG섉z6F' i}QJkmЂ/?۸|n^K;-!VOi-`4l@DqV[iku9>5>GYIm= zI;.z(Zzng V/vN_wy 3>>ghEn_8i'=^Ԃ#wxHm(b'Zyv[6~m8bPn#ӽ{m _^!~ҭZnʒڃp|uT~6#C/??Fq8=:9z팼tyryRk5k?mqݲA};!Vf}|3Rp)nb-C9u{fs|ݷߚEw΀i|} oT2kcy meLd#X59O>^~ k[2~wZF6Hc3=hgNG E1YN=[K L78to_Oe6zmY롧sN K{ /ճ) 𰳙[n;VRdQ vz-T$Czz-Lj'L=/ؙ/ӁCO휓i!VB&4SkTB;?/G[ΜL=c%K:ZiShl}~@PJ`/Aۍ˹suWLUT[M?wPɶp~}x{zЃL0`:=crP Cɍ'?c߯hl#F6N1r~Rn- y6䶐 }G!pr?;%g -7ǾhO1#r?c,Y8/B"HlIphN:edґIG6ttxqQP̸pΡ;WT dө@q M@+h5~krs B2AdtqUh<} rɇc,0:iћNq \gܐaq]ndވFǾh`?>r{亮~&MU㖼v *+>ûK.ٻtҽg(i7'"e|-x7ҠTLJ)餤JDݖ @AB +@>?=Ǿh~Pʒ)K,tˉxdS@6l%~ r7Ǿh #;HxP)Q̣FEv$7m LƟDg?ӛDxD1r5)<!=̻aN2;. (^Kp~S'x݆h"I6Nh򵔠%hbR%p'l2:t=2T.-䲐W+@&?t -hf˪T L_ >/s߷h-4'ӌl3:0P̜7}%ׇ|oz}?`$dGIw /̫\3<}u,13:|8d9 }/DK/ 'fabYH=G{\ ,|eɯBP^RLeOd)м3$c_>rM67tX+*YJP2WC_\95EkFdiD$^)RFu`KiՃ'zOwǾh`(rC7PKYjO͂0K95y6l2Ɇљ}+Vre䖒_JoxKuʃC+Wƹ";OstӍTīX*[*AEh_fޑ}GGVFWUVSi!gN?ZE }rBN&ltaWCYko*0WD_?>ïK.үgW[Zd0wJ :o@@k=zj `6:is[¼-$B: .6kV[YZu6֒]Cg ݯOB:}7b<jyOd +$JkEE( "O+ 8.V/IH!QjAMr5פWS+ ^qA+%I+ %8|V s_~M7>Zi2xeOa'&k,eJr>rsϡ7GGWQlӪvj.T?^y%wzGh?Z/j(TjP ^ SO&DvIt'+P VcXk1F qۃvIvtw&M\ߌI3L hxnGCD$I/Ҙ6o0L!@3)4Mܗ!dK&f9 rC+! mL襠$ W|qz%\yxE}H4H,gA % s:-'^N̒G$\reܗ2L3Eˇ_%$- ?$zuUU%_^UKa"xEeKqA{7ZaBD=`zXJ+%Y ,e4h%f aȇ C+/7Y*ͰRAnmhBv383~ 'N'nZe򺥺7--KUZED<"C,5jՔueHh#YkZPh;e@OȤ%NZi՗ea(bm$ZBu^*'[Ny&hMʖ[V Bxw L3:[[} GY?Obm-G[[Aߢk7}:L䦐Bo Z[vr{;kZk{Z5֐dID>JqMB"/ƛ83k3h!x!fe\~uT[b517&5&ߘ^cMC0s"ߓ^v7y8 Jn(ƞ0 ˜g+_Bo6ݴV/';mBB̃|0rGw]]b#EA{.Cx SrO?2WPӐM]0F«h^5*0Wq0PP}sANrA/P"z%*D"Tp׈!4O>o]wN;nB}C Ho A `: "? oRXb-=Ka/cޏ~ \g>gϐ;C 3ϲ܅{?$z>M!zoe;HBTjZ1ӨfZ5s/;s6J.+eO6( '_sW.M6jӯÞ:1w"D3@~G?{$<}*4rO7&[ļ'7|z/`B wKn/=v.}OIN?A9Q|]rwߡw]f~/_{A_6F39LagB_2Wv[! r+YVGn1v9Ό%Ys#F9O5b| n w z7d-xoߡk">_}}/ ZbH\B 7dFY9zvrN/}0E!_^ES jC듫OPew̭~bOk?@?]eCȅB4{|X}br/ļ6'zzo`F8'O?C NI}יU+䮐B /%+oȽ!+x鲏$x2t>!3G^(qId!L 3_/@$ /ȞBPj0D_\mՄ.en -kN9[%}#׏|_z}˾Q#ɍ$?H# sßOn>y}V_Mo55Y G(1'ȝ 187.L2;<g_{A9gϪ|LU*Y2yyɌɜ ?3eWgyC><'T*UѫW'W|5zU˾fM ~cr7ט~4'~/r]`J~(g8̂0JWЛ a.V1-'r+سB8!G!!ww"\ A>^ c'O=%cx~Ɔ-W{z ܸ73Mz;GEEЃ'z/d{E'0bdF~agl_şCn_]f^+W[A~Wg!G;JpeeKp /л@"{.#x)~ O=.Kn;p! -/RO3g$I># ^Ür$|Nz9bOn+WƯB *AE}ACo@i]+s7wǮ.2 "? 3 ȅEo&pٷy,_Bn %_ʞe3@?N.Az`˾p,;K{=!#r?=]woɽ%[أH=Qzt=}9C6|_r}ƞPˣW W?粯>s=_\uա_=2wFB z!e@`~rןa TiM'?To1"X -=`fރ}]a> O;I$O4Dm;wG.;pe %_{I{^ԓ(=Sz*ur|^쾬>ߛ7yozJAi2eˑ+G,2Pe_mZPkЫA&{jA{=zGN:H{ಯs_ߛ\o߇=}aLd}drO3Lt7yşCn9П˞y 3@߉.;.N0cG%Qs#ѣE {ǐ!C/3+u^[Wq~aYD |zmgTuus6ۯpF{)˙YggT[pFefAȫ/?ʥ8^sL7Y|_^Qg4,Ng43BpFopFp%MK|y+kl޴SM;3go ~bul5._͈m_(i}DtClFB͈:nF17q:}4PK>LK7xyObjectReplacements/Object 14\iۿ?s_0v]ݹv'**ݝ`Zk`+"6?ww\u~dgt:Ng% o#ms㠞u ԡWl@7+ E1IIl\d?Won Mخ۔<}}Ӣon-(47~^6;Io+)h&_yv+?n㷿nUA~w])et[.ٻ߾92e,k> 7ȳ|]o ?\l 㭿bwg$~vv~/=c׼MHMۯDmQ~Ͳqg T0R݉tWtq} ^A6lo>A@f!u )0UfXz8on}oyѼ0(\f ߢ2mc!e^?SϹE ߋy2Lqİ#R /JSmtUS!Cy4|[~ej#NzFG.Ds%E-M@0d'i)X=Ri?~>h/6Z[ܢ![t[Q ET~ -znm-\ah lCy_x[7z#p8JX-4qaz7i'1R;N}-ZWѯuO,=k'@ t BpE]r?[4JC?n$ts^F;yG]UQvY?pZe88J譍W]mFK =ԡn)lC6OGK%K>D=lx!+Uݵr0I._v?}AZS 냴! ǻ65:@hz)OmSc*y*?o+mmxߢN꫄-j݃5俿E}>kpۍ[YEm( H1kE?ݴOvavWd> &t}Je[Fvث=`?iQ0rgw ;EStN=EEZ=ǐ{H>};ēOp7>D$6>I Chh>o4/ɤ'Nze|&_(a|.|}}}ɕ }5ЪC5䪐B*jXXRoXxў=uz$Ӄl:=2{%&dS8X}KіbXDf!مt]l|V߉ݰBCCC!}Ip9J(ct}w]g(3GG'w]{cŒK?ps*L`v",n|={Ǿhi 5~*rȧ~joxD!7, ENC+_\UF d+Щ@"+ MV0!ך|+z}т Fnt xf`&'0O@?xo|?sͥ? Mnw3$w1Efٝtv}?LCwY 7wynm7+X &47}蕠k΁C60 46eC{2ȶӞ97^9ĜWCap %;=ihSa L&3d:N1/ך u\@n`ވׁ}^P؃n\`."/%sa'ed${E{G{g_7o_}!}RX-E(h>x>2WflR|8C+Wı8Z1( E&[NE-%Jږ2ԵïG.: @k2ȶӚnvYr Ln`7 m"LOnqӟ`WAT`5T Pʡ+ vAvtwY*Ug,UYYhϑYz}wn-I&ٛtnҽeW]Ԕཥ#rɿ>7ki TkUաZMZZ[zCFo2sfe$ } BO/?:xuduk=YjZZ̿Fٚtj}_KfkF>^}PC=VcX10FIv$QtG[5KMRX˙/_Nnmfla `#}gi8E$NiжP`DCmm krɿZ AۍG){!n`>/ ґKK>-thaxbJqCp@~}}ЫBL2*"(m?h ǔƣpsZ8aǾ^=t'D>^w x ƳDg4h';-F_ a[`ye !xQm9Cc1p"Ea21R w\+pOK}q{Fh7n*E#VLn&h"R\r%wvメ-Z)p.Ǿ %W|ze=R=UC h#A{ tr=C{BRa[2-^p~ c0 fA~n^+)[`+ls{ o ^{w 0rG*\HuOx?xH!}E:zP@Ѓ)髢7}qKC"r=%2I4*rDNe2&MA˃L.9$/>t|LhfϦ,)3d۱b$`2gn,Avx9D&ss\r@vlxd -H BhBf.(j :s^ ->KD a,h9Dաҫmr}h}s^ovZ?K){vU^J%ԲBcY,9m.^Ǽ= t#g4)rȟwi=Gc=h}xrÞ.vY%}K+Iޗ^ qW:TïJ*үƞ1G@yz˾>̽~Or=ד~/I0y Ti䦑Jo Lvٷy ,_DnE_̞%%|(=eIpc;F8{N]|= ݇{.^3qы=$wY2b!mq{ ^hZ14ɥ&^jiؓ C+NPe_P "+ҫH=wYZAk6~mɵ%G v׃; $H/~{8<}"$rO7ƻ[ȼ#7y.J3|_=!4bn)k \ubO{:P<}Hr#ɏ7<O%7TzSOctX7oLn3M6}^PrC˞}p d~*л { EE{ |eMz1}uٗD;w 3@ω\.9O;J0@qb䊑/FP>zo@>sמ#Gޏi`0JwzC`˾)̓aDrO7$Lհy-:֓_Go-qٷy7 &L/~{v98|"%r_wλ|!wzwe=xa)=phGߓ0&tw'c|c_____x9-/hVb%hU^ݕWF5s~Ϲ/=s:H\i襡=e.^߇AQ}U@eJ*D z[vڑoKڸ "D/~w0y"$&Do"Lpٷy!,On>_v1&|`Q8A.|Gsnm;wG.;pe_s,N9XD(n$^5s~Ϲ/5s*H\ )襠=d.^" +]Udˑ+Gr˳4-[&ך|+z-˾@n .B+{h<}xrɏ7Ƹ<&7lza\ ۘIn'6}̇Arw!H|&-rߤw{?&cz?aS2(e _Uʨ <̞ ?)KJ?{ 4G #\b 3𧓛N~:gg&lM̛ѷo%za˾a}G?{2\a~ ?\$k}c!~4h?dO gEi5x443mƒr;!'ܢ`-ٍ:^>gkd(C8[@^xYXDnG?mm%pp >E_5k.grkd[mfOX\j$w%HNF{?O69zlHe.ZEisz?#ZyF7]t4?oZ縌-iqguF%P[iJA J7mh 듫G:xF.U6)JemumR*@.9 C [жmUr\ZۡѶ+imJ:tҒOC/5]#M;9B V.襺Gy vP^B\CWP؋o:~\=PÔ~)r'ɟwm"I=V낖GjL pPb2#ԣ;QVO)}ԓJ_ 9z3䚒o3hg*-TuAJ RSC^\M5UjP~~rS/pv RHu^^Q2Lp .7x]WɩU*\CċTTuA 7u!qvEyom[ni6;]? s{y]M8 wI~! EE+!OSV) 1Ce-Zrkȯ VD ɍ'?={L28 dx 6(9 9 ^6 Vr'ΟѾ}Q}:M~St#M~T_E.|ԃ"H!t^TeiWWѯB2?G{Ʉ WjhF<7&mIfi70fOidJgyӲ2!2>H# a #t Ӂl:dRdx"@: j"SL&OHIђ&tCPLI%eJΩRe󺠼2eZQdK7x'dM*C4/vb.2;6>撙CvϹZABbp^4Na( @/ AЍLW]EQЊVW6C#ӆlk:趄J d+P 4^QY8 *",džPJC)li 5TdS+Uī$ uAfQEXkqGw'c%kckWJ%PB5x5ky]=QJM(ܣ{Nd=ƹ6Z.hR_^ԅ:P7nXYLv5k,)낦(MT4ѧFv*)t'C_>ЛL/fk))֢tTZAKhњ &z NjJ~hmډZݾ( 4zi2ȖKdD/2^d^Ȥ8 JtI!tD M =wo]+nhxA#=ቾx<;K,ٳ 7^oq^.耾8}a}͹ZOqnA[J+9@7P; "\`aZ1,6o dh!zϘG~D$׍|Wz]3G_\u8F7F4;X^?^TЏca Qh#Ey(9e%U?DIxDN󺠔"~H,Ҡ!|*z)!|M_u `: Bw^-tKLaT / e?]"I7\yxU󺠣n8`.A-؄ 7b%xKf[[.閉źb r/H #?LJUx(9=m[vFguIQ6W\-ѫŻ'<7v_rhˑ+G,2KCV,3D>}ZH)RIA6t=ّ >'F-/F|cL}$='s:>'p?G.OKg"9/L:t!X!zkx/zj/ 7Gމ8p \̟d/ӹbU\38}Mh'O;A8cfM7@~A'7r3lE!m %dYLw,#Ї#7pz# RQHzT`zM7^t{Bh7&ט|czM Q638_&Au5U'_^UU s^ȃLy52yWzEf/4o|or^3KO?%yaK⥇|o|'`lF3x&_ "GDh˛`wJ&ey,d9MhaVr[o]&;ery%J2+ɮrXFCoLRd6G/bn9[hiZ2 j&Slm:ѭŎPzA|AZ㥗E/e- ,dL7dH>xyyv 2ɏ"$g8GK'?{vn&wmz|F" sω<\@靣0.]dvE'Xd.w *E֢_Gn-5V_'d-^.9ߩ`[AdLw .mېkCޏ^[K3z<ήh 4 ۀN}.bE%_^qp>7?($s@N9$#u`ųqDyW:47_ Z)((dRXW@QЊG^+hW\!{ecދJ.|RW J)Q))7m&&:n0mLşJn*)Ôr8dFAg8a0:u|ruPᕗs)dch)&kD!b.KΗR^%Yr+eȋL>y䡛 sR$%&DV>TR& h2:+H_EB5jՔOGk7nAt#B;ȅ?@7:rlGێvm0φYx3$;l}]zryh}}9ƢKn,1F]wL3h n`\X7-ZiE%tC3(\,~YreɗWNw^P@L7 )Lt @~H''|rz)|6ѷknh&|97Fz}^L C h 9k#ow!-7(pr#t~hmc`߷K^2!dC;a!#??\}tD]9 mId'љHw%@?:u?KtY_~^j>UJO~֧P?H-^2SI&W<Jr5BMTSsΜ g!|zYgeO6(eˡǯ@AY}BjM6: Й zWn云J tv7y @nȞA0f1F?\s͆Y.0U+ɭ$JسAC&A8<9,;Kx SrO?#;zgH,IT$W'C/{T<}Lr3Ϡ7[/%RzK/cr㇑ #> i8I'靤=! 0G?ď!C!hx-w<2N-^2*SD2XTSVR^ =~:rȧ~zdbP/9_%@q}ՙAU*䪐B }RKA[voOuכAzɞ^0&1OF?TSMI.0/E -$Bس!y7Pr !.N0cG%Qs]{EOu%ǒ%K/~{^{l ?3;z|HKW|5FJYFbΉ<Dタタ"L%B2Ξ&w~Gj ,'W W|yz堬˾zu~mrצW~ԅ+~7rw:< 7zd gKn.9f,}kW*V_Io%UY ap !?D pwYg靥{A &gЛ\%|m9,_Jn)ھ!Ca/>a立;|N$wIz'bicŐH/{_{M5T $XJCis24O^s(?,l*%RɪP(˕28gDV>aFw?8˦e>O;ESO sď#G>^y&魘eF"3)VYqY +lhO#)BROM/54I sQb'_^Q(ⲯ se_\EU_=fnߖ\[~@k}=C~ @;'O"7Dz`˾ `>߾GI- H-=#FǏkMOp+vOP}}P\W7_;F įy$9^ze>FFݑ_T^g,DmrT y_ry7K6Pu{-6ol,B=S*g+gBEF 8^ϟY}?PK>k)ObjectReplacements/Object 15X pTW>D](?)4Z(E`#(2D4 hm,AaЈ8VT:-T`6$437w=;e`EkwMdZ2*+zns{z|R?{$Qg.*,J\ c[RAu J%%tk{/#Q[MFYqϳ[+=|-"Y R =B3~cddH+7p֓xy1eg۟y?lvQKjH*Iۙr9uIT]! (RUM|d# $/L`Fk0O;{'aFqtC5XbY{Ւp oO#s{x>c4k8nlY gh!޹S$ ;WPRQ8[$!5L)#RSfUHt ;Ϊ:{ G Gh8Ob=a{G":93LVwŷUPqr5y0|"(Ǒ 'ކBk4Y`UVZˬiMUK+B- 2Z%VP)'1}|<^8&j6BcMkȄyz3D/H=.3>3^np#,gG7㝲ƭt~FuoPK>$%p"ObjectReplacements/Object 16 N{fccɾE؍fhhȾg,%T(BS-TR+{n8~vSr}ZB+h~ot!- 1x 'dHWiIpn0p' tCoߖ\[m7Rڃ_;Vv{g^w = m4fP}^BE^׋s'Jx^A{Yȗh! /L(Ɣv_K2+NBN0$T)HugvfL͑s;!Gਲ਼<6G3|Ckttrӝhixiz8SM,%'V:e%˝*xo*uޕy;2Yka Z6O!7Mu[ϧzEg|}Xq0$dY8[`+Ѷm!|&=>O`;6ΘnБ~xړwv%#Η|vI }8_I}' ~r-*;Tqw-@/E2ʐa\s﨔^qNHQ8( Q~_OrΞSFﴜ1W8g i9F{O:g0n-WPg_[T_Et  +2 Qj["hG+_ǖѾ6JӎB+@gNd:̘.6&_qPʡՖl%~T5zUiWCW]_*:ZԤ]V*P~zyrʑ/ϸ8[V^1{j H#lCh@>Z=-EO^z4h7ݬ_Cv=oAY ? 9Hckzz|u6h߉T?'{tޫkh-Z[bXRmiBksA?l-Z;v:z)I'jG}M;hC{Ohg}.Zw:zWi}D{k{uD ѺA~ 8݂~_`YA2+HGhCKdu2#9#:#;Pxm0ذz5uւlujjɘP~%U$_QD{ )z:ZKB)~GzdNeN4XH :1,'e7a,VЧ,k6Um&C '~Or=d\/YN_lЇ}m/=xA[-*-pla|o~փǰm%_ѯ U𪐩B cʧx;:J ed7삝-M> \BRQWhx_NϚo9-]i';N~0Oo#pԯ!>4u#|`Nށ7ivn sVW*sN/3)]A-XL-$lcsx=mi0_y~CU_:d3اg#cGh 2y`b@x9vcB?}C Eˇ>YMaфN-Ą;vSfB1JEئkhJF&^kJAI!4Zh5~ur`\MWֆ-kr,B AE&f6*UE!;$/SSY2Lu4Wsg*v&wH\ɼy:nayS,ĘXX-^杸{*}!W~'wɳsd3IysdyyR/ǧ$\w=R;Kɟ:q= <3sOIjRX͟r5hH)8g>Y$O@34k5fG6he2ωD^ߍ<'(;,V|Cu;'۝չg}ޫ7uZH1Ξf'eO #Ij faZP >K+p!3O\Ia\ԕ!Q9Algotp&BYZ/W]$R®$DN9=&I6=ٶnÇ=\i幮%ِo4Q.~ކܥݥ6:(V^gV`@'?9) ;_#~2Zf:s0^a)\[s'}n֎v>lG?sW;U+LWc PK>f Y4"ObjectReplacements/Object 17 N{龎a6`+Ք%-B,5l)lY&cKv%D٣,m*}ߙ;(3?~s];#cl†Ϛ&T"M9?'OJK}i=Ӻ]p "5@iZh *- в_^݃0pBnZWUI%fUZx:0τN=P?kTsO=lXWNY +I% ? dg5'>zhjh%٫.j &2er9iIysBsꚜBc8ܜr/rvJOOcϿn>0\cCI0Sr(WLh* E3+:SXb9zgU읖+oBZPٹ=9+o*U?rtT>˔I#3.zv;BWt[d8kLucLNҍ:Ju:Tw)4Y2 d&. u|[ݢ us yWVsyg]mUӹ9從c&NR"-ujBU/l'Uj" 0SoMs-\,O @3 /2YwΙԹgUԡҬgׅVq${Z5Gɺs{֑0S[2W2Om{y50xKK^0w$kd>a޺a:JRdeam`^>e0=y{ \=7,p֓l4G5˝tΙ'=s3Op̞DH;s:۾9@]97P^Y]$/GRfє$\,򇥷s4%͇>=wQqk1M0{Eۙp{2_*KV5tĻT|N&7;kr9kBZu ?sƒ ҄wzsqo&NҬw <uz1m&Ujd%G?3n:}r]A8wO1e*G2kK;J'L3t m*=*s= άJh ExhYLX^Q"W8lJJ+3RPv88~^y䕃xed)m!0Ah% ZÝ7oJ)k*W%ݧ&w4pGpІJ=̺2TrXxơǛ UW"%g%֝ `"L@/%  EA$~$H򑌋rÛ*E' Q 0hSE8̔#Nvfls͓c,_.gEy1;37o"&x e >pސU:"cV-y ;oˋbxhKޓ7Y.;d K}xmL`x?87YR&_oZt>x'{YJ2Ã]| ^o_3iͰ >hw][oN9x[nvv-p m̘p\jn;eUg/}hKuv2W%@/_ (~rEe\10a|'o#h˷A#~;!߃_oM>+_$ C~7|NlBf ٭fC_o5]kOZ72But ~鶠`#t י6 .]-a~{mveN ] -V- Z"׊|k%rx zʼ?Um%md+B6•^a嶚Ve]w&_Z㡜Jl"\I ˵,c$1>_^wƂ_^/0{Zp-hh{@]V&z6=zԛ~_m'q;! zkSDuDkchDv6Ե6UC hv^+}zz΂VhHf S?> )=hiuv{iGk#3ҵ>Cz?$Cx-/E{_ ٝd*h)TIa*veEXك ݡZ^3ksd:Dk_|UdV >P B~re1l۬%ka٦Ed+l`3&HlSfbvI좽m zG̗z^=z1K~9v~ ~~[8 _Wht3c6sL5;[]liv︾~/ԗ ~юK0feLfɸ s W 9OtO4vJ8o~ל>>Fl_qf.B*L&hF+G3tH#NlwA+ Dۖ[ י)iG׫fKMi{)eX(IZU ȕ#&/V^Q~3mq`M9]-"9d,Y "JhXbR܌PK>5'#ObjectReplacements/Object 18 xT=߹wّ%Bزvl+hR-- IDBX+.U@YbECXe j[-aslf,f yeyfȽcJ+(QOY[= s>pj,Ӱ?ry:m֭O01j{Vuw<%ºI[nf%z4UȄgƨK{3ϒS4y/dy:Uwks qoI eV^Ӟ-)ݪKjmuWR͝X-RpNyW~U- 62c.xx&!!~25lqHL,=S>EET'uZNj{Qt JJGc9Fk.ܣ0NpQ(7[{~Ruqۍdk<0!jBL|Ts 車TcՊnxFyukJLtYu Ļ{떾/y\zaHN _uʽ*\ZS/e)f|)9I¤|/]Sg꯬uQkmOZzu]:R@"1(\y,w1.{̽r9ʞT:UsG}9[+W㦹 pu2-\=:cq 0vhxj.e `hmZ"9 gyz~!3Rw'wI%2n`>q=NSieo-mq3n~i`X<=55Ro,';N}Ǹ.Z:fŜN 3ùLwjB-ƵKN9;h6m:ƌ</LԌo(0#ȏp4Xh D9?H_UZ FF{p.I;w.K002adéi~9.q E@圁PЊ]Edv!@>YB0'S@3헃q';a[o=1ɂݰ>'$|57~3`l&}rg;,kCV3NGKK#Nv55k/ ),#A8_h,2fh1m?~_ 0&D$o?G ScUFC2Eŏ%G~4u~C0r'- /Kۥ/wH)흰n,,_N t%ߍn6[>HpPȇSCsa |oN4X6B&;~zdZXIB(0i</L>j /?1ǩ;nRBK{_;vNgxV{h%ߺ2`7-[*kY &IҘ⥒I#Nj[Ka-efBeySftH4d 6B_q!&hހ?1~5WeyEFCX<7ȏo0Jv5+sy6o5"tmfH/ef16o_GNJ]W3T E PaB.|u~~xM9ϣMƛ,ڌ Ia<6o_1y%8G{o)|cG.|u/;F8E;;)#! aZ ^Av5x~6oai2\RॐI%FM:x-_I2PC _C"LTy 06o_<8O.5/ў{#8Gqٓ/W 0F0ch="}DBo%?39{ׯ~GwЇq$Zo^܍PaL&l5mFM3yz@wKMnGc ڃx/p@gNx@w|ȃ\Sw/r%Th.t[ :Hv`PC [6B 2th @ITHa }~ Tiy-[ K%_[@hx2]7DT)4CuᏃdI ~hVz 10y4^4Qdco  CuhjJvIo=u5yHWCWׯ=^HA:oxaXDۇO>׽'Y=o_~{@#5SEۋWZ mڒ "LM~C#YwMV]p]mv8m'._xEp\1c_>Pt.V[)N9E45w0leͰ -oTkZXaF _x`= 7Րihx:U)Jdxdɮ&|"X K/nJ[z*P+3=_B<#?N-oSwD3B7LhjFS` A V mo-[{uOxHIPoMx>~#=t ߑ5Ư7:-6mے "L_CFИ\~0lYxK%jl5]5C7z3;$SܸDU'gT;5C5Z*Թ:V'v:w9U~bN ֽ\u3bm?/LU{S6iX3Ws*ރKmGr?GB?.#Ro*8moh2{3WYJM;Rm^I>ך^M;S$sOkz S|QYpbl۾30+OG0OXU*BqZ/3+^w|>56Og^:,}r׭noۈP=`g=ZW\rTTbLuH*[r:$m(>xUxX%0^eؠW7d)]wYa U.5^?WFR]VZϹjoFf>du-{}/VTs+Rz AuO=7?!>W@Է;np >km)绫DUwW5=#Zs?v5NǽY~ͪkU.jÒB0 [Νl8wQgszV-9 nM_yΤRPK>N2ObjectReplacements/Object 19WOhU~fĸэҮf(Z"f] Ĝ!{P/% ZOPXĽ@s߼&la}&ч8B:Oxj 5a{щ\ƱKv5"ۈ vY0Qt H_(&$1[ ȎsN.G+GE{}svxHtzH*_0L;Q%* DyG>5)~&AW#8E^4=,Edk7_N;]AkF/ziҋfx\b0kVo[i.X3BI$,Z\(PO ԻE_J!>S{=6RKDiU*'YWaVRhy*kh B!*7NytXc歂蒌I$(=q I%|l 9Y3DGCs<2fӓHA&`*{R ;Do.Q @WD(4AO]T?;'ڧ69}ySSV|E%G(>"?I|FNi_Vn]$->?MGaڸMo_s;A1zic.]|+fƶ\&'JMgw<w|NHGkwɜ 7@o_M!ofҪ-}. ;?PK>zPObjectReplacements/Object 20JAQFE<*"*JxO !!A@_Փ'vq2$"|IOWf3 ڀ _Htgo@ݓY%% 鴎[c='L$d4"I,`yv3/!c'R_& 3g8o@88(>t! q2\0Փ"\'8`jvX2o׆ꭹ2V^v<ܠ+k%<4.XW8|UZa[()ׁd\$CJ-{@uE9^@FPܴ߅yFBW_REEM6a4WhlSk_eooRC7/+JwK?)|^s5~:o`i|m?*;u$'1KH?8wv5Iz- 2L%ן;ıdA'F:(7/熭ePK>ktpT ObjectReplacements/Object 21JPOZm -•ą?bpiK jAܸ|Gr#3w썴5H>N23s@8$eg:e {<A2HKn9{LikqL ]ziy=c=! PD>i``ua]%{nh$ӥiq0J ջlgӚ2Θ3-NO>'-[KA}8w3EZ/^hFV`O5'3_CaPkDTF#hLObjectReplacements/Object 22J@*Z/h-ZTZ/Bw *.y*/ > +?96mm`Of$!ߙ$kTtG/o `.drp8uO/ӓt&&@=@I[?ck>|jۥJBO3ˏx@'n=N9.`:,3>r10^qۧ(i.أP_cawQ*>~h ט5F }֎G#c鸤}ctwI =Ob+^vܷ0k[:(' Y{6P ˿ُ{+ǾEa\^cae"7;(&|Q^ca-ғ+0Σ?j S[D={И'ϯ!{Dh٨}濅__PK>TObjectReplacements/Object 23WJBQ]7 JDX`O*QD0zEF5M4#4oW^MnXxw?kp#xrop'<%"JUzAk{; zD1N2C"娘bh.s)B=2x:;đ.dq πaӐu4Fe^S( P|8V"Rڄc!5Haքgf~l;d(XMz\m;_[/g'>fjj& Ib J|w#JW_Po'tWʽ),**u`|-*Zi}YPK>6TObjectReplacements/Object 24JP:8[8.u'](DEE8tΕk@\4ؤIP%>rsOnn/C!ȘH] 3@ +M6c2NR(Wu_muLԙqͦ#ݤt;si~dbΘ'۶sߚ~2C`egrhI-CAFh t:Cs%$cűHJӨU1sPB Yk]o"?@EI_sXŵߥ4ϋ#6vXNs]A}!Lal Ig]O oBЃjO=ObjectReplacements/Object 25xyl HoI/ A@@Q $H 4Q){G:Wl(tT (†șs{fdwf+9p<'lj's?:|lvmeҊ( =lDwe NZ )s7>q~q;lt3R$ՒPvW:G&ITz0i g|[WvrW9*:tU˯%l@x ILIޤ0yʧIp?.uf8qqăQt~UV$ Jmw1ƊA(C=Řx\ COr=l›ġyNپ-+q}Wإ]_A}}+_!:`?x84ohi׉VvhznmFl"$ˢ"6q-r5E\y,"Q QUϢ{RVJVZF"qrƕR˒6,QeljY֦cH 2(m̉eeV[ġyud:[[>Ȁd̶?K &5LK1XА84Vk[JZٗe*6ģfffFa$F 4oL4y/򲙉71 -g 8Gм[L0KI">mD8*cr9.W_j-0}/ךsrc6&lUר_:rKġyȏ=4UWG2|SX3E\!Mn)ȟ2j)`*a)f@9TV*VQ0S мjFzjTP}54Pc3jlP#S ^Ga 84olP]P1ffX3#ǑO}<}:hƪf FR̛^Fq3K5U;3sRת٦qmr̗؊-;*2*9C8o$'U$qErqQ]Py4J ʚ *\%\FfdѹA.ɤ@O?nȀd GbS/N_qtҚ1SCk)}&B 3u*SA6II֝;#:=Bz:^_q"._ֽ W g 9=y# =B)&N#= 1+Joןm+r_OV1Vm&f~-J;IfjIw!vbyGg(fCn0KgptbcGo&Gq&Gs&Gu&?)I&Ȃ+hFfoFc X]ЌӅPE食7 ^')5]tUGhwmMng@ܕ|4b6u]LGC:{(!nvi?[^l%!W[/B,@hއTAUTCu? |Ϩ}NjzWJđ*O +<([y|5nџە\YB8qh^ o,m#yۢq{YA>(BIކ둫+_B м.ުj.ZF qOjqB\\%мWe@oYDWkx̛O.EF.rr);ԛIfFdE67 c56RD&z7y3"rqCNoMi7.oZ{y_?~mq%~<. wW n?ďQKKO:z._ w^AjBh^iݗ(;"ȉpB=.QhۉmuQܷI<ی/[EsߗxZ=mmHzڷNBKмJ[O>1բoEw7},[XX@n'f`:qht73&f%_9mC>|0cBƈվs8' &X8/./ \o9u?b-_w )nOq 1亊_}]/G~[C{"(D*&7DyCEh^fd lV|I+iFTVHz#7w!8UN c55NZ'8}a!N|Cf83&fa69ΐ\g( Mm =ci:0#Xgz`3-0'ě-@C_!|؄мXgO;=;p1z{<Ѝ8\s$9CɿO u9gс#Ny\ N!1?CxX}' 8y:yHX58Q~+򨀊"@9t{yvڡ- ,NȆA.qG}Ka^aӐ/8Y9=L9ߵpwFޔcb5Ӕ߿?WI{=p%OwBC{Oz?3jDtLowXQƛ#sSF4*)~Нv=\/6:KRΡjޮu[e䧫y_5r3L5m2v*¾ U[Sj-vKIs[9N.vu.y"/H#pV{aG½_"Dq֜򢧪tOs_5^UrX=,z7q}\zo*_ ѓ\eq=J \?˙9z)x% 6I#5!Ç87xMws'@Rl xfSdzT>f7ˀVZZQ1e5U',uЬSiX)FzI\c S_4@¬;Bqm;z-WۀfϪ̝6[fҞb'z֣U?9sFzv͞/AyycHu,)x_2Nr8—E>YwD?JZvב3b㹛~)r}v+7p'K`}g)+4NaG{8!mN} {+R ]/W=Gп9U\Qor%mvZf tɲ2矘T #~ޢ}[ 'f/[}#s濜-dq¸?ﮛ6>qWq- !ra-֐[Msz>5ְ~mga9{X#Ԏ%X[Q_HB-,N1o2S04?uX?9SЖ\jQDۆ5mY.żgnB)f5뚱)أ#_z_uP?y~Q@"}Ⱥ/95^k/gsP5pGpQjG \5W_ WYw}fX$w 'җH"YvL|~r˂sX~ys؞K~g|g< L4SOo SY7S{aSAGnc9.s7ބ&7e]3<<n5IoHT$WZyz_uYb^/F8}/κ/[V]}L9Fsp/8\~K_b%_d|3l'?M}?ͺDI1o{g?Y{  瓟G}.}sǺX3b<0$&?uX?90 #A~8a 8F`dy}~ן~:ZjRAO zkkɕAYE֗'O^c]qH1/9N=}ź\gNN\Q'e\R'E1RqcP{4K}'?)qG}/}{Ǻ8<B}+}[ʺœ/01Dj@DLb=CJP e +QK__?$;&h1úGN(vW@9[i|o~vF唗?d/$eM#{=uGM/8=!^BKVZS{9}hn`xs7 H{93n6|-1ErM5K3匴3:P8SբVNO q+JiP+3ϱk:jsV񘀉'f1VDCjQ{f$F`Fnw$kB9L pWwƿ-twXtsgv8o[Lm㳿3G'g{e ,2N[KK9GoYO+iOs?..~NA'TJw#Y嘰?{dG^u#DWvrB;E~m)_$o+ S U*ɔ~dyտ|l*8Ȳҕ s/JT{dNpPK>`QObjectReplacements/Object 26TMhA~f_M5Q(IbўH`Ԋ[{oK"$ɟCs ƙٝe y1 ?(|bb%QGX1v*NJ!2Ygˎvų] 9WE"[&xm n  n`%^xp =jnҜP\sM5Wsͽ.iw=ʲ??qWPSu"xn63W5\8| S8jRz:ۭh[xa?f7ƀ#!.`$pHn~>wߡ?s=Cy~_M,2| Q?89 v|R!{[ _3ߏ{RY|ݴ aS,ܢ~e1݉zm淬<-D5W"/OoO$>PDfObjectReplacements/Object 27cdd``6f 2 ĜL0##0KQ* Wô9MRcgbR ;3PT obIFHeA*/&`b]F"L,a k!ȝVW İc@ܚ#m LF]F\YAZK+!`FTB?@L`1·acDד#^& Ma`Z 2aa 2؞mp{à|.hpc ][=xfdbR ,.IeC `g!0`PK>!^>VObjectReplacements/Object 28cdd``f 2 ĜL0##0KQ* W&d3H1)fY XA7$# aPD.#l `0ro *'03188f&+'+31X +8|.wH{1lWS'+Hki%ļdv L,`qeaX 0~dc +ssl8>^&@F=osAc K`2@"+#RpeqIj.C @ ]` 1ÀPK>FJ9ObjectReplacements/Object 29cdd``~ @c112BYL%bpufOe*F\Y@Z+aRf_Oc`l|3?{Xs3|pD@rW"]\PsCl, `p221)W2ȂePdh,;.Ff PK>5[@]XObjectReplacements/Object 1XPNG  IHDR25QsRGB pHYsodIDATx^]yWEiKAQ7B9CXX fQdU j/PċAJ2vK/y:$j(hcPӉ*IGo p%9bXipF2۪n#\QzPKDc!J@*;$ľHtСCq ;YRNqG&R@aNq\Z;"o*#T8ejP"YʩO)bN\D8Z*ϖ˙!5g\|'!;DvwB@5%SXʸU<$F즩Wwn+bNjT8#Nh4F%S8 ,Ů w'%g_R&խiWQ(jebdG"btUO8Ѻg+t'`$HE,ZO (?N3%]9˯!K,@,+QV@9!8UF%"E0m5; hqu:M(aIW E.5ՐDҰL_KY`V8|]ۥ8\sͶ?~zM_ KgffhB*N d" e n;HN\^6wl VɣEJL=$,a5iސ^ S>rr8C]Rqz 6+W.##KhMA C:xWի'-&fY6  .C Jz w5}>|]lf&K?T*E5*ose2\x,!-.(^$I< _K58pWʹ"]_L*WO\[D&ڵk8G(-Ƒ#{Jǂ뱝%ZX)W2,,ERpBI2MJlŤBwre6U*[ew-[P6jԨrH9ԩrJ%-[rV"g͚5n/_D'{!C[@0Ho jp[ +v%ʕjSpaz&ghYKsJ+\_RN%r?bpNq06m0aO?tQ3ΐ+Vعs'R-Zf͚~xȑ uu/9_3gWR{N`~π !ʒ*m/\4Kg'Cr%]O+] W½T:@c>b"H@Ǐ߭[.,ѯj7x'|U+hԩ]tQ_|E5jhӦ*rZPP}Ϟ]֭ݻ7n۶m?޽{e 4hҤIVV"IUDa˲By6~j[L t(q҅;?K7R*JY-equͷjĥHU :& ##+CiqMW^xR]*}tP26gTMH 1vlhX߿o߾"@)`;~>},/<2cpKAD,HJJ$XFwzz3+KOC` $]+I(,_|ň"Ͽ{Rܣɓ'Ϙ1#R .@\{O<+?j(l=pzGkݺ5K/R ʔ):\ f0}nQݼy5kEܹQ5cQn YVdan uXXF>rT&+sTrt,&(DC\>([ е $e<.J =K.=x& {Rةo G 6`cG"SČjժxVű6S*ש@#F48Jٳ_rMuSY6w-ZsדeV a"w]pDT eGmD]9)C] }n2y,3y!Rx2 #F{g4Ć1a8aӦL׺ߎ;VV=SgL6[&p]ܨ*.Q>y+qQ^wE؛K!ZbO0|x4ˆ>tÄ0qD`<1"ĦJ;0qyuQVnnIމ1,}DHn 'IڊoU7y]"ЧtU>cr$9"KШ AD(qx c㪫R=:NYMDϫ#:$NLYY5R6:vkVsQ'R,䊊nn_t`c-ai3e|OLHFق,Z5-;GqՏ`#{7p+D/2#u*e qGZڳaIr1cFɓT5;߱`bOV]Vw渒2#fW ]_dmx B)VU]լBDm]y{ =V]999:^FƅoH[o ~G8vYҜ~) f0` hn6l*͝;B۷ի38ۃgN~"ep|A#l\Oc-Z#$PYH$@0,Т]" qj ܈1)|ZOG!j.V*INl ]v}x;lß۷/(㇓YjmO?%Ck_`QX+sh xwXL̛AH|Cq.VaRݖ9~rT NTy݂)X,]Kw_[|"Q,DҔR?$Z;uK݋ԫwV:vqXW_fj6nk5jljBX k3iĪR氓Nȍ<$"2tw"~g`d: "Jh¡Dpb0å/#8Iɦ2x]RJUmgP )gi۶C5⊿&[aזRSDd-3Z1ɪ vFPǏ f` 0[AK"w 4 pb|' _1`B@ժnk'҆@q͛7V:8|ю .+n[lċ&&g $w\qTc*8D +]|HڍG"\P%vzK \.1H,:C8{G38}lD|d4Tqiܭ[oA<ѭ[M]tJ?'u ҅S> P##XA P?3c)YJn&RRnL'l\5?l) H2xccB;@k>"5G $9)UV5kkiӖ/Eݻ?ԩUx*^j޼իW+.D/\Ud2!1E-HEo-?ɬH`]J39^gF6+N'~-KƱGc&mk|#Be㥘 Cs^Eqݻ oe*ѥY>=zi:g' J &|rwp[Vr7bIgU6sP+ݻwoժ~JHq _bn_9#1]^9W8ތ싵sx%G?[R4Az_ObjectReplacements/Object 2X lTEݷz-R,A<(PC,A Hh)"LZd ʙ0fj?J(&4h|oB[Go@Բ_,[U>1H3Up=:'$>i= xҖ[,[h&KB0˒`<44yxk.RUw}R,'`Qh2# a%mVTRp {Yp{MDUKi/aQ7< cSPhi~ I:4/ Uח+NXcPGNL7Û{XDᖴy3(w*C5MKiYVb(?F5C"ϛy3,aUz7t,UFͫ ʱhC"RS[p_]_Zl=`K+,;aWfҚ*uPKI<.7rs&1QL~!?Lp?'!@OU E V*Câ^,:1I>/Wo3fގϲ\{=HoK&o C*, _3zOcmKa*'\'d)s89XA08M/˭HLy#b+&F8N R4 lq1ncōĝ7:jcioj\4O08:}]*뼽^ܷUT!koaZȄ k2K` Vgr|20;u(k`v3VdM^稠Ga {[Rzptu|:YWj)]tFgH*H+irJWf3g.a4ҽegA+k6q#aӎ< w8Szw"ٓRPai/oD͌2(]MeP,?5xve) Yϋp1[Bԁc͋|~J WsBP?t9;iUYlfkþpFgߏfFkۆ-fWۖ[xNf 2uQVY?o<y,! pT} mou'܌1[݄ ),u,EԄOF$*Ne wITdžZB}vd5>1|:F\'ObjectReplacements/Object 3Z |NW>=w'%ҏE%Qڣ$H-XCA j)Z[kU*R*SUC܃$Qd?{}y{/g>i.g)y Pv?=3=ٻGJrjrwww/./QM,BtFjZB@{ֳnVY^U{j/t SzwΧ7xeʾ|_[֒/ OM#H{N LKXe CpQ#q< 6$^O דV [ZV'e uZ(X^vItEGʖuO-ZҩFFSFy~ñ,gˇc(/έSg3*6_Y\3G1ėfjfse: N>DOi p{x=^E|iVfcX}Y_QB1MG/G8-~ɼ O+EIツCqq1'J>bXmfӞsw NEUHPkPq^,Ml,jJ]>VqA~KP0=绠NX~7T۠:;'J|OuvG[j6982)N鄋vNQ7y'GAs݄vpwP6W?;BmtyNa(USwt?Q-T[&CAƢ*h,Za}z.'XMyG.,IYr'1INR̛[Sx`nmUD׎鶑m+;"iBmEdc %8&W:|{XkE M0|M ޔe^N1FN}zSPt;PR3|ք_Q|ˀ ђ.[rv1(Jw%[X-wARx`_~dvZ?;}':7F,=V/~ۻ u/.2O7t}ӻ կ|u,_Y{d }oV ?8Dyڿ蛳FClܘta]/f>$vq։hXEl-䣭{> -bbUۨ8D IzB\&u8.uxAgUzuˊ{W涂k|Z>v1tOK|>TֆHqai*E]eq+v!*YwVE>.? 8MA(6bhM9YX#mrK;ԞQcIe˧Ϡl bvְ sX~LLd,[h0&Z?d]9b<L-*κ屪z4o|-D=v-U|&mG tϳLKr೑BN r:Z8Q23'X 놀u+CntOK{u7XXن,ِ1o;7va"6gj*:#(PipG!/8䓅|!,-i0x LBi R ~~]WCj[);zƣSy jܽX[ɏx`Cfz[ _*VJ4Wl'c1WP1M"4&,Se*df1 U3A=d*g3ROW}qt7A*2zA55ys23j90fc#Eud&C w*TIm7Q5wX}I wWINpL-s r٭O;ܮE%tM[ONT9 kCvgyO$֗uFo[6@5o?)_sg(>&7 7NG/ 5m["Ƚ9 k[^0]Ջ&^2}@3Tś ٥7UJm~Mm|Yq}`]@VP)0uo1dHaFR6X9 V+=f1AS6_ ]j٨>29 3[BLpP妪novb8VwPj^wfߨE$υ׀F`{`10=L(?TwRF{شJ1> }?v V??ijP w>€]m|:nW$uVgM:fF1vfZj>VsIGMGEL6 <AM&gJhoJTi:_6̦ː+L2< {ӦT՜Vy[u2KUG& ƹ&NJbb~p̛jb=ƀ/Ӱrcdp%` r^&>^rՇ+%i荚fVqQ荆QH>jެhvuI8'.iJL=:a?L3/Fqcۅʸms@WI3a4ѝ8LatJz?7Wǿk(ſg_N_h3ݼ ?E VЪ 3L`Hi廨F1sJkJQ!c oDž\ ZHO5AMQktOU{v$?W\}CsUsLnfӻNq8UiF-VtG8ә9OSo^8CLKlzU.Ok)[PF xHʯ)H/Tt(8簞wtge 'AIׅΓ2_/YY2gu &_y.qfQj%^3Iy^ J?ai-j¢.# ߄޺HӍpb"S3'C Su 9N7:Z=dNYʢz8@V9v:((9Qj5&ɶIr2+N/@e!} ^ ͱo?D}~&FV&E"BO, Ab%أ6+Q=qT"KUQ*B{گF?L=_Lӫ:ol! ߆t"$пxa툀hCm-r Э.-R ѭH+aW?I'ۚLg3@}HE^DꟅՏKV2 Ku9Oa(ExԗOO)1ZP玨;EJ[)))lV)O S} Oe"Gr퐇h,ɪz|L'!rN#u'9I?.:r&ox8| ^l{st ]Wu Ll~E } }|;}gw=VFث,bbv&y7&|̓UvvL1_޲xz^8b2OxX[ɂ<}|z:OLH3>J97?Kx,;3|%P:y הrx9i4nROF[}焮D?2;'NYǺ𘤄@F@Ini ;VuYi|d?Wg!T=*BW1hOys#/6YxZGbrBj -9-{rީ, pA%jȼZukx>HT޷JTE\?~ծl#YRg㭸^j#@ r Guk}cH[߯j+G:Y Ta/Uv[R:xr}y'U *߫\5V9ܔT%*ܯozz!+x!XZXzYĄt7K՞T&6[r;_1 ߥ|w3Z˜~h1cPK>w ObjectReplacements/Object 4J@Eo*mTRFݻuQWb@-n ~/tוx_fNj[]H.\2^漙pտ @p63^@@ODr՟}K󵘥KЫ4JdN 73s3 _u\h mxB0EhK- z.B1\:29zu 10kp6s`=lZI⯕OPor.=)I3YM<`uwؿs N~(eaMk7??6z\{}0 9?A7$>=;Zs'PK>d[36ObjectReplacements/Object 5UP\tp'X[p܃0NH'';$Kkvvajj޾osHUe9%XZ崋P<}oҤyT3JYL=#@4 gy%s$I$L`d?(ȯP% CD'SCms\(E6 Y_A&@ 6<0';;;T7A!(e;InO߇+(P\]^xDWюMwš@[R)0 y=֯8|dڎ[L/虦8u0<#ld+@0k #`o{( `O|0,.?53tM8Ah=$]c;Yz|dDLs3dSď=6 j߸Hsq픐=h)6 ٰgT X 0;yjsPG0 ~ܰ.5R RA}yls%B[71Ks-sYJA{<{qI=cd8+uV'~'N ;uØw}g_v vSncS'NEVYelRYǓ y`+Dqև1 uⲮNsTŷ3Zۑ񹬀f$.ń.DQ؆}g2 sM:[G}BA٪ciesc:;õ?X+3M-ǹ51tOw͖&ǹ48d¢FJ5UlYh^pg#ES Xa7yU\|bHFq*D/|j1DA&־Fm1ߨ) 9I8\xI=n&H1%_ Y+x#^@S1q36]I=ԉ/ >q$1~ԖsuПv#2`ҚټD~kʆ=W Osu0 ״?}!VigFDk8 D<Ҳa?J"]AT7^q\ġ{1@. (pPw5Պ8h4j# L }O7'G5Ytl7+!v9qB(Uqtk#wq.s3zo+Ulm*YuEO2N_4Y569Us:';R^q=C`Q6Fuί;-F)f1DftXM.V㍓ O_cZ7uT3W881W NT0y[Xl ZilV[*} ,+\p&jZe8 toxڍwLp.ۋE FCodo%ȴ>Rv9$8[HVT<إƹ'4iTpfodVtSm2yh7!UJOv8M0rq:Ȗ|2Oi,C`2Y=(dN+Ԛ-}Й$pҢ{dt7 3sGۯd4|8@$А{/шitwd^"{|XZZD* O!F'fɳ$³/4KN6"E~hk+>!2mt]YޞW(K ڦD}7Fzko<ʂ ~  c%ޏ_#Qf\Ɔ,red l?`Ìûda_//`4,R% i?cPs>R|1+klÒGC5䣖7`˞?WBi+;+kx…H!#oG{]8qPQۘ}f[O;1>˰"Wt5>~VtxTnO y}_ԉSxV0lz; bu\EەK'e\8 J }?91%wUfx߇+Vԫ=(b[s M)2u  X{,+gw/,{yrCʍ0ZI6j؏pkz`j1yJyӝSyya'1u巷8 ^1Qu6>౞1QlHLrhw)XϬ` S>3HI P@45YE}a9,I6l 7rm\m5Qj |^"ujr i?Lc}du>K1QCDATGAs@[οp05/GGΫ;;Z,hT)^h/M6C?@Wx29bp aj;$\\[!GISVUX['G1&wqZd dq%v]e lgi&Wczݶ`du5O߬LaBq_H!-Ü\Xj6#w1y[G|;nKWruQauKjYypIHYU컰UMG}[]Hl'.[+=6^4oe-Q) B\a'l6Y/VǗ^';^~h.X^1Xun~>jW[ysM^ 'drLM'*(<9'RKzmpJWӔB_pŒ>)ljCmT58`_=Z!oJڄ'G+F!q/i7:\(5SD\źIz(ב'(WWM͖N<'G,=˖35vquM }|}™]Cשw S8/|R:hT}B->E-&;sz4Hϻ6}I]{%:2ڹa u^qa GZ CXJG^R[7t0@7@ Gh8?_tc %ȧ+X@=Y|-ب$VsŲDeHsc{Rtt8($-*`"7#1IL7g=ʞg^{hqD,;}E Dq}FGSn,ɜmG).B}+x],`=];'f@v2:/CVF}ˣ~!3SR!ҕ_b* ?vD!0} =!AlN*h$%2degNR?hU^&,נ&pSJ뾆lS :X2%ocw]9MZ37^p)/ђktZ60Jl{N.{ö`IST}2L?%~g62AFZY<H&黡DWbO(&D!/o CP1~&NH R;'6 EӠhx& ǎC5? Hǿ<G:/16?B\1"ZtA;U߾%>f-8=^qC|w/#| L58  ĦeH SQfI݆5x3O8Q^:tWB$&*luoSE :h \N"ʿIz,0^{s (2l>XgNZGܩJWbV$IO_^mQh֮fc3n YOfeO0 U0P %5%+v{0&6l3^*}8e3g@`OkscQjA{!%:/hZy?lrcH0MTcǼ')Ā'|>Ckbeb짠v4G2=@tTw~G ϱԯ#UV"Wd/}dy5ETC6y/qaھԯ$#5VG_409v֕k(-g?9:0rfZ*:ot f!-2<}n&um.4X(aϬ_0б;)eVSc*D1>AG0ҔN}8S ^4q[%OۮZ܌2w5f+ ㍆3v2'FvyJhO5-07RLW;YAH |SmakBʥnor?)P~Gi2Ke^_Lt[.lͤB{h,ٞ } p! "@_ 3w[Γ*nؾ Y AH^[(uۥ;Pfr1o߿ u[l wӀĞݚT\CY.?4IS}&Lbjv4@-KƾVC[QM{ϷG?*[2= A#C,;q|gg>}9J5f<!_<7}v9-l"c~?j^Jh#/bq+ҞRf56F:!ɛ`O>+˯b,zHA"^,3N6QߧG%Sz3~wxb { NbO1\g>)U33zmz pq1{{3_ֱ 緦^>US1Ĕ{>$j)h.?KH=eJKiro]cYF#CjYLҧ֎-LiVQ"g/Hz^ʃ /p5 A# ߪ2|@ӃI`733wb=1\8t#G5M L5- nvzJMw+(˭2g!7Sʿł%zT>گO0%!F1pv\$3r@l<o1dNa,H ?7xEt1C\$~AhͽW/C%;3YICې OFL8[M`h˂wwD8p藞q[ +z(hMeDID/X< !\p?<mu&uWp&rrc: gQ/ʻG͔8? (n.Xa@ "c"d@)y{Ϫ7ښ/45CxX([jO$DKək9Se #b{q%bEQR(\n5[ xU %a! #׉Yb,Iw=O3̣{ 6 L֧7]f|XNjHTH@μtIz xC5*Lg΢TyΩ^#`O%I0S8^`gԯLeKa7LX?T@H1ǥ ]k'ߺ2YUդdD'*_q4c'_5~C?g'r*OJy " #s* q >!%|a8 TI57bk XO,i\>.&U 9FXd"#dڇ^_pJ Tѭ i a‹0K,|n&( Q*7:j瑊n}L3QcK"@kErvK- 9JNDf_D91Bp} G1ht%1<&(Eto EU3Hb}l4lgi!u{C;!u-Bs0<7wKҮ4F7/D<ƇUhJi**NJFi$\Ϥ6p"$&FXajI{r?6faLVaVtQc o`Vu^=^:OV[+Q?6J!r-.*瀒G[X1ňϬ#5ý@UI g 7b:cX~_)2 g[-]^S9^,&N~0[- }D g[d@IvY Vor,sՌLhbeͶNe2 ̬< RywiS L6&@잁xPJz -wf]g"Phn>ut'g'Ky$J }xAD;`a)pp *s n\zÛxF6!)9ah&хt@E?bl}hDcqdgJFDY%Y/W\ƭkeʣ8jQi qEUіsِcqˈu]LfNypFM M0Yy8~p {]o {wr* G$JQx&hJ{[Áފ#)NW!m{vX jN^R휥Ic{8JlSKr;߿^NT_9}Lm=MvNߚ66D>5_Y{u[,z;ɒnt۝s ['f6hΦ!:/q9h'2D)'Oh%m9Wޘ?@CT M%j4US{ 5|k4@۟2WC/CuM] jUAۈ ?߄Ϊ9Lmv[rʲؽ(8_)vXeKBw^2MRL"*:tn 4RL_+~r"wVY772>?BȔ1ՋwjBMWcaX_u*?/ί* |@:Wf_CvOߐDQ oDʷ[#ء,N$*5z\(htن3yY X9GejW'30bW?\ݿ\%p"$Y׈\LFE=Y\`€]ɝVT׌FI q˒*\u}7JδƱ<Šq4M*/V=nwȌφ3;wL>F.bڇ/KjO=VQ LFs/Z~c5q3 KOpBZ(as?BZLiV?IVζֹjYڡ[K:^dB͗:gE.m[dh҇٥%Idf~UX-c3ɍl&]_$NțCDNAAf=5>/HXʀdуoNN0X&SQp  vtI()z.O"ջˉ6EZ x`ґ"U ﷸpT:m46PJ{FtZ(#'q: /ILX7ˤۀZei*-:Њ][sxޔ%Zfa$ƎpP`oAq90뚣Gzy鲏ާǚm ݷ;׬re+ sllPc?J^Z=;GNKŷ88-vq'(Ll` PEk4y~R] b@|du ϻnBb>X~& ŜZp{d+ ) < MVg!)!_0 avН GB, (ܟc𧖦ڣq) `ԽyKgPN՗#@e<^/+RY8;E Uc{.h#?-VG.U/kd]%x7$1?nJI?RtJM``WTE^MP Q7_ Lң*o '{?}s=+jz!'٣j_.|tGW87y6^ĞW3 bxTO] P.l=[r~!FYp[Gc~ܷHYe$RAѰ|:^vOcLMڀV/jTv%

k1_O/Z2CjzձsFo4|Ch û~׵[,I*Pʇ ȴxBԷ%2q_e"=Ns3p XW' E $W'\2x/ld`Q.׬y5oS}) v&!' S;#&cT֞;un?~ڟv7=Q)c:"5_ժ| nRzcbh{fX]ir9dd" $:Ucj9{R\% Xr'תC9ρFgډRԼW$8+Ky5 I)Wh_yżNoc[Q+#O)UA6d {nL3#2;0 NZe*H%rBC2:2kzGvBв1‚(.jP^A@GMPpxV _فc!ULz5d~ DK֟ !jF ~,3/Xl{)J>2sݖU"<ǫ7.zj Wߟ\py@yZpVʡ`N#Tn&0``vk(P'%ƞ|ERLU/}Ղ_ ^^z\W3k2rBH!jr-l+ ?BHlwaH:ŶJgt,Q $z[C٘g⎆WSt` ]sƍ"` Z6Ci8{WN-j3Mx30a2D1y7 O)07Z{[E>VȡF"E tՓ.̈VNVBQ*z}6|2Ɉ/ZS kyi<5n/%mD@HnYD8YxɝV,=%HEgp /G6_ ʷDXGN|@Q#0P}` H"V5nBCxW9-WIrm-zҸXnGd`H}F3ОeWh^XIkݗ=e 㣕}(T -Fze+ߚPK>J.Az ObjectReplacements/Object 6 |M{9j){s@*F R 腾&z%q6z(;ΆֻB̛IG{ݳ_wtwą@oZW@31Hn:;ȩwJ.#** ZCJ8 /+?zZ}|axtP@}u 1TTYPM)VY 1iV\aeՋ~~>]G9ݐؿ )ml&ymy7*[*o52]VS oȓdc>Q22<yû4ysxK71c^K~ۼ3eaQXnYLHÃX]0_hq|8cI(xqt }xPCωyx^,+b^o~GL,6W.6-Fa{]0;aObGnbef ­;0ƒx %-y]T?*$H~-H; O3GbH/ N|#g4oq|MܖįU aJmTW" Z>ZfhUG$g&UNlP% ߣ\b*"҆K)!x)P}ԧx%N;T>O |^빆o3V=5=pnEsiVn[ : VՈwj>Ԫ|U'X f3-|u ;eY?:~.XUÛ[Ys{kcoc&{+Ycfo _egk)l=m cDZ}(ƜNKVysڰNsk8X-96)9O`)N1f]XHvܹGo~ &aXIb?Ɖk_=DU!ZpG6d}LVeqB>-nBMgRx:aF;G/ֳyut2ԉ]UoK#4!}JnJĦPl2VpiJj".WHQ{2)bޡ<|{Pj<8Fc iizRGd7bq ǫQN$@쮆c7RWR.jjKXkIpR+RkmC}ڨaJlc 5CI!j VWzKĆPl+KrRyP?O~b(JBIB՛vB}(R_jGXQF-OL3ϲ'%b=(], 鴌S+AO:@r>_IuXG$FR|7RGb(}@%IK))[*ےkMV8C6iI-IVZS{bcHI7R)XS5hH}䳤ƤHM5XXGR'LeCRR}b(VȚXTTW"&!%Vb_*)7gH5R, *XT@[V%U#U' XUiwIYt dejDxf Ѓ~KW_]X%U2~(v%坠$]qrR,Ri/=XwjϨWe¼ZakCY U\xU/׳\ð~aqÔ{?l]\Ù[c\Dϰ脄ꞡqD'z_I/16nB  OCzoA9x@_4;2ޙv5U S]bWD7".[}8_9G+ SOɜvɜ:|Y9ye|e0|->uŵ$?_M>u\@̫:RbO;D)/'\lb=Cb^P>b3;; a<XTPC -T 468ZtޅNj5|D҈Ra # lʂIJ)f /ϦldkUwl¶xw5m4|&ۮj;vSfIvE}ͮKn[W‹gxἤnt[2t_^][Ey;w[xWwa!C}-F Rt ]IRb~"nqx{zqyo9<>,\5\-)3O`G@7w㎆S? D'@qkDYwqW*#Mx[cSɻYVcye;~FYJQf'8QVP:R>)]ObjectReplacements/Object 7\Ǐ; XnLŽMEŘ-3'bctnb'3wzms|ޯxߗ8nŴXDra  Xe-򆿤c>Nv""#:*M7'ON[NN/ݱiP#{wf }TġxIxӴ;gqD-%C.:DϷAD6-[? ~"㸢~v71*^kȞb);_{w]o'X>0x{`yw _*_9jviɭ4^{b)fomo7[,!]NUs <~o?/0tV4Sy}r= WMa`}='x*{W^S^cKj5P߿"ȟ\F>V WA!4X3?wٯ_+s4z&:3(r2CytUouoVƨݞ>7sG[M^,ZYĩu43▷Q7)7*];m;ou|Ct5ҷ%%^cYzft{g7J2^>}vmӵKһ/帽q LvnqմSowNN#g^n[Mo!p -4r6{a|9D(ouH*WIC&_?_=KQQ=jY҉m&>F>_aO1uֆZ{Et ҽwdw.Y?ty&Lx6˥?0,gSկt^pv"~w,eu<K#Qޘ#Jkiy<eR0K/e]rؽCDKĿs2\dmD1ʿsL%ynZ$;ɗNd5ſ;Iݿ}β\&~J~g?dY҈(S 0lbO1m0F^1@1'A `Ax 2x$[N %px#z|-@}h F( #І skɴ"ۊN+1ƢFb1Pcq7a4QtF-&MƛbӌXX q+dIx\֢2ɮj1m cm fL x\.sH,xbRDṪo`E7ǵO |o#r%\ 8/D[W)LBrh+VjԔ*X +`92e} ) J7TA[k^ z\k9ǣ[7} %3tqވ o1S~ô0Gn-6mεorXK-%R m;OrvɟGc?pގ ok)pq{\Bۍ۸+ }pލ okEc{MWt^p-/Ȣ5B6]= ;ڗ/A :tchNc2*'h5DoɄ hx'ES pA"Y3}"ן|zQ%xW)uKJfLU6W h.-Ddb҉@wت1m] nw$9H]ВCT->$svk3O>c'Fzd/)xk?&K6\s/^4~9(1*h+xQl9pW jB 5Ԡ[C0kjYKf;M7CM3;j*Hyy}}@o2d{E7R3L<ӌҘ`f,rϢ7KK/^hn4/sރ--^Z׾x{`7"NLh% WlU-+d-^F׾_}2d$k9 '7iM+t_S> 9rpˁAVYdUCcy-N^ryG{3cokOT濳{忱,$mWX{s~<~Z(YzMGW5k B=wA/h;W!sD߾zw5-wp{}\W:3n[WrqU%wїgԘѻϪ^Cϣ1k |R guUw^W}}m<3G0?oWr%]_sK㞃Lyj]Q.`5+ޙ+?7W\ε?yMb{!Tj5[)3mhvѓt/N%O] ;!ַ | zUs0ʚRehv7hvm Uoh C/Bs N EoCmo{VvARhvu|nۯ!`r𚯿T堁-},D_Cs?̒ 糊QWyW6FYkEM6Ad~WB$3X\ˋheFqLS)h)KXT/GtLS{kސk6-'8⪖@"RN=f'=֥g4)ԳZPP7}+,37Ձ ziSL03S$lC3൙W"v(o++f e"VgUʿ~Eklx[/~L+} Ͽ_AO"^:xćb>߉J̕+W"1ZB.|&M-+tEwu%)=׫Wa^(Qt[/6Li{1m:4rSEϹoBd]@g8L;v0l'sppH$LqH)v$%v̷o&w|8@{K!B)gb7nAo(Lr7삝ڏx?E~rMϏ܇OTDEx>a=hvc ujEtȃxEGyHtE&A8udC/~01AaLf>2I's ̃d撝Kg.yqQ`xdz룞;/JE( pA"Y3}5j@uF*٪tѭ^»,ڨWD[hۣoOzEB/Itz^YU^ǣOnp6f$5ͤ?KwCSzؠ1n];D'z;Ro;"\mq er_>$#s=:&w CK&X]6-$׾h!d%lV:Yf=Ŵ_Dq(%K/IUJ1~LcxD h HFoNw%ו|Wz]wRRH"9/L4tFs 0 *Eo*is[X k ^{~4SOsv52?5u/YZ$##xAx-=^z׾ hAztҒOK/F,2&C#,\ d }C9ʐ/C,rFv첡S6!dE˂ٵ#sh׎L[m鴣󖃌\r0|_> 9!Zvl}8!C6N q/=r{o3_}\}мrmD6z2ɮ/6+'O3R?gXKK4kZB9(*UH_ ~??}9C+ E L0`:tX?Hְ~,kB-\~mrפ9402admfWYFZZEe/>{sH0aF^59ZC΁rr{w ;E$ٓtN=mWG>֓Cxd u6BWõOjI xjK\-ak s70&s_aBP O6?t 5mMdjk,1WG_\UU/ 4oDFol ma2zؚʞ̽zIp|?` ^39B΀a6 &Ϡܷy),[Lf1t]bkRry-:|;kӉϼRByJH蕐J@QZ eh+c$**E(ϹZY2J+!PBȅ">@#QYB7Q >Cw>@ӋUЪUSʗL5i:T\ ^e׾qbŒ+jƫl! z.\^M׾ ;@>Z D IrK4ꣅ=C )d}B '")^S%ldsK6S20h9 ^>t?MƗ/_%Z+VJ9V)dl ZkW6"Sl :5֔WJ{ ;)eG9Ckֵ/zM&l$H 'x(d7eG $;@\hxbGL馿a9kŰBqt.4f~0ďf>ȋ/k1pa{,VH2- wY r./ȵ% xNgtE(Z1bZRdLZC1(V/ص/=/r~[K+#*Xˋ>|`-'>2K+$z]&_^mkx֏D' ]O+U+$gC֏*U$ SU TJh}$70撛K~.h5j:bl[Vx[l& \L}dKg/ݽֺhꉫֆgfm [Cԃhuꤾ3yH:}hm𴅉4T&Иs#x ]r7dsI7Zs梔-\2V% - /̵zuF**tЭjkhmk/@[hgkm F k 'r#E:u$m10bl]8[gĹ#Z}g0tͰ}Xc !ںuhvǓ'_ k}%K>KL6*2$2,L0K:yZ ^YB7oH!tCoͶm5~8pfOQ"7@z m_ XM.|4hc3basBE_H/isŏ'O0ơŘ!a#䎐?L$|.'wyz_`EHП sz>wɦ!&`^( Ћ97~r} gCB~!ḡY̳%7za۾+`92r/ry7Co7rw?AN?ɞS C{)d,$ 7{CߢŘ33'Mo߳!H#HO#Poss4< eND?y:&Y}wo-$rI%ѿŞ ]*ytUɫkJ{ }3AF|/r^yȞLP 3/J("􂡰۾?+H"g MЛ7'ל|3zam']3~'rw׉~gt!0ypFNo u%?$M?=S`,g^UW[}ϼo&fzoaV8'O?C NI}7ouk䮑Fo""]@9-HO5H?ȥ#^:? /D @~}C9ʒ/K,r) sc&B7PoGvoϞ03rCAso"?8荣?=`,f^e[mbo zǞp2C? n~f W/L2*̯_!kz۾2HO2ny!? "^ AzP $K+I{JC=a!Ы!n2ɇ ߚ=m?D1@?  (}1ca ~4haXq [D~!8Xo=:XO.||/y ܷ俥-Y`? w;|ϒ;K,sc')O=%B zC۾aPrC70 Y0y\y摟Kov۷y%_Nn9_ v3Aߋ>{n0S'ɝ$Is_?"Cz}B&K<=~ Вdv߇yoz9!LW O.?/P0WE_\uU*nB@cFoDi!zO^zID|?` 9{0k"?0m2楰1[L {'"O۾QrGw1;pz2}Lm]}o_+8/ɿ+-Pvp=4xYƸ#=fܒV#Inrv! }9Dr%?Ǟ0?FR>ü#uR5b&Mv̹|}ŘB`r/žPj2B_\ՂnZ07faȇ ߌ=͡'z/H8D__b?PK>Q<ObjectReplacements/Object 8/AƟ*!DD"pN:8hR$p'nHw'zμ ["$Owvݝ杙m >tG:H1,t笯{ctnk۝{$fM!n1z"mi|N=O|mKida,Id 5Y y=RNt17.ֵt/FO=1KUEZ`G>xP>sR ƄW[ǣ7}Uw:ks$"7%0= "݊_wy_caa}< k,?zW5 0^cak f l~ͯ xk(w e1xl5 [k|?H%#t] _J^' ,:m%?W`;':|V/kV鷔_PK>(/ObjectReplacements/Object 9J@OZoRj, čK]UJmQԍ;'gp_xn'cFZ 2M2|sgkzw6{s{ ʬO!=K-1aX_G1:-z tt|.Ywum?zd UTp5 QSTJ=K97"\=8]W?7cRWBxvCQO|1[ObjectReplacements/Object 30cdd``> @c112BYL%bpu1X +8|.ϑPHq-`ҪQI"bI_ׅ9Ar8 8fl=q # M `p.`dbR ,.Ie2C 2PK>] ObjectReplacements/Object 31uR=KA}{K. b-DLae p*DH B84Zh{ANB hmX`܏#'{eHF )vDQUh Z29tINZXѕf-v?{J[n("./ =@/h 3v 6Ń|&g~\8w6x U-t$_=ŴL+ZJP?g+Z6ȹ>S'wj[ڮg .h߾7?7͖CjvY{2 g=﮷/z*P1[td / 'C~mI^)y.MCjy$[656軥`)Q^}\CK"1c4YqpPK>e05ObjectReplacements/Object 32uQJA};=s iaF8YI" .p`emK Vt 9gv/ U@kY)" (sJ7_jÊhsvE:! p9l/N.9&!b4^'uD}j>&Vyˎ`qSvܖ֒do׏xԣ,>]#SW;",U枤s(8h{~E\MLZp {1WDQ1 ; Kkav[+oKPK>\ObjectReplacements/Object 33kAj6!MsQD0PZE`UTXXTmh#1J=Q !,$6ί&Ye=ްwAFvF!1Bnq_u!jX(pt1D/[JAbĚ2tXAt-lo`M1#v%00ō(,61>aW VwR7'! nCz {_aG;=^^ׯ#Tb.Ro Q17忾 ⠷u)MKC..ɘl_%VR*43 W2. Πy| >T}\eF^q]&s]e. ='Ljso>q]&s]e. gta>"=Icg@7Qf#bD^>Ȝ@x&+[ Fa|خ̕yX>D S@f:{\a_PK>l朓ObjectReplacements/Object 34kAߙJ1]CBMRE!KJ֦ mh]ыA\b!T(ѢI))4nwB&,;yy;aa/ЏF0v[!BhQ[uy"bTiݰt2Xˤ]MimyaJ&!Cg&TGN'ytTJG]Y;\yi3kN;M?T@G]dkf)M% t;σ7~ok]T&A˟&l邊!un"Z}|ZQǧ>+ϭk]̹=Tg69j0Â/wCwi2(2cG !5O4 ~{2(2cG Ϋ>_񨷿[}ej2/+2\K? ]&"s \zz||lWGfP !u5?+֩uw*2'QM 3٭Ȏpo޳{a/LsyX>D@gǠ6PK>>ObjectReplacements/Object 35[PUUks4)SE{)T43D7G}ɇ&d L9xzȱA mPzfp6H}{-fRBU^!b#羽y#].=1ː-O1*ot?ic{y~,@2[{F&#==<>>yS;GǧWE3DX-2Ex+]TIYyXR%;?[t8KQbUq鎢ʪ3,7 N%g(YoF>߇N)1E3c%\%{{33zEjhExWRe2v3aEipav1W4_(Q|)+!dgd]֢: dF_y?Q߃}}w{҄ukB u5Z^t^2tD.|} Y}1brgї隷z,G!C>lͰ}+Vr[ookޛE\!B_!A FyR}MM7ѷpB3ⷒk!LQ׼ԧ$z~6m\+Wѻ]%E׼m^^r{MvJ JB u5Z^t^"TH@Ǐ'O>HA.B\Q/%gӷ؈H~}]Q@>z~; oOJcxڜbDK{"ڑ!IvP|+˿S:K~+9A99\1={BPK>aObject 10/content.xml]N1 wƅ+Bj!INt:i/]Rk: x J8wյ؎`eBIg +u ɞ&WC6VX.JV".8o&kn2<|JHLhjQ:bMe Eah`gV:X̢lqѬQMϧ]M7!U3jXZK"]Object 10/settings.xmlQo0)P5*h hl:v &2HҎ{B$>кY BRmq^wj} (W󩅳 ЏCLRz\z !Tz ={Oy ,ybR|yqb6t|FE%Q 3X^tNm^hN'C*3 4mڎFz9Yw FNF#!;z=6q)vi/r/m;Y[ D,2:& 4NEHG2c>1=T !sʳ-Ԇ=]Aph_ jֱ 6DUƄsRd6Ft ۵Rd<`|[ CysۏzL@{s8Wa4G۫r}[ÖGUѹf־GDoVl@9<>&tC2A"YsK2Z]wTF9f5 6)&M\Tb]RƐ3du,yJ@F%-j>%դB-eSl %oeQE2:"RN8XnB"9Qduǭ4N4i7PK>7qObject 11/content.xmlSN06jRT 1Rv*`ZKliu`cs mB+(t>߳"`.Z%$*ՏRMrw;<kvSM̹ҪzYO)..t)ȹr2,΍ZBV/춭-JvSA((!q:3¥eBxfa njz2^߾D+ٍ]z?ԾnxʦZI`N]WJ;[=?q.s ?][hCIC). Mz=A]~n֏'PK>|ʜ^Object 11/settings.xmlMs0Chi$9 {MdGW˜Pli}W s@H6O3 Object 12xg۶gyfgw'w ^ %& (B!ww  Z49;;!2';u]άrhfkqKqX44GGGrtjy-Ck;ɹM)@ZH!dL@V_}vns@N\@^BP@Q(PJ@I( rP*@E}<+J ՠ:A 6ԁmmh14>9-%v :Cc/|ϧֱחfJқu\ Oا\2zozhnjaJ/}(0P a[-ϻd,R*GN5Dv xWxIW"`C=Ǿ۞ yog_?vm\ɤf\x\FmUW4r&=BCD 彠4i齔̓{F XAUqkϻBI"w2Iѯ{|' )I^~>GJEFfI_TlA6ŖGZʨڼWTh5*WҒ$-IKҒ$-IKҒ$-IKҒ$-1K:%omJ0_(AQvn)Ga3LJnm;!pg(=dϘ1[O ~R)}XߦJMɔJ-v P½z}oWJ%RVtJBi!](JΚyMCommՌ2.8:WAStY)ۢ)Q_w=%۠;kʷ0{T[0l| SW֞.:YGcw[S˷:9AJTmVF?9N#Oל|/ajI})JppWsEcC#ŷz^0)äp4T{H[Efc'˩TV.6>V2>L]b͘!Mj{?iӷyMͦh[&Oΐ2C8fH3dz 0 Aªd݇V̠7o-w0sc#oIf̑7G-(n_}+ڟ7d5_9$ٞ1GD#3ȖsxaϘ#G"9r&1G@"̑sJ9Yc܉0Gg܏<0G8氞{1FM~{7equ^{yQc4Og /< | _ 㘡 ?d3XFD:3I'v 'U؞qOxqe^K{|wUmwOGl.1{;|bkW-A!3:cxavMc5uMk-ɞ_5 5k8HPTxV=QyNG 1KHoһNk@ow53PxK 5㘡 ϠZf(훡ydH)b-YQR0Qj˹ٸկӜIyIϕҪseC>[ <&7>VկbSlTn3f4 :,qp*vzp*Y}'{]с%MGt %[un~'lεT?K@9LG!R.lSun9PܮIn:{C(*32Er.[tއ}Қ~v d.ӌ))LG?%cm';{q&9GSUeNsytCW8}Sa7+흱q1 ?%U nf>v2.?A:K0jpGfQc#27T:nyg jr{NzattN̶u4Jع>f8_6U5y|Nf84?Q8޸=2{pwqJb0QNA?|ǝ8>'z8ڪӨ7=H<Ԙ )sn|SM ۟~dnu7LgM9Wkmsy6yC>2#h Bq7oP_W}D|(=-JaBn~ɢ_ 4HmF鯼 `UHo},Na!!Tڅ|uQf_ %"?P>vEUmv氫 (VPjz~.t~^C c~A&ֿwĮѷX^2̻KRn&%rs|.#hHE\~|J*q~<ovѣ(_1?L͞Cj+=&~S>ώ44<#wn;/m4'M0mUh"hk HTiߑR᭑ޱc)'CxS_Kf/ΞB;3dm=wC[1?^2 _@J1n3_;=~D)iZh{p@АKo Oy/9[Aۨ|1o?%۸÷z6$K/2Ee/Yc|Z 65_kF]Y{cޏWq9_;x߸R P׋t^]#w3:M]U])D(oÛ$׫3T#vo뜑t%/;r)%x=|D;(yVekwд{XX`sQ3I㈻V+DXh#Krb[]ɭ$_v,1gYqpq|a:ǹP|r?9b-c]m{B;>)~,v,19N;]!c?_w{Q];r^@Y[;S@ٽpjkkٍmzy]Kgg'{u N>6w_Sv8a=[iedc=wMrT1Rn=zSV?4,w+E=Wg伜K~YZr6^Ŝ6Kٱߛăܞb=ɶqw4_#{Sr.2MnnpG.i鼤qT9z C}ǙW3•L=ZʕR=\Yo}׀-+ EΜ^&p3F_-饤mtƢtΣO{ܜGbB7ng:`{ /]ŷ'&EQrێ(H}o{W\lo/zۊP{lqԺ?JGmێ=K !h:3gXh:QQ=:.8q %Gɼ/(ч,D_ho`X"Rm $Ҍ-+@qQ q3K7n} 5,1zWN in/'^/[tH_ 8yKeyѻ|E_sE\wDp ,璉|9Pמ&',Va^9y.1:%y"D^ILkn0W-ny-!+eQԃtf>ïWەPJUS&Jyi¯Wm%US"JxQU F/d/{e0Jb=FF-ڷb^Qtż ?(Qx"ۋ{ʑrM؍ o߇hIɾONʅ\a K[L~ufѾ@FywqǨ9 f~#-o՟~w՟_pW#uf?G'?&sC*K.ԙʠRPLI%)Im)ǯxFechM7Coߔ\3uENd;QӉΎ?r v\CE?`7m?XcK8G^)?َr9xs!;m_An9ԭ~-qGpqnM p}{!:Y3pN9E5=}{E'ufhadȆQFm*^5]wﮮ~x$ȽO=0B 3𧓛N~:uөᮁWC]ﮥ~ 5Ս7m$j~}wSxu\vׁP j DEN:5FSݞArO}uZmZ~ѲAVB&3d6!^#ZAy'W|Y~BMZԦ ^Sy/1%rwPB.|u!ki ;'M$ ԌߧhG}DǞxUjXk=muhג[C~5uf]wdNvjwxSz{9a#:IH0> 'IHqQj"HE)/A4Z :B',ʋ.e ZiR"擐U S,*U«,ƈj- DUZE ~ЧLCR7VNe+b,XVD_2f[`3l"&6:hu38 h .Phuj]C 䮐BϢZc&Bͅ 척)4!^C4!dSRڔZKl+ CFE1 Z9^s*蕡d+RSڊZ{,ZCIvhmA $ۃ]кue1ސH%AWֻuwɾKͻԾ+{%˗Xd 'Z~7:[/_A +qNI^ ~{rߓeP ›W=AQrEcLYcc6|`& ~C;hK 6Եu|6ou,5s,0h_{}4FIH"xK'S̱LLw,%-[o ,EdREh+Vbv{ahF?'ɜ {ԞpC[^J:6 "%g}Z~dPڇ6mm"#dҶ k+^ O65ͯmGہCT 5]vm6-9fdQӌf^}xDvPWv>؋opa: %7jb Li18 G0!~0s@;wJlΊͰjg64b$ ~Gяa8D Ρǻ ~־U}G;w_pM6uwоAt^ HQu߳ڷxFdrIMNjs:BwETt^~+e~AC2 ֧> .zB/矢;h Dp2adè 6%u[M1yXDwoLAf:Ϩ;hwK/ wnۇnrnCG{"3Z\v>G~ opuשH]F9t HRA; OR =+d2D]fsRd4.,ru'^jAMr5פ+9Z +]]e7W*H ) 9Z2d~!L?R*\iᥓ\0ޕQNpeҢK1G0TSJTWf,xY WVծlr++da=3Z&L~;з62[nf []9yW^y.o\!@Nx9~G ~%sUjR{͕-?^~iw$.Yχ/_ztLiI. EЊEe1@(EZaB~ѫAUB2Uq@+WJqmwܥ%Jfe&ߛrh*ȑr7ݕwEzyrxecDLȽO}>pWAWM.rאa ,uAuUѪUf+m hjz$rוu3xɜ"{L\"{K^rGk@>t7౻v7ëͤL= e2O#4&7EkL,i! yC3֛5kW<#SlYjR[ ^A66^+%2v+<:uC=]0 {@g:LƓOxO79^ <=|OKhC_ k`5UWQ򠧯C`yŠe\>~r קԵkϸoC 6Ե-}A( `z~8paԽ,d<F$7HFR?>ggA~:u~K/-"E/ F߃^{ ,0> O;I$u'?E:z$~(]?-u+1#r? yL|Wfu+ЕU]Y_/_aƅ ~rSj@MƵk!W|mjAMK֌[AKZoA] [ҧ %J?u! #`80rn34 OLG0o!0yQ7Y[a;wI~ua QrG(sCrWK}{G=uws,pw,tehKů 5'~j뗂\jj5M +{umjWEWE; F?YjP{Nc e򗩻LO1htETlϷ~_}4-R%'\ThUh B+B0uWqE_\y+O}TВq+mȵ!ߚVү;Sם `8o$7ԍ~3~şHn"M]`> [D~!u `_zu֑_G:K8 G?I';,.1~俧{Ϗp3~GR[O}54 P U偼/@僼2_9e ~irɗ4eS@SЛ ׂ|sASKw]u!߅.wO7 CEa_n( {6ɿMԏ s>yṞ[x _EnUԭ~5}A80䎒?Ba8do.HE꿡Ϸp0=rE]cTkj8AuUѪUrB\C>7u _SJ1. %+N8uũ/A2n &SZuf :w ׁ|:Pߑ> "D?`~ǐC~ uc>cad< sfY0o%eQY{a;HuaYrgɟ,soMu7F"|KT`7Ą\jWSbvɮHϮF@ƃ!;~o3c"{3ag!7l>Y~-'ԯJ@?!;-.2ϑ;Gu?O pn2~;oSw nZ©JBSҁ@lq.d13bE%_O ԅz7oH!Շz~vmɵ%ߖԷO{1CǏ A>k~c GE~uM7St3$?2Ka br/n1Kvn{#^nKiSN?E)O GG w|up&<j4cr?1Q]PHfM:@c݉ċWqa(_\A+H}!Pqm:u%_Pү %[RגVi qP?XdNn8 ~}ހi?ܧ?coㅰ>S7Y`;;wE~'u;`I'81rs~$uo~?'?CHP3Rͨj&N4'^LC>K]^'?Tꌃk$W| ꂠ_ ͡~SrM7)^`}_GW ~CB~uCJCx Ti䦑Jl7\9P7/36f[зo#VfKaC?D! 0~ WrFU.rwߡw<"ԇ{qH+(o:?:PN;z"|:-No|Ӌ[DeQH+˽־G4cp&djoz>oF_mϠ8C^-h:ї'O!؏۔ m2wS:_h FߋsE\륑sh:gYh:7o&bmI'@OJՐXQ4ңo?(?QLfPy`a)߭K?FZחqoY:|e{5~g3~m-wk}$ /3~Os6ovE ? iʇY_f2.U~gN}XY*Y$Vy?g\f%y6v6׈u⻘s8 _b?T^Dc14 Object 13xջ̜K-޻CキФ ҋ * ) HQ?*tr߳B0xs9}Lِٙݷ7o6=' 02@X|4BH_82i_5=L.pC$y*Hm"- #d̐B69ur1 y /P B!( E(PJB)( e,g/2edNwO<_A>1 aecy)+g!o8__Hc/0 1=sD>,Z'C?m<鿽/t<0i=ie<ޓƑc$}W]j-Vׂza jԧ"ڄṠ4jkw\Jr}G ԳxqvH>zPH4kfl5R yY];Wd{M ϛ2"e`UӄD.Gw WԻʥ,Rck)iJ)iJ)iJ)iEn5чx D+:ճa YtPauSPZTv5#)g魻)@S CXocQ]eB!q =*?=?ոRFa=~hR n{`o!"`klҠ>1,aUL1FKȨ'mݨG*7Uc+ꭨ\2HͫA8]QA=Q믶S]qbZ*{,}LywyTϽφ7M^~j!.W.Ot'0IL5JۂbرzZo%q(TW婁X4I#-54;xdC2e1UMϳ1AS}nvj}32ҙj~ֳC߃t=6&,y{PvnuhA9Y穷AK[pPG|~ L>B#(+z-slvO)$&K"MhE#k"#>%B9c#{"+>r$BA3KXJ>GD#o,}'Bb#O"?>cܻ_SyN=p^<~^,yX΋U:/KXK֥u@%cyڣY"pS(R&ŽRCP$%^4{D)䏡O*G?bb|eTL>)K&*K%P)[T,=TNpcJRjGbj<܎Co21l%絩z &kS6V=ڤ=.5b]^bXƎ߻{m4߽fvTմtT5{;UC=EA:MTmG+r:WSwj/3OWouVRTt--۾(F&~ԻF}4%OQc˞QW3Ӟw+w5ӲQz7U[pJSG)')}ST_MR$39ߑb+Y;|vJDfy%/OQO5a?G=.Ύtg-7'8!Oy3ۯ*l[mۮMsygE2{}hWQO;p:yU$ajyJVڹ|zFV(Wf# kZ4SԳٰð2ޣG>z+GɨWNҹ 9r|[Q 8W*zsTT{֫mF?*9r|[UTTsN;zU[QWk'9siOQI9*.5CS9_jR }Q7݋.'{3ݦjw_ SveZF>SJVM}yʵD?nG?+}:ENƙt2Liꆜ2R-!Z>>n|>W3uta,tyӝ.U?ZD7*{rKjzb ?1-2 rOy"z}g; )^pO,.o&SO}:x6筄z>jHaEs+Ԥi}sT-Ըq/|T/|&RGw1V'/˫#]X0pGxw{:GX-ion4d齠k[{~ANEiPHRiƕJOhơVc~eWFyePs'X\!"jg@R\"?S3/晫HHai ԨW굀~\ɜj~bn'+~pŸc}\hrɩyuP;~h,q6d&ӥeDĩְƿS{ĿQ jv#P^;+eD^zUq3tʕrggGky CteF5\zy~oG`>3u>}Vu~KGck!OcgZr}t_;gъ\'?>=П.Ԁ~aÝݦ&B|#~"K@ZW0= MkwCq裗0G?cDGNsxHk=#ڧhK*gWzG>jY?6㴪U5WUgrP])##o;x _-$f>)k|@;!D+z#"6˽M>A41EC}aW;Ξs=h/q;{zkwګzB^'9Fۨ,";ưnWe|nHm,{ژnkt($6R#Z66=Im_s8%+ˉԈI8*˳#, vjcDGNءUCm#5x ZYEgqdzkw݁nx;nDt2JzB3y"=Dbz[O4G{> `:G&_AdaWܮ dVWLj.{ 8>sǏ*wӃDDxBbXVwGT= 0Y?_"|bEn-/yE--fěy-ZŃ-Sx!=#d/@߰q%^T6r/K=sYF:H+9!2ȴrgd evų22D#SvfVų͔^6@T|eSZ,JL?IZ!de_<8MLq< 0ĕ|@a+;pD:wzHDafJx%#+HcWWfG]Z93q^y 1^bQAψ_* B/|bsb+Vʪ Y U!5U'5' 7T|#Ⱦ2Xz|kM{Dg w +F -|oᛍM|[ c<] ֢}+zio" }# ד竷^ƻߡ 9爟C?,3w~ M7ɻEm mL Az{m;@0zn|AM~m|N*+Aem|OlFƴACxONrjжɞ v[a h? '6 <x#BPGUm| f,گ}_#W#b}އw{~_'jX!Wx»૷V؂ o3[Sh?p~O߉Ce%x.HEr/%]YHfɍOO;v_/+,2Ʉ79lC;/Kdi(ei#^,2KWXԀxNNurk.e:δ_'Wo0_?G~ 9ɸ&'㪜J{*Tߛ$o6oѮύrU *+h 6mzr6ѸvK7ȟgŸ & v횿bsrΒ{θvO`%]B鯗XxMGNzrf1(.#e %D/8bWX^ _%ȫD~eU46Vf;i-9mW)O?"|&xV]Mjrט9r{ s7sh$~~O;y'̍ۼc1=3ؼO<#.ꥰr! 7Cbyyf^|fbˇ?/yz.e)49e-k@+`6 4 BEוX tۑNv 1YE0FI|$H|#'Wb/Tg2L!wU UҜ[%_烯ޗľU+䯲J2wZe]*mm=xw |~% DOlE+k^1oMe3o~ M7sJҦtP!VUAU &_\"VJ@q<'8%\Ϣ=guU2A}h@! _<_C;h-޶%2Zs9"\U!>_7D>xOWuaΣ=myx}Nl9,C RKeh5ͭ6;\&@ bѪ} sar{UyUϼWᚫ.ԁPXM=]AmF$Gnhf쐃v9sV_P )9-n q75kB-w6:W MkMDo Z33@/g prXbc%E^$%wKxu2#?<_%?OYw19* % YEn< )nOBXlOBJ(i| h匪Q C Q@9+VڈzRhM &DT$,sFQ 9xXE z0p!Vxo0[oPjĪU[H|| ?huu Qԅ:,&V ^{`7·Nv52Mhb4׻Ms rn{C4#ZkmZ+#H,7#^0'\"7ֆX[FE,ۏ~'6ŘO3&c><$Izs oᙍw69ɝO'6m>X+*5 UtbЦ}O|lijzr֓AhogE o:Yh3?g 3ϐwFw x0@igXƻs^⁐K?yEg5Š80>a%zUWP s#1h V'FkhmF;c,dy&0ϼ$vr3Xo)-5孰 !<0o÷1Gwab3V!yy`,#-=wxos* EE+*ӹJ\š" GPĞA+$a0AW%bѪ\LAUUB{.I}a7"&Ӟ'yȟHI̥=̓z>NftbЦY`;D߉o'~}wQ: \}unN5',,]δ4 3`:ihӸjL1 rEx f<,ziE_"N1i!^zWj;굥Z +Zߚ:m ~ D 0Qo>>yz^ K?)O%Y ?f[oE߆om͎zGhCahM2|W_&o'YV$=?N$d2YVs|f3YElZT´ AA /@^ RTCD@ G[@sfoF^3SÈ@yaQ%/hQFE(GSE o~wyo[z^ [!y _DŰ6D{{6FG>K^Qg?s~E;ӾwໃywȿK{RLVU+XIl$ʠP^UB< wzAN/ ˵z>,!,!ڇA?(9G= z> O;$y'?EҎ$.|R>_~_pICG4RC*ROi<Ăтe(HE_BPЈ,P<˓W ԩ͠9[ KZ@sGC7P|C %u(ME/7K^=O7 4?:3`!,''-Ez_ ֠ƷjV:_^G{?Qڿo'Fܥ}}O=>P&d /!R0<(yqÙς  m˲epQGR4ƴo _3Mk;넿yL.0 A|$(|$o w{0} )7y>?&}!1w }%WUv.ڻAߋo/=]z+3LB_ܤ}m;M-6 JXfi!<Ăтe.x0z|y~,MD/ $uJA=O5ߐPQ#vۑ׎!Cч(yC Qo2I0} '7ԙ\H<먷}ev;N?;D8C?(%uJ7kp5>vuI_:~^kgA;ECCw89 CzShOIM?Od hH#aJ+s_Nr? ;hH|'.|$G381|#ǩ\k~M7ȻL&0.jq98K -;䠝x. |AsrQJ.Ћ+(yE/FPЮKz}|#.qkG-Ao5& u@x #EG 8KXQg< ~sy{zhKї[ yK_J`3l6FVw8~!;DaK7į_w.ߎz D!=$?:B2CyV*iy-YDZT" C! /H^A Q0Ԁ5B6ZՄGV[B oN^s[P%078y Qo EFMh_KM{w.wțo;}JX"[Db|af?=lr;HG߇o}#?u98O] pQp.w{Թ-yVh2%bТŗ^򒟏: T]xujN^5׌vSh_ckL~4Їv_돿y}(#ap|'o8#3^7hI|6[?7 G?L6@zQo/=}]w_?~9g;9ݡ}nwMn:ជ}zEbpVȳW?j!֏Zy(&]Q kD}Q'F&ˆ~ +#9|+#:=omz>H ?U6#&:XeX M0$^ -YzUԈ{G41^#ψ20#zh[xre@qЕ\Leot'#J[p뮶e[aD_GM}끦УN^@SsgSl"?ML! @:zŀ}[N4]XI$R_p9;dnigs*ѭobM!3}5͞GY<22?eu)ڲ&kzm'1;\Bf>ZuIB9cOi)l? s_4+|/?h=y|KTS[?hWe seRIŽu;kO6 =aO^7Nz=Īq(]S\ue\Gr̬\;Gw绚=iDߟ8OA-VoZ+(cFשUIF[>1CMR>oR|OLȟL-4%9>F}ٌk@Sh='D6\;sRvR;4%ΔFa=~hR``o,GhX f)R[@RX]!&2QUQEA'0ɻ8HI]|_4wNEE\+v5ZqWtKgfygvΚoVl3Ck&MISgzM86i;MzY:-⸺;_¾Ý#g- faE}QeSYea}a߱5~jTIJJ;դM5D[jҮ)i}C7eU[AQ:+Q _Gx]W[",w}K {Y: X}.jGuaG Object 14xg۶gy7$8${pw$Pb^ZZiR(+P,XqY/M_ wߛq2\uϬ4&:?ﻔ7P^6+/M}\EQګׯ_ WKx兞P͍`3X꼝}X.$ĐBB2H) %Ԑ:{2B& Y +drB. y /P B!( E(RP@YrP*@E TjPj@MԅzP@Ch 4fy[n B[hXw ¡3tq#! AwNͥ1wmfffl1 '*]cvOj1Ziu>T"ؗH.)9 iZa?m=6kDҗ;_'M_duo}i7/OQk~P? ExE=GX}jê=TT3]tT1A۟Pj6+D?h۹넷C.2^ў;G+^FnԿ"c%V{͠EC6Օ):%:]kB{ګ2z?V:Z ˕$, K’$, K’$, K’$, gIsS9nZemS J-;{ɕՒ+d(*6b3WB=MsWfk)AJ7AJ{ҁo[K)ǾgmS|Wh1_~J\v|JjB U̦n҃-{O2hV[*[͹-۳βS'Ze5뀙~[}F{}OUwkeРAcc?E͙L2>XiŔAJ{&]*vC vդ*7nkyMN=R}}x4XV?{;ZgRLHzsiͥٷs1Gx#e{-pd;&;W;[zz}} ^zz{ǽ7 Y㘡m ^34cA񚡡Yx:iw8z{?j;jqǑ5O23u9I7|c93hv]{>'{s'as=se0Gҷ0H5G8hs$~s0G$Ma,}a"1o}%N;o~35ٷg|G?H(v.VF8ؘ\zZ~las^c 5M?c  v2wG wszG.v*_9S8%.G;Gr 75-^1O`g"a\NYspһM{%e]ٽo [ uPSY]f{yuKGnP]G{4c Fnu9ڣWF!rvcD3@zюPمi"A 5=3ȹy̎=hvg'.O7M.ӹw8Sm^`@78CHr}Zm=8/3fs*/728rז{ hhgs\q_o LX>}iY!;%c]=O%gVGΏJf}roZ\u!]wֱoshvKp&k.x.ΉD{%g7u1ˑyru8;گ}Gq~Ya" Vu6һ^r xh݌nGK9:{;&3};q 49XGe.n/&YgT 8 ;ucAl@oY_u;M{k<ΚPf{S8k[5n'йڱJkϱʵ蔿>빞\~g@׳lIN̈́9|w6~]V r={L:'6%(}j7iD*] JͿj*uOڽ+rxBjzW|@ L~D-ֽYc^o GUz3TY J_j: X }vA򷳇(HFoBP#(oh{}$~=i/S4&9޸دr͠%_j:nɓKV]7WPAO;) Kҵv]ut?Hf?({}HV}u`) kRhx:taO'Ifg~:xh 040|#X{4e( h؞oGۮ2놀Kbe.z]/'ZO]OQ`p郍O4`Ԟc>ȸMc=z>xFa.cc!>>M=> WD(7E8~KTF?q>(Q^RH~|H;Kyh C_{P(%N竢|=ߣNL}pܣv|^Op;\G=g Qg(}s}7xJ2x,91xALb?ǟDn"5o|?\sK'> >ԃhuj}602Cf}5}901>P X,%e.iLB}>~'^p;?A8ԝOKOk?{Dه<W?o3)A6o m nLV47TCK\sˍ rB29&9}ᵗ}d% UWE_\eskAC2 6!|;u|; g3Z<ɇS?gzsTǙWq3j_c6W{m\%"uq:&$Ư`_-[za%7\Ao\`q,%-7xaRϸ;KeWkƕ=ߡ[#x= 5hk֩>/ium jw tҐKM>5uiL6mQE7m6mW TJ*D]%x6Ph L{ݰh;@Ѝ\(꺙~DۋOm:~ c`'`/ڏx?B 3`:iQ73ACJu5Z/ph?pۃvNr;nWx3Y8M'8hqE w6[oQw)Ӫ|N5 泪|N} 7~)ГC2$H>@y xռ+j>̗\ hιG/!P\e+kv |Sm-wU+~]ѻ@g'N>p-xwԡ{0#̱'phnMA $rOn>Rcu,?<hmC [`3M7Q)3zNI 7sxS'xn_kpUWj~OE ,*@תjy,/'DOΏu3l9,&br$lvp+WC1Ũ)Fm1͊g-~4F1^#2 6WxaڑmKM[jY%,chI*Y@bHh~x~~?dƐCjXђ%,W%XlI!$dlG_kɬ!ԮFKF_%HRKw "\ s9jQ{ޒ-^ԒE<%xiNgfVX3 5d,-^6KdL֜"5dl- ^w腠 dShy&ԲDk^vn\xZdZmAM j[X +$zYZT p>>!3pjS;Z^ 1ZF̃bP^1wѿd]Nrj[ˢ֊bV?YˋrvY2xeNȜ${ԞVBWY=ze||>}7۽zŸC u&[>AxD @W1 hsC]_hC>#$& S|P %BX'?>%6a lTl  w?~g,gxU\>`' W_Euר W=f<H!=}_'V["֖Xlo@`` fӒKK>-uiOG ( G/_\I%+żUg\ W!W|P_>ՠ-c= èkd=E.10gǓO~uX~sφY3$?ϢlXkC_[ke#{C/_&w%.~߇{bRK=\e6\ckmrg{3 4SC*ROI]JS'5B /J("B^*3+@uw Z3nߖ\[Ե^3Q"GRI}}Hx4cȍ!)uaW4䦒JTg:|+B_[+f v vP>4a|yrɟ,w-򷨻Em^cMկ ZhÏ-RC,]rNKRVn)cg[Ѷm4foI%5-mTO@gpré 3}Px8O}B~uaW)'M"?INɰ1^;rߑ_ArXo㭰37S- "woԝ^~g|_#w5Q>7@'psmGo|zd{.0;Ч# AJn(! A^&2ǑG~uO a-䖒_BݷWM7֓_Oz7g#_E?qǨ; z \ƿDK]2}Kx5"[trd{.+~h~C·[ѶmdgA.eϧ,E!_"O1 Goߐ\C g⇒ %J](m>?@S7{X)OJݧԏX1 k`WuV_Mjg-CA?y?Gsԝ<}.;[-wcN]G;&-(Mw$dz{dz{hz{`og۱hw]M5L}_Zi 5~*rȧ. AaEЋ#W|Q@a~UWJU$_WOeh moGԅB~ьC7(rQ䣨}(S1cɍ%?OaWgti䦑F4gUW_Kn-5ԭU^0 wI~'u;Ep2>~ Swze|&wmnS>w(L"dLqd!ۏyd'#|2Q>) g\ ~!rWqy(B.|u!ԗOyh-Doߚ\kk -E2]u!߅.wO ?A?(#Fx ?d򓩛L|aп_In%Vxx;lJn+m~}I)gȝ!SW[o7 N ]&g2&|~/q$OB. $%>)} f=/~>r.Wq(_\)+E}iЄqSf5'ߌī_g #;RבN 0Pa '?0ī'D &@'g| K/E_r˨[ Kma6o$F6R>(c|Ir'ɟ8w5WBU\;vbMwcyC4L>i)3 SIr1k߈0^﫤GZOaN~q8}~Q>34.R#_Qƅj7;Qh\; 'W|=Wlo{AKԊoJo`1| _-R+@yȁ?l2x՜^ Ji^MeNMm\AOC.5Tԥr JW[ {A ^ jX+ѾWA,@?1 aFI [ սM>}`,C_K [avr{A 9\`+u6̂ԡ䆐b~PG< 1S{ ?{E'u17oJ)j {A ꆃj jMjN]5 %|/lF;wD-`|/(pLMo8f0 G0vH 0 p$Il|/DJ}M}? '>vL} 9gȝ&ZhΩ_P98 gN?X %W/e+xW5zϧ) /EW_[DK}4(rȏ߀nT= HG߂;@~-z(~rɷe;=󽠺j=QW@Q"&_X@{X-|/(UTͦfGN.eCFަ x/U{A"^ת/ ^R,_]"I@W|/WiG^RG?N G`F@f=lF4Yl}+mbf0 o`"OfqԌ>hx~b|Z6X&Cd"1Ta %;0:wd:@M-)^5DSh&!BĢ zi(E$ْ29)Re{Ae"z>2y&7 =)$!lҡ@^ 20꩑ %M]7Dv&xYm^)M3"+d̐ -8Eo};l#6r%v yRWYI{jvLC _Bvv>xt^HQHѢ -I' d* ](^1Mx> m%JFdڐmMM+j[BE PLyEI(V$< *$B CY(ZI:`J %dSrlGWQYEeafE%CFZ W+{VPUë.]PkpI!._&sEj.P{?CvZhu}{Ab=lPA]juԮ9aYdg !Z#b^gjS1ƫM dƓGgԎ^=!L=fl7GkRV= S[Qm-4Gk&¨m5ЫC52UVU۰z>.PJm/J&SlIjJP[ңC Aj /\dP= JvI ¡tD Sx,ulGEEgw]]܀uMd~'{^h? s]4@tm[aخ 1l@[ о[Hf>lEO||/hn_G}׏L?t@Ax3.n "w t뒫CnF twF򺑢aPQB B.3̺l6oȮ|/(nHLԍSKI>u!VƈWXR x6oPtU&XsqOaG'8~WrGQT^neأL?(`*|S&ݰ  ōYhf7C'f*s,e>,3a(g{BbϹ`|w@7gDi;~'a\j$W|-j]u~_xQr!RWҐq&e x 2e\WD $CKF&dR@pA<7\ SeUkxKpi!nh&{[ބ0/p Qw[bx;$nm5WEQ6mb*LC?4S)1O!=1m~ᾈ(nd&ztïGzhW`x$*U"SlEj*P[Avгgjg.1c\R'"Zj2ɦ&%) 9xC?'l?E{\oc/=) ߣ}+[N~uɤxr6 /[@f̧v̅h䆓A'2^r9Jz~[}/Z_C]o{A+-[7'ל| -^*Zz~_S6Zm2֦5Q 2.7Hvxie!p dFNfBD&Ld6 c3 D[Ђ񂹵 H/`BA:ӢO G;gϒ;K,u!?wL3κh pkk,[ɖhȴ"ے6fPqzYʒ/K] ^Y^B>]3_T@+H 6h ?\ @x6ѵ)tu- h| 93yuF pGi*o-4^kyW|Fshϓ;G,ug? B߉;Pxmp[vr 2kȮf5`%`<}TrSOn&ghT Ǡ!3j>v4EN75}t R~gz) u) t) /u /t /!@MjT @Cr5!R-%_VY 3~&rg.@Y!˓+Ou!P֫_=u~mrצ6uS¡3.]#EJ]կ?㏠~_r}/LOF/On2|o/a!r /n %l-oNn;mm-^1>? wP3}57$;u7WgLc)$I E!4$ ap3$Xxed &L]0J@IƥK!W|iJAI~ׄU'_נOM;w'NuW>{C/zI]O{ѧ7'OğDnM^3s琛C~usKy60ވ 37Q6x~؇^{K>Kp]#+p٫Cq2xI >2Wd_&3$!)RG&b|]rwߡ6Kxsϩ{N c\? wP3}57$;u7WgLc)$~2IJV[l%uny2# 777`'K/C ԕ^j1 5𫓫N:uթAwDN.|':B~}^=$ߓOoO@?$i̓s!?9wzx#&6DF'a^r{n/.eWЯ_#wUe~0~{@uw5'RX$a;)Z|rn\+_ÿN:k]+^3?$CR>VDz_dPjb 2-^M5qOK.-ԥ>}(c\~Ir%ɗ8Wq5_\UB}UTӫ;@>Ϋ_O1?\4hꢩAc>6ګ_w ?\$H"O7 F 1?n47t?TSJ4La%Uא[C~5u`W݌wNvAwg3Ϣ?OĐ[_k[3{,onhm{W.}WT+4::b܍W3%=suֵ6 375]Lxd ZFv  *.*2&:kPpAADcYIsN%9ٵ$镤^3}?^5cdX1ص^Q1a}dfMsv̾̚^qv=!t^]'1"ЋϷ{1{zh#Gh7COuUfF; w@Mdr[mtd ݿ owF[+nӯmZ^6̓z|M@9 ߣsu,翪i3 UV2L-B(tDoG6 ys_n}]i56V(Wi۹m8jm2P:;f~n]KWw;olk_I:lн}6\YƁ:[7{.w̓zjzǻe\=@2\Sp]~*{S[޼~]OL(͂K7]k:g^}Fq?]oo9}W?9-Muo޲_݂Wv$kr{$,p/%>4&0yp;̅LX~I^ZRv5ԅVT%t[ZQDEFBO/pAc}&r/AhK__ޥrQu:5o|']? ZVӯ$i2Ki$[KMԷLXkE+}`kOϹv'o'YVN:a$rTnB {ǻ,>iK,h錄Pg,&1qAe/)Jlk9.L hon[VTtDhb}RAH뼼Ƕ5EG8*}PygJ}E9#ols^mms++S$, K’$, K’$, K’$,m:W8:3w*I_p28_N㼼88G*)깊kqO}}Zos>^{RhDx׾JykعMeϣ8kQg?;&J1a K’$, K’$, K’$, KfD_TT"YG+}ߩ>32㽄mR\5ϸg:U {WUڬ{K J(:0 ,|Jfoׁs~kﱸESsG(ݸ*y0vwpn Uu`Ow~;̯Vvm&J-%Dc}7r.o;0#Fc?t}5y9|k/ɝ󧃹\c.qҞ@AO [.)[a?ǿ^o5vu=Jn9o߼?E2Wcy_ PK> styles.xml]ݲp95s5S9=T%=t2w)mNcp W:+~ ,0?6W:6ZZҧ%ۿl3&}}0kz>=A[_kg 4?8:ʮ {>xȷmQYJ\΅~ VfhU\Xmt(ZR^/=;ة^8屿 px8#OC}\yia3å,sn>d8@Ed. ªA:C~*lO17 .wlwlu(d`L _?t-z/&PI]a iyqWYᠼh4ߒ!W@I7c*Q9}H%44&lЙ-O<YPT;F^`d+De)EiwCjеgIğ|/\(6i{|u4QVtDAό: + ۢZ\;oTB11(z z@EڣX_Lid Em$cLKψBRYS}hq02+ҞMx[ޮk{cE ~ *:&0k1^ݷ1B'oɭ3i_YsQKb0l-w?z/J};cWgF}=ikwB,TAm##tYD)sYA㣳:1n}U<|C ktV6R"GH"Q:9q 9@x;D V ] <ۚGu2#]JS̽,6۱8h>jpb9%=mzA=KLoZo#a4Gl>LO~DTumE?_ZK7v͸ǏSĩb-sͅ*fsm˩ .5ޗǾQlvVۻf h1%75fFQ\v`ON#*[bf#KQO_4F~ئU6'EOdhƙnoR"5Az)&9X6ϸ}fW4S#qgV[[%oN ;-pay.XaHXX`3G^` gct b Ay*`#jڹw'QʵGu\$guY&=42t祈dz F4'd*?4_ݚrWw|Q6Mmaa s:㨌{0_|:7mgF9IK–҅ [3"V0`*&u@ׁ`8iÊW|VaQZKKb:.s(+0ю!}!OIT<~x _EFQe5V.d)Q4͌rY+*z\6Ph~rEl^.~(50K!%7'2|H~fkA4qGK3W]Gŷ؍-%;I';`1wpP qRyrU8,.P|k4nb VmF -K@X/-s6†s|fg=YbL3snt#yꔟj5f*$qݱ8^scXe┑S,xQR$~6)*S8?JYA(KYAeT݈8;ICWsekK3Z@HǠV_ pk@-jF>Rj0fcP+ԯZԌT| j\@] 4iJy+aҘKYQga:]όY{\ YRI1RO^qHݕ?px}E v~+&,Ih _C۸UV>9].*kjt{TlLĻL{melB-Nw:܇F+tYT['S^xcA;{e0}-Hx_6A~L>#^iޙ╎@f^qKE*^֧ճe5zv\.2g%G4SM/_^;v{$+/tIdr>Bc3FYDHh/%W cTW#wtH5 |]<;^׳';x)߽ wῆ~+-mp߷mwhZW[(E+{{^L\m"g:g^Oehew]o~ߵw]ҩèfʌI*rن֬FTOI"{w-{L9rsnvܳim(? \sM]秇h{*g⎃DxނŭEƞ Np{ cw6GC"ӷD N4z^쉏&ToiN/hG55^\?@R2WKEI?%03TwRhyb {qX7\(M_"ъ?ܢh6%/=QW9@tkS"㬷_%s,qR.bpii* *P+YDS$'ʟ?iB2wXY?mB2ʟtX ʟ5iO;7ʟ7Y:Ej/PV2CKM(QF*_W^W)^oB2j_vW Ԫ4ӓ;d#CɆZFM%'dinkۗçV,l)o}֦A \pm*\ĵ)q}צA\"W?PT>Ik=Hqd:iX. Rqa2mc1=>NvUۯ^:wGկV%ftƫ_)# Fg[PIaԯ4 M@Pr. ou2(s ~/; 7BY q 6Ϳ3$ ;~EI z^A_΂_kBn!f/T9s Cu9r} C'psn`ӯ`Mn`ӭl4i`c6=mMGIqD9{gb~  (vn@bnPʊFpL>tYE!ϛqJmwwS6 [y//G׌X 8nx7noI\v7ݡ {*A: t4!::@N:>: miӯ@Nnӭt4ic!:m7s: t4i@N: t4ȲͪHWV U_V+T*|aWnU [HABu ).)!k @Ra]Rc!:=mQ|9D!id*|9 yAz9!z:@ρ=z>O@Qn}^U0'JDqY*wʻ{Jsݘj(vЍ>a4pػb4.o|xdEqO 8^~~4.oz5פq{7v D!or @Nr-2o!fe >w]/F~؋ 4A_{^~G*v '[k=GbXص:h;8 ŧn 5&T?꾷^S7}9e'lnXf&[nS/ъhPnNEm탨HtNOĦP{G Iy!mbB*GdZT 8 pmm '艠&*p# >PS-AIR j@˻1)7/IWd˸°*%aOneTLZ04XZg,x&.4x[Ed$N5V]հќ9fbѭxB/D`Į6]P.IK *l.ϼgrY47] \SXۻ޿:]Ӓm"J N'@M]ӝG@1KzS2sp1dHt@SG :V}azGߘ#?D8O 0bd:23Z.s!@Ne;;G'4:.Qy4Xh[wdUè)g: Sl\(КU2BC,?uBὍFW#P *Ƶlc(6 R!MB@X27H-Pp:;ى#Fr1[C8R& jV@J~9 3)TXE~D<"k)>9NZTwDB;O36+6= Bs}-̽ON{3j6*]Zc̅[E>v)c·l棰mIU;Ǘd`N'"{D=c뉶;2)%`? ߧ w$ғ˕FxJ3^ /ȩyHN[E== ]P_PNn؇h]%PKfoPK>^I ; Object 15] |?wַf'laQB`X. IX$ Aϖ"TTh[WEAb[OQsgޛBйws3rw@/?4߾HP,Hr_"uuHun"yH>$?R)*#e e"e!u@F 3RH9Hݐ#@ !DER_!S ! DG4iiH#t&P 0 sC*@4i$V{Hc.@.XqH㭸8 i2 "]dOtK.EtR^ǙHf#Ait >w*TA5jǙPu]p 9^˦֤@,MXruK+1d@WCV?K /ӟ3o/s?5+1'۠镢ˠ" ,(|vhlEUsjBSg2vS 獯YzvP8rWwY8+b%3eao|gs`\.-N`t@[TT+A`Xf5!;b[H@0dm} ;;Sw\⩛ˊCؐP+j"o0S</O NAyQA9^mFJ9J%AN )҉sѤ5^qQDg 6p:׉Z|rG/%]I38z6墰8`$6&sa63YxYF mAEe&J<(`fdMLfrKb9^㉗!KAL6lcxlQLgbpF/Y> C$D"NCj/aN8 RT6-xz&4x RQ=4V4y=o=NW'<7%)RnIQ^=RX3 h!:\ 8c ՃrW F ZuM|qhV[u>K5hx('1TzG4 h, zRC2dDŽFSA \Dg0-BXN5KN訅7 *c5N #@N+Ϸ$F ҿLm,%c^d>n2TRlPmSjN!-L||Xzar#W?A k1I*\'ZA4afL sbhUR #0HjB)G؏ ,KZ5pI\։_<+,]!Q,gpz9o`~#櫙a~+ۘec淳u|~;|f_Mf j l3lK`E%G,mH+[ڵ T i ԕ7ˡ>>3OSFtj.,`B#k~'|YR gkg%Reb G0S#X)+wAPKexTىmur@ z|8FE3e_JW0!lb7q;g pX0k^&`S?|Oo?>o1y2:d5݁&}:2ٿ te} 7[6>ߦb]^pzN!F̋b>/Щ~WV;}Jc>u$擙Oa>U'{.i̧ pKgؿا2}-q^s^VpzJ櫘_z70rfjk6|-9/wUw2mXϩ~>w37F6vodSO\VMc>mS]>3__>̗a^xBLNP"{'F3،[3$?E=3'&iJ6m3+ Z%,:\.B![*O Xױ=ngO+t>Y1=̟gKLiȄJE^T &_{Z^<iĘK#/+DxE гW},U%$?( el~(ٸ`<^h' a\RԺ׋Ww!s|b^OCũ!6SBzxI[!~}whpFis(gMD93&s\ b c$?rYa# d80_R ](bn5\ taT:Y++D=S;?TZ*a P)b.}\b' ;D4YdYa9iaE}~ Iİ-j*mا_f C9xCQ#WyҜBZ 8E1.Ÿ(&8*DpL<]x(&_;(&H(&߈kDE1.9QL#癥٠^3[@d\&W}|qEzm/C{E} &5ܬVjwcOSz%ʽnQF#/+O빟v\ƽEa. sQX zv&ۅ2K:Pغa/)FyzEa. ;qQXHJF0k`X)։1X}Zܦކ}Rtv 'h[v\㢝8\`y:wbo0`9hbro09ȹcηR%%{'ɺ> Otx*Ł{i>pN1 G/X5tD CXNm"}[tɻm esru\bf{1nĶ8PAS53*?2GonY RǶGE-ܚ\ġLzgkdY6Z_3jaP囊ZFcimF6pQZ\ |){đ,ţ'%ŁZ~ t1BV5E-.j9Qp̓ ` @:܉~ѧm,[^\⢗829H/=K&s%ks.gr=|KlJ,-SC=E-.ji jy}(O|Y޴Y^S3/Ms΁-,6XzJ}0P~8Ft0ގa!4g4'vL`H7!JBbG4.4c4.WC݌&=vsgDhۣD- dQm=wb&Q?0~wBs(1h;WJ;.<^G!da>@it;FQ:lFYzAh C1_Z@P# h/4?Aנ1ԾrA~4K7< Tͱ?2 V>1K#i gtlk&,&C[Ezpi$ c^ⵈS+P LW6hZ=iFL/6RFLn%LTM/U1}Zצ#}nܖM"#2Ҥ0/ 2sQ9rjYNrjR' 6ׇ?cYi:JK:،<C^j (T@6R!/[Sfz|#So|[ǟ)nlG"g:Xr>b8?BR STW!'_OR[!/'"ԈGe櫢銪BȖc//<^ljwfQ.aJ9;\Kl,4tS_74\ڇC5/4XWxa"# QjZS_I?1ָe?quuTᝁ6;'-M+&P=yZHd41FZu~GC umi>=( %]iJ0h|=zV Y]jNMiJ7R,f GO9=eݨQr'-]T3{} u4 md+)Ia.%̲Yެ wxuEH|FȄ_m9|URëH$X>AaP()VPw1xLw.g D[pPDʱ +0Mu1 VU#Q,lB툏G%ȪFTʝrLTh\:≣4 _aaxQ( Zhm>b;}tد\ f+iom FvrDA9~=h7mEaIxDBvyk)Owqg٘;Ֆm6DT6=s?EKŇW=~e7<}ZazJ$JkT>IOE沽XwoNQ/ֈ"eXLbH,Vn}6OL|qDx^C(]{m=t3nF[QLD|)[:D{T}D{^=O[˭#&~l 2hwn0ojV{h{j;{h7zk1ڻS[yM yϙZNiV1?eJ}vZkAJz%bPY]tho^b^"9꿌Ri܌s?ڮig)ns3Qgv3@xj-lEYKexBL7Y5>E!s!1L J yj"ymhهXS_RrpW(C}R*}F_S?ɍ0ǷU=&=!=#>5vc?-F<-7m0g٠ܫ7ਛ5Bg}y y+ˢgHW=Wnzz0K攨5m"u3zc Y#>PZ:,=[ pDN[[ihP:=*0(;dc\HH;Qv{|};Ʊ{q?.7|}Fr#?81?X/25~gh6 `9 п>5V8p^X .'XTI/ lOVxYO L?hon}F; hc6!MGʍhabx9b䏱/2ZG9%yztn^fug vׂo|}vs$o 2#Xmg>Leڨs[(ecjE ɋ0ev;fLCLrgNw%{fUTϞYSQUyIA#d:4Կה׊^ѐ4^ps^̓dlh55p |hfC)R7:_k؎󞷝u{?n/^k}uo b70iF vBBpf+J;>*<liFl7Ȩ 0z?yCzo*FEyCꏔɇN~ٚ!]Tj a t]Oԍwq& ][8PwD¹Xp-b#SOõr* Z3Wغ$u{Iϭ?zi^k}"غCXCiY\iǦqs6SN:V8bH)ׁWr z ^N+W\0rOWNr%S + ܜ/ mMTmG:$9KϛUUt [8gBgK芞E>_0V|ѹjas\:׹us\:}X_]5퇷O+|.uB}KCZӾо@G /~ZC ;-ٯBF4~xɸ6sN- i M*ne`rEMh׹us\:׹usNxGU5հMqBʽ2(Y^[+k`>n@ (:%g)0&CۆKBX03,ZSϱUK9hI{mOeeDa \%0bl~ :k/j~e's_&7<ԯXo Object 16]`TU>2$B!:,4DAHh҃IjPD,+XATAQTT݀d$e.|sw}7of[WlyHdн!Gv;6Tm@ D@%2P5q@u $@M:@ PH9<7@o?hd-V@kG~;= t:Z,K+]NG;Q4&BA&fI#4Ju2 RkII h߱}c-j&\=&Qyc R.mP T[ ?`ZޘL:k7?y;x$Zq<&;eǼ |Idw$[h0'9hrh=(g1b]cpWwHLՃڪ"[ՉC[9La9A;Q'61)%!VOkGy$GxjROj'ţjD+*ē*=76|%/ӳtDQCq4F1] krô$5+)D? c0?H&ڢX[(?TXRz_`Ngc{5v}+&DqPy8gB(k0-u=:j-rq}SN~|M~|^o Cm VӏPl/7ke?6T2Y +]9!Fz8Z o4w7nuKjt;GUr"D9VXg`攳|Xg`P$&`EaYk֦ң0>(QXɏa(R|5BiA|A%-,~=1|z:k'X=1!'[ETb b< Z)駣ߴ2ZIw j?#!k;uQh?n 1h7=t?zk]V$~/~}"1 DWDOt ҕX,ks%BA4/kRі ?5F>FЃ+v=w?񫃞NE2W-wfUؽVMK㤖Z5oDjeZs=fUvhA=(T t~R_j+;;BwFu{ͤz1y*7okMzԚG=j*MY$p/jeTm md&F:-XӨVʴU]7v>mgu#rp!,z&^IՂjNn4G_}=F͛!DTm8j&Y\H4j6CSӨ2,o @w5~w,l {]ZI]MՐzȱX×k5H=~,{—Zf"G)M+롾1ˣvi.V?}T]LF`4>>φ,0ZI pJ=O|9P+AL;+}RZuS[Tu\̂6\;}8B1\uܬ.qSV>FliwƜM6Ф@0̱sA5+}m˒عX$8wfq{7MG|=gksb?[Ƶ/~:j#"G8bl"Q_"8Q~{L-;Sn@ yv&&M$=Is$g.Hje5)qj'(.Z nOs,.vL8 L SSY3c2>Rf0UݺVq+S^5=DYQh٬{j3 {=gU$u1U$ۤi(Ò4gIŴʹBPϢ.ys&YީEz~/Le=5ԬzSz7)ͭ\"VN\5̡'1|#ʖk>a6R-/4WO"oI TΒ!γR =`PXC+zXbmtjhR0ԢušhՑWGQG_`h֊Fpw1BY` [&#j@k~, (.i/Jn<:"mgn^qcR{F _5+TUrXK tKj;3Cd7 z9QġjciZ"m_9_ʃr+r,Ue|ηSy 2_GV2l#VD w|@uXnx S6~v4*O/[)Y:{۪gM;k-5K_Z3ҹH!WQ]V+=eǩkYׄy+%< n\\ C@rn"N?~`;%Iy^tՖs4Z_/U޲ӭyIK.uh%w2wDֶg%ndY_55:nYxͬYU~ŌLMf"o4kpmȒK-˷̬ˁf*?lRY2/C^ "}_dAVpMV1f6"<qn8b6ҁ@d-k._ٞsvKk._9h?W2}z~?~?}`n|114Fnc$p6d#x:ˏ[qx`dO.J^6#d&J? <%-.A^Oq]H. 6IMB-:WXUc)"dK2+|J_'*`5dk[.c|8? @@ρOp1??lt o= l6BvOO6II~B<Ӑ=ݟi{Dus!{![,~)~)-ӷCw>|ߥ l;/3Wx*O_i.߀MY7N&o{ݐj ِ~8~d{#o/ ?A3GN?|'w\DꇁπOC@# @ u`W)WW?Q|Uo~/@,-׊;Nπ# ~N ;_K3\ ! i?A3t?a{G# ӊyv8{a xVc&ӚyY9{L$h٠E@#p_Vj,-Nժ}ZU @VYժZj 'BVZG囨$`VGh@m %a?(Ff$lG!h.t2pi e0p KA @kJcD:jMf7,t |Ͱ3ntZ,]My`WiW_k ][i|յIQjh$A#RH'Y.:Yu\o-w!Ernuo` 8/ϡ; ðqK Y/yH?y^s2\  ˷QMfBrC6H6"\|5ae(dà&koŒ#K,pl,QrG WC6R|2EdF&IL& <q LAv50 \mYL]!2 %(@ Q<B墔hhhٙ,`6ȮZص> #-Vuk5J i i4u#Bv aPnFn&˗(&P ;$̓&Bv$"Nr*|p;'@@prn9ww"r(K(GawGKE5}ʇ|K,Fxd~R`XЭ8X l<-c~uЯ:دu= ݣpM oXc=* F,7Ï[''!6 |2 << <6I'n' D~e2 rU`;ȞaP;(݀2 *dA\|m-i .^6o 4u3)tMaMmI\$uxxdoKm'':/pNgr>pr 8 |o ?װ: a;}L_' seZ^^c3NCVqypiy xN'm؄f=l7 Fd3OYn~  ḲbHK vi<ҵ7", tmL:)OdOHȢҮ|ir(FIU@% (-TMCVeRm%iPH e큖e-O]:[ ^%CWGkJz R:%kutUa o!@FZ`ʯI4f;:ʡLyq=*zBX]>aJ7Nu$TZNmk}W*GoIUą>%%OMX-?mxv;Jr,BisyJ3Nq-T3_ia 'y:& ^&ti`D.ٯ8it'tJQF`v}r>@4 Y}ޯOV,4|an z6kroEr_C7k p,!IG`NI͡㧌mNUgi sP>ggQoOS?ӈC3ş{on%J8S^!V[Zè6~O{/->Wg*y[)l_9Da!zFZV;LpK.o#- .q&eyjD8@%5i}F<,Q>w}k}|@/=SJkTu*nah@=/ƎAyMr*m12Y͔9\ZwlJQ.-?oVFN8HCč) lfi4rAv$oo3(?\^ڏcX#Ͳ}գߵߘ@tq 'ZIH/ײ?<0}+йB w7Rv:pȃ-3QD}׽n?"T!w(_͌5SQ'G1}WY'O@W7:jw\^5Zէk 'ByU"L%4$i}oBqoNnOP6X[+Qǭ_[ZmL#=@0 \ :SXiaخM"aS+2HImocIO_o%8m"=ILafgYo,ݿ 4 qoMټoR7׬Soᴺi Ro&EI}S\؅]m[޴ď5¤a=GddvjGsO%4l%jmdlNg%!lXwxKU޺t V͛3)}tnǛq+|)Czmc'RÚ{]؅]؅]؅]؅]؅]؅]3ܹ}׊{~ܨjǑ/J~>}u.ԹrdגWj Q=IN~U{@^wۯABW>:x?]VUSUSQ]؅]؅]؅]؅]؅]؅];T@)t7O$d8^Y3I/UE:R-7J;C-2ʡCe'}H>mdzIʝ~U'}髪5']wn+Q_sFC/u>M,G;=+۵?(~0y|] *8og~i12*[ vzr?<PK>&\ Object 17 `E' $!@8C}  pj@DPEAWe=@@P0"@Ei melc@ @< @5P&H@2m6A\fa A\ic\Z5xfk"WD1Vdq":(5$`P:v(mƭaőR鍠rmK"QS2$o׎"NR|c,moU+,:IistL [iބk'ūAqoȑřY7,L@/F$j(m.7QOz$xjof.F#OZ2DAmjQ.vv;Sɾ ww!. s;#Kπ#-TMa`zNf1hNr-GSF(^ zC/16z\TCVfpjU/j1jxjB*pY5ΥZM<0Fm1%I?X#-֓Q4S7c=\#,D']㣙9>Z+,R5놡7s5(Bl$9,udh%TЍ‑'a!O^+\EW{t0.RqaU/@yK4ȧ<%3T=:\.Έ=`tS2_ZCDup֢Z1vC!2 [4]ySGv~O2z3d=VGBBhDYJQUH5zuJh3 ~5u 4h j>x-֊(G,Ԋҡg`?TAK/_o52,Jo52~^9ܚ~{65lld`?w4SǴdmS-kW QrF] %}81b0δh.JHlH]YjL3Gǖ0woՓtl'c w,ca1;O Ko1yO1 PjmEʷik *GX=3I=ĭ!EzYƸ ;+&ѳ:Egj!:؂Rœk(^ӧ'6VCPfRӻz~ EEJhz-{PsH}]2T.|L^汅U#QG3۸﻽fF7z+fTlsrƪP܆ONMK#؜,:/0ji"mިqvrwЩ[:;-D5)i4*7F-)Yج]FOTOºKvyuީtn 7{x>4"U9"Kcui/\򚠡OBP(]㓞fTr?CK` \s=PPz_q }?)3 WDat5u]GJQ_i0>WYK.>CZe 7\/mHMb|A5nd#iޝF)FIrPx}VKσD"p?A;ԕ7 ~!9zWLWjo\}:}B_R~c5$<Ѷan6s+ח\n{偲,=>x, )R\wm3/|!.=b>*}D*Ug#bs-F#4{w\*!p'9[KmIPLP\f**^5biQ1&ʰUWhF<=bT5F6׀-DZEFmZ ɴԨ ["-B~A9HQեѻhH? >x lu60r4Tph [6>F k4~F3p%MakBA/ AW ]|7-ỚҁhMQk1 ~5l-1Pmlh[ы1Pkt8]O1H_D`?4aH/6pC}0}C` 76`wþ ]H w!n}(|C}车gV}mӇv}D<#QNdQ`4lcˡǀL !>ZK|sᛋ4sv.@ w> t}2'6D;-TOu6p;;ồ_3&.0LIA?aO?ґ>E=Om~/و,JmTZ}.)<0, a[bjx}9U}X Ű-xaG"]$G"_ |+pH_E 0xm pF[M5tJ{o=} ړ8=cs ` ^ۋ{`{i?p^B;s`#x<:lOh/`"=mE%^z8z+g5Zm^AE`! n!/DE6ݥE37nܓݭm 0F{FQN"lM9ѻY }`/xm7݌A='v8zt=APi.>˴#P)Ga;1jTC U@^JHW +#_v S =];Ѿ_34lH_З|w}Y8zȟSpT~?sOcGH{y_>[RPNYD;pFo#[H&xF?-7`3Y=$#aΫd!y!9|98z!B&[o[sA(V _Z6 owoܑ?wo[[>`; !}0w3;r7~o]tA3lpډw;ora__ p@~x[_^ ?r#r_76Ag˙|3x.C y<Ʒp#@ n-la<)"eR[6TQR6GFQ1 `˅/%zD\>ZpZ2܊xrњh\'qSЄ')`*m̀WsP 8w 'nH cH/i6y  pr$w#>8Yӽs<7G$-i A",m>''#A#H>e-OV3O+x/=#lx7^<= V` l7GQcX`[ˏ":0+[4+v%j^q-EM>r?GqAc>8zg||)c(O4DZ t"QqπO῁48v!^___׼I|?`+_~B'Y=| [!?6G`[Vÿ V!j[#~'^ iqc%D ~?``SQē)T!4ۀ7ZTc@L9 æH? 0 _d m& Q+"AEa VDkD%y,[PXPԐrQM6 *Ɇڰ'_ j!}2%ʺѫQ[V2VIׄ-QV4i|XW_ͥ>PEX`qaf}/6zcXZH bh2I(ӑŝcv;Vmqz~V/}k~ΰNBm;bowUovI:.*D2nf}xp91w]ng[ܿ}s9L^֗|[_9qwt>jޕG>789n_vS:zz/d[_\nG>Vkx٪>\Fߟ[*"Df \~bwTw&F\I *͍k5B|;)hZk@k:$0  k9Q(Nߧ؅χv CT g`1-EV0w.(!ݻv1o$q`bo얻ghߋPc༻m;ޠ/\߮R0;ɂlqWzm6Ω1fkY\w#36 |_ `pH}S䉭.^ݳ\".a: ʿ@X+\7Ԣb`0?YX)ՠZќW OPyyoOWқI#z8у ³>?D\խmWqeܼ9#r;D87l8%]kcN0g T+Aw\:O       p?}pej`ϨZla k?[X}\@=#Pԟ[-aVFRMXAỮW:uݣmzFvV uzb +Qm*>>       ;"_$_?UyZ~t$o@c5"EPWUY|h#2Űrס],C3Χbz8A46]z/?JOշlߟ+CI?p;PK>= Object 18 ` GN/"V@@E B<D=EiKE+7*Z۪E *xR /シ(I7̾c_ߺw}ӷEL8Mhqp"l v҄PxEEE`HW8shy$: TP& ߐm#dLhZlV5hc ڃ<t| |n;')T={|d(wZfBQ,J81j1UWД^DҴ~!bT1rgLR*&kkcf9?'ψP#kW6H xd xR[ҫK,a@3's'q*kpwp7Exͥ6DsKk,1up5I2Z.%xn 紕ɹ"e /# sءWSf58GJ=CrhHhAUzӓzq zapuuTNSQ(,WډX"b "r1 }(rω-sVI}h*pVL!Uv;( N Q9\ZN*pAzU8UHB!j zTpd6W:I:I$;3#M]NArWc{Ga;X򱣜>_V_O p[41McJy}5c4QI׉l=sѳ n͌nhnjfo_Y^<ښךך:57UqSǰVCۏxf,22S!oB!r̶m"ҫ2YD0f!)#Ӆ@*3X`bEU,BGDB%n;\ˌ3]~)78S"Xܖ_&a꺾PSL,L$˳.ߑlV'VZݣ32虈ED3vfB\mjiQX͌LHi@#HM3jDڌ|cыacࣴ7o͹=ƌQ;Qe3cXv`65X$, `vNcL.xrC?3& &o,s7KZ@>۰iif!Js\s!7sy (T:>wBhǰ/+U]v[  svܴI[nn'm1O.Cҏs~I?Fa?>]4 4(G#(7h}U'F#]4 T)}YYcO.Vjխf-JJǰ_|w95B~RxzKR|QkYYYa?4V?qPr oeg1)`O"$W+AWcM4Н&Tƍ2晡rmJ[?޽^_]5`zPײ=|s8 %l[*rT9Gb&i.s~rSKPmE'E~!&M{DlSb\֓Y[DY^1uƶWEd']iU%,|pbdq{oʷLm# )**T(~tA!Esޭ2rl]e$t3fHlXy[OD?57vL,Um'I֗;EWwJ1sFf/YӬntr~繎Vh]T2iqBO=z3 ZIJckenݓ[^΍Y9]R~ܒBOd_]yslNC\6gn Rei3Y:z:Za%zCj~Y DԑLhQFwNL9QuV}ZўA8qka=/+k!h̍[FxşK }[h\\2cs).)]7˴5毡dklu}ҐPɁziu_K}(؃xEZoXȽ&zuζ/u7QuzU-[BnP&5DnQ%5LP1MTG}* zZ1|m:ܒ#skbC9T̯-S/+"+~HTBݜ3gNJ"`~Ř]Y b'ڳ,Hri%ػԭւ3 T-E_`S9;N'#:N fA 6鲝lʵ( [9C18j?`?؇m/^$ x{~;~~]oOMmo&_*+e!*Uw iւ@ob߻Hs 7l/y=~Aۉ%zK Pդ ?cܳzG}% &? $IMJz]Fw)π?mۦO.7B{ J)lඅw=@O{8ǰ= {:w~D@)|3[x&Zj$C`X6`)wZQAX `[ Z`k>}i@onx7Hrl۬{S`+b-omۄ&npXm1bZ׀"p+YjҬBE`1X]qNlwZhslPfݦgYpwO%`/LO~O6`~tEKEQ2GY`f=*A5[Zst?Fov3an;Ofۏ~;Y?A~<<:ߑt^~on]f] wVt-JtJl]+? u blWM}߇}>t$l&ez+آ/כ80LW`71~=؀FlclF5z^ VKJWg%Hz E`1KHD_Bbls=Y<}>\@Bl#. M+>C|8apè0r88F덄\ .F1kDmܙ@!} =⃱ 7$tċc6Wwyck摦6#M3}:Nv*ܩZZ KWIdp SN }_#Q=A[7}@u>oI 5_S 茭\'U[fTA:b):l6 pjW`˱/_JW.лnX" x l*CY*Sߠ@4ye[B4 5k't= LW?n>W;4H]?\..\.R!]*Id)RẂ]9&napZwPRJ\srŷ=i |L,4ſ)2 l*Tu\ecJϔ3u\~/Ŀv };)O;#j+?V>^+]`7I[>;}j3xRWO |ܡރu`=I^c{]JV`9˰/_ W.лN/o =LR r| ob'w|1?tl/T5\&?x ]Dz]Fw˿m;vU(Oϩ>yb=>tŷ4gTڃ\'#m @ʧ6Oa IcB =|}W.wn6b^mkՓ x<밭{A~_'ր`p+J\ epYrҬ'X⿐t 2p?ݧf GnpX vozS`,¶nH{@|I +; ?zM<IND{Z1D߭^vۜ{]Y "198_w4 YU>G/S+oׇx:4UVٟ;}nPz3m`g8E~UE<3Yj;~fݵw囂>u^@wk}wpWcC}|Gų֣_V>@|!Z5#i{S2KyP!9 V*9^<Kg<*+]ב%0 T+m s>ڎڒ;!%̭E);1Lz3]TRjK-'}˶:Xy͞{}.leoIje|*|di5yۊUVu_f7Īmܷߺ tm?:Kf7momFxڶe{A!rHxM3 :+TtFqH4˧OԈxl?+m1 ]:;"todF׏w'";^yּILcE!/8Tm^9ś= m_3MFgyퟗfGGZͻ X,bgV]Pӿbly]^z1$~o oNƵyߟ`|t_늨o'w,c>=T`p=(0ߛbxDCzøT&RDaa4ld~lOS *pu4ocyag7"%ww΢ۼ2պ[^fvy[Һ:!2=@꼧oKDHp|mnotϑχML[s[~.3;#~f;̤~i+2 o-Y}h͌f>~T_"U,̠aқJ̓81\z)ߵUlE#|LL;%\qL75?NfnS oxsO23A7~t&|m"$B"$B"$B"$B"$B"$B"$¿"|_|~fidS}~K4|ͺY#0!RͯW onw{Exg}"z^o9bxa]FEb9OkVG/U6;{EcV7d|X:!!!!!!}0߰[,JE8S5 G*KRd4\ݟYK1LLqQv!UkaV5o&ce.C=?]{$wqKw榊iebroo S ~綶5?E b*ٴ ߿=Rg:P-j<(uˉ CWZoK3Dw!lӧ~&l>emtJ wDoPK>h Object 19\}pTu?}>v@E2"QJd(_Ň θ.ĴUV+a2ܴ@0M&'1S'3M'm8vȌiLGH;i0 H=VoJZḱ{߽ι{߽?:s΁tJKǝqSt yLqD6Arr9rrjstB\\<[p. #/@ʿ(Bz"/BIߌb!߂|+Fe]˽?>HB v a EiTNZ5~[K6։RҐx$XP r{k^>+|#%Rkk*$n*Ծd3YoB0r3ېoG^|@mЂJ?|ϘZSIZK/P )Fc͜($&(U"=t>7PߖJzp+^?ang.$P*%p\ ,=" +[ОzAشQ-Fl\[_n "O}8Zذ X>z̳PPTjZ 4v,H@m#![xx)-zG8Z.h=iE8sqtAHX-Hgj0r!*06bPy7s˛Tk2X Hmd,\,Vc;@kI!EXDsYpi35k>VX "N '@ԂlZKObX~QcQ'>cϝlͭ.M#}~O>~HVBJ ApDPީ<v`(h01"_Ta“L5 SCS#D R1/dȓBv#; Q [?Cp5A0q=ȟD~(א:ȿB88(K OqSBrT-↊5ek3ihehdlP(b+]$ʶ_u̘A@& ڠP,f`ЌY#BFf=ДTs,Sj&2" *aWdC<<x ̅7+O3 g]x9xzY@<Ӆgjs,]BY o5Ql=A6_$ra\%]xe%.%wTG@{!W{.y9aWV~ {~.[6^FE~m!/G B[F\\mmK+U%]x .~\ GK\/+N'`* 5塎WLZA G` z{Ćy urb{PcʏqrHO_{*,k y^<29˔2>hwvh3y~s>vrOzϔPe2|ɱUN@ɱTiM+ 'GWP i@e!!y2GS9DCi4hѦi7$`$;lP lZ=o3&SY}F:q;M^j[p`]3 ;Arq[SkԷO'1okYPˆ P4ȓjXc/9In:=hadVaƅᐃ-uT1bQ& 6ͽh{,Jbow'fh ]&:D0zzcplO^ZfK[ҿ^ Vj5=rlvؾ ܶtl2M9> ٯjdhzW<:Jv=TtбKCN؀n` UJ9PQfNgJF»Rxq|G~=_j5U۬^z95{T/m>kO蓷+)=?kt${󚦑__B|E@YA⒇N4u:u%{80B{ :S0n`YU|G íEYiĪVX7L7Vg4yxoХ[{дx{cCT 9̨Oy̧֜">e+ofcz}SY~s:|X~}5>Ӹ'^5U7QnKަ֪7 QsX&gW5j7139 (zPHҤ"_3ƨ~=rӖK/wuƨG3{Yܓc9SQF Lڹ%ht k- @fe-*n ysߴ[zb}Zd~ ܓLDӉh_l_o/ECDŽy&a udo"lr"O҉d`41Mcݻ;IGj5+ 6djx {\oq/h yP7zc%] Cҩ(<xt+~~rǥ@VǏsB:31+gr$ ']SsjGV'xOO;3I!{=Enj֠fʣϒ{ɼ14&o tH_w~yP*ff}O&ɍC񭄮]|/Ts=DT(OOw?LI;Nָ^Q!HiPsUo0\*l(P'?6ƦxwQ,XS#O6>*Ի@&#DI%YuS?zzķ#SN.G_g".:#"OtgB#ϩ2Gc/ v1o*}Dƹ8D䑌zPݷf׵4o}6 (o{zC ~$: i)~=a 𙦇;{i>9]*?|i:E;]|uwbΝt.;g%vVSZxh'1k9ĻcT}.5S\!Fc8c#_]?[ohu)o(./ES Rpݠcy 1F:oO+_x&T%ȧ3)n=׻ ]YJQ|jו\g*,A>7>TU|_wtL3/G=I˗R-& Pf>q>>͝_)ϗᅨ/+A?PK> LhObject 20/content.xmlSn0 +&8@ӤAҸ5@# K w'KRvC0~vIbXKcN}i_1ig*]>4>eY;nkp:ًqDB˽茤m,HdիZ%;f->S(bV@$w8e0!F> RRc a-mVjJR # :R~e\2`H "wr#9<b:"T@nQbvC1 twPp˗;ڒҀ9Bcfq~ JCЂa j"Bh)jH꿂=jz&PK>A{^Object 20/settings.xmlMs0!$m2hZf I^@Y0&l'li}W :W5^AHNN8?\>up6>xq\HPJ =K/yub=$J|#4o%OV򗮳P*\w\.ۧ(nݼMgtQT2z;85nil ͙Ku*MlƵ+.jNּ<#'}֑~Ðϝ^̔ 4PL/l:_d{j]gxh <Q: es ]." FjmT !sʳ-̎Xj 85 y 1DuƄ<Ag9 եC hAv)"ތ0 }Em1bm$*yXUe; !8 p$vVoǰvYj05Ӯ`U$VE$vЪ=J%⒘vAXھ]5c7/UaKC }øiVdhH9[[>sRd6Ft ۵RdE9?V>H9P<0ңU;g>ǭTa\3kCDoVl@9<>&tC2A&YsK2Z]wTF9z:mRL#l#ź!gYB9Z@F]wjRN)6BT7 O모"UxN )aZ,^ Gc!k(V F%~8u= PK>Object 21/content.xmlQAN0܈"lĉXXJb/MKG#}Di%Hz]ϊ*akBI%)rn-ݔՍ4@T%+7ukfS JLh*Q*b}iP/:Uu%,g>s%|(?M!b0{V)I'ȩ27*9oCg< :c 4nZDӶ VsCaY~PK>5]Object 21/settings.xmlMs0i dѴ@&#+aL(Nli}W .s^AH6OIIW1l;_'KFKǝ+X,Ng(f^n{>JGq 2RgְVKɝдnL~rH?N<6u\_),Qs=I@|vޡTٰLC55ܼhWlu}o;Y[ D,ftM&9,(q!Xd[GF01UoC0Object 22/content.xmlRj0Sr5cP6"`7=@l%Ѻ7vjj19_[g X cV JTYB^_n"cWqlBEw63v#:B ȸr2,Ό.c!"S`0wĬHBGkDSoS7ӿQe~  “FvTu;iǧIۢS>s|yr>I_h=Ji%ܣTۄNXB \/{ 뀙,s 퓣2@u@d1cAnSǵ2-71=NõTLm/PK>d^Object 22/settings.xmlMs0i dѴ@&#+aL(Nli}W .s^AH6OIIW1l;_'KFKǝ+X,Ng(f^n{>JGq 2RgְVKɝдnL~rH?N<6u\_),Qs=I@|vޡTٰLC55ܺhWluq7,.}t ^3:&.57D>;|oisjroHw1,Ej;4#ʮYzrLd h\hmb2``)u%(/e >CȒ9nΪQSQM)R5ņPi]U&j] 4J"+v,"beVqJ#<N hPK>63Object 23/content.xmlR=O0'l4)T!ۭ}m Q~!sR҈ dg=w_xK+kR6\3Mf){y~X\$Zj|ʖ;ΫT7 >b>!HsMH|Ayhg+=9"sҊVȺOV:E)S(KP҄/ڑ[:ua_ߓ7;\Object 23/settings.xmlQo0)Pݪ5*h hl:v &2HRF=!~?ghݮBV{!)Ӹ;5>sٌ!pu!A)=Dt.uۉH*=NB=ӼSQ}"@fB֬?wur/4M!imUԶkmG#7 ]Ԝyy#'}֑~ÐϝN8fʆEfK9?^7_3e8} J`97x\P#`gF01]-5Jۗ+2uXS_bp{M_5gf$ S@0'E~lcLo]{*~NyE9`|[ CysۏzL@_|s8וa4G۫r}[ÖGUѹf־GDoVl@9>&tC2C"YsK2Z]wTF9f5 6)&M\Tb]RƐ3du,yJ@F%-j>%դB-eSl %oO벨"exN )aZ,^ Gc!k(V Fgp{GLPK>*FObject 24/content.xmlRn0 +&8 Iekiqb )MXj([W?MsBH#???I'VJ;+]f&aqW@P[el~༮A}7p~ɇqgi왉RJw5 ?@TOEFkd9f+&iF' ,ѥ >GirA]ZQ=q⅗y(y#ŔIWE?A#?۷֡Digs>i GktC>@AL7oIS!p.M  fH/< IPK>]Object 24/settings.xmlQo0)mmT]7$&I")O?Av$"w|UĜ"oӆ0|v&w'uf4?  J!ӹm7G"9@*1Mߎ7ɊQvJž-)׼6o~BLHZƹ~woBr;Y2- 8 "gظv5E͛G=+L0v7j7 4C7;ajk@|g|92|| J`97\P#`d[GF01<+xHmظ}f!<$ !r5&\%:+L.M=,F3Ml?rSDa*0b$<0HUJfv}Mq?PXGᔁ}Qi&ގa5LM*#`j]) IHV56U!o(jH|7 "j͠/ǁJ AW:ԗf^quƑ G@Blm_P I@xӽ lJExP!smc/l?*.!C}-| 3=^S~ƠsxJ>.5="|\w`Y5[Qn"]5ҝ[e,`5N24.@aI10I` Ħ2D!dIKz7jg(YQ{&jb#DU h}𴮊*Q.ِr%rt;yc[8n`|N{4xEtPK>(mC0 Object 25ŷ﫺z’3,I 9+H2JN"H27cFAA0"AIF҂P[|ۧ9af9v/}qF+T@q> D!SNySYTp c? !CdS@䀜 rGυ,A~("PAPJAi @Y(TJ \UZ+XրP jC|l !Ac2oʲ4ZAh 4z\٥d2j&E-WH}Ba+DŽz4]~HL܌+ ][$wLZapY-Tu["-H+B6zaq {Q,j[-O/"ЭꈮtLtՙQ2ntP˴'DE6;R76Q͐1ɼ\}F4j>45lnA-$ܚ~jNLaL9fmfkV9UEc 3?w\Ĉ+>V0+w1ܭO(3tF=7罖 Ed)N?WGӽ3[6SoLuyr-%$FݫC$&%:UG&"zu:Y\Ngeg&d `̄0ƒ ^`Y%޳ L^;U2j=O;_w.^˭b;s69VμKFq_)QgjժqƉ_lvaͱΤ9$i(Q./靲9K^3["jtj,#~ s8CNGD:-)5i#LF>NgV))}*r2&;ܖDm͙UnrAgzrwMZStqz93W*N`&z"JDϾHqz2]^8/R/)Ny&z+vE+^"镉]-3U QueѮ|!{罹ofo9R[ן~*tűP@ ,YUS_|?mm"]G{Z Ѿ:y/I 0yu:59}*a-Eo&V?f$VU]r|dY֚)9%wܞg+h//șXR32JGk 'zoVdf;ǞKݳ |7Z Mۜ3b;SUqP]U!^'oӎ:#jņJ[#n#KKDs\#Q sD{r 4Z0ʙɳ$z|~lhF$\]x)izvL9W6ˋ8gU얽>/7e~{9Ewn,Ŷ͙ɏT}v^mcgT ,Ŷ$;=<-XU^kijXK5;,_^h6[Ƌ8ׁo8x999}l/\eRoye+uaxjrE+uirߋ8B(tg|-v X5EmO:6hBؾ!&/ŶX.@&G1 D;ԛ21v{8./bE8.<5!7jn;9K^pܤpĜsssܜ."77gcL&HXOjٹ9 "}_ƍXagB<+}3]Y~KrLX[/Ţ^Օu'9YX]iԭ٩U4Ѻh}_ftwU諸>4hHw4H<8C#} 3N0WgFgz(dQNVYZ&DŽ]DVz9݇8qz[^׈Go z]7z *v OUl4]Yqdp{PeqvbL^˻\>Sw'6X T1Z^Ǚs7;ӹdhc)}=ӉJϠO8Oڱju:%K#-鳭w|M(:Crayv[]>_~^ 7@ Nۉ]JƓMirB [~ߚ9խUi $21Yz[Yks.w++ɈN#JDySDFuszJ&[%V>{t[HG=$]%cKs T~̴$}I܎yy{gpt  ;2)2>1mdUL'vR9Py=DNSd!r=TNi.iHj/# 0|C{!<=%O~? h?%O3,_"y/샯e?+=&{~S]kew-~aò}D54/3t_}L <G >G#V vbwsw{|`,OoZOһ}zާ'z LiPԛkx=|WF2k:ނa^Ͽw6bo!V U}6ZFkhuVlׯgiY K`1,O/y|x3bg09fBP WLe]Liu93C P1f$ # p ӝ# A؃u{! A "釯o~en#MW}ݱ{Qmz101V?n5n~e`R4+~4/K2N rV4n~ V«m4W ԄZP[o].ϦŔMG ;/P@KBZ"?dƗK>lO/yc!;ggD] b7SM_&OJh ӻ>:U{>:uĮ'ro \ ׀ޭz{TO{/ޯzߨ>#ukomfLlOoV-߂aWKwR{Z`ğ$I{S-W1lOee +5z~C +ُ2X K`1Ej/Py0Jp ~#v䞰_<=㛢oRi0{2o#V/M]@elOoj`T7DF9[גf)4:nj_wSuR}5p-]vn_[5ZcR;ip%4j3a<@l9ɝKn P|5Ԇ:_](<'RS_I(! _1WT} a{z|yN_>+V_noG;#;_|7\j?~1_X%@6'_:ˡ~_'W~ǭbPWЪ?dU#V%Q+*CX rj[G|?XաTOȿJXZWBh !a޷߳@lO6[X۰;m p'C=OŷӺf_f_nakZk2X K-ބհ <AXYZC>#n?somOZӬaLk~ceQ0n7JYaa{zAV`Hb YE(vI&4JY! ӫfUt='v/JuyUahohgh m[ke74&Yͭ@=prM 4N C <;5;6ԁ֝z8 gg$)x<P Aa@uxV֑u|_@nk-> ևl;8i}b ! '7U ",؞^ xH/xұ@ !c \ >G!xzE{e>Y8V ~'AͲMc6| u ;6.wup=]u#;݃oco%F 7a{zʁoAUrppL! ,÷T..|lOoyp|< ,`\|X'H>Ob <9ϓ|p&eDPNt(|:)  Ml *">؞7bJ$ ؇&GB; bCĉ~[;|ߋ?$ eŸ͢\cC|ePJW=^T `#=qԀPX}r m|oᵢƎO -¯·Z )ZCbTqx G-?(/`!6WڃVoWTF+^i9҆}*4fYKSEoR'ͥV7R>^Dc F[R]QL ]N9>8Q׹T|>WO Q |..ήfagͽj~5SնSPl7P.,E;bM}c=nmmVYU9[3L]2_5zߍ[]mƖ/p2V@1e_o?+2 1ZA 6e|t9"[r[B!94\g~F?1~[n=vq46_Ps}sVHD>xelLxZy짭z+le6u|ꄩkfm/Uk7RA0#mfcz&椾|1j=IMBOUvXU|oξjN]5Y[i/k5Ěo-^bk}_m?o?1{XuU#0jye望92Xк;{f(ՅXΓ؛\n|,_ \tYMbOe\4E}QbSz?c|Jjp5x7ciR'HE>e/rhζ~O2ԩ3y·eyٟlpU>: v6wS8 *W٠M6ceex/1G⻕ح$xzW:T3TU3ҰGU]A Qaۛ0|WmӻT7^[]o@_~faz[aݠ+܂fb74&.jN7׫ p#MnVx>g,6@g]M*Z__bbz-VК6k_wbtUߍrIWݬ}@Wn+F, W+wtI6kZ.#v}L+' :"Am_.iv:໊U1f7So ZkA~n_+vh ͠92?J1x/rkHfSa LB= 5$K6;ȿî &jtnvU |5Ռ]M#tvNg TƗLku]NײC%K%^C+R]2|9b:$I:]\gK@IRJ+;eJhA\gE&VX7OpGM!n >g0~&|>nYq2bzLꖖַWRQgO;^)9]G.ѵm趸Ƶ8<:kpڰ~=+&u3|tc37WnʫѾCUUoh?mmkh_e Tnڿʤi G?v[yKL !/X^3Tjdg37om{L?G]ކK5&ƷA*ꭦ\& r|n0N7U0 b;Op O'~#S(e|fXƷG>Qova3.۰9v]_JR,R4bx<K\<Ϗӻ{G|yȟDIԿ5p vgw$#}!m)9m{']. WX]r_z N"'L^e+S2J'.)#ظtp!z g}>e} JVlV4>-k,^ -& ² ˙ς79ԛĈ)0I#~/y&8Q1ǒ7K1茆kF)9MmF͘m5ՄZkWԫMZz7rze+WdU*qzEY/IċW+N$t[CkyPq.؉ͱSۉed}MMR{9VB?VM3b>'؛}LcDf"yX`5o 51U3fl#^_ >܋^b3ƈgXM1gnj(`oY!^i$Q-_@8["Ls"_#Mt߽nzKXa!/]ʜ!S>r.+ݿD_2YfԿۜ{|}˯UDW oyo̗|k/3e)i?ْ"i%u{NQ۷+3⬇8P GMz\::x뭿zڗdԿ3g|ڌ‘_Kё_t==+K|*!3ηG۳DVpsѼ|tkVѝy<\ZK * $$o 턄1 '$NӣU.ȗVI>g{Qj[wrP d0|q3Ni0fl#x@G~;9Wo H{9{gaNbU+.ivW%V|̥%JlX !XoKqY%d_07sq=q&>5/*yKgvUFډ;_>t]әT<*"w84;D)"ٟȌ{"2r̠ȗjWL|v 9AF\_Gfx4,ٶFMr2/cm:lP=SD|AEٸk;mwID~OX4[ƒke3t^ulm׻gs2dUJV*Y%dUJV7n]\(q<O<9{8+"r3߿OD}s_ѫ%"2ߝz$1 Object 26/content.xmlVj0).Mj)Ӷc lɕ8鲇Է;I:Yg lhfO3c!K}P`6(.߾.?,9{eܮJC,gǙw$8=]Kp"d\ZeZ&%2gXanq]o5E!cub#ŷ<5 f~H\VEBʍTR{!={jQ=$ V.4DU S]nՐlCW㵰p84 ~wUī-CNWKkcO<1c uRpe :) Z'?^طY~gQΥT[;7rb ntoA\[SDzU܀o/6W[W8+A:S?er-omb Av(s-l#X7PK>+0`Object 26/settings.xmlQo0)P]5*h hl:v &2HҖ{B$>If+Iyݩ1|v'gߜΗf/@?3 J!KnXp$)x?++FKY(y\.ϗ(nMgtQT2z;y qfk_S:Iﴶ*MljƵ+.jNs>w FNzG#}!;z=6q)vio:_dh\^fϸh3\Q:>3]FrBiO FHG2nhpHĜl'm,aOWW0 c12$(a0@YdBum=6pY_FnȀp3#LBiB_F}[fIJ(Vlr9eN{éޏjbD22/*1iVe$Lʹ+"!XUaU *dRFDr b *m_r뮤XOa"L}if{U7~Q_ר`$@w0ݻvT9s$)[~cRù 3!=Z^S~EsxJU>*53="|w`Y6;Rn<]ҝ[E,`54A4aI10o Ħ2D![dq \Tz7j'K)iQ{w)&j)b#DU(i}p.*Q.ِrơpt;y"K8n`t‹ܷї7L/PK>V7BObject 27/content.xmlRN06jZBnT:nk)}iZ.L|'_4D(9wP䰗)n HF^7 OՎ-Ҫ  yJ 'S' Qe5 ԻF;$nVdmbmE$_)-LP+>*>t_44EСLYW'l`/wgDUvxFy@΂zE-\(Gb.6(79 ~8'0Pw¢9L˥vR/N0~2pV|d;y'O)=F;CÏPK> \Object 27/settings.xmlQo0)Pݪ5*h hl:v &2HRF=!~?ghݮBV{!)Ӹ;5>sٌ!pu!A)=Dt.uۉH*=NB=ӼSQ}"@fB֬?wur/4M!imUԶkmG#7 ]Ԝyy#'}֑~ÐϝN8fʆEf~]E׍M#xC /\ D42:&< J|^0zDrtLۨC"g[>3;b о,dAm@ y$A r KS3M0rSD;aJ0b7HUNf)vcNq?PXgᔁ}QI&ގa5LM*#`j] IHV56U!{b5Jgb ׻cfPiҗc_w%]zUaKC }¸iF # r/} (> ܏m kwO"ɐ/yA1m%灾p+ hHW唟R- sͬ}$G2؀rx)}M-8e(OWEtdDѵ$K Xrj:mRL#l#ź!gYB9W>U9JZ><|JI9ZʦQJ4t'eQE2:"RN8XnB"9OQduǭ44i7/PK>B8Object 28/content.xmlRKn0#/+.TBRWeE{Ԟ(zΞPBBB͛O<)`=maJMM)\Amly(A0p~Ňqgi8LY4Iq]A6.)h{ۥWI85&`Kw3w¶UP( $GJ%iI=k8^!#䋃SsV_B.R{͝M.Q(FM6p;|p41}X^C}0y dKU-Q oJ"PK>\Object 28/settings.xmlMs0 !I2iHrZ$误1`;[=1>zwWW!yi\֝pqrչ~hlF}"kz:^Ă{H$'!HOFihoK/gTr\^]VnަC}3:?G!d&$G7ԶsM~Hw[@qA7c+kNּ<=dQHaNvMnv3e3 "p@UZ_mg<4Q8=nɃX_ctM&,X.P(87D=rtLۨC"g[>3ԆͲ{оı 6DUƄ*5"|ݽw`Y6;RntQd-ɈkuIAS  0tzۤ G7F p bS uICϐ-8r*뵫r{Tr M*iN<ˢdu8E6qhx%ݎD-r7 O0:_ݣܼ`PK>UObject 29/content.xmlu=n1b" b!Ab.TX ,Ğ`~D*g+eJ4c{鮩akBIVO u+ɖo1h\I]lyQ dhdw[,}̢mu١:go5,s5 u'Èà!GǧǗ=$ՌoPyPPK>8 b]Object 29/settings.xmlMs0 h24-3vI^@Y0&lb'[gj"dw"o9guǀiy=\;/ML^~W'CdMOK^Xp$)x:`ɓ̔<םSS]M'tz(*B LHY|wjk'BpiR|PMmظr4{0Dɚ=#0r7j7 iכal}e>.g,닫ٶ3U8|ݒ Jg,`)7㰜P:ŢK$< WHM7Ja8 bJy#.ڰqQ v+A:vx@ȱ ԐpGJ $22a^{pYOvFnȀp=!LBiBOF}[fIJ>(Vլr9eN{ñ>jbB63/*0iVe$Lʹ+"!XUa6U *dRFHwv7#b *m_zr뮤XW n"L=iV{U7~Q_wV?24}$9[Z>sRd6kwO"ɐa|[ Csۏ˺O@{s8Wa4{۫r}[ÖGUѹf־KDo}ӽVO9>&tC2C"YsK2Z]w,XF9F5 6)&M}XUb]Rƀ3dq,yJ@F%-j>%դB-eS QJ_5teQE22#PN8XnB"9Qduǭ4#4iw7PK>E#-<Object 1 |Ǖ&L2u6;^ޝf7A-YW ݍ,q!nIY@ c 6`qLlcc+d;ۉh~nYn[~矻նzlgW<_& iЋ^+! D>t[O )@*?A VH_o }ҿoB!H!@@o;o!}H ]H  }H )R XH )RDHI!@i"TH^Hi!)RU9|r!M)RBHE!@C ҝ Ci*iC.H3!͂Ti69B|H -bHK -TR @AZiZH d=% }huWsHτK <_{߼Cw8YOW?"v70ػ U`|Lӭ~=ۃ;e̚rQŷeϬ\\y[ʴY+6 4&ջfHχ1 ,W0bWgKOï)bfٷsWt~g´o<21dߵ}lO58CH9Ry9cf]Hk!yNV Wv>6'^C ^;b)SűG(y%ZnP 0}- '+q (jK.?8l [BSS^T}h`%k*}w=!yEv}NoY.h^.ɷ͊8T.bvZM,rRn]ĵGkLG AwwJesd-X:I '#wln Bvf{扬>">a%KK`RAڵqa.ek_O%ԟbEJ>06~߱nVfwa]2KiU R(h;Ԑ1iwi`'RI`ʲ +> ' 6ߚrֵ45[L'2X`uZLK&ߤI KW\<~SEGGÜļfuKˋ 9bK6K7F;sZY"EV{0_mE) QIA[oG7|%3~?*666>>955#;;쮙3+ϯZY[P_eMMvhk;t@ogS?~'Ο:u̙Ν?.\xyk/כvE?otZei .KP8r;2Zœ`goI2 </ ௠ _QQ1пrP2*hcSub/ݾ"_bu9i 9F)eI-Վ:JiǾ'rBENL 6j4Z&HShA 9҂:t] Κ5d޼yΝۻw)S,766SCо|y=T^< G0X@"@Qϯ%tvmVvcMJO^)y PaO%d^a/=<.[ig}R#stsZotTWS.=6VT SO@[]fڵkOٓCf? ܰaiaOS?~<**feffJJ**'O"<+7}zܹ",Z%KUU(+0a„ʃb>``-+G/ee^aoa"lL~^4.iGxa-ʺ(Zh 9ZE trFBzҥTP4q A"WwӾ~z:S \OLL,>~|B\\+Wc|l LogeLގ'i/}d}EU` ڍq˰$,ұ80N S/ԥSBE FN$T@Dw P)/g677378A355.x8xve}ݺuljKS4v Ô9]S}q` jڐ|v^ڡR{<6KUc 4TeZn1k床4 ^D3ݢ2J__nVVVWW$zGGG^^o:eɒ%[l9qDش̑>bvGvJ.|ya7WTf]-"9y#RP zA3EdEE;erljcD\\-Bٕ)|> 'jjjta~}D;>fa,XPgϱЮv*1\#ݻ 0O^)WM4MaS_(.eַ0veJE(6o :w\ÀpF(?OڡZh5 6ጥBGѮQP-R3%k{rҝ%c˙cigv\/5ڕ{Dj^1aB ̪U,M|*EX  /6"/011w…W3 H•(%tXqCrL`Fv9Ĥ x67dJ3EEEő#GLTN&W4C"x++{ƌ :t򡩩)//8⋿jhR]]CՋE4vD4igKan3)1t^1uWY23tC4.'n1fΜڊ5PQDUsc,eN;9'NGEE''@Ocx`3gΪHٳ TPș3WSꅅqvttՑv?Neu&cvhgRMrG-))1LzM6FUqTtƍ]X_ l{ *)^' o===))iutt4ܾtQΨaEbLc&hg]Ot Вv*n&2,Urhfjg@6Ǚtz|vǃGi46cvwt}D/)0@ 7 'U[&I. i´HFt'0aCgmLu:7|dK.u:06uT9|q6#gz~TcбNDz'ZZr}ܸP}X Q;%F#ƹt ')#@R~Y,YBi42ϦAITɳlr;z_erّ P@uC;}: z=Y{gѩBΝ;r9sTUd ]3EBB¡CO8v4O8ur ]$R\_ʹɫkU̥zکg3g.b]|Jgk٪RǂxG,I{ܹN1CQFƎOz3r;Ȅv^0E@Ɍs>]^>v>&ś\gZǡ] K9GV0"Q+Gt<[wȭ`$lkԚ-c) \>*-n'%Kvڥg2brRl޲۴XUu˱~%iN668|O=t,'?#/-EGWae/N|>ߤv}IE/Eπojj†Cc,<h(;z{᥅kI u3C8.]#)[4%SM\;welTkkig Gp,KC=? zw g֭x vwwFӧOpF8OڡOHHLI222׬Y`-ٿZ*thvTtk1'7nTfV"vؽ=9_  h낲e˖&BԶO+h ,(/8j*+5i,Jٙ4aĴLJHwt\Rդe u&d4-&걑m-lѓK"Qvm2\ղx3mEV3f̐BPR&]p;4Wi(~z7MG:uJ EťdffO>{WXmZY23|I-LT3f fR\?jR掺CLNaϜ<*zKكI "H9tiV{iQb? ॗ^Dm;a*,=~Ν;Gꩧ,G2 ]ol۶?hMӝW]]-`|irtfu*e* "!% ʼnYJ7.!i>,o}(>t2'^7]e{g;R0C]s &of"\xYL)dMJ$%ݴ,aa|];{-,5\I0 } { 3P{_"E,bX"' MW_-O3!<vг?<%/n< -O?훁^95E,bX"E,bn\*ñ( ?f1,2G"x©SG;:6חk~9@<1!]ZXxWYYHpOϝ]gfd+z"Ժw-tW"cbbR2RSKO? 6l]Qqc+&B ZqdרkԘk/}pר(nRdO'#7njǞ=vKh{x17ta1WU{_(/ONJ*lZR\Py 0.;,B:6F,_k0k QQZ+Nka]CC͢Evo_kKn QNֿ3zԨI^onVVYq=;,ƑR^~O@\cwmB-G~iM{Vx֞8t{ٳ7/e1#i&;rsji890`Ki#ھ(%ȯ$>_I>ȻwWͼީ֭1O)c,zs ѣ%%%V^SP`kYO֯_f͚3{VND] ))xۧ-ijC9L~_>RzC{L(G)ZޙgWVPHGJH$7بFZ&ۜ9s&CEr: ݅SO YKK˳K;yyy'NLOOz{{͚9ss]#=!9?u{LU?Rꩯw#ohRzy"4./6(gGߵ]$E:{8vd***E6rĉ|΁+ÇO9d֭3}2(۵kw'K;|2 _볳Θ?z+|hjj˛s]MjbSyݫ^*bT8!#Lhg}WwcQֳKNaw@E:tH:^[]] ZpժU ᦦdY;ԡC^:.-''g˗WLV6cƌhltOrBFzzWW@O+z멼Am#V39ϐ7klN1ae#֡(J K ܹs-sS w}v &cᖵי|1{mMG(r7!.yGU h8JrWӀ HCHw`Rɀ!`в[2PteeeJVvL޽ ?O,www6W/X۷ϙ=[};hV(%猪eNa):Pr5\ipL+e޷ݿˀ{*.@ɀOǎhGG,cɒ% ϻa[ 5ztyy_v|a𾹾T?ҵk{y86\C;;MJICҹ-ȻICc8DI4&2 ?L S777[xII?Of}ر k+7@tTԪ?ёU]]L4, (4txG 6[F+3p. (/ς*|KKH'34tR*T&|iInذXTT?H3pzbcbqqqPՕ+WN2×YoX7y&SN s`t282F? @gew6w^HNҁ'S}(ɦ͘FVNg3Mt(xp N#Gjڵk1~ *iatJ?**>nh=_כ6xIɂUUS&OzI`ϝ[5ڟ`EUԲ &@vAKתm 6 2w:Ri3p 2JX(+60lN |ȉ4s0QM6&? XKΆKikk[l;wLd`T;]znHk ARuCi#M6Cj߃ R i;7E~ ekfӉfN2J9A 09D - S;::= '''9Ϊݺu돃Mep$3kMz}>_~~~A௰ ՟Z牫=_yY8J_c ؤ@XiSql”VR.OS6r%hX%r|m 0NV%% |֠ka;а=tQT#S 1hd]V_8žjbŊ۶m{6.kرv׮Xr=m޻o--{޷kz~v.ɓ'n t g9NAEE\{݂~9nvUg0Sbl%bN\cuRe\Ζq҅n}? U~6 a`ShEu9pv\QFy{|ݛzi(qGJgl[ɖ=,K:i(Ήe xŜj/n|֩3a ٠F HC{tIrV&s*~\# iJKKW=رVZ"##cay=C,C-fk+{1̙CG~(T4,Cϖ]¨&|m@CΤŘgH.m[ȥ*v"Xp{̖€PS)N ΀M6 $|ooo\\i甔={ɰjVWWG}x?<݊FaٞnK"mlZ7lUmQB-Z!NyׂاQ{kHghþ]Xl&6 t'Z-hS3%gΜ\YYYl#9cd!?nu*+iϡ7ȶCt!Z@r 9\iZVH%N OGZ}VP[C۠Id4,LVKT71vs׉TSDˍP3-z\;Z(GR#"]F=FҀa ukg=b6`wFlBMYEMfyz/^H4!dQSN'R+QdOt 5]:te.hm.Gg5g@bwmHL,ɖU¤ro? >..)11%9yBJJĉ E233233s}ٓ|܂I J EE7ds/::] .-,,/F7Uڜc U s0f޵FkkwnTNzj =xln—] =$ CvRM>xJI¤f\ᇒk5a̛K-p4+P#L3 t)WȮX͠&˓UFg6Kձum?M{:@Rѥ_sb 8Gb U̙i»ִo6ڀF[Kb/j1fZ-X>0}.,Kf)u,D7#U5;!aK? QaE2"IJ&b~o67DŽg!};3=jYf,VvdiSd@Q뾵Xuǻ{_D8I~ZYm?Q0UYc5 -Gõr-2T1cn0v_`;0e mDZHҝʞ޵i)} 3Z%!?슮NHXjc}$ } nVBqS&L IďMǘr`Krcv"> \2'C*/cL =ñ#<_$y*Ş<)yK-gpmO|Lӭ~=ۺss &&OggzÚ٣=O1So}#~r\IZD?S$x2p 9. ?3 y17r?x OR^?ͫ'!|m9|Ȱܜ3xCG] PK>I8vObject 2] tUN'$@H"! @EuG ``u (xF#+ZDGQ}`=AꮄVGVQ/}o+ޡ$GMb1':uqmmy08\.w]%v莰\.WU" fW!<\  >Nw)v;D&!O+i-Ԛ: xɳmNdwPf(h.XMS!}҉cZi1w5ؖ@5L|ґ?%L5_K;L;9'IayjNses rM-M [#Մr 4_M%|]5}֕ ҧ]xCmQ+,\JATӅjxP)=}P LA-t Q$,]i> Ԉp4 ˜(ǝw 'E1{?(/eTFת/{+O^Lc=!N.-v}_ }' ` yo/1Ę-7G9{"4d[dF}rzSW^wit={|zHjn.Qq BYHDp-u :< u8E.K?/!^ oW x3W鋷]]=cXԂ4Pc>\|PK@ 2nv? ܅zjz 2Fpq:#J_Յtg&(iinb=tC(bmMg-̓.^[AoJy1APk}V]:)zH%G O~2KTD N BPBT)\[H.N ul9<{"lG #z/kA.S7ntIGC}RG${Tlq%nJ!壮:);P,kG,N}x{ x 7:"Yc9)} ţ^6. ᶸnj G)*5>q4^M#N Z;׀Ox @=D1;-ňy_ëI0&'WzG-)z< 7uɈ1{0W(^*`|р|: w0|0(Qƈp^F: ⴙk۾P8m&pTcV@!UVQ]:R.xנ605 ^Mn$jx fՀc`VCtR]c:um5F[xݞ$1jUL8h>96$|;~PKpi3 Knsplu*B.?Ob=8!EВ>ke3}JzeJR3'Wv$=˰ԠYىT1еe_+϶<<(&"⧠JE9J5BkTVs)Fr)ސ41μ9%BqK%@[E95ƬnW "wXgmCK?g IC_M[zА˃>GDT4x=rU(p+9wru$e&Mtx, +|R=K@<~9q D}CtihSàKtu?k<#&9tX0zanQ\5V/N]1ovE=cCxrjB:*²LL'0EX2*"yyg%W?BH:ᣳzĽ J_bdߒ-|r|)-]tܤ+w++?Ə,m+V(m=T&v1[_tN$B._blga:)};%=/ϫӟ@wGqrIMvo![2o6RYJUP%BqoK}^5ju7s7I}v!C}dq_O0n?/-ME[RYI<>:j}SKZ]nY]O59Zc'u}F [s(G9Qr(G9QruPg{:۰vAN_Dz__QkI\\=~}|>{H?INzK}=L:czm3fN. >:y?]x\9QXY62*̼Үy[ġs(G9Qr(G9ORP~ÿy _R ~e^Y FK7gGawXjTJ h.ZB[|~Gy[XF+`y̨Ėof Mо6le+?| ̦z՗e'@sj%k,k/*|IJ˿A,K{MWB/}*%g_e__g c99PK>^>?k*Object 3} |Ep]U!0r!NH.B&ADSQPY@b *UW{z&\@"ߺ]W=^^ =K?#_'W]D(@C!K#g;忪pP\L l (P @8@YrnP 2@nP&@-u !@#4)@3;0 .h 7B}@,@; 3@ wԽ {>   0{~0 `)zn @29<Q},rQd1=2iJǣ«~͋'OSor=F?_cǒSx eejׂv 8|`Jrj4OAt['ĥDG66epTSc\?_`7 2" wš/az>@:g3@Xj h_uiquq-(XüWpNVfub,NS]L#`JX045D~G򣐧F=/O#m>,/Oy ˧11l>#>I.+g_\M7g>تDo{fU.'N0f^g^w)fJ2 3x:xوw?EGP0Pw Bܒ VtpnM56zS6So&S,cNYDR-4c<#/YxlsE<|ď"^x!E#~ K/C㕈GU!vQhD w{6دKVR#>?aAi`OI;x x y +b7R8q^I"nt\҂oEIKV\W7)i\GHR#ec;B/+o*dDt,{İ(Rzu~uΊO 2c6,yn_ 7k07dIz*/@8OS0~5*ѧAo=^YgCH))<># ^1R>A)"3CtR҈e7H)#^) ^v_NCtjH 㠥#xZ# ⶈA; xĝwZwCChyz -}{ }U_CH$ēN+ӑ>uL3> 3B<sQy|lB/ 'hW|],9I$zJ?Xƛ~nSd v2^KpC|!w_+']փp^!2Pk?z$h;7A:ZRޝ->ooL'ZkS>|IgkHDxe@ HWHMI'H HWHMIg呎t-p+H'lAdWj) #2PB(EV,l*ѱe/CBw\NR}PU"nDAULR|!Ż+/zIBIRb+c ͈RY~9>vv1,4co.AQ= mGuۣ67mEXn{UXD2O>'g> _*GydiY#+(|It t#4#O|ҍDl' _++ +D$"xE%h~k_W34hq-gLϡ/&j缾uvtIIe7F E~d2סw!~OƘ3& xYG~8AY o>AU儳;5JC$|5!c4.Eނ@xbc`OyV(~zRj;1!U@ʑ,.籗V׀FvAxŦ(9)Nrkv2eJh4DNAܵ7طVNp٥ hAZ{SSEOz%'!V&O }8#w_QTb6~2(t>0%95yHG֋}]eD?Im&=u|jQI|NHGmN u_2_f1JF}kĬ? ENv?azlhrsZeIS4kzphrFro< JicWM!Yech7TNtZ "TD E#Dne* h,ͺȞy8&ۉ'ˈ)t{_$OY9r2W#ɯ0%(DFP2R1>puw.|2O7YG3x=W3㹀 Z1N}iV!imJ/[^A4VAyaqoB/.;6vdk.hy>6UiG~t`V +N//bP'^ǘ @iH{miEe~/vL$I[`4B&:Gt:IGuN̡osՋ4]%U/]u&^I4].AfՕ~./ W{TA3If`-H?zeJA2k.R'Y|}(IeO4@edk6Aaܕ&'ӱ~Atl@JQHW9yly_f/|5ZNbBKpT#h/Um#͒q}M.s#]$_~: 'Id)MVa{dvR6gVW`Ʃ l6@oCY0-XYp%'҉ ͐ ]-fY6Ex&G*fAҢ֏Q5'I  XmYuIu] *{Sc/lVql&{Xu,6t %CtHhlQR A..T^"O˯f!)s,% RU="e.ѲtnhM}(DquѴzvH ADj@ZFu?!C}S.Z5).;QSt@HWe$/UWh {n,DCu_QQpJ݄:a߃@G87C7}XgV {O`;eYc" L}&>+gӹ J<;,# onU5F@{lGPߋ#0H{HQ`魞=>#~6pl 8d"y&d)9B@ [c-z3L& _CMx%KA%r{ V>fOf{'yoY`lQ0ļY:wD$:uAu`u!Ir;h \7F+ ? H`3 לWIww9}^vv e+}.'+Z%NXśVf뭁 X`Ӭb/FXD_+N|nƉ#f'Lϛ 1#Ib@$kEqyX2M&Kdyv\6f99YL6;fCY^.7\c~'^0Oͽ".ψScKs/5ZZd*b5CVGbt8'6XW@M.'[S Yy:(?.3V=ʵonnuE0r? };@߻A߆oUз;KrĽU|kZSn+`2xX :/f{{н  ^Ѷ&cf1ż_191q0mn6 DIq\!]YQU7+:Paf=x @*d9L!*AT.|RGf|l~osd|D(Pa0kj%"nhB?F[#E+aݚ#YCv1zW,)\ WL~aqӓӓV: S7PwG(5S>vB;|נMFWXdSRwhz;P|籺>=DOkbYf8gN,\ 3f)3b- 5mǃGHs:}:@dݜ aJu~5gm2Wf_.> ׳MS(y\3=0=ƛq9 gAfi vafk%@빢&~j $_fc6_k8iZd,guΡhMAr5QȡaḯYmbkkZ([{ܫr#ʡ-2ŽMuoȡp$ߑoʂ71VR=k7~4X-uALr]g\nHOavI yϙe@v $F,sU,>z8$F@O r3Jlq0s4;jDȃFeo9g(ƨ*d=^"keE#QV1ϡ3aOEL}*aQN}>CrnE+l4o 1a1 > h)4|'ҷ~t9t+DZWGD/цM:Xqlo_UbT0kʱxU7upՄjnl.}^jz-r5 /UP53U+>Au#@Kj*P1q\$3ȂTVij 멶U&蘝Q'@9KP߳WGu[ k`n]~UY%o.>W8K]=}p)P xS+SS`ee=p*%?C)|oI-zGeLO=Ǩa<]=|j—AixI'!WA\>~T 8fx6Ex $UuxG64ݪ( SPw<}[+` o8ʄ1*-0^GzpN "Oؘd0> rne*^'*V;˭`-9Kf"l6?i~t h\Gt&z3 tI{A}V}-ƃT˖kM?ׄte\󙓖G :`tcWR3' İۈ~9aTj$O 0'uaa NNi |5%e&G8&I ȹPQs.zr,բCzҒ=iR OK".JPE'J @x{_dҖASDyJU~5/=jg1]AkBI% z^ik6pC=G c庤設[h#H [A;_ݪ/\A~ǎA[zZ/A[jEX.\Mԯ}q,7B zu5˵u2,W%䏘pT'ЖKI92֋>//Jk@|( یf_߹19N CuPFhl?06f ӵ7,׿`,sS<"e?-$GHV6~(+ I#Βu$ #(BG1oyQǾ2q{t˹B0?GhJלaw}# u^h?'{dzjPN,Kx?L/Iīl+i}寿7ҏϹ||M?=U]<C 9SϧO7T']ߡ:ڒx$>>?]^xzn7'_ڂ_3rJ_ %j GI@``af޵;00O\rjp@_~˼kO+s%emW'Fź1 !pG Q 06~9 o ɏ~?8jji5[ f+i)G鰺aҖw<[vUrk*[~pxpQuoBH-{X9=<+^Gӟ/(ԩޝ$‰Pgbv སLR\^{ S{'CeKP~ YS kZcQFF JN#FEz8,*ZC܂ǓݦwۯovS8)NqS8f_uKca_Mznaޗ!~_@}}@п^Cb~$"~$^m5E\z]遼nq+ !mbwU axZNqS8)NqSǓI6d4)xa?;;+}/a}mampYS҉$K&< 0_U|h@Tbb=MU} !(v_~{mQ_HOGZ%_+~ _G5N-q rx#8xSPw"ƿ/ѿrF hBP$c^VrRۿY{i} ]W=A RpKMoV1O}z׿3;3PK>(&$Object 4/content.xmlmN0w䁍!ž4-QwV&7I(ҝ}n6`ir@ʽ&gSyU4 W@ w]twKN&9rg&eTAwɀZ(M5(o(`Um#z7;#feF6K7jlꠙ?7ϯ$sF6O0D*jdoeC0cMIJ4a\Kuhʶ_sKޛ= ~LEO6LJ6PK>s+q\Object 4/settings.xmlMs0 !I2iHrZ$误1`;[=1>VW!yi\֝pqrչ~hlF}"kz:^Ă{H$'!HOFihoK/gTr\^]VnަC}3:?G!d&$l`z|wj['BtiR|\PMmظq4{Eɚ'='L0r7j7 `l}Zdn6Zr/m;Y-y ts tό p\e"5<6*ᐈ9ٖLXj 85aP"*PceIP*aȄT{em! hAv)"0 }Em1bm$*yXUe; !4 p$vVoǰvYj05Ӯ`U$VE$vЪ=J%31킈Z3}˱c7/UaKC }¸F # r/} (> mkwG"ɐOyA1m%灾p>WАm)?#9% X/Object 5-U<0ADB.0P DJQ+ҥ->F3{5֞=ss̬vfιrsv-fkf뚭fimޚ'665MqGC =z<PCK]1O| (t1%K..6жХ@Cvvv.]tEJЕ@Wv]tMZе@ׅ]+tCFЍ@C7n|zn 5thohh_h?hCw -@w +t7P={B /t?aBG@GBGAGC@BNNNNNNNN΀ =:z(0#GB!i4Z?6;}Y繟/l?7]ﺬMm6/\nHǺzVkҍNM=V(6:6g[h2BLޑq_Lc X9C&j#K2u}zUgc:[˻xy!on#\=s'ِ#Wp2 }Q} Ys/@_]]} Ukסo@߄}]{@?~ Sgϡ_@~ [w?@ Woߡ@_Af;mhSh 9th hKh+hkŠC. ] 4th{ЎNCW] 2t.ՠC׀ ] 6tC7vvn1thw͠=Cn 5thohh_h?hCw -@w +t7P={B /t?aBG@GBGAGC@BNNNNNNNN΀ =:z(0#GB =z,8'BO =z*43gBς =z.< B/^ z)2+WB΂Ά^ z-:7BoBozv9й;wAz~A>}:q'OA>}y /A@B_}u7oA߆}}A?~s/_A~{?Aw?A?:f6@AC. ] 8t ХmmKCA. ]thWh7ЍC7vn 9t Э=[C{An :=tЁAt']Bw't/}B=z tt$tt4t t, 8xD$dT4t C3B=z$(cB=z"$SBO=z&,sBσz!"KB/^z%*,lkB^z#&h-f-[Ao zn={A>}a#GA>}i3gA}tt!e+WA_}m;wA߇~c'OA?~k7oAg/_Ao?h?) %5tQbšK@.mm ] =tYhhGh'r+@W ] tUhjաk@ׄ]t]z@BA7n ;tSf͡[@n  7/?t[v;@w;A@wt(tw={At0p##ccAAC'@'B'A'C@BACg@ =zp#GA=zx 'AO=zt3gAφ=z| A/^zr+WAgAgC^zz 7Ak7Co z;\лwC z?ЇC> } 8 |ЧOC> }<З /C_ } : зoC߁ =KH/:K$T6L{2-8*!d^|ZT2!"xI#]CTMҴBBYSYȝvp*JŤ2~iфߗZ+T`-,t_3gQG/jXԂ #?{OfDi?f$%qU^24L/1o)îK/ ^R(^@հkx`AF xzIBqU^R" l)4OA/)G/jXvbCޗPv@s_ )=T*rW]*Jd4K^Ÿ2?(UO2l^b;7g)楢TL漤dnl K ƧL2x/q_խ8GkzI+cE/QP5jd}ix<[>V^G/jX%LCV sY$zI8zUêF֏O/ds*ytqނtBm|J/ ^R(^@հ󒱦q9K5^PaU#ǧ ^?"݂neW(~I8zUêF֏O/ nfuZ jݻKP5jdm KinA\"&BqUd^2 '(%3m0w;}%K V5~r^nTpCAv[4]19OaTͣc*KP5jd O%!biV^PaU#g.`0=v3"nW͕@/ ^R(^NXCZ0/Iuv[sK cp:`Z"PQ*&+cE/>ҟ5Xldx[)#̧Y<]=ZX>$9eI ^[+rJT:*2$9Wнjf=gpoV[ڦU bzE9n%.\^B/qԲ0W }эӗil}c$ Kz^P5jdr-Y_G+i4jmu޸K:(zI8zUêFYpcA§yg;Xo'fl:oP5lcL+OtA <hґ\^"dk8}LFK%r @ 4//o1gGl8h걳j'W{$.NGqCS* [Cimس,z3kF% y+[ZK|S x{`g$u@G#y-LjaI3y/)QJJWW;^6Sj7{4Dlڤ;=ւ~ԫT@- Hܺ);o&DVݑEKF}NqkK Ou2;AѢ$%/WEĕIt^ZWT0Fxɀ%\^2I/ ZxY2L#KOAGc^afrEunV|ܺI\#G^孝Rt4걧k4dYJS.bF{\#hS?V#HKt+ /{%%ዧgZw&a$ ^pr]%o21B| snfFT%#q&|uO/Qy2PeGii8CQIC/K}PJ^bcK42iGZ^/62YJ}\CT Y?~!/Yuyx ϩ4607P&c$LO䍤Kb*%\e| /yIL%q-% q#i%K2q7hK2^2H_l-uŸTU7TF9/] q4Ni]UFKMBSYZD\OT%=ʛFel :22@/Y^6*/ITJYUe$tRK5-s$F^72aDYtñ3A&A v yI=Klt+N#{4VNmH1x JjKF%Ig*I, cx^qÑ1۝4?zI8rS1ޛ<5/ʞFzhT="+SF/Iz_:U\6+""綄h4DN5;ѧ3#he % qd/ bSy3/iDDEyddc)Ii;YѮY%[y4}>zI8YHFU|^w.͛F+TV|T=Bq[m42m^Qڷw4 B1xpU~^+!R1n/ѾLc؀a븙P;!ϟ$M&A*ӬUJ'k'WK˯ eKFK긓X&`!>>/MՋitWF+cTuk:TJe+&K/!TV*TK(%4 bYΣ%44e/IB&Dd^4 BȨ7ThTK"LbS!,Ru K:>5R-UW:a BYj8% ! HEso$!fA^2tz#!~X !B/! BH*{ ?T'RK!~jBVjB!K!B/! BH*B!K!Rw !~jB+5BJM/!RK!~X !2[v9B7d: B!#^B!$z !T%BRBI^B!$z !T%BRBI^B!$z !T%BRBI^B!$z !T%BRBI^B!$z !T%BRBI^B!$z !T%BRBI^B!$z !T%BRBI^B!$z !T%BRBI^B!$z !c6 !sKRN/m$ Ex).ʤa=(v;;bΑg;zvSbFz S%uKšpe'hȇt= WYm4HS2 h4/s߮ʺED9@&LN/vK\ӐK 󸌗t|³ܛbuX?_29K̀xɀi H/f fhħ]WXc҉r2a^"RDǕTS)KSKO=#xuu>g=-f3 K#]RY_ծXu%jƨӛLPB"4`K^ z !Ys5|)( }"gLpâGawnP9覛ZwB!K!B/! QHmKR=^5[vlTmbiX˛rPj++uOzvSbFN'R1YUׁ$v)|FyXXG8A;륡4\` SMZ3~ͻ|HeMXH [I 2 KOzX %V|*'F%!i9K|b,K̍8;M>ǝ{+D8vuzI'<˽.Ӷ"k@ʤJzϊ?E+uS:y,YÖICآp5Z9 pYi]>qzkӵ62.KUOg?,uH>/9Dsg4)S)^bhuXXMHbFv %/iWf̢l=0ĉpHy>{JZ^42Wd!iUm3uIkd"ԆTBbz./qJd1xgK05qKjZ($8Vs]<=7G25`#yLo%e%_ !B/! BH*Br27 I^BHN%du"}W17j٨2Ұ&V !FӺ(l1ג 3. 1chMR>#g5Kښa!>sgSAzBQ9hg4A}tuUpFז^CdXWv[d!Kw½;WX=;q|* d2^"4-g𡼤q,=rU-Cv/17 )NF%ͪWLzIF+OHh ^bM5u1YQy2 M{Ip[g4S#/t4-pEhCV5+tf.󁜹ڎxtQt(aB]1g<"DTK-W=81h%֧qVc+K[ J^ҸGY{-NqtD^o' !Dh@2qDAr*ryIkf<-wYړOLj뵕_zxL [}zI8gJl=ѡ%"Hh Thsݳ !B/! BH*BrRڄh@/!$':qNp b>k9"F]de0RmTSٻTztyO½]bZК=|F'R1k(^Q>sgSA_ݓ{JԺu\'aPd4+ȇ6D"b"x:° %غ%8qA~P%aK|-%Bޥ:|(/i}4K\UːK̍wʳ zRsv %71@zIJzI'|c?kѭϊIhOKBq90Bsĕ ^b`뚦y:7Ck&f+ 󁜹żocu(:0Kڵi&dқX"n4&%֧җ1%֭Z%/ilB!F,AEk툼:OtKw nckqUh#Hο|Dk09ge9 GKq/MF(̦0}|6D+I k_"v@ O>Jxj} !B/! BH*BGA/!oGY|>0z̅_QJL@\& !F9KųNF=)l1#g\z'R1uk[Nu[;b=e!\sl])zi4-GWXWogyw4!y׃^b"a@lݒ,j 9鴽Cx)$Oz-^"]*횡[La0e^Qz)OzKh<tU\%, WdW&PK|V0)K^g/q%6Xˇ|)!ohwU fhħ]WX.I'km]zk;.B#.~ %֗-z7zIXzFHF>g5!a*P}?^8:"AF]}-y uYJdm˧eykd"ԆTE./'8LGm?.SY\[@3!7TY;}bz^Z%፫*e0e:U[(Npr-ƑyʴK#%^{f50,nP9f3cz+)DLVՊH$;!T%BRBIeKek=UinGo(7{5tJN^4O^2d,9)9=u/Y#t¶C- 9iLv}4-%fЁF=)l1#c7O{_vֵʺγ,iknAkɚ\Ή /9i})F%ṳF ۉJ5z0ݣNJc";V?zpc]ɴON:[\1;̧/_y7G~>cC7F8AK-GWX.ocsӛLP-(}>ыvTi15/YX\\iT2>h>5>62k?Z )/*?3KzIX|2(r4* 5c3률WƵaLY]q?y[4ű~SoM/SJ#\{Lc4V2pk9)9=z > z~%̞B!K!%BH4+%kY1xd̀\fϡN M/=`QJz 85oj@%LcV2ӆ^B/I!f3E:[\G/9Z$+g.I1sXi&q[ ]x5{mf>PNձdy*;4+9ia/ * 4z=WF%>*4zuR,*5ӐKL12uK7;rѥ?{JI/^"OFKnɞFst=Yv)qQ2TlY4iJI/ҨK9+e=ۇt6jpƦSNDS)酒KZ/wϭiXdOCX ^z7_uX~܀(] 13v*%PKF{5NJi$6FF}6wn5㦻zuI,izsyt' Object 6}|UE{_ICBxCGPP\]P*$"(ȢX髻~TtY bu{Yؑ|gnKbX733g̝v}k GYCR\D89S#*@{Os3.]5UWL$P׹ @HP 촃Ձ@M$d@G#v#1h 4;[@-# jτtvM7 G wd.#Y$'=a#342L'ŻRM-Zay4$Nけd4|&}D+O%ZHEyI5I}XSkf]ڈ 6-6hlWo=9iBqY9YsCeeCg8k(ԁ̞ڑ怟Kϛ*ɨ’HvBg n.I$#1}WL9@.AhE 6Ph"zNEj@oJb^t%qXO~%TҙѠ2@U"ͅ QH1Y)*B+f@XBNSO" ԇPoks[#3W$n-RtYnˋ&AIZCKꑦ8pE# W;Qjv*j,Z0:FX4TQ %t$f)1;Z1M44igL+ӇfјfWnC}Sp/ Be1Ú0cLΕڑHA̓{XW cs:뿞g!91,t$0 tpfCqfkHllllSQxv>ᦴ_0xo2h>Wi/43:vIxBgz0R`9p3^GjDցL+ /AAV gguW-S=;|~? Lvה7I@|k|%1+xθG7}jUwv)/ 106Mq-mJ͕+wDUE ҫW#KQI3K#PAz'ssqfvV +%^Kq%E:!͌lZɯQDMxE. dU_nUo .*Lr7o5_#Wv L`CXEcqIZD(İm5P+L/)^BWz5j9z:zl5=C㭝"[jN$#fuxZhIzm۶+oicZS-R[.Z S5&߾RXrYrPʡQ rh$T24jC# rhĆi4C# P94eh-F zQ24CÌak3K4̒4Ui8wIҌ#%{FzaJv /8ʋIT6)66Yrk(5DzDFȱJT"RkJNKN0zlԓV\+VM%ՙm38ۛz9+2ox it˽O!y>z4BhO$rkH/nd3Gi,W~֪7!>BQtBt;̣7ǻ>z9p\OLC!4y^t/Ew0N殏㞇`(㞏Aۡ3aυp}t UѽUU%T(ؓǖ87|wz 3 GQf8QR¾+Q=#?/C%(TE {J8;zѳq > cJ4BTG[@ gyn^( {_+ãzЫ9=}%CY_hlX.Bx9/PcwBvWszE I=;+kvރPz>z~ !W z?`%J ](^靇C%=lˠ8G귂'ѻ) Ƿ"KpOǺ boKr+j[zK,,,Jx\=`~IO2"lg $tUqcZ='+^KXW+^C4cXpʈq"n+;A U:q- /)~OX?#~_߸(EȇF5WLCߨ  ~ttDtRQ+Z1%e-x xRRQEm^Im^qjp̈́bT?Y4[ 'uu; ?mƬv4WZzD۬z4W tr5E͚Eu$ zXjB2.αFUd;AʾKzCfNF]!D\vVy.UmCUTWk* Pf(ΓOXMS7Xkhb<`n4a<~q6w:c7ְ|#}mLxff2i^łx3ds0kd̶?l̲̖lٌ <~Y0Cy/'{z<ߘGw紅ﴩ9{v=M}=~:Ʒ[Mo-}G|KnB7_eYG3A_ߋV=m㿘Nס5<~?Хx;go?#?o/|kA B[=~`.2$\H. $+<I L'S)d_`"y60#+H`gl MI`klAS<>-Hz>Ⱥ[!8I%S~)pzw^n6+-;y]t,kf ]CpEXgy )ir2[M6ɘ͚Ҏ\?7eb ,s?/^ v Ľos"-97鼗G.|'d]~X'eET')akAzUOnz6ZjXҌl&S|#j`^;{h~41ӬjXWWGSs}io]黂>E?AmBB $u}d=?w 7?.e>%R} 6gJ9sU3IM<1&4vQPEvR6c_쨜ޖk+1|gؽE^l>I>;c&""AbT܁Y{bU$yH#d;Z 35MF~Z|kJ&O1``c1?5Ÿ:[ogOgUade~&V\Zf:bgZL h;gcߡ}6߽oeXOc0Ns}8}A1.Sq宫]E>coҚ|.5Me=D,7QE4}Oh_"a\mD m(5p?l+Z/u8ֈj -V772Z.JfpJz{,>!+>Š#Q¯&!aƊ . ~Ib)(jDNya8%W SlU{Ɔ^-QTVHޡJTC^& κF~PĊ)90kд̜桩Y2s'erʙ0.wriARHP`;rk>_z³+]+w/#wr7n㛇2ΚSͲ2YIzXSTw՝|X095rBV5rNP쉙&?c9i(hR>9ֈDRFcs=J^}Fc3H_r,;} z>wr%_(χv:|hfAmy~mŊiq>f <?SyB-|C?VMhejߎ O߾aDq?96pd8UWR;HdpW N|޳xN7Q"C?DRiOImx(-l! #?J?[  dpG{=/,<ͷ珓|;p%g(/|ybӐ:h"6o 'i*tjqD%ԝddj|\\U@nP.Q>zסU]GzO1Mf]>}YzTG<z~ާՇsT菪bb1fՍ,YǏc ܸ1f<~_YǿF Cydg$F=~ѐ/2JnMЂ ?NrX"?fv?WsކP:lIfsHU'd=$S|~9?5Lr$[y| . UefZ?4.4%O">z[KG#nOrtqoM,(˄wh[, ~ 5nz|䴣M$ݳT' ^{ $Eu~L_o< ]0~ZqG/Q본7abbʱSK-911Ĥ̎9몈7~D3R`3&|G ;Q{0M3ҫݛ~ `IɁ 3>DLf4a_+vkxk1z ֿ3g_g)j8֜^}{VR/Wz V?TBj&jf"i [Gl^cfvѫ jW{L/*{O$B'o{E_ ?EeWPx;jdҨxjoN #'^Opu&[8 +{ZY$<޴d<:︄:r~֯YM+A}Ù5͝tݽvDMDMDMDMDMDMD0g^=!51~X7i^5{^c}/ M^_?@kN^b;ڇHuwn[ nr.MWJ %;'0trnO:j&j&j&j&j&j&je"$DzY_߼طDIoFc՝5%d3~:߮,˸o &CI&{yuH_?#>MoN#3Pcɔ _I_T }];I٦/+.+Q#ҍG/38S)9Object 7xeخgٙ H@ ޛ{ Ei;$"cE"`7AA( ^9N \yfwggwgٷ7VgEJTt?~${ >9!ujPy \ p8aY2@CF! dlC  rB.ܐ"!/P B!( E(PJB)( e,Ps/}ٗ]q2u=ͿmUj晵D4ǻͳO'd7{`w~0|,d:c0u{qX/㏽88r:5jٲjut5a1ѱ[Dt4lfnֈy)1D?krҟ׼{ 4Or/$uwࡐ6M-$ڹFq]638󦡤l7xU%B+滌gU.bnW꒺.K꒺.K꒺.K꒺.KGuԓOVIR+ 2)5?׆kYH8 Pb!>C j p\clRs3\"Ko#ZtuVُ~R¬=N  RS)-O*u޼B[y +`;3d) fȒ AOʒٞYS#S#[ sx sdOa0G} s0GS#49Ÿa)̑)9S#)̑+9SR90G0Gd s~ sMfǺH5)?5h2!^S'*R|w_ T=!M23xwRPo f(a3Kq>s)RSǑ<9趜v7g*xkȉ rs`bH>{ǼjF Xy8:e=vj| 1TPUXWvjY8Ǵ:_Nsk$,>[k?*VAZ;WNvoݪ1[SɰjNב5˩hߞPoPխ(yoiKݺG;ĪL9'i:cf;,'u)㰻>cj>29> )u#tޱ%P#^g]FI$VFޏj=c~88Ub#q h֣n9Žg 7!o{PBITV~7)WS>\& %뢿YWO+/3A0yVRPE561*=Ⱦ IyNb^wx~N+@6UݯJY Ⱦo͗ڙePUW>RsoȺ)Q?_>١9e& 7j& _=v*U淾 QTj4)i^1ɼH/铲HC?}{aUE=R$>T9m"SH~q%V+|:3d,O(U {ި}:X-`O-kg2)>n6f/濒 L[ZwzבN5ZqUw[VggR&a[BrjcH-FO/Fkbf%nV؝RU23$mƣoȭM5҉:FZH_=ea{=ʪ4@Qm |n.Zw%G Gz@*-\{d{A.uew{!}"Qn١}{{?|ccj3tY)ߔ{?7㌶QV;KYIM;Qǘ聒*Ig\5 gf:EDŽ?ߠaxTǾ]{dž}$." ߅Y\A~VM z2קl\x{޷k=zۜ/35k:>DzjJsYYѼ8aף+>#s+_5g!38f8{'7v8rr_9?ci. k#%Rѝo+*Geo:QLr:R:SU{0Gm3zW'_?=Jǫ9Gݳo\lqsZH:?ï>\J w":~Vܳu_=ʪyyS"]$\󎐚lQF+kɟixyA[ ǃXV(3\ExCuX7^('}2C"n'Κ{QE"RO73{'=g8WL|ɛ»Trxn =-1Dw+h^Qz$#|b_ W +_9PJ-EM)jKF\&T0F7'ӎl;jډ 0m$e1MT}a&MMěaٱԌv6u}x[ [B& x~2ɮf5;h3f;. {,}xe{&;xoNcpG;*f%ᆘ sfͶiTPy0BExP#= !KY^oݯ8z1(JV m9rZ Uz}e% m)R_kVZmAM j[(k_R61 qz1c{-vGH2#f ۟}> އ9l>},}D#>R6mJVN([omۛ6mB??jPm+VSಲClmloEۂOR x#{{.؍oYݯgz6u=m._򒍤&ڼ~ԫ?UTW5ԃ#?ok"EMz;R_G=E;w P "?I_~_WOo[o)_N❴-B_ ';WϠz^6fx i>n٥^`"%Ki~P~V ؾvM^:?»:o!9o w r 'FM6wFTt&蕜{p;zEׯ^}u֥.uS6;٩]itś0|82dc6֩x1əƘ S`3tmM~sg0,򳨛L/X 66' SgH--^Zvm̈ /3q~_YS,Lh~Wѯe2^3;@ 1 -nha !-;^v_vlBMjh"rZ΃g\nK4-2]s^4œM+uуwQXq)ە/|}}Zu_yϫuRG_c%jkGưW+k ݖp@ܑzW{V':&klc⺾\sM+ Wu+ҾUruy+ alMh]UK}Q=cS:h }m!gF!t]uUg2U9rN=GQoTLjx{t=ݣmEݷwde WÓۣ0a+ |̫=t4HS]w9.MJԿA3~O쾣vkjmw"{L._Ӄ(&4z7Q.{^qOdZƺ2@(Q?=ͤ;$NGL zN蝞=d>q[ϧ qvt_ПSw>d;v?IHmx:Ͽ.w1aW<\ Ma@3YO߁frS8d6cܪI_jy{[dtOG"ɞ} aE b*{lg&)BD#?#Cc~z,Z#8>=Ay!Q+glb >=R,E3ـrV"*s"_ӧM%>=R2ySrA^QWr؊U p %HP>5X*{|z&FkEX!m=QE|*B5θz QSWhM ~(QEQD|%>y }F/~rɿH}P7`L I oK;o{-F[ adPڅb3Wf5}q6Dh`/Cb=T}+[D<߉sϡ?G,xvn$w nRKl*2(9m6Q [;o~yrC~.r9.KTgYe' m+_cƍ!^2֧ xE7e=v.؉oo0O?5^LUi0f0~u䦓F<`.!3jP;W9T9(>ʏs_9?_]h;avron;;Cx)0w'q3dN:_'5r_*G41AzTWaB;w8 BBȄ &P8qQVYPA=E;wW.ԁdjEMmj'~_E' ]wA߅\gCxL?yobzZLb )S𧐛L~F{fG]R3xgjX?'?'d7P|m-ߑ}G,YqB=/~zN+/N:_+/%d.HEj/.yIp^lC;oˎ B2Yf& YΫ$Ҍˠ/MDաjdQSkxE[h/ۓkG-E>&ߛq!8o0ySg<o܃p6-pΒ'OYj9%ӡ(Ms B vO]_fL &ڌP2iRXs*E*G/_\QEׯ ڳ ~erW2h %t56xmȴ&ۊ 'N;us)#e$42m4kFI_xL';QjeVhih+W[N~u~_}F2nf#kx A8?1>~'r3p~'ߨZ^eR$=3* Aң2@tҒOK]:xzVԳ(+Dق_Jh~yrȗ<lxٔfz9<!d,h21 ]:D5(a0x9 ;Z6vhS`2L"3$j&Q;Y3#7+3=zۡh!x9~}`=dS z^ne|<?~߃)_N?IIUn;pWϧc|>{dRs|py y!G+W@mR@$5 *%I>u~exȔ$[RԖ6 VEM"P AAx~:@{hG-ٶԴQ QBa!CL~uOM0XcGx$^)eQF B /$|m_Cn5ԭ~Q(=F9e/x{%`4q8QG;J1^/rnMr Mr7_OwU4p)QAn;ma|~;D ك'WCWc*\?]!4hw}E wEr7Fl7Fkdw7Ur@2E%B>u~E C!(H^sy&r?f\~mr_hs5'ߜ?nBnDC?wK%1x1d^"ۏh6^Fna Uwk;.nBwϤo)C%d]Bj?tkqu㛬#>+!dJHL!+!Or(!(V\E<#WjP]TkJP hɉWB*M D"E]x ^U!ՠ*TA{+Ca &7 hj˯z&%o:PZh5j/0|/5k(!/alD#hvx~Mn]MК5ψ? ^<'͡4&hQxQv[7dSsZKr2(m l@{y_z.I&l85Ԇ+mᵓ+(PI(WV:@{hm^{'Sl]jR[OY!wJwMt.lwF7?đ%KM,JO^xJy LiJoxzAOx~slx,{_Oޠʟ/A?F}l-䶐B%?2H~So@v8X5p.DuhC.U FP6o/=dl䲒J]6u8rIu\ JeQrYxeȔ&[ |jׄdNMujc⍕۪v^ wP8 cF㍶CdMMoj&MǨ0N&W)0Ih&foy[ԼE[ ^Wo˫aV}S^=m:t7_Wd6D&j7ě)QgGW߃wa&6[v,ē'O]>l9pc%)5Rs#xG&K h}f;;F_SίоZ"߇w fv@tLwhɑ.9/vrm;lc{+-v,2dPS2n=x{({ 4f> {`7.v蝠#t מ|{:h C`(8{$0ƓO~ -7^n=}dR}FABxDQTsp(". E"{[F1(Vr2JAI(ъEA.\Eʠ+'** < C9ˢ+$z#h 5 ߀Jh\UEw=]UD/׳ ە*ULfe'ߟjhjib:̀]&Ԁh&~3̅9搟CWxħ3j >w_}9d?Iv۩NvW#x)W3j*N@4Fh &~3I٫\9sxωw+Һ[t"<a>,`}br/n!,ǻicXa LF7 {E߇=n/wp8SwnMƷo!wmnM~.1W.Sa LF7WIjLUc SyEٞ6/_)%~qr8%SC 7&ט|#B~ېkC um>m? `<eA08ca hrɏn4c3\ßOn>y}saV$JVR>a;`}nrn'wQ8a;Lk'Я wu?9 24 S`2$IF2CI.'p TIWqQ(_\a+L}Pq]z'_Pǯ_kƭ%~ r-ȷ- ^Ʊq'G],{(?#AH`g!7lއY~V0^[J~)uK_Fla}vron+lCpGr??HCp .3~kRw.$u@.|u K$IFVl#:af2%Kd|W7׎|WfGCsEEh=N1jGbYxr㩋,}΁#4Eέr)Gj5>;ܯ"'8# "D]+NuE_*g+L2u>B hɸzk6ڐoM]+hׯ;Sם #`$Q&7kԍ~`:Nn:M~}^r+ɭ$̯ߗ7H~#u>_p!;L'A~0>';ߩ9 ܚCd -5?ρZ ~:rȧ."/BD/_\a+Ub\*'W|yS_>4g-ȵ ~$u`__! __s ]'K {pׯ_Z%|[ rEEhy q^|'rBJ/M]iЧ,4(MЛ7#׌|S@_N;BړoO]{;Ч# +R7x"LOn<ԍ~}&|Xx!"_DBXo=aZrkɯn-1=Q;g8qǩ;N 7&[C6uSvi`fy庤tq\R:;.*J> !?0j^v( q$xLğ@n M~"}&Xxb%䖐_L"Xo1:rȯng=쁽~SIOPwsn-Ʒ%wn-~nC8,Z<^ "FσI.|rCد4RPKPW) !FEoL]#hׯ=vr/oKv02~}`r~8Яx`,rcȏn c3_@n̓eV"*VQ>k`d }7r{nw18G;BQ?/o$w _~4qIq*.*ENjWB!q8zN\rI]8~E!_"O1uC߀\uaZ$ג|KZRߊ>!bǡ@nA_ь_Q#ɍ$?ԏk0 g<}\rsϡn6o%eQY[`+mwA~;u`_ÌC$Op0~ OrFUO(ENȯ_~[rmɷ-ˌBn M`<%7XR?>x>_@|o㵰5WS5Y ;a{K~ua_1䎒?JQ8@-7yEqNQ ^]xΠ;A8#EE]N7`\%W|QR_>š.c\~Cr 7>6V[Q׊i7}K.wr[;_/۟]||G[/0'3;ގ&ϿW6לMH$':_iIϤkY:,X›թU3< k6]V 6}qdLA?ri?qV쁯BVKgt!YIyd]#0d깒}d}v6$"Y7{{\o^;ձOރ<ٖgnu=:mv3/uhUhM=bڭS%uI]R%uI]R%uI]R͟8)\)e# zL|O.fͰ%lZx~vHRy\oj[|Rԑ[03e!3{ǾzWa~Ru>R?NRG?w~7nm᝷.G_7qw>c崷sIU<w~m6w]=>co]ُ8)s.Hg45s~ӕ_,z݂[#u<}ПgH<;o}R3Ϭ}8 ^ ƣI==?/<?-)߷I6V5Object 8/content.xmlRn0 )vNHeki!!I\CF6aI{j`v8vXUD^P~%"OUr U6"k6fYe76/t0t!G1} ,"ز05:Ci!PY&qv.QJ)̠:wHx"6ĉc_8r/U3CDV<]܊kJtQ(??jҕJ?&,jOJRqչ㦼1(~3.! 3~jw7U~ z-X=@8MO+/4wwҲ!mQ:Lձ/PK>:]Object 8/settings.xmlQo0)n%*T]7$&I")O?Av$"w|˫UĜ"ӆ0|q&w'U%f4?  J!ӹ7G"9@*1Mߎ7ɊQqJž-ekmo6 GQ(D܁̄ԙ ]gМ,~P}l\PX{Σ@&|vޡLٰDC5:o\T|u5vC _A"Y/ ctM&9,(mk"ʍEfHۨFC"[>29n ;p߾Ԭc3DuƄ"Ag Օɹ3ˆpY_^#ۏnwFʄ" 6vRrƲvDS}Vm8e`_T;cXM;SӬHv5iWDJl"RU hUJ%#1͂Z3}qcׂϠUaKC }øf # !r/} (? mkwK"<(Ȑc|[ Cy ۏzHP{ 8_j hDW픟1R- sͬ5i ;ZmTr[-p(7t qd-͈kuEA'S aI10I` Ħ2D!dIKjV5JV=|*8ZQ*4tHObject 9/content.xmlRn0' ŅRhu*- NJl)'#@)U.|ao&RE#n2P:6Գ<'TTۈ͉yZ&vTDhU*5alEf&w&QP Y|WΫ v=`cWQ CONpNA}{xutNʼnL0f5CRkQiZ5`)S7*&>>>jkX.85k_jmH[G{:<C1-@9}~[z[)j qc:`G .*ېBgKioPK>u#^Object 9/settings.xmlQo0)P]6*ڮt$Xu|اMe@R{B$>IfIyݩ1|vgWMS SՙYӏs%N,DRqa<}aɕ%̕<],狋s3q}}C}S:;E!dHYÚg76Nt8; 9 BqhFas칿y#'VÐϜN8lʆQͫE9?ǽfNB,Y/etM&9,(i-\EjY6*ဈ-LXjG.!ط5aP *P#eIP*a ȘT{Em!pYO"ۏNgJ҄"12vSYrʲe8a`_T;eXM;SӬHv5iWDB,"U hU%_qAwz7'bV *m_zr뮤ح +jUEz}߫0nQ/>`$@Vw7cC`wS32䲘{oKv(fQrZI=soKe> 3}V룪\3sKDo}ೃVO9>&tC4C"YsK2"X]W,GDFf5 6)&FM}\XWb]Rƀ=dy,yJ@F۱7jRN)6DT ݉uYTuy '0-۱ESY]q+/N3Nܬ/0?PK>P..meta.xml XFLR5 v6.02 Guidelinesx-andre2011-02-15T14:19:00AD2011-02-15T14:30:002009-10-29T21:09:004PT12MLibreOffice/3.3$Unix LibreOffice_project/330m19$Build-8PK>NThumbnails/thumbnail.pngPNG  IHDRg?WIDATxػKWq/i]4EDt ZmA-hCW%$?~M__~pt<ߏ{xv>\1779+o#)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ea"LRI0I&)$Ek0} 5_vM6{n˖->}Ǐ{{{޽{ر:QW>|ȑ#v~>~w<{/_?~tt&y͡C?ɓk׮>}̙3nݪm611ql N733S۷o_^v۷߾}[ϟ?߿rrr۟>}~Ț5k^|zJzzz*Ǻf|||֭uW|M^-[. ٳѣGΝ[jUvƓƫ_~jp…kɓ'|KKKO:5ls΅yjpҥq,8Ko߾7-zA'ÇZvQo*}~oQK^i~r]<ӰlVI7nhjhj-QYzu`GFFjQ{yUXdzgGImܸAW^>jTg^x955U[ڹĉuΝ;_t1 XfOMurJ?yayw͛kpk ~,[KS翷> g>9a"LRI0I&)$Ea"':, XIENDB`PK>@|JObject 30/content.xmlRMO@+&{0p h<,t[-N&D1iev޼7qzy\Fez˞Na,˚uSSv;O2po:hpJ( *I ۽ڨDpN4!r :d!R((^ϽTz(sXeFgy-ˋB;}ók#F `ᲉD^l9Q(]<[~8! KZDġ^ B !UE[p2x,!XZZgy`+M`T#BkՉ\9|8o^ \|PK>@j^Object 30/settings.xmlo0WCkT]7$Bg`ES`lB($0 |>"d"o9Sc@弌Ͼ:w/8P8$(ȚΥn9IISt=[' F{˙)y;(n]M'tz,*B LHY|wjk'BtiR5 8 BqhAa59z|Gao2oӮߺ&7ۇajiѸ.g,f팇f_A,Y/ atM&8,g(n.\e"5Q) DL)϶|brR6n?t}%Y9V.HV @FTWk~΀V1.ȍ'I(M)¨osl#iW'ŪU., ``Oq8֧@`W\lp^ކcE%xմ35ͪ`WvE$*&*"XհـVlQ(.gD ՒAKO}ݕt ⿃ڭVU'j0 /CG< S@0'E L^*~N\)g~\}Rޛù ӧ!^S~FsJU>*5]"|ݽ7`}Y6פRn<]ҝ[E,`14A4aI10o Ī2D!{dq \T:r<|JI9Zʦ3*j<ˢde8F6qhx%ݎD,-r^7[iGi n?0?PK>1RkeObject 31/content.xmlRKn0#/JM̮=I]D`O4ʊn8WJ) 4̼f4awa*ZE$h*R #r!]v&GFd>Qy+oi3c WB+PƖѹc^/fS$n3ldeHi2 L1UR ihƣyD> "^xbp'$z#X(LwI+rsjel,.}ރ{ʍ$D3d7USAq4rtٸ>r ܭ2;A.6K0lE]A %D@^ƀiY{Z{דLNNS!oo>_PK>]Object 31/settings.xmlQo0)P@5Үt$Xu|اM IY |>Cz+Iwyi1|ug_ާ/@?3 J!s%N,DRqa<maɓ5,<]Vs uuunߦC}s8~B=LH.ni| !U4vk]G#W }Ԝyyo)FNFm"!_8f=6q!̕ 4PL×j],nٶ3U8}ݒ Jg, n2aD^\,D=rEIۨ#"g[.Ԇ=]Cph_ jAc@My$A s S+SV16fGv"ޜ0 Em1bm$*yXUe; !g4) p$vVoϰvYj05Ӯ`U$VE$Ъwb5J%1품0}ȉ/UaH# }øVdhH19X>sRd6t Rdȗr~0}rBۡGe=& x9vm! 3}VeQuAtRϪɽ#ǐrLwIܒ(VWdI3Object 32/content.xmleR0>Nh,3Ep$'B 6dK'.ra| ymNg7o ymM2}fA*%.PD\s^eP-x8E|BHMʥAzΖ{f D^+5\!Z:M Qf:=6(&o/1w2p tM\f^1I=KbBumDHDOK>4ƢD@Sn&H!VP Ԅր q4L:Ōը w]OEIGoX~PK>WG\Object 32/settings.xmlQo0)P5*h hl:v &2HRF=!~?ghݮBV{!)Ӹ;5>sٌ!pu!A)=Dt.uۉH*=NB=ӼSQ}"@fB֬ׯS:Iﴶ*MljƵ.jNּ<]dQHaNrMnv3e "p@lFfN_A,i/+etM*x,(v`*3晶Q) D)϶|fvR6n?t}%Y.9V.HV @&T#,k# ?g@ea䦈 w:3$&aԷňobU&S08&:*.68Do)YMjڙfUFL"UfXjm@B(j|w "j͠/ǾJ_AV*ԗf^qu F@lm_P I}@ӽlJE!g^QV>H9P<Η0ңU9g>ǭTa꣪\3k#"ɷ{G 6^ ne{K!f!U,ݹ%Qt.;Vx*}ADNoH.Al*Aq.)cHCPU%vUjRN)6BT7 ݉uYTuyȆ0-۱ESYq+3~8u= PK>OA:Object 33/content.xmlUKn0(5VR,jViWALd"GSAˮzw(C$%%JAH7'ʻZ-"xJ dAǡxFχ*y s0Xd|Miee_\^魁- <,F[()`i%ZɩKn'FR!GjeŤ&{`ac [Ri̠Qq O>H&+e$ZFKOXi=&w<_Ep^Object 33/settings.xmlQo0)PPN#ҮtSI")O? IY |>C*d7":Mǀyyܟ}q>up6>xq\IPJ =K/yub=$J|#4o%OV׮P*\w\//Q݋vnަC}3:?G!d&$l`fM;{i94^g H>ΨĦ}l\:QXd{γ#L0r7j7 5;al}Zdf"V벝m6Object 34/content.xmlUn0(5VR )de& *y ;ugw蓔(mtr'DyWE)WZ' <D37z>$WA[0's5Y}ftpy9R۷$4_EodfLj Gn.$S' n'FR!GjeŤ&{`ac %`5ҘA}2e6/O&+e$ZFKOXbNWȴ u;¯"t^˴]V3^֘2%-L DB0|cۤ{wY.kY7nz7[p3.#FZyj6سº{J=N aObject 34/settings.xmlo0WVmTnHM&9lلPIʒxOĹ}9\/Cx!)svt} (uɥs!pu"A)=D6\z !Tz ={OvG{kXre(:s"u}b]]]PΎE%wQgְVM;;i94^gH~NĦl\:SXld=3/z2IU03츇&7;ajiyyQy׭Vm<㢙'. t 0:&1=d Object 35\ tUՙ> <.y\/oT.'!%r57O5kHӥ]k|㚥K0jgXQvź {s Ijg}o}O O>%oR!I纳 `s"\wwJ p|_l 5:iTC"ÀbRct40cqxc Dr`p0bn)6ObYRNuTOi!*NTMRctЫ\YyuOP3oUTz(}k[d@#O=g)ߑ?U!-=_s2)|?_׾?{_ۥ?DH߇xfWWW_`6h.0Os_}}0 k+7Vok._:ԍ9Ju%GT5n̢K5R}Uof)q/qlׅAngF, Ș' Л9V||ޫy[!3Tޑ`)i<N5{3)%jWY^z>fM[rf☕qßU f&#g "ɑHhZdBd092K/)"34~Hsq[޿,UcZb:uA% k^GjlKl*D]gLL:6Hyʶu>Y˨Ψͱy(1SHҰ8FkZ d4J(p|wT;Yܝ>)ymZmk7,(ֳ(0UF-۵ ȊsP K);ԎORDYLJUTȎE@h}n KP).9ټq}K!uBqUTJl\%dʐs.6(!\A=V q="D/R|+\-7m\ [KEQl^>B-u9W9ssL?w]]]_Oܶ[fG-3}3\?rN~R-u+WdlSdVrXmźxˤY cy-|/Ϭz2mCm;? ȿR(v,q[ NQغEcA)"[RqQ,Ϊ(V]g9B'֗1bu1=>QKu_! [+$+dZ;Y8i8s$+#=<9#x_Y!1;nKzNHiXIG5ibE|/~N?4oLsS-|.J(iif6*aCp4սI0o|]N鷤~lQgْ!X"I+eҢ#UϚh%*P 7߲'HI`C#à7Zk^Gt>h}mMg7g/~?a9?_3Ԏ|7Qh(dS.ъ} ˃ēB_BeuecMmp,o&g<.0MU%\.^3R]X\Lp1cK-v떚Ó:k9o8pIc<%\auڧA5nUĦuT|`}[~]z=v>Zۥяz6m]~Cokm-7 }""`π}?q_σ}#:X BUؿ _.FmFmB| 6 5>N¾~{qw"~(p8c??G]|" pa~OiB3qU5O~~UĽ~)OO!7- Mn;l "  ! LB? i )⛋`6%%9r`X}9[[ۀ|5*ثW*ĭG|5 @1ck&/|7H lxZ@[=6ۡg ^q_g -7C-&_|??)!]埾v|J^;:mlqoYocg|4 W}+Ny6(SApzmϗ)|ava"~8|Wxl 뙚Zt=o^^Ҧ7/Oxڢ=3ZdmFl! g(CfNVEmٷۃzB` &S[Y79{]%O5f$tdik;Fd=Oؓ;NG@#MqO<&纉|"}`dtӦ#{4; ް}.7~IC=9DSң2HC;&MHwPUBdBL˄j;< rCZV!ϛu["W;ڜ'v*e'#\)B^Z5NT~]y'Nyiu餦x'x'x'xYH_7rih?b?={o"/O{y>?g\_I$IrQ} leKo|ⵥtY=E-JrˬFXQX_C'x'x'x'o7F ߨ;O"׻$)bxce/&ڢކ686_R{Y8A+ |9;ηzG\-mE;.Ȕo|NL^r|w^W=TJ7|wJϷѼaYnjԣQi2_r |ˌe T/#g_/|Z?O /ߛwPK>'Configurations2/accelerator/current.xmlPK>Configurations2/progressbar/PK>Configurations2/floater/PK>Configurations2/popupmenu/PK>Configurations2/toolpanel/PK>Configurations2/menubar/PK>Configurations2/toolbar/PK>Configurations2/images/Bitmaps/PK>Configurations2/statusbar/PK> settings.xmlZnGSV+R@`b K38VUi AKi+R[ )}}uRY{V93;;sjA6@H䑉0fV'35ǂ-LKP 1d.~=q"c2wn˽:1lRfJlli=E-;9==.8[sjWʊsHo18όuh2]9^??e; Z6chdp'L}﹄ 2w3oT7Z&?1%18XS&^vlUKx? NؓS'Qys l1( as eJx<+ ޔpېD}P90qf&ؽo`t LJ%-lmSUh{G'&RPM򔩓+U =;"EȕD;HjչPhCiqO8lOwOKȜW.eb).>qJ0U`)8zK.^_qh?Q$( ˜:WKY@G qAoTAy=}Qc- *LPAtxR^MCX6 ED %pZb? X6Q202J#"pj8Au."Èhe:pUːG Pu ǒ'QD߾ ҷ$j b6eAEz ິ"A o"HUX_'B9WOǟ;_;7 ; o! [z'"l_ 7}'l ۿ{aQaqyv~;—́&>r~ N ǰ}#l ν$|8|t받T| o|YZ^0QR-Ƚ|,7,p(V42R6sJ+!jܗRy3H++&a q,8tʗgkɜ8^ɤ7Tbkvx2|ZF6s4Gb` Y7HBn(B4ǍX$h1tQ/1VHKsD4qpiV|ٞoI_APKXv̛G)PK>META-INF/manifest.xmlZr8}pu+\IښBd- ߯ NIe2yHQVۯ?껮dcW:O4߭ݸ_nqtl_nVݺmiヮM-J?I{y.yz^4iK}2K1봾珛ksifg^׻6nʸy[[kkCV?6W4mkgW"YH7qпA#:(n mQ`jaȤ1 CFD3qS<)NNwRC;"Nk[7n]BÔFxWNE$VzRKxE) CT toKP(NQ ͞ >/]R^/2 X!8P.3wקw2&E=??y\=E$q/wҋ6橫ÿ:ie'86`Plapl bHdV2`+ Jl%[ɀdV2`+]gU-2laK [aŮ[]"h*fM?EuӤtwEuhx/okCqJL*Km.:MJQMYP^2 ''mimetypePK>{6""-MPictures/100000000000024000000195D17728C6.pngPK>,=z-e#Pictures/200006C400003EA10000290A6ED5325E.wmfPK>ʣPl-::Pictures/2000059700003EA1000029DDD517F244.wmfPK>CIaIWW-pPPictures/10000000000001AE0000012A977B24D8.pngPK>7MOO-dPictures/100000000000023600000147F0E7CC63.pngPK>gga(&(&-Pictures/10000200000001090000008D68112626.pngPK> Ȗ-bPictures/10000000000001FA000001637AAF07A9.pngPK>0-wPictures/200006F60000376D00002462AE65D36B.wmfPK>/-o Pictures/10000000000002B600000161755707D7.pngPK>н M-Pictures/20000201000042610000325C969DCF28.wmfPK>Ofo-Pictures/10000000000001AE0000012EF117893A.pngPK>#[) ;-Pictures/200001C9000038FF000026007119B2D1.wmfPK>,3&&-Pictures/10000000000001D90000015D3A4419E8.pngPK>*- 9Pictures/2000062000003EA10000290A705B22ED.wmfPK>zeh-!RPictures/200005BA00004F0B00003DD43C539478.wmfPK>h-kPictures/1000000000000186000001155247EBC3.pngPK>-Pictures/2000074700003EA100002973EBD9240B.wmfPK>7Wt4-Pictures/2000011C00003867000024DFC0AB93CA.wmfPK>>``-Pictures/10000000000001DA0000012FEEDEA63D.pngPK>= ;-dPictures/200001C90000391C0000261DCE22F4CC.wmfPK>jS-Pictures/200005E100004B2E00003DB154EC39F9.wmfPK>9j A-JPictures/200001E6000043BB00003899BF289333.wmfPK>Dk-Pictures/10000000000001EA00000125EBDE8E53.pngPK> ``-Pictures/10000000000001C2000000E5BE9F95CC.pngPK>tH\8(-e_Pictures/2000085A000046120000174729721B1D.wmfPK>jn n -\Pictures/1000000000000208000000AA90981B63.pngPK>M $-Pictures/2000076F000045F000003D246E880C36.wmfPK>r-Pictures/10000200000001BA0000016EBCA0A574.pngPK>qZ/-9Pictures/2000025E00003B0C00002309BFBA58D3.wmfPK>!2qIH/-NPictures/2000012E000035CB00002600789D1BCC.wmfPK>v@>>- Pictures/10000000000001AB000001351293192C.pngPK>tV2-{!Pictures/2000011300003867000024DFF7E85024.wmfPK>T ,*content.xmlPK>G " layout-cachePK>O B!manifest.rdfPK>ū#<`"ObjectReplacements/Object 10PK>,X#ObjectReplacements/Object 11PK>L#XT<&ObjectReplacements/Object 12PK>܇#VGJObjectReplacements/Object 13PK>LK7xytnObjectReplacements/Object 14PK>k)ObjectReplacements/Object 15PK>$%p"#ObjectReplacements/Object 16PK>f Y4"ObjectReplacements/Object 17PK>5'#ObjectReplacements/Object 18PK>N2CObjectReplacements/Object 19PK>zPcObjectReplacements/Object 20PK>ktpT ObjectReplacements/Object 21PK>hLLObjectReplacements/Object 22PK>THObjectReplacements/Object 23PK>6TUObjectReplacements/Object 24PK>ЃjO=vObjectReplacements/Object 25PK>`Q ObjectReplacements/Object 26PK>Df+ ObjectReplacements/Object 27PK>!^>VObjectReplacements/Object 28PK>FJ9!ObjectReplacements/Object 29PK>5[@]XrObjectReplacements/Object 1PK>z_+ObjectReplacements/Object 2PK>|:F\'1ObjectReplacements/Object 3PK>w DObjectReplacements/Object 4PK>d[36FObjectReplacements/Object 5PK>J.Az uzObjectReplacements/Object 6PK>>)]ZObjectReplacements/Object 7PK>Q<GObjectReplacements/Object 8PK>(/uObjectReplacements/Object 9PK>1[zObjectReplacements/Object 30PK>] 6ObjectReplacements/Object 31PK>e05 ObjectReplacements/Object 32PK>\zObjectReplacements/Object 33PK>l朓EObjectReplacements/Object 34PK>>ObjectReplacements/Object 35PK>adObject 10/content.xmlPK>ZK"]Object 10/settings.xmlPK>7q/Object 11/content.xmlPK>|ʜ^Object 11/settings.xmlPK>3 ~Object 12PK>T^Dc14 (Object 13PK>uaG :Object 14PK>fo Wstyles.xmlPK>^I ; nObject 15PK> йObject 16PK>&\ Object 17PK>= Object 18PK>h  Object 19PK> Lh( Object 20/content.xmlPK>A{^r* Object 20/settings.xmlPK>. Object 21/content.xmlPK>5]F/ Object 21/settings.xmlPK>UoC02 Object 22/content.xmlPK>d^M4 Object 22/settings.xmlPK>637 Object 23/content.xmlPK>;\E9 Object 23/settings.xmlPK>*F< Object 24/content.xmlPK>]N> Object 24/settings.xmlPK>(mC0 A Object 25PK>$1 Ir Object 26/content.xmlPK>+0`ft Object 26/settings.xmlPK>V7Bw Object 27/content.xmlPK> \oy Object 27/settings.xmlPK>B8| Object 28/content.xmlPK>\j~ Object 28/settings.xmlPK>U Object 29/content.xmlPK>8 b] Object 29/settings.xmlPK>E#-< Object 1PK>I8vh Object 2PK>^>?k* Object 3PK>(&$W Object 4/content.xmlPK>s+q\ Object 4/settings.xmlPK>% X/> Object 5PK> ( Object 6PK>/38S)9G Object 7PK>I6V5 Object 8/content.xmlPK>:] Object 8/settings.xmlPK>H Object 9/content.xmlPK>u#^ Object 9/settings.xmlPK>P.. meta.xmlPK>Np Thumbnails/thumbnail.pngPK>@|J6 Object 30/content.xmlPK>@j^ Object 30/settings.xmlPK>1Rkew Object 31/content.xmlPK>] Object 31/settings.xmlPK>3 Object 32/content.xmlPK>WG\ Object 32/settings.xmlPK>OA: Object 33/content.xmlPK>p^ӧ Object 33/settings.xmlPK>6e Object 34/content.xmlPK>J=N a Object 34/settings.xmlPK>1=d . Object 35PK>' Configurations2/accelerator/current.xmlPK>d Configurations2/progressbar/PK> Configurations2/floater/PK> Configurations2/popupmenu/PK> Configurations2/toolpanel/PK>D Configurations2/menubar/PK>z Configurations2/toolbar/PK> Configurations2/images/Bitmaps/PK> Configurations2/statusbar/PK>Xv̛G) % settings.xmlPK>&!1JKwE META-INF/manifest.xmlPK' xflr5-6.09-06/doc/ReleaseNotes.txt000644 001750 000144 00000117547 12250656141 020206 0ustar00techwinderusers000000 000000  ******************************************************************************* XFLR5 A tool for the design of Airfoils, Wings and Planes operating at low Reynolds numbers Copyright (C) 2003-2013 Andre Deperrois ******************************************************************************* xflr5 v6.09.06, December 7th, 2013 - introduced number input/ouput using system locale settings. - mesh resizing is now enabled without any limit other than the one set by the compiler and the system - fixed the issues with the animation of foil operating points - removed the option to save as a file for xflr5 v5 or v4 - no point and source of bugs - corrected the automatic polar name of foils in multithreaded analysis - added import/export of the wing geometry via plain-text files - fixed the bug which caused the pitching moment to be zero - solved most (all?) of the issues with OpenGL text rendering - improved the default stylesheet - fixed the translation issues - made the code compatible with msvc nmake - removed the access to the array of body objects; bodies are now objects attached to a single plane - deep code cleaning - other minor corrections and enhancements xflr5 v6.09.05 beta, March 20th, 2013 - Modified the project load method to keep the data even for corrupted files - Other minor enhancements xflr5 v6.09.04 Release candidate, March 2nd, 2013 - Added optional stylesheets for application toolbars - Added a feature to reset a wing section to interpolated values between two adjacent sections - Fixed a few bugs - Made some other minor enhancements xflr5 v6.09.03 Beta, January 5th, 2013 - Added an option in the polar definition dialog to ignore the body in the plane analysis - Corrected the bug which created straight streamlines after a failed analysis - Corrected a crash bug in plane inertia definition - Corrected the automatic polar name for foils - Corrected the bugs in body edition - Corrected loading issues of old files - Restored the max number of points in a plane calculation to 100, with correspondig increase in memory usage - More code cleaning xflr5 v6.09.02 Beta, January xxxth, 2012 - Not released xflr5 v6.09.01 Beta, November 18th, 2012 - Modified the wing twist definition which is now applied around the panel's quarter chord rather than around the y-axis. Impact on results. - Corrected the bugs in body edition - Fixed a few crash bugs - Minor enhancements - Made a lot of code cleaning xflr5 v6.08, October 24th, 2012 - corrected the scaling of foil thickness and camber - corrected the incorrect foil automatic polar name - corrected the issue with zero-length wing sections - corrected the occasional crash bug in plane definition with elevators - minor bug corrections and enhancements xflr5 v6.07, June 28th, 2012 - fixed type 2 batch polar analysis - fixed the issue with incorrect 3D-panel calculations - Corrected the incorrect aileron control derivatives - Corrected the bug in wing analysis with ground effect - Corrected the bug in type 4 analysis for wings and planes - Corrected the bug which modified the chord length as twist increases : impact results for wings with high dihedral - Cleaned, corrected, and improved the code for B-Splines - Removed the option for Min/Max type controls in Stabillity Polars - Added an option to edit Wing Polar paramaters - Fixed the crash bug when defining wings with more than 16 span sections - Corrected a bug leading to incorrect results in stability derivatives with active controls (CPanel::RotateBC()) - Removed the Splined Points Foil option - Other minor corrections and enhancements - Code cleaning xflr5 v6.06, January 28th, 2012 - changed and hopefully improved the algorithm which intersects wing surfaces and body - code cleaning - minor bug corrections and enhancements - reduced the maximum size of sections, masses, and chorwise panels on a wing to reduce global memory usage xflr5 v6.05 beta, July 24th, 2011 - For Type 7 polars, listed the control value instead of the aoa in the top drop down box - Added a calculation form to determine Re.sqrt(Cl) for foil Type 2 polars - Added the Japanese translation to the repository - thanks to Koichi - Minor corrections and improvements xflr5 v6.04 beta, May 14th, 2011 - added a settings save at each project save - added and option to view forces on panels as coloured arrows - fixed the incorrect setting of AVL-type controls for flaps in T7 analysis - added the missing write operation in the project file of the control variable for wing operating points - modified the setting of boundary conditions in T7 analysis with activated controls - impact on balanced aoa - modified the wing construction process to allow for a gap in the middle of the wing - corrected the bug which caused the disapperance of the left stability toolbar when switching to 3D view - corrected the bug which prevented from changing the default number of panels in naca foil generation - continued the code cleaning process xflr5 v6.03 February 13th, 2011 - modified the geometry connection between panels with dihedral and twist - may slightly impact the results - corrected the calculations with sideslip - added multi-threading capability for foil batch analysis - added an option to display the position of point masses in 3d-view - in the export to AVL of point masses, corrected the missing addition of wing x & z position - modified the export format to AVL of with wing flaps - added an option to highlight the currently selected operating point, or the mode in root locs view - changed the interface for stability analysis - added a properties dialog box option for operating points - corrected various minor bugs - made several minor enhancements xflr5 v6.02 Beta December 19th, 2010 - added an option to load a background image in the foil direct design module - corrected some errors in CoG and inertia automatic calculations, with impact on results - did some deep code cleaning - re-organized the panel analysis code to perform only one far field calculation per operating point - optimized the panel method for increased speed of execution - corrected the mesh edition for NURBS bodies - changed the export format for graphs - implemented the stability method for mixed panel/vlm method - implemented the stability method for full 3D panel method - corrected the bug which lead to incorrect results in 3D panel with Neumann B.C. - corrected the error in the jump in potential at the wing's trailing edage in full 3d panel method - set the estimation of inertia properties at the time of polar definition instead of evaluating at the time of analysis - fixed the bug which could cause a crash when dragging a point in splines design - corrected the asymetric transition location for symetric wings - corrected the source strength influence of thick panels on thin surfaces, with impact on results for planes with body - corrected the Cp 3D color display for VLM2 analysis - added the influence of pressure forces acting on the body to induced pitching moment coefficient - added calculation of neutral point position based on Cma/Cza ratio - corrected various minor bugs - made several minor enhancements xflr5 v6.01 Beta October 14th, 2010 - Corrected the incorrect balance speed in 3D type 2 polars for planes - Corrected the final moment calculation in stability analysis - Corrected the incorrect lift calculation in stability analysis xflr5 v6.00 Beta September 19th, 2010 - added Stability and control analysis - changed the 3D-panel method for planes from full 3D to mixed thin/thick surfaces - doubled the maximum acceptable size for mesh definitions, i.e;. new value is 5000 panels max. - added an option to run polar batch calculations on a list of airfoils - refined the inertia evaluation for wings by considering mass distribution in the spanwise direction - changed the foil list table in XDirect - corrected the display bug for stippled lines in 3D view - added an option to reverse the zoom direction with the mouse wheel - made some code cleaning in VLM and 3D-Panel analysis XFLR5 v5.00 April 11th, 2010 - changed the executable target name from QFLR5 to xflr5 - changed and reorganized drastically the file system - changed the icon images from Q5 to X5 - changed the unix directory for translated files to /usr/share/translations - added the spec file for the creation of rpm packages - corrected the bugs linked to undo/redo of spline modifications in direct design - corrected a bug linked to a potential incorrect type in WPolar Dlg - correctd the option to save in v4.00 format - made some code optimization for increased speed - made other minor improvements and corrections QFLR5 v0.04 Beta December 27th 2009 - Replaced the confusing term XCmRef by CoG; added z-position for CoG - Added some signal connections for wing control polars - Declared a bunch of local variables as static to speed things up by preventing repetitive memory allocations - Corrected the bug associated with tilted geometry calculations - Corrected an error in the calculation of downwash for secondary wings and fins - main wing was OK - Improved the 3D view of lift and drag for results with sideslip - Fixed the issues with animation in Miarex - Fixed the issue with 3d Cp scale settings - Corrected a bug in the estimation of the CoG for wings - Corrected incorrect summation of a plane's inertia components - Forced the use of QPaintEngine::OpenGL, which seems to fix the font display issue - Corrected a crash bug when selecting splines in Direct Design - Corrected a crash bug when capturing the OpenGl view to an image file - Adapted the code for Qt4.6. - Made a few corrections and enhancements QFLR5 v0.03b Beta October 28th, 2009 - Fixed a bug which prevented polars from being stored during a foil batch analysis QFLR5 v0.03 Beta October 25th, 2009 - Added a form to evaluate the CoG and inertia of wings and bodies - Redefined the pitchnig moment and yawing moments for clarity - details in the guidelines § 5.16 - Added an option to store oppoints in foil batch analysis - Marked more sentences for translation - Corrected a crash bug which occurred when trying to run a biplane analysis without an elevator - Corrected Tail volume calculation - was missing a PI/180 coefficient ; no impact on results - Corrected lift calculation in Type 2 polars. The lift was calculated by two different methods in separate parts of the code leading to incorrect results - Corrects bugs related to projected areas for aero coeff calculations - Corrected incorrect units in reference length for AVL export QFLR5 v0.02 Beta September 1st 2009 - Corrected many bugs - Made a few minor enhancements QFLR5 v0.01 Beta July 4th 2009 - first release - QFLR5 is a re-write of XFLR5 using the Qt4 libraries. - The goal is to make the code cross-platform and available for Linux and Mac OS. - The current beta version offers 95% of functionnalities available in XFLR5, and does not provide any additional feature except for a different look and feel interface. - In the future, only this cross platform version will be supported. - Once it has reached a stable state, it will be released as XFLR5 v5.00 v4.17 June 1st, 2009 - Corrected the bug which prevented the definition of a control polar - Corrected the bug which prevented to run a foil Type 1 analysis after having run a type 4 analysis v4.16 April 13th, 2009 - Added an option to use the area and span projected on the xy plane for aerodynamic coefficients, instead of the developed planform span and area values - In 3D wing analysis, corrected the pitching moment calculation to include the viscous pitching moment generated by the viscous drag when the wing has a z-offset - Corrected the bug by which the main wing's position wasn't taken into account in the calculation of a plane's tail volume - Also in the tail volume calculation, corrected the confusion between deg and rads which gave false values if the elevator was not in the xy plane - Corrected the bug which prevented convergence of foil inviscid analysis the first time - Improved the export option for Plane/wing operating points, to enable post-processing of Cp values in a spreadsheet - Corrected the bug linked to airfoil duplication which could cause the code to crash - made other minor corrections v4.15 January 24th 2009 - Corrected a bug in foil Polar for the power factor Cl3/Cd2 - Corrected a bug which could cause the program to crash in the case of a wing defined with flapped foils, if the foils were deleted - Corrected a bug in foil Type 4 polars which could lead to display an incorrect alpha value in the OpPoint view - Corrected a minor bug relative to inoperant graph translation in some cases - Corrected the bug which prevented to run 3D analysis with step less than alpha or Cl = 0.1 v4.14 December 30th, 2008 (limited release only) v4.13 December 6th, 2008 - Corrected a minor bug in Inverse design which prevented a second consecutive application of the spline - Corrected a minor bug in the display of bodies imported from text files - Set default coresize = 1�m minimum both in VLM and Panel methods - Switched to Trefftz plane integration for lift force in 3D Panel method --> impact on results - Improved the export interface to AVL for planes and wings, including control surfaces - Improved the interface for 3D cross section Cp display - Added an option to export any graph's curves to a .txt or .csv file - Made a few cosmetic improvements v4.12 November 16th, 2008 - Added options to export/read body definitions to/from simple text files; The file format may be obtained by exporting any body - Added an option to export the client area to an image file - Fixed issues with file paths while saving - Fixed the bug which prevented XFLR5 to launch after a selection of the thumbnail window - Set the default parameter for 3D panel wake length to 100 x MAC instead of 1 x MAC - Added the x-coordinate to export of current XFoil results - Added option for .csv format option for all txt file exports - Fixed a rare crash bug when using foil polars with zero content - Corrected the bug which prevented to insert a projet in the one currently opened - Improved the GUI of the panel list in the wing design dialog v4.11 November 2nd, 2008 - Changed the twist/washout application method ; used to be set around y-axis irrespective of dihedral; is now set around the panel's quarter chord, once the panel has been rotated by the dihedral angle - Improved the foil flap setting algorithm, which generated incorrect geometries in some special cases - Corrected a 1/2 missing factor in the output of non converged LLT oppoints - no effect on results - 3D panel with tilted geometry : corrected wake tilting - Improved streamline display to reduce singularity effects, essentially by enforcing Kutta's condition - Changed the algorithm for induced drag calculation in 3D panel analysis - slight difference in results from v4.10 - Solved the multiple storing issue of identical Opps - Corrected a bug which could occasionnaly prevent from reading the saved settings - Cleaned up the code - Compiled with MSVC 2008 instead of .net v4.10 September 6th, 2008 - Corrected a minor bug in Control Polars - no influence on results v4.09 September3rd, 2008 (limited release only) - Corrected factor 2.0 in excess in induced angle in VLM analysis - Corrected mix up in plane controls when performing a control analysis with multiple flaps - Added extra decimals in AVL geometry export - Corrected downwash display for planes - Corrected factor 2.0 missing in MAC span position - Corrected bug when running a single point calculation for 3D panel method - error on results for symetric calculations - Refined the Lift calculation in Type 2 Polars; was missing a cos(a.o.a) - Made a few cosmetic improvements v4.08 July 20th, 2008 - Corrected the bug which caused to ignore weight and speed parameters in control polars - Forced Dirichlet Boudary Conditions for 3D analysis - Corrected a crash bug when loading some project files - Added an option to change axis color & style in 3D view v4.07 July 11th, 2008 - First release of Type 5 and Type 6 Control Polars for planes - Corrected spline foil bug v4.06 June 25th, 2008 - Corrected display of OpPoint results in animated 3D view v4.05 June 23rd, 2008 (limited release only) - Improved the Type 5 control analysis polar - Corrected incorrect orientation of local panel vector in 3D analysis - snesitive only for very high thickness airfoils v4.04 June 9th, 2008 (limited release only) - Corrected the inoperative animation in 3D view v4.03 June 5th, 2008 (limited release only) - Corrected the crash bug for a number of cumulated span stations greater than 100 - Corrected the geometrical bug when setting a flap on a foil - Changed the De-rotation for the airfoil, to take into account the flap v4.02 April 6th, 2008 - Corrected a 1/1.1225 factor missing in XCP calculation in VLM analysis - Modified the interpolation method for on-body analysis in 3D panel, to account for special cases with panel numbers less than three in one direction - Made a few cosmetic changes to body view - Changed the scaling center in body view v4.01 March 24th, 2008 - Corrected the omission of the airfoil's contribution to the pitching moment in VLM and 3D-Panel - Corrected wing surface normal calculation in case of a zero-length panel - Changed the scaling center in 3D view v4.00 March 16th, 2008 - Introduced the 3D-Panel Method - Redefined the moment coefficients - see the guidelines for details - Corrected a sign error in geometric yawing moment in VLM analysis - Changed the fin definition : all planes with fins will need to be redefined... - Changed 3D view rotation with arcball - Corrected an error in Ground effect in VLM - Added Reflected curve display in XInverse - Added Slope tangency constraint on spline in XInverse - Inverted Cp signs in VLM 3D Delta_Cp display - Added option to offset the main wing in a plane design - Corrected the area of double fins or symetrical fins : factor 2 had been ommitted - Corrected occasional crash bug when deleting all Opps associated to a Wing or Plane Polar - Corrected chord calculations when there is a gap in the middle of the wing - Corrected a potential crash bug when loading a project file which includes a plane object - Added a save check before loading a file from the recent file menu - Modified the panel Normal definition as a necessary step for 3d panel methods. VLM results are slightly modified for twisted surfaces. - Changed X-View in 3D display to view the plane from the rear - Corrected MAC span position calculation - Corrected mid line inversion bug in Splined Points App - Corrected "Reset Default" values in LLT/VLM advanced setttings, to set default vortex core size at 0.1mm - Corrected potential file write error at the end of Foil, LLT, or VLM analysis - Corrected minor bug in the panel VLM creation routine which could define a non-trailing panel as trailing ; no impact on results - Corrected other minor cosmetic bugs v3.21e June 17th,2007 Trouble with internal messaging issues : - Deleted all V/W_ENDTHREAD messages, replaced them with idle loop checking for end of analysis v3.21d June 6th,2007 Trouble with internal messaging issues : - Removed autoclose of dialog box in XDirect single analysis v3.21c June 2nd,2007 Trouble with internal messaging issues : - Restored the V_ENDTHREAD and W_ENDTHREAD parameters and changed them to WM_APP+1 v3.21b June 2nd,2007 Trouble with internal messaging issues : - Deleted V_ and W_ENDTHREAD parameters and replaced them by EndDialog(0) messages v3.21a May xxxth,2007 Improved some cosmetic aspects v3.21_Beta May 27th,2007 Added tentative volume calculations to plane and wing definitions v3.20 May 4th,2007 Introduced a Biplane option in wing analysis Corrected the tail volume calculation for V-Tails Introduced an option to edit spline ctrl points coordinates Released the constraint on spline leading and trailing points to allow their translation Added Recent File management Removed the foil's automatic length normalization : operation will need to be performed manually Corrected the initialization of the Inverse Design to take into account the latest foil loaded in XFoil Introduced Moment display in the Wing 3D view Corrected a few minor cosmetic bugs v3.19 March 31st, 2007 - First release at SourceForge.net Corrected cosmetic bugs Add an option to export panel geometry and Cp values v3.18 March 24th, 2007 (limited release only) Corrected bugs related to the units change Changed the bending moment calculation for negative values Added an option to hide the text output in XFoil BatchDialog Corrected a few more cosmetic bugs v3.17 March 18th, 2007 (limited release only) Added option for ground effect in VLM Analysis Added option to remove the Cp graph in XFoil analysis Changed internal units to I.S. Modified the ligth & shading settings in 3D wing display v3.16 March 8th, 2007 (limited release only) Corrected the bug which limited the number of points to 271 Added option to read foil files with no foil names, or with points in reverse order Corrected the foil normalization process Added an option to export current xfoil results to file Added HMom calculation in XFoil Modified the meshing process for wing panel with flaps, to accomodate the break at hinge location Added reference curve display in Inverse Design to enable foil comparisons v3.15 January 21st, 2007 Made a few enhancements and cosmetic improvements v3.14_JM4 January 16th, 2007 (limited release only) Corrected the bending moment calculation - was calculated in absolute value along span (impact on results) Corrected a few minor bugs v3.13_JM3 January 14th, 2007 (limited release only) Changed the title of the incorrectly named static margin for wing polars Changed the pitching and yawing moment calculation for planes with elevators and fins (impact on results) Corrected a few minor bugs v3.12_JM2 January 09th, 2007 (limited release only) Reduced the max number of wing panels to 30 instead of 100 to reduce loading times and memory usage Added XCp export for foil polars In LLT, changed XCp calculation to interpolation of XFoil polars Corrected the bug which created a double operating point for foils at alpha=0 v3.11 Not released Modified the streamlines drawing process for supposedly smoother streamlines Changed the position of the wake vortex in VLM2 - very minor impact on results v3.10 January 5th, 2007 (limited release only) Corrected crash bug when importing XFoil or Javafoil polar In Batch Analysis, increased the text limit in the output window v3.09 December 23rd, 2006 (limited release only) Added option to perform inviscid VLM Analysis Made a few enhancements and cosmetic improvements v3.08 November 19th, 2006 (public release) Modified foil management interface in Direct Design Deleted Auto VLM mesh interface Corrected Drag scale 3D-display for panels with high dihedral Corrected printing bug for dashed and dotted lines v3.07 November 14th, 2006 (limited release only) Changed Cp 3D-display option to show lift component normal to the panel rather than the vertical component of lift v3.06 November 13th, 2006 (limited release only) Corrected visual display of fin lift (was using fin area as ref area instead of using wing area); Good observation Marc !! v3.05 November 12th, 2006 (limited release only) Added XCp in Xfoil polar graph variables Added L.E. Flap option Corrected panel interferences in flap option In wing local lift and local drag calculation, changed the erroneous c.cl/mean geom. chord to c.cl/m.a.c. Corrected minor bugs Made several minor cosmetic improvements v3.04 October 22nd, 2006 (limited release only) Change the order of twist and dihedral application in wing construction, with impact on results for wings with high dihedral such as winglets Changed Direct Design presentation to facilitate foil comparisons Changed wing construction panel v3.03 October 16th, 2006 (limited release only) Added Opp Point display on the Wing Opp model Corrected bug for plane calculations with wing panels less than critical size Added import routine for javafoil-generated polars Modified the automatic mesh method for wings to increase panels at wing tip Made several minor cosmetic improvements v3.02 October 7th, 2006 (limited release only) Added light options for 3D views Modified double fin option to make fins reflected rather than identical Added analysis parameters to .set file Added option to set minimum wing panel legnth to be taken into account in analysis Corrected minor memory leak in XFoil analysis v3.01 September 24th,2006 Corrected a major bug impacting results when calculating a Plane with the VLM-Quad method ; the consequence was a double count of the elevator's lift Added stream lines display Added option to perform VLM on tilted geometry Added tilt angle for fins Added length unit conversions to plane definition Dialog box Minor cosmetic modification v3.00 September 7th,2006 Made several minor improvements Corrected crash bug in 3D view when foil is deleted Corrected Total Pitching Moment minor bug in Wing Polar v2.99 Beta 014 July 23rd,2006 Introduced Induced and Viscous Drag 3D visualisations v2.99 Beta 013 June 24th,2006 Corrected viscous drag calculation for planes v2.99 Beta 012 June 15th,2006 Introduced again wake rollup Corrected memory overflow in VLM ICd calculation Corrected a few more bugs v2.99 Beta 011 June 4th,2006 Corrected crash bug when loading a foil with an existing name Corrected rename & duplicate wing bugs v2.99 Beta 010 May 28th,2006 Corrected a few bugs v2.99 Beta 009 May 20th,2006 Corrected wing Type 4 analysis sequence loop Corrected WOpp deletion bug Made a few imporvements to printing options v2.99 Beta 008 May 20th,2006 Corrected Type 4 analysis v2.99 Beta 007 May 20th,2006 Corrected a few bugs relative to operating points saving and deletion v2.99 Beta 006 May 19th,2006 Corrected a few bugs and made a few improvements suggested by Jean-Marc v2.99 Beta 005 May 18th,2006 Corrected minor bugs Reduced downwash scale v2.99 Beta 004 May 13th,2006 (Limited release only) Used wing area as reference for all plane coefficients (CL, CD, etc) Made multiple minor code corrections Introduced double fins Removed Cp calculations and graphs (was useless) Modified 3D surface representations with minor impact on non planar wing VLM results v2.99 Beta 003 March 23rd,2006 Introduced Cp Graphs for VLM analysis Corrected minor memory overspill in Inverse Design v2.99 Beta 002 March 12th,2006 Modified Cp calculations for Top & Botton VLM v2.99 Beta 001 March 6th,2006 Introducing plane design and analysis Modified the wing's geometry generation at combinations of high twist and high dihedral (VLM only) Re-wrote the VLM algorithms in depth with slight impact on results Introduced Quad VLM Method v2.05 January 28th ,2006 (Limited release only) Corrected a minor VLM Polar Interpolation bug (no effect on results) Changed the interpolation method of twist between root and tip chord (VLM only) Introduced alphabetical sorting of wings and polars v2.04 January 27th ,2006 (Limited release only) Improved the sorting of wings and polars v2.03 January 24th ,2006 (Limited release only) Recompiled with VisualC++.net v2.02 December 11th,2005 (Limited release only) Made a few cosmetic improvements Improved printing options Improved code ergonomy v2.01 November 7th,2005 Reverted to Trefftz plane analysis for induced drag calculations. cf. Guidelines Rev. �5-4-2 for detailed explanations. v2.006 November xxxth,2005 (Limited release only) Added NCrit parameter in Batch Analysis from list Fixed the EndAnalysis bug while moving window v2.005 October 26th,2005 (Limited release only) Corrected error in Airfoil Pitching Moment calculation in VLM analysis (OpPoint only... Value in polars is correct) Added automatic generation of 4 & 5 digits NACA foils Added VPlot capabilities for last XFoil Direct Analysis Added option for batch calculation from Reynolds list Added option to start batch calculations from alpha=0 to improve convergences Added memorizing of Alpha for each polar in Wing Analysis (Special for Marc) Corrected spline commands in XInverse Corrected sweep and twist scaling bug in Wing design/Scale Wing Solved a few more minor bugs (no impact on results) Made a few cosmetic improvements v2.00 September 29th,2005 Official release v1.99v035 September 24th,2005 Cancelled loading of WOpp results in WPolars when loading a projet Corrected interpolation process for OutPoints in VLM Changed Rename process for Polars and WPolars Separated chord and span scaling in WingScale dialog v1.99v034 August 31st,2005 Virtually identical to v33 v1.99v033 August 28th,2005 Re-transferred transitions to the WPolar's definition ! Implemented re-initialization of LLT after unconverged iterations In VLM, added Cm and XCp calc based on forces rather than on thin airfoil theory Corrected VLM panel save in wpa file Suppressed common foil constraint at wing's plane of symmetry Corrected many more bugs v1.99v032 July 14th,2005 Corrected minor bug in 3D view v1.99v031 July 6th,2005 Added legend to 3D view Added twist to 3D view Converted all floats to doubles to accelerate computations since C works with double precision v1.99v030 June 23,2005 Corrected crash bug in foil polar view v1.99v029 June 22,2005 First test of double precision calculations Added legend to 3D view v1.99v028 June 8,2005 Separated flap from transition parameters v1.99v027 June 1st,2005 Last batch of minor bugs Fixed the extended status bar bug v1.99v026 May 26th,2005 Introduced Y-Zoom in BSpline app Introduced Animation in wing design Improved print capability, including B&W option v1.99v025 May 12th,2005 Corrected resource leaks and other bugs v1.99v024 April 30th,2005 Last round of corrections & improvements before relase of V2.00 ? v1.99v023 April 22nd,2005 Corrected foil flap bug on interpolated bugs v1.99v022 April xxx,2005 Corrected minor bugs v1.99v021 April 2nd,2005 Added 3D View v1.99v020 March 20th,2005 - releasable as v2.00 Corrected again PCd VLM calculation v1.99v019 March 18,2005 Minor improvements v1.99v018 March 18,2005 Added import/export of AVL format Added bending moment calcuation Corrected PCd VLM calculation v1.99v017 March 5,2005 Reset graph defaults in wing design Added bending moment calculation v1.99v016 February 26th,2005 Added automatic VLM mesh on insert/delete panel Corrected a few more bugs v1.99v015 February 20th,2005 Reverted to Induced drag calculation by surface force integration rather tha in the Trefftz plane Corrected ClSpec bug in foil batch analyis Made minor enhancements and modifications v1.99v014 February 17th,2005 Beta version released for testing v1.99v013 February 14th,2005 Introduced severals cosmetic refinements Developed new options for VLM calculation Changed VLM Induced Drag calculation to Treffz plane Added optimal elliptic wing loading display v1.99v012 January 30th,2005 Corrected duplicate wing bug v1.99v011 January 26th,2005 Corrected induced drag calculation for VLM v1.99v010 January 23th,2005 Introduced several mods and corrections required by users Introduced VLM Calculation v1.99v009 December xxxth,2004 Introduced automatic discard of unconverged WOpPoints, and re-initializationa after divergences v1.99v008 December xxxth,2004 Corrected another batch of bugs ! v1.99v007 December 17th,2004 Corrected a first batch of bugs, including moment calculations v1.99v006 December 10th,2004 Incorporated Miarex v006 to XFLR5 Reengineered code based on MainFrame/View architecture v1.25 November 6th,2004 Increased general code robustness (hopefully...) Fixed "Show Points" crash bug Fixed "Init Boundary Layer" crash bug in Batch Dialog Fixed "On Sequence" crash bug when no foil is loaded Added power factor for negative Cl values : -|Cl|^(3/2)/Cd Added 1/sqrt(Cl) to the polar graph variables, Cl>0 Added "Keep curve" option in Cp Graph Made more minor enhancements and corrections v1.24 September 1st,2004 Enabled Re input higher than 1 million Added Cd x 10000 variable for Polar graphs Added polar type filter for display v1.23 July 1st,2004 Introduced Type 4 polars : fixed Alpha, variable Re Increased polar format to "4" for storage of Type 4 polars Made minor enhancements and corrections v1.22 June 9th,2004 Suppressed the idle loop which generated unnecessary processor utilization Corrected export bug from Mixed inverse Corrected bugs linked to mouse position and context menus v1.21 May 28th,2004 Redirected all file openings from within the Explorer to the first instance of XFLR5, if any is already running Added option to set BL and pressure distribution styles Fixed Export OpPoint bug Removed Cl^3/Cd^2 from graph variables (apparently a confusion with the power factor Cl^(3/2)/Cd) Made minor enhancements and corrections v1.20 May 9th,2004 Moved Foil and Polar selection to toolbar Fixed crash in initial inviscid analysis (Thanks Windsurfer) Fixed result display bugs in inviscid analysis Authorized sequence analysis for decreasing Cls and Alphas Added two polar graphs view Added option to define variables in all graphs Added Cl/Cd, Cl^(3/2) / Cd and Cl^3 / Cd^2 in graph variables Added inviscid result to OpPoint, even if viscous analysis is unconverged Added IterationBlocks and Iteration Limit to ".def" files and to settings file Added automatic geometry normalization on load of foil Resized wake arrays in OpPoint Added option to skip OpPoints storage and to keep only polar data Made minor enhancements and corrections v1.17 April 18th,2004 Solved Graph scale bug when dragging and zooming Solved Smooth() bug in Mixed Inverse design (Thanks Windsurfer) Solved crash problem when visualising Polars Solved Cancel Analysis bug in batch analysis Added minor grid in Direct Design Improved RenameFoil dlg box behaviour Made minor enhancements and corrections v1.16 March 26th,2004 Solved Bug in Animate() which mixed �ppoints from different foils Resized arrays in Direct Design Corrected and improved scaling of Foils' thickness and camber Made minor enhancements and corrections Solved more bugs v1.15 March 15th,2004 Added batch analysis capability Added Direct design from splined curves Added interpolation of foils Added Camber and thickness scaling of foils Added zoom capability on foil in Inverse Design Added zoom cursor both in main dialog and in Direct and Inverse Design zoom Added zoom from middle button down and vertical mouse movement Modified Camber & Thickness calculations Limited all drawings to dc's bitmap sizes Corrected Grid bug drawing in Direct Design Made minor enhancements and corrections v1.14 February 27th, 2004 Suppressed CSytemsDependencies which may be the cause of conflict on some operating systems v1.13 February 26th, 2004 Added Grid option in Direct Design Corrected resource leak in Animate() Added DeleteObject() in all graphics interfaces Corrected initial degree display in Direct design Removed double points in polar objects Changed polar format to "3" for showpoints toggle Made minor enhancements and corrections v1.12 February 08, 2004 Added automatic load of buffer foils in Direct Design Added zoom & drag capability in all graphs using mouse button & wheel Associated ".plr" files to XFLR5 Associated ".opp" files to XFLR5 Associated ".dat" files to XFLR5 Made minor enhancements and corrections v1.11 February 2nd, 2004 Made minor enhancements and corrections v1.10 February 1st, 2004 Implemented Full Inverse Design routine (MDES) Implemented Mixed Inverse Design routine (QDES) Made minor enhancements and corrections v1.00 February 2nd, 2004 - First release of non-beta version Added Q Graph in analysis Added Q serialization in OpPoints Made minor enhancements and corrections v0.36 January 13th, 2004 Added X axis control in CPGraphOptions Added minor grid option for graphs Added half-point lines options Made minor enhancements to design module v0.35 January 10th, 2004 Resized controls to fit 800x600 screens Defined macro parameters for XFoil arrays Resized snew[4*IBX], isys[IVX][ISX], qinvu[IZX][3], in xdirect/XFoil.h Resized usav[IVX+1][ISX] in XFoil::setbl() Added Grid option for graphs Added single polar graph option Corrected print bug in design module Added "Undo" option in design module v0.34 December 26th, 2003 Corrected ipan/va/vb/vz/vm/vdel array sizing bug in xdirect/XFoil.h Corrected qnew and q_ac array sizing bug in Xfoil::update() Forced 'Apply' request when exiting PANE menu Added recognition of '#' comment character in Foil files Added View Log File Menu Added 'Foil Menu' with option to rename/delete foils Corrected more minor bugs / made minor enhancements v0.33 December 23rd, 2003 Redirected XFoil message report to "XFLR5.log" file rather than to CRichEditCtrl because of potential incompatibility with Windows 2000 and older windows systems. Added Automatic polar name option Modified the design interface in depth Added color/width/style save for "plr" files - changed format to "2" Solved bug related to change of output points number in deisgn module v0.32 December 20th, 2003 Added Xfoil Advanced settings control Added XFoil message report Solved RDEF bug Solved Boundary layer print bug Solved Legend print bug on Cp graph Solved PANE and CADD bugs and changed appearance Solved Design failure bug after 2 loads Solved Double-click bug in Design Module Changed "Set Analysis" behaviour so that parameters are kept from one setting to another Grouped all polar commands in a single dialog box Added automatic load of settings at start-up and save on exit Solved yet more bugs ! v0.31 December 14, 2003 Solved bug linked to PANEL command Solved bug linked to Clspec/Alphaspec toggle Solved various bugs v0.30 December 10, 2003 Added option to work simultaneously on different foils and superimpose their Polars Added Type 2 & Type 3 analysis Added Cl Specification capability Added "Cdp" storage in Polars - no compatibility with former format (author apologizes) Modified "Export Polars" to use same format as XFoil Added "Import Polar" feature to read XFoil-generated polars Added dialog box for free/forced Transition parameters Added equivalents of XFoil's WDEF and RDEF Added flap control Added Graph background color control Changed iteration track variables to "rms" and "max" instead of "rms", "cdf" and cdp" Increased space for foil animation drawing Solved "Cancel analysis" bug in Viscous Iterations which caused Xflr5 to run in a loop Solved various bugs v0.21 November 16, 2003 Solved crash problem in Polar Graph Options/ colors v0.20 November 15, 2003 Fixed some bugs Improved Graph Display Introduced OpPoint archiving v0.1 November 4th 2003 First release ************************** xflr5-6.09-06/qss/000755 001750 000144 00000000000 12251146616 015100 5ustar00techwinderusers000000 000000 xflr5-6.09-06/qss/default.qss000644 001750 000144 00000000027 12246406507 017255 0ustar00techwinderusers000000 000000 /* empty stylesheet */ xflr5-6.09-06/qss/xflr5_style.qss000644 001750 000144 00000033403 12247700344 020112 0ustar00techwinderusers000000 000000 /*_____________________ All widgets ______________________*/ QWidget { color: white; background-color: #2a2a2a; selection-background-color: darkslategray; } QWidget:item:hover { color: ghostwhite; background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 darkgray, stop: 1 lightgray); } QWidget:item:selected { border: 1px yellow; background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 darkgray, stop: 1 black); } QWidget:disabled { font: italic; color: #3c3c3c; background-color: #2A2a2a; } /*_____________________ QGroupBox ______________________*/ QGroupBox { padding: 2ex 3px 0px 3px; /* font-weight: bold; */ color: papayawhip; margin-top: 3ex; border-top: 1px solid dimgray; border-right: 1px solid QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0 dimgray, stop:1 #2a2a2a); border-left: 1px solid QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0 dimgray, stop:1 #2a2a2a); } QGroupBox::title { padding-top: 1ex; padding-right: 11px ; padding-bottom: 1px; padding-left: 11px; subcontrol-origin: margin; subcontrol-position: top center; } /*_____________________ QDockWidget ______________________*/ QDockWidget { font: bold; color: oldlace; } QDockWidget::title { text-align: center; spacing: 3px; /* spacing between items in the tool bar */ background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0 #323232, stop: 0.5 #242424, stop:1 #323232); } QDockWidget::close-button, QDockWidget::float-button { text-align: center; spacing: 1px; /* spacing between items in the tool bar */ background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0 #323232, stop: 0.5 #242424, stop:1 #323232); } QDockWidget::close-button:hover, QDockWidget::float-button:hover { background: #242424; } QDockWidget::close-button:pressed, QDockWidget::float-button:pressed { padding: 1px -1px -1px 1px; } /*_____________________ Menu bar ______________________*/ QMenuBar::item { background: transparent; } QMenuBar::item:selected { background-color: #1f2c2a; } QMenuBar::item:disabled { background: transparent; color: dimgray; } QMenuBar::item:pressed:disabled { background: transparent; color: dimgray; } QMenuBar::item:pressed { color: white; background: green; border-top: 1px solid black; border-right: 1px solid black; border-left: 1px solid black; background-color: #1f2c2a; margin-bottom:-1px; padding-bottom:1px; } /*_____________________ Menu & menu items ______________________*/ QMenu { border: 1px solid black; } QMenu::item { padding: 2px 20px 2px 20px; background-color: #1f2c2a; color: white; } QMenu::item:selected { background-color: lightgray; color: black; } QMenu::item:disabled { color: dimgray; } QMenu::separator { height: 2px; background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0 #161616, stop: 0.5 #151515, stop: 0.6 #212121, stop:1 #343434); color: white; padding-left: 4px; margin-left: 10px; margin-right: 5px; } /*_____________________ QTableView, QHeaderView ______________________*/ QTableView { padding: 3px; border: 0px solid darkkhaki; border-radius: 3px; background-color: #232723; selection-background-color: lightgray; selection-color: black; gridline-color: darkslategray; } QTableView QAbstractItemView { border: 1px solid lightgray; border-radius: 5px; background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1.0, stop: 0 darkgray, stop: 1 black); color: white; font: bold; } QTableView QTableCornerButton::section { border: 0px solid LightSlateGray; border-radius: 3px; background-color: LightSlateGray; margin: 2px; } QHeaderView::section { background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0 #616161, stop: 0.5 #505050, stop: 0.6 #434343, stop:1 #656565); color: ghostwhite; padding-left: 4px; border: 1px solid black; min-height: 5ex; } /*_____________________ QLineEdit & QTextEdit ______________________*/ QLineEdit, QTextEdit { color: ghostwhite; background-color: #101010; padding: 1px; border-style: solid; border: 1px solid #1e1e1e; border-radius: 5; selection-background-color: darkslategray; selection-color: white; } QLineEdit:disabled, QTextEdit:disabled { background-color: #474747; color: #878787; font: italic; } /*_____________________ QPushButton ______________________*/ QPushButton { color: cornsilk; background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #101010, stop: 0.5 #202020, stop: 1 #101010); border-width: 1px; border-color: #1e1e1e; border-style: solid; border-radius: 6; padding: 3px; padding-left: 5px; padding-right: 5px; min-width: 4em; } QPushButton:pressed { background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 lightgray, stop: 1 darkgray); border: 2px solid darkkhaki; } QPushButton:hover { background-color: #272727; border: 2px solid darkkhaki; } /*_____________________ ColorButton ______________________*/ ColorButton { background-color: transparent; border-radius: 5px; min-width: 5em; min-height: 3ex; } /*_____________________ LineBtn ______________________*/ LineBtn { background-color: #101010; border: 1px solid #7f7f7f; border-radius: 5px; min-height: 3.5ex; } LineBtn:hover { border: 2px solid darkkhaki; background-color: #272727; } LineBtn:disabled { background-color: #474747; } /*_____________________ QComboBox ______________________*/ QComboBox { background-color: #101010; border: 1px solid #7f7f7f; border-radius: 5px; min-height: 3.5ex; color: ghostwhite; } QComboBox:disabled { background-color: #474747; color: #878787; } QComboBox QAbstractItemView { background-color: #1f2c2a; color: white; selection-background-color: lightgray; selection-color: black; } QComboBox:hover { border: 2px solid darkkhaki; background-color: #171717; } QComboBox:on { background-color: #272727; } QComboBox::drop-down { /* defines the side drop-down arrow */ subcontrol-origin: padding; subcontrol-position: top right; border-left-width: 0px; border-left-color: darkgray; border-left-style: solid; /* just a single line */ border-top-right-radius: 5px; /* same radius as the QComboBox */ border-bottom-right-radius: 5px; } /*______________________ QListView ___________________*/ QListView { color: ghostwhite; } QListView::item:selected { background: darkslategray; } QListView::item:hover { background-color: dimgray; color: black; } /*______________________ QListWidget ___________________*/ QListWidget { show-decoration-selected: 1; /* make the selection span the entire width of the view */ background-color: #232323; border: 1px solid #7f7f7f; border-radius: 5px; min-height: 3ex; color: ghostwhite; } QListWidget::item:alternate { background: black; } QListWidget::item:selected { } QListWidget::item:selected:!active { background: dimgray; } QListWidget::item:selected:active { background-color: #171717; border: 1px solid darkkhaki; color: ghostwhite; } QListWidget::item:hover { background-color: lightgray; color: black; } /*_____________________ QSlider ______________________*/ QSlider:disabled { background-color: #2a2a2a; } QSlider:handle:horizontal { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0.0 white, stop: 1 darkkhaki); border: 1px solid #999999; width: 7px; margin: -5px 0; border-radius: 3px; } QSlider:groove:horizontal { border: 1px solid #999999; height: 7px; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0.0 #b1b1b1, stop: 1 #C4C4C4); margin: 2px 0; } /*_____________________ Scroll bars ______________________*/ QScrollBar:horizontal { border: 1px solid #222222; background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0.0 #121212, stop: 0.2 #282828, stop: 1 #484848); height: 11px; margin: 0px 16px 0 16px; } QScrollBar::handle:horizontal { background: darkkhaki; min-height: 20px; border-radius: 2px; } QScrollBar::add-line:horizontal { border: 1px solid #1b1b19; border-radius: 2px; background: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 white, stop: 1 darkkhakhi ); width: 14px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal { border: 1px solid #1b1b19; border-radius: 2px; background: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 darkkhakhi, stop: 1 white ); width: 14px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::right-arrow:horizontal, QScrollBar::left-arrow:horizontal { border: 1px solid black; width: 1px; height: 1px; background: white; } QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; } QScrollBar:vertical { background: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0, stop: 0.0 #121212, stop: 0.2 #282828, stop: 1 #484848); width: 11px; margin: 16px 0 16px 0; border: 1px solid #222222; } QScrollBar::handle:vertical { background: darkkhaki; min-height: 20px; border-radius: 2px; } QScrollBar::sub-line:vertical { border: 1px solid #1b1b19; border-radius: 2px; background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 darkkhakhi, stop: 1 white ); height: 17px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::add-line:vertical { border: 1px solid #1b1b19; border-radius: 2px; background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 white stop: 1 darkkhakhi ); height: 17px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { border: 1px solid black; width: 1px; height: 1px; background: white; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; } /*_____________________ QToolBar, QToolButton ______________________*/ QToolBar::handle { spacing: 3px; /* spacing between items in the tool bar */ /* background: url(./qss/images/handle.png); */ } QToolButton { selection-color: black; selection-background-color: rgb(162, 162, 162); background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 lightgray, stop:1 darkgray); border: 1px solid gray; padding: 2px; border-radius: 3px; } QToolButton:hover { background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 white, stop:1 rgb(222, 222, 222)); } QToolButton:pressed, QToolButton:on { background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 rgb(222, 222, 222), stop:1 white); border: 2px solid darkkhaki; } QToolButton[flat=true], QToolButton[flat=true]:hover { border: 0px; background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 white, stop:1 rgb(222, 222, 222)); } /*_____________________ QProgressBar ______________________*/ QProgressBar { background: #505050; border: 2px solid gray; border-radius: 5px; text-align: center; } QProgressBar::chunk { background-color: #97B1a3; width: 7px; margin: 0.5px; border-radius: 2px; } /*_____________________ QTabBar ______________________*/ QTabBar::tab { color: #b1b1b1; border: 1px solid #707070; border-bottom-style: none; background-color: #171717; padding-left: 10px; padding-right: 10px; padding-top: 3px; padding-bottom: 2px; margin-right: -1px; } QTabWidget::pane { border: 1px solid #404040; top: 1px; } QTabBar::tab:last { margin-right: 0; /* the last selected tab has nothing to overlap with on the right */ border-top-right-radius: 3px; } QTabBar::tab:first:!selected { margin-left: 0px; /* the last selected tab has nothing to overlap with on the right */ border-top-left-radius: 3px; } QTabBar::tab:!selected { margin-top: 3px; background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:1 #212121, stop:.4 #343434); } QTabBar::tab:selected { border-top-left-radius: 3px; border-top-right-radius: 3px; margin-bottom: 0px; } QTabBar::tab:!selected:hover { border-top-left-radius: 3px; border-top-right-radius: 3px; background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:1 #212121, stop:0.4 #343434, stop:0.2 #343434, stop:0.1 darkkhaki); } /*_____________________ QCheckBox ______________________*/ QCheckBox { color: white; background-color: #2a2a2a; padding: 2px; border: 3px; border-color: yellow; } QCheckBox:disabled { color: dimgray; background-color: #2a2a2a; font: italic; } QCheckBox::indicator { color: #b1b1b1; background-color: #323232; border: 1px solid #b1b1b1; width: 9px; height: 9px; } QCheckBox::indicator:checked { background-color: qradialgradient(cx:0.5, cy:0.5, radius: 0.7, fx:0.5, fy:0.5, stop:0 lightcoral, stop:1 black) ; } QCheckBox::indicator:checked:disabled { background-color: qradialgradient(cx:0.5, cy:0.5, radius: 0.7, fx:0.5, fy:0.5, stop:0 lightgray, stop:1 black) ; } QCheckBox::indicator:disabled { border: 1px solid #444; } QCheckBox::indicator:hover { border: 2px solid darkkhaki; } /*_______________________ radiobutton ________________*/ QRadioButton { padding: 2px; } QRadioButton:disabled { background: transparent; color: dimgray; } QRadioButton::indicator { background: qradialgradient(cx:0.5, cy:0.5, radius: 0.7, fx:0.5, fy:0.5, stop:0 dimgray, stop:1 black) ; width: 9px; height: 9px; border: 1px solid gray; padding: 1px; border-radius: 4.5px; } QRadioButton::indicator:unchecked { background: transparent; } QRadioButton::indicator:checked { background: qradialgradient(cx:0.5, cy:0.5, radius: 0.7, fx:0.5, fy:0.5, stop:0 lightcoral, stop:1 black) ; } QRadioButton::indicator:checked:disabled { background: qradialgradient(cx:0.5, cy:0.5, radius: 0.7, fx:0.5, fy:0.5, stop:0 dimgray, stop:1 black) ; } /*_____________________ QToolTip ______________________*/ QToolTip { color: black; border: 1px solid black; background-color: darkseagreen; padding: 1px; border-radius: 3px; opacity: 197; } xflr5-6.09-06/qss/images/000755 001750 000144 00000000000 12246406507 016347 5ustar00techwinderusers000000 000000 xflr5-6.09-06/qss/images/checkbox_unchecked.png000644 001750 000144 00000000222 12246406507 022650 0ustar00techwinderusers000000 000000 PNG  IHDR r|sBIT|d pHYs+tEXtSoftwarewww.inkscape.org<IDAT(c``.qIENDB`xflr5-6.09-06/qss/images/down_arrow.png000644 001750 000144 00000000327 12246406507 021240 0ustar00techwinderusers000000 000000 PNG  IHDRsBIT|d pHYs  yIDAT] 0 gT@d_|#b^d> v3;J)R&3;179Z w 㬵~=H9_a)6-rIIENDB`xflr5-6.09-06/qss/images/checkbox.png000644 001750 000144 00000000367 12246406507 020651 0ustar00techwinderusers000000 000000 PNG  IHDR r|sBIT|d pHYs+tEXtSoftwarewww.inkscape.org<tIDAT( CMŬ!#d B_HH, fQJU" 4ڡtO`pJ)િ <~]6q6T5E`vү neloIENDB`xflr5-6.09-06/qss/images/handle.png000644 001750 000144 00000000256 12246406507 020313 0ustar00techwinderusers000000 000000 PNG  IHDRHsBIT|d pHYs  PIDAT]1 0 Dџ` 10\CժNz:JU%~usDb{+3{3 @  UIENDB`

u_B@ `BB(B!"ޙdH;Y/ t!&E0^IkU)y%BGZtm [ZqW{og3R.U?[@h]`/DMb(ATJy`-"ĕH|@f|@|ys86 @4 6;Y4RS<& * EO  )Ȁ.,Pkqoz#iƘT#~-cq{S5jDQԈp'ՈMFEHQ ʻzz˛z+zBpHki+X/epfi}RqF o2#GJYD$ n9$2Xa|(vկ~Yy_3^IWotTFʠ&մڳ=l44trG"A .@.D%.ˤ)ϤX$I \pI0$l%P*A'y8@g̰1DfhI|@{fZ=SḰ<hXFmޡ.߯Z`:=NL2KoOP(::0/s0:v`{ij o_N6vkDu'XHHq$ވb#eF?V7M.}_R!85 njDjԼMfIoDnڮ7"Z1n15"KAF,ԂFVT..`w~IWU&zj"~'w t| DI D(!>WbB0>>c~|Aa_XW׺U7V^ϻ}{KsitjUG A tyA;c`OqQ. dy  $R€D W-qg$r|"]jDj` iAb(4J x<^GPI``WWjb }kj{j3'camL!E &\o4PtQ8%HAj y(p͚-̱#C;'G!a3p'7i8EUsh҂RVAD(e?vp/*DҭQ"KwԈҩYJ񸛷սjM0jD1^5|sJwX5"ԯԌS##jDHjD TVTTuW>]{XXXu@+Dg!.ufS!BOr57$JDA:2 Q1B$kH!h/ѾU؎Az8(, %ǫݫ=k*˽}J;Q7uxtȴ4E) Q,/#*EI1H$AJ#E8 >P u ͖,2#{?q+]A !U( l蕽 @uK5+ts`ZzTo@8;@<ؼ#ycP' JZoGt% II7R.l<-xrFuwoY_6"deȺ/{ɵӱwrT$A7/*8fxHdҿWHY;ιow*mM^oľ:5Ax&ވtjވOm 5Fqt;5KXjDJDj -8 "q3EY& #=$L`Z_#c\!*>|@1vZP#O:ҎfKQ.ʮ{<8V\X^\YVYQ]][WX26e]SL62<4DXiB|E *"4j,\H1`!!J4A$n -qP> O|;9Uj"mCT-_.B0v#]aU> w @VI C ~Cu'{O=yzSy@ 6 2Fw0@A M1] {d+nE-* v6jYɣkrpI?O76mcsbitؤ6$ՈjtFGr5gõ"J* 8p5"ވ15bވdcjDbpҩ97"gMuWwWEwB]¯I$SzC A.>z5>%nrVQiͳ4}]!c4]wCG= *=*K}K}JkǦlyt궑i;ohЌ}3}:@SGa2WBEhY5AU!r]8*)Ap%n ;Bkb$HJ @ݵJV.JEB0 v]aRu:ypB~OaP\B]8'" @L *^AH( ra^W٩θCMڽK~.}/U#kdԈM{~Ty&,G}fވNvjFZ*P#WUVo.- A.zsG0wz O@ХyojSl#h WAm-$2BؼTRF!JQ1(ou[~3;ܻܷԿlؔգS׍L82mCw ;8sp̑}J{Dž22Id@=BEY,b)qI. ⢘ ErE)a@KY#*(S뾿Pr待cSNY>:uȴ5M44c̝f7kc{Tu`lrXfI1H#.˲tap%"A@ |>Y"DԈdjo[)TJ=hwu:],kڞ*; `{W p.䁈Ej8 T g@ b9~`o#vn1o}  yQ'J@Wk- " X "h0Ѩ-JېЌxVb^dwn;8:o~MFD\FkKy&Ǽ?2Gtj> cNDH5b+oDQJՈ!8E!+aWpmW=%OZ}&R3zyPl1m1D* hwh@[\ru|@f\L{i+Ҕ!^v>7,]Ap_|pJJrRUcS֌N]?2mP3vf540{t/{s!>,Itg@1 U Y$uQL,'%"QdY,}埬KվrWopOe:].vk;o-[].\oBFJ 6@=@X~naw~]#,>AA'`P80QBkF ]Έ+3 !&T*EtId$SjfuF)c4YuamWέT\׹ѡ;bjDMcML(ijN͎x#rNN=7"R$a]5֝7b]荨ՈTAԈTw? sxOyꓓw)] 8>N},CH^R/2\| c,2TRbM3$tt3?ÎJqiwyweoMؔS*{ ìp_FܗQ!SR /T#W̕bxE%O}mԄ ㈋$.7n%X Aw.b,)@OeoOeOOuWwugwuGwm{XZMcPw뺂5]0:Jf_Fj@?@=[Oko\,XbL`G˼C܌uUtv0n%F"X1.P1'%^E|DGhgVͭuIƐCuwEf mm{o̾W}H+誺7bKU#:{i~֌ [:fde}oSf %BEGnxk~PXť՞)t*mcSvN=2m`x0%3J3zAɿ](cMQ)ҔA=[#b{gm*G a(qI"ׅA\[ E$B9'D @ASC=[u[wukwuKwmsXXm( ڂ Vu+`A6y8[h @KOS?7kbn0#6 pR`@YI%x=F?h Ƒ\% ;"\kE}Zl3qnk@'&ވf-ԈѢRF{O$A^Md ͑A-{I^C;\]|@ OaLd %eekd?#2/4vx!x%ݥ;>Aa_\Y+^I=+[ʽ};KǦ N:224lo+G; l{I$cBA)qA@?il%⢈ =@!HCg %AR>hX[[) ʂ,  u&Q_B1[r B8O<#O~C33 yhBv>Arwv@h[HEA B @HP$ j;`gI)L8-hie}dj9e>;"AuetF35"ވ[ိ1i޼.8xhYW -hK.|Fةy[sd㨒!tYE jDjD1N͡7'y#U#po>{<+c"f~qAFXzS3-9jJ@F > ᤺ AZ7Cl*R*bD+f1y!ra_XRVY]{)4R#c[O 6l8=QTx%A!Q[ ZcFP%QO- K(K[8p{%Q sVg N%8A @0 4E V)"D׃@5ݵUbmE/+K `qW+x+7̂YD_pg Xp'X6)'Kk8Zs  PBz1kB6 J"1N{%eBP J0>XHa`s L)@ͫ42ZsW}eXF!,}9pu(~iqd ADLG{YԈ,ʨmvj Y5bJ3Eq#Fd\oD܊)FlT#D ԈO{_=QOw{o<"t {G^V2йj>tg6QqȀn=fuJkՊ;kݻ=r]t&Mf/wb{B`35g+qbBK1I!b~Q-$5.B Qppţe,].8] ]!!@q[(BA,/֖mI_T+ Ѯ`~uѲDYmd{J>f8Ytfyz\h1oĘtz#6Q#^SsQ17⅏76coѻh 0W,FPDE,$+5b_jވu5RQ#G#jF7,,(ڑyJ5l(ķ `|77LA:b 5tF  JUݨ@Ia}ct=sXG#P\x:W]"d,tfk4&Op ձEpq#?F|NXZPx/Y&jd3F 2ñN15"2Fd1ƂU#Fl,ɮ7"GI5umԈ=kOSo='SN"M&^qm9F@Iqmq@ৠC$cML&R;;̓+ !c@] U#/ ]]}]=]mfޙu_6SFP ^qBfQ(}X8 !C#A>5PLI(@ݏ@=3V5x /,' s!,}:7,=gqvlF$/]L7U3Kujnh}VXoبF|Fbá`.8ବ15"\WbU#jF\ԜBQ=&OW{z^xX%D!3CVȱ !I!BGK!ߪPT1b<*[',/Z柿a&3ic5XFcEQ%)vBME_ETK"0?P-wu.:ښ̂=y`/J€,9^2mv=vy3>h'e% +ZRqF QKF RAn%3 T}laIq>u˹7uIU#*N[F\ԠF 8x4c|vHFG|j(fވp3MՈ/7Af 90)~dmClRIw;>MΘ4ވѩ9捈ө9T#6c4ވQ7c|ތu ii5IԌjD~Ÿq{uҩygoyk7">)UpԈ굞z^ 8x%avgp]z^"-&&brw,.8A ӣGV~8p|jly {O(3텊jmR:>T`tTuܪ&Nm93j<8_NEK|M\<_܃2)>]jGG$ߎkvB ,a'T1 AC8/xS?ȿxr\k'ov@ܓG7rQeJ(imA[ PԔ0R@nC!Q^@xفhYdDt8()n&!Φdb@8 Ɨ;}­潨D_II'qK]hc@Asp9~Siv[wLuiUܙ -B5FfQԈ,XTؼS3*"iH&WԈR) 63VNjD:5hשAԩۚFRFSO?K="O=SWpdO=)X_DxvުYkko"aW轵ك a^MM#7EVh"</ 8jFIqp^XN.hM;Sn 1wOaa&x;Ԑ2Fw0 z; #4c*63HURD@#PB.}#M;[P\<˪},'q ػ 5"4nFjDuN͑7b5Yfވ]sFnY1#>y[]7"5H_iՈՈFd y#K՞zb @S& "e}#;=bLXL3:- R(ݠO ΃rEHYDx^M->Z|?`R\Y0AYy;WyzBէ% ZXێP >x}M<;n}Qp3 S`lGGB Qݘp,W3>R\\8 Yڙ@S7NV;ngm#թi3c]iL#G V݈A{-!P4PJP`4du~p ؀av[ݨ6} ?0Fcp;" &)v%P 8`W%6 4ƌ9&ZeK 8c%j!8eCv3v&C*hک,Lbx;@' 0eA[5ۨFlԜ1qCO{3:5GY#YljQ#R@ ,y[I r/%aZ\Hy{N͏N&:5FdE]oD[R935s @'0K^@jS^agb׫I7?A;JgR /2,Z7E FL];D-Cۣq.gi7VDx,Å']?ze)_|^p (ed0ǠYZeK!\^R\ĉBXOr*,k} 2lz=93A=Խi$-`r?6QVZv @.8  >`'&}@P( v6} KcL:w !y '&g4H ݀tamĞxT' db# +(mxYSrmM b#۰vIζK=F/KfވVR-q&Ո;U#r_E.t]$muQ4KԈ.0LcU 4V㍸F|8:5ވYYo(F|zFRg{ ppN :SN"؁Q@ԘMg8{ۿ-`"S%!*E\+"6Mo~XyTgu&O rA#2S^y[Ky6PSk# K)R :}6 Y5b#* w{9P ȌE>!j0!݀(Ej Zy[ r;|wИN5,5*2"`H,z\ni^}a iM0UϘ&QT4SnqzJ?&v%^Ih9X%FIac0qN#8uBW RPQpbw0^kp2FI(a *1H*b? > D_~ABzU >P3cw2PzVegڜ7P w{GM8 F:AwA~. JH>`5hqPyb7Z6S]]NJuG)WWZ@)Gk!6yugKk|w̎ٳ|4QP#6F{'F4]5l=ݩAz#qwYAJ3FU#Q#BQf1Blh7bF5 ׅ _P#>5Es 0=u|@̉C >}e?<@Z?H RQ-~f% (4]DI/r w K9D:wH+w Oϴn#0EzGkqO=Pk}~i?BGv NQ!E+$Y*mG cSB@j - A(ơ${S1Riv!ਸ6GL )^"ړ 4yB&!V @׃" $~Ä^@u8@p61nvCl@9??$ ]!P/R 'R&a1f6hG!AՉW]98O.@,B)ʲmoM_}f7Cd7P? FdyT#DyFTdQ#{vIwl:%NvV#ވҌQԈ,[(ވzPy%dqEo6!cވW#Ƽcjfی USF Xj:8809!8P=5u5t2s􀉢{i{M',Ĩ}x(Ih*!FNw#O`Lr\z7c/Cxwބo5,2I=bИk(~_Nf{,ؤ;2e ul /v Cf:BfE1B`QRP\1hp-8Nn(YFjSb(մ,Hw6f'O`Aڟ O  gB/>? EvCd@K Hpa;ddCnF!Pd{@N@@ AO1$DR !bqDVdAcL['$Hӕ#|sWZKC,`9,!6 d'!G-#_wF$4DFā1+LFtՈQoEةZixeX,ވoy$FDݬ#jDYN,B!vN4{L념```s$8k#E t_8Z!8Q!l_g{GMd\PDa!dov4&d:8 xx9/`Mۛloiު[K X ai8JoD |(># # jQ!͜K~#'=7s!B!=jC{=O#UhYRyʺ l捽ZUy8? K\5")UQWߒauDEU#J_荈:8hFAL!uQt|Z"q0q^aR D!?EJ 8"%@lKUH&tgiD'@ƃX!efA v>,%/U p\~-[m 'P3fb(պk(^oD)]@qY 8\TF{æ)v!-{/!$iwD|y&aO(uJ*( >! >G $#`OAcLv6MAp@nIMaKtf`L~&E`2*_4MvpB$@?V6bHDrb$TK£fʥ#G?'U9 mmClI]۳o^LޫיfjĘ7 M-xբoā|*em3F򳔀7b[5"K)DdFtVTiP7Ef)UԈgD "8hT#@3)́p4!wE}~PgNrM?<{ۗ;E?Sg 2(5h@@EC,(i"Pp~dr RލQM'7 S^͈U_ɰǨ֟Ve`)J!` K\Thk?>jk)ˡf}td F;E2i2&*ri,jŌåO+=CKwʣPOeiRܩ!(J E8 >6 >>ZddeRNBbڀzݕD&۟4ni#a! @T@Cԋ8|!PhPU,s1JOT q52 !tUQ"TfN9DDݔ?Sp?;fܭcl\5"w׶jDfhX,M81Etj^u .FH8+.YF$!OR쏬$B"AB `~uBeHiؔҐ1Mwv׶u;,0JҁJH $[)qX % 6}{ϛ+C878&!*Sf?~#@p_jY.t6@H/!"rGSC(@|\ NrbX͋?I-eiC,~rJ7 mR"hݶ8g&>BFZcgjHpPFnxOޣ+FlF\إZp`"ފy#rtՈQԈH]5b1fk8ۊ> 7_u? ~ЅJNL󑰒15":"m(4D#y5D7$R8T>T><6mddѡ) 0 Ջxe{Ou[wuKwm踡]*Q0|߸ > /@1(-D)hAYa `Wc@7uY;ҁ@rq>( ]Q`(]qD D>>6e9? "BXq ,I9Dh w چdw9gc&8Bs5FDE7j?T/7,jD Ĥ<8I5}OOS#^%5U# *F$]AȪFLK#8{ǃ.ED!7:N2܅a8xISs7 ވmՈ hrE0ċ?<W7B:!^K\$tccjt/a<|)gZ[/[T4h]CtSȟ"6ֶ p"M*6kdXQFPvH1 =3F O6o=SFwO?OCC6kȮ;n2lKis_yIA[]][],+ (ӱJ$XmMHApngiu Ζ.N(8n? dO\"RMbj"R3XRb[%v<ƣ[!D6N!8!刱}RMUGG;Hc^*&)̇FHZ0N.V\oDiS]5vmT#*)jDtܶSsF|Fhq8Щ5n-80t9u Vk5jēƧF|ֳe\p@ 1Isb"gL4;r?cO&D +qZN#}Gĉ?``/W5SES}I B!Q)Zk7IZ6~qg{O{sTy5eAjK1/$ A>zPoM 2jIYFvO>udS6m/++魬GWWtW-+K n!\"јD1*aR2M'6KAh#ف47O ^`^hQz.JhY"uK$@$k JFj\#%s_ S_1,!w)췻f3`GF)Zo۩ٚACVwkFlxafԈZp0>oDK]5b|Zu:zVjDjDjDWp`ԮΖ%jw8a=_=tj~j'ވ@JXHp 99}8ir!vǘ`=*7̏"tŸ])!bQwG=RBGy:/7ֺV{vTzvWz}å>**@ţeR!+TtUrVg84uG Pe``"АȚ#QD0o*M!l2q)ckKJ+{ˏj(X[XGG D'(*!QVD2IȡO >0?=Hv X`d:kǏyX~cl34X!\22)@>rn$Y)tz!~ &H"agVgcbM ̭uQCpϣ;+b#ᥘCv!0io\Yn$eݟdChՈx##mQh16LF5?JU#h;5S~ȅ8H p{H0DRR+.u/,)/m*o96eAJF׆D T< Dp~OݔQ~#< FALm@[΀i H @ѣXj}m}M}}}}好EG{+{*T=T=X({ykSe](RXH+kd $ 5 "K$@%|eC=`THFYPB?%Ȫ"!nhzJ'X\ퟩJX`Z#3Nyⶖ~Oz#ZZQ#&YSs;5/jćֈq˖6wm3?P﷨klb OVJ-ԈҩYԈYS1&@Ѳ5Y 088,HK$-ۨY E \ĉ:>B'>Y4 I"D+^ ;ed 5#T\&떠p_/W~pgAwQwioyX)Gncdit$DpMn?E'/vpWWA WVTh|PyzwڽEW!+ R%H(UE$d  $` `gy 0 VQ zp+ ],p$*0de1.dY4P!D 8xT?kأG+SDHLkr]%nb R?<8l:>Vri {NlhMd9 ɂ MnjeFԈ- ;5ǼihՈϻjĘ7"9VVGnfl`HrKW#D]oĤ] Q7xCp!/)-d)Ţ%K*@X@|rbmqtjnV{/EϘ fFd=<0ND'{ fH I5>p:! #|1s[3`I_1N|pSP_}gJyGK}My|tʪѩkGmex黆f 7st߬l/c} " B¢vzDd>q Q5duV{sb?)#(-G@Y-"+_"Q=6,k Fk1:!R S3 W*ք[5"j-Q15gǞoTS;5^\W#NS#VɑN(u(沝)1捈7Ś1ZoĄ1^d: 4 > hQa,@X#GXPA(S83zKOXOt =T;5:ԐvΈjZc'vџdK A*jD)U[z[ N1JW(^-Ոܸ#|g>+_KP#>{.;ҩU#ZoDE^GY-vj&ʝMF+J5clFCHԈ1#fS#^,*Q2!FV{! 浓P+M iA!~OWh@S|6B3;-8&ѷ $p_}_AC!//htґiO_94cufmu`woQû}tuNq };DFG~'oS_`GwtYj٥xgC2"D}Y B9a`!B"TGսeY)n2.I (֖b- Q{ BpsWۮW]X Ǎy+AT9&(-5Ƒ\p2??}]f bp$ф]QPLg4$35xCaA@RӯY<{guV_(Dȫb]"H+'r;"!u bbՔh7IԩprՈ4c7CoĹyMۏuIwn:UԈNZC>{,-cjDVAx#Hu;5O5NvԈa3:Fs/"Je ˕і*?5"e,8=,Ɗ)7޷L"XP+"*>N}5DH$<<&N(A(t=;h X/?7j(=#ӤF"!`tA 5B_]X[\_:6eԕ# O_74c-fms{}Ю#;8b;iO !hI¡M Նc ^BS(RPR$"`,ަJJWW+p㺑@H#mA(jeQAW9>K(wu)u=}NQ:槕*NLh, a<{01dq]h @~I8O'?2_7 ?ԍŦ_V> 'fZaM x4!Ad?5O[nF7I[%jD_P#!V۪:0g\jDS#rsՈIoD@T ssa[5bN͡#J\y#"8hF"kQ#b+}` x#fP#$]* !N18B­L}2Q"NxAf"̊ `b*8¤"_E (gxKt "jqLnPm"P_|hgawqoiV!~xơ[gn7k={ 9jhѣt_G Rz[kE*"Dfu/BqLbTRh)7PPzaGCj@ZX+ l([ 4bpY w CL rlM!vMɒbx:$*E <]g,\A[v.7Db D19B(qGج icvZ9~c-T,=@"p+ &W"ۧF2dzWPoq5NƷn}z NͭՈ8\5"Y bqo>ݿN?T!ᆱoĘ-5꭬ȟR'L!74nhFt1?/ࠅFlhhՈH͢E? @馎=́* 8 lG D~K<rdAcBeԈF.Q6)wZtx|P,b_G7eڦp @(B*GqI&*1)m@h(qHEF d8q"$ﻦ/"<ֺV{WzBUcS֎N]?2m-C3ž>;x+I1E@|uՍ48ltwG?~!" Td($ !F!eqW"HG 5BVKDt9lԍ{XsAlaX"%}1BxP\zqFʂ`=u9B#>_=vF J2BD W:@D $:CY&+f~WH1{Q,"Q,Իz72sJmz"_D6@]Nd=+}w{5uSUYW1NFeS#ˆ'FwՈmxFtՈPԈ諸!֡1`7bNPԈz-.jD+88jD}x|7b[5vya#Mj ƾ sJ>|ЖBHJ3C$Ll$*"qS gNJ$9WAq-g{nhiGEq\z,vj+=*k}JŲG!*ţwyǶPrRu)  ;mRA"POA20KR)dBzU!@!аRUܤN6N= Dn%Sm2^⩅ziQL2,Q`(R z~8 M*3p4=\ZǚdZ#hyDHƎ$.r 3䇴uD 1#z7CF{mc{" @4DC3jĴB8Rrު1IGӼujnFǪ]oD0,{a -* Tns7jF-D)= T5P%$@8?6)XN3ToDr X(l0ƣF1,H|TdRxC{1 AYKa!B}? ZCمH{Be@L1u> ;mT$(*XaO.3$!?x=HdpS\r0k?b.CUFX׃Ќ#I몺S1ա&Zr$&lp0n87CH15xjHp}MۥXco~m[Nk?Cսq[~*ވjD2Т15bAQY5"Ѧj=}坽孽 [l3jDcl2]D3QY쏒jDl?jFw T-8@RПSsjDn\jD]A!S)c8A" WIƸJh/ň1j| ^IB!Xў2Lt^*r3ШFծ Q#7jD}  P_mMnhQd޵RՈ"80jDO=+8N tGr2 +O:'4 {JwXQi Mcx E o̧NQDt*{VqegȀ ZW6Bؾyv¾-' m:yx㩣O/=sc8ZEqD ܑ 3rBB*,{9`j)""͝P$7R)TטBB&*~X҉F@xI@J@~k\nk@cr zg y3"2n8Lȴt,Z i 3`8"G?aw0v{nc'$P>C\Z$Ik@(`N5(Y|+M!<~ {F D.HBOW6WjÝEpn3}sE%fsxPd\oDF4gѩ[4iވfdtjy#Ҍ&ީ7".J\5tjFX-z#fԈD`go_:};5b')KEp ́ E bވ0!GHU#AziԈ/q ɺvil@Qz,ƅz2 AS1tcyi}5$"AHߧH4AH!hl" 3x @u~**E:6M44sӾٛe1[w};{{72ug 9sdc+-/?iZſT_pD@ 0UD=IS7,Y ._\(xipW !J ŽQƂ~5 D1" =Ӷ EVH<!ϯx4>ffQ6S7 w'z%S!0\??·5Dzg>X.R,Rar>=cg|ډtr$"%;V{y&?\ԈuEjD}9I 7S#~otu37{ͮoćҼYpJU#rˊ]oDʬcUv 6VtU)UjD;{~>\W#n#FDY~ՈajD}ԈS0|a݉$'V/EɁjď)줇cv[vOݕ%ա9&" c!~\\1#>Wmt>=Q?`d65 GE/6 ov(w:HhI D0܊_+[-T"Dton*Ofo{q܎m'|򮍧Y39kh#+[~~i?AkqDpc<4#vI n{Wg<]b#O县~S377kdՈ/3}k jFBf]?0SsLQ5"1捈U5U٢F#f-3{#EQ<@*~?b#t"cjDxG7FT!FDp0.8зkT4DtD zQr ܬRHp`;57x#r;껌ࠥN:tNUitUYVyCoy[/zXLDWj"HlI$YhvGA*+"D18*j;H0"g~B4??4pU<en=ǔ\yQ-ޭmcS18kQ; Nس佛NXڳ:gpyÏ?Ғ+T}R#ૈVQ<&9 dpDt!:$ m| x@ǂ'- .??ev]F)e7"4@", n0N?B ^42`` B)&#ZX ?T"6>%:AT KwFl# i Ţ.j 5^P=9۫ р1d(Tt%EC "~P5 mwHFqft|{owŶoz~ꝚU#AVe1b‚ǤMHyhH)UhF?!7bԎB^TMĊ\~Q"|Qyo)O3؊LJHy+=+};JSw4ks{dھp=t"К n69>~oٽ!C}wy-!(8pX7"h)s( <#3~<8g{cnF,NYrpK)U,5)X5"w!DQ@V)Bcjφ 34TJ),4J@cdO"¾~ 6C w,Jݣ&b'%)w`x|DyRy Dw.M3:}̽hp>p<ÛOp3G ҋ*/.5bRMUAe3xD//Y_$EKb j[=X1RZaS"l5+3A BOR,# BlBtr(BUB0xzA BFX.! %s&/q\lߧSgXS՞כDhi) FƦ?y@`e`x`8m"qbjDPj145"9Ɋ:5R5"ވ4ctՈ{#F*H=6 XbՈtjnFW:5Ԉ8ymE*PۑV' " b#c}NJU#m2ܡ۩͒S0RQg aBo RԈ$AjďF ҨF4FWBp+I!.֏Y(o69ž{owoy4ڋ1#;v6VZ +έ.!hWFnT_EH9G Pd+`j/vΚknv<aOmξ4 B֭/뒁 D&X?6}e챤RjL -)؜Y[e -a^~B! B}FQ)viMQ?`ICr iuiW=ܒ@LT {EK^6Ը?CE|rptL)jD bjėN͈(Œ,o1F4X}u7O!8hP#|ɚm|#던LޓۑU#U[TvSנF)7b7ytDGV^n;17"L!|!aS!aLB(8R45:FpeՈ5wjDpbx!A4u&$A0 /#q?L X?SW)wDHQZlGExJ-UH+L ֊ǣx nRʣqxV+ov9¾Z`#F=wlqm_zᓃW(wAUr<k3k |TPhBX_Jaq" ڹkg#aGݵ4DNG[Fa@m"6k D@[/ D@DQ!|1SԿ cP|L @2ĦE"d2.2|^>H\(*4%\ [.}oěn,mzg0OGݣI4U)H;kW cC@1hRH$Fr#AF,WࠔF7TwRx._I2^ $Scפ'*pr Ǟfhp Сo~]4t%F%P$AoRdI)mW>u_hM( pzn=gw.o;..Pe7ORH(be(#& s)w CuU!E E@"Itgv'#r?oF"1519\;;F"|HDeE0m"Ԛ T }*l/B"kW %"k&a4wA24V`DЗQW"+Yov?@oBwo900ޱ {TOjyظW.ɗx#+ӈ_axEb4A#@EN1o4 64 z#B#Ҍ1hhD8iĴR=DHQFdv{"B8 MVS]:FD1ԔF,҈iDLkVǪLy Dw$y/Vg R 2fSEWu谇B,b, $)g DxODI?RZ"D=D3S23]GdXw`x~aӅ :A냥/ 8X/ 4HejM[)"B"P7HJeC`7:DQ$¾0GD" ۳P";ۍDXc$&N#n#n3DA&֗2 5Q"~< T t@ #`N2iBQ ӝXy%HJ hxtDLQ~~H$JT3ai(3ˋ#l"=.ܱ^7p,,ztrs|-O0*LÒ5Jo7I}A*b L57bhFT@IX]\oD2ـ >cҩ7b*pvj܌3Oc*LU0d!NGc!QҜa9M\4"aHK#ShH"&r+aHhVovhD> -$PL| FܩΆF$C%&=PHjaF"觝)[_%'ԟfuQ黇8E hQ|0E_]93XS H)AC~P}hprojgFsv:'mXXia!,Cz@s$ mw H!Y­@!ò:*b\B(,]8yH#]齹)l3E HRE$)v+H#z_OBR@HB~tD 43LM$5pbB(Ba#T M%peInХs;[D!PHDS_@"l$`S&f%9Ͽ#%8fE}C~>$}*?} T};I-v/d!z&SV8ȊVa"J&F#bf\izl bGFpumOЈz$+miD]e3ZF?CAUvjFLF$O҈84"9(r4!B8 IRuo3 O~ åjIZ[oDhFd VB#PqTއcވ4"](UF4zrL/>(Q3XU!F A7"LpiDkd+ЈL$aj?׵|* \9Z=r˾ *q]%DAR3 HQunAmJxӴg}E(&,`^]$¤ll̬C9ݴZ:pyAgy4Y"X`8a 6pBK'[HPm!$?94"f}g##i E HbIȌ(+x/g5e<: UCZ 8*Z%-RP0 b=Z_"n7 4.dB E"⿔2t c"*ct*a@+( 4"n*)g(J[`CBBFf$C*AJL'` $yɉY&KD ""ȃHSͨW\ &M/ I' p~ ֮Ȯ{b{֋.RGRGNbPMz# (6-b?zxߙOf88w喢ΕW{% :fz|^ hK#uj~KNFH#F8"OJ?&:5T8R^V$+uj{oDL#Pg4"q?*F&4"SF*VK6 4Wc#AoV<|br2cGqY3tp7ո9! Qkfn7Fэ}K^Rd K#91Xť]⍸W쏆磎7bUc(hDʕ*DH=B#~1%ވáW+ \"8Y ,hDn bK)¬P>)a_:BJN ^r* R辻&NNn!"Sm8\ubt$m/ N.M/t*=p¾3 )l?tcaẂ2Bg-xr>A+pE$5EI.wB, !hP17hnzS1L6jD=hG": cfFTD3($@0RnURZX;qevТـz/j(a8`PI_jIDAT"FmGFD#Wi%=]$x/ ROA"A%(E,hZF>1I#ZoD'!Xlhh3ۓϮf-K2a PMr"<3(=_bވUhă㝚GIP;5N#  O~,fȼ[j$ [GI|RA D#T" R8A],"'|X'˵Z$& Q.cX#<]a!o(\# j*x#{S9e:5[oĦ*5c|B7cL#xqK#`$F0 @12p5A4b)WIӈa涒N1DToDS4"KmK#J]d.Aq@YS4"HLi2҈*eӔB PkЈw58@Xx Swӈ8aFVH4F5шTO71z8#b=k,kjhG6af#"(/cTMe&g꘣WP:XmE"\ֹEJ*B$B(hQ"lʟ%w"${7ty10{HI1/" vGq $Dxt"@"H#!42DؕQ{CľE3o@rࡋEŔrxd@rcbz9 K$B?3Dwgj?>;poG8S8ʀȤtjNiD&OJ; %;5'Y񟌝K#dhDI;2#v,x2[/LXiG,pЈ' r(iG)4"K#bâM>K#fMhD O҈OhDzsO , IUU"dL%="' C}o+S.U!Á=D84{6 I  ῍D;R޽{HyK\ykH*@, (j+^(B9@ZX $DD7x#D7o`o;Ms=-H"0E@"$’H"@]3GmdlxdiI-+ύ4"0 J\JtkLđ#HP*7BM9=af~ٰwxWF?Al@w2!뷊D8sFL(_"NY!6}ΦU6& ػ^^tFĥMIoDj@#6,YXFt1-Q5ChՕ1GB#Nͷ7+Y0bb4"9>4z&GUЈF5ӈ:aiD|F2>x#"lYҩYG4"ASčވKvЈfh+RH#XJ=ӋǤ|Hb>fQRX#D(B$nWޝ$j#vEa=*UeE"P6ѐ"X HL\V"+K4$&D؞;ggݙ3u}3zN<3.-++M@8('DF$H4D0bGW(7EH7"I(pn *azi,c-D(5]3,%LD>E!-h#j:~j줖-D=BЧ&JsF7 _,P>e~imd3hRTwbb UOJ(b4ϩ4" o}Ft>}ciD (OWW F1r+Ҍz#rFX7bUUxFKȁ<[`ٮ"<19BFTcD#@K#vjz4|"8F7K#_L/ڸvB#RKc>[ PF:ȌD8p'{;Ǧ&4UZ$$!A7ѐEHJ۔H"^" M4@$1Kh5=>}wtUdXLRVJF2KC!g22:d SqERɺ"p55E u05٠@ LL '6_$UTn":AV}Auqj?u9PFn8BhLшWX8Ƽ]6Dш:IlQDò<,]zTk7QXS&zFO҈g=(GcH#DT٥H#ө9Fzҩy4ǘ@ 'ЈoTٶѽ=B7"*TDA?tjH0Cv@q@rRߥ(pOYC.hI&рןL1R, =ǕLyQy;F"xcr"Hmj,I"Dx'U"PZXN"H D8WL$ i7D"tMv滚N#DXID",}#%6 bgТe.2ڊD21Fk0P]J(T%-ȯxMj !H谜!Z@Q MLH~1-ᗦG6*jb`H!L֣e{4גe UlU}z+Gܹ\57tj['?> *uVi%oۻ0t҈4c4r>HF,iƈqE_e-ވkoЈ(I#"vaf8P.P]ѕ m-,ޞ?'M$x-QH"Lngk$ =B2"0׾:bUŕIU ]SR,B0M# RN%F bºy6PjDMRP"p2x{Y 4}wWs[we06vU°N,UEqPFD`Xk_vjNF,KBJktөeG1 ވ1te9騚%dC8ߚ%5cFc-ވiDyғ4I&Y>B#JJ$>BoKp8(81Y4|YPTFI:ȇJ҈xvj~+0)4"f[Ј{M[񮮢7{x\%BHgtf: ߪ̊2K-AE4Sc:D`6k+f"R\$[`5JZ E"('~:EÊ@8E}]Qcy@a \8O,Epc,` Y"fL;ڊr!'B,$Y>–;>n,ZVH#7IeqP@d 彸 : `QΠ}-^aUCU}AvQbqF5wjH#f7K#D.I#҈Nߗh7&??ܩ{JDŽF$ @j@!+K(8KF%Kc2)RiĊ>NhbWҩy"R&pEa1f`yYQ` b#_޾\FRC-l\!IheV0F$-ݪ;sݯ{|aA^t&=&"P?DCYGF"i_I+gʻOy*iPzEi0Q nsա>L X'M4I/h(M 4 3.Q"H!dXhG" v w@N516Nd3{MޭWLeĤAaX?p7G8'J0`>fh-}~Du7 %3̎@R"Ǝ^B; eB2Ȕ9Z$Bk&kEt۽f9~S|G/#+/>FtAfhD1oӈEq0j1֌oDXFh%/6cDi(,U`|kpo/E5`F8x#ߐԌ6hS8Q“-U TPcLb&[`X 2(tiDRqh۪ujcif*GRiDm"F{#{ϏNa،Q īP9cb$ G"S)T;.ľ⠂DC[TqTEJ=6(3H$'D}SyW+*4{D$T4$AC'I3hbHbaD{V&$ SL?HB4 H]NEŢG#JkbqE|wm$9uL{h@y'IƳv%u2kk3l?~2>:}SU[ .8Y 5$```,6@C()dЫhQrǥC&qHM , 2`9}d1UŘ룻żFxҥ҈ Tg9z=M*ѥ n iĢ7/>*2<vFN ao(]iߥto4"ψ1X҈ hDNHz$)qP۩3(5bI VK9 H6s,F$%$4"2!n:5@P%t64 |v8N`,{4#`]kRo0ꊃ> :,HE KHkfG\15sD~+=b)O45i`AW5DuHTޏ: -HmHU)6H(Yhy$IcHȇa'00p};igB5D5NSˇD`\Ⱥ٭{b \kh|’5D=gZ !J%T3KvDM~AKMF}@ 7HB!b(\4QU&ֲV ID,{ڠoaF+Գ 0rY1OS]U$4"ϩ;41I#>RFUF=uW9UFX1Ib3(AD#W7k)F*Tk}ctpUQ҅, 9:Q4"O7#1Sџ 4pFM|5ЈoS_?S)V.޴xݧwpzF4 b-ch('TO7<Ђ|75`w/ ]`HE4ҫ6׎DEg}Cy1`i*Gbmg||DR' $S7$l?To$b'E"H10kkӊoJ$0""H ȏp lĊ~]&D\M!tV@b0:P|o/Hv9Ts2B#;ja:K,҈ Gb3C<Nb ҈ XFSsQ(iR$1Ԟ<yD^oB<{o7hD0\4"\;Hf*wjNЈemf"Ј/~}+O4XU13@ctVcЯ`Yf$vN[WF?ޗڒ# f"v[A$5j4͠_'9sD>A"p,ؤ 0Xމ,HB5B"$ &A7 DNz06 3NNپ|_kH-jؙ#)jX!I[G 8B6 `FNX PU L&js @>dI,I.h}e)2^f}Ӽ&BX_XE~O)WZ2W8dN>(h(7>)'RYRaʠfH҈<E(4cLFp|(FFiF 7PVԜF9҈DS~ވ4҈4bAoz#WsksviD1Iz\Q3FāP.,>4" hqӅIЈ :QQ*z#mS3z#hD/.\ghGBюWWZSƊa5!,}DA6%EpA26 ;$ߤW%B aH \&ExmfXKH+J WKF@"DQ$#\}  lƜDupC$]!S{&T$BMC٣Q΁4M?ln?=Q?զS&Ꙣ[ hMx>C61$Ke-BG7mr J&C' ͩI.h}@u v 4a6Yp nO=?h̫f^@09 }9m pXJ4>׎`w{<+FE> gEވ!J-4'ވ?0}Fϭةy4ވ.}< XҌ1F#"yf?nniK#J ^h&84$ J, ӣRXS#9UT~-48e#Ӆ'ȟ/׍\0c5@4BQnXk:4bXI@.9Ť>JhHd%l+-e\b\\ m\f`gA?=@aG"@-ܠ,8F"ЦE}E"~о5NN[rfH!Z<݃zLhK7Q.,F"ƴ!VLwobXG~f-SrE/+%)k`Ύ JVC 'D BXT> @JLëR5@fuؠqH ASNi: sH2_?KWpF<6avqA*Fs;矤纴eI ȥ=MSsH#Fވ5҈z#%٩{f i.ӌ1٩,?hnfb~UiDLG|XԊ+ӈ !_2pOP.!*C$Fcm4"K#JfrCx9"g9nH6ֈs/8@))-+.oB!NKEiXG)}3SCunh\Q3!~]#A sbÇqHiHuV<гtz V"@BM[g ŌCs 2apJA#H"PDX;Ģ-j=jTJ,&)1k`Qg6`K 7@-vC)f(h}AXLo! ABɌ:Lu!h*m}/ YgL!7m6 Հyӭ}F0al #'m[W &ވhD)?~g̟u̹p%oD݌9SF4"Cc1F#$thĔNn,L4 `65S|Uъfqrq0Mt-|(D"҈`B̒1_N1KK%hDZNЩR0F|x#/k C##+ORZSɈH -_^|7M9q`W$9Z8rEU5uz5}Gy?P]ʻWy)I="ؽID"6{t45"GxIi/d=VKp(AVua}ᢍ 6LGp{g˞~ 3Pf̌iCS& S4lDgelX+SHc*hp'}p'FGgOQzGH\iBFCjآ \ -\0$8 1oW R$\ȼPHS)~!;@V .|T#ũq$>zoX aCW2H盘7b 4Ta;=-h1NVAVыN5шfRPX p`iD vaxH(F#G<\q)q Lj &x#8꠬7"#  )D2,\b/V^d*A# N|IGimj7BNz#}6jSx#iģFܰ;a:5O7"DD6E \c@|C!Ɏ5#権#8zAhWBcs!BX@bZ XMp|qﱑAY`v-'kG-0r4"4:4"sBoDC#Ҍ ӈI3Y~(FLvjވ4oĐFt1##Vp8Csc#ЈLV0[q@089Mꁗ$'Tq#''Xq (4 q]KFT!p7"ш;#^D(V?5:=J# zXL ~ !%4؆dA"1(hz'W9AZbغG6Ϻ'bӃ{By(ow(B[ L zg#Mo߸"%>iܰHF@"Xk$BJH(\qlsvޓ7!7Pn|@>B#f*>> @b҄L3-iA HP6J Z -QtH ^DžeH^2GE0ܼYQ4IV.J-T6(K CЊc/DgoENd8vDqNվorj}ߪo])OG[:5#5U:5 H3FԜXFID#Vw {֓Y]㝚.?crV+CSLL y`Q1BoZhĤ7Ј .-p`iD CC#SiD},pJ#`4ވE~ +D2\@2ɣaAFt|7Ј5Јd)+-hi=AjkRF4":B#"XXY'YaXTڎ!6p7%ECH8Hh`41I;Ģ>B1$L{$&4KyEm~f?0w ,Zl;/|a`ʫgtQCi5[F@"Xk$B]VW\vGM9; g./CG;r3szsSstg}&~~0}za0ӬWfZHxOdƌJF%@j'oEPa+#Hu>B)|&LH !ԟ[$ b.d^h2))gBj"/د/ŨP,"sx_p UUB-o-#@-<ЈRcNЈRFF157bFF4A/ވb CJ`#Ė0CoD&J4"3(<2<.Y9nވS(G#"Sb4"g^;xy# Th;5Ǽ9[ R%N#4b±"dt}cc0Uar!=@c[4"ߪ$" *ٜFEHe& # Bfba`jAK9y޳]m/_꯹_y\KɗF?,0W 3!D% "*HTBWA<# B"wD=0M.DNd"A!%"_67 PR<1@rA{$2ިP] xrB~$1( )"I#c*8_U$7 荘)l1nnɭo)z#&1ޥ;oİe!#'0Ј8)>/¨TYܖ*HNa9h+iƨ(؜;;B 87b4"+Kb$r%4MP\CWa7ک`Sp.lfNEo.(y4eF<klXB2PN JA"0pPX,;'uί٫uO̴ip="V)oc$:7`i1D%0N9PBl@ >X3Z zGwმF>@Il0+8yΗL=Ly yFC)v鎎~17g֡`@0OM;:$CtEFP|9H S"+Toj4b'9ވ`e7hDjވdaTN#4۩i"4ig[ɆQj )p 2D.X`C n&$#b$Ha|Z"n }HD<$?™&_#}~`|$e86RP((0ჼ&HKIbxZ0:a`Lv*&R_P< 4"eЈ҈xϑF2H#f5L،nb"+ӈS 1F4 ncO#꧀ǡ"o1)H8p@}D(,ylGI#J3edgr[[/5M/3ˆ/Y>l$ RF] F(Ј$NͺIH#DCASzPA"*1PJлDm"سEh~ Uk` 7뫿VaݣX#|Z{5E"lW>YOMOvv=pF6\xq~e@B` aN  SCD,N QqzJb=tap{J Еޛ2ͷ&@!t*%([LΞi H 1!A&]A(z$ZTLmvgRgøVpÜ+ He#>S' N5C'2% Jac>¼Jôk*4 &*`r7 CKѳX((ftJHf}4iD(ičãI]hD=r|4@ZfbnveOGH##Nш:U'4e %+>7~1Q-p@jވ1ឤɘDH:5sqF8ةyZ_?MNO^_ӈaK:5=T,8YrZ&Iw^i1oRkQHd"HQCT5]\yd4I/.W>/j3RkД+?$ pF3Yj+D Z^>ɧ81?ҏ!do2Lo7r$':z#hVn`Ƌ7t4"O4MR$FAU5F#+O#VB4s{ 1F$€xd05,!Yx^9Qӈb4"lNF,vj@L($/=ՔsD( (&syɌ^ZP9*8JV38"r"LC􁥋{ă/^ 5'_ 6[55'e 6ϕD" & MꟚ陑霕=:7{h~vo uZ@ o tG@]blqcb6"JJ(vmT.,~0hAG%Kf>&T ~M=ltQQ YPZ8Y3|=`Ê.r!JF}E ,w^0^#FaH[s$ c((-Whהo$ wPGlRoQS))3#V60#ȃIЈWN͵Јbl:5i:5d0x7ЈT]N$ _NIo$xo#u8CYc-4"pipoox#_m9m JQFcoyFd$W,ވcu{hFL:ٻwFy'L&k *$_S.}H\H ,h]Jo5[IQ )'`$1X\-ay~kL$Dst ! 7_X0? $ٗH3 s)C3l+x07UJ[,\@ nD"&ڳVz,p Q~"?3xrLJ.,pЂ.J U$Z`dt!JF}IO "87xS#??F<)8DD~d>)a]W敃^ot !u'`P~i>%FH4hEq <-4?җKJ4GLNЈQ7W1Pڞ:57"Ԍ7"xKI(̣S}U:5XB#}Ku҈19 moɑqrkI0hDr ЈuI;ZD4▖.smE H$HK):!XlFЩٽY1aLs<$B,H+ÓrA Y{|߆h'\DF+s@GG5 IA7sFKh<['!}>?:w| 9H8++ $6Gc`$%~!8~m7oA,+ Ģ,h\'+4z~02K=htpk UBD_/Q4DΫHD5u@I7iT2≯3Ks]D%EQ A׉@wZʅIF_+  q$y/J*gO߼EE>&wɳ h$"H106C Mi4! {S(E|@Ni%F%$cqOF,FMNI4U{C\_F -N4J `J@xĠ4"F80zE)jF"t=L{=f )1HЁ_W\%H]I%bhaZZ>0=EOJX* v䟏GCܣnZ?,=HQ.p#nUH^ T10LT,(% mɆ5k|c'b^xK#G1tŔifsF)K#2K҈,CNͮ7b Ӗ8piDV'ވ1F݌ fIQp@ 2`,hDhhP=?qhD}C*P$re8]|4"A5⊠i%qFLzz#^\sZuJo/8R;~|*#]$^8HN #PנK#)G]Y߸w{@Vq߼=߶#ӾspҮ{ힱss{мw;{醳v3}2/ȋu*"ĉ91,8u (mТzQR7"#k2H.,5R K: F FqЈE;;=lApr"s?4"W(\ !F9M'Lwވ|><:87HU] F])ވҌ1SK#H%[F|bwS3{Xt%B1 Q!`1w-)p0NaGr %iـ1ԥ /N~)QPG`}EyP)5m-lϵ̴G~k!nq΃J{fv.ڱ(ܖ .7p5غkHcX]9o[`m9"*"7 dUY @Npn zA /Z9LC04 `C!li64k `IChC`Cp_Czg~kd  0OC:X8ޑ&DC3ip;J|Hh('bJ6RjW!m?'ɿCXYVgrd/BH`,A4"ͦ h{|OFujε?ⴇE#MJ#RCtSXFRT!I#]7bU`4"=$DfAEQ?UiWQ~nf5x\=K#R#A҈UxYZo$xŮЈFw.M#}ujX1ND`EYVp@,pXM)p0fzCiQұP۵AEdppGV< jb"lJM[^ SL34q}J8=H笎s>4s.j m_\z^/S5ܠzzTlmGP" .iDԔ@$xP kJ ݀Jp t iGr "Lw7F_on7k3Ӎ#d^JRS4?+u'PXeq~I bTXc7%vcl f;+r1&w὾bqp,ih#q % MeSAH1l*[6ů`ఽ ocBqޙ#N(\oD!{FL҈n3FFy#whoQ3-6c\1bވ4" &r4"υK#R[9*|kSзR{̬I;6I#R҈/L\1F~ވ4 J;5sIX (G[ZވmoDAC+ш;V]n9l_^1>s`2ĉ\NO(" M [-;r'rwў]3:/{fv/ %j-RVkJU_# oz(c@GT=5[TyC%/U%ȎJ  }MѦ¾®¶Š3:Z″0y1xM4x/N G!0 56kyw#0+u1͎.,L"rq4A j۸J0d3A1}`CQQ*Ny_(bS}0H+\e 4"x#҈h?FGB#>v2S.4"@yw04jذ?uj&GRrix(G#7-FL҈8iZhD|(UxmEoŚ’LSm*4cl*ӌ1TA?A]jciDP!R$å(ѩyOhmbr`a.4"8ЈO{#2V#6U5y~*ԨND M✝.V,}W%U bD*@ _Y]FK'\6X*j5|95`fQgƕ~ӚB||˖\lۮ̄CN =?|gs-V[/R5cLA b-[M@ G" SJq*@TWm$'ТD2J+|9?Ԝkw5666w6575i3 j/nNh` Ce ,O y 3ӃyFFndp٨Jp7.Ѧw@Dr$ aɸQz<*qƤviXT U gRHBiſ3j|,G c(فFLFIx#$φO?iƈ7{إ]%lƸu 4#>덈zFaaINhXo4"7K#]1#ވ1q$#ŭ%TJ;5hǜS:Ј|F>)B7?*>%4"pHMV87t?ug/ٲN#`ܨ  .U+Ԣ$FL`Ũ2C [J%H(kTk6룖K~ӊB|˺\l̄mC L?`N ѝ1{̡y{9jjjYk p-׀ 'yjČ0,2o㨄$Jt "5 !k z[r]-#--$5Vk-k-k5KpU~1N O8 cԻ܍a jݐv#` )KDx 2 A~z)q\Z (<"}7E>ͼR(i AxLAɅwԱI1C^DKqPF$1FQI94bԜJ#nV]jCx",Hͥ]xNͮ7b45NAf* 8P4 iDTw3 !TLOF Ϥє-쏦E]*҈H K#uj4"!cX#?n i$k;5x#=CЬs7SSs ~/8a $P R IQ v 3)}ĉY`MbZ:}Kyu OOM˷ʵͶL4Ծup⎁I'rwiӻ~9[b,͠ lNL6 vcۧ]&GOF@/V=? HmK#Hmp 4b-iXFԝ|Ǫ+NY88Hz#r1IkSseq(7A6' 8 ?Eވ.<i0 o&wjhZ4oLå:$JpvႽ lXވn3j4" ވ4l;Up%4"ێu`t#ω"Ĉw:ͰR p J0ybZ蟸E>85Zd-4?o~2߲4׺<۶"3aP&moީ{z ř}S8qvoZƏX?-HA.d=NJ"E"#DX%j *LL03acС C' 0}Ж ml-:S%YM6=l0}L;0F`NA:F@6|٠ ܍<Q3Ux$1'Fh$(J hh} A8Tpy Js'Y"ȻK $_\F$7\hD݌1C(ChDΖWtjш qhDoXЈ1$ `1HJbvqr9q@#r$nkhEL ;56cdu &&B#X~5ބ4"JS34"˶:8:5:F`ZPca)ԡS qULJ!+5n _pox`|'mK3r}`&m럼oʞ^70kP\,_7F",T;5\։A $@nՏ>QbkC%%tW"mD x,D̷vm<>}pWV &dvjMXhԮ ۍDF 0 7'o1ul0v)Eg]84A4"R "I)PD*PBQTL?,R$rDɻOV}:nH-b-A$F7".r2`n< .,YXS3 'q6h_9iD[`;5F88`A/өSqqoDDT23ވ47bHxvjoD1 VԞ'd#7!7 &:5t[eЈ+Pw9!HB!1x`_ܥOSV> @pxH5|^y_U- ?66Jb3~sUecuKm{f N<20ro䁾)ީCz:pp J1# Ar )1wE"PJ)-0`6IyFU4 3qyG#UN#ٖ̌*:5;ވhD7b xЈNfmk˸mHl Q\VxQ H7Pޡ[{MF҈:5K3FJ~Ҡ*{#J»ǚF l8NWujT- wv 4jת7bqmyxQIxj?0$L5*Z$BR4A N &Ѵl $g1z a#-1[7MHv[Z;mݙ~D_wE"pڄ;,x(VI5X8DC $%3k`%"z))}lIthPjٲ@sI[55}  걦YN(;T8dL# NFFqʫF,ߩ9I#rq]#`8SC8hMx#8֩9N#Gq aJYy{1#8pPш WG0jxo.}UɦrmJEhI3ƁTAhDtЈf )7DӤ%Huwj/Q9'Q V$50JV1@ J.8? H @a{iha#0nE}(}]y-⤄M]q}-S U&mw]~SoiМɷt7jutOE[ԀD${ e`vnHR³]<}- u |j*>m@$u34-SA   6n-oe[mSoSC Ά`[C!Xt\<вܥL?F5c۱?шNͶli6b|/x#~H0_#܍$۩7be7"ɸ7b oD>G❚i;5ӈ.0Nߔ?.܄X`FSu{Comk4 uqp”ƵD3('RV|xFhGSxN}HjE>5 $pŦFɔӗ4}SHETݺ{@y*)-W*WT>V^W1pݙz,`l]10 LZgrl|y 3H te,`?vw??paΑlY=I%BwCEzk#JFHzicA6z&Fl ۀ)b\9Hq2pbVGN/ffT m./@We&68Ԙ*rJoF&ˤτF8e:5ӌ1x!݌"xmiLxh\M;\%)0;ŁFO#FcO#~ш#F< `~\FSA7RoDhvj8y9 l7"4ckswaNB#B1VW(4qo:x"F Kq'R 2#1PDUri^'\E*mSe.'"kP"$ ^- @kD1c N,dWn XBuIBٻvg/`W8}a>ہ¼ӎg#%D~Օ>aw$6FFl:`ˈ)_6ٰ9؀b#\$egYK$@V b*x1EqYq1*Јd9ވ.$o-$"(:O |[(E]R&fNrc@3}IFP@s*ߖ6DXJ>h! @ ,jJ%ߢ@ rgfT EVtÓB2ul냋6n/`䟿?os-sw.)tHElSaۤ%‘A#v5M>qsz'Y{lf B$`@B߅  )"` X"X"WpBi%~  ZWAVFuKDZ4b7b F$ B#. ;5VˤSg8Hx#V J#J3F8ȵ-7"44c\^ no$Nb3FS34"  ǼFq`lOވVS‹ߊ;|4?&-Txf*K#d(,U4"\4"Y!\+шTMcI:xZI?rW.J ;8#:eKQhjZ$w{qGq꛺ 8zslK*'kh+ڢR\12dBaJ;#9-8 {VkQ~ %(H~.~@I'̀`x%`k E%ࢋ/ۊʕV/e[_ο_L,~>hHDhmw6466w5755oo- [ iDD4hA ;D@ zAN (h&6{Upq#Ͱ&ŃP; "뗵FoИ7"x#F|x#+z##\3Mtmq1jUPz$( å_hԮoEq鞂 шzw A*p9>{-&vjF Ssyة䧍qf۩s%PNU0BlgN\qGtfK#ӈ[78-xΗݰAY(*e6L^I5ȀK5ίGqѯHb A$+!*ʰ^"46?3;\l=?tq` 'B |oX!Jp,A;g,5lW?_Ŷڿ,]"iC|?|30ags~wN7MӋfŐfcc( @6Ԁlh0_n3ؠz0b `DY,Ufū@XTّˋ&J)xq`iD^шho-8n0F\Ԝ]oDi(4ی[)FtiDT-U폤Skz#.ofUj+Jވ3 7N#\MFqPF,n% [Ȋ$>YF썸 v@{#(4Qш"4e;B%ejd$'O-kuA NJU9٥\J{Y@ |~]3櫌A#o, O/HT4`$z0@XEh/ <\3\l$X{ye/ |qm@ }Ʒ.̅){i\ۻg[d§؞_ܿf%a"@/JJHCk0Ԝo:Zh;Вow8lԛt`;܀#):@6'H,Ha dum{DؘQ80e ,> š鍬 jM9~'L땆FވI!nlFq0ցɥވ15tfhĝiDtz#6c҈EoD80NB/kCL| \o/y/S.J;5^)Q+}4"0 ҩjqGHTɃ`VcaЈF\ߒA%[҈Hd۩YhDhCqyVt{t4uq0hĪgK*eA췩*!!  @G h`>«ccqe SBfba`JwFsvȼg7_䯿_s%/ {y+#%6 ,8-DvKpJV1cfi))/˻G=%hH= .M-XDÞ !1NfL DZrC->ݾ!GZGe+t4ɦ!;ÞAWZ"  PDȗhi1P(L4$z2 nah9NS$e}(*Hv 4#҈x#3jF4"kFao94b҈.ppD^hS_4]\oT={Ɠ&Hb4"aK#9F0hDeaS3砋&HspbhN1I#"~ҀrHBD#r@PzBoDDeEpZuI+$I J|9ePX25 N3*tQ HČWɮ HF)"@E`qK$рNMOw,t-_FaŽŅ6^쯻_DZO$H)I'qJ}Ű]D%J2&$ "(s@0O$BO0Օl_D8A'z5פK"ͦFlskD@> G`'N6D@1Yq@@[ ,0,| ?xJѕӏIc҈^FLF\{;09oiD=ͬ74c@#1<\3FF:kqM#SW r@mtjNo_ވNF4"ވi4bSs)(ELI I7jUz#4O)N'Y 6aLT+ RECIbBTU { ̢7I´ iO=u qZ 3f$d wPDcogS]GO(™ݨEHwB쵁##.R ~JV%h H@/t@(r' cgc%4DY5m!jl6m0$i-6&$"$}c #&He@",b2 8# | ׄ*&0Lr0kx(tj&K4[DRnFwj&XEz#&Fe!N#&1҈G5pPB#f7y\I4HƐ_3xe)H?qhD>K#ԬĩO ?u4荨i}GEFkZ48郘,J RT,S pQǹVp0gȔe$&hPF+<|N (ѲޏД>büx0k8+sJ@| s B! -^KBA=SljA\mC Rb L!CbI3g%nO 130#rz4P[o !NlƔg%+`9sΟ׳>ܤ_ ~(pO J$jN҈82x#.xl۩YG{҈Eor4"$,nf^1\3ƍ-0X4ȥ}F vj//-: \Kp=U0.$!ʨ(iDFt;5 @n@K--&˶`ƅK h+C#iSH%L!UEC9(!9J(p*t# -Ay$H7Hp-m8DNJa/MK'lH#{aTCo8p¤BB s ^Ņ"ЋE$7%2Hx[IZ=Y鶂d%q81K N38Wxv֧n/ VnleRU:F DHC&@9 $`,ȿk0PJ .#ҕ{\ZIi4beo1]'_K3djfFD]ujNkoXJ#wq-p`hD-шo2GI7"1N҈D2gz#hD N?kD?QX҈ ЈNf<<  EH 8Xru)k;ʌUb̏#R K* g9PǣALdUgPtS (Яl84;Bs_eP{P0EN V(Bߠ0KF ś9iAX%dCm4 nr`f 3B130%җٚ&zl#`_+$N`5UKlEWI0"JA42?+T+. Ғ}4;l=HTo$'Њ!m.o24"Zz#bA NXvrhuj>q;5W艼ЈwFވ.hH=R1jvjFHDш82%iĿ4]%mTNHEsiDR+FO( dQJF-z,K/U 4>Ȕ_M#'%v# zPh>4 M G-֞lk_m0L2l%~Jg;KJJR%HkDXb TBugN mIX tY@gv@09uce1j $pr@ Ŏ^3e8DJ8LD-1Qm}m`XA>O7 F|vy+njFDMrX¬pcҩz#l}f$1VFt;5ʨp["no'SHFHz#hDiH*ĥ\hD TSVk䎖z# N#'bezNS S T8X`]Ҷ+{q]t{E!? XL79BX4nM ͻ-{s-smG3& N x Ƙ(:8:b *K }hH*=Q܌J>Ox!*@4&i $S bl L XTؘљڙ Rƿd5_~w'vc/ )oLZn!L⒉\ Нv9%PX$ЈwJ#^ ط%Ca3F>r-4"`;5F8S34mȲOD P7ވUiD>DшLC#ғFL҈IoJ43S_҈i`W/U8Kj'D(*˂Z4A5E4Ҩ2TB38[1 "6 ܢI nghm>X4<477[Zwdvgf&j?<8c`b}S2EP( 3:GmOvU NTtD%lJ br ā:fpB*- #WP )u2ۉ?3%ʀqL1I.XBϑ4'LoLdR`Y A%VPOtjy#hD\#KuhĘ7"%0 NJF8 \Q쏨E}YQKh{#単J#Nhg'> 8:XotKipwjࠣ-I#Ƽ4b|4":8. h9Y%˜TAPA%_q^ukt\ '~ [gů};LuF"<4>7.W[VZZ7d6g&ls}}O:?oJwԾ=2v曫=\(=Q =U Rq(Tr 1:#:^L|'ssX4ӹ&x )/Mn a8 Q9OLi/)kNi/hx0h|ozм$teYlLL L?ig=}SN9;Hϴ=]f uvؓEj$J%k_àQFa/~~$̸+L(T{$H$]V|O EHؑ׈8W҆ Ȕsd,xy|FTd"koOA?j4v;-~XhDDވçvjNQpŁk-:Hå9[ 1iD1ҁ&J@ihYS341z8:?O4ToDY7C#A:, Fc\C p]E\M Asd^n^B +3}wR*Bӓ幖ٶu &lj>8qĽO>W% LvSf#qp,l)⽈_?;b@L% # ыb1,nV(0Y 3=bH6OnF6V,S^6`-E`I^,d"(F&J[%~%4"G6;5vjw(+jXnToaӈ{[s1.F#:5[oįxJ1~B#ZxI4C/14" m34QAN6P7"M#?F#"$T,ވUuo88)S 1`UEC9Pю^"} Q H dH}#3.PG3o1SIޱaI\yUymeCusm[mgfž'o=D8K@EjmXl?5/!|`dys,;ƈ#B)#P`7 l =C Bݙ%OA!͍o6WUҝQ8m2 p \(d\14_T!}m?7C#r4"zHQHRFDY6cel7"G'#6S⍘GM3FFchDz?ވ,֣fgYPNe!S3]F7bm4"Mӈ4c$ %KNJSs&lH,\7"';&{N#>5A 7}*d\*8;8<3@)R䥄p'@XcdE.͟}BDQ+ S' @X- ʆ2aK6z6 W +rX \6.T;O2Gҩ u!$&%-cF#lg[p^ڊіD#j%mX1+tjvjoT16cLz#ш<@TcζB#^ &{wG1x O hOD&^0wXڀu𗣰_țwA'I '2 FOF @䆐F-XS&%u I@?K -͡H: ׄa"#P!Fo`"Ha 'PݏߪQ |P}JҞZMA&Q* sq:Or4"u &=%ވ$tbWFL҈x#ghOaogElq@ЅMґ8Ǐ'z# Gcf.8oďwMЈ1fҩ١㩳 -fF` ɵӈB.84"ť)ĉƒ_ FA#qhDhF$r Ffh"4ϭ8 -s0 )3BG%h2pJc󂿊O >*eb*;w@y8`[0Su V; h'V} 3KVby]Y(@1b-y h0S:5(fz|&~M^C :AFm(/w:a6x lܐo\I*$}bwwd>tj&8a+٩yTވbvjvJjԬ?T:[HN9uOԜFd‵>+~ QKr (ҁiD$ u Fc1A#b3*4"4RFD iW tj@#(lx_Wct^Z Q "X*3)HƁ,V %`D,}e+!-36Q ^_1qT] n `>CuJ8VN@+\Z#$` n" 8,1ݬFA%!AYRHb`1vOB$H~@H)SN?A6C$7xt?ɇ IJ#:5C}NA(.U]Kw FLz#V\7bY|GZ D 8F$ AC]oD1|D7L#b.e2\J#/biDsK#Hgyaϓ4P%1ҩN# Ya*:@A(m?%-:T .2HZA.! /VS Jح4T ! k4 TBWڗbH+X׫T {?1*aP4wKDAR?2rV1@1Lϔ"hۗ;;%hV2`m.y{8m >~HvAQc?vO24"Y"(Ss-4"}4b-{ih7 oĐF#u(bx4"Bz#^^h!874m#--HF7"v84[QދԀCsP@|L}U pSso PWXz)b6cF#\\x]?JvjF(I#bTA҈*z#FXFޑE#ҌLfK#BXzxѥW^qdрc/x#6F+7:eB"W"H/V%"@ҁHp $P @  ^qK%K@!P g"Mawа/h<7)l(4w{-\k&ۚD+%1> nDܪ@Pr !X2]1̹x&{f`wI+MGԇ>>A8?rD} KzVQ@g xe &?}hF㰝)=&ވ5(keO}.Ff1oH!@7bH#/O#5EDpPq44"|kC#ctocA݄B4>F˭D#^XNE ވ/*vjSf>Q"JcLhtM `Gd^ы1EdVm&3Jy+oP >4l۵RӞB|r$ڙmb֟084!}VY^62"ƍLAG!(Iy4 >#Mٽ(pZ}Y :8@'q8ߩOG}~N3y5g=@/QhLtRШ]:S9UAR"!}c@5TDhyX͑ 20NfӚ#hƄ7"U6cH#V\F ӈZ"ވD=@5&1HO7r4Toğ5rt3' pU-JN͝mQhD\Aqtw .X:54b{Oy~IT1%OIC &]ĺ*%c *AP vT>aEа:h\77&͛[-;Ol>mv83ЄN;8`6lv߳& k h3RMBA<8jH\IZbFfpD'؝xh t\_ 4qCOOy(hihKRC#Gȁ[rGiDZ?*F#RAf-4UE),FL H$4bM{'|=Oy'\s ^1h^M`9ƞb[U復˪x/X%T\B(~+>3=Tи4lԴм|Zk٘kݒmݖmۑiۥ;?M7~pn4s`Rw~aZS 3pz7a|RhHQ d" h֐0 Dx/ߠ!PD m|oVsu˟o xT"3$ '(b$8ޡ0xީ?HF(w~IF̴R<2&1^S3GTRHcSs-ވڳ6cL]8h*h@䀃Tnvj p0-xQgbMn#T#iiD@(յ4" 0 +hDZtӈujTOgPGK:N].WX b,ed2=TD+δ^}]{_5_2KƇGM%LU YC*awm_f G;{%Lj?~4{9?2784/8 {f``[9 K,ܥRFVpT@@ ,0ޑ@4Pvh  5*SƛߨnEy0QHתeTo ~ W0 TPSf2=,\o.5]r3c'7XIi4"?k'^NdY[Ǽ]oDAi^q4@cfrQ6(4"9|S7"Ah$Q1kiES>vux# H9ȈЈxde4B/A#bOE{ṚI>%lV#P }ÙIEjwipqnqϔ63PthJHJCA#A~>ᄦ兦&.߼!߲9ײ-ײ$geڎfh4ghBЄ!=LL)N+t(t.[84p`LB"۹ / ^2XqM`Y90# nCR ,H^{Uw@7Խ @$@ Pp@o=ۣ$¿)=O;5KBqpwc5c/4b7U`c%u8Hz#"7" I#8jp҈ ѡ;5[q:WIQ C l_v4Up3/+k:Pb`ihaMа>hSддд@CR0%;-=31;{ r{Z۱( /ί4pYa+ 36π)TrF.wcw~D bj@ A82pWUXmBD`9UZ}mh%IiD87hD8c8i$ T,U: aiD $HNЈ?Ni4" F\9 i5biD vb4V^H#bf`ˤ9:G'w.ŵ0!† T78[(AWc%ӳUA$@V '? '0`야 ʆu\+h5!t)CSze(vw;:;wdN0i`w` Ɩq'@ttƾ 51A{H'ْ V1v&h>a8шFfoĿ*^)1Cq< L4 iPJ#*SHԬ%K#ilZhDiЈcBH#7"T+FJ\hDx)CJ HF$Xj`]DH܈ pvɟp Nr Z%!30^L'}S==1XcB0ً}m`b ЧU^&Ԕ/2 @уyyY@ FR#Xd ?ԛ<#F,r6*0.Ԑ%>ZD?AF'9'ۜC#fZ $:5rD>a>x#B\RpP#pP8x;5-kCo̸H#sM irxL!<@]"Twtup zpB-c$0;HC1a4 Ua*#u1ޮȊѶug‚ʛ)%8Jb8lpѠ ~%ȵYiL$5Z워XACBhiYp9(^#Ʃ,QUFDhĤ7:5WFDI3NwjA\B#~f7bF{vb1o=qs[|"FIӈw_D.\r aw4! 'XwayHԠ0O5xMyW+ <>̵vO)o{+L(K[@Jt^" -j7%6l&eϿ|YXqdJCp0\oӈ8͐>I5vjL#r nfJ( A*Ztj ,F@#D#~U5Ii6VF\|tj.҈ ?ιN#&`f5tA!6y@%6$#C4ưV3pcB .=Rx#e:("op7f_'7Bvo7څY} #U}|)%A1z#;MUԜzG٩6ct:5F@#Rrވ`x#`:5[o24b-Јx#$ӥc^F`F퍘a~]_ x_DDHwN;&h0ə- mbx@ףb١x̨0ROD>j|~drw4E2EI] !* ̜D^Fv@Bx"CQH Xa# M@v>G*ݫ4az҈Ҍ1F8P9M*FܩN55Ј%:5 HԯDNЈ>7"JhF\wӈ ϊ8ScSeu0 H{ftjpk8i($+ h*-JB_TWL/(*$mrP.ܣ<Q Aͤd"` 6IU0333C9maHtpFEcw䄑;XRI?ވe1RSsRhDJ-\1l̠z#fiވRNfFF9L&Gq泞5/F%N#VO$u0{75P!QRPB$3LìhvBQ" 1tPxw 439:I JHC]uNҧx$E*|S6}`*TFf{# ֩Y5? S3ŖS3iwF3(Jw6G O5nU6c:5Tg҈>H192ܳ҈s;T ]x8@]"V"Td@%#b(8De(v3)y 7%:NDP1KTH~2<9 ?T&LQ1n|H!# B'LLL< P/[^ ~Ը%Ŝ輻 }[z4PΧ}ċq۩yX4"9)"hD kcވB#>4b=]l @FfSF5౽s=<IF<&OKaŕ ZSp $' P Fhf"8Z!!B9(UoL:3K>|.}”?迒&qn H@ `tfi(!!tA#jooOW_yJTfVԻM4|०ѵ"@VR8FM7y e:5sRӡU4x#VoTCЩYӈ˶>:5O ;t9&uq5e>ζ.X"TTM @DZ4w `{^F,UG)0Z fFjޮc y,H|/;F}J$7D(bd<ǜFzʝ+z#j}9D3=u FzϿWwi7"쪴P٨ %±IR58P oazAS oҋmЂ!b C z'DN|&Ҁz`'7EHȁ L^ [ҩoF|z%ή7Ј(҈Œ2_S %1+d\'grj$ LC,]Z5h, 9A{On0VL|P/Uxs}unLRe͑tшT?1w*ЈH c'7"4"0 ԜlfN,38خΑN?SMfnշ~_X.S7AG葩;Z3!00XiOUj姾L?@RI@L6KR\1b5HG|e2l 7#4 W`@ @6=j ~U aݗ HS3r?:4">KE,XȫN%SsH#54fs4N#ӈuA<up$BlHB nh^ MIՒ #_\/?1wTDxXڌRYgj$rPڌة٥9INNͣF,G#??1oK ?gNuy6#WK3^9LL$+')d 0V 1Pt<# pc4b Ëم@E)[ra_7o,Ap02oDN K#BNN͸8ީF8UK#H7[,ވ]qsWn1N#_1ic +PQ"B~9;&KN)SQ2fJ 6qAoRK&+P"^=E0ԝEFBfҩSL#҈wшYOЈq|{tFstNӈy{aKF\x>'Hr4-UЩ9Cq`-*R@!iTFDX<ө9F#&:5B#x#6{#&hDp?Gw/@#^!wuGhĩw;5[:x !=ϰ.N'as=6p2>9 7be=G1bP (ވjF6oDL}ؖF\lG  HZ휺88Eē'_~N+PEHz# Af) F|C#b<F䍈oDh?Vqž'9ҭF|jH/:ߜQƒ0NfS4TԯpJ$m%@ qqF<4bw[&]oDK#ҩAGv7hΉЈҠn=vg2W.NaoO+P"UAcU#FOSo6ujFsDS3ވB#>PSsEoNo{dh%4ⴟt/Fӈr %B]"ԯpJ$BF$ q>@#"8y#&iD\\M3Fl,xoNM-XFqOw2a/J~^=p*'?O.J WD"S3Fd"$r z#F\YSfu޳M?UFӈW]v¥CSsFyx2Ncs>vW.N#,WD"0[Q:F1%m^7"ЈNOA#>⩏zSg=UL} ވ.ȹYqރFt{6F;N#A %B]"ԯpJ$B-I= #tqL?qQR2O]c;N#uq(;Ů@]" )vS?@:)it?4y7=%m3T-ވ7V.?ѩc4bJfQ*zN>jկqup..+P0'ԹQUz^TfS3Gӈ[+шQ&߯>excߒbވ:xP>+p|@]"%B W ƉN{t쏴"ވ⍘?YM%Mgs xz.oR \/MjWW֯@]" N+P"$`/ԵL#ST7Ј(4/oTCoD_Wu>@կup">-\`4{Ki/VtjވO73Ge-xzmx#҈w,VbW_~&+p@]"%B W n҈54bn]K9oDhUx#ޭ~oIJ4eW\y o[N _up*L~JЈ/uhD1QhD1i8\q:o+FFzFS]5x˶N~?ׯ8uP+p*\ _OWO}S1vӌfqZ^]7"4KyG_1ϖtjJ8'C4WE8&}\'YѩF(F#OUN͖F|4c֩҈?Tozg{M}էߦz#^Kq8_quQP_S Dמш҈iFhm==)h:5_\?:q5OX\D?+p*\nOAO}Sԧ=(lG O{ 6"oDM#n)lcB#>^='_Qo[HQǏzb7(TEB`D,I b!| ( Ð""SLZ4"˖ܖ/;gUMY{#\F|4$%Cy=w" Aڈ4Nί㍹cOƞ'5ވFa cBi#acM{7FFf\,V6c65]s8lRԩeEڈk;W LAI{#a+{#b/drRKPHFz<̻}{zpboF\M7Ё#W?+D~3وfafĈǬd K{xrčԣMF*j 'z#:lģ% 8ٳOyH ## @~FAyqFYWut/U6bn8#Cyo_rE%`?'5l&l /Tol6Nڈt-30 6b6cP*m˨LZS6 >08%TB(X]z$@H@l~2̉6bEIF#qJڈvާlYpp6[N="_$@$@$@>' |~.HHH#7 Fn    Ͱq(IENDB`xflr5-6.09-06/doc/latex/figures/img-49.png000644 001750 000144 00000033665 12246405674 021357 0ustar00techwinderusers000000 000000 PNG  IHDR`fgAMA a cHRMz&u0`:pQ<PLTEې::ې:fې:fffff:f::ff:f۶::fff              :X(tRNS@fbKGD- pHYsod5IDATxyƝaiVٙĖL͵^k' IE n-Vo<[ʃ'& \+z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z E"z Ek7g?9B7_8w >ϞaLZþ>}AJ[@{W]K +t[^ V?yK +t[z6x\&2z}g9SawKf%tLZ1~_5;.=~gS O<& ym ~Ll)SVF;u鋥=Sa[gvZq&n$;.JaKY@n$ϛ -[$O,υBKwqU>tn ޻F^e ~ ]D/Go7}/'B ]mJ`Ak_{2N~|خ܁K{{ =Rۄ3Vh,_up _Dq]q3 kzl| Xp#z -[ӫSen;:u=7 ,95o<gI0}zreb] +lg흸]$:;2Esfw9gopߙ~O?c3VhKۄ# Wo]g3i)ЇM;?=7>f +h_\g/Z\tolשOLZ :;|e3LksϞ6<]@O,7qŹ%-b +dW{ced!9v`A:%<2|8ԖGLZxr^{9=us]1~xYy +`O=S|>h@KOt@/=@ ԧ3:i:i~7=Dg/۱|-刞Bw6~p"3Vhz2'P tGLjB8]>F/r)ֻK%\I=SafM5x7c:xz`sf};Z G(x3'AwCۍ9ӵ1办BsvZQc_xÅ*1q.Нoz祙[H2A$+3V(zOK9.K=SawD3Y9=SawD31@,ZLzz hNjzWĹ# wDCf%Ox+ zO4݁+חIu/u.o>@ÿDu>/O?fb]h օ@B0ϑ4rȟr:kDXiCocOM`wytSĒ]XWA#ԇ@WKbxtޗh օ@N<~@wLJ ^KXD 4|Sׅ'_8h_?z# :p͔:8lo7rhd_]L4l?%G+}Ko ~o; H :i(?,lӄ]xwA95S8=qד1}zi£4wn=6y瑣 %/G.u1H~_k'Hßmw h ֥@} N׽ }~? h p}b tzH<8cDF6` pSߌ:]~0Ѓ[BB 4k2-^-z݆Ch 4yoؽ:t5|UG~m5v6.-t=y@5zvtB8]y@Ư$<Syh&.wg8h^;:4y4瑻-=NuU39p؟y%lջ#v@P : xӷotzyLX|6c7?}́Nb|b1Uv6ЇP.o}{Gθ]@ 4l8~[zS[>>Qht3 zc{BOx#@ m ѹoyss_ 4B'C,K;UBƣ DB>s-W6{ǖ@.:9"]aw߰=qӥO_>h6#ѹ΁܋c;$u4r7" 4@P P((@J %hB 4@P L P((@J %hB 4@P P((@J %hB 4J]?m]cVR 4JyGnOpO)gO覼=/M9C'zq7 ׿M/_Ҹəx/GﻬDW}9T7gCTq7, ZV#z7E!ze=zSz @!{I۝^l췿ẋ+л~8CoϐçMOj9peN;|cO\/<,@N6WEoϐ J9AU!cNYG{8 93da3}C[c?П7Cg} } |Z=hkOpDžy@+4s3dy3e_]yF.v&kk;co9F9pqC/?KΟbzdZaǿذ }N[t]x!@!Ĝ]u~Νo'K o4,Wcv9ql{S#|;1gvOZ)#g!G<P@o} %@/2@< ta? %m@w7 ~L~lkz70O@<.@Y `| ! ^'АϮm@O#ऎ3~ :!M,А0cwӰ =XvJ30Nϱ{ޑw!m\-zxlwmTsOx㗱tL&/h@=0=m+Gw]anP krB'#N)詷w?.gLܺ@Lr8?cw77 ?a"SwEW }ńN֦^ t3lqcs;$З\g`DuΌ=Н"o@wS4/ ~HVM=}>=uirQ.w7~ ;5>$`s__6%]*v1='O|.=p;>_:a3a;>Knt/7~@wz_ގ?w=V?nSu@pwc7KRNoPe#}Gz?@O : }5dr%aow=B2=\}{3]fY{;R2yǖ@Ogx4lvtqӥݰ&~6÷Һndd͛AJ.\-ГXkww*<J|-F_@Og;F3TMnv-BC)Yˎo4C[@C9QKh(@i &-?Nݠk?j@C9=7]"Pnm 4C[s %G~C# 4@~: h /qg7]r"@^SK}@y tOh :ߧ 4 d@gO2[w UZ9 mgp >[k(J@h}*@3P5Z*0 a}_݋jm쀼V{h ukUۃ 䵦@ ZQ}z@y'w?YV_"@^k .h uYV}CIVGݽN.*@^qwh  4W~䧧4Wہ~[ 4Wˁ~)' p ng2k6O2k5}ȫ@3P6@ >-h1 4@3І-@+Z >h, @3Аgz9>SC. dN,@f: dH,@nm> 4Y. dB@5B,@f> 4Y. dV{@U,@fU,@f5< 4[Ł. dVoK@U,@f> 4Y. dVgK@U"ZhJ.yhyV@3Zը, G]g`E >kRSXh}V@3:>U TE@:,@f> 4Y dV|@z,@fe,@fE< 4[Ɂ dVp+@,@f> 4Y dVh+@,@f%SNȫ@יgr+/еY̊ t}h ]oȬ@Wg dVV3@^EZNJ >th}*& *% SH@3@g# >t;}v/ @gr t;yh @g2 tS}h @g2 tc}h @g2 ts}h @g2 t}h @b,"MYhn d@7g2{t@=8 Y,@f t}h G> 4xl #-yXBG@S5 ZzL`Z{D`Z`{Zs`ZkWggWgrcWg2_g2[Wg2Wg2OZa.^c^g^i,g2Yrz}h ́^q,og2U^r"@^< 4[@ d-Ы@ > 4Y@@ >h ,-}h} g{9 pZ@3h}sKn>@3]->@Zh}nv@^ckIy@y->h  5;KfZh 4ՁK@E ue2.|*| &|hy@y] >_K.Z&@^33@3@g8Z"MZBMZMZZZZ 0h}^ʥ@N@Rnd5>/nv@^@b '}^N@-(?:u7h\Th}@esßi`FMFtV}@e6Uo&D(tcϷhl6ݦ݈sMF:.OBHt}%Dl$M@e6s6MFۤ4Q6nFshl6(ܚ@G <|9LMkIsM֐>g)imy3+h`;N߀s!TO[ez*ՓVI>PBU'ϭ2P=yns )TO[eLz* ՓVWݸUFg'n@CíhB 4@P P((@J %hB 4@P P((@J %hB 4@P P((@J %hB 4@P P((@J %hB 4@P P((@J %hB 4@[˖DR :cْ4S!\'z,[=fJ5DeKL@slIX)h=-K3uDz%ciTCNX$z,͔j4׉˖DR :cْ4S!\'z,[=fJ5DeKL@slIX)h=-K3uDz%ciTCNX$z,͔j4׉˖DR :cْ4S!\'z,[=fJ5DeKL@slIX)h=-K3uDz%ciTCNX$z,͔j4׉˖DR :cْ4S!\'z,[=fJ5DeKL@slIX)h=-K3uDz%ciTCNX$z,͔j4׉˖DR :cْ4S!\'z,[=fJ5DeKL@slIX)h=-K3xLկ'~l񼝓'ro8WE@cْe#}{o^ N\f>z˖,/=@@'.zlɂov#+$Љˁ^:z,[2SOGWzoFeKfVx=Dz%_AK6E/g%tXd/k%Љs޾O Dz%_|^+N a GDz%_|^+N˕'EeKfV˖~z:q!9#g|ͅ޿tHXd}Oé٦Y3yػ>=zAOo<5{Xd ߝ(ɑhuQ_ݦt@r9s97L3>7&Dz%^=k,+W)4'~`ۇ.ycْY/Ձ7ѯnS:q> ٩“uÇ ?b EeKfzD:m@')O)p7կG ?~lɬ@Ϝh滁EM@? >0xKakӄs!uLJG˖~nD;_wg:3m@'&}~'NGN0}Jǝ]:5Þkpo@wq߇&v)K}B@ŕL[~]K5+GnnS8vY;$1Em)n=Rd;n,!}svy;w5SsB'C,K;;- ~4̇o (-ե֥@wO]t%ao'p2[?s!G>*ѯ.՘=.:9"=}w|;oԻ _>Zo @tu@K5^luűOt:Dz%Lzɽ ~uFޙ7=-K3"DOzLSu^4S(BT]@W z,=UK3"DOzLSu^4S(BT]@W z,=UK3"DOzLSu^4S(BT]@W z,=U[=-K3"DOՖDeKLS%cْ4S(BTmIX$z,=U[=-K3"DOՖDeKLS%cْ4S(BTmIX$z,=U[=-K3"DOՖDeKLS%cْ4S(BTmIX$z,=U[=-K3"DOՖDeKLS%cْ4S(sy{wwScْ4S(¢}{o>˖DBL/=@EeKL'FGEeKLsWx@˖DBN-=-K3"̝Z@s=@cFHE%Иic 4fnzZX!=@cFHE%И>лfgC^6OڋK1sz a~w_z֟m]['~V{]Oc3Fpc 4fn t:89\I)~o =@cF@'}9%;WxMyXkViۍ@LT137Bs i>Ա`]k:=@cF@z#|O%hetꞚBG%И{:=n|!@N h@ 4P(hP-@ tMףLK1s#=c_TX; 'E%И݅*5<)z,̍P@ A37BǗue37B<~:>nG??;hY:CTkn x{yªNK1+[u7Swc 4fvdYLu]X] 7Br]GTmsD+@yPsz쓯:c+z,,P^@Duy+z,,*ӝ"-}hLtZ=@c֒D%И訵$z,DG%c 4&:j-K1QkIXZKhLtZ=@c֒D%И訵$z,DG%c 4&:j-K1QkIXZKhLtZ=@c֒D%И訵$z,DG%c 4&:j-K1QkIXZKhLtZ=@c֒D%И訵$z,DG%c 4&:j-K1QkIXZKhLtZ=@c֒D%И訵$z,DG%c 4&:j-K1QkIXZKhLtZ=@c֒D%И訵$z,DG%c 4&:j-K1QkIXZKhLtZ=@c֒D%И訵$z,DG%c 4&:j-K1QkIXZKhLtZ=@c֒D%И訵$z,DG%c 4&:j-K1QkIXZKhLtZ=@c֒D%И訵$z,DG%c 4&:j-K1QkIXZKhLtZ=@c֒D%И訵$z,DG%cI-?A %tEXtdate:create2013-03-31T17:10:45+01:00R%tEXtdate:modify2013-03-31T17:10:45+01:00#xYIENDB`xflr5-6.09-06/doc/latex/figures/img-11.png000644 001750 000144 00000060210 12246405674 021326 0ustar00techwinderusers000000 000000 PNG  IHDRO`( pHYsodsRGBgAMA a cHRMz&u0`:pQ<_IDATx^ Wŝ^ޙw昜{75bĸIT}G FQ"(j Ⱦ4M/4;4[7CM5k>\nݺ˿ZUWUߔ6~" Dp!ۿzR]]}ȑ;w?onxuuuW]um۶'N\zݸɊI @$G@WVVn>;wn޽G~[@Dǎg̘f͚*#͚m#E# Dh.[x1-//oǏ_vAŴiӦ"&Hiy7TFI N-[7ߌ=5:z)Rs7i$tᘖoo'RF$I{.zsڴi!CpaGǝgΜSb[Ϡ&¶mny2r¦ UӤAspޤNFԞ%9o޼J<:ARX*87-:GbhRީtI4#;#Q'#5U4¦ G'tˣH#({n" \Tzp֫(8oAGj)lhP1EP<:7Ǎe0͍SKTYe8`P:t萣 GjnhHUvNxtBtra/\ލhҥKFlFzԚ cۺ%?m;.Wc@G'DxtrmgӉ<-|P4YfH,N X͎Dj1lh LvNxt"U<:1/\PEalأ Tn C-H d,md0NFJ ƣٿ4^ǑbqNfK.>"maAqXJJJ0JR,t㓀ݣDs 4ȔG'zvbT-DXҊ+bG[h۞шB*xίZ<:z7駠ZM٣ubPhLnNnTHtEj4r1C/:DVha+k2_4׼nOOC<)d|m45HX$щhNcKǹ 504(ړ'S˖- K >J|7u mRNGj4,{/GFKщ]xtbvB_,0N%bY%0ܩpS v!qĒfРWf 3Ry&;)9:!:xtFwڥTʠPʂRiM?F@iJ:\UzWF^HgE ~Cu Rha.z;m޽cжnjh]j٘FFkC9ŶnЌ3SL)RmK"'0U+9SقBj5)q:U剚ըQ%R~z+N a$@#D'yA!5 MS!Īj3TgKT:Qo7gz% ݣSF7K'Tْ y$dlviy\Po 6fX@N+oJ@ ztb'f%{ǎN99T4) c@XvN8J&"ԀDÇ;? ӠPJkpfOmXb4dd\6"݄yIH&G'.)GƸW{M/0^xӚe]#h`Ji~": :LJ5cOZBnnOK>n،Ԣ3+I.,0DAnrԠّFjij3_Gmytb`4!:sqv޷oDXEuiV]oAQ[V$"e"8N,_NmFjWD> ?`\2U9?ʣ70s=pca,iRF(hhR*XXNn6?#5uGjh6χi$ [4َGӛMjspZLJpXe)d߿XRԨ ƣI6r&L#xM'`8?Xxcy=͊8XNE4R̈>RXy24T'RR݀:Y te8ڊ|NR;/ԇd?psWpg+:+LP#F`0ǢM|yȊ#H @ mU>R(jIO8ʡCb\'[1qD:~~ƌ<_Z^xiSuZ%# ˉp|.гGj4㔡N~ L^l*0_*v]huE1oy= /WLynDjQu"9T'M&4K~~S|so{ڄX3DszEo,fk9 3@̶L8RtR|ӓKِ!C$ͬ$}\~}_MmB6q/6XuS'lGxڟd w#is?Iڹq WSQ*E(#҂7]RRmJ%KcȢ_ݗrv7S T'r㎐ 縇It2X;] nL7yfk;`M$xBpg}zh>e@A}]M?S 57͆.]v{K*l%wfdxr:9L ~N5PDi3*.  %ʈWAzًqG\6>3Ԉ?=+a-ƥm#r 쪛+|Q]9,qT=0yWR7PQ<|'MD*ٳG  r +w|U.lH$Ϻ+ؽ\IǧR72aMW^ U1bFC(;aD+21W Avpsa/ Hµk^uCxj&H\X n#=+ yۊ-SSSf*uSQečQ 1[/FmGe#x*ߥݫ;,33@Vn|Hegؒ찁sB#5'hMOy &{FbfXI1”)z]?c6?g T I{ 9xģ9pVJ;QFqĉ ~5{}18xS N}~˸XM2Gri}s9_Hݻ7ll_FͫQA=qGpa: |EOaa3tP^r 뽌uE2[1sD"agW*cD$W9"5jLZQFؓ?=h(wKX>YlItsUY!,r^S~6HiW~Rp]J8uFA =AgaNqy  0+`Ze露H͈l$^n-pP 8bSqٿp6#5F(#ܵޝbY]U&ջO\|DyD-jb#$crYN<'+(޷!3e o-A$wg3R(KD''cذatJεϧ UZ4eZܝy. olx:"n9;3t`lO[aW^@NŻTfC[ ƤQ%5*v%BzU^L[oJn4)FR7X{WM9Eod~m^mia]Z?lVk,7"sjúGݐf=b=6Zo"1s y#5;',MzeMyXooWt01:ԄK.1n =Йb$v ZTBw)%M]<O>ј6֟X'%?3Y?Uj=z9hH^9G'(IڭyZ=<2b&jDtgA ]v)i8lh)Q{Z (QcdV1 =C)2Dǵp7-[4ztbVua9>$P[Z ޣS})k(%!^RFp'QF2rR\H 95&ɋ*ĶK|,m_/]7'+rzjXW^1?˻Cr[^y:Ҁ(..֓8֐RW)QFZB"0dܴi ʮmf[6,.of ,'ua99rV{<}!*(}%I>hըСY`<%@v\|Xю*7[ա=<ةS Ǝ3@úYiͬ$Nv8<T!E\]JZQF}0PKnycS間9LE>+mv >'VC Z+?¡~Jo"sT8amMb@l/^i$jT ;E]u'ByG<֨;N>Z8Q+H8Qki9 y .)-v`a|΍7i ´ F8+^UVСN1Z Hcm^܇rsw_~4{eenըDqvxHڊ!o*duXOKs:TcX qY. L+80dF[\,uQ_/F1@r\'F3w/vQߡkolds?:j2Ok;GJ\L[BֳJy2Qˈ$MP"ֈqP_`^-[1зdQ`i%Ѭ2G,_}13U耩iz΃>ȏ<'Y @S сp"sF\53HVdX7}dg`uȑ81"Y@ wܑ!VN5Ci¸9#{ ,b4$3Ws]WwSEjl!i{ȨQJF%f I8+Y!#Dicp'2 $M2#L100qKVJN!i$;KGNaO{@0Cu"X~|@7WvDzs瑼 zh\{mi׮׫t8LR5*' ɉߝ5-l `::"qDv)>ab;b=hN !`m }n:i=p͚M937?C{8e1u03 s &Df:Tw>u'\֫׊pq|ĈNJR{j"=ٟ@Ǽ7]6k;ƪUT$,sI93*(X1Ä4>'e^p2YYc @+IbVUIEŲ3?Cێ {hq۪zqX;v 7Z~-G?x/ܠF쉹e:h 0FHj&ո#MǍ8螒sgmw9T pfǀc }Ĩ|(eCVHMG\Xc9~X#G?Ж-O4k6SO5<aw Azr|bď; b98)2(ZW90;߸#qs*8JpX-,b^٩y.+&!8Ge\Wu+\[L(Ñt \bcS'8iL=v?5| 6C{Y|IV[Zy]ӯfrq1itX4jqs'd {%6Faͅ@N!+ρ`8F22j)dC"BiV )rGMuHZ\6W+Esx}8Gߞ_ms2w^35\ߪQ8Hti(dVc`{>CS!g3˿1ZSRROWѧK.HƝ`Y\P`OnQ7/Rhe$pI'Oc?yo""͒pux-O@|RHMN9j0KZ49L͊TkC$cZ"Ϙn'kGj0m ĘΫ??uqKЂʝ.ꞛD@ vVُ?u?_Džs_Tʁ;O(%kR8ML/ G `ysXW2N8:FV{p~nhGf]~H5/NH'4KBf v)qΝnj9hК/C~̘zݴ) 3:=1]uU j3s[XB7mZX$jKS,{۞jo͝mwycȐ~h+ PK7})lq5˳E<~+~)BKx.[ Jk>>O9)zm@Ccp1sLSTZfT3o{J]o1,W& 튎C|X\- X=5|-[ʛ7~ W_]|Pjz#>-}iżph.Y?8g? Ba4B҉#/̱ 3 O[f9h|b-7@GC`'QWkݖc]H﾿cNJ>Ⱦ?w 9~g ϲuriX*^siGg) "/OtvfOr{q* ,[̠QGeH75+^sŮXQK+z gmrIc#5Hr٬~4e.ԧ8"T hm_4gŗ+%iK72R7?ohcAf(5(phS\aH<ɋ,u#Flxz?73htVNꀖ8ějrdn|DV_|E1d8qg7]b$]}|GiG-x!PA9V)7\bBcpڱiӊygCV?[P1{vìN?ꦼE[Wnu*fA(BN!qOzQiQ@$NXxjw֛5#+7P =.h3f 5ŏyVL|n$*xk:}pݎ/g xM={6fafU_]7p`ߨ'l+m3kɳEBu)1P82d_hY]3KȐdۇNwWϴ>}"GͻM&›0%B7S4q5)%y4 mdIFL!'ɋcC20S _W{ u %JB|sIAV,\&7yrҥs}to~3׿^|# Q@hˈD ZǻԨu=y+M `gm-_ gR[/O.ԧ#,fk ![\XEyy\ԳajdUPUᐙtѢ/܇m6^*R5)]2o8p:ޥDPy rc%.]t i\Fʞe{*zP' pjS%sV6})a%1Pjq%]uk>vnn`{.h* S^]SLI&EFf>Q;ٔab[-?7Z8GnkGz:S'/)2.@2;U]S_F;,+w5@M5|`!q}ɤ|ޥW4ሼKId-V K8p: '0`'Eᄡ_J?uj0bFƻg[7-|Ί\8w_]wͺe %^>ʹCzi;S@I^cjjjQW%"˩5?1i)IMƠN#$=C5Be^X/&ӧ_Uُ?NШ_ t۳.GOdw^̮4Ilʝ "R$F\_ʦvZp0u&6/}}qӦIoݵoc_|qAqNZ(hya~^#An;Ppa._Gϥ49>;`Cq0|c$i 9Q(](xWwBE/>24G?r#0Ϻ|뭳~y!~Ĕg!,\u_r4YF` ߶@Rv 29}-9U8n(ΰ>RR#P,.O|bՁK.I۽O⋂Gpw>DlCO3\؆1x  uF:B5!B4 w#exxBuF!1~Ng0\/n]?uꜪ%> ovO'*CPIDV_I(M ~zgr:NΎt<cPO6:>kؖ-[m^dJ= ,ȋ:6~}*8Gjm 41x۵kP1n.F>%]mZDb.#cd8B*#FzQ[ vҥڷ{ɷ߾M>/諒#!ɵg{Hv.n> 9Oj +jS%(pdt sIG3м1oG]zCV\kkj,~0gHCà35/dSgϠ,nJjyf̗bՍ?۽a|f  DR2jM'+{_.!ŋ]K/iU"̦xY3;g`ǘ^,4NCiO Wu£\֭[hD"~ƭɽSOV,JбF?]hgpCu-cG޶|'?9t|,9X~Υ q|ݟ1d~wFÂ6Nx#QiD8:k)儆Uw< k֬ٴi^naor!//VԺQ@ƈՄ5=5jek׮Uy&Oȕ 6p^z+-7Wo*ƠG/1D 5YU'O޽{S7|ΝSR# ͛o񹷄xSnL®;z^pH!5Ɣ"Lj̈.kP ޝ)J,/d^Sm'XZB;{f׮e=x=qGl7>Y'N/*%Ywc7~1|ƥk1B'4cJ 6 O2c |X]]+ӻ>n˰ -1@ԙ}eɉQ"zp1`[[CݺQm,T!E1hTAwGm9,nv71' !Y#XPg_fxq ˤ]v{;~ַfΜ?wnѯw=3[^^~rպ&zy=w A_ M,av<--A1nxڸ1MeF"@ao^.O-O9DXWc7pY Abp=uؒ%?<鍊 :sz;;\R{ܢ(%82Α9X,aJ1F4WU+[(..]s%\N6bK1L!Գͫ QIac%h:Bf7>vg5Kn£+L߿}„>H&}eFCjh)(Lz `ƁjܶlLi/^YP?i )!o?Y L`,6<Ak ̩}sN /T?t- (uzk7K2op $W裏0KT,c/ 4lb٨ؙ!p}@e]8|xav߾GRzugsOҥڶ7s&x3HmQ}"mL)`ݐXTxy; z,ը{|gGgq<5)t:S:&,^,>' sc.`ʧ8N~׈@x!k%,ySh1vЉ_4Xc:'6Tc4F)>`M8˗ ip\Q7; *8g=,*j 7=ؤkַ" d:;gh0C?Z~Td(QdfgX ,Q PBL1~xF'*@!ulh:a:SJ,K$oE ";Gٽ{9{n[oO.H-xp 咁7oРţGpfrz٠, B34yF9^?¸qd͘+ԙb^1ȗLT'MZx'{5|x:%Rź1˦OJBw^+CKzJ! R98LHm?V'ş0/u@CTU]CGx8eJ-4~u%Qf f 8?!/z]׻{[`1& ^xF2ٙ ̝lѢm%'SW6!387Z曧vs[ٳΙSo_۶nZZ^4j6ЊdǦtxr)YA& B\Ҟ'vul[ϿyYB#]LĞ˔9b9;u"9n ݘ5YxS IOdIoƧO3_y%ʔ?{VVn..ڴbʚM[l@iQC{`Dn2]΁uB}hOY;Gw7nY^ƛU\{%_fʹ\~}Q҂ݻuF-k࣯ۖfkxWصksMMћNVBwZ/xaa'l#(FlH:ShJ;V ѩӷӧ =7*;tsT3ջlzM{<Q =su}YK!vk#y}4먷;ba@N{K)jtWQђwapS7w*?ˋ'$Kcw\'>U̦M_xvvuUn>rKe^()ҕ1YR9zsIsRK% zӊQ#Z|_c[/?֟>(m,S0x ᫘ȹVZ׻wENG_hga|¥̥/=F&N3V!C}A>qaϗtr͚sr׫؁KL5K VlNdgOw)oPRY[ɖtS_~yiUD\PD-c_-x=T 0[k#܋<$4m1c6lݺM:m;KG~р;잛 f'$?hTz, L1L?`^}'G'?[ѱ#VgGK s⟫#G ڴuV{yFS$7e푧kYVQ0!9kxZ; _ܿGUw=bYU7fyUUߨt;!4gUP'Qg߿j}NϜ,+k:ADZx]/+s Ev>da N,ᨷůvp;gRoxLbwD>@NSv[/V:@99yF_y夋.ʝ0/yn=CF&*I!A:{uoՑ&$&$T=13vCV¦p\9r68vO_EOwڱ2!YxS{?\⫯ }mێz啵=z,Z~ԩ{6xnVUi{n65 k&6DXPi Vl8ܹtժ?oޒ yg]wM}σi6%09BpHb<#Ak{nJi]\|fy2$!~,nj[Z[Soyt괲wڬ,ܬܺ[.($HSSumXkY%vVѲbȐÆ|svmn X8Żr&k\ 7LX]n}~qƹs3Mzeuj{10;hpj)o~^TM,Yѳ'{Uo5嗃]_OhB"~n10XT;Wɘs 'T`L%^ ϦRЃ\dwq/9[Ϙqqp'wϞ.Ԩ:s JQ2 ;U'd3}m_VUe[|KndL x$gqiuYx9Lu t gA 7kݺP(Pz2ǎ'עEuMxO?rꭳg7+vl$B.j+lը忖u`)>z5}>_Orw~q>=Rg'h);jVJz-tq~?QUSoVGyNvOL] K[WIK|+GNeeu>ov̚Uo_EmmCM V:P1:S&i,Nt#rrgc7ҳ~+B{BC-h4dM++M.i~eiiq۶{db6xnڵOo֌vqn۷djfըԙb8zXځ~$ TY_lIO<1UI{ku̍nQ*ּ7oP9A߈r?yrum9qb!+w?@2{ڍ{ѿŤϜY_Z\MH/'Fv6LNT Sb9Fݺ~݆u[ճg xIͩ&e# Dșwpm{WW/5jc~c[sʷ.Xj NFj7}]s4۷sӀ6&Qd!<:Υ5U۱cKDz +tv2]^xx7qYϪW۫ŋws%|r%/ayn6<` ynf=mhg$ ^С͟|`[?ܧ.}ޮ\ڵkTɣMYB;,ٓMJwD$ ci4֬Y>hP^6 /WrC,[4 U"J_3eMN kժrϞH4M $Frp喉>[@N_1lr2YĽqi*~;k*Y/'ݳ7X&0rw2:V,&GFyۯka ~ܧ*}x% TY[.ːIk,'s߾})AIO:Bq]{/"$Ća;H&uFkzhVϫٹ3۷'w\Y?hPUK 8BC`N) TߋO??yۋjso>phĥ&Ɩ>}5n=ʃWXNXsJv2Abg obˠ0֒?_Է/n^ijp~"JLXE ꊪlf۶m˘D.QL] L$MH}6 (E )Rۦ@V?,Ngʽ1-w8#S<9%C,FjԍqUlb9Is&U*s Ck3ĀYs1]ΘbTIB>6ɠQWLH;;`if,(윶c :u9mZjPFņ`aXW򖽆p_D{үH[dBgol 6)=C7|2(Dn6e6S]&xG,Anf]g͞=ᬳ׬r4",)) vXŭH}#A…3|fa69!W#dϗ/YVa̘;y䑜-ǝwW5RqhCmԛ&a9+**L.zN#v@57%z`Kg&J`;)_&M_Ι7oNlbh.EƣG֖JRuu`3z>R)%РFqơRD4Jx'=.NeJ@y Ç9ژrl7saa_=zE?qϻE)5k_Mƈ$T júGgW::rF,$bL'I0~yyV\ߟծ6m TףGewW`|%ݩֈH{xbb./j܏; xʘ{vV?[i=Wwś>7y5ŃV[Wo_ΝռH%hfȕS5_^pQэ!ΧzױVz툜;>\gf Ag&AQ%Z#j0Z6uu?-hK›\xaD}d__.dӏbX fx"SISѵFXY0lTB{;dU"~7 [yg᫯v[~6վ=J*ߵ ҝ;,+ؽu<H(O۸4:ptT'cz ٘ZZzW^^zig}믟aCոql"܏"f3R9X h|洴 %~& ۈ$xy?$|Wxܹ|o{Uy͛l~԰a{ (kܶ Iil6b .jizD%IODiy1=dԩ۾:?'gB_?GWrˌijssa6+vg*ZgΠ1U%1Lw]M- 8Qܲn`6;fsZ>uݻ㳉;䟈lj#%Xe6vXMWyʄmktաT߸q}4E-[fkoqMUcV]1ƈ$VIb vŮBnH7z@E]i)vUA%+Y~sv3_]p_ᇻgr۶1iNT _%T)4sWHK:sɒ%N:2=i[ .dܵxŕ?>eݺ]0gٌ͈B$] $UrUTv6%&Λ(P=ƽ*Kn8zts۶o9 r/3xbF/۶lF̦E@ sM&Qq>}N&$GwERk^s饫=TW_;zLTe# DHiީ~˜LHMoԩSSeԗE7l8p-=z}y}]ѣN暝hDF$kϠÀDP7lؐP ȹJv Ӧ}.ssx`I /ޙ]^S 1Ѯ$ҠQs>q K^4c:b>RTS>wUW %ѣ+V?~򬳲.詧6Ɩ3l[쾉I&4j-Ӹ7Qx#aL~뮺Q1usyo9嗣?l?SV۶k-TO=;ArDfg# Y(  橪ܔt&tuVúw޴ł)}Wڮݶ_Uߌ{M(M j@X" D W(#ُЛSL!=wvO6SmVa^p<2w[kl-(cbI )Q7# $J܌}PIENDB`xflr5-6.09-06/doc/latex/figures/img-34.png000644 001750 000144 00000013251 12246405674 021336 0ustar00techwinderusers000000 000000 PNG  IHDR% QiPLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712Hs?IDATx^풥(Os_PdGLDȇ {jiO.@P?L_SOQOSZQOiVd`4bU Ih ?*ȞU#6 YZ%n,6g D6v?Kzj{2)Y;ek@ZF|tԮ޿Pccxf:vLL:+t*z&i hfiK9,v>QQy.WUӲvtWweת:}w 4-6$w<]5:p3C;]e[A|G@kHH:ov{=ڋnsjIʱd-KFs[ f&nV>k璵27EF+m/B-vv { ]Ik +WG]эN˼I~㝭vf^+ aV۾NoyJGcok;[ io Xŧ7Mѓl-WֻO1lK֚p9Š.olw${zy[*Vև?]sy~^9qwR vsnU6<_u_W`Xxpm&dǥ׆l,+|>PFeϽˬA Dֱ>uE@>\۫,!BO=kg똙knw%JjXuMHn+\ &q:kgK,ܠ[0uxD5꿙5kgx+jTSF+m$qoujoQ|R5~lP'+Tt}+CQUr.;x흀n|ͺRsN1&fdꙭQU';ŔVw}P_1K*xgk/$ _؇m_P5gguG!f~R #[e=֪ǣ~me&^8_l5G+óO*zŸ?7_rd~/TWO~rnf}ܬ.d ij2|{/Y "wu5mg+,4Wwsut{'/+ @Ԡy8\r7Jo!#`Gv@^H9ҨbjvھG87_":E-NIǪxΑ>m Eh/~Քn{/.HҾPS}Y`/#(b(5@@}Yv t@@d_nBmǫh9h]rME@}.ܜ%ގ¾߂=P8_>k4b"ntM.-5}Y3s2Yˬ; AӓGYer_#YPH_E>/F7uPCД&FUo/[85~uӨug&FU:/ē6~ u/' QUd쳲싲Ǔfߦ^-g65}Nֱ}i~O5Ҧ!n#ަ"5 LՉB^'f]h>:fxHֳ蚀UE^ZxB]/f]*4xM@"oF;W%%9O L3Ԩ*.쓨I,k}Â~uȟuM@>zFki a$U>@ًd-$o@ԄH"%5 ZQj? ujFUJ@BdI"^&Q@@M \e};Ԩ*du`/̿$jC9敀U>Զu4Z [~6paTROTyT=xؙ :XS6$FU!cmP;^f QUHU3Uu/3_\z{bO*Md6J@MAnVYRN@Sa}݃e#j^ې9y*ʩ+jgjFOPUNHPuIP3UڢfC, 9TYgs]xF@pjKwN@MUт:?Nq`'$FpdVպ^5WEfge͍~'6ڃvo+eQdUM _'/cJe@wj2@{xbגּ+&K^[l!I@ݛR2ԣ4}8 *(%C@=Jg7ձdGilqPUԛQJzgpu(%㣶 \(m,ΔoF+ctQ*㔨t}f@QɅ&$O |i3r ̀d t}f@QɅ&$OO.5!}T}r!D Iӥ !*EMHj.u\Q)jBRtBJQڧKE'BT>]x១RIENDB`xflr5-6.09-06/doc/latex/figures/dia-01.png000644 001750 000144 00000100201 12246405674 021301 0ustar00techwinderusers000000 000000 PNG  IHDR3%AZ pHYs+3IDATx}w|Uzޥ ( Ho@A@JN) H/D* E@ Aw$&7<ݳ͙sfΞqGs2Px+fg[n/^|ԩyV֯_}ww;w8Ԝ9s9;h+aԨQqC]jܹO89sf4iׯ_իWC 4iǩS}J?dq*Ȕ)d2eJ>GRdlIRXXouOK|a A ƨHhK[(/C tY^;qF~NW1) )}W_%ׯ_G +5p  9_PZ3rڵ#[7MۏJ5eHs] Eccҥ,20f9Ȓ7o^LQͷhѢgΜHLc`Y;wNՁӧOΓC x*.D{̝;w_4uۗƯT*Ov :,y+dea3/^0v%xߚ<5K$?y睂 ~嗁k׮ IԩSŋ!ֳgOcÆ ]Eo޼HEjkUǏ7nܸi&H.nnn$@Jد_iӦ!_H̅5,dɢYvQZ$v`U/Ӕz|R}kĉ=3W\(Qx<ذaCǥKe%VRy4md"sI+ 6oތ_red\jU/BBرc6fzY6ݺsF-J)o޼miH4 ;=} U/7ّhWX ,Xx1%<{=c ^{AgH߷o@__ߒ%K6nwrq,bN&h$~yq-hE25O4R]ⴅ^͏Ȝ\w&9Jt fHB5k$?P?&&L}~Hvs2eJ hMTI#턪etn-[V'Z.%4ʹ-'uꠠ , i\oaqk,5k,_<%НT%]P:MGY?"E Lr-N5/4RSu#8̢;t&НT%~]:NGY8Zt:zCFi߾=AEDD̙3o߾$QAv4dФI%J[lH2η,om$ \pƍׯ_SDWo]aƖ6z1c @w9zyɓ'8! 9fP:Qk'ֺBSib A'!`L9]qQBGàXO#H}\`1c >\wpvFHXQ}FXQ8+ 4M&터[Ν蒎¤I7ovʟXuty/t| e"'ǭ?#ȟ-Z`~8mڴ֎k׮UԉS#yI\ʕ+WY` 8A4iʆh4y={pA-SǛ5kUK._utN ləܥK˳gϠ~dtB#oԨѦMԩSHF9OR;Q\ݺu) Hlȷ2RG# T Щތ)Scnh{l ɒ%bۄHڙ0H|vb…XW>cby̖-ۅ Ξ=[X12`,g !`uJ{qN{=MDi5, h€E$q$I;XV'<_}D<LPƌ#ig, S3aXCiC駟G8ۣNwwwvvZjx#mڴ`/_L$VC$'OI`%S8kgé#Gܹsg Ν; ~̘1"dʕ֍~%)/^ 75tB  iݺ}&M4s;PrI#sOWb6*Rkx]!eY?񢝱 FSڙ[7s$=Y.#V/_\n]ݺuĺ+W@p1xG޸q#EY_2eJ6+yaARWP]no'e /hժ ) >D<\15kFvtAbI<,]vCڵ+I_}^Yd Dwsf;yЪ^#dGȚ5|8 Xg*Q&L$#MjjBxr =EzJ;/ ({^ ep>8tcIe7o$Kdɒ7bMAyɓ~I. =zD5 *ݻQ2fh3"N:ѡ?خ];ʟ}򂐝+W.RVLbŊtboC]* C *Δ)SPD:ui'3fd?Vq."J~LΥB9$m7C]]:B粃6e.բe]vF`[nвeu\F"M7Wv$òeaxӦMHO=qj#cN yz L5jOD1&q/N)O˄N˄:;z~c2jg=AA9{,9(v$GW^Œ%Kjر~Iۘ?~ǎwǁocP#!H'|vBw9$$-Snva+V`5/U69ڀ ht 5CHH 4 32MSTt I?}ۤdrV8k'ڞ>}z&MN~:m޼y0ٳgx"wdB7-H:QI-W9vIfjXc9ocNާɐ!dZߡ7n=D#S쵓iC;ZxYf`kߡsBP;i.Y4Ζ?E/z^&zXi'wQF%򱫝G\R܁?S L2ȇqFAaD#;V-4{75GH ]8+kQt&lYOTR%y2ߊ|+v|ٯ_iӦhPv8pZj7.Q?eذaCӦM{Oh={3fѣH"#,Ylٞ={cIFXN:FB$G$@Ψɓ'# kUVJ B&D(7ׯ_>}z:EiZ43o޼03gS^.\ח>}J*Hct'J~ܪ/O s<;oѢ:w4sp;{bժU("&2ڷj͟?,xb5Rnݠp-\l9i$yi/\0Ir`: I$KE.]G081m'MZ{O>}/%&TY9$ VyOz|i˺bG;c'P,"~a<ĪPΜ94@X2eJ>} h|4aÆAsd#Go~΅u> yPĩSTVʕ!Cj#͖`O.Hr  T-k4Wzu7Kͯ!{P/=Η/˗)ݧ<蟺@^-K4Ͷe2C UA;Y)UUSTWMITShʕ+Y;wlrլ1j'ȋo'նm&3Ĩ<>Y޼y,TݻwQ{ wy1;wnhduj >k'x Ӡ:+TꅪAKȑɻ8*K,t"7tQW`Ayyg@u6ğȷA;v^o߾qcBfAaĈzxNo'?3shd,ѣG ]<y3@#㜻%Jv֩SH": ј`yK~eˆ vB 1cƘ1c~nǏOq!ԝKvؑH ElPhskv!WZvyF]r: V>ҩRz))1ɞ?V0F4hC4.\iӦFCqȻt5R;t?f[9C1w *-[} R#x1n/nͨ,0u &'CÆ %KXC Zvu^v-nAxF.'P#Y >o{" ;Fcyhŝ;wvv }gQ])w@2W{Y||/NbO<Ŋ Ç rnj<(>>> 4tڰaGx;wIqI>=MjtQp)-tjނ ?Eizӷ4}ʝ;7yzRYϷl駟ӧOϙ3E4}wo\ ȟZnM(9)ĉ9D]LHmeoz@g\> lx?1F nn2B&XC`MDhhh`` 8HC8irI=`KO f):o=zgϞ֪U y5bŊ&6 %:t-,&ph۷SH7tЁo޼K.ɝf cRD;i(vZvF) TUN@wt3~uFQnq_?G'҈* Du6\{ tX7D'%G"EΞ= /((իye+BÙ3g #/^B֭[O:E44iRHд ,+`9sfВJRҥKq S!3P8qSWZu̘1D;v@H:uHHt2eʨ.TjA,IӧOxtݵ>ϸϤ~,*ێjdfp;?Py!+.6ASS ti*a,INeA޼y5jD7{bŊw6nܘ)}DDDj׮tÇ0@Dشi?^ZwVTIH"˔)Ɠ_cԍ7wtȉ-R5cƌX"m6F,ǤW\IAixR's1 M# jt$OŮv81Q#| s2'j 2 @4" 9]$%C&ǝ2ʕ7n\z\cǎ:u꿺MXnsxΗ/_.]*Rț7ohsDS~7";4h@P#o߮yw *9rXbG}t]V-*1888v$3Ec*g^~AC%عsQHKA3H UƋO>JKp)k&Ki>gN:/^e mګt.]Gᢹky5^!r6ڿXbOV3 4SVZ(Dte5kV{R["{ 9+W.e΅]Gظ~kglҤɞ={>aB>sL*U?z"?7⒜1?os]rEuiY"o\xٳg4(((HuXjU gYYA^;߹إ j{dϟƐk׮Kxkg)r:OSS ti*a,zcjq.E58ǢCN㤶,Xɓ*T رYׯo>n۷a.] o 9{!C̛7I9 ͈#1c̙YvSjU~kѢEtG''kҤ L:|ɓ'䉛۲e>3g|J*E^zE b4lq9{ݻS)RPCKR}ة#K9pcm7uI/_L괷B&ytd2+W/VT 4e*^ZBoٲeէĂ{3$hgX 4~gT-,Dr9[\r"&@:F(!(* QO!!OS cLdQz={?~LM6nܸI&q4>jժ~49t?{ Ɋ!iҤҥK:u mWtyedSz:uzpzt{-P(NMĦǂnzڵm۶9s&(( ȰXmTa„ eҵX"8lՊ+:k]h!4s" ZRbSV#[=z_6LP,U=o@E3=S3&RQ(PKrڐJ,yIqo*d!6" Qg9ҙnTԶ|r2~a\3PpGu/#.:5@QlB8pp@)dw&>!sռyjvd+4<) ˗Ws9Upqd˵m߾nݺcƌ>|xDDOڵk3gFʕ+,Y^y!3et}YTZht7]seF.L5d^J4)J ,P[n̙lǎJiL鹬$Iܽ{\r@7777oʕ@jKu w'[В?"2dÆ KF)Sf֭ܿԆ)S^UV־yF,[ŋkY𵧧'svB6jHA8#r:u hڴ)'`F5k /马GfHH5RJ\t4iڴivړ'O⯮]̯_6#̙3邸=RLx%R'P5GDm6ִ8tҁG 7Mjz.KXpǏw…6ZJEu"0Gu5|5H 0XhX[~Z=+ KDm.\X=D{'3 Ң LVF6>}KK'^']ICAℜ!s_5@)*:ԤIN:4e?֬YgCH$@r7PiӦŝJ*% qQO /֭[g̘qѢE'^sNھ}{Df͚)RlذA]v]|'|u֭[֭K*TV-5Z_|tRܳgOVf̘4x\4ǏӤIox%KVe//ŋ7j)|M.]߿zjSf;w8%#ݶ 6vSO>~޽5jFC3Νw6oތ4ŊBդI%Q5k6j(6gCfne˖U ĐÏ?8n8+XtmP4[xTpa۶uq0ƾK}d sc>вE\J1\֬Y+UW:1uU"[-6sSB9+ZͶ`tG}ٶsE%,bŊampB4&"rF*k,k,H$bBk׮?xĉX}uv:E5G CҐsz G,԰}$mYCM %#G%:VNJNˠ% ,: D$B'Pf9`@gN>]z> 584Zjdjit,@Sl5+.uv,AғьI;wX?5=z[e9"ba+ʃ@h)Z BK2m6mڬZVZw]B8)SfϞ}M\0H^~*U<>/^w={ѣNJ+޽K_~Muһ>|X@ڵk/] -m۶M0 cҤI)S߿O,ei;w.HE9J%J߷n2}*t 8qɓ'MVf􉃎2us Th׏,۷{xx00C_#GHH ҹH:5}W]^zˋbѪޱvEh 2 c,Rh)Z ;h #\1:WTfcBKR -N"c/BKR Z:;tбcGwb(jوQ#-׬Y>}'NGb z4jhܸq8zhѢE>>>6m:|_~YYH䠽}ΐ!ڵk֭e-Y.V^իW}m޼yTԩk׮ *jՊVXqљ3g>|8⪦LӧTgɒF{ .Æ [|ٳg3 믿Ë)-Z'Os > A ҥK6Ŋ;v,HҫWm„ ɵkP>@Aɓ'$TڿgrUq`=Be@@Fqڴi);yStFt}Dg! dkױYL:Zr& 9`ٳg翪W*x&W)S ^-===<9S=xi〿9FANs Ƴh駟)xZ}1dݻK.ݶm[ٳgO/j ڎ`i16tgى$MmTHK/C . XT:\"WUыN.D'q0Lc`޽ÇE1c,b,hiĉ/BKR r@R -BK >R _ Wegi,+U.ZfΜNũʔ)+:k<]B4igϞ>}̘1n&K,cƌ<K"w%AVRJTI:]GGpk.: ;wl<)&HTO1?Fh14h`oͣf͚>}zdZr":ǃ)PcէTI:]GɶmV|ʕ+Y@\IA5˗)[̱|*rƍ͛o޼xߚGA;Oׁg PK7`;|δTWI5ԬκzgvFyiR= >]A]Z 6jԈi&M];|w5V*O3v-RLO 5Q[,4&1ēm4iso/F>Eg,Q}jZy:cqE-Q$xEKيZ .@Rh)Z _ -;[XR -+@XM>+Z 2_A-I۵k7k,z&ME#-zMtBɏ9RT)%KSѱǗ_&o"gΜ5jغuk)߿Ϟ5„jٳg#;)Y)ٰa43CHz .Xkj~jł  <8{Vl_`6:upv-Zĭ^|9-wM  }f$LToŊu@ql:`&4hE5c_1c_!.jD B -ZKتC 6-nf>ǹjz;VǠj>a4ҰOfq:`VREW Ef05DQ%w=pR@ZV e˖uCDXtJ4jï!Θu}tiӆ3W,I ˗/eʔ4`"yfL4iժUZ0fj­EВqs̙3qD/HxvG 'Rg@B2d}aĬi@#^@)t(&c*,5jE55/ˍX- `ԵI3I\gp!LK3<<|xr/_)S&j={!C8ƍA3fҒӣJ;v>ɓ-ZP˗/OE~zРA}3f̜9sԖ|%Bn߾e˖?)S$ZjՊb:u -(!;FxbժUgϞLx1ܜ7o_>+Vwҥ+]4@ڵknݶmۖ!C9@W Ǐq~zO 0l'L@ moݻgz};uD',&;'N+>]1OB͚59s/rUTALFݾ},fYj`ͩIvy|k%KcT➖F_t&UF_bJbƯ@Gw'uTƯ5-6nYPk{b6!j'S b6 kNO6k ͋%^mJef~gTN:&F57лpv=zdX-˄;ؤܹs㴂LJ/e ~#,,L}BXg޴?- 49҂`l4" ,vnRHd.2d($Y5++XСCi^D3ZҺ\,@K(gիSU>SGB˗/U[3:s-R?[{/Ǐי!Z2PݐffEX"k/3c޹sg@@R)RD5+ƌ?~UuyZڂZdet3{lmgy5kVfeP1ϝ;*ʼ!'g09V -zZXKR -HK-BKRhE Pѓp0!ҜLQ{yq ݻG6vcmZ8ED.DKook׮ѵjW_˗[n|--ZD{ٷoaÆ-]TAKg HyZ۷fǎɦ>yd BBBMFw/^%M~wL-2ɓ''I$Yf @:$U4t̘qlY9i(TlԷu6u۷oO.l)޽{1{yy~tg˖-n2kKm|M-LǴ.Ju֭_>gΜj57`ҥKd˖ ܽ{wM1`K4)ڏl,FR}jס2[FtC*88 # x"ߪ]6FP֭[j}:uX tQZ(lٶZѵ$9rluրj-kr̗8s V.Ν;;w| 4-UTtc17FѲeK=)s#G4hRT]j3gEӅ(E;F\NߥKM0ʕA֎:N;wm۶ac1OqsjVuzi0rzbӅ!K*^(Z(P7q>>yE y:k֬evg'u @S f$5#cNIȝ%Xj\)NLXLH=44v(j͚5Bt8 n+@vڹNj{~fd@ BKgK80x(uH-YjvT imE,6 lY,GheX숯moE,mB={TfvΝqLKֲxi|M:g{+4^g̱ͬф kY<4/moEY,5p`|M}Q)d@h)pMZ$|)Z RiiQ)+DpdDXR 8iҤ,+Eʾ 4,ǥ́jժϟ?vD?.%hɖuwɚ5+zTR)R~=VXq]EϧMٳg.S̫WN<9sfw4gΜnB{:!}o,Po&K %L8|3ev鹬YoV<-7Fŋi$V']blζܵkqܸqNNZlI~5y>TR9rĘ'a̗#FؼyK@iTJ,i(* j  5j [ڹsg,\ o/y_hI: VZw0i (]|gn'UyU,tM_M#`|nʕ+@X,J ZqYϗDHlxQ&_ޞ`۷oGù.)Th)Z:g7 5`e,w+@OT,^޽{TR̯ 9`l)akذƍׯ_BЉͻ~ȑaaaȄ_BK:ر#9Ç#6^lŴ4ݻ7۴iB|2wvq!(slԠ:YjՇ~Y,{pEU+(Fs0dw5qz (t̙PvWL<͛3fP).nY^#*GFs06;lhsDDɵKI}~':IGR .KK;)vEܬym+Z 2ꈈhܸ/:|7oHtӧϙ3g{&F/\6Oy5 JxXT6mڄsկ_o߾|p0_mҤɓ[… SXu֡k֬]vexxxÆ V_%B|† ~駜9s'Zٳk0*9R"( ?޼yԩS/YD5|pEZΘ1# `˖-|&C"EtbXP}|| ZRѬY33-E|?^;ԩӲe>Ӹ% ԩSg݋#/5Y7ݶmj@tZyk׮ ڵkX0l'# 8C-xe۶m_~M'H˩SN>}֭-rRdlƌGdUΠX6m>}@3gμz*$ S_n8,f }:/P%EҮ_Yuߑܹs'jIiҤ1Ua dY&&0A۷k@|da4TIL{)\@i߾=#ѧ7J*nAL|2,-[6`z`Ν;%W鍁0P)]4dK>Ja9?Pw//ѡeܹի!:0#۸فUu1kժn5s6&ë)f6p2=Պiηf9r8u&6Ŭ9"24ǸڼH< *T2eCc3ڂϟcI*Uo^$x[f=fml!a6Y\>mEW7o޳g5!V"}-=':߇~ #eʕ1l޼5ӧߵkȷ @h)$Z+-qDXYAL^Uݻc\,YԨQ#cƌ*/^͖-Ȑ!ڵk֭kÇ^… hҤɞ={~ ={v Ԯ]{圹795yʙ3'uV :ὐuٵkW(C) dɒO=[PP`^X:u*#YSp~=wLH]ٳA0DNU 21ƵҔ[ jC ,x5&.fKVX1F"~ּ'OO? T&MZj|ԩMUVaÆ5-9V `^!!!(iӦ{lĉKo6mP- (ڐ={.]m۶W`Hj3zt=Μ'DNK*.`zAS:CDq)_|]`|im)Ew8蘮!GL 4;2ŌayeI_RqDR $|ZFogĞIsUȐڵkEǘi"%T+*T6mtѣGgΜÇ={A)L;pPHJ, f͚"i[*PxAJz5 P#GΞ=[re[~''RLH" aIM4t5:iN *k"TW~x[+VђjxB\Ocqܺ٣k{c>p5:i8 Z!yGR}7Fp,~( pAӠJ*j=_vGyw8e+8}4A0힞E;; 8Ot&_|'1c(`iPO\ (Eyw ndJ+;z'FzK^ 4+yKtצiӦX难{էhV'(Z:f1|qQUFK2Rybt>VX Y1p@ )3L@ peg~͛itd]83K.KpE*Tx)EYjUHH ӧOgc'kiN [ g&}͛7+Vc-Zڿ͞=H"-[}vÆ ˕+7`ϝ;W=ٴi2eф xAΝ;7k֬)S:}رP#/_͘1#iҤO*J7}W  2e 7x;W\ Ț5ɤs۶m۰aVSΙ3GMe78̩Yb|X]V94k#:tHAv+Όg˦wBJ(`ˎ;kYɓ{e Uvw2sxxx```ڴi.]F`rR /R™ k׮_Ou֭[!b9rڵkuk&]`ҩ6UeMcjf=ELuVv;VlÇK3]svlXZp@ ™p@ gKGsΕ~p!kȚr7op@8S ™p@ p4g`WPufÉ@RSH@8S tiU!ZBCJgDę+Vl߾}Ν_~=iҤF^!!eT1vLAc´먯J/Bp w–3 >}@A={l׮]Nk™8n: B™p@ q,tȘ1c\r\p@Y@ )g L@pl̺"7+)Ҭ@Lݧ9_QBsg=URs8qux[b>3mt ݷ':~"m=nbΥH XL_9bZO:SnF&o۶m:u|||Lӫy~'wC5lmZ͋o>tŋ*т -*oXKcqr55kl8Cќ!;dhvLHcĊa%δWNSm*ªW{9sړ>JN4ÀF.]ɓ ׯ7n1uilچC=];pre Q%98Imϟ;lx=|/E0yzz&IqƲf0!o$EJ ik-jEL@3w̰' }ܹsZjW\+u.\{2s)\p /n1x`ݑTMQz4k1ZFidǎƐ-n#m|2EjئMLk3JLk)LI3@;C2Ѣ3$JRWP@~tw"""z衙E ͟?fw$k-FZO4-vv=0aӧO8`mmR16дCA[ҥBgӅit|Ӣ5ެФI x7][Fios}ΔgF4@!zH3 2 g L7nI:pf9ZǕuȩdɒ#Fhժ zpu'WLϗѣG*Uϟ?y ݩ&ۙt19  B2X[3c +KtO߶m>}14é&{2RZ 4=dZIݱd@8ӉН%b/1%Js)RD3jIz]Hix6`Ǐ#=#tRkzazV͚5SN盛lg.7}@vL{Z;֣ŷC3™uԁyA p F"]Y™p@ gjQf $عst@8S ™p@ p4gR;8|8\jiV =S g ™&MӧO͛ךs_СÓ'O,XРAV>nUAGO6Zj744>~z|juq g {=c|7o̙ĉYf,Q=~'O>}NV\vڵk?{?߸qǏ۴i3c Eϟ'H8лwoFnkV[ځk@L?I$ !ֺuN rm&L0qw} I qyTiW/^hԨ1>? 2|2iҤmcƌI<91aٶm]+jzZzI 7o;u`]zu.\@_Z{E֭[K6RXb͚5;vaf͚]J;I 㙶 3"񖎂GյZ-K8@ļ|r0w}w1]RL(u3ʖ }] S5o( Ӫh#iodٲe~~~jh7k%a*G+VVjKb;ŋ eYBɓ'_t~z_׮`>`vGzLsg߾}5ř ώXKv:zh, m۶Tl۰FW1 L2%1ou k_~)Z(Vf{?ӧOI!!!M6Qek^3efɒ%:٩^bvȑ#Fk"2Lc"Qsfޜx~ ?L /䖅 :ujkE[@׵j24Ɗ>+rB"?ui=u̙S~ 0Բlz[Ezt %˖-488.K-HAӞ"-krfFH77hRʺi"$= ,X.FluVԿaÆ`3"QK9䝪7nHg X6띔l%pfe{9*C*l[g6LclpiEu\Z/5e 6ׯ_Z[H۷#A+TaR\ <Tc 0@8)0å?K=qe{9sK|||N< n\~q㼽m۶ 69sLKg:1tq4;"sوE:wvp=zRD)ljҧOSN߿UT6lWj֬9y^z 2Fqe™[j.;\Yi rH ~OnVFb2>.7ҵ+֭[!b9rڵkMKT+#0`:vXٲeig Aܹ'c@8S g 3c@Cƌ3˲E " ™@8S NL٘u5E\ L )RY@L@ )g x͙ÇtRqgggᑐЭ[7eEEE޹zl3f*2JmE6,,,<}q㒓׿ZaӦMYVUtGҠ"ٳgO Tq۶m\BCC###o߾ 3g4'3ZꑙԠj9h5^^^QQQGIMME*UHe2OnkXr?}J7C?I쩵uaVJ=E !WQ6e˗/gȄVR\Jzt+ *2JQ7h\þ >5 e5[aիW ) +ea2TTuJ 򝆄dr&+ԭp"*j +az,#3ŮTrM'FM4)''~ Nd*%-2ڨPƒkjqqqΝ٨Bty$j:I.\{Ç4 +4YPgB !]cƌѐ*ܩ 'W޽{m<==1PtZ(%-+ KxZUP.((-PJRJYGj\EFءiJ:u+ <N;`TֵkW;&3*bDS"ԣܩ&c0Q 27+**!77W[[Қ{kBˌ''y])`qFҢ;~z-}kB 3 1P#bјfڭk玺ZFqwZ1U˖-srr7oc77Ǐ{NgϞU˗|*Rw-[]5R{YY.vS}j{Ӊ*uȶ⩅fKk::ݺGstt N y`Zaٲe>\f jժ{Unݺ}efrN<+888??ԨQ999AVc˖-Ν?~^^4hh"gggO?;wKsn׮|wϞ=L^zׯرh;rQ3 =s |zҥN;yeej INNNJJz b&3{-X !!Ayƌg{"Ξ=uȤ}o۶qtr]\|֭ [UFr١hӧOIY ݻWYjv h/~_L]@>͌π栬,%%2~9zhx-($yݺusp6;نLՆ{a 0e˖JWasચ "df>|9f6l Ǐ\֭[5jd&}v03;; {H#Y ̙3qVjh/gh㸸8wwwp<43ڸo߾aג\ָqctڷo6bĈiii+VWaO>>\x4""@ݻ3ڛ-Z8z?>tRv2r n:==*wFYH$.f,F9b&@ fZ?O$bfuC&\:żY|Uٳ w+--U˴=ZhuȑիW+0W???cڵ!!!luRc6*w-&\:%.x$pg1\ۗi{M:5>>O>A"##cbbF>}\vյf'ewC fV 467RR%4AeӦMqfҤI999{NNNFk 1Z`K A߶\j;g]222vwʊe0iϲf͚ӈ....]NrI\zllƪ=ј6ms[M R9Kk b Ԟek͛ IدLq(5@̬>(lg'.I 3 I- rP A1@,@ fL@$ǏܹӾcǎ0`Ɗpkm<}UzzzRRRJJG}gooOAfڵ T 3fPԊ:uLQQ͛wq}psTQϟ8qnZZB"j6ktj8!6lHeq̼q:TD4OPPBj$oW(6[RRuVp֭[ *;1BѣG/\0h 4C~ hڴ4bPx":k>ڸqcbQPPx!qџ $U/;*,zMA̬TDH:t(f #T' ddd߻wo.]@Ttyyy!͛#?%@z)--ݴi0??>W{QٳTAff!CL包,Š \g%8::Lvv6A]vCF\cS̼~:J{nWWWtER-5jr 1:2eʺu/^&Udt^j՝;w`_}U\\jテړxL̙3|pTzz:m۶m۲<(U₩J7|SСCFYrY%XZ(@ uHJJ?c@51!b?b!q+Mjp Ug52 ,]NYYEVT/(ױc^z]vM={±pXgƀ)J/A„08^!&Ho%%%F+^hUܕUq3/_,lϞ=nnnsɂ&dN۴i)X63ʺWe_ғ,If %㫫W"Lo֭[|2Z1 V^=p/%zDbR"-ePS^&kr%X oW4 ߟDEEEϟ?G`|bK1KZY+WlҤ Ow3c5yX"##BCCeQ}ѢEʋA M1m#""4'N܂Zҝsۢ=|N0Z"F+[67KF Qu3Ox-qDρ) VC6Q1W!"܋vL„͚5KMMUv,UStz5Jjy&}1X g*8b(~j1ڽ̘8EQc0c~K^]Wq5`Z# #//?ɉS.-7}&9Ix&;;=j߾=:j(kyqDfIC@L??>},`ue1 hڵ3m۶^:r|Ea5;#)"oc@Ѫj,fGًT|GoĉA-*2eJQQӞFlRWJfrnݺ7nL0!77{H4ܹs^ 0`nWWoü[|ӪTYZW@LL j;%%}g!7((&jEfZ[sU{nnnzL!!!-<_+L}a\\صf͚/^t~Cwp?Z&D{/.\r p1bDZZ+󋋋؈vH^ZIff&; /q^ K2~xDlqIIIwܑ?;F}ne5k}=նG]RRv/1.pww9%ɥxx299Y+W;**J<ryZ7 P ˎ=z APf[|1xzz:lTo"2uŒHH:C0nn$RSu4TrE%RFيZIўӳY|!%ʅ/^gkM>9?uT-)3^ﴧڢe|f͚SkILElllf4oggg]ϯj\,f"fE ]pD{s纺Ι3͛ƍ\d11@yGn( _r'߻woXaÆyxx-_\c(nZ[:!((UV8\"]àpD{p2PCM&F=(ea,c8V/YDB;UծO=c0&G'05W$ b*rȓ'O(`7߀Knnnݺu0̠Xdju,a͛ǎ HGSre=vATUEl:X0EH܅# }aXZial=e^#Ň~Q1;իWaaAxqD P+7F}*3ᖎM21aa_' * 3tkYSͅɚ!frB@$L6N,VIENDB`xflr5-6.09-06/doc/latex/figures/img-46.png000644 001750 000144 00000013035 12246405674 021341 0ustar00techwinderusers000000 000000 PNG  IHDR?)gAMA a cHRMz&u0`:pQ<PLTE Q Q      bkE Vi Vi-ViVV kbk-  -kbbb E  b   biV RR u gu 55 ~~g uu~g  5 u5u~~Rg 5wDtRNS@fbKGDr + pHYsodIDATx흉۶Ns[ȍFbyiّ;7^R7l[q-u=7AHTEE/ HZLh,k)D.H}1C!&#?>Q?D1CDn@jǎy>D>q( ;!rN!}\>H"C`> &h;y䉠? D4N!}uS!"atP9!aL҇P=!TaOʜ e[oE!{U;!TaE!}E;!a!}5:^"⅘?dc>]!`/I!},2gB Bƾ.7u {m?5)!9W}$/ sxߔcXD 0rp=1̟E" h0.wd=+W=VcdP/ͼcX+d=7)RH̀?f ?vn1|ޕCK71{SGرo?f\0G#5md;fJ@sYsff>R-+?s@C*ڮ$:eu9aH;01mc7=֜ N|{P?|-}-Aas?AyRȞt$?7<XT'y^pdU=Rʢmm{Qf:FkDž? [hq}$=Y` R ̟;U7YM?|2CuOknjȪ&a2f58B2; Yݮ8 \16x8 d>x-EZsRQ(-Tfch(R>VUkt90-FԮxdژ?"S7V?Ga?9,W'(N?rЃUxG >Ucmޞ9uS@LN~7goȜxg;U-%$P>Ph듁eo<6]$?V-i%P9I㼣HƟ:?R+?23SI4 ?k$VCOj#_G3@AGlp:-sُ*~-2h4Gq ˬ>'j Ƕu~Z?9j&r%]`Ŭ?ɩ*dתܞ?b~6 5Ze3V $]iwW4E.GYxiagHd飿˨Qg6Ǟd?]k)y_is}rERn؟pU6Z5Gw8c9"pfZ*HMTbE_CX),ȖoNWe=g"RP wxUi646(Pw[qOIأ/nk1\jϖeo)J2mW*ǞJU:"/ZWed\di߸"mEEO|v_}:t\z[Wi-EdR!dN KMVl X ;voA1bYċÿd a`7[(;}Z2 \Cp h9uJ-bC|'?Tg_LU*'zXoXʟM6s$?n;ݟ}YOͶer%[4a]@k~9'p'J^6]$)ASjDP'LߖgՁ14c/Ja))#B"1N%}T?hl֊khP?ZU3U* ED'?{-O&?%̇iBȳ)К3BR/R??&YR?(+ẇ {ka(Z6ȵOC2ОDI#lt* @TkYp|qR菠\r`W Oǟsfv8vbla94(WiX1;-[e[${1`rJN o1ҒFح?ίQXT]2URW0vVgVFl&ν;{6}3ݨ?zJ$tE:dz'[Q E=M9H 3QWN?)LIuj@?~?E*.IF9?{Ԭ?E 1vtğ@yUh?Ϣc^S"QVIҠt`d؟Pqs<xUZـm :zO飼s2O\j?>5hי+O;=@#e>|y%:g7`~':<ij24˟pϲ˪ɠEj`t/,/`2qDt Spq΢B]QmOܵNuqx^h%;ys# bo3>3z5H Eϭυ \g|IB _?e3g ko8+rئ{=aEq+A;/[-8SbpvQ3 ˁeiXW] ty&|/9Mp|[`mW'N۽JQ @J?N?;܌ϟgV|'.0F9ҟ? ڐcGck^_? h?u+j6)+xڎ8s9rr/;g[-4̟?{"J?w>tg-văO(Г]^FYϋ14J{Y[74Tj_5^MgºF͌R2i7ʟچC]Oe7MHȒLPShw#E q@?&M/ǁ)ΧП>Ì@GJsfΪϟae}2T O>3r2~%4_D?`Xz)/ϯr7l'~aceY6Tï^ G&Azq楊 ;x 9(a]LC3=f "];/q8YPfbjpLP7/'s~ܱʯiwIe j-W# %˻h>sN"o^8r0SUP& K ͅ o^*w(11AD**ِ?\{%ѸRa!|1Հ?]1h yXytDcqYp\q#&ٳ?pS}k;?wxӇ Yٚ3`Kc{S}ƪw-%=A|X>~GQ,/:Lkpag4F!FvdoQw!DX <Ă~ﶈB8ca05Yl<,Lw>Q;A~yğN%;~u>Hj,#0+o_">@Epx5zKN zKw v@҂D|amb6D-XkZ<a))- juk~G[̻΋$yY<0!uo OA#ÏxBt6 ߐGU5*%?W{gw ya x] 3~{hdZT>m{[섭F;ɩn]QF M?=~yᖿ?Ư7Kk_lrvK{öj^7N}cq~8?"m7y/h3A6'#$4x.s@e5e+Я1 R܉7o}W{ӿw|zo>{B=Pk+}q+^6_ă-ćCK#| _VW]+x[{_pMp|~wmͻɦcm ۝zfGjvƯ7'[/-*р=]ZONXs82uwCQ*S=;Ѯ &e'>sY"o >v4g, 7, ò8|\3,Q +'tzdx1w0S\h-8xX4Rw5߈-+63P{|# FJo_}Ov6D?DY5NN!q1/<^xw*DŽPhxFЭlD=0/m_\\Q$Lgx cNͩmDsy6c.*-#\{0̝Χ m.6 wj,3Zm:`_n#hw{H{6pL7w^ [~ 2ӳ?=FgI{[}tt_[[-|ݴ({;?6 %ڮ I4j/,|_x+F5hc֛}nD~?]1}V2Jo*{?X&ѸȠ |M>8ꀯpK&^x{cxFO0s46!\ۍ=w<T rNsRzIM'8=gtmYr ~ 7,7, 7, 7, 7,i=b޺dGZ,}z,ˢ_+ -\~2ٗ`f_o2MֿB FC/X9EpІzm껭1ZEWWΤB215,_}% ϬaQϬOx>ÿ" ›%hin_T̯-?Q+[~050 ogTdOx>ÿ" ›%h`$+`_6^1D ?M73K*'I _R?Mb乲 vmcOӄϬOx>ÿ" ›%h`$/FCo9TU)2D ?Mo0sc+eskX=X{oW԰ |WrHoWԐC)NoWԐ|StWSΫbSj~9{[WoAC_s>ÖoGܭh nUy_V]@vc_4e6UmZ/[m&4r (|1۶DC#?5{g Z/A'ɗ1A㞻[ Qϖ?lحlj] {SFثNR} V5Y~֕t/ȊW: 7MRMa {l{R930uѾ]_3V<>p⠊OLѫ]pZm[jEm^_{0oP6l뾈[]~ܓ4GlŽ݆U;44{l~C&O*hP̬28Wӽ:iFoU6V ]!m$ [wͽS!UZ{?D=={{bNwvWfO؁4 en ?q[*UQ=e0)|4FTOqʌGAgu'wgw]%h SQ㙍axϵm-{ Ӻ,LcȾum_QO?Y{rX1˰KJ:R2)t`|Ox+ud'Owr@U0_+w*)h + v=fM~[IuS/WK٢Ow)Vzjݰc;f^Ⲋt %ßJ/j<E}h6v ϱ9Y֣, w*M@)Y~ޛmdA Z- ]C՟lU"fai|ϱz[!wkeih'@|e]u- ߕۃ=+p@}V$qy}SupZO \x"6 IR/^k22&l&@wJWоtZ dW}E0|ׇ+u>xC{p)ji©V$\e޾F. KWuθax[Au-ߠ7nKv-[~P^{cO\j{'i]_X.OX^3%?W ~T2Ye7`]M| {; 3k_쥍WW1= NA#޵G'USm~!ap ô96U77b*ІW(USm ͯ@!܉I1{۟%ܺ miCKdgܦ\VRT}.m|1M|_HxyC {>__Vه(ɣ}{Tkv&_HXy{'uGY<:Z~_an`.T7V2fqD5+§) 50V>t3u*/$spP4K%hNd _QYs]ΐ݂gMƕRsl9s/TqEW?q>,ӨXqM39 *+i^C fvF*C.C!g;c%KHV ? xM oßAȷg]yU/O_n6V|H.cKD-U_ hqv+M $iꙋH9pU/lue5_PC \n9 ehזm*isTo\_k_6Z>GBkǔ]3Ń}>GH1m ̚l9^49y8B,m\,Tb 6zO2_ǥY~y-J^Nξ.!Y7VѹlßA2/hW|m?d7So1$OvuV)3|y걻Qތlvw.a ~ءG:e{|R<|q>|:>w~Powq~(.~aC]O: ~o(~ yы9D)W}dq7ׯO qz_rN 5g .L+Kn>_GD)W{8`S-g5omkLCW7cѤIa|7eSO}>ٟ.?+_:/:D\H 0Qik>j{o?6XۏOoMAo;~US5cSb>'}۸Rlp 8 g+=1fyZ~h֗sj혭2)Tb7m1\C=1~0>b}{٠]0sӰˣe2=X.%%˯Ҭ%?EVx/'^}Zϰ.韣 \IEӨUf+5fs~__&|;&᱙?Մ4ˇ,ɖ?$m"V/aLRKFkBs^3Iuy^f l% ~u0W\~<y-֤g f+ }\gq-Q=zPs~e/y@؁Yy+U 7G .%\s{4@>RO{JךWwa_d` dD+uB~cT]Zm}+٧#F~ӭ>:4KP0+[kW"ۢzp0PϾg߼7Лش0>ʹ)j,o})m_=}իl|cGk\A]Y~hukbm|< _eϯd".M-kWj "; 8EiOh>YX~&k .*U+_W=U5 z A UMi-ÿdLunWX~UNWXj1wn}x^mj6S^~o8b:f4Lj <μut[ `&M. Лc%b:.!)V胹x< ?#p,ә~öf,ͧqu`KtM c;HgHLTe8͐?`y_Yq,d`hoѾ0,qw0}~vNkUb: Y|c~%NLdy=g |x` f:ڿE ,B ]j0 W(ϳ7l[wݶ ,k/Fw0Tx1OVY^`NuvD:gY{1ٽջ?ڋ~{u'OR6Y^ |w{7ϲbt3OKݔ~; |HU|ﳍ7IhxԺ0EU[WE,#ez>"xm*[~SFnǤ~1|a_>O:=|_r}<6>O:2~~U'^~|%ix]mu]e@EeZW_@T/NbZWy ?Y"eq('Sn+۷Ӹzz݀UYC)TY2Tï[w:.ѐ~QV ֹFSSAv'</b4~L;dvTrWXɦW:%OcTб5HLp1~Qo~ߚi2 JW{מR3kU]5K]X45tl}r  ?wkoL!<:#>MYS Ǣck{1~Wc΅dv!7p4HL'ֹESSA'@ Eemvxggÿom>/?`ٞB/z/'_=GAE?)/":?U,Tuu׎Ӄk@CA=-=[pU"&W2DCW^='v4`xEo\5"Ə:-dy;or8˷!""׉fEб燷 bwmѯ{כ}M |=|Em _m!w)W깔a~h5)ˉ n/p7+B?P SM?M|b)K?T| W#^si\$s˯g(a{Zs_O2e VO udm1/LwJdL_@[)i`~>ن9~ҧ*.kJ_Ys1^AWnɑz#C>vUXi*>n证-Sroj!J2+ nkoS6th  nuMl.kdb֫sv@~,p2|课Xn!OgzV@~;eTb֫y =}`ep~m$^,zU}O~^_I x}Y[,zUoR;w),T-n7 -ޮ5~[SMz fJW""zj%hu>X'=B 5_tn7m>wcoK^Ր|gJFQ=pi1fq%[jM jo)ym*k~ ?oJmu>N*~ _?N;%cv⅚#Y/GWqW/YKjݶ?[~ }| n+_O SHmwgv'? Kedv-e9iZ~?/gfWAQ8X9`=| ~j-ڛl;~ ß&EP?'6med٠aޤ6_Чv8O`7rMb+/Elco_|S$9["敛|I]柍]nICV+O'0jeirMX~Q0.7G~|2fKy/iei|!/+~.l*濈)dsrvR$jeO ː'pq[' $%שֺzUGiiė\֫Z>JO/JՖzW|`KS>E??:Zj\UvQ: *ՒfC*}L@L)7R>b󂊥O 2:ZnI*nkW7%7Dzaaaaaaaaaaaaa59`n f&߲0<=ˣ3K}QaٿdD/+ "je+–a [,/ 7, 7, 7, 7, 7, 7, 7, 7,1|mwXXXXXXXXX %LQ%tEXtdate:create2013-03-31T17:10:32+01:00r%tEXtdate:modify2013-03-31T17:10:32+01:00OIENDB`xflr5-6.09-06/doc/latex/figures/img-29.png000644 001750 000144 00000035661 12246405674 021353 0ustar00techwinderusers000000 000000 PNG  IHDRF@gAMA a cHRMz&u0`:pQ<PLTE::::ffېff:ffې:ff::fff:—:::f:됗ېf:ې:f:f:f:ff::f֭:ffff:::fff:ff:f۶̓`etRNS@fbKGD- pHYsod9IDATx{}q4l9ZRkǑKtvMMi:{ A #s! 3!s:t`@u38X8u38X8u3zxXu3zxXu3:|`8Wz8WzȈ8[??=jS"AOw@`8K|Gt(8y^R-GlJ>PBE+l -z wg:gyd}qg=8\: ؔl#88hʩP:sD?}X+uĹ;]tx3sC=ɩ3qhu]㶎.m&@k֖utثK{_$@Pȶt]Xu]\{_,g<:$qṁ+_zQΨqpg [B 8/դ;!yC8h[{B 8/\|YvIyNwy݇ !,:h48wߋksqvk.rv} 傎Wk3 )2׋/Ԑs(w8*~󏒾u!0% 8gscFPvzҵY0γuܿ>Ts0Vp};4/PLyy'0i+ι pB 8k|;'q%A@U@"qc_]_;Ns@Vs~?,/Ԑ܇885_!%ʺ4Z: !Hqa8+JqPg۬RFϾLjscL8__ t*vo/V5܇8k%>C9Ms/>}9#ι O1q}<t>뀟tu[3u}8\%.;`v]@j=ιqrw|0`!;]5_N,g T8>Y?w% D '9̴(85ZL'e@ayӏ/J9Ii3Pqޭy`8'*3m#|jfĹZk1qʓZ+m@6J*j9vZi3P\s +mj@5y"YqYd*3mjݞB2fqVLCĹZè%\eݨ@N|=^ EgGk[_ECĹ* 9mz$*#G '\te>mǹ8`>r&qgy2~/f@ qֶT>Z} h!V| #Ϊ|) #Β6|# #z||΍6∳Jmg!|Zs qVQ'wskV|M*sʠf@qgP#Gq>dO8[#Y|F,s|OPF,s8[SĹ2~i38Yq>f@\5hcw \Td[B|{08XYn9;2wis, yֻ✑tH#ιPfs@e8'F@S!Pf4(3s@j9eqBA!;Qf9=(3̈s0 ?2(8J!ξ(3 ,⼍2(8o,5⼈2CQfv q^B"΋(3;ye`8 (3R/ 2(8o#(3 y e`8⼂2BPfF* qAgD@qAgD@P8YXA@qAgD@qAgD@qAgD@qAgD@qAgD@qAgD@qAgD@qA dhG<D#@K{Xh#mnqHB<g~AenqjGD* [L[D q> ԇu @uXd> Ԇ6q C !΀:18xgAg@gt\PE8У#΀"|xPD8(g@c@73 se g@k#΀ڌ H#΀aI3F3`Se!΀֘8ll#@Q|s3Λu ^[ȫ+>5hx#y=RWZήNm,H,:[p  "N[-ӎ&DHyqNQ^@_I4O9+8R Ѝ,&(%Ι (ycUvh h7',q&s3I4E338Q* g9ʺFIEq9=4RhE/ΞӒ8g`D wBd;:{*蜆`(4poxѣ888&q;Nq\q;s: CsȔ#)h9h=ƁH9lQhRgqV4Z'E0 9|ZgOmBM2q1XqbQh4G%λqvRQhD$&qpBq)Z[e"hFwF@Q/89ف gTK!gqD3H 3uN!}fqD3:*gΕY78'ls84&甩93mnrqN[z;j2{1zuێs{k?|vO08&ĩit]G_DgEH˺ɍ9i`qf# ͳnrqNߝhsd3d8hX78N;|\`T8?R4hX78gNqQkep!'Ȅ)\焵k D"h1Β2|sqq>+9X+#{eQz"۶TJ9ZjqXyZ>}Hvȭeu5$1|mZ92rqyqasvܨCn/.g|N|e֥|LsqQ܎C. .od]c \sisúL魂8w*,Bz]c33U᱖mn89cyU᱖mn됫8 Ĺ̇iyU᱖ѵuUd\0%!X˼g@8֛mdsO'V\tfqUxϷg@ 2c-a迢mS;y8`ܗ*<֒+8幓qgs-^k]c|>Q.T35%zݶTٲyN=Qok mn^)mm39 \(Xs<:RǤ"ͯ^n?z nS@)m$Gc-!x)Z$λ} ;e-qnsEmNdkϥT~qi3q.FϝۖJ89թsFAu.t"9xG}4SvRIg6sg6 q>ϨӬl9LLyw;ۖJ8+9z]#[L8>᫂q>Fϝ_-_|ۖJ8K99;8uygs=w_U~9{ۖJ8y}QgZ670zoo_|}=],s&<-qθ٠̧q>Թ fFϝ9oo~_u)V5jJw-:2?O\xp\DgG60v|~9a}7ն(2mulRS8_O/+,87s~˷g?:~{>qʂq.a`5Su;"=;?Η+{Zvw_w1Ű}oZR9w.wVrƯ3l[*IfuZm}(X%Zװ^Vڜ'ݿz?'#>?4ق-n>>ٲ>f~t㾛mg݊!77կ_'9Og6:klq(Xs>Yb`i^~Ozz,}qZǘq>Y qL;%u~뾋y/&Yywo^O_{?iݏj_IArd!x5:7a\(X(ѯZmNoMz'}n)^ҷ[t[;Mm.=9MpgfqMZÓ wiY#sCqдqN>q[PcǎeקߟkioO^-bݕmxK۳0'W/N7ެ=?'#5]^_PHFl,qː{,7L;(nsټ驳cǹRq^zKq~u9tޯ=sb~C1۳0w4%gx㾺$: ;WӼ=gl~FQ,q~7k<_?V9߾24ρt\מw]zN{g|"¶g 5>S(8 m2ڱ[n{w?lanR{^t/?;ݥt$HmDY5y{̥t>.ر#<ϳw.f7Y?{lOfK'LvLwnqWw;ݛP~^qm<۳ lx 8{9on6cîuwYzsF9{>an>/jyx DԌtFqޘeaks8_|C4{Ϯo8㕈{pۏތd2KL8Kyl%F5ّ^q~Z+Y6y8nӓ Σ_m8?K[e%o}qs۵m"w!a`=OT:6i|F7Ŏ8o`rƵԯw$o \Aroo5b9g6xqNt%T}.ر#yљ_|7qk\ݿٵ ʰ#>twݫ_]ƯQ2}ql=IQD*ٻq^akvzryoäaw0\{WQk'8+.8O8Z/9 tfʭ-!4/]ݯnt޻/6ؓba#w :e62΀=qVltv@-֘[n={ۉuUc1~/>?< 6ΗA}F)#Βm@87)lŹY?-6y7*y3N~=ާL9=ω6UOݶT]tnW(Xs7R8"N4o4`{6⼼=z?Sg:PjaCEW寢'qY[oSE(XsY*[myk81Hֻ"rW0KO`]3}>?OgPEIg6{|djuIr+5\GwP")yޏ~=5ާOl<vs[ոF癞Gq~ M9`5 zs7dkۜ%kr|Kֳ7}z[YNGyF'BPڼ۪qЫqNwy os}O=wnq`u__^|ӛ,BO~me}38BlPS}ΛgkqvgGsŹ}]c~[8έg۳0S̿L'{qgo$1wTƩg6n@qv8KJ/ڜ>8?=o]x)Ono>ya~3\tWу2v'q*٦罫8xIeOf?j' ?qb5Yy>jgz)q]-@3(#-s;&mzz5k>B/=E8;3l}㼴=0xNt=+Dr%q2ٰu.ۥf8Yp>c?~-ޞՇqplgz짅u/aD/lD28ZX۶fjD?o/ͮJ-vm$~?>~ ۖ_֛U5'6youf*P>C@3n葆_Dݗ梳yiwYg" CqBx9csҋkږ]j\X4|3N8msf#eX8'Og5l6Td|3N8K'糮7eiQڬ3S!8+6%d,yt@Ul6Td|3N8(7b|2?$]Ʊ1x/۬3S!8-V}YXO ӫevBQ'X[@;ڬ3S!8/3ª\y,:~{2Yw ǚ0۱!4S!81'~ɤg}|ƹqڬ3S!83VKmNs]$Υvcmm]f,yƩǵ8rp5|f Ӣm.m֙Bgq^i.wʶ9sXѲ0vcmy0]:3Y(sc)Kmsg8Γ6n\dF<=|]ķYg" Cq|3s;g21)*PDgkqIf,yy2Sg2%.tƱv:3Y(d<94seIc:3UÃ|3N8olXxS+PL38;Muf H@g)8{OߨכLv2ItƱ6g/ҴYgJyYoH4Cq4Y Hk3eYMtơ喣:3UC#}V>Jg|ɞo]+sQ$6!8YqHne>{k[Di3l1)YOϱ;fm6#{2&6f'Mx9`A+;c7&_Owk.y5·,cFf3zd|8oMba).cFz8;gSOU\Vq@u]Թ/(3:e\AVK7eBT_nԵ̧@ ?,I4EG=Zd]z\3s|g/\fQg|hj8Y֛8x<CIce> yC[-t*938DԹ4N#0&4Թ.eSmx,!Ƈ@L|*$_P1 6 G:"H2ϘM)99`Թ0B($ cH3#(2M9;;liovbX ,ϜC~~5Zh1Q%gWC9ݨ֙ƐCjyŰT+PfR/v/uKVcr *4 g9x՘Jʞ9ԡs&筗 ٱNd1PlS6m <^] u^M*LwVhMWBV Scq'xr\7RcT\`K:e$=DV8"0u7xZ ya&w-4i}o`*6Y8{S$h* $cfy{ZsH/:y2C]an4\8L#s&@0u.eVrlvqtY8$2 sq:68|8ۿ8n,8 1PqY8?.ĺ' (sq^Ώgte% sq~,Is!3:m48g@u:[oqtY8_ ޖEe&<\cn3qY85qtY8k|/ sCq hm&΀007|"΀20|"΀207g A]an%m[ qtY8W1 sqpc8\kk\b!΀.0Wg͈C]a5U8E]a)^qY871A]a#qtY8Wle l3 :5zC#΀~?|-ǹ月3+$^B|GoIg"΀~vIɟ^C\% ua qte*FE l8;Tyv"MB]}=|M$ qtkN_$Ε!΀~_z~aq qtu"ĹVn5?JAg@׎v5 8X f3kOL?qD]jz]؈~k qE]jꭁqt駜978"NYsqtZ4 ఈ3kGK?_JfazqtO-lX"΀~v],†>8, .Bl8BC:4@8!΀А>(4͟&v3+ Ma82:9YNGag@WXF'̉>czqtUti }pX+D~>8, ڹkUఈ3+ /dev/null $(PDFLATEX) '\nonstopmode\input{$<}' 1> /dev/null $(PDFLATEX) '\nonstopmode\input{$<}' 1> /dev/null clean : -rm -f *.aux *.toc *.log *.out *.pdf *.dvi *.bbl *.blg *.haux *.htoc xflr5-6.09-06/doc/Guidelines_v604.odt000644 001750 000144 00002574446 12246405674 020452 0ustar00techwinderusers000000 000000 PK>^2 ''mimetypeapplication/vnd.oasis.opendocument.textPK>{6""-Pictures/100000000000024000000195D17728C6.pngPNG  IHDR@!_PLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712HscIDATx^]َ* _1?H&f &=Yz0.4O ~&jUEHI0h >RL!.t{GԔE؁Yngv2IE`{iڌLPv93m8:κ 0nĕ c}N **t*-ӄNZhr Q umqᖡ]\}ylI?@9cS 8GVer_*nQ݀F2֑cLJl6k=UWge!Up .9yQh`ԧiM2Xʗtv& ESNSYeSkP+89ȣO`4-͙Mm72B( ?ꀞIT-` (!`M~8$?@bFMpSo_E6W F& Y Ż )[նn[SI 82.y:#s/=s#|V&C6P8+ WWV !X0k,@"Pq:?Y܀' ?!|5e¡^:EGzCLj[A@ʧV*q,0NWrH ú˦UawC?B<ƒ^WD R}aWng&P{%+;m|lj!_?E n$MJk@"n]ѱ>v3?~{0)lv<[О $#Nsvɳ(P1:8 t1#Sl˷@N*FDSh DZ|F)ƙJd qgማuϮD_Qx豜qsE[.D jil!4!151&c%,_JRMhƂ@/`O$6(@h|'W޿_= 'X \,W88Ώd]DC0ۈΒgqOh7+hU 4@Uh DZ?D+ϡk ty ԋf{(1= K>VoK 4L^u>% ʑBGګec1@،0qKQ_ TBYr٠Y8V_EXZ0"gZ9~.3DbM w88C]; T ی9B8~R(WzNj6Q 4}BE0"yg\{ !°_vr-8 SE A9_]neop!@o#@E1CA jil!4!151֓JY@AA-w-]Y8p /JL l9(\ A#$—J9U뜳0p1w˰p$'+EJ }EF6\ޛ)8N⎅&@ª@a`#B&8di@-pC )(%49 x?MTҦO`=+Ln݀hԅ(@+ܟ!J..e:R&ΨKI 8͹c~UϢ3/JadԆ .ޡQ#0uXo_cz{ XȠ(<# izLK螏Za͘G~.L0,@%Ras]eo#;@5*l]N9\Y= Nަ~2[P9w# #x~oϭټ?OکRTw:@3%P=LtLmgaJNP^oÝN|9\M: Isf@Ι"pa&RWiڂUL };={, {ˆGPhͬ6/.Ƒ͠AUC`@6HJ?]#ivp J82LŐ{PY\ @3p82@9)~?O| *U*$5u)P qe>Qx@@ ?}x@bGFƝB:982L*f%P BE < }3p8t S6y;G*1)l#\ rBmc+Ƒ= %P99l.Ƒ @DEm 1W#hӣbpb 1qd6Mb,x5öHj 1qd=..Ƒ2iBFr AbG6(4H bB}i8@'fhc$fqdmK.%P9P*+Ɠ)lM <9} #6ޭ@@ bbph]#w J9$bӓ62OMbbG&r І4H b!'FͿbW͏^)QPȒhS* Z6흭sfzZ=a> مlh]#(櫰aOzf@M/.Ƒj^@AMlNtp2kR \1(PMj8BBu8BCu ze ́N<~"$fqH-8BFTbp!i<)Xi \1P*PK߹FQ b!&P:8BMlpxE05fBc3p8B@e2=B!1q1<.ƑtBRU@E.Z3p8Ur!L&w1[/A\  d7oLZ"6ͻ:Pͩ˅F%Zoo,ouq1(ԁWj>M%NKyBQ†$PAu$. %ХV%ьLjF9Pڵ=$P @) DBmV/̉(KaC 4LJTyhl;Z 6*dXT|RqD@aC=)ƖK [/SD8). %Њ<"E+lk@c#B(lMa529&4RP'o"RPm! mޟuB(lj:3O"%D TJ@P͙̮v8z@[4[p'R̈ρ@yuh AiM@(iiX*pd O ;iuQ )gK.# `=ps]oGF$!PZyOGCm ;f$#&Z\@1Eu - Kʯ%Piw) QY[mrK6?zeKA1ZZ'Ij́CXc`6,ƈ1mGd oF BDSE~ԑRY.$Hٌ[8 GOaWsLj[ e#a 7%BYv5@Kƨ˃4b* ڏ}]A#U_629a Tfr9z,r4hy6efFs^h9uq.UkXEIH|Tΐ )@k$hQDbixwġOLcD 4 kV="9Qk%?>a_+5CiH(,QۈF6hyǍfbT1aM #6{7h49Pf%ƶã)9p>v4 T(/:[aX  w\0(Iprfhdd%)4|hhDzb+j!F/9Aaƭ{,j|y֟Ld eDP- U)=RSj)ɢgEi䟿n~L=U/2w$ga$.}>{a֞LaU6(PTt3FU2!ȁBҦ + dSkY '@=~pyF4A#fOM@#>^#V0Fl$bzPzZ @nG[ӃO(@L}a>Rj* ݵ-Pc|GUȀ=չ+u=ƈ5y@bwiR ʝ:vdeI@ \bP'6ʿ"f [- hx+p1R};q;@P0*s@t2SX]i0paR7RZ&8+'NdMτ4` n&bg$_ee|A% i1'{ȯyN)$rgw\ZdA #807xiGXC wCwU ݧ0BaDJQF:0˟)668ذ(y3@RNs 6:{_# 4pd>Lh+{ݑ^xaNVIt`z{uW BVN_bp)и@hӔ^@eorik#fqdX*ɟ/1qd3 *8@!wGV:r:8 MZTo"6u@3 mnh  \1d'GP!A=AvZ)KaZx6 m1 %)lldHCYj&PdXbp&џTԶUm40@aZ&@bp'@ުyذt@h#h z]La6`:{UF#1=@;ؒQar)@A`D 8Qj)^GP @' "M\ |&܅B&64v=3p89,5y/w1!vlGn_oK$o-W59dS{ \1P 1" dBk @g FCiL'C 6cj6 b{YP.Ƒjřb/w1@"@et\H bQI\ NOOLajO @O#Da†*3 J24}Jg4"-́BGP**PPC)C ݧ0Ba59o@ I@h*hZ)t [*3 $w12uU U Zm**lA4rZN R0C64|4JF(lā-%4zևPcJ|+k:6Qh DZ/ل} +Tո`*旀bp 8j%k/L%EY(|̮m' IV%@绸4} wc\#\#`CVk_ ěٕ6\68J4_MhȽ"n74'Ꭰ0d~z>{` *B~ )%K6vLHš_@fJJMmr 6IQZ#έ%I[/2T.|t>M'g\oǡ_K9'/3j+(5V-[QɈIqۭTd)`J *>cnzޕmyW6!oqn%CC|*C $X'Sd6ЂgoYc@xtYaw1F*>ܹ2_q)ːDp3Wa3caեuC e {,  Dԧ9@s}}m%S`%~__[ #L/IENDB`PK>-Pictures/200006C400003EA10000290A6ED5325E.wmf] tŕ@-D4cBib.UEBֵ$Z y MX_9u=[K=S䴻;37e&䏙?g2s73|.]EǿO^x-;O8F:ƽTij>&@x.KS(]tAw}i,{<̼t,USX(>]hoޓbb )wtxBlӞoנ[裚\W9 al mXv`gf݂JNL?/e vEufա);>l2\a?<٠_t ˻ >.C!ͼَh~haV Z̦„M9:7UgTf;b-Yu>ϢY eJ#OXzdz{MN>d-Jnwf4nnflޙ:B:a UN}ˏ-!01RN2b:G%8bIZZlVyv[:SL,źJ҉N Il~fa+L}Jd` ޾p i<I2祦$Ҿ9/:9b\P]Ҙנƪߺ0o+.,E3Yw+\XBT?;P,L(gݏsmcuXYԅJKzMX˅41.P,lpaX^  /\X5P!baۋ 2i^Pȅ叠ͳm^.,ڮq~n  \Xjwd[ _B!ba; mGZB6^UZ;}څen'E1@(;[PckX*=Cـk.,t}@c Ǹ}Dcc%%4kYw`.,᧠xo\XGk*립?^w=PA(^yne(^wyVy  yfyV%g^ 'a gmXZam{d|ld'|o'Lc$3sdaI>6O3yUda>6OF< swSelXxϯS#,,_I}wOXx͓tܬmH7#YCUѹ#dgohAy2">~gȅ>=.P#݅.wׅz?&U@p} /j9IkReN" /S~Wj]m/ev5Jt/ó/h2Ch;~iP' ^RQ8D| /@zLqnE^ ugC qʸuH7"QC)Mg.F{LmBJ:D| 6;iрt3motLEFڛI:ɸuH7ߌIωtaPvzɸ~ F$1ٗ.ϔlubQ+jCu#Hj@D ҇ЯG!ISZ[Pn(cÔ#ualue9 u`*0\{scp\Ca|> aO{vkG8qt_F+]̘ D~CXjޯL]O_sj_jPk ɬG=P}ֶ|=-Z8s #R1ӻ~g#YX}Z6P,|~ KL8; =rB'0:m`~1Y{>Xw<g!bq1^3ι>X\kC׆@ C paIL1:g`oLlBk:7](rX\{\8DvBe;尞(6ϙ&4CBY7[?-KL4}z } 1 /Jă7awBOVbzȃn@7V gGgsR~ap~o#{^cǼ#?[\otUjKWw^3zL=A^yuW^yݟ ox5+:5;Y^ye.OWw^#$>ʷ,CKh -0O !2 @Dɼ1CoD\Q>gEPigOs"_^ # 'ץ8 }d:mWF:㍲\?[fq*Lu.yT\j?8?S镏Q;E' y7:05?nGq9ՓS<%9t羜 O rOB]GXȂށtqǪ_dk ҿ tEH/{WnK!Ω~Joe,{ä28z.ͿIx3 N?SR~eO̧8sJ59K Hː=ZNB|(NTۡwCPZr)B|TߊCE9S}I!8J-H^-V>lg飞Mq A'wrƹ%R{FyP^y2t}Z c`'ޅd[lh\W-H-i#kOߟ&26!\)mM=~H|,_؆%+[.|S{o MH.Gn@[P4vx1A&>d϶1j;</(yDƋ yQ¥Bb]m`#ď vXOiwOV;tdl#-KT#]{2&zmv==%ըF^1 QuU`1O/4EWf*ܣuq]ϔg \TQƟ[zvLɶcUNe ߃آl~Y0kkt( ŧ~ٓ.B)Ył¿m?,U&q~Uس3K_7< .9ye/c}>Ni.צ Q+Ol;67jôӎ3l!ȱ6i92EFU;(5Ǧ10YAk]Y3ϵK8 "GS/=+!ޔ!yMÍ܏:ml8-0 fV|u?\;_I[B1~܉K6|/A_Quf_*Vebiľd -Yme=;x Q6ko@4ֆaשFWܑ,7 okUT\ePs82RNLPK,=zPK>-Pictures/2000059700003EA1000029DDD517F244.wmf] ŕ>=ܫ$Ycasx 3CA(2JpP@DYcVY5$"u,WTLkj宥)jjv;0}{o_`VTOߏ7D ic{gULiJdoV| ~\ы$zcBtL j wӿ]T {1L{z]N?u܃=஬+f,>>SGx=P]]]t”Å9w=-XqqUY. yyg 2q;eXnH))'7SEۋ+a} ls\-mݙU9VZMW_Aa@+n1j zesjnTN 7wa>^ut}a'OR7=p3kƵ{,$y\C#DKN[SGhCva"o)gtm~8>s߃w8}Al+ʞs(=e=*{+^QXnc:;9TBl)%P9}d}Vn~GZg-摡˼vUtخ2O=M 'COLOޘ(ٙ7*,0߄ $'Sia_#o~Ko 1W?0ѯa|L)ƔɃX>>Qè^#wso -17_}p94VD~ w[?:ЋE:}׫=wIZ8Oi{3o?(4 WK6<1}ya.kayM0=z~fGŒo8]5'z Г=SGd 36AOou]]܆-|OغSh|{ǁaGŷD| =|ہ~`f{t;wWXA_E֝"ۗ Ҿ/hSnF۲=E%]-RN3< [`)[Z*~炞|N.Gm ^uOU|V䑱~g \N$s"; txM֝">ݧwY 3A7`)}W1|t=| vOIn_o$; t=x֝">9=r[z2x;E|/Arw :;E|o1o#5͂3cւNÌRpfjеZwt_i cXL1%/~k TiuD.*kV] ~SĨg b_%WF_'O)k=HGX:Ez^"Mo돒8ƓxkĨg@bUCr{|#aSĨZb?Y?Yw$Ѱǂ?)bԳ:1W2{(c`SĨbO4.~3Xk1Ꙫ3Dg*k=[:EzN,Z(0'J5(D,"F=8Q{q;ؓ`1yFmSgӣ;d^ "KQèHe.8N1>/_0m70>o41rc}z!B^<g~/6럹N(c= Qݓ1%Ȇ]zW)kܗ ~k#@ouOxk#:'Gt#=&=O{Fy9=c'@=I1||~{ OawΧ_K>CN_Ձ TNaG}<0NdI7ݺSħweEWGtn3i);b):˓Mtx ֝">.o@FNi7Lyޣ^cfnɺSħwM|7g &Y7׺Sħw94w&(c6 ;E|Y,e 3XwN]UX@/ouO︌[-r>#rY bN÷^gBK[b);Hcw>?c. e֝">S5.{~^rN7x2ڝQ JVZwtm|&Uu[k1|mV 'f5x;E|z'q ]Stw \zx;E|zr ϟ26 Fh);cX;Xw>^C;iy}z;V}=x[wNҮ{ۍv%֝e~[PZ]SZe*psRYߑQ]߉1Qy\WfQK~N%Sr1~8/Jcx8vIcWqTEpl8(cqG86K(cqa8ǰs%Qy88(8NGyqTe]%~33kp({/%z N8q0-O:rrI?}R >5uyߠu gz1 ^HSA͵zV' _E8Ҵe~-*NEu鰯8su\'x*׉⿟5`-KZ/srkD׋JuAYԀOW_-_R[7LN ;_r߂zI^i~D ~W^42鮰 ꑦ 7Ǽ:|sլND44WGʯ1Y恡4VfTˬ~IcFv ~ϳ<\,Br'bX穮婺:msG* \e[Sr+>(@rwL/s#|w}ua'OR k1zZ=w[}l*qN?wrtxHMݺ~uuo:-:^'J]f[t:Y~{nKZ%#㇯caǢWu9>{B{<;H|}_M+P .raTMU~^V٧?~YwH~L]y3Ey9T@v*^]uD{@0 O7Y4 ]#qie0OIN,6nk'pkq4syVG,ڏ3TVxlg<֨wt6Pc1cb|I:y<0uunɹӶ;f?HOY]w\wOwqPKʣPlPK>CIaIWW-Pictures/10000000000001AE0000012A977B24D8.pngPNG  IHDR*z DfPLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712HsIDATx^[v( sz{MibsGRNdT~#~*'XM%X)X.JVJt .V 2VKpR]\`eDb+c$~~pt%U%ۥ/V{{Eql̊=:0/MYMhu =/|fie5nX(҄[ u+:fj3\ +C믎 GK6\ь `0wt@fTt" ~@P풽tf"&]v'ƚ Ǧ^tϾ;T4;:ڋ%y?꣓SAu ng㣾\sRp"&+X+%X)X.JVJt .V 2VKpR]\k*5ot7v(dLDfAjTE+Iš~jF,{mn t/ !9[<|t9{L/u_H9GȌ}{TpmoXէۦ&\}mJpmoXէۦ&mƥ =WS vzd2W‡Ɨ4rq't}ƻ*?0;?nA[rpE ֩7qje$[]hC2݇^#~hӵjL4 32D]덇0ʹoȧ $5 ҋǦ*,v= Cf?JMd-^`Eec?](3Vp%ﳽ7ђ, +y)䦂+!JK義[}[,Y 'idX"缺d/]6 畋uˍ2Üo uX1ql|_ɸn[3L;p4\v7WPM&M̉h lQh2S6² T\p34X!=P&ₚPGe[H4]8v~ԚkRjלLEa׸ l.K3azl.ߋ}50$պKpzPh WhM~Ve:l}˚pSpmw#wEՌg^+V-#`#Ue+7ZZ F&\aޔrZ Xèp\M.u%Wq5`ۚ2p]v . 6X׮Rޏ}KsEU /d\[KG0ݰJՉ+S.j7?+P40vKh=ڷ\¥gxNr@?/^γŅI6`uXѕu!p?"£5hlZŸhY7܃xB5ngich=.Dt¢b#b {Lh32q.2$¡d[&ᘄ+vZ+qaJ&8¥Lq!2)ߛ4ݝ)C. ZMCG<%fQYװޖbzV\WB_ [rIᔅ^RJkMp)e2q]q3[+A9:Cb2,bYO- uGO|`jC|c;qys YK2çb8oM,` /.C\%ZZ]¦Úkqp*];pe7y"Yd*o_dO^t\|%i(* 5^>\˦aT\ \B+ J@\;Buگ\QJ [;^noY[q]{pg6LAߧix`MvVm1ZpmGζƫ S  lƵk! `P\C˿k{p^@\t9k7-D\oW)o^GS R` $)rxNN :.%ppѩUsBq.k~ç 78_у -D\)ZZ )tB_[:>-t#-̃dP1EX4\z߲7"E+"") 5?!Ԙq#(9Ď.j~]d8WW9Zȸ9Z8". EOE+Xaz!i6Ҹh 2Eu+p$px`<6ՙ>tJ,.ʴ_+^\tB<{pEth=ǟ;p11Ǿ..6^Clpy\ hƗry8N\b\6'7@ۻ*H:[APUo&Y yMCqb{,75!&yJMe5.y{_c[T-vg"jU"2JЧDِWe ĥP+Ԧit~񮐷6Fj㬆ieכXyڜuZCt^C{׳2,cV1ѕ؁eLբ(HisE׀K75ysD.0]t /+J\@pT{x,$\3D;VX!2G1k(HtȸJiqq][˭eqK}B`' (fBo7C,4.y",.K%]H- ?"Լ:>-R%]:ROkݻ(:u:[VO '83LO: ht zc݉„QKp5"b.- (v3hj)Մ^ɲ{?,S 0ʸ0%6\@u|5Pz4.BPOEZH5x&SU3/BpeEǕn Ŧ ~'u'rJfDWf\h2/{:v<5ݣ]v+*-sk}BRG-rs> V",{I!x\reCKq׷{ޅ5u .(j;$3r6\S'!0vDchיj.(z;u%zĴ{"yzꡝȷ08Ì/9WH}af3gyABslf*>γWe!}pU#uiV7Dom2a\>lJ)a2,D/hTߤO@rbU@p. \3%<>S\gvVE qхQLp5"Ԃ15B򷚒ťoֿ7MOO-Pictures/100000000000023600000147F0E7CC63.pngPNG  IHDR6G=BsRGBgAMA a cHRMz&u0`:pQ<OIDATx^[]y畯235Hbn\ $ 8\IvTtp'Iz;`0$U&ϭc ƇGpz޻w>>^ڏKUW7͉̟ߺ~?S+Nt!]oi#"ETU@P DU8K eRTU@+p2#lWXk~U@P&V(di•V{6 L4 i+s)B4 '~`QqQIP@3q:)dhe`@98ÒROiR@' (:1Dn#JWX䐛&Vd֬ h$3h 4Wj5* VzƁ\ O_PTANUXFTUXfĕ+YX,jMLeEQW fh 4ZkPTU@⠏ H<|^rj@ _q7֠ @Nҳ(B/8(6Wإ*= ]բaIQ&̪@W 賨Ѣ3}N (RI` :U"j@AT4l.8aFWئWs9VQkQ_ˌETD5N\ͭ5Cgn26G5U k* JOiS\cR(TU@Jғ@&a ڤFQzP@E`}QzHVM'VhQ6wCjqwS*R\1mW"je8묔LZQ,#⪅h*Е郾2 .c;m`Sf_PYʳ(ZBʮ@ g킆V4i)U@Su :+5xz-ըPRT (׀@Trkx]|nF&.v \n@Y"\ص=m!I @ZJPfQ(C0丄ߴdPW\I]QTF H"+\qz)} ׀-23,jJgie" Xf-"$vPQ_UPD@LUh 9 hR)LQ} Pu2W-@TTwWI+@dCe$*9a _APPQE^㤄îR,Ȉ*U :UU`xK,Z٨+`6GFWP-(ϢVgQ5NJ>Z)h$[W-PPD+jƮ-췎>~S+,>[X\XO",]+"J GF4HKQYoEqYg̏Zq2b *Z8֩ ODɮ|W Ad\UTrzj *0ˆғ0WvPe5jauשϢm_3ғ*01 v(R*j~U` L(= 9ZI`k:(U^4װzfg. gزP,ɪݛZ\P}epSqQ[!8C@SE-d}e$?gU n/lAU XDE(2DlW}h1@H]@1[ +-("jAƢut]LкR.E^:ӕdT`##V|[k BZ%kX/* @ Y_Rӕ شbL3*@Ggh1`'ՙuSNqTYBh _C> l2 WuVX澁##iyVR@k\p8>wAa@[Pq5Q3?Mmƀ]&Z > ήD "$N NyTv L(2b5N3@_ !82jhŷ֠ G 0W( B}KJdP~XKQj/ʁٺl?c'PEZb;ȫ_2o1Iu+ Qe ՌJy֣ V, 5EuTQa3.LgȈjFGUgzh4{ΎZA%|g ׀-jZ(.`T[Ȥ|C۴>,J\*GQQŚ _h.V4ťQRJv[O5EE!ozҕXJd7*fUDqZh(|[ 7'g㷮c\2 Soӓ@)zV@Q2M^&qikT~=+pPe Ռ[NU`vф@ͷWIڨ j>Q[}F+TR@H-!YT7lAU`n.k_:ma5S|t(w^C9y)_Zwph5t%ŒX##!V(_Pu 㙳 5E-2vNߺaP~xȸZkPʍvkj9z9 4RI VaߡK|l}BqŻv%BQe mD@l\M"&Vؕ=Fu qdDЊf -Hu P|)~sC1V5Ǖ>3.TzE> ωZ+sJ9!8'dMy"ʎ(c< aK>H [OW",7Ȉ*KکNOGQ(eF'~[vׇ|HD|fF@PEMtz.vm.}`n1ٔ؂+)k=#(H:ז-8ò;XNPVhPήtx쮹D ayħ\^NF_Nz+ߟF@"tڸ8C@@JE`A@*onO֎s;ĻJdE ׀-W()GrV:rC(" eBu Ȟߧ!C@ET GN碒$tIWt`.-U'ՓD luUȑUEhES΃Uݤá\6ؘcdgt.vA~Eb\K?+ *ZTR=,{BQA[[D@[PqXgMX*fl]Dy)>0ct5DrNaeaagQɃl4 tp7ي'R?|b8^akfs$rP>@.{F?'9/\%LTk#dJpEPW"ᅭ>xG˸zmopDQo8#;mܐԖYk̜c3DB\Tuw24'"UG+zP7XU4l>´,V䩕 {X$YE-D ;j~Z!6CW"p;ZϬ\oN >"[E%EXzƕTՀ>A0f`6+d0y +ΌlsQqhTy"mD<B`%f>PUQuPr^ϵ i-6.7$OrU,\NQU&Pv`W}®D8!pUgÑ55hRۃr\RʡyjVƉ.kB0á փ}C!u!D A[PqY$ >r[&DprKpE^D6'G@tAaJ~+fry~y%><  +z+ t8N6`\JPvmuXŻ cUATnXm]CDd \e%Z()" 9³u%vs;RqW*?H嵾3”WN3amK;쁗> [Pq%5 U]hmUU^@`TUf>b0ya_h( %jf@# 8.3o [+pXwOEEqE6}N: 8Q0[gSP؀jZC+qo-(5|sH)V,x6{B+)E-Ra-֩90YFlAUեQT«( r[&R-lNR=Rӕ'a_c /yDX;.%V8OR`NB>"9(X~ /e}-Y\ >:`]@d0٘q6GFTY Lf=,6puB tEJ=IVcZt.v92!'FnKhod6BRq7}]sjh/Dv,$]%q%ΉoPӽn+2x 9FV@f`)E=,#iUٯ7ސsɕ-,B;DU$1'P4־-8Lڈa4'"JV8gQAv/[XlĐ~&ןyYFTaC*sƪdsBV숒ET'ai+!;j~T+dJ8C.kV7W,D9ģB ,'q|"Aɒ*"Dܧ9l:U+&LBh`^Ԓ P2m)l4\Ѧ)˸yy7 ?y۲9 &L8Qe ~OՕ4y9C@M`|2ҋCzuy0 |XVA_AV[,dސ<9<V(Eu`M s|)[" !(_+'Ċ܁k?p87N|*,b>P2d˚> zh Tߚ*<( n[ =MNWP a@@S21"ۅ [ je?|㓋|8x"Cڸ4_SgewG_gjU`/_~%5.-Jp¦p\(Y>XaW"pp܄7 'G&E8տIJUnKRS_ᴅX-_X&]!`j{Q"J=( 74aaVc n;0W`)M?y}dd#&2ٿ|=ynVUˇ9^zt"0%m++s+>@:"OW" çMO׷|2dɑMLO.22 }We`v*,~T@ev W4[q@I`"hK(CTHf,+,"_f=ۦ=ᓃӖO;29>2|zꯞ2{ޤ hEԏ KT$ۂ3Q 7vD!" $EC4sp(.ȶNӍهDWW4d>,iNAd)&BTatڪIPN\AV[,dR^끕;S P*t@ ia:g}(#؎3dE;'C),|D4{Z(ZLR 6WuA S}9\A\kb\`?-:TRo?ws {;J|P^`wr7L"r#+/̶PN\g\E3h _ ĭsNj$V=IG`AK+fX-<[W"p>dBxgU2Lp*mHA߅ Cڑi˧n~ΝFV,,L G_2m1 d s;b"*>c!.L&`O|$]dO4 , rHD;dh<t>|#(%?OuX%n`-Z 57e34,BVy e?uW'?i_\5A%BjmlӮ6+B çΜ٤D!S.8|N5j+('./!VCjēk&uk\qGžFN> o.yښj ]gl]Y%8>N~M|ז߄|szOtMj!`M}c%[ 4嶀;h1B'rm+1ɑ 'ç>yOg"`~0UJ03肭078$'0NQg_>p+'K&^ oSP h,DU]݀M?`qTR[5! ¸{u\UDp2+ KcO?5t ~hF䷻}=W1,989288 F|bXEI/xV˺2'haTHe#cU4HW!ybY8#=rdeDn@:"O"`\4z ds&;,LBPaE*꭫`5"T$)f_?ʓ;"PqAJ_'$&N29>ƅ*E0~Hf@qQTW"̂{6x2{&Sp%ӖO |PY>QV52y WڢYWAO Ajr[e.7oN aS9rJɄS킧&Z'*Q53wxes&E0Sd)&'LCŞo6N@ϢZ}#7~D#Jn4GnBIX/y-&ǂ/T'>/9J6 _ OpJz>F+NF[,;P+Z*؁&;1$O Ku\U \T~.Dc=K&'ʸ13SVڍ>>@F= )O>y'ӥ7/4ih{=1Mܚ"RZMj@)P]9hB@f2w}<KDx#S9ڞ(O@ X-4D%w0 B~ߐbӂ'C,Dte>rF4\:甯E*rՕWIbGZѪ+'Z< ~a,QqgrW7#;KU>tYD ] (Q}&ugcbGXWa9yIϽ!' KL"p g[ P BlEt>~dDɓ=0xzG6ia鵟O^uoy#&Br@ ff<\hamJ/b a~#'V[q+88\6!)SZ滠FpڑiSD=޺tKO.g~f9f_\JiR 8ģhcX/ 7A~N" '{7 %8ĂVGQZ786+~Q+J(Zf%A\*$SiS@!xGNO6u\třΜSOT4'S' P|ӛ&6A:ԅZ![M 5$-e%B>T>^>ֳX?3`d0ЊvtvENi╧{d <m˛t_o<](2N 6NJ.Ub_h b)ݣqT_$40i\\U+8~?mUi7 y5`iL'x:>~,`5Tmț[Wj5s W. `3TOU KRwQL1' [%O%˧Nq>9s⠯7p]%0J0u>evrC,q>(I&4gzv[zԩH%yb)>帒| 1V} <+h)!7@FαjssJ(?];oraSL&xdʺ>vyYD<+R ^픓nบQ3$rGw1SLýL)H߿mi>> kHYYںZYF@,vhz(2KDQ˙QCֻdʶʸQq,eg3{i9S2 {6`d)ݾK3&Q;śn[,͍&46jzg׸3z(rc{SkAVOwWSɒJpav-]j-͋Q\ U׍cuA_EKM :ֶllFǺW7w1SO^޹re\d~0N4mŵAߛWۨ!dq\e~ccBdD +p:{XWu"*O;> |옴oR'{VB%qֽ$<!4(H\sT=}8=FFTS$@=DW!-L\ ;&wQ5he}7l5k%8yzý?S|z… {W~o'p(٭S#o]-\j]mj/[uC(5 ʋjsO\Mv:h{$ {hdDS;3p d#!xiC& t;&jxaw쉋蠯yle,mJDKB+*,v/룽 )9.c2oöEƿӗpJ9$*r%'6)@G&ǾLI8\pO;֯K4cZm#L#,"R[2s Jq|჋/md&?xi92p֧?OX5>JzX786攅,Suo Wm#B vc@zkU=YoĹ5SN|ڐ1i_ܽxQ863K ~l 검m{+jݻɏF]=oY.d]][寝"'O㰩<}m{WӎLO1i  d^`ڸ|fv˓ -ćy7h O1~Ȳut\UD $/{c2k׾QN0\㻜 ,ʷ yv#(6|$ş>M7x,y"(x`ɦ_i󴩲g/s 쌸"4/:<[)GQfj0{~2MN_L^ҶiC,c'KI>rsOX/1vXjl9m:\M8QJ5lRFm[-ǂq|Ni>瓉8X]TAƙ'3V{ tD` H#*ѨV@slѴx{A <2%䑩|3W^pŶB|sp0( |W:(\(w>dE/4ӘL=C!|z ?^wiý4&XH`$tF6~VG B+*9n&P2h?GN$B0}$ klfNLOIK.|2HyEa; NY@#4c-9N2J4\P8}?NR-0݌4cN~u/?QFfiSKEqIJh׊ֻ`EoUhTqpi qՁU1`CF~)9mT֙) SLmTSýXOtk!9);#8ƛcE哝G|cUSJarUq?{̶iu} pڑ L߼t&}֧tSXK8(_\I+oڵ]NYȈ'.q Q`Y5#7(%.%iF=b85t+iӎLndrO3qgod6\9K;!|IJ[eЅrp¿wܘRؓ@+|rrrUee&{WNɇRå7/dW`깐̱5^{V_@!aF<[ M3 B8=ۄM92_zRg~kY8[t̔~3*<`rQ(Q2֫B *lU^ThktU6DG&NvX#aNe/@}q*O+c QSLh8"ILC$ 땢(r 䌸.[s釹/AM!tOt4ddP c ~ÙH31]]UҺ؍z+h8svuM9]UBćSK6r*n`-M}pU,FkGKA^%I-V& qvЫzy2Aξt]|0N}nHYNLpF R5f%Djs']yJNG Uy gݟ1Lt{`AHX(o)qa{Uo d'L8Y2æ1,L2򓍜pLv-Gw}}Ί)RpA`#UK ]݃eiiK K;2 p%%>`{إ NbWYXM0re g`Wd[$S9XFN;8Lã#/m#z|C'|>$Z1_$S>hq Ahe?ܿU9G|^L>ɒFNI,m#'*;A\nUENSnrzIJM^ʫ$8̌ 4P-vl90(߆@ eT SLNY2s;W NWnWXiYA쌘,ւͱ,zje<prړ{?pp\ؔK6 $ ')@%pL[>8{7΂xheg\i0p] K擇 B _3_y0`LN,pyNzCOr`⪷@0 Y_8 CzpHv6lL-1NgK~FN\䄅iU[ H1jw,d rj'QooKN_}0*1q( NR <-'.p)߆d4iwJ.m9)R r%}WիzI84#\3=ytyY )9"9鱞b(l}8$p0 UVdC4g#-3@:> HPi /91L-db&C&XFN{wzc8)]S̈r]OV@79S}eIȪq,DzN ME+cB?Gi2oCdN Em~dL7?spR>1Ox/< LԜM4g>ZY&&!Q6X!T@^ny.J FpJLRp\kQGDp%{ȜϊI5p[#"ӻWnP|8 8iQbU  AΈI= A\ݹR3d&3t2${`0GM;2UdИ Y$V;9#r3ԍШZE?L14`)CU>kDmw7ڻL*DN%U|Bf$p0e.pڝW7/c,3!hdi*'/Z2L2 MXdwVi^pvs.\ %²\ۘL\'&%كWZ一ɒivLr?؜P։(Th^-g[]& ,Ph21hӞc8/<2\Txδ yQp ^a`d $fzGsKQ\ɆVW1)2mZr?|{$w1/IxL/h&'9D(a I`Y\qJNdJpn?&dMq̔#SM92s-~Œ[$u]UuV,pHDW' jwFLI`%'f̴jXB)iQtjgPD$ d#!I9 uBB+gFKՀ]23 Sniw<\^D;ZQYUqVni㬡3)"x&)\ѕԺ5Ƒ UsP (N|8;8k\egD,$ ; 8GaC)wö rG&s|Ԕ{ϥ(U '׀H&7gA<V=~%i^xQ S)%K@/~ y[ *izbtUDE7GWz㙰υI>W4ƒLӼ&dz{PQSL3=?`s(kxN4kQ I J%F\D(gђ|_ܱJLɏ,ɴ9KciöꕫҸj2ERDȸ8 iPcsE8Rx1©JD9͓";): uMf&xrJN =iUVOW1%)!UZA6Q1ө/ov" =6`Mַ8SJ촘 נWȆU\}t_N0E6g]?!F_b?s& N2ɐi 5BPAj-hYi3 K8 t-g =3b]21ȔRyC$G&NS~N?uz ZT{9U b8>" PolɴL)ɏL-FҸ,+j-*z; 1L`cʲ-s&`$KK.r2`%-*֧δz2ȃ+T-fbi|$/Cb$/ak4'WYDյY = !oxN. C9SLـi=jyi2?tC3ٟQ])K"j1ZīK`I iΐe+?^тLհJ&s*f7*F,ڭU f9ͫOӃ?C?$Jpz̙ML0ɦޖLQWfPZ+jp 'z=|g҃_ݣ%GnoόG.w0æLɵ Õ [͹hQ6_U\ْ& M{&c_89$/<ڣ1)*q֦,,i@ÒyA{YQLo_b8a&ka~§۔9QS=C[r1.Qٗi$8=g҈F`2J]8p!]}I޽fYzԴ#S }t0|ĥ_V`AEV'ʍV$7Ϯ3"K[Y 9M&db6Xrp2|rɊ_!`rENϘ)xKDT!i"[ӴX$p+춇vQC>hai!$8vGyφd2d" 'rWBu+ЇFn.ru|9Ki^h8lʽ} Jm'r JV0UQ+po!NW]ՇFrڥ/R@?/I:w;7w?xQWil 6=`pCa&it}B9|Q>: 'U+i$O,T&'rpn XNGt2|!z+XW0azWuPQ^d6& {߅?LIpH@[\J3Q*?=t>yp2 B9ǁ,߫m(ہrj;C}l!|z_^OO^'NR7'r!MvibQ ~ S_~ynw~tƏnWL2~4oOAQmjO޳y"*@@'QW|>2ַ*}KQE1%?{Z=s*"jNѶUzEMK-NEL>PKULXn(*09Zj2g-U@S@%%eJ*2 , ZL W)frmVPT^'RD#گCRTױ9Q #i&U@MyXkQk_imQ"2*uQ(ifU@EET/hETKunU`@o,*EU n3T(tZP*XR8Xd_uWRl-z=[իm_R?5\*PPD!֬@R TIURSD{`eN3VU`- wu\15U5: _"jVQU@WöjWdPlSETΩ@NE*}#8EWD:(W$PDIuKݞ˞:+Z (ԪT)QRJj=KU@j9U,pn+PrifU@EET/hETKu^խW FDجŚN;T@W4`]_E6V@6VXW)j$V;3lm^P@%ѓ3d}]HCqZՍ)#* cQkP@7kAPDS,UR-V (RinЧMݘbΎeNj[5NF]h5h t[V)EԲu1Gh%%Q`e* T@HӺA^uDED%PG#RCjU` (iZ5ȘE4=Scfw U(n*ZV[]nVkfSi&mG+:2vEPTUW@Н;$!U`&Q3 ͪ* PDWT.hKwJ%,VQ@zZVXt#RD-xuUj J)ZjQU` (o @_>n_Z[,]ztRW(+r:+/o,fXdrghP5dU]}iUPD9F"ͦVDPDʩ*S+S"jy6;+ք{D[\ELVTAE!"cTV"jF:+UU@XH: apIENDB`PK>gga(&(&-Pictures/10000200000001090000008D68112626.pngPNG  IHDR ,PLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fDbPtRNS%bbKGDH cmPPJCmp0712Hs"IDATx^]nW K΅/ R7KB#R7;Bkx s!C4,~NS~ 5fwxW_թ>l}6t>_t~x`'8/Snr?N^|gly (#{X˽TsŘI ]`bh6,*7[xUUjjfժ:|bt:t;=^âuZ;moAob} m {p0s0[,1MFܚm Fh:L&d3tl6=Ml>c>[3-?>ofsj0IUՂ`,;imu;NÞ4-ҥeGpŦ}Ņ  Ѓ5v` ve`׈vc0>A{MZLaɛ c>k6Oc:n c@m}X}~D856M|k%UCHtO@C+12,51Á [@iBdt0Ok B1 k̸5+zGU,*[(Kjҽl=m\ | [2\ DCQ{@kDpw][[؃KxCc=`AP` 1ov Hٜ+@qY6f.sN͛͗P|ʃ$@0Q5(١ 0p0 z/C۴2İ"@a _PA[cL!pqL8k+bA"ah-߉3|dWư<څ;N8DIri?"AMDI ؂"@f ۰9SW\~D $9(vAT@m0c@4Ûc !9B[ MES -`Pɘh4E1?{䉍jnjfx"wBMFπ=mBg [o2BՀp[-+l a: бC `004v")/Bd9!Nf !q/a+[p1ybjN.٢%NIН&MQDfPKн؃h0vl;0#jId(|>A@I W 7sLGM1՟DDR1sz gM캔c4@-b%>w\^2tb ik B E x4>;C!gdPwR G$KP 1$7IbO@7x1" ` Xv|CXQtژ^^5߃Lz.aD!#'!QPB(V0@O/ĚC)O *ę6 ['3r:$ pp TXtFqtIsFP3&+ P&1Aw G%ө{Wb +z70G9\tvSQDs @x1G L&?” |# ǰL䘠`@K@(tclHX- Y 'H!0VKo0lBof1c`}"ID ʶS{ &Cx $\ L w[ +B1C O%"p<Ɉ6e:Sn(DEb!?Aˣ Esx99mT`̩\go(ߦ(KI Edb{eL,z=X;Őd;x"KB `ALA LBKD:y c9fsl.p߫ L'Pm6Y1*(K$ATeHJ:c\D&ѪEY&S A<Te$)6, VW8Ϥ_ |0P*Nnުvvw~0p4[#QCE 9PQ9l@\BO 8\1 DsC/΢$7fh0]E0Ȱs"br bH hCS%RV`B+hQX̿~rx`1jsM!x(6*0&O5c h5@B "Lr~inU-B)(CGp!R+Mc1\c&HZ2 w:w]&u ާ>`S$Ҭ`CY (b/T.TF]MT*Ǭ;KC͓WP'~L9+g(1q ,aM) [D o]x8j/groWJTٓYq8*hxPF:EW=O_'5#poz=(P!_Lc{4%QCyZ zD-ojVV: U Kw0az~.XR\ ;6zeԚ%򡫗ң!řy^QvV)R]Jan,qmxeP2@!//H,_Lp;N65RH-04 *x>qccvws;ZV˳ʹ 4{- vy\kA;v̱v2= q?=\D0Cԭr9A[H}y9zho$5+}N毩_p:4Ho:.~ x/I:Gմ2a+dsd/];$ZEO[Z=v5BԒ~`N>8*Pbļ7;|Z#E ^k'͓*]Y<8R<)f$C"ՉO]A)zFNm^+R=* ZvxAa#<%Fo GXrsxJK|8!DjՎt<͠FSϜ(CaUp*1[)6cDε b>$0AKGf4,Laԧ#.;*gJ5}m fc NɈ6ctShRG*Ǭ;wN֝ovɈhh`/x7=n6#=2lۈ谒&*&("<s4IIgy1wo/̜ 硺ȃ'Df&/ٶs:AzPe4[V(9U-R ځf"ӺX@H=9:]&-h"T?y }4b2{S_Rn9~$I'D oL|a(TDnu m#RЧ4]/]jB\ SK}}7^F嫥#;A?J GѻV҈;3t8L;?jߍy:BB5rEQY2F#oNч mF+u H|A*RZP8/bBZb̸"\ڃ%;dXQ~p+'zhD)LWt?\>Bt@ű^y7zzy*VB-AkCލQv;sRަ%DѹM7Gl23Sfџv1|4V~‡Ej¥ax+桿}hK.y7zƎuS gGI%ntX"F,_tr:>(!FOy7z)!FOX]G~Ȼ3 r-F&"]{a]#7;Xy>y7z^5a&VYBF1Fy7z2&opCF2.d.p?I_-,.+a!#?y7zz&+湍9x-yl,ʹ>d{7G.snpkxx4?!;?!d;LJGGx?*;a8gx4>!C? 9ԉ,FIȻ7v{[ۻV{ޭkmWݪ]on w^=7fGfܭ@S*s/E)Kw>i̺{v78}wOe~[Ư3eSZ}I%KzW/Yu7|6tΚıH~q78D}7zQC#hZ(/qDy7zfvi}[.jpdg6g7nѭz_wCH^Sk'BFM2O?F.~0s}\ Ȗ-Pictures/10000000000001FA000001637AAF07A9.pngPNG  IHDRc9PLTE@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤X4DbKGDH cmPPJCmp0712Hs`IDATx^ۖE~VnPOWwJwLVDpӟ?~>?7GDOmV'϶g+Ng[-يOl? ; )EN?z' f.ϨwϏ.]_ Pp9[iq~m"Cؚ}xnNM 4E&+>oOrvp"B h^җe=@Stt2y'&3tOSTŭqpFWzS:G.\EX0)ȃx"zNޝ#&:6ţWˡ=GM'햘𕻐t_қ(aMkZk{:O|B/o)2|kޜfq'z ЛRj?N!lc8rӋJu*E/J7Cu`PV*ո^~vc|D%%8an~X.z,INSA0^t~uH #{m8olW\P&raTC;KNo\wEoҼbcuU6Oq8ɶ i\dkbXS+)͋B!z;+>~_j-8;]Pӥ#;|;7>C3Vw}T8 {ވXxjaD(]f@6& C4VA+6sSqgz .5Bd,y3w#Xgv&1ႬH7GT9_T!#{#AToWmb z-y؜sDoЇ䡴 x69|i_ 䡴!&rwa{@469z,$-޵nCiAMpE$:7;Á~IaNG8+oV:& i"uܻ~^w?l?nb -yw&ڽ21s+)>ۜ=~/A4OPw+R*Q tYzIe;CiAM>޳z^/Q̘i^[K߮TcBH5K} 'cC 5F):izgxGNdHMOp䡴cHqXG?÷ j̝/$+ӌ3j!'I[ 4M ꀼl1"N< /)>". h{? ꀼp h/9@^@SDG"z0zڟl8eћ~,tqA!n hi^sϟ"Vytk:|C<T]T}nTᗐ*,+"O /#OˡY{; =]u_L_Lى@MQu];"*"t 95KER+T[W-`/%Oܛw3݁]H[io%'Oկ DD*D:D?*z7 J+ܢM=8wGtדW-z}PYT^W=pw|}i~xNkj ݢyVRv/m}*/؄+XAܛ_,3o$lb`/z9]v8 yM}vF3y{*©<ω@D O3/8<_0F")ywi-rzcNStŽ0<}#$.}9/#D_}\ff&ϿoToiIڧuT\ .QE )+*I[E;z`%ws9F/E{Jɇm $V#)a&O8j$yw AkXŌwy&4%@K::?R@oiGQ2yʘQUD]tϷ9xVM]FƐjPy`3cGӷ3.up.XfH_;%x8y9Vhjs'K}dD%z t`gg_p2Y2~&#S2G0ߞkJؿz7UtjGؿ] I+oB_8+]qMAq>lBաu^_r& ^JeSWW}Ο|ezz}UWW},3Dx -!z?~ᇓ='r4moCȿ^s 6FgU^wǐsܡ:_zDL6;z跂F?ND@݅ ލ^Fw)c[21;zOW,*N^Ϭ3y9[S}ۑ3VӼ.~ai\o}ܙcJ~T HͿz4ZCh?BAU/cX"LԢozK:o#kB"?o%p\yW:|i>I^z^ `ߓ'z!yhEG~e!3͸q -zX~b,G#W:|1*2? 9=>]:'jϐwS>[FT"Oޠ K7I7N"An^}F>}MY wzC֙XOl\rGl>rRǙuҷ賶. Ys2AˡӈW>LKQ&Y\+b9.TY AltKD}'1aU7yRD/^J"Dj6#k03GhI C|&=WOetu`>u^`@wO(G~ UލZg"%H$v\B 0ߔ !y:|95V@&X/?LZ[К0vSBX^=svE ;R/Qc};.9W ^/&tem"h$<_ٻ~Oysy~ãw/17?<&?jm>~oAHxD|rG |; /?ܑ|16D?AϷ w$A@<_ #bm>~`оXL`IENDB`PK>-Pictures/200006F60000376D00002462AE65D36B.wmf]{UřED0<5aG`5 0!2 8ECE 1>XE*TRGv&XU;;Ez+՜_wQD" '-5"*4s2~sQ7rp]j>ݕ{p]_W=|-[g{xWzx?W\=w=] /o.?YB񦘎}'p `Dc{?sp .ǎsp qp/HmՔm>zxwȣ\dH,[m" 2eu^dwQDNʶyn-VSg[olsn?+Rv>%3.[&n? rNMvp)e:sۤȂ֫SnrLwM&Y}8";" ~gDv3g>us.NCY:eu4?-: $nteu:֩ȮNC":=:=:9]NRiuڝ;7i:on*nF/b/ ]v]vWdWݹȮN}ȮNϢNϢNWdWN_MY^FY^FYv]^GY^GY:}3euz:؈d;f?(dOQ9(k:֊x=嫩V=躕[k.\<(Q.]s0Q.urru?:=E.\<_O\d=662;,l'ӗoR"!.lOcR"k!./"3gIB\yg#WdK߳S"v"񑭟 ) lq}FHػB\.Q5m.e}f"2K}"6QgC\ZίWf&E.bKq]1ʬeE!.ރݔ(ч|WgʝlMY~`?E~7+qe;xsMs~`kdoYwUdklU[)q!~8Gxr!^)r3!;m<ΰz)Irs+!>s-^jw# O_(goBBfdyv<䉸N>Q)rC!By?7 yv \kh9Ern%ı]=]yv^WjBiKQӅ8k_TuؑG:h-qH$!t1 &ǪH#TǾ5XNV#5Mu'Xu4qQΗ8β}\iD3}M#Yf#gdCf{8bb5X-Q8e{d Zo|S(gCoTfߤ^/} m+!u!ZN 1eХ6͸.ެ9;BV2yv%p] -Q{6sѦ&\7I)rwY827^[}m7 ߎfk9E畱-6՝u 𻵜"GyOP##m} mZNH-Cǃt~}Mo'kO}QQ|s؆褳ՄWBjc)3^l{c]̏R x6yibl]̏f#΄<\On}?so9ÔaAl/vy^Cɐkb[92<998/ƶY+8B{~;G cbZd뎒Y/0{j ش߯ɬ_PNy ڟ"{;FfM؃|Scb~yeRّ)c1?& :UՐkhblXowo8]n$/~[~#~U4܆U%/v[~S~u4%/nl/Sз45&ڿجBercOV[3>cb~z^:Uj &hblUo-[[aAl/NnSfgayiڟ"G6eqtة5hbS̏϶s)8΂\ئ#w(s&QyEڟ" >̦[- 2O_M꫖g1RO_= 2;Cl/~{gؖjߧXO CcMNV`[Kn*?y}>+ll{O'y z Gl%G?E~ \[Ql{IZlleCyu϶'ɬ{\;+!-c3c$s[q6H؟"md1'ó4r#FO|#{ك4KOc{b۞؞ O6'?=[4T`S?E~m >Cu/Ny~ѱI~p,U TmO◪TE1'~?۞ƒ؞.<XO|)TE$ 6FSWo7| nJR_؞{l{wթJȣ5F_&QgM}^*؞ivSѷ,g_i1'nl{*U XOc{zfS-iZ`ڟ"?~]ˁmO2?یvM5DO|/2=M!=<O|?06F=Փ؞&CV)cӬ~X^l{Cb{<O|1glj.k1's϶%$[)g؞؞'=5Cڟ"?gm/}j5h1dl7؞VC؍ڟ"?=mO|VmO؞6@-ڟ"?lx`{?%~)i΋QfmK_w=8~ia\JxvSq<_Pr87$i0N:6-Qi\LM q(*`;lOHcGT4ZmH5*446HcyTÃiLi+ƴ4j] Qi\V4%7i k B6Ϣ>{Ng_Dv'mQIK}E ,oYrוWҵjV}Wti%-,JZnym>{ylŰ\ih[hLs+zpjgևЌz[TM_]nwuSe}7Ѧ~*[{lӭzU>8*j3#ǠՑ2{3iFw_\*mS|]b?wr^Qbϲ0o½Ff%[/^{޿EE0_eی6}G),aʔ #q,"OT3m+'%Sˇw^C˕}ϔ2)/x 7,sab])Y}SO6/?L׻Y{ r~=5YU4<tX{:tdRo?8]}~VJ ɺg2 S1X˱{7=Kc>C:t<2lJI/cƈ3U^\`1\Ox1 <b8l%cD7u:[)8NN NV'ut/a":"uccuN h׉ЉЉ:`nt1^ ϛ\}MʹS;':I)~k'֒0pkuյBZ~K+= C{~^χgis /grs!7“K>eְdݗM}o4:z;WӵZn^Ba~ye:PK0PK>/-Pictures/10000000000002B600000161755707D7.pngPNG  IHDRa ~gAMA aIDATx^$Wuk'mޕV9$$h0Lr &o``mm @A,&m9NTnU5=Q_}tW~]]s=; 3@> 3@l|g |g 6^># 3@> 3@r{~3a40:TgPP>g 99Dȯ|!BΗ3p$@&@>9D8C~3Cg I"!#ar07||!‘8"@> L !  3CI93@_ !g`g 9DgH"L10|rp$:g 5@>>9D!B>G ao 3C#!9Dȯ|!B8f ~sg " !!B~ 3@r09Dc>`> Hu@k |&}rC|!¤g GBxȯ|r_ 303C"3p$@&@>9D8C~3Cg I"imo/|49DOyrpBHT@ٿsI;9D83pf Ak$DH>u@!|&}rpA@vhFϧ J9Lqrqg ᐀Xn#tId='B$ !]/3|2@&DhKd YPHkej+2߭!Bg@>-f "4# \M@(`2NH=,SxذS&CI||pg  H爫FX- R!{rdiv@;c 3vr09%ZvfJ,(cE=g2@g`3CB +2=˧d2 1a\ӕ@>Yf Bz;Syt_-Bu12HFǸ%H¥[3&Y#o"yi83CN lOS9;:lzq?:>U`ȸs++[!="'*-|@ˆ~k  @b dwC!)4͙xH DٗX%EC#+?`>{r@,PĹz3.ա':ɴx2E#7H(ة"g>~>G $܊s"q\~0!hd";U2X^?[)ow["q񯠅 #<'$C%cx@3 r:2])&g-VB efID,7EyS7Myӵo91̴M^jQ`p0GbHN(v?o>@Fp 3'T[mdIT$UOaIw sw6@cQR6?xMvhih +X6" 4 'CnQ 1B8730R9D&b$w@®d:K:/ `LT6J*CMw\e(~gF8O?$f6l飀 bYˈޭOC'·|;nhg&Oh *>h3+u/UE=s3p O$5= haQ)`C By iK*z6^b6d6yFŘ`Hޗs`ܠ1AF2hC:8g mň'(DOCho`\>$&rlߚKs% ;|%K0 A ˕RyOQS4xx؁ƱΦF,V+A k>PNAy]#%-30Y@y"BBl Sk(8@;l ! h8&87=4@\Og({򞭼l<؇=8]$s7x QD`FvxC6IODbe_gBzD&o!&Rkl \dr \dW³ m h{򞯼({V@c ')a]6|FTsXa}" ?| 35"QVP͋qr60 dcBd!L@vh(Xy/I*l/7(ef{~_7F`3Kp #1UC9| Hd4y$t(w#BD,^ob|gG(3c>~ H1Z\jE: )5, \VkGcyy'KlZ?lp'Eɐ0?>A2ptp{:> 3ZƑI" t'8@AU~o4T(D =2" $)@*gA)8?␸L\(!x·gbڵ#"!MZڅIX 8u,%Y*:pb(Ȋb "/g !H(4 0аOP1z@N8'w)ާy7#gk^b8NadZZ@v\m1M|23K9J!!xOO)I, O2:!)l#"aZ>;PYpmKdo;x[C[4bl jSZeN(FϤA:w@lf5/TMN' WA}HyVG~q@o`"h23'"5hP_P @0d, $_@ntP'  h(IMyRާY}9@<ٍ9fc)QH8CN~ >cU=iyx"_\~ $g 1;@?UfDy3IeL${p"JNA\Dh tNAtO7Q*+&? X;'<>`4:  P*ᅯ}Qy/++<%*|lQfgQ`HCyٍKtOȳ0?DarG|8X2Hv~C|`E0QXfؗ:AJ k_">8Qj |H"==>rVd@ XY `>i4! Sהw򾡼o*ol YS2q#EXnR|hi!ˤ7ۧٗef.S4QfAh &(AB@jD݄P oAe:}"1kwVf3@@P pownRʻEy*ﶆof,hg97 9X*$al^p*C.<'Xn/Za⺷ÞE.buc#J); []6*<`q`'(Yy$RD PÌ*5p M@U M@ ~bqfhCyw1w9~^ݣwSL)~gƈ~yA#0R`RI~THr,|=Y:QB& FH`¸ c W,{, >|KI5өY Yh"Kh~ I+@FmmhmɄ4>A , KD8} }An)Oyy{l<>ָAbA `xK L#sut!a'S}a{B+=Ut*QlMd9b|]dS.ĒdO A(-s2ZD־FʃpX(#{IhS@zAj*>dTA2d` Z^@6<v88`}Zߠh&Ё_6 lm~=Gͱ T-TߠodX؅+@ukfGE 0`6Hܼ:A^é;"<NQȩr @$A:S#]p iń|O4%b3`?(FY"K[2 ((w …%Q%1őha?;E`#EDDMϐP0ad Tݍ4 ̶(X%ѶTylɓ ܠ|$)8 ?0C*|b|,̫O1Oh>硊rp~5=agEb|*b,ޏ F10kd }P1S%@Gj\]pL͞H1Ƀ4~7JhT{1.ڄ  HBA`N!Gd@H ˔'f[n_ѶRy ϳ;7}%*$I\]V.m2LE侥_;S"6 H,2@,oD:[`*ɶZykm9>nG^l ) D0A քb 7T Ws u袄E~g`?a2 "/ma>M >h^qv٘s%U@oiȃ24\3q$hf@Ai  58@( @R,X4 P V̦ݠlmضy؇CkQod$9an7&e(&QnTz"_J~JO8hз[ # |/, U6gcDž)V7D<8;j` O CFف$ڣQ ,aDS3P O$`I " ÷*mʓmvMqA0 P1pN(3yF YX-[srĉF'=f \?Dt}OR 2C5SgHdMA쫊(!f3~HM#!lق\DG|`=ËfEQzAc—G2rhMf۝%5_ $@u!8![ p@24vEn퉶c0.s0 J*d e&;W_0ᐺO:y"̀Фu+` uc%w\=V'Y7i"lKB}φ䅘;ŔR ʅMSYQe\e-XktAIAcCfA, ;lGsH)Y6p V1p JC6 IJbK},m_ *O! GۨF! halzB  %bF MKc2":E~&G BF6!c6&N}/ܑ!ύ"/\$ı-DhѲG{6p*R+ >@(bXcm>83nHo1#, 75 :NfdV0]H9z{t^f.8 s u8@Bxn pblƢ@6 yJR;>o^}hZrpOw( 6Aߗ~YS[3n(e;rYn qU:l3Qxn!>[#ʌC$)[@Ek, KS2 6zH@ $ ` lX¿>\@A^5jc&A=܃Nc97ΜOGB&æPҞ\12g/"?#r&iW r mufow'-FHᙃ:N1Mô >dno򃏀8'GӜ`n,QϡR,EdIY^7㳆okU؜́'&"p"fO , _T5nUGU;*]~U AW%*MGB':A> aC%ሌL:3mWΓZD"|, Z,qQkrR rAo/RS"}bn)Q;\n:[KL9J'X)@$yf!D3B)X Q#a, b $0h9"¿l,[*mme^*(/BlU ƂѠkDͅ:pKwЯ27< ՇJ!A% a3ᛁQWvY{HC}/621I1D%@2'>2[L?"P ĹZGFxJ\ g$\HȑŸ)i@ry)3,6iu2 Eh1Cw| D<ݡp"5 ARhr BQJl ' ~ "jDijmކfAf}r`P jEVՊ(P %0FύJ>ΪF h<^ؚDA8O9X3Cb|vCAxC}S~fm?Akax7 >8tf2% z|G^j)Jc8彠@iDRNrᣑ["Di,#&2<@8Qsv|| jDPC@.2Ed@ @H'R^;" !^{QBVD$!"趋\8;% T1 YvhO:3Ar/mN5֔0/Pܘ*>%ҧQJr.D V b|pcd>qL$%>RaE0@.2Z! j K$ODծj1jDZjqjI^cv{β!i(hBP+(Tݕjw]vU5JI=hCwISN YtC@?bjÕE5Z}bPHǤRe QBH\A$N ͕MrA8>I5^\h)>Э&Jق4+p_8] N| DSDD~,I(l5H X ! "dALpr|tx ?yyxliׇQl“oJ7( PUzJ`4 SDIm1{ 9D8q%#`Ÿm$9[SjAtD 7phߙ>Iq")^|@Q{_ĉP)5H >@ĉ4'L+&ߌfL!n0}8)^q9? >@ Ed JpS2@U,L I HF .&8U?]=C9S>K:[X'OijnSecUF($)8s ʽ~V{+r9D bF t3ߏ%WG8`3P̮Ť֥R"0#rpM+^I1f4 MJ2ƕ8Q Iq#> (3@Hҹyh' >TԪ+aY._1oR('q26||Zjc"ATN5BB@H@b<` Q+S]^pEj yU`qO #'DR_W-@FzFANA|!wCy BxAC;8,-O%/B7C]&Z۾"[,D3 pJ$A| zWg?*xF( Z9#7&¯@(D)k̂(R` T.X|&|@Bњ@#S0lD*r`k`5ᜐOෘ"bR2||zW cUh`!pσxSU2cXm:ƞ}d RS頡/);z6،Cow bn\5~AvooH17NКH%H>0eA I>7J?HqN/>0 L8ZHقQۥ"KAL  1S0<$}T`Q7 Ȁ< [E8 Ts,P\"r r᧨|zc`30)`\1Cg0BAjRgJt)*EZGc:me6U_RD "D0A  >ge}lByo3z)n'S ōR`v5:4"K(48E& l*a2@H" @܁f5@R ꗨ$@v'@ uUgzc_\u;;X708"c|81BR8-(%J%PiF0hhsV9D8V~{bQhb㒳 !uUn?!se憋ߪ䄶^ʘ_H.PJ BODDHZ! D@?@)k1Cc~:'j}8B+ec ,m 4 \'d BAT D` OX@̆AJmsW b?bS7X/Uy5?y%F^7Xn A@>#  = )P}*.δ{@a|5ivP-r0PBw?,f tAq,xg3ϒSȎK%OU)ͰakaW*RNG`kr U"@Q\|`මp_ )~i;_@[OzSK($h;ɪEL A,pN%hQG@f Lz|U1@ /R7 x%귿~#ԯ^~ WJz9Ͽ720%Qv%N=~H!]8A`H |7-zݬoDMxxA[ ^mB,^GD\ +Gpr zTT14/X yA7b~`@1n2f Rhk*Eg@6! {$ eC&ԍA_,/WxY4 xkՏHT]DZ~':y^m,n`ia`88X{LHGzFhArPk?J!-چض;Ėnx,:НZ=˦61ힽ3O:#7:Z~%;'V$ѠO,)G0t|T?F/7?i "m6s6HjiNDg@ʟlpIy-'p?gWJ]/85ǯU?#~S {oTe3T4> n!b~ɁԂdꁂ I='%&eAJD  JuD 9D84W~Vubq75 mwxbEБiOQFh)|~;b2G R~THBhQ&e BCFU??xD7[eֲ;DyU"}  @)a#[ڀ-h|YaB666w >` OT30nb@S |My[ߪb?R_kVN< ܐ !+NUR)"`DzEPK'K?FKM&O9D8bX~2iRAjhh}'/8W>xg6Oec(J1 9kP!4SIz N.>DC?@[8zUOQ3w^g6ʘ#_ݙ 5GCx&bDI lL(XZ|P OڠWUUY"1YhiPǹ@ ~mh4 #{L`}j D8w >._V>!ݸ W&;N8A(r/vhtd|>[ wk_"D uE-4>Rc#9{^;o:MQtJ'L DZ ѓI6 LiՈrӄKP͈RD uO߯>x̓n/< 4pXP ?b{š^ADY:5CÜϏܿ(!H$Ocg 8hbDԓ2ű#Xʞ{ m;&*?!y!$9Ikk zfE%'P8-jmeoo+[_ݼQ*dmn9pAlDJpP@z+F́_ğ&Yg@b%Kj0fy$M(Ȧ 05bCZm 9C|? D`@0P@p @p>>!X}_>>Q<8.hvX!d%1$A 쉣I3 !J%%isoJOuC8um-nDcoY }hu,<7:9tAҕuݓ)tL YC (-  X N0,Y gm6w >@3mفkDf,y@j=*F@N F>1|Ոa("m X26`(6X]ABm`aF}ZX&I‏E』>cۇ>>I>oϱQ(ٌLv@f,Q.k T2 F3YA)Dv>d |SHAMR(j1RmM+w/ @|X}>8wORiO~Fg?~Np,x3@`B,h80 @"G4 ),@ *X6"O!Qo%"k&Ο[*,¤Oi>Tp} K@Z0"mUۏ+X_oq"gJ5*~tSѹy(@6_̇X ßiPH-(_|->lfL2 7\qoLՑYc)ՌQG>e)`h(kU"ZYS@$6ϒ6 #@(N, pO8@8=TORϫ/VXI^eO 4 8 MX'eOHPI (XJ1$nB@5)@m>r 9D8,I#>]*2f4P#sMhS[w-0K#c7p`OQ.]a+ R&Zd4"QtKTy%8GWW?0\@( Dv@AYR\++cS+#+C3sj{<~|@7cd4bu> rB _aTTձdW_Y5進G)>Pph%\YŗK!ckY,7C z@vGZ0z C$Q '`˟4_6`G[&(i\bƔFF8VJ塙Y9=GWwͭ{lsoYw;J(:@шEgԈ^,h Ǐw+Dg*x)yH BgZ Z9P/DWD r >-"| %zOKSJcZ8 >0Iiވ9OD> ֙1EnzF+}c)ccSK#KC3f]uLeWX|Rm)ugk trr$ >D⢈ >+ >@vϱ|;ҞEHpmIhbq O@'\q8/VgUozUzԟq, /;s1XC8@=D'@%h(J JK5O>J!g5 `\zlavXdmA1/i~S#>~+v1ư1 AO:^I 0B 3^ ,^ Y!/ϟ0?ERGqN|̓\ ۽#1Gj=#Ҕѩ#džfUSsty1V_zbuM6V[wFm͙Be[ eqPHقxfDk`)ڠ6hwC'Z!  z8\:?H5?Q^Ul˟?V#16 p xN BQH@ņx+!M(!؇TPWE%{z&_9Y,g̀Ñ5X]mcag%.I4LU#"Ԉ: 2{֨&m4Ɂ " dg5Pe}r]Ob|OgK X$tK:Sއ")@Нc̑o6aOD@~C0wWKSFF O9o=GvSq\i'7\xJeiugTלY[}vmeK/ Gia| DY\_-yOCbw(RDrqB-m@&f `# ̳ x58z~^3?W _J8yٍ9Jb?z%Zc#}RV%//Sra|πmClbod׵7 :R)k0:*Ψ9sϯ-". \7j| (I8 s8%{O5HYD;X/U@& pK^[U/AFbݬ^;B6OU1p Ha?} tLTph4 >, CD&(2/R">;кGW1)׎CI|I{}%O&β >^mwkGL.F)}Q7vFoTSYx3R\qy@d%` m3 'H~yF/J3.Q#8(J %G[`%0"}2]ۂAמO7a?:!,C!-<&*>..I.\?zyȕ1Sܨ񁼣I.TIIEH]́lN œ> H&#*O+DtF0 #{Dԋ"[ nUgM=v\;wܥͱ1";#v9ZD Rݫc~0\C"Lp΀a^{o&?=c+,0"yH3o ; f?pՈ? ՈsӪڳ:/]vъOZebO޿!BzB%BeV:eH쓱/J A:R 'r $Q-~ Յ)ۈ \N n }~ZZǪ@eu徍-% Bα=cSN26JGGƙvϻL;GհX~*8LlLl!奎t>U*IXhp .Ȁ}$US>q`lTc\!p " NOAwHE %*3֊(E\.r6>;8RAeF1@ bjDF~{cP|Ԉ~;F<ѕ -hK.lWl};|W ҝ"`?0W(,6"><:8qGp)Tǘm-d.5ORH#)"#6Ea_Y5 uCusP/uϫvϯ,,.+(*-m(o66e=@C#fVE`Y`с-ĿSzZ|b@D.pLt %& I.P4H(:F)bd+E 8I| D =7m:Wp>''(%(+k% DglLHYAbRO}ω0DH3t?Egl~B5"4 iFMN͒N&WhՈܰU#R8@p8xբK-|Wn]>c}W3D7i#49o- I|@ >е'FS~: bx 6'"rxo8]h pPT{Tz.)VV7M2:e#SF ӠaZixzuh9( _pH~idL.&OiD=EԈ2 <ڀHEvXg:nq] +pC8 NSEDIށAK5BE3%HƁWd&܊{? AǵsdG[,콲C=۫D'Zv3u9捈O`-U5l~FᄎQN Ʒ@05?<5AF,QP=-̡7/rE4 WdlV1|>'agNuwu_Px/Ԋ j )U޵M-cC |0upDヱ镡5 GX| 0rAl&Dv`o4<{V@ALy`5DnF@"x;uLr80N5vec7gdA$NS̓2F;BhE SMh1%yoChY۳(ۆoϿ FteګvՈP#>eCO3/@= 'DNWA}_+;{fH3˵L~A0B. /TR(I!8FIbrIbz$U %Z* =kU;KHƦ ҽ eTbW[/VuOL/X/X| rM.`; l{$B,Ofd<p%>F}fڗ9Wv5=r@-'I9i$?ݮ  9D8Dm@WQv|K z:8ᦧZ{35uoĺM޻^*8jK,jĭ{=v|.0ǃC5\ew 4$ZHZ5y @I(-`.,/8'6fېn7PFwH"Ƥ|DM ż1̤H>2?f Nrpvb>"Ae_ 2@ԌLH3Flf15b7Ck48XTW#>y|FUW#G',)Qhsç_546Hث!O  ;7;!!$>*G" A2JeT!${nS(K!bWG;GVU~a_\_+n 1JK14J)+a#A`CA !>8_-`109N[>1!SA8QkD:_ % &HQaH> $KȗH?cʃ5F~$ @;)tG"d=AHqDx`Ϋmuǔ"trp$Yb/5ڋYpm{`[dt^3qo\EH<p*4#jD:93Ffވq<ިF3{VH^dghDG5;MvY59 = MeQ BjhdF Ai@~AN>`;}T8"K!H;H]}Ek5H("A(fh$242OƼ0]0hp~l;kv(.vt-ptm }:>9*=ݱ߈4.yptZNT/UΈW?Q:7 m?U u0<(tbQz҇ɶo&Co0 >@2| >FՌ%H-p\X _Q=q WUc;[ Q>H:%FJ"9D>4qiTz@c)QhzZwߣA=Ciq΀Bg9rh/:84_ةI16FujT;6aA&FjgN تK;wx(O\Xp"eABf9Bm@_S`CX @ȕ߂D}I1v6oפ_BGK!\b\ Җ * 6Q&JFL|@0?1Zp E $ ȀÛ ,,(PSE6_b@BtWؿh (3!a "ReOf++Jz^E rKJ@l8AI$xV!8hFlakUҝSjتڏ(~wab89b͌:nnv(O2X&5 d|><lb`ǚCA-_ޮ)J :<(+O5Y a~H!xkٌGu ]CAa/bE[O$}dՈQF-Fmf P]1Xϳ DB-(V eK( `E*@9!b']80"J#&J` (_xNNav`h`Ҟ uhchHM:ncވI5⏆h(jco^?@:Fdª{Q{1$C}iڻC!bk4(嬺 @(("APZ),)ɭ|t@4$R7;B- )opxHU ?{!,%([d,y@rZ}"J& Yw&#% >`OdI2DA 'IZ9%H > ĕȵ7R`d"ڴDHc \  TSUOU<@h8"ҟ |$/ HSqI7'3W-apKE(}b*,8X#  lm03T @<5QOxjؠwNH:Jfc%u`0'RR1ë1;ԒĒ')[%C#>r袁f1>1t#&.*l{mɃGpCI8![i;5qrS5żHQJ1;Tʡ{Qs,>Ft|';f7v2JJH` z1"z#Yhgu./uGGQ!$)mPB!xPݪJf%Q2 .y@kS,yZ;m>tn䒲du> lF/0>@ڀ3'KآD \ᡀ{@&GlA !O zj D6^,J|FzEB}C$l%pV(&._Ĝ!@PJgDB"{E,T7 md&;m1{xvK5H.Uza,=\]뎃1Ӯ}qV#ujy#Z#FU#"6RF-9*rn\ܙOV&"wjz(yT&tZ!^HOAPDI7w@hS |.Џ\ RBWEwf-B ABXt ܮB%]D|@YxP/p 5VHql@O?`4k`-7(G’ORVbE*+H j>i(Xz[0puR Cz ^OnO2H;^w%"p1##%0 $\@Qh5S;P6 8O҂ٴwg!㝱#lXm=Ao;T6voo;81;8fEYHeHDd{qNFjD#5ѿEozҝt7i(cވqKF$w*Vn}ŏc~Aiw!BXj!#>H m!BJtnr5TVI1HwN1B 5"Zb}Ni 4ݲweoڋw8k4(Ya!6"& !:W{$BC ?`(^HPY 2ݧE,_@:;_{JF ZRd )aU@0.% ,#*U1.,P;=S=ȃ]v(!jN8\F F +`dO ?E2 ?b!f ;GXޯORLh`/X:5HN=U 5'깦kG4cx#ވ٤{S#r#7 +NtFJ}=}孽" sf8ģn#DONRF vHciզ%XQ(A:J@%b I1_&QTP4*E*v+|T-'Jxfu >U RKTYXvAR ?F$ R>h1j$D5i>@Ղ8Q6@"IFpA7@|@΃vy8a FR@tg>$S[utj>g 퍸SN15"@J\5"+jDΪT+ kpPl-o-ﭬ,,