Browse Source

Merge branch 'master' into libArachne_rebased

Ghostkeeper 4 years ago
parent
commit
0fd4d303ad

+ 4 - 3
.github/workflows/cicd.yml → .github/workflows/ci.yml

@@ -1,5 +1,5 @@
 ---
 ---
-name: CI/CD
+name: CI
 on:
 on:
   push:
   push:
     branches:
     branches:
@@ -10,11 +10,12 @@ on:
   pull_request:
   pull_request:
 jobs:
 jobs:
   build:
   build:
-    name: Build and test
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
     container: ultimaker/cura-build-environment
     container: ultimaker/cura-build-environment
     steps:
     steps:
     - name: Checkout Cura
     - name: Checkout Cura
       uses: actions/checkout@v2
       uses: actions/checkout@v2
-    - name: Build and test
+    - name: Build
       run: docker/build.sh
       run: docker/build.sh
+    - name: Test
+      run: docker/test.sh

+ 6 - 1
CMakeLists.txt

@@ -16,6 +16,8 @@ if(CURA_DEBUGMODE)
     set(_cura_debugmode "ON")
     set(_cura_debugmode "ON")
 endif()
 endif()
 
 
+option(GENERATE_TRANSLATIONS "Should the translations be generated?" ON)
+
 set(CURA_APP_NAME "cura" CACHE STRING "Short name of Cura, used for configuration folder")
 set(CURA_APP_NAME "cura" CACHE STRING "Short name of Cura, used for configuration folder")
 set(CURA_APP_DISPLAY_NAME "Ultimaker Cura" CACHE STRING "Display name of Cura")
 set(CURA_APP_DISPLAY_NAME "Ultimaker Cura" CACHE STRING "Display name of Cura")
 set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
 set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
@@ -24,6 +26,7 @@ set(CURA_CLOUD_API_ROOT "" CACHE STRING "Alternative Cura cloud API root")
 set(CURA_CLOUD_API_VERSION "" CACHE STRING "Alternative Cura cloud API version")
 set(CURA_CLOUD_API_VERSION "" CACHE STRING "Alternative Cura cloud API version")
 set(CURA_CLOUD_ACCOUNT_API_ROOT "" CACHE STRING "Alternative Cura cloud account API version")
 set(CURA_CLOUD_ACCOUNT_API_ROOT "" CACHE STRING "Alternative Cura cloud account API version")
 set(CURA_MARKETPLACE_ROOT "" CACHE STRING "Alternative Marketplace location")
 set(CURA_MARKETPLACE_ROOT "" CACHE STRING "Alternative Marketplace location")
+set(CURA_DIGITAL_FACTORY_URL "" CACHE STRING "Alternative Digital Factory location")
 
 
 configure_file(${CMAKE_SOURCE_DIR}/cura.desktop.in ${CMAKE_BINARY_DIR}/cura.desktop @ONLY)
 configure_file(${CMAKE_SOURCE_DIR}/cura.desktop.in ${CMAKE_BINARY_DIR}/cura.desktop @ONLY)
 
 
@@ -50,7 +53,9 @@ if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
     # Extract Strings
     # Extract Strings
     add_custom_target(extract-messages ${URANIUM_SCRIPTS_DIR}/extract-messages ${CMAKE_SOURCE_DIR} cura)
     add_custom_target(extract-messages ${URANIUM_SCRIPTS_DIR}/extract-messages ${CMAKE_SOURCE_DIR} cura)
     # Build Translations
     # Build Translations
-    CREATE_TRANSLATION_TARGETS()
+    if(${GENERATE_TRANSLATIONS})
+        CREATE_TRANSLATION_TARGETS()
+    endif()
 endif()
 endif()
 
 
 
 

+ 8 - 2
cmake/CuraPluginInstall.cmake

@@ -9,6 +9,8 @@
 # form of "a;b;c" or "a,b,c". By default all plugins will be installed.
 # form of "a;b;c" or "a,b,c". By default all plugins will be installed.
 #
 #
 
 
