-
Notifications
You must be signed in to change notification settings - Fork 275
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
Voronoi diagrams #692
Voronoi diagrams #692
Conversation
I just made sure there aren't any potential merge conflicts |
...And now the option has been added, along with the relevant captions and comments for translators |
`VoronoiSettings`
Not leaving the ordering of non-leading component to chance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks cool!
I left a few comments from doing some initial testing. Please also add a unit test for this too when ready :)
|
||
Span<ColorBgra> dst_data = dst.GetPixelData (); | ||
|
||
for (int y = roi.Top; y <= roi.Bottom; y++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The effect is non-fileable because of CreateSettings
, correct? This loop could still be done in parallel for better performance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not only that, there is more to it.
Most effects use the entire canvas as the area where the effect is rendered, and the ROIs as the parts of the area that they have to fill.
On the other hand, in this effect, the ROI is the area, and the calculations are done based on the ROI.
For a more concrete example, open a photo with Pinta, select a rectangle area, and apply the twist effect to it. The center of the twist won't be the center of the selection, but the center of the canvas.
Maybe we should re-engineer the rendering and the tileability mechanisms now that the rendering API can still be changed, and adapt the algorithms so that they can act on either the entire canvas or the overall ROI (while still being executable in parallel).
Also, just to clarify, I understand what you mean: once we have the list of points and the list of colors, the color of each pixel in the rendering can be calculated independently, which means it can all be done in parallel. That much is clear... I just think it's essential to address the other part of it as well.
I dare say that we could delay the plugin feature by one release if that means that we get the API right. The current one is just very limited, and just like support for non-tileable effects required a change in the API, I am sure there are many other things that just are not possible as of now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that the API probably needs further thought to solve this in a better way.
For now I'd suggest still adding a Parallel.For loop to improve performance - the only downside is just that it won't be able to hook into the live preview to incrementally render tiles as they're completed.
FYI the next Pinta release is hopefully not too far away - basically once #674 is figured out I plan to start locking things down. There still can be API changes in the future if we decide they're necessary
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's being done with Parallel
now (with some adjustments, as a ReadOnlySpan<T>
cannot be referenced inside a lambda. There is a noticeable speed improvement in my machine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great, yeah it seems much faster on my machine too 👍
PointI pixelLocation = new (x, y); | ||
double shortestDistance = double.MaxValue; | ||
int closestIndex = 0; | ||
for (var i = 0; i < settings.points.Length; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably more something to leave a TODO comment for future work, but adding some acceleration structure here could improve performance when there is a large number of points
|
||
public sealed class VoronoiDiagramData : EffectData | ||
{ | ||
[Caption ("Distance Calculation Method")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest calling this Distance Metric
or Distance Method
to be a bit more concise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went ahead and called it Distance Metric
public DistanceCalculationMethod DistanceCalculationMethod { get; set; } = DistanceCalculationMethod.Euclidean; | ||
|
||
[Caption ("Point Count"), MinimumValue (1), MaximumValue (1024)] | ||
public int PointCount { get; set; } = 100; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would something like Number of Regions
make more sense to a user, since they don't see the point positions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I named it Number of Cells
public int PointCount { get; set; } = 100; | ||
|
||
// Translators: The user can choose whether or not to render the points used in the calculation of a Voronoi diagram | ||
[Caption ("Show Points")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there good use cases for this to be exposed to users? Seems more like a debugging option to me at first glance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be an educational tool, so that they see that the cells are centered around the points, and then it piques their curiosity and then they look it up
public bool ShowPoints { get; set; } = false; | ||
|
||
[Caption ("Color Sorting")] | ||
public ColorSorting ColorSorting { get; set; } = ColorSorting.Random; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might need some more thought on how to present it to the user. The effect is neat, but the huge menu of combinations seems intimidating
The menu may change, but I'll also mention that Random Color Sorting
could just be Random
since it's inside a menu labelled Color Sorting
[Caption ("Reverse Color Sorting")] | ||
public bool ReverseColorSorting { get; set; } = false; | ||
|
||
[Caption ("Colors Seed")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd maybe just call this Random Colors
since the Seed is mentioned by the "Reseed" button underneath, and similar for the other seed below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went ahead and called that Random Colors
, and similarly for the points Random Point Locations
shortestDistance = distance; | ||
closestIndex = i; | ||
} | ||
dst_row[x] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only using the closest point can produce jagged edges, so you may want to consider doing some sort of blending / antialiasing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this would require either changing the algorithm used to make the calculations, or applying some sort edge blur effect (that is not yet developed, as far as I know)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could probably be done easily with supersampling, e.g. compute the color at multiple sub-pixel positions and blend - currently the sampling is done at only the upper left corner of the pixel
Most pixels don't need this though since there are large solid regions, so this could be skipped if there isn't another voronoi point close enough to be the closest to any sub pixel location
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be done in a future PR? A change introduced in this PR (the Utility.GeneratePixelOffsets()
method) is useful for other effects, too, and there's no risk of breaking an API if we add to this effect in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think this is fine to add in a future PR
as per suggestion
This reverts commit 4fa83a6.
Now the merge conflicts have been solved |
👍 I think this looks good, the only thing I'm not sure about is the big menu of color sorting options which still feels pretty awkward to me |
@cameronwhite what changes do you suggest? I could just reduce them to 3 in each direction (r, g, or b horizontally, and the same vertically). Would that work? |
yeah something like that sounds simpler. I'm mostly just worried about it getting even more complicated if we want to add more options in the future |
I've now reduced the number of sortings. As for your last comment, do you mean an outline as in drawing a border around the cells? That is definitely harder than just filling the cells with colors. It's possible that you mean filling the cells with the colors currently in the palette, and that could be done, it's just that it's very likely that at least a pair (or a group) of adjacent cells will have the same color. |
|
||
public enum ColorSorting | ||
{ | ||
[Caption ("Random Color Sorting")] Random, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you change this just to "Random"?
The "color sorting" isn't really necessary since the menu is also called "Color Sorting"
{ | ||
[Caption ("Random Color Sorting")] Random, | ||
|
||
// Translators: Horizontal color sorting with B as the leading term |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this group of comments, could you change phrases like B
to something like blue (B)
?
Translators might not be fully aware of the context of what the individual R/G/B characters mean here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem, it has been done now
That is what I meant, but I agree it would be more work to implement and isn't in the scope of this PR |
Looks good, thanks for working on this! |
Here's with Euclidean distance calculation:
And here's with Manhattan distance calculation:
For now it's only raster-based, but maybe at some point we could add a different algorithm that allows us to draw it based on shapes, and then having Cairo put everything together.
There may be a merge conflict inCoreEffectsExtension
if we were to merge both this one and #457Thank you for adding support for non-tileable effects, which made this possible.