diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..d25d71bcc9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.git +.github +resources/materials +CuraEngine \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 97c849144d..c69cf91433 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -6,7 +6,7 @@ Before filing, PLEASE check if the issue already exists (either open or closed) Also, please note the application version in the title of the issue. For example: "[3.2.1] Cannot connect to 3rd-party printer". Please do not write thigns like "Request:" or "[BUG]" in the title; this is what labels are for. It is also helpful to attach a project (.3mf or .curaproject) file and Cura log file so we can debug issues quicker. -Information about how to find the log file can be found at https://github.com/Ultimaker/Cura/wiki/Cura-Preferences-and-Settings-Locations. To upload a project, we recommend http://wetransfer.com, but other file hosts like Google Drive or Dropbox work well too. +Information about how to find the log file can be found at https://github.com/Ultimaker/Cura/wiki/Cura-Preferences-and-Settings-Locations. To upload a project, try changing the extension to e.g. .curaproject.3mf.zip so that github accepts uploading the file. Otherwise we recommend http://wetransfer.com, but other file hosts like Google Drive or Dropbox work well too. Thank you for using Cura! --> @@ -26,6 +26,9 @@ Thank you for using Cura! **Display Driver** +**Printer** + + **Steps to Reproduce** diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..68255c56b9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,45 @@ +FROM ultimaker/cura-build-environment:1 + +# Environment vars for easy configuration +ENV CURA_APP_DIR=/srv/cura + +# Ensure our sources dir exists +RUN mkdir $CURA_APP_DIR + +# Setup CuraEngine +ENV CURA_ENGINE_BRANCH=master +WORKDIR $CURA_APP_DIR +RUN git clone -b $CURA_ENGINE_BRANCH --depth 1 https://github.com/Ultimaker/CuraEngine +WORKDIR $CURA_APP_DIR/CuraEngine +RUN mkdir build +WORKDIR $CURA_APP_DIR/CuraEngine/build +RUN cmake3 .. +RUN make +RUN make install + +# TODO: setup libCharon + +# Setup Uranium +ENV URANIUM_BRANCH=master +WORKDIR $CURA_APP_DIR +RUN git clone -b $URANIUM_BRANCH --depth 1 https://github.com/Ultimaker/Uranium + +# Setup materials +ENV MATERIALS_BRANCH=master +WORKDIR $CURA_APP_DIR +RUN git clone -b $MATERIALS_BRANCH --depth 1 https://github.com/Ultimaker/fdm_materials materials + +# Setup Cura +WORKDIR $CURA_APP_DIR/Cura +ADD . . +RUN mv $CURA_APP_DIR/materials resources/materials + +# Make sure Cura can find CuraEngine +RUN ln -s /usr/local/bin/CuraEngine $CURA_APP_DIR/Cura + +# Run Cura +WORKDIR $CURA_APP_DIR/Cura +ENV PYTHONPATH=${PYTHONPATH}:$CURA_APP_DIR/Uranium +RUN chmod +x ./CuraEngine +RUN chmod +x ./run_in_docker.sh +CMD "./run_in_docker.sh" diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index b929f0f8f1..6da8f33fff 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -111,6 +111,9 @@ class BuildVolume(SceneNode): # but it does not update the disallowed areas after material change Application.getInstance().getMachineManager().activeStackChanged.connect(self._onStackChanged) + # Enable and disable extruder + Application.getInstance().getMachineManager().extruderChanged.connect(self.updateNodeBoundaryCheck) + # list of settings which were updated self._changed_settings_since_last_rebuild = [] @@ -133,6 +136,7 @@ class BuildVolume(SceneNode): if active_extruder_changed is not None: node.callDecoration("getActiveExtruderChangedSignal").disconnect(self._updateDisallowedAreasAndRebuild) node.decoratorsChanged.disconnect(self._updateNodeListeners) + self._updateDisallowedAreasAndRebuild() # make sure we didn't miss anything before we updated the node listeners self._scene_objects = new_scene_objects self._onSettingPropertyChanged("print_sequence", "value") # Create fake event, so right settings are triggered. @@ -147,7 +151,6 @@ class BuildVolume(SceneNode): active_extruder_changed = node.callDecoration("getActiveExtruderChangedSignal") if active_extruder_changed is not None: active_extruder_changed.connect(self._updateDisallowedAreasAndRebuild) - self._updateDisallowedAreasAndRebuild() def setWidth(self, width): if width is not None: @@ -217,30 +220,35 @@ class BuildVolume(SceneNode): group_nodes.append(node) # Keep list of affected group_nodes if node.callDecoration("isSliceable") or node.callDecoration("isGroup"): - node._outside_buildarea = False - bbox = node.getBoundingBox() - - # Mark the node as outside the build volume if the bounding box test fails. - if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: - node._outside_buildarea = True + if node.collidesWithBbox(build_volume_bounding_box): + node.setOutsideBuildArea(True) continue - convex_hull = node.callDecoration("getConvexHull") - if convex_hull: - if not convex_hull.isValid(): - return - # Check for collisions between disallowed areas and the object - for area in self.getDisallowedAreas(): - overlap = convex_hull.intersectsPolygon(area) - if overlap is None: - continue - node._outside_buildarea = True - continue + if node.collidesWithArea(self.getDisallowedAreas()): + node.setOutsideBuildArea(True) + continue + + # Mark the node as outside build volume if the set extruder is disabled + extruder_position = node.callDecoration("getActiveExtruderPosition") + if not self._global_container_stack.extruders[extruder_position].isEnabled: + node.setOutsideBuildArea(True) + continue + + node.setOutsideBuildArea(False) # Group nodes should override the _outside_buildarea property of their children. for group_node in group_nodes: - for child_node in group_node.getAllChildren(): - child_node._outside_buildarea = group_node._outside_buildarea + children = group_node.getAllChildren() + + # Check if one or more children are non-printable and if so, set the parent as non-printable: + for child_node in children: + if child_node.isOutsideBuildArea(): + group_node.setOutsideBuildArea(True) + break + + # Apply results of the check to all children of the group: + for child_node in children: + child_node.setOutsideBuildArea(group_node.isOutsideBuildArea()) ## Update the outsideBuildArea of a single node, given bounds or current build volume def checkBoundsAndUpdate(self, node: CuraSceneNode, bounds: Optional[AxisAlignedBox] = None): @@ -260,24 +268,20 @@ class BuildVolume(SceneNode): build_volume_bounding_box = bounds if node.callDecoration("isSliceable") or node.callDecoration("isGroup"): - bbox = node.getBoundingBox() - - # Mark the node as outside the build volume if the bounding box test fails. - if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: + if node.collidesWithBbox(build_volume_bounding_box): + node.setOutsideBuildArea(True) + return + + if node.collidesWithArea(self.getDisallowedAreas()): + node.setOutsideBuildArea(True) + return + + # Mark the node as outside build volume if the set extruder is disabled + extruder_position = node.callDecoration("getActiveExtruderPosition") + if not self._global_container_stack.extruders[extruder_position].isEnabled: node.setOutsideBuildArea(True) return - convex_hull = self.callDecoration("getConvexHull") - if convex_hull: - if not convex_hull.isValid(): - return - # Check for collisions between disallowed areas and the object - for area in self.getDisallowedAreas(): - overlap = convex_hull.intersectsPolygon(area) - if overlap is None: - continue - node.setOutsideBuildArea(True) - return node.setOutsideBuildArea(False) ## Recalculates the build volume & disallowed areas. diff --git a/cura/CrashHandler.py b/cura/CrashHandler.py index d74b48a53a..f51174aec0 100644 --- a/cura/CrashHandler.py +++ b/cura/CrashHandler.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import platform @@ -14,10 +14,11 @@ import urllib.request import urllib.error import shutil -from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, QUrl +from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, Qt, QUrl from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit, QGroupBox, QCheckBox, QPushButton from PyQt5.QtGui import QDesktopServices +from UM.Resources import Resources from UM.Application import Application from UM.Logger import Logger from UM.View.GL.OpenGL import OpenGL @@ -84,14 +85,14 @@ class CrashHandler: dialog = QDialog() dialog.setMinimumWidth(500) dialog.setMinimumHeight(170) - dialog.setWindowTitle(catalog.i18nc("@title:window", "Cura Crashed")) + dialog.setWindowTitle(catalog.i18nc("@title:window", "Cura can't startup")) dialog.finished.connect(self._closeEarlyCrashDialog) layout = QVBoxLayout(dialog) label = QLabel() - label.setText(catalog.i18nc("@label crash message", """

