Skip to content

Add drawing shape interface to World#712

Open
tigercosmos wants to merge 1 commit intosolvcon:masterfrom
tigercosmos:2d_drawing_api_design_0405
Open

Add drawing shape interface to World#712
tigercosmos wants to merge 1 commit intosolvcon:masterfrom
tigercosmos:2d_drawing_api_design_0405

Conversation

@tigercosmos
Copy link
Copy Markdown
Collaborator

@tigercosmos tigercosmos commented Apr 5, 2026

Summary

Add shape CRUD management directly into World. All method bodies are stubs (throw runtime_error) — this PR defines the interface only.

Shape hierarchy (C++ templates in World.hpp)

Shape<T> is the abstract base. All shapes live on z=0 using Point3d<T> for rendering pipeline compatibility. Concrete shapes:

  • Polygon — closed, arbitrary vertex list (>=3)
  • Rectangle — axis-aligned, defined by (x, y, width, height)
  • Triangle — 3 vertices
  • Circle — center + radius, approximated as n-gon
  • Line — single segment between two points
  • Polyline — open path (>=2 vertices)
  • Ellipse — center + semi-axes, approximated as n-gon

CRUD on World

Op Methods
Create add_shape(), add_rectangle(), add_circle(), add_line(), add_triangle(), add_polygon(), add_polyline(), add_ellipse() — returns int32_t shape ID
Read get_shape(id) — by ID; shapes — all shapes; nshape — count
Update Via shape object: translate(dx, dy), scale(factor, cx, cy), rotate(angle_deg, cx, cy)
Delete remove_shape(id), clear_shapes()

Usage

world = mm.WorldFp64()

world.add_rectangle(x=0, y=0, width=10, height=5)
shape = world.get_shape(0)
shape.translate(dx=5, dy=3)
all_shapes = world.shapes  # list of all managed shapes

widget.updateWorld(world)

Files changed

File What
World.hpp Shape classes + World shape CRUD
wrap_World.cpp pybind11 bindings (shapes + World)
core.py Export shape types
test_pilot_drawing.py Tests (xfail — stubs only)

Test plan

  • make builds successfully
  • pre-commit passes (clang-format, flake8, ascii, trailing whitespace)
  • Shape polymorphism verified (isinstance(RectangleFp64(...), ShapeFp64) is True)
  • tests/test_pilot_drawing.py — 4 tests, all xfail (stubs throw, as expected)
  • Existing tests unaffected

🤖 Generated with Claude Code

Copy link
Copy Markdown
Collaborator Author

@tigercosmos tigercosmos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Key design points highlighted inline.

@tigercosmos tigercosmos force-pushed the 2d_drawing_api_design_0405 branch 3 times, most recently from 09422f7 to a7742d6 Compare April 5, 2026 14:03
@tigercosmos tigercosmos marked this pull request as ready for review April 5, 2026 15:12
@tigercosmos
Copy link
Copy Markdown
Collaborator Author

@yungyuc Please take a look. Thank you.

Copy link
Copy Markdown
Member

@yungyuc yungyuc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not look right. World is the canvas. It is not necessary to have another class inside World for creating geometry objects.

And it is called World so that the geometry objects do not have to be in a surface, but can be in a space. The World is part of the universe module. While we do not have a Universe container yet, it may be a future extension to hold multiple World.

And it is not correct to postfix the names to the geometry entities with 2D (although d should be lower-cased per the naming convention, it is not the point). Polygons, rectangles, triangles, circles, polylines, ellipses are all 2D entities.

The 3d postfix we have for Point, Segment, etc., meant the entities are in 3D space.

I am moving this PR to draft for you to follow up.

@yungyuc yungyuc added the geometry Geometry entities and manipulation label Apr 6, 2026
@yungyuc yungyuc moved this from Todo to In Progress in pilot 2D drawing basic GUI Apr 6, 2026
@yungyuc yungyuc marked this pull request as draft April 6, 2026 08:36
@tigercosmos tigercosmos force-pushed the 2d_drawing_api_design_0405 branch from a7742d6 to a56c683 Compare April 6, 2026 14:37
@tigercosmos tigercosmos changed the title Add the interface design for 2D drawing API Add drawing shape interface to World Apr 6, 2026
@tigercosmos tigercosmos force-pushed the 2d_drawing_api_design_0405 branch 2 times, most recently from 4e8f208 to 4a5b559 Compare April 6, 2026 14:45
*
* All concrete shapes must implement the pure-virtual methods below. Shapes
* live on the z = 0 plane; Point3d is used for compatibility with the
* existing rendering pipeline.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shape base class: Abstract base for all shapes managed by World. Concrete shapes implement draw(World&) to emit segments, plus translate/scale/rotate for the Update part of CRUD (transforms are called on the shape object, not through World).

// -- shapes -------------------------------------------------------------

/// Add a pre-built shape. Returns the assigned ID.
int32_t add_shape(shape_ptr shape)
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

World shape CRUD: Createadd_shape() and typed helpers (add_rectangle, add_circle, etc.) return an int32_t ID. Readget_shape(id), nshape. Update — via shape methods (translate/scale/rotate). Deleteremove_shape(id), clear_shapes(). Storage is unordered_map<int32_t, shape_ptr> with sequential IDs for O(1) average lookup.


template <typename T>
class MODMESH_PYTHON_WRAPPER_VISIBILITY WrapPolygon
: public WrapBase<WrapPolygon<T>, Polygon<T>, std::shared_ptr<Polygon<T>>, Shape<T>>
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pybind11 inheritance: Concrete shape wrappers pass Shape<T> as the 4th WrapBase template arg so pybind11 registers the C++ inheritance hierarchy. This enables polymorphic returns from get_shape() and correct isinstance() checks in Python.

'WorldFp32',
'WorldFp64',
'ShapeFp32',
'ShapeFp64',
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shape types exported here so they are accessible as modmesh.ShapeFp64, modmesh.RectangleFp64, etc.

@tigercosmos tigercosmos force-pushed the 2d_drawing_api_design_0405 branch from 4a5b559 to 516884a Compare April 6, 2026 14:56
Integrate shape management directly into World instead of a
separate Canvas2D wrapper, per review feedback.  Shape classes
(Polygon, Rectangle, Triangle, Circle, Line, Polyline, Ellipse)
are defined in World.hpp without the "2D" suffix — these entities
are inherently 2D.  World gains add_*/get_shape/remove_shape/
clear_shapes methods for shape CRUD.

All method bodies are stubs (throw runtime_error) — this defines
the interface only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@tigercosmos tigercosmos force-pushed the 2d_drawing_api_design_0405 branch from 516884a to 1778bd5 Compare April 6, 2026 15:04
@tigercosmos tigercosmos marked this pull request as ready for review April 6, 2026 16:35
@tigercosmos
Copy link
Copy Markdown
Collaborator Author

@yungyuc I have update the interface design based on the review. Please take a look, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

geometry Geometry entities and manipulation

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants