diff --git a/cura/Arranging/ArrangeObjectsJob.py b/cura/Arranging/ArrangeObjectsJob.py index 481b8c2dc8..46b1aa2d71 100644 --- a/cura/Arranging/ArrangeObjectsJob.py +++ b/cura/Arranging/ArrangeObjectsJob.py @@ -4,6 +4,7 @@ from typing import List from UM.Application import Application from UM.Job import Job +from UM.Logger import Logger from UM.Message import Message from UM.Scene.SceneNode import SceneNode from UM.i18n import i18nCatalog @@ -27,10 +28,14 @@ class ArrangeObjectsJob(Job): title = i18n_catalog.i18nc("@info:title", "Finding Location")) status_message.show() - found_solution_for_all = arrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes) + found_solution_for_all = None + try: + found_solution_for_all = arrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes) + except: # If the thread crashes, the message should still close + Logger.logException("e", "Unable to arrange the objects on the buildplate. The arrange algorithm has crashed.") status_message.hide() - if not found_solution_for_all: + if found_solution_for_all is not None and not found_solution_for_all: no_full_solution_message = Message( i18n_catalog.i18nc("@info:status", "Unable to find a location within the build volume for all objects"), diff --git a/cura/Arranging/Nest2DArrange.py b/cura/Arranging/Nest2DArrange.py index 93d0788970..727504c9ff 100644 --- a/cura/Arranging/Nest2DArrange.py +++ b/cura/Arranging/Nest2DArrange.py @@ -3,6 +3,7 @@ from pynest2d import Point, Box, Item, NfpConfig, nest from typing import List, TYPE_CHECKING, Optional, Tuple from UM.Application import Application +from UM.Logger import Logger from UM.Math.Matrix import Matrix from UM.Math.Polygon import Polygon from UM.Math.Quaternion import Quaternion @@ -44,6 +45,9 @@ def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildV node_items = [] for node in nodes_to_arrange: hull_polygon = node.callDecoration("getConvexHull") + if not hull_polygon or hull_polygon.getPoints is None: + Logger.log("w", "Object {} cannot be arranged because it has no convex hull.".format(node.getName())) + continue converted_points = [] for point in hull_polygon.getPoints(): converted_points.append(Point(point[0] * factor, point[1] * factor)) diff --git a/cura/OAuth2/AuthorizationHelpers.py b/cura/OAuth2/AuthorizationHelpers.py index e825afd2a9..b4ea2d8382 100644 --- a/cura/OAuth2/AuthorizationHelpers.py +++ b/cura/OAuth2/AuthorizationHelpers.py @@ -1,11 +1,11 @@ -# Copyright (c) 2019 Ultimaker B.V. +# Copyright (c) 2020 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from datetime import datetime import json import random from hashlib import sha512 from base64 import b64encode -from typing import Optional +from typing import Optional, Any, Dict, Tuple import requests @@ -16,6 +16,7 @@ from cura.OAuth2.Models import AuthenticationResponse, UserProfile, OAuth2Settin catalog = i18nCatalog("cura") TOKEN_TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S" + class AuthorizationHelpers: """Class containing several helpers to deal with the authorization flow.""" @@ -121,10 +122,13 @@ class AuthorizationHelpers: if not user_data or not isinstance(user_data, dict): Logger.log("w", "Could not parse user data from token: %s", user_data) return None + return UserProfile( user_id = user_data["user_id"], username = user_data["username"], - profile_image_url = user_data.get("profile_image_url", "") + profile_image_url = user_data.get("profile_image_url", ""), + organization_id = user_data.get("organization", {}).get("organization_id", ""), + subscriptions = user_data.get("subscriptions", []) ) @staticmethod diff --git a/cura/OAuth2/Models.py b/cura/OAuth2/Models.py index 93b44e8057..f49fdc1421 100644 --- a/cura/OAuth2/Models.py +++ b/cura/OAuth2/Models.py @@ -1,6 +1,6 @@ -# Copyright (c) 2019 Ultimaker B.V. +# Copyright (c) 2020 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Optional, Dict, Any +from typing import Optional, Dict, Any, List class BaseModel: @@ -27,6 +27,8 @@ class UserProfile(BaseModel): user_id = None # type: Optional[str] username = None # type: Optional[str] profile_image_url = None # type: Optional[str] + organization_id = None # type: Optional[str] + subscriptions = None # type: Optional[List[Dict[str, Any]]] class AuthenticationResponse(BaseModel): diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index 2c29728d66..c9e3689a0d 100755 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -19,6 +19,7 @@ from UM.Scene.SceneNode import SceneNode # For typing. from cura.CuraApplication import CuraApplication from cura.Machines.ContainerTree import ContainerTree from cura.Scene.BuildPlateDecorator import BuildPlateDecorator +from cura.Scene.ConvexHullDecorator import ConvexHullDecorator from cura.Scene.CuraSceneNode import CuraSceneNode from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator from cura.Scene.ZOffsetDecorator import ZOffsetDecorator @@ -108,6 +109,7 @@ class ThreeMFReader(MeshReader): um_node = CuraSceneNode() # This adds a SettingOverrideDecorator um_node.addDecorator(BuildPlateDecorator(active_build_plate)) + um_node.addDecorator(ConvexHullDecorator()) um_node.setName(node_name) um_node.setId(node_id) transformation = self._createMatrixFromTransformationString(savitar_node.getTransformation()) diff --git a/plugins/SliceInfoPlugin/SliceInfo.py b/plugins/SliceInfoPlugin/SliceInfo.py index 284389064c..61fc777290 100755 --- a/plugins/SliceInfoPlugin/SliceInfo.py +++ b/plugins/SliceInfoPlugin/SliceInfo.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018 Ultimaker B.V. +# Copyright (c) 2020 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import json @@ -116,6 +116,7 @@ class SliceInfo(QObject, Extension): machine_manager = self._application.getMachineManager() print_information = self._application.getPrintInformation() + user_profile = self._application.getCuraAPI().account.userProfile global_stack = machine_manager.activeMachine @@ -124,6 +125,8 @@ class SliceInfo(QObject, Extension): data["schema_version"] = 0 data["cura_version"] = self._application.getVersion() data["cura_build_type"] = ApplicationMetadata.CuraBuildType + data["organization_id"] = user_profile.get("organization_id", None) if user_profile else None + data["subscriptions"] = user_profile.get("subscriptions", []) if user_profile else [] active_mode = self._application.getPreferences().getValue("cura/active_mode") if active_mode == 0: diff --git a/plugins/SliceInfoPlugin/example_data.html b/plugins/SliceInfoPlugin/example_data.html index 103eb55a6a..b349ec328d 100644 --- a/plugins/SliceInfoPlugin/example_data.html +++ b/plugins/SliceInfoPlugin/example_data.html @@ -1,12 +1,17 @@
- Cura Version: 4.0