markus / MarkupToPDF / Controls / Common / MathSet.cs @ 2a2e72c2
이력 | 보기 | 이력해설 | 다운로드 (14.8 KB)
1 |
using System; |
---|---|
2 |
using System.Collections.Generic; |
3 |
using System.Linq; |
4 |
using System.Windows; |
5 |
using System.Windows.Media; |
6 |
|
7 |
namespace MarkupToPDF.Controls.Common |
8 |
{ |
9 |
public class MathSet |
10 |
{ |
11 |
private const double Rad2Deg = 180.0 / Math.PI; |
12 |
private const double Deg2Rad = Math.PI / 180.0; |
13 |
private const double UnitAngle = 15; |
14 |
|
15 |
public static List<double> angleSet = new List<double>(); |
16 |
|
17 |
public static double getMultipleAngle(double increase, double YourAngle) |
18 |
{ |
19 |
angleSet.Clear(); |
20 |
|
21 |
for (double i = 0; i <= 360; i += increase) |
22 |
{ |
23 |
angleSet.Add(i); |
24 |
} |
25 |
|
26 |
if (YourAngle < 0) |
27 |
{ |
28 |
YourAngle += 360; |
29 |
} |
30 |
double TargetData = YourAngle; |
31 |
double NearAngle = 0; |
32 |
double k = 0; |
33 |
|
34 |
foreach (var item in angleSet) |
35 |
{ |
36 |
double j = 0; |
37 |
j = TargetData - item; |
38 |
j = j < 0 ? -j : j; |
39 |
if (j < k) |
40 |
{ |
41 |
NearAngle = item; |
42 |
} |
43 |
k = j; |
44 |
} |
45 |
return NearAngle; |
46 |
} |
47 |
|
48 |
public static Point getNearPoint(List<Point> pointList, Point setPoint) |
49 |
{ |
50 |
Point nearPoint = pointList.Select |
51 |
(n => new |
52 |
{ |
53 |
n, |
54 |
distance = Math.Sqrt |
55 |
( |
56 |
Math.Pow( |
57 |
(n.X - setPoint.X), 2 |
58 |
) |
59 |
|
60 |
+ System.Math.Pow |
61 |
( |
62 |
(n.Y - setPoint.Y), 2 |
63 |
) |
64 |
) |
65 |
} |
66 |
).OrderBy(p => p.distance).First().n; |
67 |
|
68 |
return nearPoint; |
69 |
} |
70 |
|
71 |
public class ClipLine |
72 |
{ |
73 |
public static int DONT_INTERSECT = -0x01; |
74 |
public static int COLLINEAR = 0x00; |
75 |
public static int INTERSECT = 0x01; |
76 |
public static double TOLER = 0.0; |
77 |
|
78 |
public Point _start; |
79 |
public Point _end; |
80 |
|
81 |
public ClipLine(Point start, Point end) |
82 |
{ |
83 |
_start = start; |
84 |
_end = end; |
85 |
} |
86 |
|
87 |
public bool IsLeftSide(Point pt) |
88 |
{ |
89 |
double dx1 = _end.X - _start.X; |
90 |
double dy1 = _end.Y - _start.Y; |
91 |
double dx2 = pt.X - _start.X; |
92 |
double dy2 = pt.Y - _start.Y; |
93 |
|
94 |
return ((dx1 * dy2 - dy1 * dx2) > 0.0); |
95 |
} |
96 |
|
97 |
public bool IsRightSide(Point pt) |
98 |
{ |
99 |
double dx1 = _end.X - _start.X; |
100 |
double dy1 = _end.Y - _start.Y; |
101 |
double dx2 = pt.X - _start.X; |
102 |
double dy2 = pt.Y - _start.Y; |
103 |
|
104 |
return ((dx1 * dy2 - dy1 * dx2) < 0.0); |
105 |
} |
106 |
|
107 |
/// <summary> |
108 |
/// get intersection point between this and line2d |
109 |
/// </summary> |
110 |
/// <author>humkyung</author> |
111 |
/// <date>2012.08.30</date> |
112 |
/// <param name="intsec"></param> |
113 |
/// <param name="line2d"></param> |
114 |
/// <returns></returns> |
115 |
public int IntersectWith(ref Point intsec, ClipLine line2d) |
116 |
{ |
117 |
double Ax = 0.0, Bx = 0.0, Cx = 0.0, Ay = 0.0, By = 0.0, Cy = 0.0, d = 0.0, e = 0.0, f = 0.0; |
118 |
double x1lo = 0.0, x1hi = 0.0, y1lo = 0.0, y1hi = 0.0; |
119 |
|
120 |
Ax = _end.X - _start.X; |
121 |
Bx = line2d._start.X - line2d._end.X; |
122 |
// X bound box test |
123 |
if (Ax < 0.0) |
124 |
{ |
125 |
x1lo = _end.X; |
126 |
x1hi = _start.X; |
127 |
} |
128 |
else |
129 |
{ |
130 |
x1hi = _end.X; |
131 |
x1lo = _start.X; |
132 |
} |
133 |
|
134 |
if (Bx > 0.0) |
135 |
{ |
136 |
if ((x1hi < line2d._end.X) || (line2d._start.X < x1lo)) return ClipLine.DONT_INTERSECT; |
137 |
} |
138 |
else |
139 |
{ |
140 |
if ((x1hi < line2d._start.X) || (line2d._end.X < x1lo)) return ClipLine.DONT_INTERSECT; |
141 |
} |
142 |
|
143 |
Ay = _end.Y - _start.Y; |
144 |
By = line2d._start.Y - line2d._end.Y; |
145 |
/* Y bound box test*/ |
146 |
if (Ay < 0) |
147 |
{ |
148 |
y1lo = _end.Y; |
149 |
y1hi = _start.Y; |
150 |
} |
151 |
else |
152 |
{ |
153 |
y1hi = _end.Y; |
154 |
y1lo = _start.Y; |
155 |
} |
156 |
|
157 |
if (By > 0) |
158 |
{ |
159 |
if ((y1hi < line2d._end.Y) || (line2d._start.Y < y1lo)) return ClipLine.DONT_INTERSECT; |
160 |
} |
161 |
else |
162 |
{ |
163 |
if ((y1hi < line2d._start.Y) || (line2d._end.Y < y1lo)) return ClipLine.DONT_INTERSECT; |
164 |
} |
165 |
|
166 |
Cx = _start.X - line2d._start.X; |
167 |
Cy = _start.Y - line2d._start.Y; |
168 |
f = Ay * Bx - Ax * By; /* both denominator*/ |
169 |
/// lines are collinear. |
170 |
if (0.0 == f) return ClipLine.COLLINEAR; |
171 |
|
172 |
d = By * Cx - Bx * Cy; /* alpha numerator*/ |
173 |
if (f > 0.0) |
174 |
{ /* alpha tests*/ |
175 |
if ((d < (0 + ClipLine.TOLER)) || (d > (f - ClipLine.TOLER))) return ClipLine.DONT_INTERSECT; |
176 |
} |
177 |
else |
178 |
{ |
179 |
if ((d > (0 - ClipLine.TOLER)) || (d < (f + ClipLine.TOLER))) return ClipLine.DONT_INTERSECT; |
180 |
} |
181 |
|
182 |
e = Ax * Cy - Ay * Cx; /* beta numerator*/ |
183 |
if (f > 0.0) |
184 |
{ /* beta tests*/ |
185 |
if ((e < (0 + ClipLine.TOLER)) || (e > (f - ClipLine.TOLER))) return ClipLine.DONT_INTERSECT; |
186 |
} |
187 |
else |
188 |
{ |
189 |
if ((e > (0 - ClipLine.TOLER)) || (e < (f + ClipLine.TOLER))) return ClipLine.DONT_INTERSECT; |
190 |
} |
191 |
|
192 |
/*compute intersection coordinates*/ |
193 |
double alpha = d / f; |
194 |
|
195 |
if (_start.X == _end.X) |
196 |
intsec.X = _start.X; |
197 |
else intsec.X = _start.X + alpha * Ax; |
198 |
if (_start.Y == _end.Y) |
199 |
intsec.Y = _start.Y; |
200 |
else intsec.Y = _start.Y + alpha * Ay; |
201 |
|
202 |
return ClipLine.INTERSECT; |
203 |
} |
204 |
} |
205 |
|
206 |
public class ClipRect |
207 |
{ |
208 |
public Point center; |
209 |
public double width, height, angle; /// angle is degree |
210 |
|
211 |
public int IntersectWith(ref Point intsec, ClipLine line2d) |
212 |
{ |
213 |
double radians = Math.PI * angle / 180.0; |
214 |
double cs = Math.Cos(radians), sn = Math.Sin(radians); |
215 |
Point[] corner = new Point[4]; |
216 |
corner[0].X = center.X - width * 0.5; |
217 |
corner[0].Y = center.Y - height * 0.5; |
218 |
corner[1] = corner[0]; |
219 |
corner[1].X += width; |
220 |
corner[2] = corner[1]; |
221 |
corner[2].Y += height; |
222 |
corner[3] = corner[2]; |
223 |
corner[3].X -= width; |
224 |
/// rotate 4 corners about angle |
225 |
for (int i = 0; i < corner.Length; ++i) |
226 |
{ |
227 |
double ptx = corner[i].X - center.X; |
228 |
double pty = corner[i].Y - center.Y; |
229 |
corner[i].X = center.X + ((cs * ptx) - (sn * pty)); |
230 |
corner[i].Y = center.Y + ((sn * ptx) + (cs * pty)); |
231 |
} |
232 |
|
233 |
for (int i = 0; i < corner.Length; ++i) |
234 |
{ |
235 |
int si = i % corner.Length, ei = (i + 1) % corner.Length; |
236 |
if (ClipLine.INTERSECT == line2d.IntersectWith(ref intsec, new ClipLine(corner[si], corner[ei]))) |
237 |
{ |
238 |
return ClipLine.INTERSECT; |
239 |
} |
240 |
} |
241 |
|
242 |
return ClipLine.DONT_INTERSECT; |
243 |
} |
244 |
} |
245 |
|
246 |
public static double AngleMethod(Point StartPoint, Point EndPoint) |
247 |
{ |
248 |
return Math.Abs(Math.Atan2(EndPoint.X - StartPoint.X, StartPoint.Y - EndPoint.Y) * Rad2Deg); |
249 |
} |
250 |
|
251 |
public static double DegreesToRadians(double angle) |
252 |
{ |
253 |
return ((angle * Math.PI) / 180f); |
254 |
} |
255 |
|
256 |
public static double DistanceTo(Point p1, Point p2) |
257 |
{ |
258 |
double dx = p2.X - p1.X; |
259 |
double dy = p2.Y - p1.Y; |
260 |
return Math.Sqrt(dx * dx + dy * dy); |
261 |
} |
262 |
|
263 |
public static Point getMiddlePoint(Point p1, Point p2) |
264 |
{ |
265 |
return new Point { X = (p1.X + p2.X) * 0.5, Y = (p1.Y + p2.Y) * 0.5 }; |
266 |
} |
267 |
|
268 |
/// <summary> |
269 |
/// return area of polygon |
270 |
/// </summary> |
271 |
/// <author>humkyung</author> |
272 |
/// <date>2012.07.04</date> |
273 |
/// <param name="points"></param> |
274 |
/// <returns></returns> |
275 |
public static double AreaOf(List<Point> points) |
276 |
{ |
277 |
double res = 0; |
278 |
int p = 0, q = 0; |
279 |
|
280 |
for (p = points.Count - 1, q = 0; q < points.Count; p = q++) |
281 |
{ |
282 |
res += points[p].X * points[q].Y - points[p].Y * points[q].X; |
283 |
} |
284 |
|
285 |
return res; |
286 |
} |
287 |
|
288 |
/// <summary> |
289 |
/// return normal vector from p1 to p2 |
290 |
/// </summary> |
291 |
/// <author>humkyung</author> |
292 |
/// <date>2012.07.19</date> |
293 |
/// <param name="p1"></param> |
294 |
/// <param name="p2"></param> |
295 |
/// <returns></returns> |
296 |
public static Point GetNormVectorBetween(Point p1, Point p2) |
297 |
{ |
298 |
Point res = new Point(); |
299 |
|
300 |
double d = MathSet.DistanceTo(p1, p2); |
301 |
if (d > 0) |
302 |
{ |
303 |
res.X = (p2.X - p1.X) / d; |
304 |
res.Y = (p2.Y - p1.Y) / d; |
305 |
} |
306 |
|
307 |
return res; |
308 |
} |
309 |
|
310 |
public static Point FindCentroid(List<Point> pntSet) |
311 |
{ |
312 |
Double getThePointX = new Double(); |
313 |
Double getThePointY = new Double(); |
314 |
|
315 |
for (int i = 0; i < pntSet.Count; i++) |
316 |
{ |
317 |
int ReIndex = (i + pntSet.Count / 2) % pntSet.Count; |
318 |
Point p = (MathSet.getMiddlePoint(pntSet[i], pntSet[ReIndex])); |
319 |
getThePointX += p.X; |
320 |
getThePointY += p.Y; |
321 |
} |
322 |
double count = Convert.ToDouble(pntSet.Count); |
323 |
//return new Point(getThePointX/Convert.ToDouble(pntSet.Count(),getThePointY/Convert.ToDouble(pntSet.Count()); |
324 |
return new Point(getThePointX / count, getThePointY / count); |
325 |
} |
326 |
|
327 |
/// <summary> |
328 |
/// org 기준으로 dest를 dAngle(in degree)만큼 회전 시킨다. |
329 |
/// </summary> |
330 |
/// <param name="org"></param> |
331 |
/// <param name="dest"></param> |
332 |
/// <param name="dAngle"></param> |
333 |
/// <returns></returns> |
334 |
public static Point RotateAbout(Point org, Point dest, double dAngle) |
335 |
{ |
336 |
var transform = new RotateTransform() { Angle = dAngle, CenterX = org.X, CenterY = org.Y }; |
337 |
return transform.Transform(dest); |
338 |
} |
339 |
|
340 |
public static double getAngle(double x1, double y1, double x2, double y2) |
341 |
{ |
342 |
double alpha = 0; |
343 |
double dx = x2 - x1; |
344 |
double dy = y2 - y1; |
345 |
double l = Math.Sqrt(dx * dx + dy * dy); |
346 |
|
347 |
if (l > 0) |
348 |
{ |
349 |
alpha = Math.Acos(dx / l); |
350 |
double cross = MathSet.CrossProduct(1, 0, dx, dy); |
351 |
if (cross < 0) alpha = -alpha; |
352 |
|
353 |
alpha *= MathSet.Rad2Deg; |
354 |
} |
355 |
else |
356 |
{ |
357 |
alpha = 0; |
358 |
} |
359 |
|
360 |
return alpha; |
361 |
} |
362 |
|
363 |
public static double DotProduct(double x1, double y1, double x2, double y2) |
364 |
{ |
365 |
return (x1 * x2 + y1 * y2); |
366 |
} |
367 |
|
368 |
public static double CrossProduct(double x1, double y1, double x2, double y2) |
369 |
{ |
370 |
return (x1 * y2 - y1 * x2); |
371 |
} |
372 |
|
373 |
/// <summary> |
374 |
/// return angle in degree between given two vectors |
375 |
/// </summary> |
376 |
/// <author>humkyung</author> |
377 |
/// <date>2018.05.09</date> |
378 |
/// <param name="vec1"></param> |
379 |
/// <param name="vec2"></param> |
380 |
/// <returns></returns> |
381 |
public static double getAngleBetweenVectors(Point vec1, Point vec2) |
382 |
{ |
383 |
double dot = MathSet.DotProduct(vec1.X, vec1.Y, vec2.X, vec2.Y); |
384 |
double length1 = Math.Sqrt(vec1.X * vec1.X + vec1.Y * vec1.Y); |
385 |
double length2 = Math.Sqrt(vec2.X * vec2.X + vec2.Y * vec2.Y); |
386 |
double cross = MathSet.CrossProduct(vec1.X, vec1.Y, vec2.X, vec2.Y); |
387 |
double radian = Math.Acos(dot / (length1 * length2)); |
388 |
|
389 |
return (cross > 0) ? radian * MathSet.Rad2Deg : -(radian * MathSet.Rad2Deg); |
390 |
} |
391 |
|
392 |
// 사용용도가 불분명함. |
393 |
public static string returnAngleString(Point start, ref Point end, bool PressShift) |
394 |
{ |
395 |
double angle = MathSet.getAngle(start.X, start.Y, end.X, end.Y); |
396 |
double approxAngle = MathSet.getMultipleAngle(UnitAngle, angle); |
397 |
|
398 |
if (PressShift) |
399 |
{ |
400 |
double distance = MathSet.DistanceTo(start, end); |
401 |
end = MathSet.RotateAbout(start, new Point(start.X + distance, start.Y), approxAngle); |
402 |
return String.Format("{1}({0})", approxAngle.ToString("0.#") + "°", Math.Abs(approxAngle - 360).ToString("0.#") + "°"); |
403 |
} |
404 |
else |
405 |
{ |
406 |
angle *= -1; |
407 |
|
408 |
if (angle < 0) |
409 |
{ |
410 |
angle = angle + 360; |
411 |
} |
412 |
return String.Format("{0}", angle.ToString("0.#") + "°"); |
413 |
} |
414 |
} |
415 |
|
416 |
/// <summary> |
417 |
/// returnAngleString을 변경하여 수정 |
418 |
/// 상단 컨트롤에 Angle값을 보여주기 위해 수정함. |
419 |
/// </summary> |
420 |
/// <param name="start"></param> |
421 |
/// <param name="end"></param> |
422 |
/// <param name="PressShift"></param> |
423 |
/// <returns></returns> |
424 |
public static double returnAngle(Point start, ref Point end, bool PressShift) |
425 |
{ |
426 |
double angle = MathSet.getAngle(start.X, start.Y, end.X, end.Y); |
427 |
double approxAngle = MathSet.getMultipleAngle(UnitAngle, angle); |
428 |
|
429 |
if (PressShift) |
430 |
{ |
431 |
double distance = MathSet.DistanceTo(start, end); |
432 |
end = MathSet.RotateAbout(start, new Point(start.X + distance, start.Y), approxAngle); |
433 |
|
434 |
angle = approxAngle; |
435 |
} |
436 |
|
437 |
if (angle < 0) |
438 |
{ |
439 |
angle = 360 + angle; |
440 |
} |
441 |
|
442 |
return angle; |
443 |
} |
444 |
|
445 |
public static Point getRectMiddlePoint(Rect data) |
446 |
{ |
447 |
Point startP = new Point(data.X, data.Y); |
448 |
Point endP = new Point(data.Right, data.Bottom); |
449 |
return MathSet.getMiddlePoint(startP, endP); |
450 |
} |
451 |
} |
452 |
} |