├── qt-cao-editor └── app │ ├── images │ ├── icon_xml.png │ ├── icon_window.png │ ├── icon_import_cao.png │ ├── icon_large_plus.png │ ├── icon_save_init.png │ ├── icon_small_plus.png │ ├── icon_init_points.png │ ├── icon_large_minus.png │ ├── icon_small_minus.png │ ├── icon_player_eject.svg │ ├── icon_close.svg │ ├── icon_player_play.svg │ ├── icon_player_stop.svg │ ├── icon_player_rew.svg │ ├── icon_player_fwd.svg │ ├── icon_player_pause.svg │ ├── icon_player_record.svg │ ├── icon_copy.svg │ ├── icon_clean.svg │ ├── icon_file.svg │ └── icon_player_start.svg │ ├── app.pro │ ├── example.xml │ ├── README.md │ ├── app.qrc │ ├── mainwindow.h │ ├── main.cpp │ ├── xmleditor.h │ ├── scenemodifier.h │ └── xmleditor.cpp ├── README.md ├── .gitignore └── blenderAddons ├── vispCAOExport ├── setup.py ├── build.py ├── README.md ├── treeview_lines.py ├── __init__.py ├── treeview_circles.py ├── treeview_faces.py ├── treeview_cylinders.py └── export_cao.py └── vispCAOImport ├── setup.py ├── build.py ├── README.md ├── __init__.py └── import_cao.py /qt-cao-editor/app/images/icon_xml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lagadic/visp_cao_editor/HEAD/qt-cao-editor/app/images/icon_xml.png -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lagadic/visp_cao_editor/HEAD/qt-cao-editor/app/images/icon_window.png -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_import_cao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lagadic/visp_cao_editor/HEAD/qt-cao-editor/app/images/icon_import_cao.png -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_large_plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lagadic/visp_cao_editor/HEAD/qt-cao-editor/app/images/icon_large_plus.png -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_save_init.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lagadic/visp_cao_editor/HEAD/qt-cao-editor/app/images/icon_save_init.png -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_small_plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lagadic/visp_cao_editor/HEAD/qt-cao-editor/app/images/icon_small_plus.png -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_init_points.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lagadic/visp_cao_editor/HEAD/qt-cao-editor/app/images/icon_init_points.png -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_large_minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lagadic/visp_cao_editor/HEAD/qt-cao-editor/app/images/icon_large_minus.png -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_small_minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lagadic/visp_cao_editor/HEAD/qt-cao-editor/app/images/icon_small_minus.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # visp_cao_editor 2 | Development of a CAD model editor for ViSP model-based tracker 3 | 4 | To know more about this project, visit [wiki](https://github.com/lagadic/visp_cao_editor/wiki) page. 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # blender export plugin 2 | *~ 3 | .DS_Store 4 | visp_cao_export.zip 5 | 6 | 7 | # Build file and directory 8 | qt-cao-editor/app/app.pro.user 9 | qt-cao-editor/build-app-Desktop_Qt_5_9_1_GCC_64bit-Debug 10 | 11 | # Test File and directory 12 | qt-cao-editor/app/temp.cpp 13 | qt-cao-editor/app/lib 14 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOExport/setup.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import sys 3 | import os 4 | 5 | print("BLENDER VERSION : " + bpy.app.version_string) 6 | ADDON_PATH = (bpy.utils.user_resource('SCRIPTS', "addons")) 7 | 8 | os.system("cp -r ../vispCAOExport " + ADDON_PATH) 9 | print("Moved addon to " + ADDON_PATH) 10 | # bpy.utils.script_paths() 11 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOImport/setup.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import sys 3 | import os 4 | 5 | print("BLENDER VERSION : " + bpy.app.version_string) 6 | ADDON_PATH = (bpy.utils.user_resource('SCRIPTS', "addons")) 7 | 8 | os.system("cp -r ../vispCAOImport " + ADDON_PATH) 9 | print("Moved addon to " + ADDON_PATH) 10 | # bpy.utils.script_paths() 11 | -------------------------------------------------------------------------------- /qt-cao-editor/app/app.pro: -------------------------------------------------------------------------------- 1 | QT += widgets qml quick quickwidgets 3dinput core gui 3dcore 3drender 3dquick 3dextras 3dquickextras 2 | 3 | SOURCES += \ 4 | main.cpp \ 5 | mainwindow.cpp \ 6 | scenemodifier.cpp \ 7 | xmleditor.cpp 8 | 9 | HEADERS += \ 10 | mainwindow.h \ 11 | scenemodifier.h \ 12 | xmleditor.h 13 | 14 | RESOURCES = app.qrc 15 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOImport/build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from os.path import abspath, dirname, join as pjoin 4 | import zipfile 5 | 6 | SRC_DIR = dirname(abspath(__file__)) 7 | 8 | with zipfile.ZipFile('visp_cao_import.zip', 'w', zipfile.ZIP_DEFLATED) as arch: 9 | for filename in [ 10 | '__init__.py', 11 | 'import_cao.py']: 12 | arch.write(pjoin(SRC_DIR, filename), 'visp_cao_import/'+filename) 13 | 14 | print('created file: visp_cao_import.zip') 15 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOExport/build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from os.path import abspath, dirname, join as pjoin 4 | import zipfile 5 | 6 | SRC_DIR = dirname(abspath(__file__)) 7 | 8 | with zipfile.ZipFile('visp_cao_export.zip', 'w', zipfile.ZIP_DEFLATED) as arch: 9 | for filename in [ 10 | '__init__.py', 11 | 'export_cao.py', 12 | 'property_panel.py', 13 | 'treeview_circles.py', 14 | 'treeview_faces.py', 15 | 'treeview_cylinders.py', 16 | 'treeview_lines.py']: 17 | arch.write(pjoin(SRC_DIR, filename), 'visp_cao_export/'+filename) 18 | 19 | print('created file: visp_cao_export.zip') 20 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOImport/README.md: -------------------------------------------------------------------------------- 1 | # Blender Import Addon for ViSP CAD file (.cao) 2 | 3 | This Addon was tested with: 4 | - Blender 2.78 on Ubuntu 16.04 (manual installation) 5 | - Blender 2.76 on Ubuntu 16.04 and 14.04 (using apt-get install blender) 6 | - Blender 2.78 on OSX. 7 | 8 | ## Installation: 9 | 10 | 1. Run `python build.py` in project directory. `visp_cao_import.zip` file will be created. 11 | 2. Launch Blender and open `File > User Preferences`. 12 | - (**Ctrl+Atl+U**) under Linux 13 | - (**Cmd+,**) under OSX 14 | 3. Click on `Install from File...` and navigate to the above project directory and select the zip file. 15 | 4. Search for "*visp*" in Add-ons section and enable the plugin called "*Import: ViSP CAO* ". 16 | 5. Click on `Save User Settings` and close `Blender User Preferences` pannel. 17 | 18 | 19 | ## Usage 20 | 21 | * Go to `File > Import > ViSP .cao` to import a .cao format file. 22 | 23 | 24 | ## Uninstall: 25 | 26 | 1. Open `File > User Preferences` and search for "*visp*"" in Add-ons search section. 27 | 2. Click on the triangle next to "*Import: ViSP CAO*" to expand the section and then click on `Remove`. -------------------------------------------------------------------------------- /qt-cao-editor/app/example.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 5 7 | 180 8 | 9 | 10 | 8 11 | 12 | 13 | 10000 14 | 0.5 15 | 0.5 16 | 17 | 18 | 4 19 | 20 | 21 | 22 | 5 23 | 300 24 | 5 25 | 0.015 26 | 8 27 | 0.01 28 | 3 29 | 3 30 | 31 | 32 | 325.66776 33 | 243.69727 34 | 839.21470 35 | 839.44555 36 | 37 | 38 | 70 39 | 80 40 | 0.1 41 | 100 42 | 1 43 | 44 | 45 | -------------------------------------------------------------------------------- /qt-cao-editor/app/README.md: -------------------------------------------------------------------------------- 1 | # Qt CAO Editor 2 | 3 | Install Qt 4 | ------------------------------------------------------------------------------- 5 | 6 | Before you can compile this cao-editor, ensure Qt (>= 5.5) dev libraries have been installed: 7 | 8 | * On Ubuntu: `sudo apt install qt5-default qttools5-dev-tools zlib1g-dev qtdeclarative5-dev` 9 | * On macOS with [Homebrew](http://brew.sh/): 10 | + `brew install qt5` 11 | + `brew link qt5 --force` 12 | * On Arch Linux: `sudo pacman -S qt` 13 | * On Fedora: `sudo dnf builddep tiled` 14 | 15 | Or, you can [download Qt from the official webpage](https://www.qt.io/download-qt-installer). 16 | You will still need to install a development environment alongside and some libraries depending on your system, for example: 17 | 18 | * On Ubuntu: `sudo apt install build-essential zlib1g-dev libgl1-mesa-dev` 19 | 20 | It is also recommended that you install [Qt Creator](https://doc.qt.io/qtcreator/) if you are interested in exploring the source code. 21 | 22 | Build and Run 23 | ------------------------------------------------------------------------------- 24 | 25 | There are two ways to build and run the Qt application. 26 | 27 | **1. Via CLI**: 28 | 29 | $ cd visp_cao_editor/qt-cao-editor/app 30 | $ mkdir build 31 | $ cd build 32 | $ qmake ../app.pro 33 | $ make 34 | 35 | You can then launch the GUI by running the executable named `app`. 36 | 37 | **2. Via Qt Creator**: 38 | 39 | Qt Creator is a cross-platform IDE which is part of the SDK for the Qt GUI application development framework. 40 | 41 | - Launch Qt Creator. 42 | - `Ctrl + O` or `File -> Open File or Project`. 43 | - Select `app.pro` under `visp_cao_editor/qt-cao-editor/app`. 44 | - `Ctrl + B` to build and `Ctrl + R` to Run. 45 | 46 | -------------------------------------------------------------------------------- /qt-cao-editor/app/app.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/icon_exit.svg 4 | images/icon_copy.svg 5 | images/icon_delete.svg 6 | images/icon_save.svg 7 | images/icon_about.svg 8 | images/icon_revert.svg 9 | images/icon_open_file.svg 10 | images/icon_image_inspect.svg 11 | images/icon_export_ply.svg 12 | images/icon_zoom_in.svg 13 | images/icon_zoom_out.svg 14 | images/icon_zoom_reset.svg 15 | images/icon_zoom_page.svg 16 | images/icon_exec.svg 17 | images/icon_new_dir.svg 18 | images/icon_close.svg 19 | images/icon_broken.svg 20 | images/icon_toolbox.svg 21 | images/icon_clean.svg 22 | images/icon_export.svg 23 | images/icon_small_minus.png 24 | images/icon_small_plus.png 25 | images/icon_large_minus.png 26 | images/icon_large_plus.png 27 | images/icon_qcamera.svg 28 | images/icon_file.svg 29 | images/icon_folder.svg 30 | images/icon_player_eject.svg 31 | images/icon_player_end.svg 32 | images/icon_player_fwd.svg 33 | images/icon_player_pause.svg 34 | images/icon_player_play.svg 35 | images/icon_player_record.svg 36 | images/icon_player_rew.svg 37 | images/icon_player_start.svg 38 | images/icon_player_stop.svg 39 | images/icon_eye.svg 40 | images/icon_video.svg 41 | images/icon_refresh.svg 42 | images/icon_new_file.svg 43 | images/icon_window.png 44 | images/icon_xml.png 45 | images/icon_import_cao.png 46 | images/icon_init_points.png 47 | images/icon_save_init.png 48 | 49 | 50 | -------------------------------------------------------------------------------- /qt-cao-editor/app/mainwindow.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Vikas Thamizharasan 4 | ****************************************************************************/ 5 | 6 | #ifndef MAINWINDOW_H 7 | #define MAINWINDOW_H 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "scenemodifier.h" 33 | #include "xmleditor.h" 34 | 35 | QT_BEGIN_NAMESPACE 36 | class QAction; 37 | class QMenu; 38 | class QPlainTextEdit; 39 | class QSessionManager; 40 | QT_END_NAMESPACE 41 | 42 | //! [0] 43 | class MainWindow : public QMainWindow 44 | { 45 | Q_OBJECT 46 | 47 | public: 48 | MainWindow(); 49 | 50 | void loadCaoFile(const QString &fileName); 51 | SceneModifier *modifier; 52 | Qt3DRender::QCamera *cameraEntity; 53 | 54 | protected: 55 | void closeEvent(QCloseEvent *event) override; 56 | 57 | private slots: 58 | void newFile(); 59 | void open(); 60 | bool save(); 61 | bool saveAs(); 62 | bool removeConfirm(); 63 | void about(); 64 | 65 | float getCameraProjection(QString &line, QString op_tag, QString cl_tag); 66 | float qcameraFieldVal(const int index); 67 | void formAddField(const QString tag, const QString text); 68 | void parseXML(); 69 | void qcameraDialog(); 70 | void updateCameraProjection(); 71 | bool verifyXmlTag(const QString tag, QString &line); 72 | 73 | #ifndef QT_NO_SESSIONMANAGER 74 | void commitData(QSessionManager &); 75 | #endif 76 | 77 | private: 78 | void createActions(); 79 | void createStatusBar(); 80 | void readSettings(); 81 | void writeSettings(); 82 | void blenderFrameStateChanged(int state); 83 | void toggleVertices(int state); 84 | void toggleModels(int state); 85 | void resetInitPoints(); 86 | bool saveInitPoints(); 87 | bool maybeSave(); 88 | bool saveFile(const QString &fileName); 89 | void setCurrentFile(const QString &fileName); 90 | 91 | QString strippedName(const QString &fullFileName); 92 | 93 | QString curFile; 94 | QString curXML; 95 | 96 | XmlEditor *xmlWin; 97 | 98 | QDialog *dialog; 99 | QFormLayout *form; 100 | QList qcamera_fields; 101 | bool useBlenderFrame; 102 | }; 103 | //! [0] 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /qt-cao-editor/app/main.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Vikas Thamizharasan 4 | ****************************************************************************/ 5 | 6 | #include 7 | #include 8 | 9 | #include "mainwindow.h" 10 | #include "scenemodifier.h" 11 | 12 | 13 | int main(int argc, char **argv) 14 | { 15 | QApplication app(argc, argv); 16 | QCommandLineParser parser; 17 | parser.setApplicationDescription(QCoreApplication::applicationName()); 18 | parser.addHelpOption(); 19 | parser.addVersionOption(); 20 | parser.addPositionalArgument("file", "The file to open."); 21 | parser.process(app); 22 | 23 | MainWindow mainWin; 24 | 25 | Qt3DExtras::Qt3DWindow *view = new Qt3DExtras::Qt3DWindow(); 26 | view->defaultFrameGraph()->setClearColor(QColor(200,207,200,255)); 27 | QWidget *sceneContainer = QWidget::createWindowContainer(view); 28 | QSize screenSize = view->screen()->size(); 29 | sceneContainer->setMinimumSize(QSize(200, 100)); 30 | sceneContainer->setMaximumSize(screenSize); 31 | Qt3DInput::QInputAspect *input = new Qt3DInput::QInputAspect; 32 | view->registerAspect(input); 33 | 34 | // Root entity 35 | Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity(); 36 | 37 | // Camera 38 | mainWin.cameraEntity = view->camera(); 39 | 40 | // cameraEntity->setProjectionType(Qt3DRender::QCameraLens::PerspectiveProjection); 41 | mainWin.cameraEntity->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f); 42 | mainWin.cameraEntity->setPosition(QVector3D(20.0f, 10.0f, 0.0f)); 43 | mainWin.cameraEntity->setUpVector(QVector3D(0, 1, 0)); 44 | mainWin.cameraEntity->setViewCenter(QVector3D(0, 0, 0)); 45 | 46 | Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity(rootEntity); 47 | Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity); 48 | light->setColor("white"); 49 | light->setIntensity(1); 50 | lightEntity->addComponent(light); 51 | Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform(lightEntity); 52 | lightTransform->setTranslation(mainWin.cameraEntity->position()); 53 | lightEntity->addComponent(lightTransform); 54 | 55 | // For camera controls 56 | Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(rootEntity); 57 | camController->setCamera(mainWin.cameraEntity); 58 | 59 | // Set root object of the scene 60 | view->setRootEntity(rootEntity); 61 | 62 | // Scenemodifier 63 | mainWin.modifier = new SceneModifier(rootEntity, sceneContainer); 64 | 65 | 66 | if (!parser.positionalArguments().isEmpty()) 67 | mainWin.loadCaoFile(parser.positionalArguments().first()); 68 | 69 | mainWin.setCentralWidget(sceneContainer); 70 | mainWin.resize(800, 600); 71 | mainWin.show(); 72 | 73 | return app.exec(); 74 | } 75 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOImport/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | bl_info = { 3 | "name": "ViSP CAO", 4 | "author": "Vikas Thamizharasan", 5 | "blender": (2, 7, 6), 6 | "location": "File > Import", 7 | "description": "Import CAO", 8 | "warning": "", 9 | "wiki_url": "", 10 | "tracker_url": "", 11 | "category": "Import"} 12 | 13 | import bpy 14 | from bpy.props import * 15 | from bpy_extras.io_utils import (ImportHelper, 16 | ExportHelper, 17 | path_reference_mode, 18 | orientation_helper_factory, 19 | axis_conversion, 20 | ) 21 | _modules = [] 22 | 23 | __import__(name=__name__, fromlist=_modules) 24 | _namespace = globals() 25 | _modules_loaded = [_namespace[name] for name in _modules] 26 | del _namespace 27 | 28 | if "bpy" in locals(): 29 | import imp 30 | if "import_cao" in locals(): 31 | imp.reload(import_cao) 32 | from importlib import reload 33 | _modules_loaded[:] = [reload(val) for val in _modules_loaded] 34 | del reload 35 | 36 | IOCAOOrientationHelper = orientation_helper_factory("IOCAOOrientationHelper", axis_forward='-Z', axis_up='Y') 37 | 38 | class ImportCAO(bpy.types.Operator, ImportHelper, IOCAOOrientationHelper): 39 | bl_idname = "import_scene.cao" 40 | bl_label = "Import CAO" 41 | bl_options = {'PRESET', 'UNDO'} 42 | 43 | filename_ext = ".cao" 44 | filter_glob = StringProperty( 45 | default="*.cao", 46 | options={'HIDDEN'}, 47 | ) 48 | 49 | global_clamp_size = FloatProperty( 50 | name="Clamp Size", 51 | description="Clamp bounds under this value (zero to disable)", 52 | min=0.0, max=1000.0, 53 | soft_min=0.0, soft_max=1000.0, 54 | default=0.0, 55 | ) 56 | 57 | def execute(self, context): 58 | from . import import_cao 59 | 60 | keywords = self.as_keywords(ignore=("axis_forward", 61 | "axis_up", 62 | "filter_glob" 63 | )) 64 | 65 | global_matrix = axis_conversion(from_forward=self.axis_forward, 66 | from_up=self.axis_up, 67 | ).to_4x4() 68 | keywords["global_matrix"] = global_matrix 69 | 70 | if bpy.data.is_saved and context.user_preferences.filepaths.use_relative_paths: 71 | import os 72 | keywords["relpath"] = os.path.dirname((bpy.data.path_resolve("filepath", False).as_bytes())) 73 | 74 | return import_cao.load(self, context, **keywords) 75 | 76 | def menu_func_import(self, context): 77 | self.layout.operator(ImportCAO.bl_idname, text="ViSP .cao") 78 | 79 | def register(): 80 | bpy.utils.register_module(__name__) 81 | 82 | bpy.types.INFO_MT_file_import.append(menu_func_import) 83 | 84 | def unregister(): 85 | bpy.utils.unregister_module(__name__) 86 | 87 | bpy.types.INFO_MT_file_import.remove(menu_func_import) 88 | 89 | if __name__ == "__main__": 90 | register() 91 | -------------------------------------------------------------------------------- /qt-cao-editor/app/xmleditor.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the examples of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:BSD$ 9 | ** You may use this file under the terms of the BSD license as follows: 10 | ** 11 | ** "Redistribution and use in source and binary forms, with or without 12 | ** modification, are permitted provided that the following conditions are 13 | ** met: 14 | ** * Redistributions of source code must retain the above copyright 15 | ** notice, this list of conditions and the following disclaimer. 16 | ** * Redistributions in binary form must reproduce the above copyright 17 | ** notice, this list of conditions and the following disclaimer in 18 | ** the documentation and/or other materials provided with the 19 | ** distribution. 20 | ** * Neither the name of The Qt Company Ltd nor the names of its 21 | ** contributors may be used to endorse or promote products derived 22 | ** from this software without specific prior written permission. 23 | ** 24 | ** 25 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 36 | ** 37 | ** $QT_END_LICENSE$ 38 | ** 39 | ****************************************************************************/ 40 | 41 | #ifndef XMLEDITOR_H 42 | #define XMLEDITOR_H 43 | 44 | #include 45 | 46 | QT_BEGIN_NAMESPACE 47 | class QAction; 48 | class QMenu; 49 | class QPlainTextEdit; 50 | class QSessionManager; 51 | QT_END_NAMESPACE 52 | 53 | //! [0] 54 | class XmlEditor : public QMainWindow 55 | { 56 | Q_OBJECT 57 | 58 | public: 59 | XmlEditor(); 60 | 61 | void loadFile(const QString &fileName); 62 | 63 | protected: 64 | void closeEvent(QCloseEvent *event) override; 65 | 66 | private slots: 67 | void newFile(); 68 | void open(); 69 | bool save(); 70 | bool saveAs(); 71 | void about(); 72 | void documentWasModified(); 73 | #ifndef QT_NO_SESSIONMANAGER 74 | void commitData(QSessionManager &); 75 | #endif 76 | 77 | private: 78 | void createActions(); 79 | void createStatusBar(); 80 | void readSettings(); 81 | void writeSettings(); 82 | bool maybeSave(); 83 | bool saveFile(const QString &fileName); 84 | void setCurrentFile(const QString &fileName); 85 | QString strippedName(const QString &fullFileName); 86 | 87 | QPlainTextEdit *textEdit; 88 | QString curFile; 89 | }; 90 | //! [0] 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /qt-cao-editor/app/scenemodifier.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Vikas Thamizharasan. 4 | 5 | ****************************************************************************/ 6 | 7 | #ifndef SCENEMODIFIER_H 8 | #define SCENEMODIFIER_H 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | class SceneModifier : public QObject 46 | { 47 | Q_OBJECT 48 | 49 | public: 50 | explicit SceneModifier(Qt3DCore::QEntity *rootEntity, QWidget *parentWidget); 51 | ~SceneModifier(); 52 | 53 | QList* vertices; 54 | QList* lineRawData; 55 | QList> facelineRawData; 56 | QList> facepointRawData; 57 | QList* cylinder; 58 | QList* circle; 59 | 60 | QList* line_param; 61 | QList* faceline_param; 62 | QList* facepoint_param; 63 | QList* cylinder_param; 64 | QList* circle_param; 65 | 66 | QList* init_points; 67 | QList scene_points; 68 | QList scene_entities; 69 | Qt3DRender::QObjectPicker *createObjectPickerForEntity(Qt3DCore::QEntity *entity); 70 | 71 | public slots: 72 | void mouseControls(Qt3DInput::QKeyEvent *event); 73 | void parse3DFile(QTextStream &input, const bool useBlenderFrame); 74 | void removeSceneElements(); 75 | 76 | private slots: 77 | void handlePickerPress(Qt3DRender::QPickEvent *event); 78 | void handlePointSelect(Qt3DRender::QPickEvent *event); 79 | 80 | void createCylinder(const QVector3D &axis_1, const QVector3D &axis_2, 81 | const unsigned int index, const float radius, const QString &load_param); 82 | void createCircle(const QVector3D &circum_1, const QVector3D &circum_2, const QVector3D ¢er, 83 | const unsigned int index, const float radius, const QString &load_param); 84 | void createLines(const QVector3D &v0, const QVector3D &v1, 85 | const unsigned int index, const bool axis, const QString &lod_param); 86 | void createPoints(const QVector3D &point, const QString index); 87 | void getLineLength(); 88 | 89 | void formAddField(QDialog *dialog, QFormLayout *form, 90 | const QString tag, const QString text); 91 | 92 | void initData(); 93 | QString getLodParameters(const QStringList &data, const QString &type, 94 | const unsigned int idx1, const unsigned int idx2); 95 | 96 | private: 97 | bool handleMousePress(QMouseEvent *event); 98 | 99 | Qt3DCore::QEntity *m_rootEntity; 100 | Qt3DCore::QEntity *m_lineEntity; 101 | Qt3DCore::QEntity *m_cuboidEntity; 102 | Qt3DCore::QEntity *m_cylinderEntity; 103 | Qt3DCore::QEntity *m_circleEntity; 104 | Qt3DExtras::QPhongMaterial *caoMaterial; 105 | QWidget *m_parentWidget; 106 | 107 | Qt::MouseButton m_mouseButton; 108 | 109 | unsigned int vertices_index; 110 | unsigned int lineRawData_index; 111 | unsigned int facelineRawData_index; 112 | unsigned int facepointRawData_index; 113 | unsigned int cylinder_index; 114 | unsigned int circle_index; 115 | 116 | 117 | QList fields; 118 | 119 | }; 120 | 121 | #endif // SCENEMODIFIER_H 122 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOExport/README.md: -------------------------------------------------------------------------------- 1 | # Blender Export Addon for ViSP CAD file (.cao) 2 | 3 | This Addon was tested with: 4 | - Blender 2.78 on Ubuntu 16.04 (manual installation) 5 | - Blender 2.76 on Ubuntu 16.04 and 14.04 (using apt-get install blender) 6 | - Blender 2.78 on OSX. 7 | 8 | ## Installation: 9 | 10 | 1. Run `python build.py` in project directory. `visp_cao_export.zip` file will be created. 11 | 2. Launch Blender and open `File > User Preferences`. 12 | - (**Ctrl+Atl+U**) under Linux 13 | - (**Cmd+,**) under OSX 14 | 3. Click on `Install from File...` and navigate to the above project directory and select the zip file. 15 | 4. Search for "*visp*" in Add-ons section and enable the plugin called "*Export: ViSP CAO* ". 16 | 5. Click on `Save User Settings` and close `Blender User Preferences` pannel. 17 | 6. On the left side of Blender, there should be a new tab named `Misc` located under the `Tools`, `Create`,... tabs. 18 | 19 | ## Usage: 20 | 21 | - The Addon consists of a Property panel and a treeview panel. The Property panel, named ViSP CAD Properties Panel, is where 22 | the user will fill in the primitve details while the treeview panel is where the user will manage (enable, disable, delete) the different primitives (3D Face, 3D Line, 3D Cylinder, 3D Circle). 23 | 24 | ### Property panel 25 | 26 | * To assign a primitive to a model: 27 | * Select the model in the blender scene view; 28 | * Click on `+ New` in the ViSP Property Panel; 29 | * Choose `Primitive Type` from dropdown list. 30 | 31 | * If `Type == "3D Faces" || "3D Lines"`, for already simplified models i.e every vertex and edge is to be included for export, click on `Add Properties`. The added primitive will show up in the respective treeview. 32 | 33 | [3D Faces Demo GIF](https://user-images.githubusercontent.com/11690674/27374715-7f85c152-5675-11e7-94d4-0a4591192a3b.gif) 34 | 35 | [3D Lines Demo GIF](https://user-images.githubusercontent.com/11690674/27374720-81d4e410-5675-11e7-883e-762bfc0f2f36.gif) 36 | 37 | * If `Type == "3D Cylinders"`: 38 | * Switch to `Edit Mode` to fill in three details, two axis of revolution points and the radius. 39 | * To get axis of revolution coordinates from the model: 40 | * Either choose the vertex from the model and click on `Update` or; 41 | * Choose three points on the circumference of one circle that corresponds to one face of the cylinder and click on `Update`. The axis of revolution of this face and the radius will be calculated and filled in the respective fields. 42 | 43 | [3D Cylinder Demo GIF 1](https://user-images.githubusercontent.com/11690674/27380499-0d018996-5688-11e7-96f7-60947528495d.gif) 44 | 45 | * To get radius of a face: 46 | * Choose two diametrically opposite points on the circumference and click on `Update`. 47 | 48 | [3D Cylinder Demo GIF 2](https://user-images.githubusercontent.com/11690674/27380505-0f02a996-5688-11e7-9996-e8101ec771b3.gif) 49 | 50 | * Finally click on `Add Properties`. 51 | 52 | * If `Type == "3D Circles"`: 53 | * Switch to `Edit Mode` to fill in four details, center of circle, radius and two points on the surface. 54 | * To get center: 55 | * Either choose the vertex that represents the center of the circle and hit `Update` or; 56 | * Choose three points on the circumference and hit `Update`. The center and radius will be calculated and the other two points will be filled in from the selected points. 57 | * To get only radius: 58 | * Choose two diametrically opposite points on the circumference and click on `Update`. 59 | 60 | * When choosing `3D Faces` or `3D Lines` for complex models: 61 | * First simplify the model such that only object contours are present and poly count is reduced. Then follow the above steps. 62 | * Or choose the vertices from the complex model needed: 63 | * Switch to `Edit Mode` and select the necessary vertices for a face from the model and hit `Get Vertices`. 64 | This will create a new mesh containing the selected vertices and assign a face to it. If polycount is more than one, then `Limited Dissolve` is applied to simplify further. 65 | * The above step is automated, thus after clicking on `Get vertices`, hit `Add Properties` to assign it to either `3D faces` or `3D Lines`. 66 | 67 | #### Tutorial: 68 | [![screenshot from 2017-06-22 16 06 05](https://user-images.githubusercontent.com/11690674/27435385-bfc89d6c-5764-11e7-86c7-ec281f981603.png)](https://youtu.be/jeihOFwtSoI) 69 | 70 | ### TreeView Management 71 | 72 | ![treeview](https://user-images.githubusercontent.com/11690674/27358411-2ed79f88-561f-11e7-8011-f0406b564477.png) 73 | 74 | 75 | ### Export 76 | 77 | * Before exporting, make sure the necessary primitives are enabled and the remaining disabled (only enabled primitives are exported). 78 | * Go to `File > Export > ViSP .cao` to export to .cao format. 79 | 80 | ## Uninstall: 81 | 82 | 1. Open `File > User Preferences` and search for "*visp*"" in Add-ons search section. 83 | 2. Click on the triangle next to "*Export: ViSP CAO*" to expand the section and then click on `Remove`. 84 | -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_player_eject.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 22 | 24 | 27 | 31 | 35 | 36 | 43 | 52 | 53 | 76 | 78 | 79 | 81 | image/svg+xml 82 | 84 | 85 | 86 | Jakub Steiner 87 | 88 | 89 | http://jimmac.musichall.cz 90 | 92 | Eject 93 | 94 | 95 | media 96 | eject 97 | unmount 98 | 99 | 100 | 101 | 103 | 105 | 107 | 109 | 111 | 113 | 115 | 116 | 117 | 118 | 122 | 131 | 135 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOExport/treeview_lines.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.props import IntProperty, CollectionProperty 3 | from bpy.types import Panel, UIList 4 | 5 | # ######################################### 6 | # TreeView 7 | # ######################################### 8 | 9 | def object_deselection(): 10 | try: 11 | bpy.ops.object.mode_set(mode='OBJECT') 12 | bpy.ops.object.select_all(action='DESELECT') 13 | except: 14 | pass 15 | 16 | def get_activeSceneObject(): 17 | return bpy.context.scene.objects.active.name 18 | 19 | class Uilist_actions_lines(bpy.types.Operator): 20 | bl_idname = "customlines.list_action" 21 | bl_label = "List Action" 22 | 23 | action = bpy.props.EnumProperty( 24 | items=( 25 | ('UP', "Up", ""), 26 | ('DOWN', "Down", ""), 27 | ('REMOVE', "Remove", ""), 28 | ('DISABLE', "DISABLE", ""), 29 | ('ENABLE', "ENABLE", "") 30 | ) 31 | ) 32 | 33 | def invoke(self, context, event): 34 | 35 | scn = context.scene 36 | idx = scn.custom_lines_index 37 | 38 | try: 39 | item = scn.custom_lines[idx] 40 | except IndexError: 41 | pass 42 | 43 | else: 44 | if self.action == 'DOWN' and idx < len(scn.custom_lines) - 1: 45 | item_next = scn.custom_lines[idx+1].name 46 | scn.custom_lines_index += 1 47 | info = 'Item %d selected' % (scn.custom_lines_index + 1) 48 | self.report({'INFO'}, info) 49 | 50 | elif self.action == 'UP' and idx >= 1: 51 | item_prev = scn.custom_lines[idx-1].name 52 | scn.custom_lines_index -= 1 53 | info = 'Item %d selected' % (scn.custom_lines_index + 1) 54 | self.report({'INFO'}, info) 55 | 56 | elif self.action == 'REMOVE': 57 | info = 'Item %s removed from list' % (scn.custom_lines[scn.custom_lines_index].name) 58 | object_deselection() 59 | scn.custom_lines_index -= 1 60 | self.report({'INFO'}, info) 61 | scn.custom_lines.remove(idx) 62 | elif self.action == 'DISABLE': 63 | scn.custom_lines[scn.custom_lines_index].enabled = False 64 | elif self.action == 'ENABLE': 65 | scn.custom_lines[scn.custom_lines_index].enabled = True 66 | return {"FINISHED"} 67 | 68 | # ######################################### 69 | # Draw Panels and Button 70 | # ######################################### 71 | 72 | def primitive_name_update(self, context): 73 | scn = context.scene 74 | idx = scn.custom_lines_index 75 | 76 | if scn.custom_lines[idx].prev_name == "": 77 | scn.custom_lines[idx].prev_name = scn.custom_lines[idx].name 78 | else: 79 | bpy.data.objects[scn.custom_lines[idx].prev_name].name = scn.custom_lines[idx].name 80 | scn.custom_lines[idx].prev_name = scn.custom_lines[idx].name 81 | 82 | class UL_items_lines(UIList): 83 | 84 | def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): 85 | split = layout.split(0.1) 86 | split.label("%d" % (index)) 87 | split.prop(item, "name", text="%s" % (item.enabled), emboss=False, translate=True, icon='BORDER_RECT') 88 | 89 | def invoke(self, context, event): 90 | pass 91 | 92 | class UIListPanelExample_lines(Panel): 93 | """Creates a Panel in the Object properties window""" 94 | bl_idname = 'OBJECT_PT_my_panel_lines' 95 | bl_space_type = "VIEW_3D" 96 | bl_region_type = "TOOLS" 97 | bl_label = "3D Lines" 98 | 99 | def draw(self, context): 100 | layout = self.layout 101 | scn = bpy.context.scene 102 | 103 | rows = 5 104 | row = layout.row() 105 | row.template_list("UL_items_lines", "", scn, "custom_lines", scn, "custom_lines_index", rows=rows) 106 | 107 | col = row.column(align=True) 108 | col.operator("customlines.list_action", icon='TRIA_UP', text="").action = 'UP' 109 | col.operator("customlines.select_item", icon="UV_SYNC_SELECT") 110 | col.operator("customlines.list_action", icon='TRIA_DOWN', text="").action = 'DOWN' 111 | col.separator() 112 | col.operator("customlines.list_action", icon='ZOOMOUT', text="").action = 'REMOVE' 113 | col.operator("customlines.list_action", icon='VISIBLE_IPO_ON', text="").action = 'ENABLE' 114 | col.operator("customlines.list_action", icon='VISIBLE_IPO_OFF', text="").action = 'DISABLE' 115 | 116 | row = layout.row() 117 | col = row.column(align=True) 118 | col.operator("customlines.clear_list", icon="X") 119 | 120 | class Uilist_selectAllItems_lines(bpy.types.Operator): 121 | bl_idname = "customlines.select_item" 122 | bl_label = "" 123 | bl_description = "Edit Primitive" 124 | 125 | def __init__(self): 126 | self._ob_select = None 127 | 128 | def execute(self, context): 129 | scn = context.scene 130 | idx = scn.custom_lines_index 131 | object_deselection() 132 | 133 | try: 134 | item = scn.custom_lines[idx] 135 | except IndexError: 136 | pass 137 | 138 | else: 139 | self._ob_select = bpy.data.objects[scn.custom_lines[scn.custom_lines_index].name] 140 | scn.objects.active = self._ob_select 141 | self._ob_select.select = True 142 | scn.ignit_panel.vp_model_types = self._ob_select["vp_model_types"] 143 | scn.ignit_panel.vp_line_face = self._ob_select["vp_line_face"] 144 | return{'FINISHED'} 145 | 146 | class Uilist_clearAllItems_lines(bpy.types.Operator): 147 | bl_idname = "customlines.clear_list" 148 | bl_label = "Clear List" 149 | bl_description = "Clear all items in the list" 150 | 151 | def execute(self, context): 152 | scn = context.scene 153 | lst = scn.custom_lines 154 | object_deselection() 155 | 156 | if len(lst) > 0: 157 | for i in range(len(lst)-1,-1,-1): 158 | scn.custom_lines.remove(i) 159 | 160 | self.report({'INFO'}, "All items removed") 161 | 162 | else: 163 | self.report({'INFO'}, "Nothing to remove") 164 | 165 | return{'FINISHED'} 166 | 167 | class CustomProp_lines(bpy.types.PropertyGroup): 168 | name = bpy.props.StringProperty(update=primitive_name_update) 169 | prev_name = bpy.props.StringProperty() 170 | enabled = bpy.props.BoolProperty() 171 | 172 | # ######################################### 173 | # Register 174 | # ######################################### 175 | 176 | classes = ( 177 | CustomProp_lines, 178 | Uilist_actions_lines, 179 | Uilist_clearAllItems_lines, 180 | Uilist_selectAllItems_lines, 181 | UIListPanelExample_lines, 182 | UL_items_lines 183 | ) 184 | 185 | if __name__ == "__main__": 186 | from bpy.utils import register_class 187 | for cls in classes: 188 | register_class(cls) 189 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOExport/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | bl_info = { 3 | "name": "ViSP CAO", 4 | "author": "Vikas Thamizharasan", 5 | "blender": (2, 7, 6), 6 | "location": "File > Export", 7 | "description": "Export CAO", 8 | "warning": "", 9 | "wiki_url": "", 10 | "tracker_url": "", 11 | "category": "Export"} 12 | 13 | import bpy 14 | from bpy.props import * 15 | from bpy_extras.io_utils import (ImportHelper, 16 | ExportHelper, 17 | path_reference_mode, 18 | axis_conversion, 19 | ) 20 | _modules = [ 21 | "property_panel", 22 | "treeview_faces", 23 | "treeview_lines", 24 | "treeview_cylinders", 25 | "treeview_circles" 26 | ] 27 | 28 | __import__(name=__name__, fromlist=_modules) 29 | _namespace = globals() 30 | _modules_loaded = [_namespace[name] for name in _modules] 31 | del _namespace 32 | 33 | if "bpy" in locals(): 34 | import imp 35 | if "export_cao" in locals(): 36 | imp.reload(export_cao) 37 | from importlib import reload 38 | _modules_loaded[:] = [reload(val) for val in _modules_loaded] 39 | del reload 40 | 41 | # ######################################### 42 | # ExportCAO 43 | # ######################################### 44 | 45 | class ExportCAO(bpy.types.Operator, ExportHelper): 46 | 47 | bl_idname = "export_scene.cao" 48 | bl_label = 'Export .cao' 49 | bl_options = {'PRESET'} 50 | 51 | filename_ext = ".cao" 52 | filter_glob = StringProperty( 53 | default="*.cao", 54 | options={'HIDDEN'}, 55 | ) 56 | 57 | # context group 58 | use_selection = BoolProperty( 59 | name="Selection Only", 60 | description="Export selected objects only", 61 | default=False, 62 | ) 63 | 64 | # object group 65 | use_mesh_modifiers = BoolProperty( 66 | name="Apply Modifiers", 67 | description="Apply modifiers (preview resolution)", 68 | default=True, 69 | ) 70 | 71 | # extra data group 72 | use_edges = BoolProperty( 73 | name="Include Edges", 74 | description="", 75 | default=True, 76 | ) 77 | 78 | use_normals = BoolProperty( 79 | name="Include Normals", 80 | description="", 81 | default=False, 82 | ) 83 | 84 | use_triangles = BoolProperty( 85 | name="Triangulate Faces", 86 | description="Convert all faces to triangles", 87 | default=False, 88 | ) 89 | 90 | axis_forward = EnumProperty( 91 | name="Forward", 92 | items=(('X', "X Forward", ""), 93 | ('Y', "Y Forward", ""), 94 | ('Z', "Z Forward", ""), 95 | ('-X', "-X Forward", ""), 96 | ('-Y', "-Y Forward", ""), 97 | ('-Z', "-Z Forward", ""), 98 | ), 99 | default='-Z', 100 | ) 101 | axis_up = EnumProperty( 102 | name="Up", 103 | items=(('X', "X Up", ""), 104 | ('Y', "Y Up", ""), 105 | ('Z', "Z Up", ""), 106 | ('-X', "-X Up", ""), 107 | ('-Y', "-Y Up", ""), 108 | ('-Z', "-Z Up", ""), 109 | ), 110 | default='Y', 111 | ) 112 | global_scale = FloatProperty( 113 | name="Scale", 114 | min=0.01, max=1000.0, 115 | default=1.0, 116 | ) 117 | 118 | 119 | check_extension = True 120 | 121 | def execute(self, context): 122 | from . import export_cao 123 | scn = context.scene 124 | from mathutils import Matrix 125 | keywords = self.as_keywords(ignore=("axis_forward", 126 | "axis_up", 127 | "global_scale", 128 | "check_existing", 129 | "filter_glob", 130 | )) 131 | 132 | global_matrix = (Matrix.Scale(self.global_scale, 4) * 133 | axis_conversion(to_forward=self.axis_forward, 134 | to_up=self.axis_up, 135 | ).to_4x4()) 136 | keywords["global_matrix"] = global_matrix 137 | 138 | try: 139 | bpy.ops.object.mode_set(mode='OBJECT') 140 | bpy.ops.object.select_all(action='DESELECT') 141 | except: 142 | pass 143 | 144 | print("Exporting Objects:")#TODO: hierarchical model export 145 | for mlist in scn.custom_faces, scn.custom_lines, scn.custom_cylinder, scn.custom_circle: 146 | for item in mlist: 147 | if item.enabled: 148 | bpy.data.objects[item.name].select = True 149 | print(item.name) 150 | return export_cao.save(self, context, **keywords) 151 | 152 | # ######################################### 153 | # Register 154 | # ######################################### 155 | 156 | def menu_func_export(self, context): 157 | self.layout.operator(ExportCAO.bl_idname, text="ViSP .cao") 158 | 159 | def register(): 160 | from bpy.utils import register_class 161 | for mod in _modules_loaded: 162 | for cls in mod.classes: 163 | register_class(cls) 164 | 165 | bpy.types.Scene.ignit_panel = bpy.props.PointerProperty(type=_modules_loaded[0].classes[0]) 166 | bpy.types.Scene.custom_vertices = CollectionProperty(type=_modules_loaded[0].classes[1]) 167 | bpy.types.Scene.custom_vertices_index = IntProperty() 168 | 169 | bpy.types.Scene.custom_faces = CollectionProperty(type=_modules_loaded[1].classes[0]) 170 | bpy.types.Scene.custom_faces_index = IntProperty() 171 | 172 | bpy.types.Scene.custom_lines = CollectionProperty(type=_modules_loaded[2].classes[0]) 173 | bpy.types.Scene.custom_lines_index = IntProperty() 174 | 175 | bpy.types.Scene.custom_cylinder = CollectionProperty(type=_modules_loaded[3].classes[0]) 176 | bpy.types.Scene.custom_cylinder_index = IntProperty() 177 | 178 | bpy.types.Scene.custom_circle = CollectionProperty(type=_modules_loaded[4].classes[0]) 179 | bpy.types.Scene.custom_circle_index = IntProperty() 180 | 181 | bpy.utils.register_module(__name__) 182 | bpy.types.INFO_MT_file_export.append(menu_func_export) 183 | 184 | def unregister(): 185 | from bpy.utils import unregister_class 186 | for mod in reversed(_modules_loaded): 187 | for cls in reversed(mod.classes): 188 | if cls.is_registered: 189 | unregister_class(cls) 190 | del bpy.types.Scene.custom_circle 191 | del bpy.types.Scene.custom_circle_index 192 | del bpy.types.Scene.custom_cylinder 193 | del bpy.types.Scene.custom_cylinder_index 194 | 195 | bpy.utils.unregister_module(__name__) 196 | bpy.types.INFO_MT_file_export.remove(menu_func_export) 197 | del bpy.types.Scene.ignit_panel 198 | 199 | # if __name__ == "__main__": 200 | # register() 201 | -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 23 | 25 | 32 | 35 | 39 | 43 | 44 | 47 | 51 | 55 | 56 | 58 | 62 | 66 | 67 | 69 | 73 | 77 | 78 | 89 | 98 | 109 | 120 | 131 | 142 | 143 | 162 | 164 | 165 | 167 | image/svg+xml 168 | 170 | 171 | 172 | 173 | 177 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOExport/treeview_circles.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.props import IntProperty, CollectionProperty 3 | from bpy.types import Panel, UIList 4 | 5 | # ######################################### 6 | # TreeView 7 | # ######################################### 8 | 9 | def object_deselection(): 10 | try: 11 | bpy.ops.object.mode_set(mode='OBJECT') 12 | bpy.ops.object.select_all(action='DESELECT') 13 | except: 14 | pass 15 | 16 | def get_activeSceneObject(): 17 | return bpy.context.scene.objects.active.name 18 | 19 | class Uilist_actions_circle(bpy.types.Operator): 20 | bl_idname = "customcircle.list_action" 21 | bl_label = "List Action" 22 | 23 | action = bpy.props.EnumProperty( 24 | items=( 25 | ('UP', "Up", ""), 26 | ('DOWN', "Down", ""), 27 | ('REMOVE', "Remove", ""), 28 | ('DISABLE', "DISABLE", ""), 29 | ('ENABLE', "ENABLE", "") 30 | ) 31 | ) 32 | 33 | def invoke(self, context, event): 34 | 35 | scn = context.scene 36 | idx = scn.custom_circle_index 37 | 38 | try: 39 | item = scn.custom_circle[idx] 40 | except IndexError: 41 | pass 42 | 43 | else: 44 | if self.action == 'DOWN' and idx < len(scn.custom_circle) - 1: 45 | item_next = scn.custom_circle[idx+1].name 46 | scn.custom_circle_index += 1 47 | info = 'Item %d selected' % (scn.custom_circle_index + 1) 48 | self.report({'INFO'}, info) 49 | 50 | elif self.action == 'UP' and idx >= 1: 51 | item_prev = scn.custom_circle[idx-1].name 52 | scn.custom_circle_index -= 1 53 | info = 'Item %d selected' % (scn.custom_circle_index + 1) 54 | self.report({'INFO'}, info) 55 | 56 | elif self.action == 'REMOVE': 57 | info = 'Item %s removed from list' % (scn.custom_circle[scn.custom_circle_index].name) 58 | object_deselection() 59 | scn.custom_circle_index -= 1 60 | self.report({'INFO'}, info) 61 | scn.custom_circle.remove(idx) 62 | 63 | elif self.action == 'DISABLE': 64 | scn.custom_circle[scn.custom_circle_index].enabled = False 65 | elif self.action == 'ENABLE': 66 | scn.custom_circle[scn.custom_circle_index].enabled = True 67 | return {"FINISHED"} 68 | 69 | # ######################################### 70 | # Draw Panels and Button 71 | # ######################################### 72 | #TODO: Add RMB tool 73 | 74 | def primitive_name_update(self, context): 75 | scn = context.scene 76 | idx = scn.custom_circle_index 77 | 78 | if scn.custom_circle[idx].prev_name == "": 79 | scn.custom_circle[idx].prev_name = scn.custom_circle[idx].name 80 | else: 81 | bpy.data.objects[scn.custom_circle[idx].prev_name].name = scn.custom_circle[idx].name 82 | scn.custom_circle[idx].prev_name = scn.custom_circle[idx].name 83 | 84 | class UL_items_circle(UIList): 85 | 86 | def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): 87 | split = layout.split(0.1) 88 | split.label("%d" % (index)) 89 | split.prop(item, "name", text="%s" % (item.enabled), emboss=False, translate=True, icon='BORDER_RECT') 90 | 91 | def invoke(self, context, event): 92 | pass 93 | 94 | class UIListPanelExample_circle(Panel): 95 | """Creates a Panel in the Object properties window""" 96 | bl_idname = 'OBJECT_PT_my_panel_circle' 97 | bl_space_type = "VIEW_3D" 98 | bl_region_type = "TOOLS" 99 | bl_label = "3D Circles" 100 | 101 | def draw(self, context): 102 | layout = self.layout 103 | scn = bpy.context.scene 104 | 105 | rows = 5 106 | row = layout.row() 107 | row.template_list("UL_items_circle", "", scn, "custom_circle", scn, "custom_circle_index", rows=rows) 108 | 109 | col = row.column(align=True) 110 | col.operator("customcircle.list_action", icon='TRIA_UP', text="").action = 'UP' 111 | col.operator("customcircle.select_item", icon="UV_SYNC_SELECT") 112 | col.operator("customcircle.list_action", icon='TRIA_DOWN', text="").action = 'DOWN' 113 | col.separator() 114 | col.operator("customcircle.list_action", icon='ZOOMOUT', text="").action = 'REMOVE' 115 | col.operator("customcircle.list_action", icon='VISIBLE_IPO_ON', text="").action = 'ENABLE' 116 | col.operator("customcircle.list_action", icon='VISIBLE_IPO_OFF', text="").action = 'DISABLE' 117 | 118 | row = layout.row() 119 | col = row.column(align=True) 120 | col.operator("customcircle.clear_list", icon="X") 121 | 122 | class Uilist_selectAllItems_circle(bpy.types.Operator): 123 | bl_idname = "customcircle.select_item" 124 | bl_label = "" 125 | bl_description = "Edit Primitive" 126 | 127 | def __init__(self): 128 | self._ob_select = None 129 | 130 | def execute(self, context): 131 | scn = context.scene 132 | idx = scn.custom_circle_index 133 | object_deselection() 134 | 135 | try: 136 | item = scn.custom_circle[idx] 137 | except IndexError: 138 | pass 139 | 140 | else: 141 | self._ob_select = bpy.data.objects[scn.custom_circle[scn.custom_circle_index].name] 142 | scn.objects.active = self._ob_select 143 | self._ob_select.select = True 144 | scn.ignit_panel.vp_model_types = self._ob_select["vp_model_types"] 145 | 146 | scn.ignit_panel.vp_obj_Point1 = self._ob_select["vp_obj_Point1"] 147 | scn.ignit_panel.vp_obj_Point2 = self._ob_select["vp_obj_Point2"] 148 | scn.ignit_panel.vp_obj_Point3 = self._ob_select["vp_obj_Point3"] 149 | scn.ignit_panel.vp_radius = self._ob_select["vp_radius"] 150 | 151 | return{'FINISHED'} 152 | 153 | class Uilist_clearAllItems_circle(bpy.types.Operator): 154 | bl_idname = "customcircle.clear_list" 155 | bl_label = "Clear List" 156 | bl_description = "Clear all items in the list" 157 | 158 | def execute(self, context): 159 | scn = context.scene 160 | lst = scn.custom_circle 161 | object_deselection() 162 | 163 | if len(lst) > 0: 164 | for i in range(len(lst)-1,-1,-1): 165 | scn.custom_circle.remove(i) 166 | 167 | self.report({'INFO'}, "All items removed") 168 | 169 | else: 170 | self.report({'INFO'}, "Nothing to remove") 171 | 172 | return{'FINISHED'} 173 | 174 | class CustomProp_circle(bpy.types.PropertyGroup): 175 | name = bpy.props.StringProperty(update=primitive_name_update) 176 | prev_name = bpy.props.StringProperty() 177 | enabled = bpy.props.BoolProperty() 178 | 179 | # ######################################### 180 | # Register 181 | # ######################################### 182 | 183 | classes = ( 184 | CustomProp_circle, 185 | Uilist_actions_circle, 186 | Uilist_clearAllItems_circle, 187 | Uilist_selectAllItems_circle, 188 | UIListPanelExample_circle, 189 | UL_items_circle 190 | ) 191 | 192 | if __name__ == "__main__": 193 | from bpy.utils import register_class 194 | for cls in classes: 195 | register_class(cls) 196 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOExport/treeview_faces.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.props import IntProperty, CollectionProperty 3 | from bpy.types import Panel, UIList 4 | 5 | # ######################################### 6 | # TreeView 7 | # ######################################### 8 | 9 | def object_deselection(): 10 | try: 11 | bpy.ops.object.mode_set(mode='OBJECT') 12 | bpy.ops.object.select_all(action='DESELECT') 13 | except: 14 | pass 15 | 16 | def get_activeSceneObject(): 17 | return bpy.context.scene.objects.active.name 18 | 19 | class Uilist_actions_faces(bpy.types.Operator): 20 | bl_idname = "customfaces.list_action" 21 | bl_label = "List Action" 22 | 23 | action = bpy.props.EnumProperty( 24 | items=( 25 | ('UP', "Up", ""), 26 | ('DOWN', "Down", ""), 27 | ('REMOVE', "Remove", ""), 28 | ('DISABLE', "DISABLE", ""), 29 | ('ENABLE', "ENABLE", "") 30 | ) 31 | ) 32 | 33 | def invoke(self, context, event): 34 | 35 | scn = context.scene 36 | idx = scn.custom_faces_index 37 | 38 | try: 39 | item = scn.custom_faces[idx] 40 | except IndexError: 41 | pass 42 | 43 | else: 44 | if self.action == 'DOWN' and idx < len(scn.custom_faces) - 1: 45 | item_next = scn.custom_faces[idx+1].name 46 | scn.custom_faces_index += 1 47 | info = 'Item %d selected' % (scn.custom_faces_index + 1) 48 | self.report({'INFO'}, info) 49 | 50 | elif self.action == 'UP' and idx >= 1: 51 | item_prev = scn.custom_faces[idx-1].name 52 | scn.custom_faces_index -= 1 53 | info = 'Item %d selected' % (scn.custom_faces_index + 1) 54 | self.report({'INFO'}, info) 55 | 56 | elif self.action == 'REMOVE': 57 | info = 'Item %s removed from list' % (scn.custom_faces[scn.custom_faces_index].name) 58 | object_deselection() 59 | # bpy.data.objects[scn.custom_faces[scn.custom_faces_index].name].select = True 60 | # scn.objects.active = bpy.data.objects[scn.custom_faces[scn.custom_faces_index].name] 61 | # bpy.ops.object.delete() 62 | scn.custom_faces_index -= 1 63 | self.report({'INFO'}, info) 64 | scn.custom_faces.remove(idx) 65 | elif self.action == 'DISABLE': 66 | scn.custom_faces[scn.custom_faces_index].enabled = False 67 | elif self.action == 'ENABLE': 68 | scn.custom_faces[scn.custom_faces_index].enabled = True 69 | return {"FINISHED"} 70 | 71 | # ######################################### 72 | # Draw Panels and Button 73 | # ######################################### 74 | 75 | def primitive_name_update(self, context): 76 | scn = context.scene 77 | idx = scn.custom_faces_index 78 | 79 | # print(idx," NEW NAME: ",scn.custom_faces[idx].name," OLD NAME: ",scn.custom_faces[idx].prev_name) 80 | if scn.custom_faces[idx].prev_name == "": 81 | scn.custom_faces[idx].prev_name = scn.custom_faces[idx].name 82 | else: 83 | bpy.data.objects[scn.custom_faces[idx].prev_name].name = scn.custom_faces[idx].name 84 | scn.custom_faces[idx].prev_name = scn.custom_faces[idx].name 85 | 86 | class UL_items_faces(UIList): 87 | 88 | def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): 89 | split = layout.split(0.1) 90 | split.label("%d" % (index)) 91 | split.prop(item, "name", text="%s" % (item.enabled), emboss=False, translate=True, icon='BORDER_RECT') 92 | 93 | def invoke(self, context, event): 94 | pass 95 | 96 | class UIListPanelExample_faces(Panel): 97 | """Creates a Panel in the Object properties window""" 98 | bl_idname = 'OBJECT_PT_my_panel_faces' 99 | bl_space_type = "VIEW_3D" 100 | bl_region_type = "TOOLS" 101 | bl_label = "3D Faces" 102 | 103 | def draw(self, context): 104 | layout = self.layout 105 | scn = bpy.context.scene 106 | 107 | rows = 5 108 | row = layout.row() 109 | row.template_list("UL_items_faces", "", scn, "custom_faces", scn, "custom_faces_index", rows=rows) 110 | 111 | col = row.column(align=True) 112 | col.operator("customfaces.list_action", icon='TRIA_UP', text="").action = 'UP' 113 | col.operator("customfaces.select_item", icon="UV_SYNC_SELECT") 114 | col.operator("customfaces.list_action", icon='TRIA_DOWN', text="").action = 'DOWN' 115 | col.separator() 116 | col.operator("customfaces.list_action", icon='ZOOMOUT', text="").action = 'REMOVE' 117 | col.operator("customfaces.list_action", icon='VISIBLE_IPO_ON', text="").action = 'ENABLE' 118 | col.operator("customfaces.list_action", icon='VISIBLE_IPO_OFF', text="").action = 'DISABLE' 119 | 120 | row = layout.row() 121 | col = row.column(align=True) 122 | col.operator("customfaces.clear_list", icon="X") 123 | 124 | class Uilist_selectAllItems_faces(bpy.types.Operator): 125 | bl_idname = "customfaces.select_item" 126 | bl_label = "" 127 | bl_description = "Edit Primitive" 128 | 129 | def __init__(self): 130 | self._ob_select = None 131 | 132 | def execute(self, context): 133 | scn = context.scene 134 | idx = scn.custom_faces_index 135 | object_deselection() 136 | 137 | try: 138 | item = scn.custom_faces[idx] 139 | except IndexError: 140 | pass 141 | 142 | else: 143 | self._ob_select = bpy.data.objects[scn.custom_faces[scn.custom_faces_index].name] 144 | scn.objects.active = self._ob_select 145 | self._ob_select.select = True 146 | scn.ignit_panel.vp_model_types = self._ob_select["vp_model_types"] 147 | 148 | return{'FINISHED'} 149 | 150 | class Uilist_clearAllItems_faces(bpy.types.Operator): 151 | bl_idname = "customfaces.clear_list" 152 | bl_label = "Clear List" 153 | bl_description = "Clear all items in the list" 154 | 155 | def execute(self, context): 156 | scn = context.scene 157 | lst = scn.custom_faces 158 | object_deselection() 159 | 160 | if len(lst) > 0: 161 | for i in range(len(lst)-1,-1,-1): 162 | scn.custom_faces_index -= 1 163 | scn.custom_faces.remove(i) 164 | scn.custom_faces_index += 1 165 | self.report({'INFO'}, "All items removed") 166 | 167 | else: 168 | self.report({'INFO'}, "Nothing to remove") 169 | 170 | return{'FINISHED'} 171 | 172 | class CustomProp_faces(bpy.types.PropertyGroup): 173 | name = bpy.props.StringProperty(update=primitive_name_update) 174 | prev_name = bpy.props.StringProperty() 175 | enabled = bpy.props.BoolProperty() 176 | 177 | # ######################################### 178 | # Register 179 | # ######################################### 180 | 181 | classes = ( 182 | CustomProp_faces, 183 | Uilist_actions_faces, 184 | Uilist_clearAllItems_faces, 185 | Uilist_selectAllItems_faces, 186 | UIListPanelExample_faces, 187 | UL_items_faces 188 | ) 189 | 190 | if __name__ == "__main__": 191 | from bpy.utils import register_class 192 | for cls in classes: 193 | register_class(cls) 194 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOExport/treeview_cylinders.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.props import IntProperty, CollectionProperty 3 | from bpy.types import Panel, UIList 4 | 5 | # ######################################### 6 | # Register 7 | # ######################################### 8 | 9 | def object_deselection(): 10 | try: 11 | bpy.ops.object.mode_set(mode='OBJECT') 12 | bpy.ops.object.select_all(action='DESELECT') 13 | except: 14 | pass 15 | 16 | def get_activeSceneObject(): 17 | return bpy.context.scene.objects.active.name 18 | 19 | class Uilist_actions_cylinder(bpy.types.Operator): 20 | bl_idname = "customcylinder.list_action" 21 | bl_label = "List Action" 22 | 23 | action = bpy.props.EnumProperty( 24 | items=( 25 | ('UP', "Up", ""), 26 | ('DOWN', "Down", ""), 27 | ('REMOVE', "Remove", ""), 28 | ('DISABLE', "DISABLE", ""), 29 | ('ENABLE', "ENABLE", "") 30 | ) 31 | ) 32 | 33 | def invoke(self, context, event): 34 | 35 | scn = context.scene 36 | idx = scn.custom_cylinder_index 37 | 38 | try: 39 | item = scn.custom_cylinder[idx] 40 | except IndexError: 41 | pass 42 | 43 | else: 44 | if self.action == 'DOWN' and idx < len(scn.custom_cylinder) - 1: 45 | item_next = scn.custom_cylinder[idx+1].name 46 | scn.custom_cylinder_index += 1 47 | info = 'Item %d selected' % (scn.custom_cylinder_index + 1) 48 | self.report({'INFO'}, info) 49 | 50 | elif self.action == 'UP' and idx >= 1: 51 | item_prev = scn.custom_cylinder[idx-1].name 52 | scn.custom_cylinder_index -= 1 53 | info = 'Item %d selected' % (scn.custom_cylinder_index + 1) 54 | self.report({'INFO'}, info) 55 | 56 | elif self.action == 'REMOVE': 57 | info = 'Item %s removed from list' % (scn.custom_cylinder[scn.custom_cylinder_index].name) 58 | object_deselection() 59 | scn.custom_cylinder_index -= 1 60 | self.report({'INFO'}, info) 61 | scn.custom_cylinder.remove(idx) 62 | elif self.action == 'DISABLE': 63 | scn.custom_cylinder[scn.custom_cylinder_index].enabled = False 64 | elif self.action == 'ENABLE': 65 | scn.custom_cylinder[scn.custom_cylinder_index].enabled = True 66 | return {"FINISHED"} 67 | 68 | # ######################################### 69 | # Draw Panels and Button 70 | # ######################################### 71 | 72 | def primitive_name_update(self, context): 73 | scn = context.scene 74 | idx = scn.custom_cylinder_index 75 | 76 | if scn.custom_cylinder[idx].prev_name == "": 77 | scn.custom_cylinder[idx].prev_name = scn.custom_cylinder[idx].name 78 | else: 79 | bpy.data.objects[scn.custom_cylinder[idx].prev_name].name = scn.custom_cylinder[idx].name 80 | scn.custom_cylinder[idx].prev_name = scn.custom_cylinder[idx].name 81 | 82 | class UL_items_cylinder(UIList): 83 | 84 | def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): 85 | split = layout.split(0.1) 86 | split.label("%d" % (index)) 87 | split.prop(item, "name", text="%s" % (item.enabled), emboss=False, translate=False, icon='BORDER_RECT') 88 | 89 | def invoke(self, context, event): 90 | pass 91 | 92 | class UIListPanelExample_cylinder(Panel): 93 | """Creates a Panel in the Object properties window""" 94 | bl_idname = 'OBJECT_PT_my_panel_cylinder' 95 | bl_space_type = "VIEW_3D" 96 | bl_region_type = "TOOLS" 97 | bl_label = "3D Cylinders" 98 | 99 | def draw(self, context): 100 | layout = self.layout 101 | scn = bpy.context.scene 102 | 103 | rows = 5 104 | row = layout.row() 105 | row.template_list("UL_items_cylinder", "", scn, "custom_cylinder", scn, "custom_cylinder_index", rows=rows) 106 | 107 | col = row.column(align=True) 108 | col.operator("customcylinder.list_action", icon='TRIA_UP', text="").action = 'UP' 109 | col.operator("customcylinder.select_item", icon="UV_SYNC_SELECT") 110 | col.operator("customcylinder.list_action", icon='TRIA_DOWN', text="").action = 'DOWN' 111 | col.separator() 112 | col.operator("customcylinder.list_action", icon='ZOOMOUT', text="").action = 'REMOVE' 113 | col.operator("customcylinder.list_action", icon='VISIBLE_IPO_ON', text="").action = 'ENABLE' 114 | col.operator("customcylinder.list_action", icon='VISIBLE_IPO_OFF', text="").action = 'DISABLE' 115 | 116 | row = layout.row() 117 | col = row.column(align=True) 118 | col.operator("customcylinder.clear_list", icon="X") 119 | 120 | class Uilist_selectAllItems_cylinder(bpy.types.Operator): 121 | bl_idname = "customcylinder.select_item" 122 | bl_label = "" 123 | bl_description = "Edit Primitive" 124 | 125 | def __init__(self): 126 | self._ob_select = None 127 | 128 | def execute(self, context): 129 | scn = context.scene 130 | idx = scn.custom_cylinder_index 131 | object_deselection() 132 | 133 | try: 134 | item = scn.custom_cylinder[idx] 135 | except IndexError: 136 | pass 137 | 138 | else: 139 | self._ob_select = bpy.data.objects[scn.custom_cylinder[scn.custom_cylinder_index].name] 140 | scn.objects.active = self._ob_select 141 | self._ob_select.select = True 142 | scn.ignit_panel.vp_model_types = self._ob_select["vp_model_types"] 143 | 144 | scn.ignit_panel.vp_obj_Point1 = self._ob_select["vp_obj_Point1"] 145 | scn.ignit_panel.vp_obj_Point2 = self._ob_select["vp_obj_Point2"] 146 | scn.ignit_panel.vp_radius = self._ob_select["vp_radius"] 147 | 148 | return{'FINISHED'} 149 | 150 | class Uilist_clearAllItems_cylinder(bpy.types.Operator): 151 | bl_idname = "customcylinder.clear_list" 152 | bl_label = "Clear List" 153 | bl_description = "Clear all items in the list" 154 | 155 | def execute(self, context): 156 | scn = context.scene 157 | lst = scn.custom_cylinder 158 | current_index = scn.custom_cylinder_index 159 | object_deselection() 160 | 161 | if len(lst) > 0: 162 | for i in range(len(lst)-1,-1,-1): 163 | scn.custom_cylinder.remove(i) 164 | self.report({'INFO'}, "All items removed") 165 | 166 | else: 167 | self.report({'INFO'}, "Nothing to remove") 168 | 169 | return{'FINISHED'} 170 | 171 | class CustomProp_cylinder(bpy.types.PropertyGroup): 172 | name = bpy.props.StringProperty(update=primitive_name_update) 173 | prev_name = bpy.props.StringProperty() 174 | enabled = bpy.props.BoolProperty() 175 | 176 | # ######################################### 177 | # Register 178 | # ######################################### 179 | 180 | classes = ( 181 | CustomProp_cylinder, 182 | Uilist_actions_cylinder, 183 | Uilist_clearAllItems_cylinder, 184 | Uilist_selectAllItems_cylinder, 185 | UIListPanelExample_cylinder, 186 | UL_items_cylinder 187 | ) 188 | 189 | if __name__ == "__main__": 190 | from bpy.utils import register_class 191 | for cls in classes: 192 | register_class(cls) 193 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOImport/import_cao.py: -------------------------------------------------------------------------------- 1 | import array 2 | import os 3 | import time 4 | import re 5 | import bpy 6 | import bmesh 7 | import mathutils 8 | import math 9 | from random import * 10 | from bpy_extras.io_utils import unpack_list 11 | from progress_report import ProgressReport, ProgressReportSubstep 12 | 13 | def create_cylinder(axis_1, axis_2, radius): 14 | x1,y1,z1 = axis_1 15 | x2,y2,z2 = axis_2 16 | r = radius 17 | dx = x2 - x1 18 | dy = y2 - y1 19 | dz = z2 - z1 20 | dist = math.sqrt(dx**2 + dy**2 + dz**2) 21 | 22 | bpy.ops.mesh.primitive_cylinder_add( 23 | radius = r, 24 | depth = dist, 25 | location = (dx/2 + x1, dy/2 + y1, dz/2 + z1) 26 | ) 27 | 28 | bpy.context.object.rotation_euler[1] = math.acos(dz/dist) # theta 29 | bpy.context.object.rotation_euler[2] = math.atan2(dy, dx) # phi 30 | 31 | def create_circle(circum_1,circum_2,center,radius): 32 | x1,y1,z1 = circum_1 33 | x2,y2,z2 = center 34 | x3,y3,z3 = circum_2 35 | r = radius 36 | 37 | dx1 = x1 - x2 38 | dy1 = y1 - y2 39 | dz1 = z1 - z2 40 | dx2 = x3 - x2 41 | dy2 = y3 - y2 42 | dz2 = z3 - z2 43 | 44 | normal = mathutils.Vector.cross(mathutils.Vector((dx1,dy1,dz1)), mathutils.Vector((dx2,dy2,dz2))) 45 | 46 | bpy.ops.mesh.primitive_circle_add( 47 | radius = r, 48 | location = center 49 | ) 50 | 51 | # From parametric equation of a circle: 52 | # P(t) = r.cos(t).u + r.sin(t).n x u + C, where u = [-sin(phi),cos(phi),0]. 53 | 54 | theta = -math.atan( dy1 / dz1 ) 55 | phi = math.acos( dz1 / r ) 56 | # angle_z = math.atan( - math.cos( angle_x ) * math.sin( angle_y ) / math.sin( angle_x) ) - math.atan( dx / dy ) 57 | 58 | bpy.context.object.rotation_euler[1] = theta #TODO: fix rotation 59 | bpy.context.object.rotation_euler[2] = phi 60 | 61 | def create_mesh(global_matrix, 62 | verts_loc, 63 | lines, 64 | face_lines, 65 | face_points, 66 | cylinders, 67 | circles, 68 | TEMPLATE_FLAG, 69 | dataname 70 | ): 71 | 72 | scene = bpy.context.scene 73 | 74 | if TEMPLATE_FLAG in ["3D_F_PTS","3D_F_LNS"]: 75 | mesh_data = bpy.data.meshes.new(dataname) 76 | if face_points: 77 | mesh_data.from_pydata(verts_loc, [], face_points) 78 | else: 79 | bm = bmesh.new() 80 | # Import only lines 81 | for key in lines: 82 | if hasattr(bm.verts, "ensure_lookup_table"): 83 | bm.verts.ensure_lookup_table() 84 | v1 = bm.verts.new(verts_loc[key[0]]) 85 | v2 = bm.verts.new(verts_loc[key[1]]) 86 | bm.edges.new((v1, v2)) 87 | bm.to_mesh(mesh_data) 88 | bm.free() 89 | 90 | mesh_data.update() 91 | obj = bpy.data.objects.new(dataname, mesh_data) 92 | scene.objects.link(obj) 93 | scene.objects.active = obj 94 | obj.select = True 95 | obj.matrix_world = global_matrix 96 | 97 | elif TEMPLATE_FLAG == "3D_CYL": 98 | create_cylinder( *cylinders) 99 | 100 | elif TEMPLATE_FLAG == "3D_CIR": 101 | create_circle( *circles) 102 | 103 | # new_objects.append(obj) 104 | 105 | def load(operator, context, filepath, 106 | global_clamp_size=0.0, 107 | relpath=None, 108 | global_matrix=None, 109 | ): 110 | 111 | TEMPLATE_FLAG = "" 112 | 113 | def regex_search(text,line): 114 | return bool(re.search(text,line,re.IGNORECASE)) 115 | 116 | nFacelines = 0 117 | 118 | seed = ["b","l","e","n","d","r","v","t","i","s","p","a","z","y"] 119 | verts_loc = [] 120 | lines = [] 121 | face_points = [] 122 | face_lines = [] 123 | cylinders = [] 124 | circles = [] 125 | 126 | t_defined = ["3D_PTS", 127 | "3D_LNS", 128 | "3D_F_LNS", 129 | "3D_F_PTS", 130 | "3D_CYL", 131 | "3D_CIR"] 132 | 133 | with ProgressReport(context.window_manager) as progress: 134 | progress.enter_substeps(1, "Importing CAO %r..." % filepath) 135 | 136 | if global_matrix is None: 137 | global_matrix = mathutils.Matrix() 138 | 139 | time_main = time.time() 140 | 141 | # deselect all 142 | if bpy.ops.object.select_all.poll(): 143 | # bpy.ops.object.mode_set(mode='OBJECT') # TODO: check if object is mesh 144 | bpy.ops.object.select_all(action='DESELECT') 145 | 146 | scene = context.scene 147 | new_objects = [] # put new objects here 148 | index = 0 149 | 150 | progress.enter_substeps(3, "Parsing CAO file...") 151 | with open(filepath, 'rb') as f: 152 | for line in f: 153 | line_split = line.split() 154 | 155 | if not line_split: 156 | continue 157 | 158 | line_void = line.replace(b'\t', b'').replace(b' ', b'') 159 | 160 | if not line_void.split(b'#')[0]: 161 | continue 162 | 163 | data = line.split(b'#')[0].split() 164 | data_size = len(data) 165 | 166 | if data_size == 1: 167 | if data[0].isdigit(): 168 | TEMPLATE_FLAG = t_defined[index] 169 | index += 1 170 | 171 | if TEMPLATE_FLAG == "3D_PTS": 172 | if len(data) == 3: 173 | verts_loc.append(list(map(float,[x for x in data]))) 174 | 175 | elif TEMPLATE_FLAG == "3D_LNS": 176 | if len(data) >= 2: 177 | lines.append(list(map(int,[x for x in data[:2]]))) 178 | 179 | elif TEMPLATE_FLAG == "3D_F_LNS": 180 | if len(data) == 1: 181 | nFacelines =int(data[0]) 182 | if nFacelines == 0 and len(lines) > 0: 183 | # import only lines 184 | shuffle(seed) 185 | create_mesh(global_matrix,verts_loc,lines,[],[],[],[],TEMPLATE_FLAG,"3D Lines" + "_" + "".join(seed)) 186 | 187 | elif len(data) >= 4: 188 | face_lines.append(list(map(int,[data[i] for i in range(1,int(data[0])+1)]))) 189 | shuffle(seed) 190 | verts = [verts_loc[i] for i in [lines[i][0] for i in face_lines[-1]]] 191 | create_mesh(global_matrix,verts,[],[],[list(range(len(verts)))],[],[],TEMPLATE_FLAG,"3D Lines" + "_" + "".join(seed)) 192 | 193 | elif TEMPLATE_FLAG == "3D_F_PTS": 194 | if len(data) >= 4: 195 | face_points.append(list(map(int,[data[i] for i in range(1,int(data[0])+1)]))) 196 | shuffle(seed) 197 | verts = [verts_loc[i] for i in face_points[-1]] 198 | create_mesh(global_matrix,verts,[],[],[list(range(len(verts)))],[],[],TEMPLATE_FLAG,"3D Faces" + "_" + "".join(seed)) 199 | 200 | elif TEMPLATE_FLAG == "3D_CYL": 201 | if len(data) >= 3: 202 | cylinders = [verts_loc[int(data[0])],verts_loc[int(data[1])],float(data[2])] 203 | shuffle(seed) 204 | create_mesh(global_matrix,verts_loc,[],[],[],cylinders,[],TEMPLATE_FLAG,"3D Cylinder" + "_" + "".join(seed)) 205 | 206 | elif TEMPLATE_FLAG == "3D_CIR": 207 | if len(data) >= 4: 208 | circles = [verts_loc[int(data[2])],verts_loc[int(data[3])],verts_loc[int(data[1])],float(data[0])] 209 | shuffle(seed) 210 | create_mesh(global_matrix,verts_loc,[],[],[],[],circles,TEMPLATE_FLAG,"3D Cylinder" + "_" + "".join(seed)) 211 | 212 | progress.step("Done") 213 | 214 | scene.update() 215 | 216 | progress.leave_substeps("Done.") 217 | progress.leave_substeps("Finished importing: %r" % filepath) 218 | 219 | return {'FINISHED'} 220 | -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_player_play.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | 26 | 29 | 33 | 37 | 38 | 45 | 47 | 51 | 55 | 56 | 58 | 62 | 66 | 70 | 74 | 78 | 82 | 86 | 90 | 94 | 95 | 104 | 105 | 133 | 137 | 141 | 145 | 149 | 153 | 157 | 161 | 165 | 169 | 173 | 177 | 181 | 185 | 189 | 201 | 202 | 204 | 205 | 207 | image/svg+xml 208 | 210 | 211 | 212 | Lapo Calamandrei 213 | 214 | 215 | 216 | 218 | Play 219 | 220 | 221 | play 222 | playback 223 | start 224 | begin 225 | 226 | 227 | 228 | 230 | 232 | 234 | 236 | 238 | 240 | 242 | 243 | 244 | 245 | 249 | 254 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_player_stop.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | 26 | 29 | 33 | 37 | 38 | 45 | 47 | 51 | 55 | 56 | 58 | 62 | 66 | 70 | 74 | 78 | 82 | 86 | 90 | 94 | 95 | 104 | 105 | 133 | 137 | 141 | 145 | 149 | 153 | 157 | 161 | 165 | 169 | 173 | 177 | 181 | 185 | 189 | 201 | 202 | 204 | 205 | 207 | image/svg+xml 208 | 210 | 211 | 212 | Lapo Calamandrei 213 | 214 | 215 | 216 | 218 | Stop 219 | 220 | 221 | stop 222 | end 223 | playback 224 | 225 | 226 | 227 | 229 | 231 | 233 | 235 | 237 | 239 | 241 | 242 | 243 | 244 | 248 | 251 | 260 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_player_rew.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | 26 | 29 | 33 | 37 | 38 | 41 | 45 | 49 | 50 | 57 | 59 | 63 | 67 | 68 | 70 | 74 | 78 | 82 | 86 | 90 | 94 | 98 | 102 | 106 | 107 | 116 | 125 | 126 | 154 | 158 | 162 | 166 | 170 | 174 | 178 | 182 | 186 | 190 | 194 | 198 | 202 | 206 | 210 | 222 | 223 | 225 | 226 | 228 | image/svg+xml 229 | 231 | 232 | 233 | Lapo Calamandrei 234 | 235 | 236 | 237 | 239 | Rewind 240 | 241 | 242 | rewind 243 | seek 244 | backward 245 | 246 | 247 | 248 | 250 | 252 | 254 | 256 | 258 | 260 | 262 | 263 | 264 | 265 | 269 | 274 | 279 | 284 | 289 | 290 | 291 | -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_player_fwd.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | 26 | 29 | 33 | 37 | 38 | 41 | 45 | 49 | 50 | 57 | 59 | 63 | 67 | 68 | 70 | 74 | 78 | 82 | 86 | 90 | 94 | 98 | 102 | 106 | 107 | 116 | 125 | 126 | 154 | 158 | 162 | 166 | 170 | 174 | 178 | 182 | 186 | 190 | 194 | 198 | 202 | 206 | 210 | 222 | 223 | 225 | 226 | 228 | image/svg+xml 229 | 231 | 232 | 233 | Lapo Calamandrei 234 | 235 | 236 | 237 | 239 | Rewind 240 | 241 | 242 | rewind 243 | seek 244 | backward 245 | 246 | 247 | 248 | 250 | 252 | 254 | 256 | 258 | 260 | 262 | 263 | 264 | 265 | 269 | 274 | 279 | 284 | 289 | 290 | 291 | -------------------------------------------------------------------------------- /blenderAddons/vispCAOExport/export_cao.py: -------------------------------------------------------------------------------- 1 | # 2 | 3 | import os 4 | import time 5 | import re 6 | 7 | import bpy 8 | import mathutils 9 | import bpy_extras.io_utils 10 | 11 | 12 | # ##################################################### 13 | # Templates 14 | # ##################################################### 15 | 16 | TEMPLATE_CAO_FILE = u"""\ 17 | { 18 | V1, 19 | # 3D points, 20 | %(nPoints)d, 21 | [%(points)s], 22 | # 3D lines, 23 | %(nLines)d, 24 | [%(lines)s], 25 | # Faces from 3D lines, 26 | %(nFacelines)d, 27 | [%(facelines)s], 28 | # Faces from 3D points, 29 | %(nFacepoints)d, 30 | [%(facepoints)s], 31 | # 3D cylinders, 32 | %(nCylinder)d, 33 | [%(cylinders)s], 34 | # 3D circles, 35 | %(nCircles)d, 36 | [%(circles)s] 37 | } 38 | """ 39 | 40 | TEMPLATE_LINES = "%d %d" 41 | 42 | TEMPLATE_VERTEX = "%f %f %f" 43 | 44 | TEMPLATE_CYLINDER = "%d %d %f" 45 | 46 | TEMPLATE_CIRCLE = "%f %d %d %d" 47 | 48 | # ##################################################### 49 | # Utils 50 | # ##################################################### 51 | 52 | def mesh_triangulate(me): 53 | import bmesh 54 | bm = bmesh.new() 55 | bm.from_mesh(me) 56 | bmesh.ops.triangulate(bm, faces=bm.faces) 57 | bm.to_mesh(me) 58 | bm.free() 59 | 60 | def generate_vertices(v): 61 | return TEMPLATE_VERTEX % (v[0], v[1], v[2]) 62 | 63 | def generate_lines(l): 64 | return TEMPLATE_LINES % (l[0], l[1]) 65 | 66 | def generate_facelines(fl): 67 | return " ".join(map(str,[x for x in fl])) 68 | 69 | def generate_faces(v): 70 | return str(len(v)) + " " + " ".join(map(str,[x-1 for x in v])) 71 | 72 | def generate_cylinders(c): 73 | return TEMPLATE_CYLINDER % (c[0], c[1], c[2]) 74 | 75 | def generate_circles(c): 76 | return TEMPLATE_CIRCLE % (c[0], c[1], c[2], c[3]) 77 | 78 | def write_file(filepath, objects, scene, 79 | EXPORT_TRI=False, 80 | EXPORT_EDGES=False, 81 | EXPORT_NORMALS=False, 82 | EXPORT_APPLY_MODIFIERS=True, 83 | EXPORT_GLOBAL_MATRIX=None, 84 | ): 85 | 86 | print('CAO Export path: %r' % filepath) 87 | 88 | time1 = time.time() 89 | 90 | file = open(filepath, "w", encoding="utf8", newline="\n") 91 | fw = file.write 92 | 93 | # Write Header 94 | fw('# Blender v%s CAO File\n' % (bpy.app.version_string)) 95 | 96 | # Initialize 97 | totverts = 1 98 | face_vert_index = 1 99 | copy_set = set() 100 | 101 | vertices = [] 102 | faces = [] 103 | lines = [] 104 | facelines = [] 105 | gcylinders = [] 106 | gcircles = [] 107 | 108 | for area in bpy.context.screen.areas: 109 | if area.type == 'VIEW_3D': 110 | if area.spaces[0].transform_orientation == 'GLOBAL': 111 | EXPORT_GLOBAL_MATRIX = mathutils.Matrix() 112 | break 113 | else: 114 | EXPORT_GLOBAL_MATRIX = None 115 | 116 | # Get all meshes 117 | for ob_main in objects: 118 | 119 | # ignore dupli children 120 | if ob_main.parent and ob_main.parent.dupli_type in {'VERTS', 'FACES'}: 121 | continue 122 | 123 | obs = [] 124 | if ob_main.dupli_type != 'NONE': 125 | # print('creating dupli_list on', ob_main.name) 126 | ob_main.dupli_list_create(scene) 127 | obs = [(dob.object, dob.matrix) for dob in ob_main.dupli_list] 128 | 129 | else: 130 | obs = [(ob_main, ob_main.matrix_world)] 131 | 132 | try: 133 | ob_main["vp_model_types"] 134 | except: 135 | continue 136 | 137 | for ob, ob_mat in obs: 138 | 139 | try: 140 | me = ob.to_mesh(scene, EXPORT_APPLY_MODIFIERS, 'PREVIEW', calc_tessface=False) 141 | except RuntimeError: 142 | me = None 143 | 144 | if me is None or ob_main["vp_model_types"] not in ["3D Faces","3D Lines"]: 145 | continue 146 | 147 | if EXPORT_GLOBAL_MATRIX is not None: 148 | me.transform(EXPORT_GLOBAL_MATRIX * ob_mat)# Translate to World Coordinate System 149 | 150 | if EXPORT_TRI: 151 | mesh_triangulate(me) 152 | 153 | me_verts = me.vertices[:] 154 | 155 | face_index_pairs = [(face, index) for index, face in enumerate(me.polygons)] 156 | 157 | if EXPORT_EDGES: 158 | edges = me.edges 159 | else: 160 | edges = [] 161 | 162 | if not (len(face_index_pairs) + len(edges) + len(me.vertices)): 163 | bpy.data.meshes.remove(me) 164 | continue # ignore this mesh. 165 | 166 | smooth_groups, smooth_groups_tot = (), 0 167 | 168 | # no materials 169 | if smooth_groups: 170 | sort_func = lambda a: smooth_groups[a[1] if a[0].use_smooth else False] 171 | else: 172 | sort_func = lambda a: a[0].use_smooth 173 | 174 | face_index_pairs.sort(key=sort_func) 175 | del sort_func 176 | 177 | # fw('# %s\n' % (ob_main.name)) 178 | 179 | # Vertices 180 | for v in me_verts: 181 | vertices.append(v.co[:]) 182 | 183 | # Faces 184 | for f, f_index in face_index_pairs: 185 | f_v = [(vi, me_verts[v_idx], l_idx) for vi, (v_idx, l_idx) in enumerate(zip(f.vertices, f.loop_indices))] 186 | f_side = [] 187 | 188 | for vi, v, li in f_v: 189 | f_side.append(totverts + v.index) 190 | 191 | # Lines/Edges 192 | if ob_main["vp_model_types"] == "3D Lines": 193 | initialen = len(lines) 194 | for i in range(0,len(f_side)-1): 195 | lines.append([f_side[i]-1,f_side[i+1]-1])# TODO: Remove duplicates 196 | lines.append([f_side[len(f_side)-1]-1,f_side[0]-1]) 197 | if ob_main["vp_line_face"]: 198 | facelines.append([len(lines)-initialen, list(range(initialen, len(lines)))]) 199 | 200 | else: 201 | faces.append(f_side) 202 | 203 | # If no faces are present but only lines 204 | if len(face_index_pairs) == 0 and ob_main["vp_model_types"] == "3D Lines": 205 | for key in me.edge_keys: 206 | lines.append([key[0],key[1]]) 207 | 208 | # Make the indices global rather then per mesh 209 | totverts += len(me_verts) 210 | 211 | # clean up 212 | bpy.data.meshes.remove(me) 213 | 214 | if ob_main["vp_model_types"] == "3D Cylinders": 215 | gcylinders.append([len(vertices), len(vertices)+1, ob_main["vp_radius"]]) # Get radius 216 | vertices.append(ob_main["vp_obj_Point1"]) 217 | vertices.append(ob_main["vp_obj_Point2"]) 218 | totverts += 2 219 | 220 | elif ob_main["vp_model_types"] == "3D Circles": 221 | gcircles.append([ob_main["vp_radius"], len(vertices), len(vertices)+1, len(vertices)+2]) 222 | vertices.append(ob_main["vp_obj_Point3"]) 223 | vertices.append(ob_main["vp_obj_Point1"]) 224 | vertices.append(ob_main["vp_obj_Point2"]) 225 | totverts += 3 226 | 227 | if ob_main.dupli_type != 'NONE': 228 | ob_main.dupli_list_clear() 229 | 230 | npoints = len(vertices) 231 | nfacepoints = len(faces) 232 | nlines = len(lines) 233 | nfacelines = len(facelines) 234 | ncylinders = len(gcylinders) 235 | ncircles = len(gcircles) 236 | 237 | text = TEMPLATE_CAO_FILE % { 238 | "nPoints" : npoints, 239 | "points" : "\n".join(generate_vertices(v) for v in vertices), 240 | "nLines" : nlines, 241 | "lines" : "\n".join(generate_lines(l) for l in lines), 242 | "nFacelines" : nfacelines, 243 | "facelines" : "\n".join(generate_facelines(fl) for fl in facelines), 244 | "nFacepoints" : nfacepoints, 245 | "facepoints" : "\n".join(generate_faces(f) for f in faces), 246 | "nCylinder" : ncylinders, 247 | "cylinders" : "\n".join(generate_cylinders(c) for c in gcylinders), 248 | "nCircles" : ncircles, 249 | "circles" : "\n".join(generate_circles(c) for c in gcircles) 250 | } 251 | 252 | text = text.replace(',', '').replace('{', '').replace('}', '').replace('{', '').replace('[', '').replace(']', '') 253 | text = "".join([s for s in text.strip().splitlines(True) if s.strip()]) 254 | 255 | fw(text) 256 | file.close() 257 | 258 | # copy all collected files. 259 | bpy_extras.io_utils.path_reference_copy(copy_set) 260 | 261 | print("Export time: %.2f" % (time.time() - time1)) 262 | 263 | 264 | def _write(context, filepath, 265 | EXPORT_TRI, # ok 266 | EXPORT_EDGES, 267 | EXPORT_NORMALS, # not yet 268 | EXPORT_APPLY_MODIFIERS, # ok 269 | EXPORT_SEL_ONLY, # ok 270 | EXPORT_GLOBAL_MATRIX, 271 | ): # Not used 272 | 273 | base_name, ext = os.path.splitext(filepath) 274 | context_name = [base_name, '', '', ext] # Base name, scene name, frame number, extension 275 | scene = context.scene 276 | 277 | # Exit edit mode before exporting, so current object states are exported properly. 278 | if bpy.ops.object.mode_set.poll(): 279 | bpy.ops.object.mode_set(mode='OBJECT') 280 | 281 | orig_frame = scene.frame_current 282 | scene_frames = [orig_frame] 283 | EXPORT_SEL_ONLY = True # Hard-coded? 284 | 285 | # Loop through all frames in the scene and export. 286 | for frame in scene_frames: 287 | 288 | scene.frame_set(frame, 0.0) 289 | if EXPORT_SEL_ONLY: 290 | objects = context.selected_objects 291 | else: 292 | objects = scene.objects 293 | 294 | full_path = ''.join(context_name) 295 | 296 | # EXPORT THE FILE. 297 | write_file(full_path, objects, scene, 298 | EXPORT_TRI, 299 | EXPORT_EDGES, 300 | EXPORT_NORMALS, 301 | EXPORT_APPLY_MODIFIERS, 302 | EXPORT_GLOBAL_MATRIX, 303 | ) 304 | 305 | scene.frame_set(orig_frame, 0.0) 306 | 307 | def save(operator, context, filepath="", 308 | use_triangles=False, 309 | use_edges=True, 310 | use_normals=False, 311 | use_mesh_modifiers=True, 312 | use_selection=True, 313 | global_matrix=None, 314 | ): 315 | 316 | _write(context, filepath, 317 | EXPORT_TRI=use_triangles, 318 | EXPORT_EDGES=use_edges, 319 | EXPORT_NORMALS=use_normals, 320 | EXPORT_APPLY_MODIFIERS=use_mesh_modifiers, 321 | EXPORT_SEL_ONLY=use_selection, 322 | EXPORT_GLOBAL_MATRIX=global_matrix, 323 | ) 324 | 325 | return {'FINISHED'} 326 | -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_player_pause.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | 26 | 29 | 33 | 37 | 38 | 41 | 45 | 49 | 50 | 57 | 59 | 63 | 67 | 68 | 70 | 74 | 78 | 82 | 86 | 90 | 94 | 98 | 102 | 106 | 107 | 117 | 127 | 128 | 156 | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | 192 | 196 | 200 | 204 | 208 | 212 | 224 | 225 | 227 | 228 | 230 | image/svg+xml 231 | 233 | 234 | 235 | Lapo Calamandrei 236 | 237 | 238 | 239 | 241 | Pause 242 | 243 | 244 | playback 245 | pause 246 | 247 | 248 | 249 | 251 | 253 | 255 | 257 | 259 | 261 | 263 | 264 | 265 | 266 | 270 | 279 | 288 | 293 | 298 | 299 | 300 | -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_player_record.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 26 | 28 | 32 | 36 | 37 | 39 | 43 | 47 | 48 | 51 | 55 | 59 | 60 | 63 | 67 | 71 | 72 | 81 | 91 | 102 | 111 | 112 | 141 | 145 | 149 | 153 | 157 | 161 | 165 | 169 | 173 | 177 | 181 | 185 | 189 | 193 | 197 | 209 | 210 | 212 | 213 | 215 | image/svg+xml 216 | 218 | 219 | 220 | Lapo Calamandrei 221 | 222 | 223 | 224 | 226 | Record 227 | 228 | 229 | record 230 | media 231 | 232 | 233 | 234 | 235 | Jakub Steiner 236 | 237 | 238 | 239 | 241 | 243 | 245 | 247 | 249 | 251 | 253 | 254 | 255 | 256 | 260 | 263 | 272 | 278 | 284 | 294 | 304 | 314 | 315 | 316 | -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 31 | 34 | 38 | 42 | 43 | 53 | 56 | 60 | 64 | 65 | 76 | 77 | 99 | 102 | 103 | 105 | 106 | 108 | image/svg+xml 109 | 111 | 112 | 113 | 114 | 115 | 119 | 122 | 134 | 143 | 152 | 159 | 166 | 173 | 180 | 187 | 194 | 201 | 208 | 215 | 216 | 224 | 228 | 233 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_clean.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 14 | 16 | 20 | 24 | 25 | 27 | 31 | 35 | 36 | 38 | 42 | 46 | 47 | 49 | 53 | 57 | 58 | 60 | 64 | 68 | 69 | 71 | 75 | 79 | 80 | 82 | 86 | 90 | 91 | 93 | 97 | 101 | 102 | 104 | 108 | 112 | 113 | 122 | 131 | 140 | 148 | 157 | 166 | 175 | 184 | 194 | 195 | 197 | 202 | 206 | 211 | 215 | 219 | 223 | 227 | 231 | 235 | 239 | 243 | 247 | 251 | 255 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /qt-cao-editor/app/xmleditor.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the examples of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:BSD$ 9 | ** You may use this file under the terms of the BSD license as follows: 10 | ** 11 | ** "Redistribution and use in source and binary forms, with or without 12 | ** modification, are permitted provided that the following conditions are 13 | ** met: 14 | ** * Redistributions of source code must retain the above copyright 15 | ** notice, this list of conditions and the following disclaimer. 16 | ** * Redistributions in binary form must reproduce the above copyright 17 | ** notice, this list of conditions and the following disclaimer in 18 | ** the documentation and/or other materials provided with the 19 | ** distribution. 20 | ** * Neither the name of The Qt Company Ltd nor the names of its 21 | ** contributors may be used to endorse or promote products derived 22 | ** from this software without specific prior written permission. 23 | ** 24 | ** 25 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 36 | ** 37 | ** $QT_END_LICENSE$ 38 | ** 39 | ****************************************************************************/ 40 | 41 | #include 42 | 43 | #include "xmleditor.h" 44 | 45 | XmlEditor::XmlEditor() 46 | : textEdit(new QPlainTextEdit) 47 | { 48 | setCentralWidget(textEdit); 49 | createActions(); 50 | createStatusBar(); 51 | 52 | readSettings(); 53 | 54 | connect(textEdit->document(), &QTextDocument::contentsChanged, 55 | this, &XmlEditor::documentWasModified); 56 | 57 | #ifndef QT_NO_SESSIONMANAGER 58 | QGuiApplication::setFallbackSessionManagementEnabled(false); 59 | connect(qApp, &QGuiApplication::commitDataRequest, 60 | this, &XmlEditor::commitData); 61 | #endif 62 | textEdit->setPlainText("\n\n\n \n \n 5\n 180\n \n \n 8\n \n \n 10000\n 0.5\n 0.5\n \n \n 4\n \n \n \n 5\n 300\n 5\n 0.015\n 8\n 0.01\n 3\n 3\n \n \n 325.66776\n 243.69727\n 839.21470\n 839.44555\n \n \n 70\n 80\n 0.1\n 100\n 1\n \n"); 63 | 64 | // setWindowTitle(tr("XML Editor[*]")); 65 | setCurrentFile(QString()); 66 | setUnifiedTitleAndToolBarOnMac(true); 67 | } 68 | 69 | void XmlEditor::closeEvent(QCloseEvent *event) 70 | { 71 | if (maybeSave()) 72 | { 73 | writeSettings(); 74 | event->accept(); 75 | } 76 | else 77 | event->ignore(); 78 | } 79 | 80 | void XmlEditor::newFile() 81 | { 82 | if (maybeSave()) 83 | { 84 | textEdit->clear(); 85 | setCurrentFile(QString()); 86 | } 87 | } 88 | 89 | void XmlEditor::open() 90 | { 91 | if (maybeSave()) 92 | { 93 | QString fileName = QFileDialog::getOpenFileName(this); 94 | if (!fileName.isEmpty()) 95 | loadFile(fileName); 96 | } 97 | } 98 | 99 | bool XmlEditor::save() 100 | { 101 | if (curFile.isEmpty()) 102 | { 103 | return saveAs(); 104 | } 105 | else 106 | return saveFile(curFile); 107 | } 108 | 109 | bool XmlEditor::saveAs() 110 | { 111 | QFileDialog dialog(this); 112 | dialog.setWindowModality(Qt::WindowModal); 113 | dialog.setAcceptMode(QFileDialog::AcceptSave); 114 | if (dialog.exec() != QDialog::Accepted) 115 | return false; 116 | return saveFile(dialog.selectedFiles().first()); 117 | } 118 | 119 | void XmlEditor::about() 120 | { 121 | QMessageBox::about(this, tr("About Application"), 122 | tr("The Application example demonstrates how to " 123 | "write modern GUI applications using Qt, with a menu bar, " 124 | "toolbars, and a status bar.")); 125 | } 126 | 127 | void XmlEditor::documentWasModified() 128 | { 129 | setWindowModified(textEdit->document()->isModified()); 130 | } 131 | 132 | void XmlEditor::createActions() 133 | { 134 | QMenu *fileMenu = menuBar()->addMenu(tr("&File")); 135 | const QIcon newIcon = QIcon::fromTheme("document-new", QIcon(":/images/new.png")); 136 | QAction *newAct = new QAction(newIcon, tr("&New"), this); 137 | newAct->setShortcuts(QKeySequence::New); 138 | newAct->setStatusTip(tr("Create a new file")); 139 | connect(newAct, &QAction::triggered, this, &XmlEditor::newFile); 140 | fileMenu->addAction(newAct); 141 | 142 | const QIcon openIcon = QIcon::fromTheme("document-open", QIcon(":/images/open.png")); 143 | QAction *openAct = new QAction(openIcon, tr("&Open..."), this); 144 | openAct->setShortcuts(QKeySequence::Open); 145 | openAct->setStatusTip(tr("Open an existing file")); 146 | connect(openAct, &QAction::triggered, this, &XmlEditor::open); 147 | fileMenu->addAction(openAct); 148 | 149 | const QIcon saveIcon = QIcon::fromTheme("document-save", QIcon(":/images/save.png")); 150 | QAction *saveAct = new QAction(saveIcon, tr("&Save"), this); 151 | saveAct->setShortcuts(QKeySequence::Save); 152 | saveAct->setStatusTip(tr("Save the document to disk")); 153 | connect(saveAct, &QAction::triggered, this, &XmlEditor::save); 154 | fileMenu->addAction(saveAct); 155 | 156 | const QIcon saveAsIcon = QIcon::fromTheme("document-save-as"); 157 | QAction *saveAsAct = fileMenu->addAction(saveAsIcon, tr("Save &As..."), this, &XmlEditor::saveAs); 158 | saveAsAct->setShortcuts(QKeySequence::SaveAs); 159 | saveAsAct->setStatusTip(tr("Save the document under a new name")); 160 | 161 | fileMenu->addSeparator(); 162 | 163 | const QIcon exitIcon = QIcon::fromTheme("application-exit"); 164 | QAction *exitAct = fileMenu->addAction(exitIcon, tr("E&xit"), this, &QWidget::close); 165 | exitAct->setShortcuts(QKeySequence::Quit); 166 | 167 | exitAct->setStatusTip(tr("Exit the application")); 168 | 169 | QMenu *editMenu = menuBar()->addMenu(tr("&Edit")); 170 | 171 | #ifndef QT_NO_CLIPBOARD 172 | const QIcon cutIcon = QIcon::fromTheme("edit-cut", QIcon(":/images/cut.png")); 173 | QAction *cutAct = new QAction(cutIcon, tr("Cu&t"), this); 174 | 175 | cutAct->setShortcuts(QKeySequence::Cut); 176 | cutAct->setStatusTip(tr("Cut the current selection's contents to the " 177 | "clipboard")); 178 | connect(cutAct, &QAction::triggered, textEdit, &QPlainTextEdit::cut); 179 | editMenu->addAction(cutAct); 180 | 181 | const QIcon copyIcon = QIcon::fromTheme("edit-copy", QIcon(":/images/copy.png")); 182 | QAction *copyAct = new QAction(copyIcon, tr("&Copy"), this); 183 | copyAct->setShortcuts(QKeySequence::Copy); 184 | copyAct->setStatusTip(tr("Copy the current selection's contents to the " 185 | "clipboard")); 186 | connect(copyAct, &QAction::triggered, textEdit, &QPlainTextEdit::copy); 187 | editMenu->addAction(copyAct); 188 | 189 | const QIcon pasteIcon = QIcon::fromTheme("edit-paste", QIcon(":/images/paste.png")); 190 | QAction *pasteAct = new QAction(pasteIcon, tr("&Paste"), this); 191 | pasteAct->setShortcuts(QKeySequence::Paste); 192 | pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current " 193 | "selection")); 194 | connect(pasteAct, &QAction::triggered, textEdit, &QPlainTextEdit::paste); 195 | editMenu->addAction(pasteAct); 196 | 197 | menuBar()->addSeparator(); 198 | 199 | #endif 200 | 201 | #ifndef QT_NO_CLIPBOARD 202 | cutAct->setEnabled(false); 203 | 204 | copyAct->setEnabled(false); 205 | connect(textEdit, &QPlainTextEdit::copyAvailable, cutAct, &QAction::setEnabled); 206 | connect(textEdit, &QPlainTextEdit::copyAvailable, copyAct, &QAction::setEnabled); 207 | #endif 208 | } 209 | 210 | void XmlEditor::createStatusBar() 211 | { 212 | statusBar()->showMessage(tr("Ready")); 213 | } 214 | 215 | void XmlEditor::readSettings() 216 | { 217 | QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); 218 | const QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray(); 219 | if (geometry.isEmpty()) { 220 | const QRect availableGeometry = QApplication::desktop()->availableGeometry(this); 221 | resize(availableGeometry.width() / 3, availableGeometry.height() / 2); 222 | move((availableGeometry.width() - width()) / 2, 223 | (availableGeometry.height() - height()) / 2); 224 | } else { 225 | restoreGeometry(geometry); 226 | } 227 | } 228 | 229 | void XmlEditor::writeSettings() 230 | { 231 | QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); 232 | settings.setValue("geometry", saveGeometry()); 233 | } 234 | 235 | bool XmlEditor::maybeSave() 236 | { 237 | if (!textEdit->document()->isModified()) 238 | return true; 239 | const QMessageBox::StandardButton ret 240 | = QMessageBox::warning(this, tr("Application"), 241 | tr("The document has been modified.\n" 242 | "Do you want to save your changes?"), 243 | QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); 244 | switch (ret) 245 | { 246 | case QMessageBox::Save: 247 | return save(); 248 | case QMessageBox::Cancel: 249 | return false; 250 | default: 251 | break; 252 | } 253 | return true; 254 | } 255 | 256 | void XmlEditor::loadFile(const QString &fileName) 257 | { 258 | qInfo() << fileName; 259 | QFile file(fileName); 260 | if (!file.open(QFile::ReadOnly | QFile::Text)) 261 | { 262 | QMessageBox::warning(this, tr("Application"), 263 | tr("Cannot read file %1:\n%2.") 264 | .arg(QDir::toNativeSeparators(fileName), file.errorString())); 265 | return; 266 | } 267 | 268 | QTextStream in(&file); 269 | #ifndef QT_NO_CURSOR 270 | QApplication::setOverrideCursor(Qt::WaitCursor); 271 | #endif 272 | textEdit->setPlainText(in.readAll()); 273 | #ifndef QT_NO_CURSOR 274 | QApplication::restoreOverrideCursor(); 275 | #endif 276 | 277 | setCurrentFile(fileName); 278 | statusBar()->showMessage(tr("File loaded"), 2000); 279 | } 280 | 281 | bool XmlEditor::saveFile(const QString &fileName) 282 | { 283 | QFile file(fileName); 284 | if (!file.open(QFile::WriteOnly | QFile::Text)) 285 | { 286 | QMessageBox::warning(this, tr("Application"), 287 | tr("Cannot write file %1:\n%2.") 288 | .arg(QDir::toNativeSeparators(fileName), 289 | file.errorString())); 290 | return false; 291 | } 292 | 293 | QTextStream out(&file); 294 | #ifndef QT_NO_CURSOR 295 | QApplication::setOverrideCursor(Qt::WaitCursor); 296 | #endif 297 | out << textEdit->toPlainText(); 298 | #ifndef QT_NO_CURSOR 299 | QApplication::restoreOverrideCursor(); 300 | #endif 301 | 302 | setCurrentFile(fileName); 303 | statusBar()->showMessage(tr("File saved"), 2000); 304 | return true; 305 | } 306 | 307 | void XmlEditor::setCurrentFile(const QString &fileName) 308 | { 309 | curFile = fileName; 310 | textEdit->document()->setModified(false); 311 | setWindowModified(false); 312 | 313 | QString shownName = curFile; 314 | if (curFile.isEmpty()) 315 | shownName = "untitled.xml"; 316 | setWindowFilePath(shownName); 317 | } 318 | 319 | QString XmlEditor::strippedName(const QString &fullFileName) 320 | { 321 | return QFileInfo(fullFileName).fileName(); 322 | } 323 | 324 | #ifndef QT_NO_SESSIONMANAGER 325 | void XmlEditor::commitData(QSessionManager &manager) 326 | { 327 | if (manager.allowsInteraction()) 328 | { 329 | if (!maybeSave()) 330 | manager.cancel(); 331 | } 332 | else 333 | { 334 | if (textEdit->document()->isModified()) 335 | save(); 336 | } 337 | } 338 | #endif 339 | -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_file.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 14 | 16 | 20 | 24 | 25 | 27 | 31 | 35 | 36 | 45 | 47 | 51 | 55 | 56 | 58 | 62 | 66 | 67 | 69 | 73 | 77 | 78 | 88 | 98 | 108 | 118 | 128 | 138 | 140 | 144 | 148 | 149 | 151 | 155 | 159 | 160 | 162 | 166 | 170 | 171 | 173 | 177 | 181 | 182 | 184 | 188 | 192 | 193 | 201 | 209 | 217 | 225 | 233 | 235 | 239 | 243 | 247 | 248 | 250 | 254 | 258 | 259 | 269 | 279 | 287 | 288 | 290 | 293 | 296 | 300 | 307 | 315 | 322 | 323 | 324 | 325 | 326 | 329 | 333 | 337 | 338 | 341 | 345 | 349 | 353 | 354 | 355 | -------------------------------------------------------------------------------- /qt-cao-editor/app/images/icon_player_start.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | 26 | 29 | 33 | 37 | 38 | 45 | 47 | 51 | 55 | 56 | 58 | 62 | 66 | 70 | 74 | 78 | 82 | 86 | 90 | 94 | 95 | 104 | 113 | 115 | 119 | 123 | 127 | 131 | 135 | 139 | 143 | 147 | 151 | 152 | 154 | 158 | 162 | 163 | 170 | 173 | 177 | 181 | 182 | 185 | 189 | 193 | 194 | 204 | 205 | 233 | 237 | 241 | 245 | 249 | 253 | 257 | 261 | 265 | 269 | 273 | 277 | 281 | 285 | 289 | 301 | 302 | 304 | 305 | 307 | image/svg+xml 308 | 310 | 311 | 312 | Lapo Calamandrei 313 | 314 | 315 | 316 | 318 | Previous Song 319 | 320 | 321 | skip 322 | backward 323 | previous 324 | media 325 | 326 | 327 | 328 | 330 | 332 | 334 | 336 | 338 | 340 | 342 | 343 | 344 | 345 | 349 | 353 | 358 | 363 | 368 | 373 | 374 | 383 | 392 | 393 | 394 | --------------------------------------------------------------------------------