That puts a burden on the programmer.
O_o
(I'm reading that as "client" because a programmer would be responsible in any event.)
No. It does not.
*shrug*
In fact, you almost certainly knew that statement was wrong when you wrote it.
You are obviously limiting your imagination in a "knee jerk" reaction to my suggesting that the "image cutting with shapes" example is a poor case for inheritance based polymorphisms.
Anyone can define a triangle, octogon, circle, pie wedge, etc using simple code.
What makes you think the solution has to be classes to yield "Anyone can define a new shape using simple code."?
Using a simple interface to build a complex object with a familiar utility interface is easier than building a complex object which must provide a simple interface without such a familiar utility interface to rely upon when your algorithms understand the complexity by repeated application of the simple objects. Granted, this holds true for classes just as much without classes; the only difference being the "where" of the implementation code as surely the underlying primitives and algorithm must still be provided, but certainly, you don't need inheritance based polymorphisms even if you chose classes as an implementation strategy.
If all these things have to be specified by lists of Beziers it's much harder to program, unless you really know what you're doing.
Well, that is obviously true, but also obviously an aspect of simply being far more generic and cubic Bézier splines being more complex shapes.
If you, later, worry about performance, you could also provide pixel, triangle and ellipsoid based data polymorphisms which, between the three, covers everything that can be drawn with very good communicability (fewer bytes used to build a shape) and algorithm performance (less complexity to process an image from data that is known to represent a series of triangles instead of triangles built from cubic Bézier splines).
Also Beziers are rather difficult for artists to enter and control in GUIs.
You've never actually used a vector drawing program have you?
Even primitive vector drawing tools have a simple "drag control points around the canvas" approach which could not possibly be simpler to use.
Enjoy: SVG Cubic Bézier Curve Example
"Adobe Illustrator" has an epic level pen tool with "convert to path" and "path to Bézier curve" options which could not simpler or really, I think, more powerful.
Of course, getting them from drawing program to your code isn't seamless, but thanks to "SVG" is very "doable".
Also, for shapes which can be based on triangles, the Bézier curves would be fixed, strait lines greatly simplifying the ease of implementing such complexity over lines and ultimately over Bézier curves. In other words, using existing shapes to create new shapes, but of course, this applies to inheritance based polymorphisms if you do the job well.
Remember we're cutting a shape out of an image. 90% of that time that will probably be an axis-aligned bounding box.
You seem to be under the impression I suggested that one shouldn't have convenient utilities.
I said nothing of the sort. I'm only suggesting that one needs no class hierarchy to do the exact same job with the same convenience, utility, and mechanism the class hierarchy would accomplish with a very similar interface making the example a poor choice for showing where inheritance polymorphisms shine.
The first example block is using inheritance based polymorphisms to do the job of "cutting a shaped image from an image".
The second example block is using data based polymorphisms to do the job of "cutting a shaped image from an image".
As you see from the example, the convenience of complex shapes is available to a client regardless; in fact, I would consider that issue, more available tools which are simple to use, a "quality of implementation" issue being completely unrelated to the method of interface.
Here, I consider the use of templates to be poor just as much as the inheritance based solution; I'm only using invoking the standard container for the sake of simplicity as the examples are already bloated for such a simple discussion.
Soma
Code:
// Implementation
typedef /**/ SColor;
// ...
class SScanline
{
// ...
SColor getPixel
(
size_t fOffset
);
// ...
};
// ...
class IImage
{
// ...
SScanline getScanline
(
size_t fOffset
);
// ...
};
// ...
class IShape
{
// ...
virtual IImage * cut
(
IImage * fImage
);
// ...
};
// ...
class STriangle:
public IShape
{
// ...
virtual IImage * cut
(
IImage * fImage
)
{
// Use `getScanline' and `getPixel' to obtain pixel within the target zone.
}
// ...
};
// Client
void Go() // This is not meaningfully different.
{
IShape * sShape(new STriangle(/*position, rotation, scale, whatever*/));
IImage * sImage(new PNGImage("filename.png"));
IImage * sResult(sShape->cut(sImage));
}
Code:
// Implementation
// data polymorphisms communicating "béziergon":
// double gShape[] =
// {
// begin_x, begin_y // start of spline and curve 1 {P0}
// , ctr1_1_x, ctr1_1_y // curve 1 control point 1 {P1}
// , ctr1_2_x, ctr1_2_y // curve 1 control point 2 {P2}
// , /* ... */, /* ... */
// , nxtN_x, nxtN_y // end of curve N closing to (begin_x, begin_y) {P3/PN}
// , ctrN_1_x, ctrN_2_y // curve N control point 1 closing to (begin_x, begin_y) {PN+1}
// , ctrN_1_x, ctrN_2_y // curve N control point 2 closing to (begin_x, begin_y) {PN+1}
// };
std::vector<double> CraftSquare(/*position, rotation, scale, whatever*/)
{
std::vector<double> sResult(12);
// fill with {P0,P1,P2,P3, /**/, P12}
return(sResult);
}
// ...
grid<color> CutImage
(
grid<color> & fSource
, std::vector<double> & fBeziergon
)
{
grid<color> sResult;
// Use grid to obtain pixel within the target zone.
return(sResult);
}
// Client
void Go() // This is not meaningfully different.
{
std::vector<double> sShape(CraftSquare(/*position, rotation, scale, whatever*/));
grid<color> sImage(PNGImage("filename.png"));
grid<color> sResult(CutImage(sImage, sShape));
}