+option(PRINT_PLUGIN_LIST "Should the list of plugins that are installed be printed?" ON)
+
 # FIXME: Remove the code for CMake <3.12 once we have switched over completely.
 # FIXME: Remove the code for CMake <3.12 once we have switched over completely.
 # FindPython3 is a new module since CMake 3.12. It deprecates FindPythonInterp and FindPythonLibs. The FindPython3
 # FindPython3 is a new module since CMake 3.12. It deprecates FindPythonInterp and FindPythonLibs. The FindPython3
 # module is copied from the CMake repository here so in CMake <3.12 we can still use it.
 # module is copied from the CMake repository here so in CMake <3.12 we can still use it.
@@ -81,7 +83,9 @@ foreach(_plugin_json_path ${_plugin_json_list})
     endif()
     endif()
 
 
     if(_add_plugin)
     if(_add_plugin)
-        message(STATUS "[+] PLUGIN TO INSTALL: ${_rel_plugin_dir}")
+        if(${PRINT_PLUGIN_LIST})
+            message(STATUS "[+] PLUGIN TO INSTALL: ${_rel_plugin_dir}")
+        endif()
         get_filename_component(_rel_plugin_parent_dir ${_rel_plugin_dir} DIRECTORY)
         get_filename_component(_rel_plugin_parent_dir ${_rel_plugin_dir} DIRECTORY)
         install(DIRECTORY ${_rel_plugin_dir}
         install(DIRECTORY ${_rel_plugin_dir}
                 DESTINATION lib${LIB_SUFFIX}/cura/${_rel_plugin_parent_dir}
                 DESTINATION lib${LIB_SUFFIX}/cura/${_rel_plugin_parent_dir}
@@ -90,7 +94,9 @@ foreach(_plugin_json_path ${_plugin_json_list})
                 )
                 )
         list(APPEND _install_plugin_list ${_plugin_dir})
         list(APPEND _install_plugin_list ${_plugin_dir})
     elseif(_is_no_install_plugin)
     elseif(_is_no_install_plugin)
