Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SimpleSets: basic implementation #46

Merged
merged 41 commits into from
Oct 8, 2024
Merged

Conversation

Yvee1
Copy link
Contributor

@Yvee1 Yvee1 commented Oct 1, 2024

This PR implements the basis of SimpleSets.

Changes made to core and renderer:

  • Added ExactWithSqrt and Rectangle (for iso rectangle 2) type aliases.
  • Allow lambda functions that receive a renderer to be used as paintings.
  • Add nextPage method to the ipe renderer, so that when called new added paintings are drawn on a new page
  • Add Color constructor that takes a single integer. Intended to be used with hexadecimal literals, e.g. 0xffffff.

TODO:

  • Work around CGAL bug: Arrangement insert throws bad_get CGAL/cgal#8468
  • Handle edges of dilated patterns that overlap
  • Smooth cutouts
  • Fix code that draws shapes in a stacking order if possible, useful when wanting to import and/or modify the shapes later.
  • Add proper Qt GUI?
  • (Handle holes, I think this is only needed when allowing banks to bend more than 180 degrees in one direction, or when using patterns not created via the SimpleSets partitioning algorithm. So more of an extra.)

Yvee1 and others added 29 commits August 13, 2024 17:54
Note: for this to work in CLion, the working directory needs to be set to the project directory in the run configuration.
cartocrow/core/core.h Outdated Show resolved Hide resolved
cartocrow/simplesets/cat_point.h Outdated Show resolved Hide resolved
#include "function_painting.h"

namespace cartocrow::renderer {
FunctionPainting::FunctionPainting(const std::function<void(GeometryRenderer&)>& draw_function)
Copy link
Member

@Willem3141 Willem3141 Oct 3, 2024

Choose a reason for hiding this comment

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

I think I don't grok the purpose of a FunctionPainting. One can already make an ad-hoc painting by subclassing GeometryPainting, for example:

    class SomePainting : public GeometryPainting {
        void paint(GeometryRenderer& renderer) const override {
            renderer.draw(/* whatever you want to draw */);
        }
    };
    IpeRenderer renderer(std::make_shared<SomePainting>());

I guess with FunctionPainting slightly less code is needed:

    IpeRenderer renderer(std::make_shared<FunctionPainting>([]() {
        renderer.draw(/* whatever you want to draw */);
    }));

but I'm not sure if the added complexity is worth it?

Anyway, did I miss a use case where using FunctionPainting would be significantly easier?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would not use FunctionPainting on its own, but use the helper function (or the implicitly converting constructor that you suggest below).
Then you go from:

class SomePainting : public GeometryPainting {
    void paint(GeometryRenderer& renderer) const override {
        renderer.draw(/* whatever you want to draw */);
    }
};
renderer.addPainting(std::make_shared<SomePainting>());

to

renderer.addPainting([](GeometryRenderer& renderer) {
    renderer.draw(/* whatever you want to draw */);
});

I don't have a specific use case in mind that is way simpler this way, I added it only as a more concise way of drawing something simple. For me, having to create a class, derive from a specific other one, and override one specific method, in order to draw something is boiler plate and an obstacle when programming. Generally I would also define this painting class in a header, and have the implementation in the cpp file, though I see your point that you can also define it locally just in the cpp file. Part of the reason that I find this much simpler is probably that I'm more used to functional programming than object oriented programming.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

An argument for adding this: a lambda function makes it easy to capture variables that are in scope. When debugging a function, I sometimes use IpeRenderer together with a lambda function to draw some debug info and save it to a file.

@@ -680,6 +682,11 @@ void GeometryWidget::addPainting(std::shared_ptr<GeometryPainting> painting, con
updateLayerList();
}

void GeometryWidget::addPainting(const std::function<void(renderer::GeometryRenderer&)>& draw_function, const std::string& name) {
Copy link
Member

Choose a reason for hiding this comment

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

(see comment about FunctionPainting above) I'm also not a huge fan of having to do this in every renderer 🤔

Copy link
Member

@Willem3141 Willem3141 Oct 3, 2024

Choose a reason for hiding this comment

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

To avoid this while keeping FunctionPainting we may provide an (implicitly converting) constructor from std::function<void(renderer::GeometryRenderer&)> to FunctionPainting?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did not think of that.
That does mean you cannot do

renderer.addPainting([](GeometryRenderer& renderer) {
    renderer.draw(/* whatever you want to draw */);
});

because you need to still create a shared pointer, which I would like to avoid having to do.

cartocrow/renderer/ipe_renderer.h Outdated Show resolved Hide resolved
cartocrow/simplesets/drawing_algorithm.cpp Outdated Show resolved Hide resolved
data/nyc.txt Outdated Show resolved Hide resolved
demos/simplesets/colors.cpp Outdated Show resolved Hide resolved
demos/simplesets/circle_convex_hull.cpp Outdated Show resolved Hide resolved
@Yvee1
Copy link
Contributor Author

Yvee1 commented Oct 3, 2024

We should at some point look into what helper functions can go into core.

I have some helpers for arrangements that can be useful in general: connected components of faces in an arrangement (in particular circulators for going over the outer and inner boundaries of the component); extracting a general polygon from a circulator.
Also for circle_segment_traits curves, polylines and polygons I have various helper functions, and a helper for computing the convex hull of disks.
Then there is a helper function for computing the intersection/difference between a (general) polyline and a (general) polygon.

@Willem3141 Willem3141 merged commit 3c80a8a into tue-alga:master Oct 8, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants