forked from fieldOfView/Cura-MeasureTool
-
Notifications
You must be signed in to change notification settings - Fork 0
/
MeasurePass.py
98 lines (75 loc) · 3.7 KB
/
MeasurePass.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# Copyright (c) 2021 Aldo Hoeben / fieldOfView
# MeasureTool is released under the terms of the AGPLv3 or higher.
from typing import Optional, TYPE_CHECKING
import os.path
from math import inf
from cura.CuraApplication import CuraApplication
from UM.Resources import Resources
from UM.View.RenderPass import RenderPass
from UM.View.GL.OpenGL import OpenGL
from UM.View.RenderBatch import RenderBatch
from UM.Math.Matrix import Matrix
from UM.Math.Vector import Vector
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
if TYPE_CHECKING:
from UM.View.GL.ShaderProgram import ShaderProgram
## A RenderPass subclass that renders a the distance of selectable objects from the active camera to a texture.
# The texture is used to map a 2d location (eg the mouse location) to a world space position
#
# Note that in order to increase precision, the 24 bit depth value is encoded into all three of the R,G & B channels
class MeasurePass(RenderPass):
def __init__(self, width: int, height: int, axis: int) -> None:
super().__init__("picking", width, height)
self._axis = axis
self._renderer = CuraApplication.getInstance().getRenderer()
self._shader = None # type: Optional[ShaderProgram]
self._scene = CuraApplication.getInstance().getController().getScene()
def render(self) -> None:
if not self._shader:
self._shader = OpenGL.getInstance().createShaderProgram(
os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"resources",
"shaders",
"coordinates.shader",
)
)
self._shader.setUniformValue("u_axisId", self._axis)
width, height = self.getSize()
self._gl.glViewport(0, 0, width, height)
self._gl.glClearColor(1.0, 1.0, 1.0, 0.0)
self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT)
# Create a new batch to be rendered
batch = RenderBatch(self._shader)
# Fill up the batch with objects that can be sliced. `
for node in DepthFirstIterator(self._scene.getRoot()): # type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
if (
node.callDecoration("isSliceable")
and node.getMeshData()
and node.isVisible()
):
batch.addItem(node.getWorldTransformation(), node.getMeshData())
z_fight_distance = 0.2 # Distance between buildplate and disallowed area meshes to prevent z-fighting
buildplate_transform = Matrix()
buildplate_transform.setToIdentity()
buildplate_transform.translate(Vector(0, z_fight_distance, 0))
buildplate_mesh = CuraApplication.getInstance().getBuildVolume()._grid_mesh
batch.addItem(buildplate_transform, buildplate_mesh)
self.bind()
batch.render(self._scene.getActiveCamera())
self.release()
## Get the distance in mm from the camera to at a certain pixel coordinate.
def getPickedCoordinate(self, x: int, y: int) -> float:
output = self.getOutput()
window_size = self._renderer.getWindowSize()
px = (0.5 + x / 2.0) * window_size[0]
py = (0.5 + y / 2.0) * window_size[1]
if px < 0 or px > (output.width() - 1) or py < 0 or py > (output.height() - 1):
return inf
value = output.pixel(px, py) # value in micron, from in r, g & b channels
if value == 0x00FFFFFF:
return inf
value = (
(value & 0x00FFFFFF) - 0x00800000
) / 1000.0 # drop the alpha channel, correct for signedness and covert to mm
return value