프로젝트

일반

사용자정보

통계
| 브랜치(Branch): | 개정판:

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
}
클립보드 이미지 추가 (최대 크기: 500 MB)