diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..39f6204 --- /dev/null +++ b/.clang-format @@ -0,0 +1,3 @@ +BasedOnStyle: Chromium + +ColumnLimit: 120 \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c67318..492ef76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ project(pmuc) cmake_minimum_required(VERSION 2.8) +cmake_policy(SET CMP0074 NEW) SET(CMAKE_MODULE_PATH "${pmuc_SOURCE_DIR}/CMakeModules;${CMAKE_MODULE_PATH}") @@ -25,7 +26,12 @@ find_package(EIGEN REQUIRED) include_directories( ${EIGEN_INCLUDE_DIR} ) # Find Boost dependencies -find_package(Boost 1.65.1 REQUIRED) +if (WIN) + find_package(Boost 1.69.0 REQUIRED) +else() + find_package(Boost 1.65.1 REQUIRED) +endif() + IF(Boost_FOUND) INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) ENDIF() @@ -52,13 +58,14 @@ add_test(NAME run_pmuc COMMAND ${PROJECT_NAME} --help) set_tests_properties(run_pmuc PROPERTIES PASS_REGULAR_EXPRESSION "usage") set_tests_properties(run_pmuc PROPERTIES PASS_REGULAR_EXPRESSION "--x3d") set_tests_properties(run_pmuc PROPERTIES PASS_REGULAR_EXPRESSION "--collada") +set_tests_properties(run_pmuc PROPERTIES PASS_REGULAR_EXPRESSION "--stl") add_test(NAME pmuc_collada COMMAND ${PROJECT_NAME} --collada ${CMAKE_CURRENT_SOURCE_DIR}/data/plm-sample_11072013.rvm) add_test(NAME pmuc_x3d COMMAND ${PROJECT_NAME} --x3d ${CMAKE_CURRENT_SOURCE_DIR}/data/plm-sample_11072013.rvm) add_test(NAME pmuc_x3db COMMAND ${PROJECT_NAME} --x3db ${CMAKE_CURRENT_SOURCE_DIR}/data/plm-sample_11072013.rvm) add_test(NAME pmuc_ifc COMMAND ${PROJECT_NAME} --ifc ${CMAKE_CURRENT_SOURCE_DIR}/data/plm-sample_11072013.rvm) add_test(NAME pmuc_ifc_primitives COMMAND ${PROJECT_NAME} --ifc --primitives ${CMAKE_CURRENT_SOURCE_DIR}/data/plm-sample_11072013.rvm) - +add_test(NAME pmuc_stl COMMAND ${PROJECT_NAME} --stl ${CMAKE_CURRENT_SOURCE_DIR}/data/plm-sample_11072013.rvm) set_tests_properties(pmuc_collada pmuc_x3d pmuc_x3db pmuc_ifc pmuc_ifc_primitives PROPERTIES PASS_REGULAR_EXPRESSION "315 group") set_tests_properties(pmuc_collada pmuc_x3d pmuc_x3db pmuc_ifc pmuc_ifc_primitives PROPERTIES PASS_REGULAR_EXPRESSION "118 pyramid") @@ -71,4 +78,5 @@ set_tests_properties(pmuc_collada pmuc_x3d pmuc_x3db pmuc_ifc pmuc_ifc_primitive set_tests_properties(pmuc_collada pmuc_x3d pmuc_x3db pmuc_ifc pmuc_ifc_primitives PROPERTIES PASS_REGULAR_EXPRESSION " 139 cylinder") set_tests_properties(pmuc_collada pmuc_x3d pmuc_x3db pmuc_ifc pmuc_ifc_primitives PROPERTIES PASS_REGULAR_EXPRESSION " 0 sphere") set_tests_properties(pmuc_collada pmuc_x3d pmuc_x3db pmuc_ifc pmuc_ifc_primitives PROPERTIES PASS_REGULAR_EXPRESSION " 12 line") -set_tests_properties(pmuc_collada pmuc_x3d pmuc_x3db pmuc_ifc pmuc_ifc_primitives PROPERTIES PASS_REGULAR_EXPRESSION " 80 facet group") \ No newline at end of file +set_tests_properties(pmuc_collada pmuc_x3d pmuc_x3db pmuc_ifc pmuc_ifc_primitives PROPERTIES PASS_REGULAR_EXPRESSION " 80 facet group") +set_tests_properties(pmuc_stl PROPERTIES PASS_REGULAR_EXPRESSION "Facets: 189736") \ No newline at end of file diff --git a/INSTALL b/INSTALL index c22f6dd..a946b86 100644 --- a/INSTALL +++ b/INSTALL @@ -1,7 +1,7 @@ Building and installing the Plant Mock-Up Converter =================================================== -This project uses the cross-platform CMake build system to generate its build environment, in version 2.8 or newer. +This project uses the cross-platform CMake build system to generate its build environment, in version 3.1 or newer. http://www.cmake.org diff --git a/README.md b/README.md index 9b53e10..1511734 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Plant Mock-Up Converter [![Build Status](https://api.travis-ci.org/Supporting/pmuc.svg?branch=master)](https://travis-ci.org/Supporting/pmuc) -[![Build status](https://ci.appveyor.com/api/projects/status/pt0xdf8srhyui2gc/branch/master?svg=true)](https://ci.appveyor.com/project/Supporting/pmuc/branch/master) +[![Build status](https://ci.appveyor.com/api/projects/status/sbuxou2rv8t2k662/branch/master?svg=true)](https://ci.appveyor.com/project/Supporting/pmuc/branch/master) -Copyright © EDF 2013-2016 +Copyright © EDF 2013-2019 ## About @@ -12,7 +12,8 @@ This project contains a reading library for the RVM file format and a command li - [X3D](http://www.web3d.org/x3d/what-x3d) in XML and binary (FI) encoding, - [COLLADA](https://www.khronos.org/collada/) files, - DSL3D language commands, and -- [IFC 2x3](http://www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/). +- [IFC 2x3](http://www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/) +- [STL]() ## License (LGPL) @@ -28,10 +29,10 @@ See the LICENSE.txt file for details. ### Prerequisites -On Unix and Linux, a g++ compiler >= 4.8 is required. -On Windows, you need at least Visual Studio 2012. Other platforms / compilers / IDEs have not been tested but are likely to work as well (please file an issue if not). +PMUC uses the C++ 17 library feature `std::variant`, hence it requires a g++ compiler >= 7, MSVC 19.10 (Visual Studio 2017), or Clang 10.0 is required. +Other platforms / compilers / IDEs have not been tested but are likely to work as well (please file an issue if not). -Building requires a [cmake](http://www.cmake.org/) version >= 2.8. +Building requires a [cmake](http://www.cmake.org/) version >= 3.12. ### Dependencies @@ -40,7 +41,7 @@ Most dependencies are included in git submodules, namely [eigen](http://eigen.tu git submodule init git submodule update -Soley [boost](http://www.boost.org/) needs to be provided externally. On Linux it is sufficient to install the boost development package, e.g.: +Soley [boost](http://www.boost.org/) (on windows 1.69 is required, otherwise 1.65.1) needs to be provided externally. On Linux it is sufficient to install the boost development package, e.g.: sudo apt-get install libboost-all-dev diff --git a/appveyor.yml b/appveyor.yml index 932be94..3f613e5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ -version: '1.0.{build}' +version: "1.2.{build}" image: -- Visual Studio 2017 + - Visual Studio 2017 environment: BOOST_ROOT: C:\Libraries\boost_1_69_0 @@ -25,4 +25,3 @@ test_script: artifacts: - path: build\bin\$(CMAKE_BUILD_TYPE) - diff --git a/external/xiot b/external/xiot index 9cae970..fb8d6bb 160000 --- a/external/xiot +++ b/external/xiot @@ -1 +1 @@ -Subproject commit 9cae970bd8c20f9f5377ab095800c3cf101beffd +Subproject commit fb8d6bbec5e764751903be30b5520a1521ee1a91 diff --git a/src/main.cpp b/src/main.cpp index e4ea4b8..6500732 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ /* * Plant Mock-Up Converter * - * Copyright (c) 2016, EDF. All rights reserved. + * Copyright (c) 2016-19, EDF. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,21 +21,21 @@ #include -#include #include +#include -#include "optionparser.h" #include "api/rvmparser.h" -#include "converters/dummyreader.h" -#include "converters/dslconverter.h" #include "api/rvmprimitive.h" -#include "converters/ifcconverter.h" -#include "converters/x3dconverter.h" #include "converters/colladaconverter.h" +#include "converters/dslconverter.h" +#include "converters/dummyreader.h" +#include "converters/ifcconverter.h" #include "converters/stlconverter.h" +#include "converters/x3dconverter.h" +#include "optionparser.h" #ifdef _MSC_VER -#define _USE_MATH_DEFINES // For PI under VC++ +#define _USE_MATH_DEFINES // For PI under VC++ #endif #include @@ -48,451 +48,479 @@ using namespace std; -enum optionIndex { UNKNOWN, HELP, TEST, X3D, - X3DB, COLLADA, IFC4, IFC2X3, DSL, STL, DUMMY, - SKIPATT, SPLIT, AGGREGATE, PRIMITIVES, SIDESIZE, - MINSIDES, OBJECT, COLOR, SCALE }; - -const option::Descriptor usage[] = { - { UNKNOWN, 0, "", "", option::Arg::None, "\nusage: pmuc [options] ...\n\nChoose at least one format and one file to convert.\nOptions:" }, - { HELP, 0, "h", "help", option::Arg::None, " --help, -h \tPrint usage and exit." }, - { X3D, 0, "", "x3d", option::Arg::None, " --x3d \tConvert to X3D XML format." }, - { X3DB, 0, "", "x3db", option::Arg::None, " --x3db \tConvert to X3D binary format." }, - { COLLADA, 0, "", "collada", option::Arg::None, " --collada\tConvert to COLLADA format." }, - { IFC2X3, 0, "", "ifc", option::Arg::None, " --ifc\tConvert to IFC2x3." }, - { IFC4, 0, "", "ifc4", option::Arg::None, " --ifc4\tConvert to IFC4." }, - { STL, 0, "", "stl", option::Arg::None, " --stl\tConvert to STL." }, - { DSL, 0, "", "dsl", option::Arg::None, " --dsl \tConvert to DSL language." }, - { DUMMY, 0, "", "dummy", option::Arg::None, " --dummy\tPrint out the file structure." }, - { SKIPATT, 0, "", "skipattributes",option::Arg::None, " --skipattributes \tIgnore attribute file." }, - { SPLIT, 0, "", "split", option::Arg::None, " --split \tIf possible split in sub files (Only X3D)." }, - { AGGREGATE, 0, "", "aggregate", option::Arg::Optional, " --aggregate= \tCombine input files in one export file." }, - { PRIMITIVES, 0, "", "primitives", option::Arg::None, " --primitives \tIf possible use native primitives." }, - { SIDESIZE , 0, "", "maxsidesize", option::Arg::Optional, " --maxsidesize= \tUsed for tesselation. Default 1000." }, - { MINSIDES , 0, "", "minsides", option::Arg::Optional, " --minsides= \tUsed for tesselation. Default 8." }, - { TEST, 0, "t", "test", option::Arg::None, " --test, -t \tOutputs primitive samples for testing purposes." }, - { OBJECT, 0, "", "object", option::Arg::Optional, " --object= \tExtract only the named object." }, - { COLOR, 0, "", "color", option::Arg::Optional, " --color= \tForce a PDMS color on all objects." }, - { SCALE, 0, "", "scale", option::Arg::Optional, " --scale= \tScale the model." }, - {0,0,0,0,0,0} +enum optionIndex { + UNKNOWN, + HELP, + TEST, + X3D, + X3DB, + COLLADA, + IFC4, + IFC2X3, + DSL, + STL, + DUMMY, + SKIPATT, + SPLIT, + AGGREGATE, + PRIMITIVES, + SIDESIZE, + MINSIDES, + OBJECT, + COLOR, + SCALE }; - -const string formatnames[] = { - "", "", "", - "X3D", "X3DB", - "COLLADA", - "IFC4", "IFC2x3", - "DSL", "STL", "DUMMY" +const option::Descriptor usage[] = { + {UNKNOWN, 0, "", "", option::Arg::None, + "\nusage: pmuc [options] ...\n\nChoose at least one format and one file to convert.\nOptions:"}, + {HELP, 0, "h", "help", option::Arg::None, " --help, -h \tPrint usage and exit."}, + {X3D, 0, "", "x3d", option::Arg::None, " --x3d \tConvert to X3D XML format."}, + {X3DB, 0, "", "x3db", option::Arg::None, " --x3db \tConvert to X3D binary format."}, + {COLLADA, 0, "", "collada", option::Arg::None, " --collada\tConvert to COLLADA format."}, + {IFC2X3, 0, "", "ifc", option::Arg::None, " --ifc\tConvert to IFC2x3."}, + {IFC4, 0, "", "ifc4", option::Arg::None, " --ifc4\tConvert to IFC4."}, + {STL, 0, "", "stl", option::Arg::None, " --stl\tConvert to STL."}, + {DSL, 0, "", "dsl", option::Arg::None, " --dsl \tConvert to DSL language."}, + {DUMMY, 0, "", "dummy", option::Arg::None, " --dummy\tPrint out the file structure."}, + {SKIPATT, 0, "", "skipattributes", option::Arg::None, " --skipattributes \tIgnore attribute file."}, + {SPLIT, 0, "", "split", option::Arg::None, " --split \tIf possible split in sub files (Only X3D)."}, + {AGGREGATE, 0, "", "aggregate", option::Arg::Optional, + " --aggregate= \tCombine input files in one export file."}, + {PRIMITIVES, 0, "", "primitives", option::Arg::None, " --primitives \tIf possible use native primitives."}, + {SIDESIZE, 0, "", "maxsidesize", option::Arg::Optional, + " --maxsidesize= \tUsed for tesselation. Default 1000."}, + {MINSIDES, 0, "", "minsides", option::Arg::Optional, " --minsides= \tUsed for tesselation. Default 8."}, + {TEST, 0, "t", "test", option::Arg::None, " --test, -t \tOutputs primitive samples for testing purposes."}, + {OBJECT, 0, "", "object", option::Arg::Optional, " --object= \tExtract only the named object."}, + {COLOR, 0, "", "color", option::Arg::Optional, " --color= \tForce a PDMS color on all objects."}, + {SCALE, 0, "", "scale", option::Arg::Optional, " --scale= \tScale the model."}, + {0, 0, 0, 0, 0, 0}}; + +const string formatnames[] = {"", "", "", "X3D", "X3DB", "COLLADA", "IFC4", "IFC2x3", "DSL", "STL", "DUMMY"}; + +enum primitives { + BOX, + SNOUT, + CYLINDER, + SPHERE, + CIRCULARTORUS, + RECTANGULARTORUS, + PYRAMID, + LINE, + ELLIPTICALDISH, + SPHERICALDISH }; - -enum primitives { BOX, SNOUT, CYLINDER, SPHERE, CIRCULARTORUS, RECTANGULARTORUS, PYRAMID, LINE, ELLIPTICALDISH, SPHERICALDISH }; -const string primitiveNames[] = { "box", "snout", "cylinder", "sphere", "circulartorus", "rectangulartorus", "pyramid", "line", "ellipticaldish", "sphericaldish" }; - -void printStats(time_t duration, RVMParser &parser) { - cout << "Statistics:" << endl; - cout << " " << parser.nbGroups() << " group(s)" << endl; - cout << " " << parser.nbPyramids() << " pyramid(s)" << endl; - cout << " " << parser.nbBoxes() << " box(es)" << endl; - cout << " " << parser.nbRectangularToruses() << " rectangular torus(es)" << endl; - cout << " " << parser.nbCircularToruses() << " circular torus(es)" << endl; - cout << " " << parser.nbEllipticalDishes() << " elliptical dish(es)" << endl; - cout << " " << parser.nbSphericalDishes() << " spherical dish(es)" << endl; - cout << " " << parser.nbSnouts() << " snout(s)" << endl; - cout << " " << parser.nbCylinders() << " cylinder(s)" << endl; - cout << " " << parser.nbSpheres() << " sphere(s)" << endl; - cout << " " << parser.nbLines() << " line(s)" << endl; - cout << " " << parser.nbFacetGroups() << " facet group(s)" << endl; - cout << " " << parser.nbAttributes() << " attribute(s)" << endl; - - cout << "Conversion done in " << (duration) << " second" << (duration > 1 ? "s" : "") << "." << endl; +const string primitiveNames[] = { + "box", "snout", "cylinder", "sphere", "circulartorus", "rectangulartorus", + "pyramid", "line", "ellipticaldish", "sphericaldish"}; + +void printStats(time_t duration, RVMParser& parser) { + cout << "Statistics:" << endl; + cout << " " << parser.nbGroups() << " group(s)" << endl; + cout << " " << parser.nbPyramids() << " pyramid(s)" << endl; + cout << " " << parser.nbBoxes() << " box(es)" << endl; + cout << " " << parser.nbRectangularToruses() << " rectangular torus(es)" << endl; + cout << " " << parser.nbCircularToruses() << " circular torus(es)" << endl; + cout << " " << parser.nbEllipticalDishes() << " elliptical dish(es)" << endl; + cout << " " << parser.nbSphericalDishes() << " spherical dish(es)" << endl; + cout << " " << parser.nbSnouts() << " snout(s)" << endl; + cout << " " << parser.nbCylinders() << " cylinder(s)" << endl; + cout << " " << parser.nbSpheres() << " sphere(s)" << endl; + cout << " " << parser.nbLines() << " line(s)" << endl; + cout << " " << parser.nbFacetGroups() << " facet group(s)" << endl; + cout << " " << parser.nbAttributes() << " attribute(s)" << endl; + + cout << "Conversion done in " << (duration) << " second" << (duration > 1 ? "s" : "") << "." << endl; } -int main(int argc, char** argv) -{ - cout << "Plant Mock-Up Converter 1.1.1\nCopyright (C) EDF 2013-19" << endl; +int main(int argc, char** argv) { + cout << "Plant Mock-Up Converter 1.2.0\nCopyright (C) EDF 2013-19" << endl; - argc -= (argc > 0); argv += (argc > 0); - option::Stats stats(usage, argc, argv); - option::Option* options = new option::Option[stats.options_max]; - option::Option* buffer = new option::Option[stats.buffer_max]; - option::Parser parse(usage, argc, argv, options, buffer); + argc -= (argc > 0); + argv += (argc > 0); + option::Stats stats(usage, argc, argv); + option::Option* options = new option::Option[stats.options_max]; + option::Option* buffer = new option::Option[stats.buffer_max]; + option::Parser parse(usage, argc, argv, options, buffer); - if (parse.error()) { - cout << "error." < 0) { + minSides = atoi(options[MINSIDES].arg); + if (minSides < 5) { + cerr << "\n--minsides option should be > 4.\n"; + option::printUsage(std::cerr, usage); + return 1; } - - if ((options[X3D] || options[X3DB] || options[COLLADA] || options[DSL] || options[DUMMY] || options[IFC4]|| options[IFC2X3] || options[STL]) == 0) { - cerr << "\nNo format specified.\n"; - option::printUsage(std::cerr, usage); - return 1; + } + + float maxSideSize = 25.; + if (options[SIDESIZE].count() > 0) { + maxSideSize = (float)atof(options[SIDESIZE].arg); + if (maxSideSize <= 0) { + cout << "\n--maxsidesize option should be > 0.\n"; + option::printUsage(std::cout, usage); + return 1; } - - if (parse.nonOptionsCount() == 0 && options[TEST].count() == 0) { - cerr << "\nNo file specified.\n"; - option::printUsage(std::cerr, usage); - return 1; + } + + int forcedColor = -1; + if (options[COLOR].count()) { + forcedColor = atoi(options[COLOR].arg); + if (forcedColor < 0 || forcedColor > 255) { + cout << "\n--color option should be >= 0 and <= 255.\n"; + option::printUsage(std::cout, usage); + return 1; } - - int minSides = 16; - if (options[MINSIDES].count() > 0) { - minSides = atoi(options[MINSIDES].arg); - if (minSides < 5) { - cerr << "\n--minsides option should be > 4.\n"; - option::printUsage(std::cerr, usage); - return 1; - } + } + + float scale = 1.; + if (options[SCALE].count()) { + scale = (float)atof(options[SCALE].arg); + } + + string objectName = options[OBJECT].count() ? options[OBJECT].arg : ""; + if (!objectName.empty()) { + size_t p; + while ((p = objectName.find_first_of(' ')) != string::npos) + objectName[p] = '_'; + while (objectName[0] == '-') + objectName[0] = '_'; + while ((p = objectName.find_first_of('/')) != string::npos) { + objectName[p] = '_'; } - - float maxSideSize = 25.; - if (options[SIDESIZE].count() > 0) { - maxSideSize = (float)atof(options[SIDESIZE].arg); - if (maxSideSize <= 0) { - cout << "\n--maxsidesize option should be > 0.\n"; - option::printUsage(std::cout, usage); - return 1; + } + + // Testing: outputs primitives in individual files. + if (options[TEST].count() > 0) { + cout << "\nWriting primitive example files..." << endl; + for (int i = 0; i < 10; i++) { + string filename = primitiveNames[i]; + cout << filename << "." << endl; + for (int format = TEST + 1; format <= DUMMY; format++) { + if (options[format].count() > 0) { + RVMReader* reader; + switch (format) { + case X3D: + case X3DB: { + string name = filename + ".x3d" + (format == X3D ? "" : "b"); + reader = new X3DConverter(name, format == X3DB); + } break; + + case COLLADA: { + string name = filename + ".dae"; + reader = new COLLADAConverter(name); + } break; + + case IFC4: { + string name = filename + ".ifc"; + reader = new IFCConverter(name, "IFC4"); + } break; + + case IFC2X3: { + string name = filename + ".ifc"; + reader = new IFCConverter(name, "IFC2X3"); + } break; + + case DSL: { + string name = filename + ".dsl3d"; + reader = new DSLConverter(name); + } break; + case STL: { + string name = filename + ".stl"; + cout << name << std::endl; + reader = new STLConverter(name); + } break; + } + if (maxSideSize) { + reader->setMaxSideSize(maxSideSize); + } + if (minSides) { + reader->setMinSides(minSides); + } + reader->setUsePrimitives(options[PRIMITIVES].count() > 0); + reader->setSplit(options[SPLIT].count() > 0); + vector translation; + for (int j = 0; j < 3; j++) + translation.push_back(0); + std::array matrix; + for (int j = 0; j < 12; j++) + matrix[j] = 0.0f; + matrix[0] = matrix[4] = matrix[8] = 1.0f; + + reader->startDocument(); + reader->startHeader("Plant Mock-Up Converter", "Primitive example file", "", "", ""); + reader->endHeader(); + reader->startModel("Primitive examples", primitiveNames[i]); + reader->startGroup(primitiveNames[i], translation, forcedColor != -1 ? forcedColor : 2); + switch (i) { // BOX, SNOUT, CYLINDER, SPHERE, CIRCULARTORUS, RECTANGULARTORUS, PYRAMID, LINE, ELLIPTICALDISH, + // SPHERICALDISH + case BOX: { + Primitives::Box box; + box.len[0] = 1.0; + box.len[1] = 1.0; + box.len[2] = 1.0; + reader->createBox(matrix, box); + } break; + case SNOUT: { + Primitives::Snout snout; + snout.data[0] = 2.0f; // bottom radius + snout.data[1] = 2.0f; // top radius + snout.data[2] = 5.0f; // height + snout.data[3] = 0.0f; // xoffset + snout.data[4] = 0.0f; // yoffset + snout.data[5] = 0.0f; // xbottomNormalOffset + snout.data[6] = 0.4f; // ybottomNormalOffset + snout.data[7] = 0.0f; // xtopNormalOffset + snout.data[8] = -0.4f; // ytopNormalOffset + + reader->createSnout(matrix, snout); + } break; + case CYLINDER: { + Primitives::Cylinder cylinder; + cylinder.data[0] = 1.0f; + cylinder.data[1] = 2.0f; + reader->createCylinder(matrix, cylinder); + } break; + case SPHERE: { + Primitives::Sphere sphere; + sphere.diameter = 2.0; + reader->createSphere(matrix, sphere); + } break; + case CIRCULARTORUS: { + Primitives::CircularTorus torus; + torus.data[0] = 4; + torus.data[1] = 2; + torus.data[2] = (float)M_PI; + reader->createCircularTorus(matrix, torus); + } break; + case RECTANGULARTORUS: { + Primitives::RectangularTorus torus; + torus.data[0] = 7.5; // inside + torus.data[1] = 8.0; // outside + torus.data[2] = 2.0; // height + torus.data[3] = (float)M_PI * 1.5f; + reader->createRectangularTorus(matrix, torus); + } break; + case PYRAMID: { + Primitives::Pyramid pyramid; + pyramid.data[0] = 2; // xbottom + pyramid.data[1] = 4; // ybottom + pyramid.data[2] = 4; // xtop + pyramid.data[3] = 4; // ytop + pyramid.data[4] = 0; // xoffset + pyramid.data[5] = 0; // yoffset + pyramid.data[6] = 4; // height + + reader->createPyramid(matrix, pyramid); + } break; + case LINE: { + reader->createLine(matrix, 1, 2); + } break; + case ELLIPTICALDISH: { + Primitives::EllipticalDish dish; + dish.data[0] = 4; + dish.data[1] = 2; + reader->createEllipticalDish(matrix, dish); + } break; + case SPHERICALDISH: { + Primitives::SphericalDish dish; + dish.data[0] = 4; + dish.data[1] = 1; + reader->createSphericalDish(matrix, dish); + } break; + } + reader->endGroup(); + reader->endModel(); + reader->endDocument(); + delete reader; } + } } - - int forcedColor = -1; - if (options[COLOR].count()) { - forcedColor = atoi(options[COLOR].arg); - if (forcedColor < 0 || forcedColor > 255) { - cout << "\n--color option should be >= 0 and <= 255.\n"; - option::printUsage(std::cout, usage); - return 1; + cout << "done." << endl; + } + + // File conversions. + if (options[AGGREGATE].count() > 0) { + for (int format = TEST + 1; format <= DUMMY; format++) { + if (options[format].count() > 0) { + time_t start = time(0); + RVMReader* reader; + string name = options[AGGREGATE].arg; + switch (format) { + case DUMMY: { + reader = new DummyReader; + } break; + + case X3D: + case X3DB: { + string x3dname = name + ".x3d" + (format == X3D ? "" : "b"); + reader = new X3DConverter(x3dname, format == X3DB); + } break; + + case COLLADA: { + string colladaname = name + ".dae"; + reader = new COLLADAConverter(colladaname); + } break; + + case DSL: { + string dslname = name + ".dsl3d"; + reader = new DSLConverter(dslname); + } break; + + case IFC2X3: { + string ifcname = name + ".ifc"; + reader = new IFCConverter(ifcname, "IFC4"); + } break; + case IFC4: { + string ifcname = name + ".ifc"; + reader = new IFCConverter(ifcname, "IFC2X3"); + } break; } - } - - float scale = 1.; - if (options[SCALE].count()) { - scale = (float)atof(options[SCALE].arg); - } - - string objectName = options[OBJECT].count() ? options[OBJECT].arg : ""; - if (!objectName.empty()) { - size_t p; - while ((p = objectName.find_first_of(' ')) != string::npos) - objectName[p] = '_'; - while (objectName[0] == '-') - objectName[0] = '_'; - while ((p = objectName.find_first_of('/')) != string::npos) { - objectName[p] = '_'; + if (maxSideSize) { + reader->setMaxSideSize(maxSideSize); } - } - - // Testing: outputs primitives in individual files. - if (options[TEST].count() > 0) { - cout << "\nWriting primitive example files..." << endl; - for (int i = 0; i < 10; i++) { - string filename = primitiveNames[i]; - cout << filename << "." << endl; - for (int format = TEST + 1; format <= DUMMY; format++) { - if (options[format].count() > 0) { - RVMReader* reader; - switch (format) { - case X3D: - case X3DB: { - string name = filename + ".x3d" + (format == X3D ? "" : "b"); - reader = new X3DConverter(name, format == X3DB); - } break; - -#ifdef OPENCOLLADASW_FOUND - case COLLADA: { - string name = filename + ".dae"; - reader = new COLLADAConverter(name); - } break; -#endif // OPENCOLLADASW_FOUND - - case IFC4: { - string name = filename + ".ifc"; - reader = new IFCConverter(name, "IFC4"); - } break; - - case IFC2X3: { - string name = filename + ".ifc"; - reader = new IFCConverter(name, "IFC2X3"); - } break; - - - case DSL: { - string name = filename + ".dsl3d"; - reader = new DSLConverter(name); - } break; - case STL: { - string name = filename + ".stl"; - cout << name << std::endl; - reader = new STLConverter(name); - } break; - } - if (maxSideSize) { - reader->setMaxSideSize(maxSideSize); - } - if (minSides) { - reader->setMinSides(minSides); - } - reader->setUsePrimitives(options[PRIMITIVES].count() > 0); - reader->setSplit(options[SPLIT].count() > 0); - vector translation; - for (int j = 0; j < 3; j++) translation.push_back(0); - std::array matrix; - for (int j = 0; j < 12; j++) matrix[j] = 0.0f; - matrix[0] = matrix[4] = matrix[8] = 1.0f; - - reader->startDocument(); - reader->startHeader("Plant Mock-Up Converter", "Primitive example file", "", "", ""); - reader->endHeader(); - reader->startModel("Primitive examples", primitiveNames[i]); - reader->startGroup(primitiveNames[i], translation, forcedColor != -1 ? forcedColor : 2); - switch (i) { // BOX, SNOUT, CYLINDER, SPHERE, CIRCULARTORUS, RECTANGULARTORUS, PYRAMID, LINE, ELLIPTICALDISH, SPHERICALDISH - case BOX: { - Primitives::Box box; - box.len[0] = 1.0; - box.len[1] = 1.0; - box.len[2] = 1.0; - reader->createBox(matrix, box); - } break; - case SNOUT: { - Primitives::Snout snout; - snout.data[0] = 2.0f; // bottom radius - snout.data[1] = 2.0f; // top radius - snout.data[2] = 5.0f; // height - snout.data[3] = 0.0f; // xoffset - snout.data[4] = 0.0f; // yoffset - snout.data[5] = 0.0f; // xbottomNormalOffset - snout.data[6] = 0.4f; // ybottomNormalOffset - snout.data[7] = 0.0f; // xtopNormalOffset - snout.data[8] = -0.4f; // ytopNormalOffset - - reader->createSnout(matrix, snout); - } break; - case CYLINDER: { - Primitives::Cylinder cylinder; - cylinder.data[0] = 1.0f; - cylinder.data[1] = 2.0f; - reader->createCylinder(matrix, cylinder); - } break; - case SPHERE: { - Primitives::Sphere sphere; - sphere.diameter = 2.0; - reader->createSphere(matrix, sphere); - } break; - case CIRCULARTORUS: { - Primitives::CircularTorus torus; - torus.data[0] = 4; - torus.data[1] = 2; - torus.data[2] = (float)M_PI; - reader->createCircularTorus(matrix, torus); - } break; - case RECTANGULARTORUS: { - Primitives::RectangularTorus torus; - torus.data[0] = 7.5; // inside - torus.data[1] = 8.0; // outside - torus.data[2] = 2.0; // height - torus.data[3] = (float)M_PI*1.5f; - reader->createRectangularTorus(matrix, torus); - } break; - case PYRAMID: { - Primitives::Pyramid pyramid; - pyramid.data[0] = 2; // xbottom - pyramid.data[1] = 4; // ybottom - pyramid.data[2] = 4; // xtop - pyramid.data[3] = 4; // ytop - pyramid.data[4] = 0; // xoffset - pyramid.data[5] = 0; // yoffset - pyramid.data[6] = 4; // height - - reader->createPyramid(matrix, pyramid); - } break; - case LINE: { - reader->createLine(matrix, 1, 2); - } break; - case ELLIPTICALDISH: { - Primitives::EllipticalDish dish; - dish.data[0] = 4; - dish.data[1] = 2; - reader->createEllipticalDish(matrix, dish); - } break; - case SPHERICALDISH: { - Primitives::SphericalDish dish; - dish.data[0] = 4; - dish.data[1] = 1; - reader->createSphericalDish(matrix, dish); - } break; - } - reader->endGroup(); - reader->endModel(); - reader->endDocument(); - delete reader; - } - } + if (minSides) { + reader->setMinSides(minSides); } - cout << "done." << endl; - } - - // File conversions. - if (options[AGGREGATE].count() > 0) { - for (int format = TEST + 1; format <= DUMMY; format++) { - if (options[format].count() > 0) { - time_t start = time(0); - RVMReader* reader; - string name = options[AGGREGATE].arg; - switch (format) { - case DUMMY: { - reader = new DummyReader; - } break; - - case X3D: - case X3DB: { - string x3dname = name + ".x3d" + (format == X3D ? "" : "b"); - reader = new X3DConverter(x3dname, format == X3DB); - } break; - - case COLLADA: { - string colladaname = name + ".dae"; - reader = new COLLADAConverter(colladaname); - } break; - - case DSL: { - string dslname = name + ".dsl3d"; - reader = new DSLConverter(dslname); - } break; - - case IFC2X3: { - string ifcname = name + ".ifc"; - reader = new IFCConverter(ifcname, "IFC4"); - } break; - case IFC4: { - string ifcname = name + ".ifc"; - reader = new IFCConverter(ifcname, "IFC2X3"); - } break; - } - if (maxSideSize) { - reader->setMaxSideSize(maxSideSize); - } - if (minSides) { - reader->setMinSides(minSides); - } - reader->setUsePrimitives(options[PRIMITIVES].count() > 0); - reader->setSplit(options[SPLIT].count() > 0); - cout << "\nConverting files to " << formatnames[format] << "...\n"; - RVMParser parser(*reader); - if (options[OBJECT].count() > 0) { - parser.setObjectName(options[OBJECT].arg); - } - if (forcedColor != -1) { - parser.setForcedColor(forcedColor); - } - parser.setScale(scale); - - vector files; - for (int file = 0; file < parse.nonOptionsCount(); file++) { - string filename = parse.nonOption(file); - files.push_back(filename); - } - bool res = parser.readFiles(files, name, options[SKIPATT].count() > 0); - delete reader; - if (!res) { - cout << "Conversion failed:" << endl; - cout << " " << parser.lastError() << endl; - return 1; - } else { - printStats(time(0) - start, parser); - } - } + reader->setUsePrimitives(options[PRIMITIVES].count() > 0); + reader->setSplit(options[SPLIT].count() > 0); + cout << "\nConverting files to " << formatnames[format] << "...\n"; + RVMParser parser(*reader); + if (options[OBJECT].count() > 0) { + parser.setObjectName(options[OBJECT].arg); } - } else { + if (forcedColor != -1) { + parser.setForcedColor(forcedColor); + } + parser.setScale(scale); + + vector files; for (int file = 0; file < parse.nonOptionsCount(); file++) { - string filename = parse.nonOption(file); - for (int format = TEST + 1; format <= DUMMY; format++) { - if (options[format].count() > 0) { - time_t start = time(0); - RVMReader* reader; - switch (format) { - case DUMMY: { - reader = new DummyReader; - } break; - - case X3D: - case X3DB: { - string name = !objectName.empty() ? objectName : filename; - if (options[SPLIT].count() > 0) name += "_origin"; - name = name.substr(0, name.rfind(".")) + ".x3d" + (format == X3D ? "" : "b"); - name = name.substr(name.rfind(PATHSEP) + 1); - reader = new X3DConverter(name, format == X3DB); - } break; - - case COLLADA: { - string name = !objectName.empty() ? objectName : filename; - name = name.substr(0, name.rfind(".")) + ".dae"; - name = name.substr(name.rfind(PATHSEP) + 1); - reader = new COLLADAConverter(name); - } break; - - case IFC4: { - string name = !objectName.empty() ? objectName : filename; - name = name.substr(0, name.rfind(".")) + ".ifc"; - name = name.substr(name.rfind(PATHSEP) + 1); - reader = new IFCConverter(name, "IFC4"); - } break; - case IFC2X3: { - string name = !objectName.empty() ? objectName : filename; - name = name.substr(0, name.rfind(".")) + ".ifc"; - name = name.substr(name.rfind(PATHSEP) + 1); - reader = new IFCConverter(name, "IFC2X3"); - } break; - - case DSL: { - string name = !objectName.empty() ? objectName : filename; - name = name.substr(0, name.rfind(".")) + ".dsl3d"; - name = name.substr(name.rfind(PATHSEP) + 1); - reader = new DSLConverter(name); - } break; - - case STL: { - string name = !objectName.empty() ? objectName : filename; - name = name.substr(0, name.rfind(".")) + ".stl"; - name = name.substr(name.rfind(PATHSEP) + 1); - reader = new STLConverter(name); - } break; - } - if (maxSideSize) { - reader->setMaxSideSize(maxSideSize); - } - if (minSides) { - reader->setMinSides(minSides); - } - reader->setUsePrimitives(options[PRIMITIVES].count() > 0); - reader->setSplit(options[SPLIT].count() > 0); - cout << "\nConverting file " << filename << " to " << formatnames[format] << "...\n"; - RVMParser parser(*reader); - if (options[OBJECT].count() > 0) { - parser.setObjectName(options[OBJECT].arg); - } - if (forcedColor != -1) { - parser.setForcedColor(forcedColor); - } - parser.setScale(scale); - - bool res = parser.readFile(filename, options[SKIPATT].count() > 0); - delete reader; - if (!res) { - cout << "Conversion failed:" << endl; - cout << " " << parser.lastError() << endl; - return 1; - } else { - printStats(time(0) - start, parser); - } - } - } + string filename = parse.nonOption(file); + files.push_back(filename); } + bool res = parser.readFiles(files, name, options[SKIPATT].count() > 0); + delete reader; + if (!res) { + cout << "Conversion failed:" << endl; + cout << " " << parser.lastError() << endl; + return 1; + } else { + printStats(time(0) - start, parser); + } + } } + } else { + for (int file = 0; file < parse.nonOptionsCount(); file++) { + string filename = parse.nonOption(file); + for (int format = TEST + 1; format <= DUMMY; format++) { + if (options[format].count() > 0) { + time_t start = time(0); + RVMReader* reader; + switch (format) { + case DUMMY: { + reader = new DummyReader; + } break; + + case X3D: + case X3DB: { + string name = !objectName.empty() ? objectName : filename; + if (options[SPLIT].count() > 0) + name += "_origin"; + name = name.substr(0, name.rfind(".")) + ".x3d" + (format == X3D ? "" : "b"); + name = name.substr(name.rfind(PATHSEP) + 1); + reader = new X3DConverter(name, format == X3DB); + } break; + + case COLLADA: { + string name = !objectName.empty() ? objectName : filename; + name = name.substr(0, name.rfind(".")) + ".dae"; + name = name.substr(name.rfind(PATHSEP) + 1); + reader = new COLLADAConverter(name); + } break; + + case IFC4: { + string name = !objectName.empty() ? objectName : filename; + name = name.substr(0, name.rfind(".")) + ".ifc"; + name = name.substr(name.rfind(PATHSEP) + 1); + reader = new IFCConverter(name, "IFC4"); + } break; + case IFC2X3: { + string name = !objectName.empty() ? objectName : filename; + name = name.substr(0, name.rfind(".")) + ".ifc"; + name = name.substr(name.rfind(PATHSEP) + 1); + reader = new IFCConverter(name, "IFC2X3"); + } break; + + case DSL: { + string name = !objectName.empty() ? objectName : filename; + name = name.substr(0, name.rfind(".")) + ".dsl3d"; + name = name.substr(name.rfind(PATHSEP) + 1); + reader = new DSLConverter(name); + } break; + + case STL: { + string name = !objectName.empty() ? objectName : filename; + name = name.substr(0, name.rfind(".")) + ".stl"; + name = name.substr(name.rfind(PATHSEP) + 1); + reader = new STLConverter(name); + } break; + } + if (maxSideSize) { + reader->setMaxSideSize(maxSideSize); + } + if (minSides) { + reader->setMinSides(minSides); + } + reader->setUsePrimitives(options[PRIMITIVES].count() > 0); + reader->setSplit(options[SPLIT].count() > 0); + cout << "\nConverting file " << filename << " to " << formatnames[format] << "...\n"; + RVMParser parser(*reader); + if (options[OBJECT].count() > 0) { + parser.setObjectName(options[OBJECT].arg); + } + if (forcedColor != -1) { + parser.setForcedColor(forcedColor); + } + parser.setScale(scale); + + bool res = parser.readFile(filename, options[SKIPATT].count() > 0); + delete reader; + if (!res) { + cout << "Conversion failed:" << endl; + cout << " " << parser.lastError() << endl; + return 1; + } else { + printStats(time(0) - start, parser); + } + } + } + } + } - return 0; + return 0; }