mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-08 07:27:29 -06:00
CURA-4425 the thumbnail now crops correctly
This commit is contained in:
parent
a3ed385259
commit
0e7edc3eaf
2 changed files with 24 additions and 52 deletions
|
@ -17,11 +17,16 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
|||
|
||||
|
||||
class Snapshot:
|
||||
## Return a QImage of the scene
|
||||
# Uses PreviewPass that leaves out some elements
|
||||
# Aspect ratio assumes a square
|
||||
@staticmethod
|
||||
def snapshot(width = 300, height = 300):
|
||||
scene = Application.getInstance().getController().getScene()
|
||||
active_camera = scene.getActiveCamera()
|
||||
render_width, render_height = active_camera.getWindowSize()
|
||||
render_width = int(render_width)
|
||||
render_height = int(render_height)
|
||||
preview_pass = PreviewPass(render_width, render_height)
|
||||
|
||||
root = scene.getRoot()
|
||||
|
@ -29,7 +34,6 @@ class Snapshot:
|
|||
|
||||
# determine zoom and look at
|
||||
bbox = None
|
||||
hulls = None
|
||||
for node in DepthFirstIterator(root):
|
||||
if type(node) == ConvexHullNode:
|
||||
print(node)
|
||||
|
@ -38,16 +42,12 @@ class Snapshot:
|
|||
bbox = node.getBoundingBox()
|
||||
else:
|
||||
bbox = bbox + node.getBoundingBox()
|
||||
convex_hull = node.getMeshData().getConvexHullTransformedVertices(node.getWorldTransformation())
|
||||
if hulls is None:
|
||||
hulls = convex_hull
|
||||
else:
|
||||
hulls = numpy.concatenate((hulls, convex_hull), axis = 0)
|
||||
|
||||
if bbox is None:
|
||||
bbox = AxisAlignedBox()
|
||||
|
||||
look_at = bbox.center
|
||||
# guessed size so the objects are hopefully big
|
||||
size = max(bbox.width, bbox.height, bbox.depth * 0.5)
|
||||
|
||||
# Somehow the aspect ratio is also influenced in reverse by the screen width/height
|
||||
|
@ -56,56 +56,27 @@ class Snapshot:
|
|||
projection_matrix.setPerspective(30, render_width / render_height, 1, 500)
|
||||
camera.setProjectionMatrix(projection_matrix)
|
||||
|
||||
# Looking from this direction (x, y, z) in OGL coordinates
|
||||
looking_from_offset = Vector(1, 1, 2)
|
||||
if size > 0:
|
||||
# determine the watch distance depending on the size
|
||||
looking_from_offset = looking_from_offset * size * 1.3
|
||||
camera.setViewportSize(render_width, render_height)
|
||||
camera.setWindowSize(render_width, render_height)
|
||||
camera.setPosition(look_at + looking_from_offset)
|
||||
camera.lookAt(look_at)
|
||||
|
||||
# we need this for the projection calculation
|
||||
hulls4 = numpy.ones((hulls.shape[0], 4))
|
||||
hulls4[:, :-1] = hulls
|
||||
#position = Vector(10, 10, 10)
|
||||
# projected_position = camera.project(position)
|
||||
|
||||
preview_pass.setCamera(camera)
|
||||
preview_pass.setSize(render_width, render_height) # texture size
|
||||
preview_pass.render()
|
||||
pixel_output = preview_pass.getOutput()
|
||||
|
||||
print("Calculating image coordinates...")
|
||||
view = camera.getWorldTransformation().getInverse()
|
||||
min_x, max_x, min_y, max_y = render_width, 0, render_height, 0
|
||||
for hull_coords in hulls4:
|
||||
projected_position = view.getData().dot(hull_coords)
|
||||
projected_position2 = projection_matrix.getData().dot(projected_position)
|
||||
#xx, yy = camera.project(Vector(data = hull_coords))
|
||||
# xx, yy range from -1 to 1
|
||||
xx = projected_position2[0] / projected_position2[2] / 2.0
|
||||
yy = projected_position2[1] / projected_position2[2] / 2.0
|
||||
# x, y 0..render_width/height
|
||||
x = int(render_width / 2 + xx * render_width / 2)
|
||||
y = int(render_height / 2 + yy * render_height / 2)
|
||||
min_x = min(x, min_x)
|
||||
max_x = max(x, max_x)
|
||||
min_y = min(y, min_y)
|
||||
max_y = max(y, max_y)
|
||||
print(min_x, max_x, min_y, max_y)
|
||||
|
||||
# print("looping all pixels in python...")
|
||||
# min_x_, max_x_, min_y_, max_y_ = render_width, 0, render_height, 0
|
||||
# for y in range(int(render_height)):
|
||||
# for x in range(int(render_width)):
|
||||
# color = pixel_output.pixelColor(x, y)
|
||||
# if color.alpha() > 0:
|
||||
# min_x_ = min(x, min_x_)
|
||||
# max_x_ = max(x, max_x_)
|
||||
# min_y_ = min(y, min_y_)
|
||||
# max_y_ = max(y, max_y_)
|
||||
# print(min_x_, max_x_, min_y_, max_y_)
|
||||
# Look at the resulting image to get a good crop.
|
||||
# Get the pixels as byte array
|
||||
pixel_array = pixel_output.bits().asarray(pixel_output.byteCount())
|
||||
# Convert to numpy array, assume it's 32 bit (it should always be)
|
||||
pixels = numpy.frombuffer(pixel_array, dtype=numpy.uint8).reshape([render_height, render_width, 4])
|
||||
# Find indices of non zero pixels
|
||||
nonzero_pixels = numpy.nonzero(pixels)
|
||||
min_y, min_x, min_a_ = numpy.amin(nonzero_pixels, axis=1)
|
||||
max_y, max_x, max_a_ = numpy.amax(nonzero_pixels, axis=1)
|
||||
|
||||
# make it a square
|
||||
if max_x - min_x >= max_y - min_y:
|
||||
|
@ -114,11 +85,12 @@ class Snapshot:
|
|||
else:
|
||||
# make x bigger
|
||||
min_x, max_x = int((max_x + min_x) / 2 - (max_y - min_y) / 2), int((max_x + min_x) / 2 + (max_y - min_y) / 2)
|
||||
copy_pixel_output = pixel_output.copy(min_x, min_y, max_x - min_x, max_y - min_y)
|
||||
cropped_image = pixel_output.copy(min_x, min_y, max_x - min_x, max_y - min_y)
|
||||
|
||||
# Scale it to the correct height
|
||||
image = copy_pixel_output.scaledToHeight(height, QtCore.Qt.SmoothTransformation)
|
||||
# Then chop of the width
|
||||
cropped_image = image.copy(image.width() // 2 - width // 2, 0, width, height)
|
||||
# Scale it to the correct size
|
||||
scaled_image = cropped_image.scaled(
|
||||
width, height,
|
||||
aspectRatioMode = QtCore.Qt.IgnoreAspectRatio,
|
||||
transformMode = QtCore.Qt.SmoothTransformation)
|
||||
|
||||
return cropped_image
|
||||
return scaled_image
|
||||
|
|
|
@ -23,7 +23,7 @@ class UFPWriter(MeshWriter):
|
|||
def _createSnapshot(self, *args):
|
||||
# must be called from the main thread because of OpenGL
|
||||
Logger.log("d", "Creating thumbnail image...")
|
||||
self._snapshot = Snapshot.snapshot()
|
||||
self._snapshot = Snapshot.snapshot(width = 300, height = 300)
|
||||
|
||||
def write(self, stream, nodes, mode = MeshWriter.OutputMode.BinaryMode):
|
||||
archive = VirtualFile()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue