Designing a shape object class in C#
-
Given a large number of shapes that can be defined by vertices and edges how would you design the class structure for that?
-
Given a large number of shapes that can be defined by vertices and edges how would you design the class structure for that?
Hi, i happen to be working on a shape library for WinForms C# right now; i'll eventually publish it here, but, can't predict when. Let me offer some general ideas: 1) choice of Framework is important: a lot depends on what you want to do with your shapes. my usage is for custom ring design; for example, i need to calculate equally spaced points along a path like an oval, and that point's tangent (requires calculus); i deal primarily with polygons, circles and ellipses; my goal is to have mock-ups i can take to my manufacturers. so, i'm not concerned with 3d rendering on screen, texturing, etc. and i'm not concerned with interacting with selecting/moving/duplicating shapes on-screen as you expect in a drawing program, 2) for other purposes, like the ones i just said i'm not concerned with, WPF offers a superior graphics engine and facilities; and, for 3d; use Unity. if you do need to select/move/duplicate/dock etc., shapes on-screen: don't use WinForms, use WPF. 3) the interface i am using now: the use of System.Windows requires your WinForm project to have a reference to WindowsBase.dll
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows;using SdPoint = System.Drawing.Point;
using SwPoint = System.Windows.Point;
using SdSize = System.Drawing.Size;
using SwSize = System.Windows.Size;using GraphicsPath = System.Drawing.Drawing2D.GraphicsPath;
using GReg = System.Drawing.Region;
using GMat2d = System.Drawing.Drawing2D.Matrix;
using GMatMed = System.Windows.Media.Matrix;namespace GeomLib_August_2021_III
{
public enum ShapeType
{
Line,
Arc,
Rectangle,
Parallelogram,
Circle,
Ellipse,
RegPolygon,
IrregPolygon,
Grid,
Star
}public interface IShape { string ShpName { get; } string ShpComment { get; } DateTime ShpTimeStamp { get; } ShapeType ShpType { get; } Rect SwRect { get; } SwPoint CenterF { get; } SwPoint\[\] PathPoints { get; } double GetArea(); double GetPerimeter(); SwPoint GetCenter(); GraphicsPath GetGPath(); Region GetRegion(); IShape GetUnion(IShape s1, IShape s2); IShape GetIntersection(IShape s1, IShape s2); IShape Translate(IShape s1, Matrix m1); IShape Rotate(IShape s1, Matrix m1); IShape Scale(IShape s1, Matrix m1); SwPoint\[\] Flatten(); void Ren
-
Given a large number of shapes that can be defined by vertices and edges how would you design the class structure for that?
I find that "super" controls that you can morph at run time (color, scale, content) are more manageable than trying to build things from lots of primitives. You need a "focus"; e.g. military units already have many predefined shapes and derivatives. In architecture, there are door, window, etc. "patterns".
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it. ― Confucian Analects: Rules of Confucius about his food
-
Hi, i happen to be working on a shape library for WinForms C# right now; i'll eventually publish it here, but, can't predict when. Let me offer some general ideas: 1) choice of Framework is important: a lot depends on what you want to do with your shapes. my usage is for custom ring design; for example, i need to calculate equally spaced points along a path like an oval, and that point's tangent (requires calculus); i deal primarily with polygons, circles and ellipses; my goal is to have mock-ups i can take to my manufacturers. so, i'm not concerned with 3d rendering on screen, texturing, etc. and i'm not concerned with interacting with selecting/moving/duplicating shapes on-screen as you expect in a drawing program, 2) for other purposes, like the ones i just said i'm not concerned with, WPF offers a superior graphics engine and facilities; and, for 3d; use Unity. if you do need to select/move/duplicate/dock etc., shapes on-screen: don't use WinForms, use WPF. 3) the interface i am using now: the use of System.Windows requires your WinForm project to have a reference to WindowsBase.dll
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows;using SdPoint = System.Drawing.Point;
using SwPoint = System.Windows.Point;
using SdSize = System.Drawing.Size;
using SwSize = System.Windows.Size;using GraphicsPath = System.Drawing.Drawing2D.GraphicsPath;
using GReg = System.Drawing.Region;
using GMat2d = System.Drawing.Drawing2D.Matrix;
using GMatMed = System.Windows.Media.Matrix;namespace GeomLib_August_2021_III
{
public enum ShapeType
{
Line,
Arc,
Rectangle,
Parallelogram,
Circle,
Ellipse,
RegPolygon,
IrregPolygon,
Grid,
Star
}public interface IShape { string ShpName { get; } string ShpComment { get; } DateTime ShpTimeStamp { get; } ShapeType ShpType { get; } Rect SwRect { get; } SwPoint CenterF { get; } SwPoint\[\] PathPoints { get; } double GetArea(); double GetPerimeter(); SwPoint GetCenter(); GraphicsPath GetGPath(); Region GetRegion(); IShape GetUnion(IShape s1, IShape s2); IShape GetIntersection(IShape s1, IShape s2); IShape Translate(IShape s1, Matrix m1); IShape Rotate(IShape s1, Matrix m1); IShape Scale(IShape s1, Matrix m1); SwPoint\[\] Flatten(); void Ren
Good morning Bill. Thanks for posting this code - it's great to see people sharing code like this. I have a couple of comments that I'd like to address. The code sample here has a lot of shorthand in it so things like
GetGPath
have to be interpreted. Is there a reason why this isn't calledGetGraphicsPath
or justGetPath
? On that note, why have you chosen to implement Get methods over property getters? I'm just curious as to your reasoning here. The Shp properties all feel like they should be in a separate class. Again, it feels to me like these are metadata items, rather than being intrinsic parts of the base interface. I would probably move these out into a separate metadata class and drop the Shp parts of the name. The Union and Intersection methods also appear to be wrong, unless you are looking to determine whether this shape intersects with more than one shape - the first parameter of these methods is probably going to be the current instance so why pass it in? I would expect to see a method that looks more like thisIShape Union(IShape shape);
-
Good morning Bill. Thanks for posting this code - it's great to see people sharing code like this. I have a couple of comments that I'd like to address. The code sample here has a lot of shorthand in it so things like
GetGPath
have to be interpreted. Is there a reason why this isn't calledGetGraphicsPath
or justGetPath
? On that note, why have you chosen to implement Get methods over property getters? I'm just curious as to your reasoning here. The Shp properties all feel like they should be in a separate class. Again, it feels to me like these are metadata items, rather than being intrinsic parts of the base interface. I would probably move these out into a separate metadata class and drop the Shp parts of the name. The Union and Intersection methods also appear to be wrong, unless you are looking to determine whether this shape intersects with more than one shape - the first parameter of these methods is probably going to be the current instance so why pass it in? I would expect to see a method that looks more like thisIShape Union(IShape shape);
Hi Pete, i'm delighted to have feedback like this ! I'll study it carefully, and respond in more detail later. current version calculating equally spaced points points on an ellipse: [^] Context: currently this is very much in initial development, and, "final polishing" may address your concerns about my use of short aliases instead of longer, more mnemonic, names. For unknown reasons, my memory, at age 78, handles such short aliases without cognitive effort (just don't ask me where i left my house keys) ... and, it saves typing time :omg:
Quote:
The Shp properties all feel like they should be in a separate class. Again, it feels to me like these are metadata items, rather than being intrinsic parts of the base interface. I would probably move these out into a separate metadata class and drop the Shp parts of the name.
Excellent points ! As the design progresses, i may "break out" the IShape interface into component interfaces like IIdentity for ShpName, ShpComment, ShpTimeStamp (those i would call "metadata"). Right now, things like SwPoint, CenterF seem essential. "Shp" as prefix: I often "go Hungarian" simply because when i view an object's contents at run-time when a breakpoint is hit, they appear grouped together in the alpha-ordered inspector dropdown, Same idea with public Properties i want exposed in a design-time PropertyGrid. 'Get methods instead of Property getters: somewhere along the line years ago (influenced by Richter ?), i decided to never do extensive calculations, or call external methods, in Properties (except for OnPropertyChanged). That "feels right," and, i believe that contributes to maintainability in the long run ... perhaps i should reevaluate that "habit/decision" ?
Quote:
The Union and Intersection methods also appear to be wrong, unless you are looking to determine whether this shape intersects with more than one shape - the first parameter of these methods is probably going to be the current instance so why pass it in?
As of now, i have not implemented any "current ..." state/object facility. That is something I really like ever since my little career led me into specializing in PostScript. My intent is to take two shape instances as input, and return a new shape which is the intersection/union of the two