pygame-ce icon indicating copy to clipboard operation
pygame-ce copied to clipboard

Border radius for pygame.draw.polygon (resolves #1527)

Open ezzakri-anas opened this issue 1 year ago • 8 comments
trafficstars

This pull request resolves the enhancement issue #1527 (previously #3011) about implementing the border radius for pygame.draw.polygon

Overview

  • Added a new parameter border_radius to the pygame.draw.polygon function to specify the border radius of the rounded polygon corners.
  • Updated the list of keywords in pygame.draw.polygon to include "border_radius" in the function signature.
  • Added a new function draw_round_polygon to handle the drawing of rounded polygons. This function takes care of the logic for calculating rounded corners.
  • Integrated this function as a part of polygon in draw.c.

Geometry Calculations:

  • Implemented various geometric calculation functions, such as find_parallel_line, project_point_onto_segment, and intersection(to calculate intersections between two lines), angle, side ….

draw_round_polygon Function:

**static void draw_round_polygon(SDL_Surface *surf, int *pts_x, int pts_y, int radius, int num_points, Uint32 color, int drawn_area)

Purpose:

This function is responsible for drawing a rounded polygon with a specified border radius. It calculates and draws circular segments at each corner of the polygon. Parameters:

  • surf: The target surface to draw on.
  • pts_x: Array of x-coordinates of polygon vertices.
  • pts_y: Array of y-coordinates of polygon vertices.
  • border_radius: The border radius of the rounded corners.
  • num_points: Number of vertices in the polygon.
  • color: Color of the polygon.
  • drawn_area: Array to store the bounding box of the drawn area.

Details:

Path calculation loop:

  • Coordinate Initialization: Initializes arrays and structures to store calculated points and circles.
  • Parallel Line Calculation: The find_parallel_line function calculates two parallel lines given three points: the current vertex and its adjacent vertices. The function ensures that the parallel lines are on the correct side of the vertex.
  • Circle and Path Calculation: The center of the circular segment is found by calculating the intersection of two parallel lines (line1 and line2) using the intersection function.
  • The circular arc's starting and ending points are obtained by projecting the center onto adjacent line segments using the project_point_onto_segment function.
  • Stores these points in the path array.

Drawing loop:

  • For each segment in the path array, it calculates start and end angles and draws the circular arc using the draw_arc function.
  • Draws a straight line between consecutive circular arcs.

Debugging Output:

  • During the calculation loop, if three consecutive points are aligned the loop is interrupted with a return statement to abort the function.
  • A condition on the border_radius is verified on each vertex, at each iteration, to avoid incorrect drawing. if the condition is not satisfied the function is aborted.
  • As the draw_round_polygon function returns void (a choice made to align with the same logic of other drawing functions), it is not possible to raise an error directly from draw_round_polygon. Instead, we settle for a return statement whenever an error should be raised to abort the function, and a printf of the error message.

ezzakri-anas avatar Dec 17 '23 21:12 ezzakri-anas

If you need to raise exceptions from your helper function, I would suggest making it return -1 on failure and 0 on success (as Python C API functions do for the most part). Before returning -1, you can call PyErr_SetString with the appropriate exception type (seemingly PyExc_ValueError) and the message and then return -1; Then in the "main" polygon function, check for == -1 and return NULL;

Matiiss avatar Dec 18 '23 22:12 Matiiss

You have to add a bunch of explicit casts: image

itzpr3d4t0r avatar Dec 19 '23 11:12 itzpr3d4t0r

I've implemented the test cases for rounded polygons within separate functions inside the DrawPolygonMixin class. I'm not sure if this aligns with your preferences or if you would prefer them in a different class. Also,polygon.draw.arc function lacks tests to ensure accurate arc rendering. Given this, I'm unsure if testing the rounded polygons for correct rounding is coherent, as the function uses polygon.draw.arc for drawing the roundness. Any suggestions or guidance on this matter would be appreciated.

ezzakri-anas avatar Dec 24 '23 20:12 ezzakri-anas

I've implemented the test cases for rounded polygons within separate functions inside the DrawPolygonMixin class. I'm not sure if this aligns with your preferences or if you would prefer them in a different class. Also,polygon.draw.arc function lacks tests to ensure accurate arc rendering. Given this, I'm unsure if testing the rounded polygons for correct rounding is coherent, as the function uses polygon.draw.arc for drawing the roundness. Any suggestions or guidance on this matter would be appreciated.

I think it's fine if they are in that class. As for arc tests, that will have to be added in a different PR. You can still check for rounded corners with your polygon though, because it also does a bit of implicit arc testing which just adds extra tests as a safety measure pretty much. Testing is one of those places where redundancy is fine.

Matiiss avatar Dec 25 '23 14:12 Matiiss

I've implemented the test cases for rounded polygons within separate functions inside the DrawPolygonMixin class. I'm not sure if this aligns with your preferences or if you would prefer them in a different class. Also,polygon.draw.arc function lacks tests to ensure accurate arc rendering. Given this, I'm unsure if testing the rounded polygons for correct rounding is coherent, as the function uses polygon.draw.arc for drawing the roundness. Any suggestions or guidance on this matter would be appreciated.

I think it's fine if they are in that class. As for arc tests, that will have to be added in a different PR. You can still check for rounded corners with your polygon though, because it also does a bit of implicit arc testing which just adds extra tests as a safety measure pretty much. Testing is one of those places where redundancy is fine.

In this context, is it necessary to test for the precise radius of roundness, or would it suffice to confirm that the corners are indeed rounded?

ezzakri-anas avatar Dec 25 '23 15:12 ezzakri-anas

I don't get why the circleci failed while all i did is just add some tests.

ezzakri-anas avatar Dec 27 '23 17:12 ezzakri-anas

That is not your PRs fault, don't worry. It was a separate issue that has been fixed now

ankith26 avatar Jan 02 '24 17:01 ankith26

Hi @ezzakri-anas , do you want to revive this PR ?

bilhox avatar Sep 28 '24 12:09 bilhox