123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- # Copyright (c) 2015 Ultimaker B.V.
- # Cura is released under the terms of the AGPLv3 or higher.
- from UM.View.Renderer import Renderer
- from UM.Scene.SceneNode import SceneNode
- from UM.Application import Application
- from UM.Resources import Resources
- from UM.Mesh.MeshData import MeshData
- from UM.Mesh.MeshBuilder import MeshBuilder
- from UM.Math.Vector import Vector
- from UM.Math.Color import Color
- from UM.Math.AxisAlignedBox import AxisAlignedBox
- from UM.Math.Polygon import Polygon
- import numpy
- class BuildVolume(SceneNode):
- VolumeOutlineColor = Color(12, 169, 227, 255)
- def __init__(self, parent = None):
- super().__init__(parent)
- self._width = 0
- self._height = 0
- self._depth = 0
- self._material = None
- self._grid_mesh = None
- self._grid_material = None
- self._disallowed_areas = []
- self._disallowed_area_mesh = None
- self.setCalculateBoundingBox(False)
- self._active_profile = None
- self._active_instance = None
- Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveInstanceChanged)
- self._onActiveInstanceChanged()
- Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
- self._onActiveProfileChanged()
- def setWidth(self, width):
- if width: self._width = width
- def setHeight(self, height):
- if height: self._height = height
- def setDepth(self, depth):
- if depth: self._depth = depth
- def getDisallowedAreas(self):
- return self._disallowed_areas
- def setDisallowedAreas(self, areas):
- self._disallowed_areas = areas
- def render(self, renderer):
- if not self.getMeshData():
- return True
- if not self._material:
- self._material = renderer.createMaterial(
- Resources.getPath(Resources.Shaders, "basic.vert"),
- Resources.getPath(Resources.Shaders, "vertexcolor.frag")
- )
- self._grid_material = renderer.createMaterial(
- Resources.getPath(Resources.Shaders, "basic.vert"),
- Resources.getPath(Resources.Shaders, "grid.frag")
- )
- self._grid_material.setUniformValue("u_gridColor0", Color(245, 245, 245, 255))
- self._grid_material.setUniformValue("u_gridColor1", Color(205, 202, 201, 255))
- renderer.queueNode(self, material = self._material, mode = Renderer.RenderLines)
- renderer.queueNode(self, mesh = self._grid_mesh, material = self._grid_material, force_single_sided = True)
- if self._disallowed_area_mesh:
- renderer.queueNode(self, mesh = self._disallowed_area_mesh, material = self._material, transparent = True)
- return True
- def rebuild(self):
- if self._width == 0 or self._height == 0 or self._depth == 0:
- 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
- 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.getData())
- mb = MeshBuilder()
- mb.addQuad(
- Vector(min_w, min_h, min_d),
- Vector(max_w, min_h, min_d),
- Vector(max_w, min_h, max_d),
- Vector(min_w, min_h, max_d)
- )
- self._grid_mesh = mb.getData()
- for n in range(0, 6):
- v = self._grid_mesh.getVertex(n)
- self._grid_mesh.setVertexUVCoordinates(n, v[0], v[2])
- disallowed_area_height = 0.2
- 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
- size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1]))
- disallowed_area_size = max(size, disallowed_area_size)
- self._disallowed_area_mesh = mb.getData()
- else:
- self._disallowed_area_mesh = None
- self._aabb = AxisAlignedBox(minimum = Vector(min_w, min_h - 1.0, min_d), maximum = Vector(max_w, max_h, max_d))
- skirt_size = 0.0
- profile = Application.getInstance().getMachineManager().getActiveProfile()
- if profile:
- skirt_size = self._getSkirtSize(profile)
- scale_to_max_bounds = AxisAlignedBox(
- minimum = Vector(min_w + skirt_size, min_h, min_d + skirt_size + disallowed_area_size),
- maximum = Vector(max_w - skirt_size, max_h, max_d - skirt_size - disallowed_area_size)
- )
- Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds
- def _onActiveInstanceChanged(self):
- self._active_instance = Application.getInstance().getMachineManager().getActiveMachineInstance()
- if self._active_instance:
- self._width = self._active_instance.getMachineSettingValue("machine_width")
- self._height = self._active_instance.getMachineSettingValue("machine_height")
- self._depth = self._active_instance.getMachineSettingValue("machine_depth")
- self._updateDisallowedAreas()
- self.rebuild()
- def _onActiveProfileChanged(self):
- if self._active_profile:
- self._active_profile.settingValueChanged.disconnect(self._onSettingValueChanged)
- self._active_profile = Application.getInstance().getMachineManager().getActiveProfile()
- if self._active_profile:
- self._active_profile.settingValueChanged.connect(self._onSettingValueChanged)
- self._updateDisallowedAreas()
- self.rebuild()
- def _onSettingValueChanged(self, setting):
- if setting in self._skirt_settings:
- self._updateDisallowedAreas()
- self.rebuild()
- def _updateDisallowedAreas(self):
- if not self._active_instance or not self._active_profile:
- return
- disallowed_areas = self._active_instance.getMachineSettingValue("machine_disallowed_areas")
- areas = []
- skirt_size = 0.0
- if self._active_profile:
- skirt_size = self._getSkirtSize(self._active_profile)
- if disallowed_areas:
- for area in disallowed_areas:
- poly = Polygon(numpy.array(area, numpy.float32))
- poly = poly.getMinkowskiHull(Polygon(numpy.array([
- [-skirt_size, 0],
- [-skirt_size * 0.707, skirt_size * 0.707],
- [0, skirt_size],
- [skirt_size * 0.707, skirt_size * 0.707],
- [skirt_size, 0],
- [skirt_size * 0.707, -skirt_size * 0.707],
- [0, -skirt_size],
- [-skirt_size * 0.707, -skirt_size * 0.707]
- ], numpy.float32)))
- areas.append(poly)
- if skirt_size > 0:
- half_machine_width = self._active_instance.getMachineSettingValue("machine_width") / 2
- half_machine_depth = self._active_instance.getMachineSettingValue("machine_depth") / 2
- areas.append(Polygon(numpy.array([
- [-half_machine_width, -half_machine_depth],
- [-half_machine_width, half_machine_depth],
- [-half_machine_width + skirt_size, half_machine_depth - skirt_size],
- [-half_machine_width + skirt_size, -half_machine_depth + skirt_size]
- ], numpy.float32)))
- areas.append(Polygon(numpy.array([
- [half_machine_width, half_machine_depth],
- [half_machine_width, -half_machine_depth],
- [half_machine_width - skirt_size, -half_machine_depth + skirt_size],
- [half_machine_width - skirt_size, half_machine_depth - skirt_size]
- ], numpy.float32)))
- areas.append(Polygon(numpy.array([
- [-half_machine_width, half_machine_depth],
- [half_machine_width, half_machine_depth],
- [half_machine_width - skirt_size, half_machine_depth - skirt_size],
- [-half_machine_width + skirt_size, half_machine_depth - skirt_size]
- ], numpy.float32)))
- areas.append(Polygon(numpy.array([
- [half_machine_width, -half_machine_depth],
- [-half_machine_width, -half_machine_depth],
- [-half_machine_width + skirt_size, -half_machine_depth + skirt_size],
- [half_machine_width - skirt_size, -half_machine_depth + skirt_size]
- ], numpy.float32)))
- self._disallowed_areas = areas
- def _getSkirtSize(self, profile):
- skirt_size = 0.0
- adhesion_type = profile.getSettingValue("adhesion_type")
- if adhesion_type == "skirt":
- skirt_distance = profile.getSettingValue("skirt_gap")
- skirt_line_count = profile.getSettingValue("skirt_line_count")
- skirt_size = skirt_distance + (skirt_line_count * profile.getSettingValue("skirt_line_width"))
- elif adhesion_type == "brim":
- brim_line_count = profile.getSettingValue("brim_line_count")
- skirt_size = brim_line_count * profile.getSettingValue("skirt_line_width")
- elif adhesion_type == "raft":
- skirt_size = profile.getSettingValue("raft_margin")
- if profile.getSettingValue("draft_shield_enabled"):
- skirt_size += profile.getSettingValue("draft_shield_dist")
- skirt_size += profile.getSettingValue("xy_offset")
- return skirt_size
- def _clamp(self, value, min_value, max_value):
- return max(min(value, max_value), min_value)
- _skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_line_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist", "xy_offset"]
|