Skip to content

Commit cfe8bb6

Browse files
committed
Implemented zoomed/stretched versions of golden spiral / fibonacci rectangles; added simple 'crosshair' grid type
1 parent 30856d3 commit cfe8bb6

File tree

5 files changed

+224
-43
lines changed

5 files changed

+224
-43
lines changed

Src/ScreenGrid.Models/Geometry/Line.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@ public Line(Point p1, Point p2)
88
this.p2 = p2;
99
}
1010

11+
public Line(double x1, double y1, double x2, double y2)
12+
{
13+
this.p1 = new Point(x1, y1);
14+
this.p2 = new Point(x2, y2);
15+
}
16+
1117
public Point p1; // { get; set; }
18+
1219
public Point p2; // { get; set; }
1320
}
1421
}

Src/ScreenGrid.Models/Grids/GridCreator.cs

Lines changed: 157 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,35 @@ public static IEnumerable<Line> CreateGrid(GridType gridType, double width, doub
9090
return new List<Line>();
9191
}
9292

93+
case GridType.Crosshair:
94+
{
95+
const double HorizontalTickLength = (3.0 / 100.0);
96+
const double VerticalTickLength = (1.0 / 30.0);
97+
const double CentralTickLength = (3.0 / 200.0);
98+
99+
var aspect = (width / height);
100+
101+
var points = new[]
102+
{
103+
new Point(RatioConstants.Zero, RatioConstants.Half), new Point(RatioConstants.Zero + HorizontalTickLength, RatioConstants.Half),
104+
new Point(RatioConstants.One, RatioConstants.Half), new Point(RatioConstants.One - HorizontalTickLength, RatioConstants.Half),
105+
new Point(RatioConstants.Half, RatioConstants.One), new Point(RatioConstants.Half, RatioConstants.One - VerticalTickLength),
106+
new Point(RatioConstants.Half, RatioConstants.Zero), new Point(RatioConstants.Half, RatioConstants.Zero + VerticalTickLength),
107+
new Point(RatioConstants.Half - CentralTickLength, RatioConstants.Half), new Point(RatioConstants.Half + CentralTickLength, RatioConstants.Half),
108+
new Point(RatioConstants.Half, RatioConstants.Half - CentralTickLength * aspect), new Point(RatioConstants.Half, RatioConstants.Half + CentralTickLength * aspect),
109+
};
110+
111+
return CreateLines(points);
112+
}
113+
93114
case GridType.Thirds:
94115
{
95116
var points = new[]
96117
{
97-
new Point(0.0, RatioConstants.OneThird), new Point(1.0, RatioConstants.OneThird),
98-
new Point(0.0, RatioConstants.TwoThirds), new Point(1.0, RatioConstants.TwoThirds),
99-
new Point(RatioConstants.OneThird, 0.0), new Point(RatioConstants.OneThird, 1.0),
100-
new Point(RatioConstants.TwoThirds, 0.0), new Point(RatioConstants.TwoThirds, 1.0),
118+
new Point(RatioConstants.Zero, RatioConstants.OneThird), new Point(RatioConstants.One, RatioConstants.OneThird),
119+
new Point(RatioConstants.Zero, RatioConstants.TwoThirds), new Point(RatioConstants.One, RatioConstants.TwoThirds),
120+
new Point(RatioConstants.OneThird, RatioConstants.Zero), new Point(RatioConstants.OneThird, RatioConstants.One),
121+
new Point(RatioConstants.TwoThirds, RatioConstants.Zero), new Point(RatioConstants.TwoThirds, RatioConstants.One),
101122
};
102123

103124
return CreateLines(points);
@@ -107,9 +128,9 @@ public static IEnumerable<Line> CreateGrid(GridType gridType, double width, doub
107128
{
108129
var points = new[]
109130
{
110-
new Point(0.0, 1.0), new Point(1.0, 0.0),
111-
new Point(0.0, 1.0 - (RatioConstants.OneThird / 2.0)), new Point(1.0 - (RatioConstants.OneThird / 2.0), 0.0),
112-
new Point(RatioConstants.OneThird / 2.0, 1.0), new Point(1.0, RatioConstants.OneThird / 2.0),
131+
new Point(RatioConstants.Zero, RatioConstants.One), new Point(RatioConstants.One, RatioConstants.Zero),
132+
new Point(RatioConstants.Zero, RatioConstants.One - (RatioConstants.OneSixth)), new Point(RatioConstants.One - (RatioConstants.OneSixth), RatioConstants.Zero),
133+
new Point(RatioConstants.OneSixth, RatioConstants.One), new Point(RatioConstants.One, RatioConstants.OneSixth),
113134
};
114135

115136
return CreateLines(points);
@@ -119,10 +140,10 @@ public static IEnumerable<Line> CreateGrid(GridType gridType, double width, doub
119140
{
120141
var points = new[]
121142
{
122-
new Point(0.0, RatioConstants.Phi3D8), new Point(1.0, RatioConstants.Phi3D8),
123-
new Point(0.0, RatioConstants.Phi5D8), new Point(1.0, RatioConstants.Phi5D8),
124-
new Point(RatioConstants.Phi3D8, 0.0), new Point(RatioConstants.Phi3D8, 1.0),
125-
new Point(RatioConstants.Phi5D8, 0.0), new Point(RatioConstants.Phi5D8, 1.0),
143+
new Point(RatioConstants.Zero, RatioConstants.Phi3D8), new Point(RatioConstants.One, RatioConstants.Phi3D8),
144+
new Point(RatioConstants.Zero, RatioConstants.Phi5D8), new Point(RatioConstants.One, RatioConstants.Phi5D8),
145+
new Point(RatioConstants.Phi3D8, RatioConstants.Zero), new Point(RatioConstants.Phi3D8, RatioConstants.One),
146+
new Point(RatioConstants.Phi5D8, RatioConstants.Zero), new Point(RatioConstants.Phi5D8, RatioConstants.One),
126147
};
127148

128149
return CreateLines(points);
@@ -131,8 +152,8 @@ public static IEnumerable<Line> CreateGrid(GridType gridType, double width, doub
131152
case GridType.GoldenTriangle:
132153
{
133154
var srcPoints = new List<Point>(6);
134-
srcPoints.Add(new Point(0.0, 0.0));
135-
srcPoints.Add(new Point(1.0, 1.0));
155+
srcPoints.Add(new Point(RatioConstants.Zero, RatioConstants.Zero));
156+
srcPoints.Add(new Point(RatioConstants.One, RatioConstants.One));
136157

137158
// TODO: if ((this.rotation == Rotation.R0) || (this.rotation == Rotation.R180))
138159
{
@@ -159,19 +180,32 @@ public static IEnumerable<Line> CreateGrid(GridType gridType, double width, doub
159180
return CreateLines(srcPoints.ToArray());
160181
}
161182

162-
case GridType.GoldenDiagonal:
183+
case GridType.GoldenDiagonal1:
163184
{
164185
var points = new[]
165186
{
166-
new Point(0.0, 1.0), new Point(1.0, 0.0),
167-
new Point(0.0, 0.0), new Point(RatioConstants.Phi3D8, 1.0),
168-
new Point(RatioConstants.Phi5D8, 0.0), new Point(1.0, 1.0),
187+
new Point(RatioConstants.Zero, RatioConstants.One), new Point(RatioConstants.One, RatioConstants.Zero),
188+
new Point(RatioConstants.Zero, RatioConstants.One), new Point(RatioConstants.Phi3D8, RatioConstants.Zero),
189+
new Point(RatioConstants.Phi5D8, RatioConstants.One), new Point(RatioConstants.One, RatioConstants.Zero),
169190
};
170191

171192
return CreateLines(points);
172193
}
173194

174-
case GridType.FibonacciRectangles:
195+
case GridType.GoldenDiagonal2:
196+
{
197+
var points = new[]
198+
{
199+
new Point(RatioConstants.Zero, RatioConstants.One), new Point(RatioConstants.One, RatioConstants.Zero),
200+
new Point(RatioConstants.Zero, RatioConstants.Zero), new Point(RatioConstants.Phi3D8, RatioConstants.One),
201+
new Point(RatioConstants.Phi5D8, RatioConstants.Zero), new Point(RatioConstants.One, RatioConstants.One),
202+
};
203+
204+
return CreateLines(points);
205+
}
206+
207+
case GridType.FibonacciRectanglesZoomed:
208+
case GridType.FibonacciRectanglesStretched:
175209
{
176210
// https://en.wikipedia.org/wiki/Fibonacci_number
177211
// http://stackoverflow.com/a/18121331/1182448
@@ -194,19 +228,19 @@ public static IEnumerable<Line> CreateGrid(GridType gridType, double width, doub
194228
switch (i % 4)
195229
{
196230
case 0: // attach to bottom of current rectangle
197-
lines.AddRange(CreateRectangle(left, right, bottom, bottom + current));
231+
lines.AddRange(CreateRectangleLines(left, right, bottom, bottom + current));
198232
bottom += current;
199233
break;
200234
case 1: // attach to right of current rectangle
201-
lines.AddRange(CreateRectangle(right, right + current, top, bottom));
235+
lines.AddRange(CreateRectangleLines(right, right + current, top, bottom));
202236
right += current;
203237
break;
204238
case 2: // attach to top of current rectangle
205-
lines.AddRange(CreateRectangle(left, right, top - current, top));
239+
lines.AddRange(CreateRectangleLines(left, right, top - current, top));
206240
top -= current;
207241
break;
208242
case 3: // attach to left of current rectangle
209-
lines.AddRange(CreateRectangle(left - current, left, top, bottom));
243+
lines.AddRange(CreateRectangleLines(left - current, left, top, bottom));
210244
left -= current;
211245
break;
212246
}
@@ -220,12 +254,24 @@ public static IEnumerable<Line> CreateGrid(GridType gridType, double width, doub
220254
}
221255
}
222256

223-
lines = StretchToUniformRectangle(lines, left, top, right, bottom);
257+
if (gridType == GridType.FibonacciRectanglesZoomed)
258+
{
259+
lines = StretchToRectangleWithAspectRatio(lines, width, height, left, right, top, bottom);
260+
}
261+
else if (gridType == GridType.FibonacciRectanglesStretched)
262+
{
263+
lines = StretchToUniformRectangle(lines, left, top, right, bottom);
264+
}
265+
else
266+
{
267+
throw new ArgumentOutOfRangeException(gridType.ToString());
268+
}
224269

225270
return lines;
226271
}
227272

228-
case GridType.GoldenSpiral:
273+
case GridType.GoldenSpiralZoomed:
274+
case GridType.GoldenSpiralStretched:
229275
{
230276
// https://en.wikipedia.org/wiki/Golden_spiral
231277
// http://csharphelper.com/blog/2012/05/draw-a-phi-spiral-or-golden-spiral-in-c/
@@ -293,7 +339,32 @@ public static IEnumerable<Line> CreateGrid(GridType gridType, double width, doub
293339
lines.Add(new Line(points[i - 1], points[i]));
294340
}
295341

296-
lines = StretchToUniformRectangle(lines, minX, minY, maxX, maxY);
342+
if (gridType == GridType.GoldenSpiralZoomed)
343+
{
344+
lines = StretchToRectangleWithAspectRatio(lines, width, height, minX, maxX, minY, maxY);
345+
346+
// Adding extents lines
347+
var extents = GetExtents(lines);
348+
var aspect = (width / height);
349+
if (aspect < RatioConstants.Phi)
350+
{
351+
lines.Add(new Line(RatioConstants.Zero, extents.Top, RatioConstants.One, extents.Top));
352+
lines.Add(new Line(RatioConstants.Zero, extents.Bottom, RatioConstants.One, extents.Bottom));
353+
}
354+
else
355+
{
356+
lines.Add(new Line(extents.Left, RatioConstants.Zero, extents.Left, RatioConstants.One));
357+
lines.Add(new Line(extents.Right, RatioConstants.Zero, extents.Right, RatioConstants.One));
358+
}
359+
}
360+
else if (gridType == GridType.GoldenSpiralStretched)
361+
{
362+
lines = StretchToUniformRectangle(lines, minX, minY, maxX, maxY);
363+
}
364+
else
365+
{
366+
throw new ArgumentOutOfRangeException(gridType.ToString());
367+
}
297368

298369
return lines;
299370
}
@@ -304,8 +375,26 @@ public static IEnumerable<Line> CreateGrid(GridType gridType, double width, doub
304375
}
305376
}
306377

378+
private static List<Line> StretchToRectangleWithAspectRatio(List<Line> lines, double width, double height, double left, double right, double top, double bottom)
379+
{
380+
var aspect = (width / height);
381+
382+
if (aspect < RatioConstants.Phi)
383+
{
384+
lines = StretchToRectangle(1.0, (RatioConstants.Phi - 1.0) * aspect, lines, left, top, right, bottom);
385+
lines = AlignToCenter(lines);
386+
}
387+
else
388+
{
389+
lines = StretchToRectangle(RatioConstants.Phi / aspect, 1.0, lines, left, top, right, bottom);
390+
lines = AlignToCenter(lines);
391+
}
392+
393+
return lines;
394+
}
395+
307396
/// <summary>
308-
/// Scale and auto-fit (stretch all lines to 0..1 output range) set of lines
397+
/// Scale and auto-fit set of lines (to 0..1 output range)
309398
/// Min/max values passed as precalculated parameters for optimization
310399
/// </summary>
311400
/// <param name="lines">List of lines to stretch</param>
@@ -316,18 +405,55 @@ public static IEnumerable<Line> CreateGrid(GridType gridType, double width, doub
316405
/// <returns></returns>
317406
private static List<Line> StretchToUniformRectangle(IEnumerable<Line> lines, double minX, double minY, double maxX, double maxY)
318407
{
319-
var scaleX = 1.0 / (maxX - minX);
320-
var scaleY = 1.0 / (maxY - minY);
408+
return StretchToRectangle(1.0, 1.0, lines, minX, minY, maxX, maxY);
409+
}
410+
411+
private static List<Line> StretchToRectangle(double width, double height, IEnumerable<Line> lines, double minX, double minY, double maxX, double maxY)
412+
{
413+
var scaleX = width / (maxX - minX);
414+
var scaleY = height / (maxY - minY);
321415
var offsetX = minX;
322416
var offsetY = minY;
323417

324418
return lines.Select(r => new Line(
325-
new Point((r.p1.X - offsetX) * scaleX, (r.p1.Y - offsetY) * scaleY),
326-
new Point((r.p2.X - offsetX) * scaleX, (r.p2.Y - offsetY) * scaleY)))
419+
(r.p1.X - offsetX) * scaleX, (r.p1.Y - offsetY) * scaleY,
420+
(r.p2.X - offsetX) * scaleX, (r.p2.Y - offsetY) * scaleY))
421+
.ToList();
422+
}
423+
424+
private static Rectangle GetExtents(IEnumerable<Line> lines)
425+
{
426+
var p = lines.First().p1;
427+
var minX = p.X;
428+
var minY = p.Y;
429+
var maxX = p.X;
430+
var maxY = p.Y;
431+
432+
foreach (var line in lines)
433+
{
434+
minX = Math.Min(Math.Min(minX, line.p1.X), Math.Min(minX, line.p2.X));
435+
minY = Math.Min(Math.Min(minY, line.p1.Y), Math.Min(minY, line.p2.Y));
436+
maxX = Math.Max(Math.Max(maxX, line.p1.X), Math.Max(maxX, line.p2.X));
437+
maxY = Math.Max(Math.Max(maxY, line.p1.Y), Math.Max(maxY, line.p2.Y));
438+
}
439+
440+
return new Rectangle { X = minX, Y = minY, Width = maxX - minX, Height = maxY - minY };
441+
}
442+
443+
private static List<Line> AlignToCenter(IEnumerable<Line> lines)
444+
{
445+
var extents = GetExtents(lines);
446+
447+
var offsetX = (1.0 - extents.Width) / 2.0;
448+
var offsetY = (1.0 - extents.Height) / 2.0;
449+
450+
return lines.Select(r => new Line(
451+
new Point((r.p1.X + offsetX), (r.p1.Y + offsetY)),
452+
new Point((r.p2.X + offsetX), (r.p2.Y + offsetY))))
327453
.ToList();
328454
}
329455

330-
private static IList<Line> CreateRectangle(int left, int right, int top, int bottom)
456+
private static IList<Line> CreateRectangleLines(int left, int right, int top, int bottom)
331457
{
332458
return new List<Line>(new[]
333459
{

Src/ScreenGrid.Models/Grids/GridModeItem.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,17 @@ public static IEnumerable<GridModeItem> List
3737
{
3838
return new[]
3939
{
40+
new GridModeItem(GridType.Crosshair, "Crosshair"),
4041
new GridModeItem(GridType.Thirds, "Thirds"),
41-
new GridModeItem(GridType.DiagonalOfThirds,"Diagonal of Thirds" ),
42-
new GridModeItem(GridType.GoldenRatio, "Golden Ratio" ),
43-
new GridModeItem(GridType.GoldenTriangle, "Golden Triangle" ),
44-
new GridModeItem(GridType.GoldenDiagonal, "Golden Diagonal" ),
45-
new GridModeItem(GridType.FibonacciRectangles, "Fibonacci Rectangles"),
46-
new GridModeItem(GridType.GoldenSpiral, "Golden Spiral"),
42+
new GridModeItem(GridType.GoldenRatio, "Golden Ratio"),
43+
new GridModeItem(GridType.DiagonalOfThirds,"Diagonal of Thirds"),
44+
new GridModeItem(GridType.GoldenTriangle, "Golden Triangle"),
45+
new GridModeItem(GridType.GoldenDiagonal1, "Golden Diagonal 1"),
46+
new GridModeItem(GridType.GoldenDiagonal2, "Golden Diagonal 2"),
47+
new GridModeItem(GridType.FibonacciRectanglesZoomed, "Fibonacci Rectangles"),
48+
new GridModeItem(GridType.GoldenSpiralZoomed, "Golden Spiral"),
49+
new GridModeItem(GridType.FibonacciRectanglesStretched, "Fibonacci Rectangles (stretched)"),
50+
new GridModeItem(GridType.GoldenSpiralStretched, "Golden Spiral (stretched)"),
4751
};
4852
}
4953
}

0 commit comments

Comments
 (0)