Skip to content
This repository was archived by the owner on Sep 21, 2023. It is now read-only.

Commit e05b414

Browse files
committed
Update with fixed clipping and fill
1 parent 9c84302 commit e05b414

19 files changed

+1129
-134
lines changed

winforms-image-processor/winforms-image-processor/DrawTools/Capsule.cs

+7-2
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ public override int AddPoint(Point point)
3131
return 0;
3232
}
3333

34-
public override List<Point> GetPixels()
34+
public override List<ColorPoint> GetPixels(params object[] param)
3535
{
36-
var points = new List<Point>();
36+
var points = new List<ColorPoint>();
3737

3838
var lowerStart = getAuxPoint(startPoint.Value, endPoint.Value, 1, out double angle1);
3939
var lowerEnd = getAuxPoint(endPoint.Value, startPoint.Value, -1, out double angle2);
@@ -79,5 +79,10 @@ public override string howToDraw()
7979
{
8080
return "Click point 1, point 2 and radius.";
8181
}
82+
83+
public override List<ColorPoint> SetPixelsAA(Bitmap bmp)
84+
{
85+
throw new NotImplementedException();
86+
}
8287
}
8388
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Drawing;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace winforms_image_processor
9+
{
10+
[Serializable]
11+
class ClippedPolygon : Polygon
12+
{
13+
Rectangle boundingRect = new Rectangle(Color.Transparent, 0);
14+
15+
public ClippedPolygon(Color col, int thicc) : base(col, thicc) { }
16+
17+
public ClippedPolygon(Polygon P) : base(P.shapeColor, P.thickness)
18+
{
19+
shapeType = DrawingShape.CPOLY;
20+
supportsAA = true;
21+
points = P.points;
22+
}
23+
24+
public override List<ColorPoint> GetPixels(params object[] param)
25+
{
26+
var pixels = new List<ColorPoint>();
27+
28+
Clipping clipper = new Clipping();
29+
clipper.SetBoundingRectangle(boundingRect);
30+
31+
for (int i = 0; i <= points.Count - 2; i++)
32+
pixels.AddRange(new MidPointLine(shapeColor, thickness, points[i], points[i + 1], clipper).GetPixels());
33+
34+
if (param.Length > 0 && (bool)param[0])
35+
pixels.AddRange(boundingRect.GetPixels());
36+
37+
if (filler != null)
38+
pixels.AddRange(filler.FillPoints());
39+
40+
return pixels;
41+
}
42+
43+
public void SetBoundingRect(Rectangle rect)
44+
{
45+
boundingRect = rect;
46+
}
47+
48+
public override string howToDraw()
49+
{
50+
return "Click each point and click on first to finish.";
51+
}
52+
53+
public override string ToString()
54+
{
55+
return "Clipped Polygon";
56+
}
57+
}
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Drawing;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace winforms_image_processor
9+
{
10+
public struct Line
11+
{
12+
public Point Start;
13+
public Point End;
14+
15+
public Line(Point s, Point e)
16+
{
17+
End = e;
18+
Start = s;
19+
}
20+
21+
public override string ToString()
22+
{
23+
return $"{Start.ToString()} && {End.ToString()}";
24+
}
25+
}
26+
27+
class Clipping
28+
{
29+
// https://pastebin.com/NA01gacf
30+
31+
private Point _clipMin, _clipMax;
32+
33+
public IEnumerable<Point> GetBoundingPolygon()
34+
{
35+
yield return _clipMin;
36+
yield return new Point(_clipMax.X, _clipMin.Y);
37+
yield return _clipMax;
38+
yield return new Point(_clipMin.X, _clipMax.Y);
39+
}
40+
41+
public void SetBoundingRectangle(Rectangle rect)
42+
{
43+
_clipMin = rect.GetCorner(3);
44+
_clipMax = rect.GetCorner(1);
45+
}
46+
47+
private delegate bool ClippingHandler(float p, float q);
48+
49+
public bool ClipLine(ref Line line)
50+
{
51+
Point P = line.End - (Size)line.Start;
52+
float tMinimum = 0, tMaximum = 1;
53+
54+
ClippingHandler pqClip = delegate (float directedProjection,
55+
float directedDistance)
56+
{
57+
if (directedProjection == 0)
58+
{
59+
if (directedDistance < 0)
60+
return false;
61+
}
62+
else
63+
{
64+
float amount = directedDistance / directedProjection;
65+
if (directedProjection < 0)
66+
{
67+
if (amount > tMaximum)
68+
return false;
69+
else if (amount > tMinimum)
70+
tMinimum = amount;
71+
}
72+
else
73+
{
74+
if (amount < tMinimum)
75+
return false;
76+
else if (amount < tMaximum)
77+
tMaximum = amount;
78+
}
79+
}
80+
return true;
81+
};
82+
83+
if (pqClip(-P.X, line.Start.X - _clipMin.X))
84+
{
85+
if (pqClip(P.X, _clipMax.X - line.Start.X))
86+
{
87+
if (pqClip(-P.Y, line.Start.Y - _clipMin.Y))
88+
{
89+
if (pqClip(P.Y, _clipMax.Y - line.Start.Y))
90+
{
91+
if (tMaximum < 1)
92+
{
93+
line.End.X = (int)(line.Start.X + tMaximum * P.X);
94+
line.End.Y = (int)(line.Start.Y + tMaximum * P.Y);
95+
}
96+
if (tMinimum > 0)
97+
{
98+
line.Start.X = (int)(line.Start.X + tMinimum * P.X);
99+
line.Start.Y = (int)(line.Start.Y + tMinimum * P.Y);
100+
}
101+
return true;
102+
}
103+
}
104+
}
105+
}
106+
return false;
107+
}
108+
109+
//public bool ClipLine(ref MidPointLine line)
110+
//{
111+
// Point P = line.endPoint.Value - (Size)line.startPoint.Value;
112+
// float tMinimum = 0, tMaximum = 1;
113+
114+
// ClippingHandler pqClip = delegate (float directedProjection,
115+
// float directedDistance)
116+
// {
117+
// if (directedProjection == 0)
118+
// {
119+
// if (directedDistance < 0)
120+
// return false;
121+
// }
122+
// else
123+
// {
124+
// float amount = directedDistance / directedProjection;
125+
// if (directedProjection < 0)
126+
// {
127+
// if (amount > tMaximum)
128+
// return false;
129+
// else if (amount > tMinimum)
130+
// tMinimum = amount;
131+
// }
132+
// else
133+
// {
134+
// if (amount < tMinimum)
135+
// return false;
136+
// else if (amount < tMaximum)
137+
// tMaximum = amount;
138+
// }
139+
// }
140+
// return true;
141+
// };
142+
143+
// if (pqClip(-P.X, line.startPoint.Value.X - _clipMin.X))
144+
// {
145+
// if (pqClip(P.X, _clipMax.X - line.startPoint.Value.X))
146+
// {
147+
// if (pqClip(-P.Y, line.startPoint.Value.Y - _clipMin.Y))
148+
// {
149+
// if (pqClip(P.Y, _clipMax.Y - line.startPoint.Value.Y))
150+
// {
151+
// if (tMaximum < 1)
152+
// line.endPoint = new Point((int)(line.startPoint.Value.X + tMaximum * P.X), (int)(line.startPoint.Value.Y + tMaximum * P.Y));
153+
// if (tMinimum > 0)
154+
// line.startPoint = new Point((int)(line.startPoint.Value.X + tMinimum * P.X), (int)(line.startPoint.Value.Y + tMinimum * P.Y));
155+
// return true;
156+
// }
157+
// }
158+
// }
159+
// }
160+
// return false;
161+
//}
162+
163+
public override string ToString()
164+
{
165+
return "Liang-Barsky algorithm";
166+
}
167+
168+
// This code was implemented by Grishul Eugeny as part of preparation
169+
// to exam in ITMO university
170+
}
171+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Drawing;
5+
using System.Dynamic;
6+
using System.Linq;
7+
using System.Security.Cryptography.X509Certificates;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
using System.Windows;
11+
using System.Windows.Forms;
12+
using Point = System.Drawing.Point;
13+
14+
namespace winforms_image_processor
15+
{
16+
public struct ActiveEdgeTableEntry
17+
{
18+
public double yMax;
19+
public double yMin;
20+
public double mInv;
21+
public double xOfMin;
22+
public double xOfMax;
23+
24+
public ActiveEdgeTableEntry(Point start, Point end)
25+
{
26+
Point lower = start.Y > end.Y ? end : start;
27+
Point higher = start.Y > end.Y ? start : end;
28+
29+
yMax = higher.Y;
30+
yMin = lower.Y;
31+
xOfMax = higher.X;
32+
xOfMin = lower.X;
33+
mInv = (xOfMax - xOfMin) / (yMax - yMin);
34+
}
35+
36+
public ActiveEdgeTableEntry(ActiveEdgeTableEntry aete)
37+
{
38+
yMax = aete.yMax;
39+
yMin = aete.yMin;
40+
xOfMax = aete.xOfMax;
41+
xOfMin = aete.xOfMin + aete.mInv;
42+
mInv = aete.mInv;
43+
}
44+
45+
public override string ToString()
46+
{
47+
return $"{yMin} && {xOfMin} && {yMax} && {xOfMax} && {mInv}";
48+
}
49+
}
50+
51+
class Filler
52+
{
53+
List<ColorPoint> points = null;
54+
55+
List<Point> vertices = new List<Point>();
56+
List<KeyValuePair<int, int>> indicies = new List<KeyValuePair<int, int>>();
57+
List<ActiveEdgeTableEntry> AET = new List<ActiveEdgeTableEntry>();
58+
59+
Color? fillColor;
60+
Bitmap fillImage;
61+
62+
public Filler(List<Point> pVertices, Color? fillColor = null, Bitmap fillImage = null)
63+
{
64+
var dict = new Dictionary<int, int>();
65+
66+
for (int i = 0; i < pVertices.Count; i++)
67+
{
68+
vertices.Add(pVertices[i]);
69+
dict.Add(i, pVertices[i].Y);
70+
}
71+
72+
indicies = dict.OrderBy(x => x.Value).ToList();
73+
74+
this.fillColor = fillColor;
75+
if (fillImage != null)
76+
this.fillImage = fillImage;
77+
}
78+
79+
public void UpdatePoints(List<Point> points)
80+
{
81+
vertices = new List<Point>(points);
82+
}
83+
84+
public List<ColorPoint> FillPoints(Rectangle boundingRect = null)
85+
{
86+
if (this.points != null)
87+
return this.points;
88+
89+
points = new List<ColorPoint>();
90+
91+
int k = 0;
92+
int i = indicies[k].Key;
93+
int y, ymin;
94+
y = ymin = vertices[indicies[0].Key].Y;
95+
int ymax = vertices[indicies[indicies.Count - 1].Key].Y;
96+
97+
int len = vertices.Count;
98+
99+
while (y < ymax)
100+
{
101+
while (vertices[i].Y == y)
102+
{
103+
if (vertices[(i - 1 + len) % len].Y > vertices[i].Y)
104+
AET.Add(new ActiveEdgeTableEntry(vertices[i], vertices[(i - 1 + len) % len]));
105+
106+
if (vertices[(i + 1) % len].Y > vertices[i].Y)
107+
AET.Add(new ActiveEdgeTableEntry(vertices[i], vertices[(i + 1) % len]));
108+
109+
i = indicies[++k].Key;
110+
}
111+
112+
AET.Sort(delegate (ActiveEdgeTableEntry e1, ActiveEdgeTableEntry e2)
113+
{
114+
return e1.xOfMin.CompareTo(e2.xOfMin);
115+
});
116+
117+
for (int t = 0; t < AET.Count; t+=2)
118+
for (int x1 = (int)AET[t].xOfMin; x1 <= AET[(t + 1) % AET.Count].xOfMin; x1++)
119+
{
120+
Color col = fillColor.HasValue ? fillColor.Value : fillImage.GetPixelFast(x1 % fillImage.Width, y % fillImage.Height);
121+
if (boundingRect != null && (x1 > boundingRect.GetCorner(1).X || x1 < boundingRect.GetCorner(0).X || y > boundingRect.GetCorner(0).Y || y < boundingRect.GetCorner(2).Y))
122+
continue;
123+
points.Add(new ColorPoint(col, new Point(x1, y)));
124+
}
125+
126+
++y;
127+
for (int t = 0; t < AET.Count; t++)
128+
{
129+
AET[t] = new ActiveEdgeTableEntry(AET[t]);
130+
if (AET[t].yMax == y)
131+
AET.RemoveAt(t--);
132+
}
133+
134+
}
135+
136+
return points;
137+
}
138+
}
139+
}

0 commit comments

Comments
 (0)