A fatal error has occurred.

-

Unfortunately, Cura encountered an unrecoverable error during start up. It was possibly caused by some incorrect configuration files. We suggest to backup and reset your configuration.

+ label.setText(catalog.i18nc("@label crash message", """

Oops, Ultimaker Cura has encountered something that doesn't seem right.

+

We encountered an unrecoverable error during start up. It was possibly caused by some incorrect configuration files. We suggest to backup and reset your configuration.

Backups can be found in the configuration folder.

Please send us this Crash Report to fix the problem.

""")) @@ -219,7 +220,7 @@ class CrashHandler: def _messageWidget(self): label = QLabel() - label.setText(catalog.i18nc("@label crash message", """

A fatal error has occurred. Please send us this Crash Report to fix the problem

+ label.setText(catalog.i18nc("@label crash message", """

A fatal error has occurred in Cura. Please send us this Crash Report to fix the problem

Please use the "Send report" button to post a bug report automatically to our servers

""")) @@ -258,7 +259,7 @@ class CrashHandler: opengl_instance = OpenGL.getInstance() if not opengl_instance: self.data["opengl"] = {"version": "n/a", "vendor": "n/a", "type": "n/a"} - return catalog.i18nc("@label", "not yet initialised
") + return catalog.i18nc("@label", "Not yet initialized
") info = "