├── 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 | [](https://youtu.be/jeihOFwtSoI)
69 |
70 | ### TreeView Management
71 |
72 | 
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 |
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 |
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 |
261 |
--------------------------------------------------------------------------------
/qt-cao-editor/app/images/icon_player_stop.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
267 |
--------------------------------------------------------------------------------
/qt-cao-editor/app/images/icon_player_rew.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
291 |
--------------------------------------------------------------------------------
/qt-cao-editor/app/images/icon_player_fwd.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 |
300 |
--------------------------------------------------------------------------------
/qt-cao-editor/app/images/icon_player_record.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
316 |
--------------------------------------------------------------------------------
/qt-cao-editor/app/images/icon_copy.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
240 |
--------------------------------------------------------------------------------
/qt-cao-editor/app/images/icon_clean.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
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 |
355 |
--------------------------------------------------------------------------------
/qt-cao-editor/app/images/icon_player_start.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
394 |
--------------------------------------------------------------------------------