ReportLab Scale Canvas after Drawing (Fit to Page) - python

With the Python ReportLab library's canvas, the paradigm seems to be to apply transforms before drawing your primitives.
My desire is to scale what I've already drawn to fit the page size.
The problem is that I cannot know the extents of the drawn objects until I have drawn it entirely. This is because the input for drawing objects is a stream, which does not expose the maximum extents beforehand.
Right now, I have to:
Draw my objects
Check their extents
In a new canvas, set the scale to fit the extents to the page size
Draw objects again
In some cases, the object drawing can take a few seconds. And doing this twice really feels burdensome.
Is there any way to do this faster?

Related

Rotate pie chart in interactive window without replotting

I am drawing a pie chart out of provided data, and this can potentially get out of hand as the length of the labels can be pretty long, and there can be a lot of them overlapping each other. Because of this, it is crucial to find a good startangle parameter to my pie chart drawing.
Conceptually, I want to use a mouse scroll event to rotate the whole pie chart by 5 degrees every time the user uses the scroll wheel. Rotating the wedges isn't too much trouble with their theta1 and theta2 properties, but repositioning the labels and autotexts is serious trouble because of alignment properties and the lining up with wedges. I also want to retain an interactive frame rate, so clearing the figure and redrawing is not an option.
Here is one such situation where this is useful. The labels are too big and rotating the whole pie chart would help reposition them in sight. Of course in this case it would be enough to resize the chart instead of rotating but you get my point.
Is there a way to achieve this that does not imply rewriting the entire label and autotext positioning code for my own use?
In particular, I'm wondering if it wouldn't be possible to do something that is conceptually equivalent to making the same pyplot.pie call as before, only with a different startangle. Alternatively, maybe Text objects have methods I can use for positioning them around the newly rotated wedges that spare me working with just positions and sizes.

Zelle graphics: Access and Manipulate Display Buffer?

I am doing 2D graphics using graphics.py. I wonder if there is a way I can access the display buffer after all the 2D geometries are drawn and before they show up on display. I need to do a post process on the drawn image. For example, tasks I am planning include anti-aliasing for a smoother transition on the edge and applying a geometry warp map for a correct projection on a curved screen, etc. Can anyone tell me how to access the display buffer? If I have to go down to tkinter Canvas, will it work and how?

Pygame Large Surfaces

I'm drawing a map of a real world floor with dimensions roughly 100,000mm x 200,000mm.
My initial code contained a function that converted any millimeter based position to screen positioning using the window size of my pygame map, but after digging through some of the pygame functions, I realized that the pygame transformation functions are quite powerful.
Instead, I'd like to create a surface that is 1:1 scale of real world and then scale it right before i blit it to the screen.
Is this the right way to be doing this? I get an error that says Width or Height too large. Is this a limit of pygame?
I dont fully understand your question, but to attempt to answer it here is the following.
No you should not fully draw to the screen then scale it. This is the wrong approach. You should tile very large surfaces and only draw the relevant tiles. If you need a very large view, you should use a scaled down image (pre-scaled). Probably because the amount of memory required to draw an extremely large surface is prohibitive, and scaling it will be slow.
Convert the coordinates to the tiled version using some sort of global matrix that scales everything to the size you expect. So you should also filter out sprites that are not visible by testing their inclusion inside the bounding box of your view port. Keep track of your view port position. You will be able to calculate where in the view port each sprite should be located based on its "world" coordinates.
If your map is not dynamic, I would suggest draw a map outside the game and load it in game.
If you plan on converting the game environment into a map, It might be difficult for a large environment. 100,000mm x 200,000mm is a very large area when converting into a pixels. I would suggest you to scale it down before loading.
As for scaling in-game, you can use pygame.transform.rotozoom or pygame.transform.smoothscale.
Also like the first answer mentions, scaling can take significant memory and time for very large images. Scaling a very large image to a very small image can make the image incomprehensible.

Remove border around image in Pygame

I have got some surfaces in Pygame with a transparent background. They're all the same size. But there's a different sized circle drawn on each of them, so the circle doesn't exactly fit the image.
Here are some example images (I took a screenshot in Photoshop so you can clearly see the transparency and the size of the images):
Now I want to remove the transparent border around the image so the circle exactly fits into the image. I don't want the surface to be circle shaped, I don't think that's possible, but I want that the surface doesn't have blank columns on the left and right and that it doesn't have any blank rows on the top and the bottom. The wanted results:
The circle on the surfaces changes size every frame so I have to recalculate the new surfaces every frame.
I already Googled it, but I haven't found anything for Pygame surfaces yet. I also tried making my own function but it looks ugly and much worse: the framerate drops from 50 (if I don't call the function) to 30 fps (if I do call the function). I tested it a little bit and I found out that smaller circles take longer to process than bigger circles. How can I do this, but faster. If you want I can show the function I made.
The surface object has a method called get_bounding_rect which is where we will start. The function returns the smallest rect possible which contains all of the non-transparent pixels on the surface.
pixel_rect = image.get_bounding_rect()
With the size of this rect, we can create a new surface:
trimmed_surface = pygame.Surface(pixel_rect.size)
Now blit the portion of image contained within pixel_rect onto trimmed_surface:
trimmed_surface.blit(image, (0,0), pixel_rect)
At this point, trimmed_surface should be a surface the same size as pixel_rect, with the unwanted transparent rows and columns "trimmed" off of the original surface.
Documentation for Surface.get_bounding_rect: http://www.pygame.org/docs/ref/surface.html#Surface.get_bounding_rect

Rotating a glViewport?

In a "multitouch" environement, any application showed on a surface can be rotated/scaled to the direction of an user. Actual solution is to drawing the application on a FBO, and draw a rotated/scaled rectangle with the texture on it. I don't think it's good for performance, and all graphics cards don't provide FBO.
The idea is to clip the rendering viewport in the direction of user.
Since glViewport cannot be used for that, is another way exist to achieve that ?
(glViewport use (x, y, width, height), and i would like (x, y, width, height, rotation from center?))
PS: rotating the modelview or projection matrix will not help, i would like to "rotate the clipping plan" generated by glViewport. (only part of the all scene).
There's no way to have a rotated viewport in OpenGL, you have to handle it manually. I see the following possible solutions :
Keep on using textures, perhaps using glCopyTexSubImage instead of FBOs, as this is basic OpenGL feature. If your target platforms are hardware accelerated, performance should be ok, depending on the number of viewports you need on your desk, as this is a very common use case nowadays.
Without textures, you could setup your glViewport to the screen-aligned bounding rectangle (rA) of your rotated viewport (rB) (setting also proper scissor testing area). Then draw a masking area, possibly only in depth or stencil buffer, filling the (rA - rB) area, that will prevent further drawing on those pixels. Then draw normally your application, using a glRotate to adjust you projection matrix, so that the rendering is properly oriented according to rB.
If you already have the code set up to render your scene, try adding a glRotate() call to the viewmodel matrix setup, to "rotate the camera" before rendering the scene.

Categories

Resources