-        message(STATUS "[-] PLUGIN TO REMOVE : ${_rel_plugin_dir}")
+        if(${PRINT_PLUGIN_LIST})
+            message(STATUS "[-] PLUGIN TO REMOVE : ${_rel_plugin_dir}")
+        endif()
         execute_process(COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/mod_bundled_packages_json.py
         execute_process(COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/mod_bundled_packages_json.py
                         -d ${CMAKE_CURRENT_SOURCE_DIR}/resources/bundled_packages
                         -d ${CMAKE_CURRENT_SOURCE_DIR}/resources/bundled_packages
                         ${_plugin_dir_name}
                         ${_plugin_dir_name}

+ 8 - 7
cmake/CuraTests.cmake

@@ -49,6 +49,14 @@ function(cura_add_test)
     endif()
     endif()
 endfunction()
 endfunction()
 
 
+
+#Add code style test.
+add_test(
+    NAME "code-style"
+    COMMAND ${Python3_EXECUTABLE} run_mypy.py
+    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+)
+
 #Add test for import statements which are not compatible with all builds
 #Add test for import statements which are not compatible with all builds
 add_test(
 add_test(
     NAME "invalid-imports"
     NAME "invalid-imports"
@@ -67,13 +75,6 @@ foreach(_plugin ${_plugins})
     endif()
     endif()
 endforeach()
 endforeach()
 
 
-#Add code style test.
-add_test(
-    NAME "code-style"
-    COMMAND ${Python3_EXECUTABLE} run_mypy.py
-    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-)
-
 #Add test for whether the shortcut alt-keys are unique in every translation.
 #Add test for whether the shortcut alt-keys are unique in every translation.
 add_test(
 add_test(
     NAME "shortcut-keys"
     NAME "shortcut-keys"

+ 4 - 1
cura/CrashHandler.py

@@ -250,7 +250,10 @@ class CrashHandler:
 
 
                 scope.set_context("plugins", self.data["plugins"])
                 scope.set_context("plugins", self.data["plugins"])
 
 
-                scope.set_user({"id": str(uuid.getnode())})
+                user_id = uuid.getnode()  # On all of Cura's supported platforms, this returns the MAC address which is pseudonymical information (!= anonymous).
+                user_id %= 2 ** 16  # So to make it anonymous, apply a bitmask selecting only the last 16 bits.
+                                    # This prevents it from being traceable to a specific user but still gives somewhat of an idea of whether it's just the same user hitting the same crash over and over again, or if it's widespread.
+                scope.set_user({"id": str(user_id)})
 
 
         return group
         return group
 
 

+ 1 - 1
cura/CuraActions.py

@@ -40,7 +40,7 @@ class CuraActions(QObject):
 
 
     @pyqtSlot()
     @pyqtSlot()
     def openBugReportPage(self) -> None:
     def openBugReportPage(self) -> None:
-        event = CallFunctionEvent(self._openUrl, [QUrl("https://github.com/Ultimaker/Cura/issues")], {})
+        event = CallFunctionEvent(self._openUrl, [QUrl("https://github.com/Ultimaker/Cura/issues/new/choose")], {})
         cura.CuraApplication.CuraApplication.getInstance().functionEvent(event)
         cura.CuraApplication.CuraApplication.getInstance().functionEvent(event)
 
 
     @pyqtSlot()
     @pyqtSlot()

+ 5 - 2
cura/CuraApplication.py

@@ -126,7 +126,7 @@ class CuraApplication(QtApplication):
     # SettingVersion represents the set of settings available in the machine/extruder definitions.
     # SettingVersion represents the set of settings available in the machine/extruder definitions.
     # You need to make sure that this version number needs to be increased if there is any non-backwards-compatible
     # You need to make sure that this version number needs to be increased if there is any non-backwards-compatible
     # changes of the settings.
     # changes of the settings.
-    SettingVersion = 15
+    SettingVersion = 16
 
 
     Created = False
     Created = False
 
 
@@ -1725,7 +1725,7 @@ class CuraApplication(QtApplication):
         :param project_mode: How to handle project files. Either None(default): Follow user preference, "open_as_model"
         :param project_mode: How to handle project files. Either None(default): Follow user preference, "open_as_model"
          or "open_as_project". This parameter is only considered if the file is a project file.
          or "open_as_project". This parameter is only considered if the file is a project file.
         """
         """
-
+        Logger.log("i", "Attempting to read file %s", file.toString())
         if not file.isValid():
         if not file.isValid():
             return
             return
 
 
@@ -1799,6 +1799,9 @@ class CuraApplication(QtApplication):
             return
             return
 
 
         nodes = job.getResult()
         nodes = job.getResult()
+        if nodes is None:
+            Logger.error("Read mesh job returned None. Mesh loading must have failed.")
+            return
         file_name = job.getFileName()
         file_name = job.getFileName()
         file_name_lower = file_name.lower()
         file_name_lower = file_name.lower()
         file_extension = file_name_lower.split(".")[-1]
         file_extension = file_name_lower.split(".")[-1]

+ 2 - 1
cura/CuraVersion.py.in

@@ -9,4 +9,5 @@ CuraDebugMode = True if "@_cura_debugmode@" == "ON" else False
 CuraCloudAPIRoot = "@CURA_CLOUD_API_ROOT@"
 CuraCloudAPIRoot = "@CURA_CLOUD_API_ROOT@"
 CuraCloudAPIVersion = "@CURA_CLOUD_API_VERSION@"
 CuraCloudAPIVersion = "@CURA_CLOUD_API_VERSION@"
 CuraCloudAccountAPIRoot = "@CURA_CLOUD_ACCOUNT_API_ROOT@"
 CuraCloudAccountAPIRoot = "@CURA_CLOUD_ACCOUNT_API_ROOT@"
-CuraMarketplaceRoot = "@CURA_MARKETPLACE_ROOT@"
+CuraMarketplaceRoot = "@CURA_MARKETPLACE_ROOT@"
+CuraDigitalFactoryURL = "@CURA_DIGITAL_FACTORY_URL@"

+ 9 - 3
cura/Machines/Models/QualityManagementModel.py

@@ -1,4 +1,4 @@
-# Copyright (c) 2019 Ultimaker B.V.
+# Copyright (c) 2020 Ultimaker B.V.
 # Cura is released under the terms of the LGPLv3 or higher.
 # Cura is released under the terms of the LGPLv3 or higher.
 
 
 from typing import Any, cast, Dict, Optional, TYPE_CHECKING
 from typing import Any, cast, Dict, Optional, TYPE_CHECKING
@@ -132,7 +132,7 @@ class QualityManagementModel(ListModel):
         for metadata in quality_changes_group.metadata_per_extruder.values():
         for metadata in quality_changes_group.metadata_per_extruder.values():
             extruder_container = cast(InstanceContainer, container_registry.findContainers(id = metadata["id"])[0])
             extruder_container = cast(InstanceContainer, container_registry.findContainers(id = metadata["id"])[0])
             extruder_container.setName(new_name)
             extruder_container.setName(new_name)
-        global_container = cast(InstanceContainer, container_registry.findContainers(id=quality_changes_group.metadata_for_global["id"])[0])
+        global_container = cast(InstanceContainer, container_registry.findContainers(id = quality_changes_group.metadata_for_global["id"])[0])
         global_container.setName(new_name)
         global_container.setName(new_name)
 
 
         quality_changes_group.name = new_name
         quality_changes_group.name = new_name
@@ -164,10 +164,16 @@ class QualityManagementModel(ListModel):
         quality_group = quality_model_item["quality_group"]
         quality_group = quality_model_item["quality_group"]
         quality_changes_group = quality_model_item["quality_changes_group"]
         quality_changes_group = quality_model_item["quality_changes_group"]
         if quality_changes_group is None:
         if quality_changes_group is None:
-            # Create global quality changes only.
             new_quality_changes = self._createQualityChanges(quality_group.quality_type, intent_category, new_name,
             new_quality_changes = self._createQualityChanges(quality_group.quality_type, intent_category, new_name,
                                                              global_stack, extruder_stack = None)
                                                              global_stack, extruder_stack = None)
             container_registry.addContainer(new_quality_changes)
             container_registry.addContainer(new_quality_changes)
+
+            for extruder in global_stack.extruderList:
+                new_extruder_quality_changes = self._createQualityChanges(quality_group.quality_type, intent_category,
+                                                                          new_name,
+                                                                          global_stack, extruder_stack = extruder)
+
+                container_registry.addContainer(new_extruder_quality_changes)
         else:
         else:
             for metadata in [quality_changes_group.metadata_for_global] + list(quality_changes_group.metadata_per_extruder.values()):
             for metadata in [quality_changes_group.metadata_for_global] + list(quality_changes_group.metadata_per_extruder.values()):
                 containers = container_registry.findContainers(id = metadata["id"])
                 containers = container_registry.findContainers(id = metadata["id"])

+ 43 - 14
cura/Scene/ConvexHullDecorator.py

@@ -1,11 +1,10 @@
-# Copyright (c) 2016 Ultimaker B.V.
+# Copyright (c) 2020 Ultimaker B.V.
 # Cura is released under the terms of the LGPLv3 or higher.
 # Cura is released under the terms of the LGPLv3 or higher.
 
 
 from PyQt5.QtCore import QTimer
 from PyQt5.QtCore import QTimer
 
 
 from UM.Application import Application
 from UM.Application import Application
 from UM.Math.Polygon import Polygon
 from UM.Math.Polygon import Polygon
-
 from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
 from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
 from UM.Settings.ContainerRegistry import ContainerRegistry
 from UM.Settings.ContainerRegistry import ContainerRegistry
 
 
@@ -50,8 +49,10 @@ class ConvexHullDecorator(SceneNodeDecorator):
         self._build_volume.raftThicknessChanged.connect(self._onChanged)
         self._build_volume.raftThicknessChanged.connect(self._onChanged)
 
 
         CuraApplication.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
         CuraApplication.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
-        CuraApplication.getInstance().getController().toolOperationStarted.connect(self._onChanged)
-        CuraApplication.getInstance().getController().toolOperationStopped.connect(self._onChanged)
+        controller = CuraApplication.getInstance().getController()
+        controller.toolOperationStarted.connect(self._onChanged)
+        controller.toolOperationStopped.connect(self._onChanged)
+        #CuraApplication.getInstance().sceneBoundingBoxChanged.connect(self._onChanged)
 
 
         self._root = Application.getInstance().getController().getScene().getRoot()
         self._root = Application.getInstance().getController().getScene().getRoot()
 
 
@@ -188,7 +189,6 @@ class ConvexHullDecorator(SceneNodeDecorator):
 
 
     def recomputeConvexHullDelayed(self) -> None:
     def recomputeConvexHullDelayed(self) -> None:
         """The same as recomputeConvexHull, but using a timer if it was set."""
         """The same as recomputeConvexHull, but using a timer if it was set."""
-
         if self._recompute_convex_hull_timer is not None:
         if self._recompute_convex_hull_timer is not None:
             self._recompute_convex_hull_timer.start()
             self._recompute_convex_hull_timer.start()
         else:
         else:
@@ -263,16 +263,17 @@ class ConvexHullDecorator(SceneNodeDecorator):
             return offset_hull
             return offset_hull
 
 
         else:
         else:
+            convex_hull = Polygon([])
             offset_hull = Polygon([])
             offset_hull = Polygon([])
             mesh = self._node.getMeshData()
             mesh = self._node.getMeshData()
             if mesh is None:
             if mesh is None:
                 return Polygon([])  # Node has no mesh data, so just return an empty Polygon.
                 return Polygon([])  # Node has no mesh data, so just return an empty Polygon.
 
 
-            world_transform = self._node.getWorldTransformation(copy= False)
+            world_transform = self._node.getWorldTransformation(copy = False)
 
 
             # Check the cache
             # Check the cache
             if mesh is self._2d_convex_hull_mesh and world_transform == self._2d_convex_hull_mesh_world_transform:
             if mesh is self._2d_convex_hull_mesh and world_transform == self._2d_convex_hull_mesh_world_transform:
-                return self._2d_convex_hull_mesh_result
+                return self._offsetHull(self._2d_convex_hull_mesh_result)
 
 
             vertex_data = mesh.getConvexHullTransformedVertices(world_transform)
             vertex_data = mesh.getConvexHullTransformedVertices(world_transform)
             # Don't use data below 0.
             # Don't use data below 0.
@@ -307,7 +308,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
             # Store the result in the cache
             # Store the result in the cache
             self._2d_convex_hull_mesh = mesh
             self._2d_convex_hull_mesh = mesh
             self._2d_convex_hull_mesh_world_transform = world_transform
             self._2d_convex_hull_mesh_world_transform = world_transform
-            self._2d_convex_hull_mesh_result = offset_hull
+            self._2d_convex_hull_mesh_result = convex_hull
 
 
             return offset_hull
             return offset_hull
 
 
@@ -379,12 +380,41 @@ class ConvexHullDecorator(SceneNodeDecorator):
         :return: New Polygon instance that is offset with everything that
         :return: New Polygon instance that is offset with everything that
         influences the collision area.
         influences the collision area.
         """
         """
-
+        # Shrinkage compensation.
+        if not self._global_stack:  # Should never happen.
+            return convex_hull
+        scale_factor = self._global_stack.getProperty("material_shrinkage_percentage", "value") / 100.0
+        result = convex_hull
+        if scale_factor != 1.0 and not self.getNode().callDecoration("isGroup"):
+            center = None
+            if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time":
+                # Find the root node that's placed in the scene; the root of the mesh group.
+                ancestor = self.getNode()
+                while ancestor.getParent() != self._root:
+                    ancestor = ancestor.getParent()
+                center = ancestor.getBoundingBox().center
+            else:
+                # Find the bounding box of the entire scene, which is all one mesh group then.
+                aabb = None
+                for printed_node in self._root.getChildren():
+                    if not printed_node.callDecoration("isSliceable") and not printed_node.callDecoration("isGroup"):
+                        continue  # Not a printed node.
+                    if aabb is None:
+                        aabb = printed_node.getBoundingBox()
+                    else:
+                        aabb = aabb + printed_node.getBoundingBox()
+                if aabb:
+                    center = aabb.center
+            if center:
+                result = convex_hull.scale(scale_factor, [center.x, center.z])  # Yes, use Z instead of Y. Mixed conventions there with how the OpenGL coordinates are transmitted.
+
+        # Horizontal expansion.
         horizontal_expansion = max(
         horizontal_expansion = max(
             self._getSettingProperty("xy_offset", "value"),
             self._getSettingProperty("xy_offset", "value"),
             self._getSettingProperty("xy_offset_layer_0", "value")
             self._getSettingProperty("xy_offset_layer_0", "value")
         )
         )
 
 
+        # Mold.
         mold_width = 0
         mold_width = 0
         if self._getSettingProperty("mold_enabled", "value"):
         if self._getSettingProperty("mold_enabled", "value"):
             mold_width = self._getSettingProperty("mold_width", "value")
             mold_width = self._getSettingProperty("mold_width", "value")
@@ -396,14 +426,13 @@ class ConvexHullDecorator(SceneNodeDecorator):
                 [hull_offset, hull_offset],
                 [hull_offset, hull_offset],
                 [hull_offset, -hull_offset]
                 [hull_offset, -hull_offset]
             ], numpy.float32))
             ], numpy.float32))
