Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libSavitar for openSUSE:Factory checked in at 2021-04-29 22:46:10 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libSavitar (Old) and /work/SRC/openSUSE:Factory/.libSavitar.new.1947 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libSavitar" Thu Apr 29 22:46:10 2021 rev:10 rq:889138 version:4.9.0 Changes: -------- --- /work/SRC/openSUSE:Factory/libSavitar/libSavitar.changes 2020-12-22 13:35:46.122466200 +0100 +++ /work/SRC/openSUSE:Factory/.libSavitar.new.1947/libSavitar.changes 2021-04-29 22:52:49.110049950 +0200 @@ -1,0 +2,7 @@ +Mon Apr 26 20:04:31 UTC 2021 - Stefan Br??ns <[email protected]> + +- update to 4.9.0 + Release notes: + * https://github.com/Ultimaker/Cura/releases/tag/4.9 + +------------------------------------------------------------------- Old: ---- libSavitar-4.8.0.tar.gz New: ---- libSavitar-4.9.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libSavitar.spec ++++++ --- /var/tmp/diff_new_pack.9CGbW7/_old 2021-04-29 22:52:49.626047652 +0200 +++ /var/tmp/diff_new_pack.9CGbW7/_new 2021-04-29 22:52:49.630047634 +0200 @@ -1,7 +1,7 @@ # # spec file for package libSavitar # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,8 +18,8 @@ %define sover 0 Name: libSavitar -%define sversion 4.8 -Version: 4.8.0 +%define sversion 4.9 +Version: 4.9.0 Release: 0 Summary: C++ implementation of 3mf loading with SIP python bindings License: LGPL-3.0-only ++++++ libSavitar-4.8.0.tar.gz -> libSavitar-4.9.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/python/MetadataEntry.sip new/libSavitar-4.9/python/MetadataEntry.sip --- old/libSavitar-4.8/python/MetadataEntry.sip 1970-01-01 01:00:00.000000000 +0100 +++ new/libSavitar-4.9/python/MetadataEntry.sip 2021-03-02 11:33:23.000000000 +0100 @@ -0,0 +1,33 @@ +/* + * This file is part of libSavitar + * + * Copyright (C) 2021 Ultimaker B.V. <[email protected]> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +class MetadataEntry +{ + %TypeHeaderCode + #include "MetadataEntry.h" + %End + +public: + MetadataEntry(std::string value); + MetadataEntry(std::string value, std::string type); + MetadataEntry(std::string value, std::string type, bool preserve); + + std::string value; + std::string type; + bool preserve; +}; \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/python/Scene.sip new/libSavitar-4.9/python/Scene.sip --- old/libSavitar-4.8/python/Scene.sip 2020-10-09 18:43:31.000000000 +0200 +++ new/libSavitar-4.9/python/Scene.sip 2021-03-02 11:33:23.000000000 +0100 @@ -1,7 +1,7 @@ /* * This file is part of libSavitar * - * Copyright (C) 2017 Ultimaker b.v. <[email protected]> + * Copyright (C) 2021 Ultimaker B.V. <[email protected]> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -30,7 +30,11 @@ void addSceneNode(SceneNode* node /Transfer/); - std::map<std::string, std::string> getMetadata(); + std::map<std::string, MetadataEntry> getMetadata(); + void setMetaDataEntry(std::string key, MetadataEntry entry); + void setMetaDataEntry(std::string key, std::string value); + void setMetaDataEntry(std::string key, std::string value, std::string type); + void setMetaDataEntry(std::string key, std::string value, std::string type, bool preserve); std::string getUnit(); void setUnit(std::string unit); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/python/SceneNode.sip new/libSavitar-4.9/python/SceneNode.sip --- old/libSavitar-4.8/python/SceneNode.sip 2020-10-09 18:43:31.000000000 +0200 +++ new/libSavitar-4.9/python/SceneNode.sip 2021-03-02 11:33:23.000000000 +0100 @@ -38,8 +38,11 @@ std::string getId(); void setId(std::string id); - std::map<std::string, std::string> getSettings(); + std::map<std::string, MetadataEntry> getSettings(); + void setSetting(std::string key, MetadataEntry entry); void setSetting(std::string key, std::string value); + void setSetting(std::string key, std::string value, std::string type); + void setSetting(std::string key, std::string value, std::string type, bool preserve); bool addChild(SceneNode* child /Transfer/); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/python/ThreeMFParser.sip new/libSavitar-4.9/python/ThreeMFParser.sip --- old/libSavitar-4.8/python/ThreeMFParser.sip 2020-10-09 18:43:31.000000000 +0200 +++ new/libSavitar-4.9/python/ThreeMFParser.sip 2021-03-02 11:33:23.000000000 +0100 @@ -1,7 +1,7 @@ /* * This file is part of libSavitar * - * Copyright (C) 2017 Ultimaker b.v. <[email protected]> + * Copyright (C) 2021 Ultimaker B.V. <[email protected]> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -19,6 +19,7 @@ %Module(name = Savitar, call_super_init = True) %Include Types.sip +%Include MetadataEntry.sip %Include SceneNode.sip %Include Scene.sip %Include MeshData.sip diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/python/Types.sip new/libSavitar-4.9/python/Types.sip --- old/libSavitar-4.8/python/Types.sip 2020-10-09 18:43:31.000000000 +0200 +++ new/libSavitar-4.9/python/Types.sip 2021-03-02 11:33:23.000000000 +0100 @@ -2,7 +2,7 @@ * This file is part of libSavitar. * * Parts of this code have been copied from libArcus - * Copyright (C) 2016 Ultimaker b.v. <[email protected]> + * Copyright (C) 2021 Ultimaker B.V. <[email protected]> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -94,7 +94,7 @@ for (int i = 0; i < (int)sipCpp->size(); ++i) { SceneNode *cpp = new SceneNode(*sipCpp->at(i)); - PyObject *pobj = sipConvertFromInstance(cpp, sipClass_SceneNode, sipTransferObj); + PyObject *pobj = sipConvertFromType(cpp, sipType_SceneNode, sipTransferObj); // Get the Python wrapper for the Type instance, creating a new // one if necessary, and handle any ownership transfer. @@ -132,7 +132,7 @@ while ((item = PyIter_Next(iterator))) { - if (!sipCanConvertToInstance(item, sipClass_SceneNode, SIP_NOT_NONE)) + if (!sipCanConvertToType(item, sipType_SceneNode, SIP_NOT_NONE)) { PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to SceneNode"); *sipIsErr = 1; @@ -140,14 +140,14 @@ } int state; - SceneNode* p = reinterpret_cast<SceneNode*>(sipConvertToInstance(item, sipClass_SceneNode, 0, SIP_NOT_NONE, &state, sipIsErr)); + SceneNode* p = reinterpret_cast<SceneNode*>(sipConvertToType(item, sipType_SceneNode, 0, SIP_NOT_NONE, &state, sipIsErr)); if (!*sipIsErr) { result_vector->push_back(p); } - sipReleaseInstance(p, sipClass_SceneNode, state); + sipReleaseType(p, sipType_SceneNode, state); Py_DECREF(item); } @@ -226,7 +226,7 @@ for (int i = 0; i < (int)sipCpp->size(); ++i) { TYPE *cpp = new TYPE(sipCpp->at(i)); - PyObject *pobj = sipConvertFromInstance(cpp, sipClass_TYPE, sipTransferObj); + PyObject *pobj = sipConvertFromType(cpp, sipType_TYPE, sipTransferObj); // Get the Python wrapper for the Type instance, creating a new // one if necessary, and handle any ownership transfer. @@ -264,7 +264,7 @@ while ((item = PyIter_Next(iterator))) { - if (!sipCanConvertToInstance(item, sipClass_TYPE, SIP_NOT_NONE)) + if (!sipCanConvertToType(item, sipType_TYPE, SIP_NOT_NONE)) { PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to TYPE"); *sipIsErr = 1; @@ -272,14 +272,14 @@ } int state; - TYPE* p = reinterpret_cast<TYPE*>(sipConvertToInstance(item, sipClass_TYPE, 0, SIP_NOT_NONE, &state, sipIsErr)); + TYPE* p = reinterpret_cast<TYPE*>(sipConvertToType(item, sipType_TYPE, 0, SIP_NOT_NONE, &state, sipIsErr)); if (!*sipIsErr) { result_vector->push_back(*p); } - sipReleaseInstance(p, sipClass_TYPE, state); + sipReleaseType(p, sipType_TYPE, state); Py_DECREF(item); } @@ -410,6 +410,131 @@ sipReleaseType(key, sipType_std_string, key_state); sipReleaseType(value, sipType_std_string, value_state); + } + + *sipCppPtr = std_map; + + return sipGetState(sipTransferObj); + %End +}; + + + + +/** + * Convert a (Python) dict of metadata entries to std::map of MetadataEntry + * objects. + */ +%MappedType std::map<std::string, MetadataEntry> +{ + %TypeHeaderCode + #include <map> + %End + + %ConvertFromTypeCode // From C++ to python + // Create the dictionary. + PyObject *result_dict = PyDict_New(); + + if (!result_dict) + { + return NULL; + } + + // Set the dictionary elements. + std::map<std::string, MetadataEntry>::const_iterator i = sipCpp->begin(); + + while(i != sipCpp->end()) + { + std::string* key = new std::string((*i).first); + MetadataEntry* value = new MetadataEntry((*i).second); + + PyObject *key_object = sipConvertFromNewType(key, sipType_std_string, sipTransferObj); + PyObject *value_object = sipConvertFromInstance(value, sipClass_MetadataEntry, sipTransferObj); + + if (key_object == NULL || value_object == NULL || PyDict_SetItem(result_dict, key_object, value_object) < 0) + { + Py_DECREF(result_dict); + + if (key_object) + { + Py_DECREF(key_object); + } + else + { + delete key; + } + + if (value_object) + { + Py_DECREF(value_object); + } + else + { + delete value; + } + + return nullptr; + } + + Py_DECREF(key_object); + Py_DECREF(value_object); + + ++i; + } + + return result_dict; + %End + + %ConvertToTypeCode // From python to C++ + PyObject *key_object, *value_object; + SIP_SSIZE_T i = 0; + + // Check the type if that is all that is required. + if (sipIsErr == nullptr) + { + if (!PyDict_Check(sipPy)) + { + return 0; + } + + while (PyDict_Next(sipPy, &i, &key_object, &value_object)) + { + if (!sipCanConvertToType(key_object, sipType_std_string, SIP_NOT_NONE)) + { + return 0; + } + + if (!sipCanConvertToInstance(value_object, sipClass_MetadataEntry, SIP_NOT_NONE)) + { + return 0; + } + } + + return 1; + } + + std::map<std::string, MetadataEntry> *std_map = new std::map<std::string, MetadataEntry>; + + while (PyDict_Next(sipPy, &i, &key_object, &value_object)) + { + int key_state, value_state; + + std::string *key = reinterpret_cast<std::string *>(sipConvertToType(key_object, sipType_std_string, sipTransferObj, SIP_NOT_NONE, &key_state, sipIsErr)); + MetadataEntry *value = reinterpret_cast<MetadataEntry*>(sipConvertToInstance(value_object, sipClass_MetadataEntry, 0, SIP_NOT_NONE, &value_state, sipIsErr)); + + if (*sipIsErr) + { + sipReleaseType(key, sipType_std_string, key_state); + sipReleaseInstance(value, sipClass_MetadataEntry, value_state); + + delete std_map; + return 0; + } + + (*std_map).emplace(*key, *value); + + sipReleaseType(key, sipType_std_string, key_state); + sipReleaseType(value, sipType_std_string, value_state); } *sipCppPtr = std_map; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/src/MeshData.cpp new/libSavitar-4.9/src/MeshData.cpp --- old/libSavitar-4.8/src/MeshData.cpp 2020-10-09 18:43:31.000000000 +0200 +++ new/libSavitar-4.9/src/MeshData.cpp 2021-03-02 11:33:23.000000000 +0100 @@ -97,30 +97,52 @@ int v1 = faces.at(i).getV1(); int v2 = faces.at(i).getV2(); int v3 = faces.at(i).getV3(); + float x, y, z; // Add vertices for face 1 - float x = vertices.at(v1).getX(); - float y = vertices.at(v1).getY(); - float z = vertices.at(v1).getZ(); - vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&x), reinterpret_cast<const uint8_t*>(&x) + sizeof(float)); - vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&y), reinterpret_cast<const uint8_t*>(&y) + sizeof(float)); - vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&z), reinterpret_cast<const uint8_t*>(&z) + sizeof(float)); + if (v1 >= 0 && v1 < vertices.size()) + { + x = vertices.at(v1).getX(); + y = vertices.at(v1).getY(); + z = vertices.at(v1).getZ(); + vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&x), reinterpret_cast<const uint8_t*>(&x) + sizeof(float)); + vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&y), reinterpret_cast<const uint8_t*>(&y) + sizeof(float)); + vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&z), reinterpret_cast<const uint8_t*>(&z) + sizeof(float)); + } + else + { + return bytearray(); + } // Add vertices for face 2 - x = vertices.at(v2).getX(); - y = vertices.at(v2).getY(); - z = vertices.at(v2).getZ(); - vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&x), reinterpret_cast<const uint8_t*>(&x) + sizeof(float)); - vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&y), reinterpret_cast<const uint8_t*>(&y) + sizeof(float)); - vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&z), reinterpret_cast<const uint8_t*>(&z) + sizeof(float)); + if (v2 >= 0 && v2 < vertices.size()) + { + x = vertices.at(v2).getX(); + y = vertices.at(v2).getY(); + z = vertices.at(v2).getZ(); + vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&x), reinterpret_cast<const uint8_t*>(&x) + sizeof(float)); + vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&y), reinterpret_cast<const uint8_t*>(&y) + sizeof(float)); + vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&z), reinterpret_cast<const uint8_t*>(&z) + sizeof(float)); + } + else + { + return bytearray(); + } // Add vertices for face 3 - x = vertices.at(v3).getX(); - y = vertices.at(v3).getY(); - z = vertices.at(v3).getZ(); - vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&x), reinterpret_cast<const uint8_t*>(&x) + sizeof(float)); - vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&y), reinterpret_cast<const uint8_t*>(&y) + sizeof(float)); - vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&z), reinterpret_cast<const uint8_t*>(&z) + sizeof(float)); + if (v3 >= 0 && v3 < vertices.size()) + { + x = vertices.at(v3).getX(); + y = vertices.at(v3).getY(); + z = vertices.at(v3).getZ(); + vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&x), reinterpret_cast<const uint8_t*>(&x) + sizeof(float)); + vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&y), reinterpret_cast<const uint8_t*>(&y) + sizeof(float)); + vertices_data.insert(vertices_data.end(), reinterpret_cast<const uint8_t*>(&z), reinterpret_cast<const uint8_t*>(&z) + sizeof(float)); + } + else + { + return bytearray(); + } } return vertices_data; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/src/MetadataEntry.h new/libSavitar-4.9/src/MetadataEntry.h --- old/libSavitar-4.8/src/MetadataEntry.h 1970-01-01 01:00:00.000000000 +0100 +++ new/libSavitar-4.9/src/MetadataEntry.h 2021-03-02 11:33:23.000000000 +0100 @@ -0,0 +1,66 @@ +/* + * This file is part of libSavitar + * + * Copyright (C) 2021 Ultimaker B.V. <[email protected]> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef METADATAENTRY_H +#define METADATAENTRY_H + +#include <string> + +#include "SavitarExport.h" + +namespace Savitar +{ + +/*! + * Represents an entry of metadata from 3MF documents. + * + * These entries are stored by a key in scenes and scene nodes. + */ +struct SAVITAR_EXPORT MetadataEntry +{ + /*! + * The value of the metadata entry. + * + * Regardless of the actual type, this value will be stored in serialised + * form here. The user of the 3MF data will need to interpret the data as + * is. + */ + std::string value; + + /*! + * The type of value. Must be an "XML type" as specified by the ODF, e.g. + * "xs:string" for text. + */ + std::string type; + + /*! + * Whether the data should be preserved when saving the scene to a new 3MF + * document. + */ + bool preserve; + + MetadataEntry(const std::string& value, const std::string& type = "xs:string", const bool preserve = false) + : value(value) + , type(type) + , preserve(preserve) + {} +}; + +} + +#endif \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/src/Scene.cpp new/libSavitar-4.9/src/Scene.cpp --- old/libSavitar-4.8/src/Scene.cpp 2020-10-09 18:43:31.000000000 +0200 +++ new/libSavitar-4.9/src/Scene.cpp 2021-03-02 11:33:23.000000000 +0100 @@ -1,7 +1,7 @@ /* * This file is part of libSavitar * - * Copyright (C) 2017 Ultimaker b.v. <[email protected]> + * Copyright (C) 2021 Ultimaker B.V. <[email protected]> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -56,7 +56,16 @@ // Handle metadata: for(pugi::xml_node metadata_node = xml_node.child("metadata"); metadata_node; metadata_node = metadata_node.next_sibling("metadata")) { - setMetaDataEntry(metadata_node.attribute("name").as_string(), metadata_node.text().as_string()); + const std::string key = metadata_node.attribute("name").as_string(); + const std::string value = metadata_node.text().as_string(); + std::string type = metadata_node.attribute("type").as_string(); + if(type == "") + { + type = "xs:string"; //Fill in the default type if it's not present. + } + const std::string preserve_str = metadata_node.attribute("preserve").as_string(); //Don't use as_bool since 3MF's boolean parsing is more lenient. + const bool preserve = (preserve_str != "" && preserve_str != "0"); + setMetaDataEntry(key, value, type, preserve); } pugi::xml_node build = xml_node.child("build"); @@ -68,6 +77,26 @@ { SceneNode* temp_scene_node = createSceneNodeFromObject(xml_node, object_node); temp_scene_node->setTransformation(item.attribute("transform").as_string()); + + // Get all metadata from the item and update that. + const pugi::xml_node metadatagroup_node = item.child("metadatagroup"); + if (metadatagroup_node) + { + for (pugi::xml_node setting = metadatagroup_node.child("metadata"); setting; setting = setting.next_sibling("metadata")) + { + const std::string key = setting.attribute("name").as_string(); + const std::string value = setting.text().as_string(); + std::string type = setting.attribute("type").as_string(); + if(type == "") //Not specified. + { + type = "xs:string"; + } + const std::string preserve_str = setting.attribute("preserve").as_string(); //Needs to be true if string is not "0", which is less strict than .as_bool(); + const bool preserve = (preserve_str != "" && preserve_str != "0"); + temp_scene_node->setSetting(key, value, type, preserve); + } + } + scene_nodes.push_back(temp_scene_node); } else @@ -91,7 +120,7 @@ if(has_mesh_node) { - mesh_node_object_id = scene_node->getSettings()["mesh_node_objectid"]; + mesh_node_object_id = scene_node->getSettings().at("mesh_node_objectid").value; } // We have to do the checking for children outside of the SceneNode creation itself, because it only has references. @@ -149,9 +178,14 @@ return all_nodes; } -void Scene::setMetaDataEntry(std::string key, std::string value) +void Scene::setMetaDataEntry(const std::string& key, const MetadataEntry& entry) +{ + metadata.emplace(key, entry); +} + +void Scene::setMetaDataEntry(const std::string& key, const std::string& value, const std::string& type, const bool preserve) { - metadata[key] = value; + metadata.emplace(key, MetadataEntry(value, type, preserve)); } std::string Scene::getUnit() @@ -159,7 +193,7 @@ return unit; } -std::map< std::string, std::string > Scene::getMetadata() +const std::map<std::string, MetadataEntry>& Scene::getMetadata() const { return metadata; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/src/Scene.h new/libSavitar-4.9/src/Scene.h --- old/libSavitar-4.8/src/Scene.h 2020-10-09 18:43:31.000000000 +0200 +++ new/libSavitar-4.9/src/Scene.h 2021-03-02 11:33:23.000000000 +0100 @@ -1,7 +1,7 @@ /* * This file is part of libSavitar * - * Copyright (C) 2017 Ultimaker b.v. <[email protected]> + * Copyright (C) 2021 Ultimaker B.V. <[email protected]> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -62,19 +62,30 @@ void fillByXMLNode(pugi::xml_node xml_node); /** + * Store a metadata entry as metadata. + * @param key The key of the metadata. + * @param entry A MetadataEntry object containing metadata and + * additional properties. + */ + void setMetaDataEntry(const std::string& key, const MetadataEntry& entry); + + /** * Set a meta data entry of the scene. * * Note that this not adhere to the full 3mf spec yet. All keys are accepted. * - * \param key The key of the meta data. - * \param value The value of the meta data. + * \param key The key of the metadata. + * \param value The value of the metadata. + * \param type The data type of the metadata. + * \param preserve Whether the metadata entry needs to be preserved + * through save-load loops of the 3MF document. */ - void setMetaDataEntry(std::string key, std::string value); + void setMetaDataEntry(const std::string& key, const std::string& value, const std::string& type = "xs:string", const bool preserve = false); /** * Get all meta data entries */ - std::map<std::string, std::string> getMetadata(); + const std::map<std::string, MetadataEntry>& getMetadata() const; /** * Get the unit (milimeter, inch, etc) of the scene. @@ -86,7 +97,7 @@ protected: std::vector< SceneNode*> scene_nodes; - std::map<std::string, std::string> metadata; + std::map<std::string, MetadataEntry> metadata; std::string unit; /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/src/SceneNode.cpp new/libSavitar-4.9/src/SceneNode.cpp --- old/libSavitar-4.8/src/SceneNode.cpp 2020-10-09 18:43:31.000000000 +0200 +++ new/libSavitar-4.9/src/SceneNode.cpp 2021-03-02 11:33:23.000000000 +0100 @@ -1,7 +1,7 @@ /* * This file is part of libSavitar * - * Copyright (C) 2017 Ultimaker b.v. <[email protected]> + * Copyright (C) 2021 Ultimaker B.V. <[email protected]> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -116,7 +116,7 @@ { const std::string key = setting.attribute("key").as_string(); const std::string value = setting.text().as_string(); - settings[key] = value; + setSetting(key, value); } } @@ -135,15 +135,20 @@ std::string key = setting.attribute("name").as_string(); const size_t pos = key.find_first_of(':'); - // Only accept namespaces cura and implied 'default': - if (pos != std::string::npos && cura_equivalent_namespaces.count(key.substr(0, pos)) < 1) + //Make 'cura' namespace behave like the default. + if (pos != std::string::npos && cura_equivalent_namespaces.count(key.substr(0, pos)) == 1) { - continue; + key = key.substr(pos + 1); } - - key = (pos != std::string::npos) ? key.substr(pos + 1) : key; const std::string value = setting.text().as_string(); - settings[key] = value; + std::string type = setting.attribute("type").as_string(); + if(type == "") + { + type = "xs:string"; + } + std::string preserve_str = setting.attribute("preserve").as_string(); //as_bool is too strict. Any non-zero value evaluates as true. Parse this ourselves. + const bool preserve = (preserve_str != "" && preserve_str != "0"); + setSetting(key, value, type, preserve); } } } @@ -168,14 +173,19 @@ this->name = name; } -std::map< std::string, std::string > SceneNode::getSettings() +const std::map<std::string, MetadataEntry>& SceneNode::getSettings() const { return settings; } -void SceneNode::setSetting(std::string key, std::string value) +void SceneNode::setSetting(const std::string& key, const MetadataEntry& entry) +{ + settings.emplace(key, entry); +} + +void SceneNode::setSetting(const std::string& key, const std::string& value, const std::string& type, const bool preserve) { - settings[key] = value; + settings.emplace(key, MetadataEntry(value, type, preserve)); } void SceneNode::removeSetting(std::string key) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/src/SceneNode.h new/libSavitar-4.9/src/SceneNode.h --- old/libSavitar-4.8/src/SceneNode.h 2020-10-09 18:43:31.000000000 +0200 +++ new/libSavitar-4.9/src/SceneNode.h 2021-03-02 11:33:23.000000000 +0100 @@ -1,7 +1,7 @@ /* * This file is part of libSavitar * - * Copyright (C) 2017 Ultimaker b.v. <[email protected]> + * Copyright (C) 2021 Ultimaker B.V. <[email protected]> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -21,6 +21,7 @@ #include "SavitarExport.h" #include "MeshData.h" +#include "MetadataEntry.h" #include <string> #include <vector> @@ -72,11 +73,12 @@ * Get the (per-object) settings attached to this SceneNode. * Note that this is part of the Cura Extension and not 3mf Core. */ - std::map<std::string, std::string> getSettings(); + const std::map<std::string, MetadataEntry>& getSettings() const; - void setSetting(std::string key, std::string value); + void setSetting(const std::string& key, const MetadataEntry& entry); + void setSetting(const std::string& key, const std::string& value, const std::string& type = "xs:string", const bool preserve = false); void removeSetting(std::string key); - + /** * Type of the scene node. Can be "model", "solidsupport", "support", "surface", or "other". * This defaults to "model" @@ -90,7 +92,7 @@ std::string transformation; std::vector<SceneNode*> children; MeshData mesh_data; - std::map<std::string, std::string> settings; + std::map<std::string, MetadataEntry> settings; std::string id; std::string name; std::string type; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/src/ThreeMFParser.cpp new/libSavitar-4.9/src/ThreeMFParser.cpp --- old/libSavitar-4.8/src/ThreeMFParser.cpp 2020-10-09 18:43:31.000000000 +0200 +++ new/libSavitar-4.9/src/ThreeMFParser.cpp 2021-03-02 11:33:23.000000000 +0100 @@ -59,7 +59,7 @@ model_node.append_attribute("xmlns") = xml_namespace::getDefaultUri().c_str(); model_node.append_attribute("xmlns:cura") = xml_namespace::getCuraUri().c_str(); model_node.append_attribute("xml:lang") ="en-US"; - + for(int i = 0; i < scene.getAllSceneNodes().size(); i++) { SceneNode* scene_node = scene.getAllSceneNodes().at(i); @@ -77,17 +77,23 @@ } object.append_attribute("type") = scene_node->getType().c_str(); - std::map<std::string, std::string> per_object_settings = scene_node->getSettings(); + const std::map<std::string, MetadataEntry>& per_object_settings = scene_node->getSettings(); if(!per_object_settings.empty()) { pugi::xml_node settings = object.append_child("metadatagroup"); - for(const std::pair<std::string, std::string> setting_pair: per_object_settings) + for(const std::pair<std::string, MetadataEntry>& setting_pair: per_object_settings) { pugi::xml_node setting = settings.append_child("metadata"); - setting.append_attribute("name") = (std::string("cura:") + setting_pair.first).c_str(); - setting.text().set(setting_pair.second.c_str()); - setting.append_attribute("preserve") = "true"; - setting.append_attribute("type") = "xs:string"; + setting.append_attribute("name") = setting_pair.first.c_str(); + setting.text().set(setting_pair.second.value.c_str()); + if(setting_pair.second.type != "xs:string") //xs:string is the default type and doesn't need to be written. + { + setting.append_attribute("type") = setting_pair.second.type.c_str(); + } + if(setting_pair.second.preserve) + { + setting.append_attribute("preserve") = "true"; + } } } @@ -117,7 +123,6 @@ mesh_node_setting.append_attribute("name") = "mesh_node_objectid"; mesh_node_setting.text().set(scene_node->getMeshNode()->getId().c_str()); mesh_node_setting.append_attribute("preserve") = "true"; - mesh_node_setting.append_attribute("type") = "xs:string"; } } @@ -127,7 +132,22 @@ item.append_attribute("objectid") = scene_node->getId().c_str(); item.append_attribute("transform") = scene_node->getTransformation().c_str(); } - + + for(const std::pair<std::string, MetadataEntry>& metadata_pair: scene.getMetadata()) + { + pugi::xml_node metadata_node = model_node.append_child("metadata"); + metadata_node.append_attribute("name") = metadata_pair.first.c_str(); + metadata_node.text().set(metadata_pair.second.value.c_str()); + if(metadata_pair.second.type != "xs:string") //xs:string is the default and doesn't need to get written then. + { + metadata_node.append_attribute("type") = metadata_pair.second.type.c_str(); + } + if(metadata_pair.second.preserve) + { + metadata_node.append_attribute("preserve") = "true"; + } + } + std::stringstream ss; document.save(ss); return ss.str(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libSavitar-4.8/tests/ThreeMFParserTest.cpp new/libSavitar-4.9/tests/ThreeMFParserTest.cpp --- old/libSavitar-4.8/tests/ThreeMFParserTest.cpp 2020-10-09 18:43:31.000000000 +0200 +++ new/libSavitar-4.9/tests/ThreeMFParserTest.cpp 2021-03-02 11:33:23.000000000 +0100 @@ -81,13 +81,13 @@ } // NOTE: To/from for content of vertices/triangles is tested in MeshDataTest. - std::map<std::string, std::string> settings; + std::map<std::string, MetadataEntry> settings; settings = nodes[0]->getSettings(); EXPECT_NE(settings.find("extruder_nr"), settings.end()); - EXPECT_EQ(settings["extruder_nr"].compare("0"), 0); + EXPECT_EQ(settings.at("extruder_nr").value.compare("0"), 0); EXPECT_NE(settings.find("bottom_layers"), settings.end()); - EXPECT_EQ(settings["bottom_layers"].compare("20"), 0); + EXPECT_EQ(settings.at("bottom_layers").value.compare("20"), 0); EXPECT_EQ(settings.find("infill_pattern"), settings.end()); settings = nodes[1]->getSettings(); @@ -95,10 +95,10 @@ settings = nodes[2]->getSettings(); EXPECT_NE(settings.find("extruder_nr"), settings.end()); - EXPECT_EQ(settings["extruder_nr"].compare("1"), 0); + EXPECT_EQ(settings.at("extruder_nr").value.compare("1"), 0); EXPECT_EQ(settings.find("bottom_layers"), settings.end()); EXPECT_NE(settings.find("infill_pattern"), settings.end()); - EXPECT_EQ(settings["infill_pattern"].compare("concentric"), 0); + EXPECT_EQ(settings.at("infill_pattern").value.compare("concentric"), 0); EXPECT_EQ(nodes[0]->getName().compare("test_object"), 0); EXPECT_EQ(nodes[1]->getName().compare(""), 0);
