def setOrientation(self, orientation: Quaternion, transform_space: int = TransformSpace.Local): if not self._enabled or orientation == self._orientation: return new_transform_matrix = Matrix() if transform_space == SceneNode.TransformSpace.World: if self.getWorldOrientation() == orientation: return new_orientation = orientation * ( self.getWorldOrientation() * self._orientation.getInverse()).getInverse() orientation_matrix = new_orientation.toMatrix() else: # Local orientation_matrix = orientation.toMatrix() euler_angles = orientation_matrix.getEuler() new_transform_matrix.compose(scale=self._scale, angles=euler_angles, translate=self._position, shear=self._shear) self._transformation = new_transform_matrix self._transformChanged()
def setOrientation(self, orientation: Quaternion, transform_space: int = TransformSpace.Local) -> None: """Set the local orientation of this scene node. :param orientation: :type{Quaternion} The new orientation of this scene node. :param transform_space: The space relative to which to rotate. Can be Local or World from SceneNode::TransformSpace. """ if not self._enabled or orientation == self._orientation: return if transform_space == SceneNode.TransformSpace.World: if self.getWorldOrientation() == orientation: return new_orientation = orientation * ( self.getWorldOrientation() * self._orientation.getInverse()).invert() orientation_matrix = new_orientation.toMatrix() else: # Local orientation_matrix = orientation.toMatrix() euler_angles = orientation_matrix.getEuler() new_transform_matrix = Matrix() new_transform_matrix.compose(scale=self._scale, angles=euler_angles, translate=self._position, shear=self._shear) self._transformation = new_transform_matrix self._transformChanged()
def createMockedSelectionWithScale(scale): selection = MagicMock(name="mocked_selection") node = MagicMock(name="mocked_node") matrix = Matrix() matrix.compose(scale=scale) node.getWorldTransformation = MagicMock(return_value=matrix) node.getScale = MagicMock(return_value=scale) selection.hasSelection = MagicMock(return_value=True) selection.getSelectedObject = MagicMock(return_value=node) return selection
def setOrientation(self, orientation, transform_space = TransformSpace.Local): if not self._enabled or orientation == self._orientation: return new_transform_matrix = Matrix() if transform_space == SceneNode.TransformSpace.Local: orientation_matrix = orientation.toMatrix() if transform_space == SceneNode.TransformSpace.World: if self.getWorldOrientation() == orientation: return new_orientation = orientation * (self.getWorldOrientation() * self._orientation.getInverse()).getInverse() orientation_matrix = new_orientation.toMatrix() euler_angles = orientation_matrix.getEuler() new_transform_matrix.compose(scale = self._scale, angles = euler_angles, translate = self._position, shear = self._shear) self._transformation = new_transform_matrix self._transformChanged()
class SetTransformOperation(Operation.Operation): ## Creates the transform operation. # # Careful! No real input checking is done by this function. If you'd # provide other transformations than respectively translation, orientation # and scale in place for the translation, orientation and scale matrices, # it could get confused. # # \param node The scene node to transform. # \param translation A translation matrix to move the node with. # \param orientation An orientation matrix to rotate the node with. # \param scale A scaling matrix to resize the node with. def __init__(self, node, translation=None, orientation=None, scale=None, shear=None, mirror=None): super().__init__() self._node = node self._old_translation = node.getPosition() self._old_orientation = node.getOrientation() self._old_scale = node.getScale() self._old_shear = node.getShear() self._old_transformation = node.getWorldTransformation() if translation: self._new_translation = translation else: self._new_translation = node.getPosition() if orientation: self._new_orientation = orientation else: self._new_orientation = node.getOrientation() if scale: self._new_scale = scale else: self._new_scale = node.getScale() if shear: self._new_shear = shear else: self._new_shear = node.getShear() if mirror: self._new_mirror = mirror else: # Scale will either be negative or positive. If it's negative, we need to use the inverse mirror. if self._node.getScale().x < 0: self._new_mirror = Vector(-node.getMirror().x, -node.getMirror().y, -node.getMirror().z) else: self._new_mirror = node.getMirror() self._new_transformation = Matrix() euler_orientation = self._new_orientation.toMatrix().getEuler() self._new_transformation.compose(scale=self._new_scale, shear=self._new_shear, angles=euler_orientation, translate=self._new_translation, mirror=self._new_mirror) ## Undoes the transformation, restoring the node to the old state. def undo(self): self._node.setTransformation(self._old_transformation) ## Re-applies the transformation after it has been undone. def redo(self): self._node.setTransformation(self._new_transformation) ## Merges this operation with another TransformOperation. # # This prevents the user from having to undo multiple operations if they # were not his operations. # # You should ONLY merge this operation with an older operation. It is NOT # symmetric. # # \param other The older operation with which to merge this operation. # \return A combination of the two operations, or False if the merge # failed. def mergeWith(self, other): if type(other) is not SetTransformOperation: return False if other._node != self._node: # Must be on the same node. return False op = SetTransformOperation(self._node) op._old_transformation = other._old_transformation op._new_transformation = self._new_transformation return op ## Returns a programmer-readable representation of this operation. # # A programmer-readable representation of this operation. def __repr__(self): return "SetTransformOperation(node = {0})".format(self._node) def LOG_MATRIX(self, str_matrix_name, matrix): Logger.log( "d", "\n ................................................................... " ) Logger.log("d", "\n %s: ", str_matrix_name) if (matrix != None): Logger.log("d", "%d %d %d %d", matrix.at(0, 0), matrix.at(0, 1), matrix.at(0, 2), matrix.at(0, 3)) Logger.log("d", "%d %d %d %d", matrix.at(1, 0), matrix.at(1, 1), matrix.at(1, 2), matrix.at(1, 3)) Logger.log("d", "%d %d %d %d", matrix.at(2, 0), matrix.at(2, 1), matrix.at(2, 2), matrix.at(2, 3)) Logger.log("d", "%d %d %d %d", matrix.at(3, 0), matrix.at(3, 1), matrix.at(3, 2), matrix.at(3, 3)) else: Logger.log("d", "\n %s in None ", str_matrix_name) Logger.log( "d", "................................................................... \n" ) def LOG_QUATERNION(self, str_quaternion_name, quaternion): Logger.log( "d", "\n ................................................................... " ) Logger.log("d", "\n %s: ", str_quaternion_name) Logger.log("d", "%d %d %d %d", quaternion.toMatrix().at(0, 0), quaternion.toMatrix().at(0, 1), quaternion.toMatrix().at(0, 2), quaternion.toMatrix().at(0, 3)) Logger.log("d", "%d %d %d %d", quaternion.toMatrix().at(1, 0), quaternion.toMatrix().at(1, 1), quaternion.toMatrix().at(1, 2), quaternion.toMatrix().at(1, 3)) Logger.log("d", "%d %d %d %d", quaternion.toMatrix().at(2, 0), quaternion.toMatrix().at(2, 1), quaternion.toMatrix().at(2, 2), quaternion.toMatrix().at(2, 3)) Logger.log("d", "%d %d %d %d", quaternion.toMatrix().at(3, 0), quaternion.toMatrix().at(3, 1), quaternion.toMatrix().at(3, 2), quaternion.toMatrix().at(3, 3)) Logger.log( "d", "................................................................... \n" ) def LOG_VECTOR(self, str_vector_name, vector): Logger.log( "d", "\n ................................................................... " ) Logger.log("d", "\n %s: ", str_vector_name) Logger.log("d", "%d %d %d", vector.x, vector.y, vector.z) Logger.log( "d", "................................................................... \n" )
def rebuild(self): if not self._width or not self._height or not self._depth: return min_w = -self._width / 2 max_w = self._width / 2 min_h = 0.0 max_h = self._height min_d = -self._depth / 2 max_d = self._depth / 2 z_fight_distance = 0.2 # Distance between buildplate and disallowed area meshes to prevent z-fighting if self._shape != "elliptic": # Outline 'cube' of the build volume mb = MeshBuilder() mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, max_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, max_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(max_w, min_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, min_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, min_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(max_w, max_h, min_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor) self.setMeshData(mb.build()) # Build plate grid mesh mb = MeshBuilder() mb.addQuad( Vector(min_w, min_h - z_fight_distance, min_d), Vector(max_w, min_h - z_fight_distance, min_d), Vector(max_w, min_h - z_fight_distance, max_d), Vector(min_w, min_h - z_fight_distance, max_d) ) for n in range(0, 6): v = mb.getVertex(n) mb.setVertexUVCoordinates(n, v[0], v[2]) self._grid_mesh = mb.build() else: # Bottom and top 'ellipse' of the build volume aspect = 1.0 scale_matrix = Matrix() if self._width != 0: # Scale circular meshes by aspect ratio if width != height aspect = self._height / self._width scale_matrix.compose(scale = Vector(1, 1, aspect)) mb = MeshBuilder() mb.addArc(max_w, Vector.Unit_Y, center = (0, min_h - z_fight_distance, 0), color = self.VolumeOutlineColor) mb.addArc(max_w, Vector.Unit_Y, center = (0, max_h, 0), color = self.VolumeOutlineColor) self.setMeshData(mb.build().getTransformed(scale_matrix)) # Build plate grid mesh mb = MeshBuilder() mb.addVertex(0, min_h - z_fight_distance, 0) mb.addArc(max_w, Vector.Unit_Y, center = Vector(0, min_h - z_fight_distance, 0)) sections = mb.getVertexCount() - 1 # Center point is not an arc section indices = [] for n in range(0, sections - 1): indices.append([0, n + 2, n + 1]) mb.addIndices(numpy.asarray(indices, dtype = numpy.int32)) mb.calculateNormals() for n in range(0, mb.getVertexCount()): v = mb.getVertex(n) mb.setVertexUVCoordinates(n, v[0], v[2] * aspect) self._grid_mesh = mb.build().getTransformed(scale_matrix) # Indication of the machine origin if self._global_container_stack.getProperty("machine_center_is_zero", "value"): origin = (Vector(min_w, min_h, min_d) + Vector(max_w, min_h, max_d)) / 2 else: origin = Vector(min_w, min_h, max_d) mb = MeshBuilder() mb.addCube( width = self._origin_line_length, height = self._origin_line_width, depth = self._origin_line_width, center = origin + Vector(self._origin_line_length / 2, 0, 0), color = self.XAxisColor ) mb.addCube( width = self._origin_line_width, height = self._origin_line_length, depth = self._origin_line_width, center = origin + Vector(0, self._origin_line_length / 2, 0), color = self.YAxisColor ) mb.addCube( width = self._origin_line_width, height = self._origin_line_width, depth = self._origin_line_length, center = origin - Vector(0, 0, self._origin_line_length / 2), color = self.ZAxisColor ) self._origin_mesh = mb.build() disallowed_area_height = 0.1 disallowed_area_size = 0 if self._disallowed_areas: mb = MeshBuilder() color = Color(0.0, 0.0, 0.0, 0.15) for polygon in self._disallowed_areas: points = polygon.getPoints() first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) previous_point = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) for point in points: new_point = Vector(self._clamp(point[0], min_w, max_w), disallowed_area_height, self._clamp(point[1], min_d, max_d)) mb.addFace(first, previous_point, new_point, color = color) previous_point = new_point # Find the largest disallowed area to exclude it from the maximum scale bounds. # This is a very nasty hack. This pretty much only works for UM machines. # This disallowed area_size needs a -lot- of rework at some point in the future: TODO if numpy.min(points[:, 1]) >= 0: # This filters out all areas that have points to the left of the centre. This is done to filter the skirt area. size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1])) else: size = 0 disallowed_area_size = max(size, disallowed_area_size) self._disallowed_area_mesh = mb.build() else: self._disallowed_area_mesh = None if self._error_areas: mb = MeshBuilder() for error_area in self._error_areas: color = Color(1.0, 0.0, 0.0, 0.5) points = error_area.getPoints() first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) previous_point = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) for point in points: new_point = Vector(self._clamp(point[0], min_w, max_w), disallowed_area_height, self._clamp(point[1], min_d, max_d)) mb.addFace(first, previous_point, new_point, color=color) previous_point = new_point self._error_mesh = mb.build() else: self._error_mesh = None self._volume_aabb = AxisAlignedBox( minimum = Vector(min_w, min_h - 1.0, min_d), maximum = Vector(max_w, max_h - self._raft_thickness, max_d)) bed_adhesion_size = self._getEdgeDisallowedSize() # As this works better for UM machines, we only add the disallowed_area_size for the z direction. # This is probably wrong in all other cases. TODO! # The +1 and -1 is added as there is always a bit of extra room required to work properly. scale_to_max_bounds = AxisAlignedBox( minimum = Vector(min_w + bed_adhesion_size + 1, min_h, min_d + disallowed_area_size - bed_adhesion_size + 1), maximum = Vector(max_w - bed_adhesion_size - 1, max_h - self._raft_thickness, max_d - disallowed_area_size + bed_adhesion_size - 1) ) Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds
class SetTransformOperation(Operation.Operation): ## Creates the transform operation. # # Careful! No real input checking is done by this function. If you'd # provide other transformations than respectively translation, orientation # and scale in place for the translation, orientation and scale matrices, # it could get confused. # # \param node The scene node to transform. # \param translation A translation matrix to move the node with. # \param orientation An orientation matrix to rotate the node with. # \param scale A scaling matrix to resize the node with. def __init__(self, node, translation = None, orientation = None, scale = None, shear = None, mirror = None): super().__init__() self._node = node self._old_translation = node.getPosition() self._old_orientation = node.getOrientation() self._old_scale = node.getScale() self._old_shear = node.getShear() self._old_transformation = node.getWorldTransformation() if translation: self._new_translation = translation else: self._new_translation = node.getPosition() if orientation: self._new_orientation = orientation else: self._new_orientation = node.getOrientation() if scale: self._new_scale = scale else: self._new_scale = node.getScale() if shear: self._new_shear = shear else: self._new_shear = node.getShear() if mirror: self._new_mirror = mirror else: # Scale will either be negative or positive. If it's negative, we need to use the inverse mirror. if self._node.getScale().x < 0: self._new_mirror = Vector(-node.getMirror().x, -node.getMirror().y, -node.getMirror().z) else: self._new_mirror = node.getMirror() self._new_transformation = Matrix() euler_orientation = self._new_orientation.toMatrix().getEuler() self._new_transformation.compose(scale = self._new_scale, shear = self._new_shear, angles = euler_orientation, translate = self._new_translation, mirror = self._new_mirror) ## Undoes the transformation, restoring the node to the old state. def undo(self): self._node.setTransformation(self._old_transformation) ## Re-applies the transformation after it has been undone. def redo(self): self._node.setTransformation(self._new_transformation) ## Merges this operation with another TransformOperation. # # This prevents the user from having to undo multiple operations if they # were not his operations. # # You should ONLY merge this operation with an older operation. It is NOT # symmetric. # # \param other The older operation with which to merge this operation. # \return A combination of the two operations, or False if the merge # failed. def mergeWith(self, other): if type(other) is not SetTransformOperation: return False if other._node != self._node: # Must be on the same node. return False op = SetTransformOperation(self._node) op._old_transformation = other._old_transformation op._new_transformation = self._new_transformation return op ## Returns a programmer-readable representation of this operation. # # A programmer-readable representation of this operation. def __repr__(self): return "SetTransformOperation(node = {0})".format(self._node)
def _rebuild(self): if not self._build_volume._width or not self._build_volume._height or not self._build_volume._depth: return if not self._build_volume._engine_ready: return if not self._build_volume._volume_outline_color: theme = Application.getInstance().getTheme() self._build_volume._volume_outline_color = Color( *theme.getColor("volume_outline").getRgb()) self._build_volume._x_axis_color = Color( *theme.getColor("x_axis").getRgb()) self._build_volume._y_axis_color = Color( *theme.getColor("y_axis").getRgb()) self._build_volume._z_axis_color = Color( *theme.getColor("z_axis").getRgb()) self._build_volume._disallowed_area_color = Color( *theme.getColor("disallowed_area").getRgb()) self._build_volume._error_area_color = Color( *theme.getColor("error_area").getRgb()) ### START PATCH # Get a dict from the machine metadata optionally overriding the build volume # Note that CuraEngine is blissfully unaware of this; it is just what the user is shown in Cura limit_buildvolume = self._build_volume._global_container_stack.getMetaDataEntry( "limit_buildvolume", {}) if not isinstance(limit_buildvolume, dict): limit_buildvolume = {} min_w = limit_buildvolume.get("width", {}).get("minimum", -self._build_volume._width / 2) max_w = limit_buildvolume.get("width", {}).get("maximum", self._build_volume._width / 2) min_h = limit_buildvolume.get("height", {}).get("minimum", 0.0) max_h = limit_buildvolume.get("height", {}).get("maximum", self._build_volume._height) min_d = limit_buildvolume.get("depth", {}).get("minimum", -self._build_volume._depth / 2) max_d = limit_buildvolume.get("depth", {}).get("maximum", self._build_volume._depth / 2) ### END PATCH z_fight_distance = 0.2 # Distance between buildplate and disallowed area meshes to prevent z-fighting if self._build_volume._shape != "elliptic": # Outline 'cube' of the build volume mb = MeshBuilder() mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, max_h, min_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, min_h, max_d), Vector(max_w, min_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, min_h, max_d), Vector(min_w, max_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, max_h, max_d), Vector(max_w, max_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(max_w, min_h, max_d), Vector(max_w, max_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, min_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, min_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, max_h, min_d), Vector(min_w, max_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(max_w, max_h, min_d), Vector(max_w, max_h, max_d), color=self._build_volume._volume_outline_color) self._build_volume.setMeshData(mb.build()) # Build plate grid mesh mb = MeshBuilder() mb.addQuad(Vector(min_w, min_h - z_fight_distance, min_d), Vector(max_w, min_h - z_fight_distance, min_d), Vector(max_w, min_h - z_fight_distance, max_d), Vector(min_w, min_h - z_fight_distance, max_d)) for n in range(0, 6): v = mb.getVertex(n) mb.setVertexUVCoordinates(n, v[0], v[2]) self._build_volume._grid_mesh = mb.build() else: # Bottom and top 'ellipse' of the build volume aspect = 1.0 scale_matrix = Matrix() if self._build_volume._width != 0: # Scale circular meshes by aspect ratio if width != height aspect = self._build_volume._depth / self._build_volume._width scale_matrix.compose(scale=Vector(1, 1, aspect)) mb = MeshBuilder() mb.addArc(max_w, Vector.Unit_Y, center=(0, min_h - z_fight_distance, 0), color=self._build_volume._volume_outline_color) mb.addArc(max_w, Vector.Unit_Y, center=(0, max_h, 0), color=self._build_volume._volume_outline_color) self._build_volume.setMeshData( mb.build().getTransformed(scale_matrix)) # Build plate grid mesh mb = MeshBuilder() mb.addVertex(0, min_h - z_fight_distance, 0) mb.addArc(max_w, Vector.Unit_Y, center=Vector(0, min_h - z_fight_distance, 0)) sections = mb.getVertexCount( ) - 1 # Center point is not an arc section indices = [] for n in range(0, sections - 1): indices.append([0, n + 2, n + 1]) mb.addIndices(numpy.asarray(indices, dtype=numpy.int32)) mb.calculateNormals() for n in range(0, mb.getVertexCount()): v = mb.getVertex(n) mb.setVertexUVCoordinates(n, v[0], v[2] * aspect) self._build_volume._grid_mesh = mb.build().getTransformed( scale_matrix) # Indication of the machine origin if self._build_volume._global_container_stack.getProperty( "machine_center_is_zero", "value"): origin = (Vector(min_w, min_h, min_d) + Vector(max_w, min_h, max_d)) / 2 else: origin = Vector(min_w, min_h, max_d) mb = MeshBuilder() mb.addCube(width=self._build_volume._origin_line_length, height=self._build_volume._origin_line_width, depth=self._build_volume._origin_line_width, center=origin + Vector(self._build_volume._origin_line_length / 2, 0, 0), color=self._build_volume._x_axis_color) mb.addCube(width=self._build_volume._origin_line_width, height=self._build_volume._origin_line_length, depth=self._build_volume._origin_line_width, center=origin + Vector(0, self._build_volume._origin_line_length / 2, 0), color=self._build_volume._y_axis_color) mb.addCube(width=self._build_volume._origin_line_width, height=self._build_volume._origin_line_width, depth=self._build_volume._origin_line_length, center=origin - Vector(0, 0, self._build_volume._origin_line_length / 2), color=self._build_volume._z_axis_color) self._build_volume._origin_mesh = mb.build() disallowed_area_height = 0.1 disallowed_area_size = 0 if self._build_volume._disallowed_areas: mb = MeshBuilder() color = self._build_volume._disallowed_area_color for polygon in self._build_volume._disallowed_areas: points = polygon.getPoints() if len(points) == 0: continue first = Vector( self._build_volume._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._build_volume._clamp(points[0][1], min_d, max_d)) previous_point = Vector( self._build_volume._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._build_volume._clamp(points[0][1], min_d, max_d)) for point in points: new_point = Vector( self._build_volume._clamp(point[0], min_w, max_w), disallowed_area_height, self._build_volume._clamp(point[1], min_d, max_d)) mb.addFace(first, previous_point, new_point, color=color) previous_point = new_point # Find the largest disallowed area to exclude it from the maximum scale bounds. # This is a very nasty hack. This pretty much only works for UM machines. # This disallowed area_size needs a -lot- of rework at some point in the future: TODO if numpy.min( points[:, 1] ) >= 0: # This filters out all areas that have points to the left of the centre. This is done to filter the skirt area. size = abs( numpy.max(points[:, 1]) - numpy.min(points[:, 1])) else: size = 0 disallowed_area_size = max(size, disallowed_area_size) self._build_volume._disallowed_area_mesh = mb.build() else: self._build_volume._disallowed_area_mesh = None if self._build_volume._error_areas: mb = MeshBuilder() for error_area in self._build_volume._error_areas: color = self._build_volume._error_area_color points = error_area.getPoints() first = Vector( self._build_volume._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._build_volume._clamp(points[0][1], min_d, max_d)) previous_point = Vector( self._build_volume._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._build_volume._clamp(points[0][1], min_d, max_d)) for point in points: new_point = Vector( self._build_volume._clamp(point[0], min_w, max_w), disallowed_area_height, self._build_volume._clamp(point[1], min_d, max_d)) mb.addFace(first, previous_point, new_point, color=color) previous_point = new_point self._build_volume._error_mesh = mb.build() else: self._build_volume._error_mesh = None self._build_volume._volume_aabb = AxisAlignedBox( minimum=Vector(min_w, min_h - 1.0, min_d), maximum=Vector( max_w, max_h - self._build_volume._raft_thickness - self._build_volume._extra_z_clearance, max_d)) bed_adhesion_size = self._build_volume.getEdgeDisallowedSize() # As this works better for UM machines, we only add the disallowed_area_size for the z direction. # This is probably wrong in all other cases. TODO! # The +1 and -1 is added as there is always a bit of extra room required to work properly. scale_to_max_bounds = AxisAlignedBox( minimum=Vector( min_w + bed_adhesion_size + 1, min_h, min_d + disallowed_area_size - bed_adhesion_size + 1), maximum=Vector( max_w - bed_adhesion_size - 1, max_h - self._build_volume._raft_thickness - self._build_volume._extra_z_clearance, max_d - disallowed_area_size + bed_adhesion_size - 1)) Application.getInstance().getController().getScene( )._maximum_bounds = scale_to_max_bounds self._build_volume.updateNodeBoundaryCheck()
class SetTransformOperation(Operation.Operation): ## Creates the transform operation. # # Careful! No real input checking is done by this function. If you'd # provide other transformations than respectively translation, orientation # and scale in place for the translation, orientation and scale matrices, # it could get confused. # # \param node The scene node to transform. # \param translation A translation matrix to move the node with. # \param orientation An orientation matrix to rotate the node with. # \param scale A scaling matrix to resize the node with. def __init__(self, node, translation = None, orientation = None, scale = None, shear = None, mirror = None): super().__init__() self._node = node self._old_translation = node.getPosition() self._old_orientation = node.getOrientation() self._old_scale = node.getScale() self._old_shear = node.getShear() self._old_transformation = node.getWorldTransformation() if translation: self._new_translation = translation else: self._new_translation = node.getPosition() if orientation: self._new_orientation = orientation else: self._new_orientation = node.getOrientation() if scale: self._new_scale = scale else: self._new_scale = node.getScale() if shear: self._new_shear = shear else: self._new_shear = node.getShear() self._new_mirror = Vector(1, 1, 1) self._new_transformation = Matrix() euler_orientation = self._new_orientation.toMatrix().getEuler() self._new_transformation.compose(scale = self._new_scale, shear = self._new_shear, angles = euler_orientation, translate = self._new_translation, mirror = self._new_mirror) ## Undoes the transformation, restoring the node to the old state. def undo(self): self._node.setTransformation(self._old_transformation) ## Re-applies the transformation after it has been undone. def redo(self): self._node.setTransformation(self._new_transformation) ## Merges this operation with another TransformOperation. # # This prevents the user from having to undo multiple operations if they # were not his operations. # # You should ONLY merge this operation with an older operation. It is NOT # symmetric. # # \param other The older operation with which to merge this operation. # \return A combination of the two operations, or False if the merge # failed. def mergeWith(self, other): if type(other) is not SetTransformOperation: return False if other._node != self._node: # Must be on the same node. return False op = SetTransformOperation(self._node) op._old_transformation = other._old_transformation op._new_transformation = self._new_transformation return op ## Returns a programmer-readable representation of this operation. # # A programmer-readable representation of this operation. def __repr__(self): return "SetTransformOp.(node={0})".format(self._node)