-            return convex_hull.getMinkowskiHull(expansion_polygon)
+            return result.getMinkowskiHull(expansion_polygon)
         else:
         else:
-            return convex_hull
+            return result
 
 
     def _onChanged(self, *args) -> None:
     def _onChanged(self, *args) -> None:
         self._raft_thickness = self._build_volume.getRaftThickness()
         self._raft_thickness = self._build_volume.getRaftThickness()
-        if not args or args[0] == self._node:
-            self.recomputeConvexHullDelayed()
+        self.recomputeConvexHullDelayed()
 
 
     def _onGlobalStackChanged(self) -> None:
     def _onGlobalStackChanged(self) -> None:
         if self._global_stack:
         if self._global_stack:
@@ -469,7 +498,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
         "adhesion_type", "raft_margin", "print_sequence",
         "adhesion_type", "raft_margin", "print_sequence",
         "skirt_gap", "skirt_line_count", "skirt_brim_line_width", "skirt_distance", "brim_line_count"]
         "skirt_gap", "skirt_line_count", "skirt_brim_line_width", "skirt_distance", "brim_line_count"]
 
 
-    _influencing_settings = {"xy_offset", "xy_offset_layer_0", "mold_enabled", "mold_width", "anti_overhang_mesh", "infill_mesh", "cutting_mesh"}
+    _influencing_settings = {"xy_offset", "xy_offset_layer_0", "mold_enabled", "mold_width", "anti_overhang_mesh", "infill_mesh", "cutting_mesh", "material_shrinkage_percentage"}
     """Settings that change the convex hull.
     """Settings that change the convex hull.
 
 
     If these settings change, the convex hull should be recalculated.
     If these settings change, the convex hull should be recalculated.

Some files were not shown because too many files changed in this diff