프로젝트

일반

사용자정보

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

markus / MarkupToPDF / Controls / Common / MathSet.cs @ d5e3aa15

이력 | 보기 | 이력해설 | 다운로드 (15 KB)

1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
using System.Threading.Tasks;
6
using System.Windows;
7

    
8
namespace MarkupToPDF.Controls.Common
9
{
10
    public class MathSet
11
    {
12
        const double Rad2Deg = 180.0 / Math.PI;
13
        const double Deg2Rad = Math.PI / 180.0;
14
        const double UnitAngle = 15;
15

    
16
        public static List<double> angleSet = new List<double>();
17

    
18
        public static double getMultipleAngle(double increase, double YourAngle)
19
        {
20
            angleSet.Clear();
21

    
22
            for (double i = 0; i <= 360; i += increase)
23
            {
24
                angleSet.Add(i);
25
            }
26

    
27
            if (YourAngle < 0)
28
            {
29
                YourAngle += 360;
30
            }
31
            double TargetData = YourAngle;
32
            double NearAngle = 0;
33
            double k = 0;
34

    
35

    
36
            foreach (var item in angleSet)
37
            {
38
                double j = 0;
39
                j = TargetData - item;
40
                j = j < 0 ? -j : j;
41
                if (j < k)
42
                {
43
                    NearAngle = item;
44
                }
45
                k = j;
46

    
47
            }
48
            return NearAngle;
49
        }
50

    
51
        public static Point getNearPoint(List<Point> pointList, Point setPoint)
52
        {
53
            Point nearPoint = pointList.Select
54
            (n => new
55
            {
56
                n,
57
                distance = Math.Sqrt
58
                    (
59
                        Math.Pow(
60
                                    (n.X - setPoint.X), 2
61
                                )
62

    
63
                        + System.Math.Pow
64
                        (
65
                            (n.Y - setPoint.Y), 2
66
                        )
67
                    )
68

    
69
            }
70
            ).OrderBy(p => p.distance).First().n;
71

    
72
            return nearPoint;
73
        }
74

    
75
        public class ClipLine
76
        {
77
            public static int DONT_INTERSECT = -0x01;
78
            public static int COLLINEAR = 0x00;
79
            public static int INTERSECT = 0x01;
80
            public static double TOLER = 0.0;
81

    
82
            public Point _start;
83
            public Point _end;
84

    
85
            public ClipLine(Point start, Point end)
86
            {
87
                _start = start;
88
                _end = end;
89
            }
90

    
91
            public bool IsLeftSide(Point pt)
92
            {
93
                double dx1 = _end.X - _start.X;
94
                double dy1 = _end.Y - _start.Y;
95
                double dx2 = pt.X - _start.X;
96
                double dy2 = pt.Y - _start.Y;
97

    
98
                return ((dx1 * dy2 - dy1 * dx2) > 0.0);
99
            }
100

    
101
            public bool IsRightSide(Point pt)
102
            {
103
                double dx1 = _end.X - _start.X;
104
                double dy1 = _end.Y - _start.Y;
105
                double dx2 = pt.X - _start.X;
106
                double dy2 = pt.Y - _start.Y;
107

    
108
                return ((dx1 * dy2 - dy1 * dx2) < 0.0);
109
            }
110

    
111
            /// <summary>
112
            /// get intersection point betwwen this and line2d
113
            /// </summary>
114
            /// <author>humkyung</author>
115
            /// <date>2012.08.30</date>
116
            /// <param name="intsec"></param>
117
            /// <param name="line2d"></param>
118
            /// <returns></returns>
119
            public int IntersectWith(ref Point intsec, ClipLine line2d)
120
            {
121
                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;
122
                double x1lo = 0.0, x1hi = 0.0, y1lo = 0.0, y1hi = 0.0;
123

    
124
                Ax = _end.X - _start.X;
125
                Bx = line2d._start.X - line2d._end.X;
126
                // X bound box test
127
                if (Ax < 0.0)
128
                {
129
                    x1lo = _end.X;
130
                    x1hi = _start.X;
131
                }
132
                else
133
                {
134
                    x1hi = _end.X;
135
                    x1lo = _start.X;
136
                }
137

    
138
                if (Bx > 0.0)
139
                {
140
                    if ((x1hi < line2d._end.X) || (line2d._start.X < x1lo)) return ClipLine.DONT_INTERSECT;
141
                }
142
                else
143
                {
144
                    if ((x1hi < line2d._start.X) || (line2d._end.X < x1lo)) return ClipLine.DONT_INTERSECT;
145
                }
146

    
147
                Ay = _end.Y - _start.Y;
148
                By = line2d._start.Y - line2d._end.Y;
149
                /* Y bound box test*/
150
                if (Ay < 0)
151
                {
152
                    y1lo = _end.Y;
153
                    y1hi = _start.Y;
154
                }
155
                else
156
                {
157
                    y1hi = _end.Y;
158
                    y1lo = _start.Y;
159
                }
160

    
161
                if (By > 0)
162
                {
163
                    if ((y1hi < line2d._end.Y) || (line2d._start.Y < y1lo)) return ClipLine.DONT_INTERSECT;
164
                }
165
                else
166
                {
167
                    if ((y1hi < line2d._start.Y) || (line2d._end.Y < y1lo)) return ClipLine.DONT_INTERSECT;
168
                }
169

    
170
                Cx = _start.X - line2d._start.X;
171
                Cy = _start.Y - line2d._start.Y;
172
                f = Ay * Bx - Ax * By;	/* both denominator*/
173
                /// lines are collinear.
174
                if (0.0 == f) return ClipLine.COLLINEAR;
175

    
176
                d = By * Cx - Bx * Cy;	/* alpha numerator*/
177
                if (f > 0.0)
178
                {		/* alpha tests*/
179
                    if ((d < (0 + ClipLine.TOLER)) || (d > (f - ClipLine.TOLER))) return ClipLine.DONT_INTERSECT;
180
                }
181
                else
182
                {
183
                    if ((d > (0 - ClipLine.TOLER)) || (d < (f + ClipLine.TOLER))) return ClipLine.DONT_INTERSECT;
184
                }
185

    
186
                e = Ax * Cy - Ay * Cx;	/* beta numerator*/
187
                if (f > 0.0)
188
                {		/* beta tests*/
189
                    if ((e < (0 + ClipLine.TOLER)) || (e > (f - ClipLine.TOLER))) return ClipLine.DONT_INTERSECT;
190
                }
191
                else
192
                {
193
                    if ((e > (0 - ClipLine.TOLER)) || (e < (f + ClipLine.TOLER))) return ClipLine.DONT_INTERSECT;
194
                }
195

    
196
                /*compute intersection coordinates*/
197
                double alpha = d / f;
198

    
199
                if (_start.X == _end.X)
200
                    intsec.X = _start.X;
201
                else intsec.X = _start.X + alpha * Ax;
202
                if (_start.Y == _end.Y)
203
                    intsec.Y = _start.Y;
204
                else intsec.Y = _start.Y + alpha * Ay;
205

    
206
                return ClipLine.INTERSECT;
207
            }
208
        }
209

    
210
        public class ClipRect
211
        {
212
            public Point center;
213
            public double width, height, angle;	/// angle is degree
214

    
215
            public int IntersectWith(ref Point intsec, ClipLine line2d)
216
            {
217
                double radians = Math.PI * angle / 180.0;
218
                double cs = Math.Cos(radians), sn = Math.Sin(radians);
219
                Point[] corner = new Point[4];
220
                corner[0].X = center.X - width * 0.5;
221
                corner[0].Y = center.Y - height * 0.5;
222
                corner[1] = corner[0];
223
                corner[1].X += width;
224
                corner[2] = corner[1];
225
                corner[2].Y += height;
226
                corner[3] = corner[2];
227
                corner[3].X -= width;
228
                /// rotate 4 corners about angle
229
                for (int i = 0; i < corner.Length; ++i)
230
                {
231
                    double ptx = corner[i].X - center.X;
232
                    double pty = corner[i].Y - center.Y;
233
                    corner[i].X = center.X + ((cs * ptx) - (sn * pty));
234
                    corner[i].Y = center.Y + ((sn * ptx) + (cs * pty));
235
                }
236

    
237
                for (int i = 0; i < corner.Length; ++i)
238
                {
239
                    int si = i % corner.Length, ei = (i + 1) % corner.Length;
240
                    if (ClipLine.INTERSECT == line2d.IntersectWith(ref intsec, new ClipLine(corner[si], corner[ei])))
241
                    {
242
                        return ClipLine.INTERSECT;
243
                    }
244
                }
245

    
246
                return ClipLine.DONT_INTERSECT;
247
            }
248
        }
249

    
250
        public static double AngleMethod(Point StartPoint, Point EndPoint)
251
        {
252
            return Math.Abs(Math.Atan2(EndPoint.X - StartPoint.X, StartPoint.Y - EndPoint.Y) * Rad2Deg);
253
        }
254
        public static double DegreesToRadians(double angle)
255
        {
256
            return ((angle * Math.PI) / 180f);
257
        }
258
        //public static double AngleMethod(double px1, double py1, double px2, double py2)
259
        //{
260
        //    return Math.Abs(Math.Atan2(px2 - px1, py1 - py2) * Rad2Deg);
261
        //}
262
        public static double DistanceTo(Point p1, Point p2)
263
        {
264
            double dx = p2.X - p1.X;
265
            double dy = p2.Y - p1.Y;
266
            return Math.Sqrt(dx * dx + dy * dy);
267
        }
268

    
269
        public static Point getMiddlePoint(Point p1, Point p2)
270
        {
271
            return new Point { X = (p1.X + p2.X) / 2, Y = (p1.Y + p2.Y) / 2 };
272
        }
273

    
274
        /// <summary>
275
        /// return area of polygon
276
        /// </summary>
277
        /// <author>humkyung</author>
278
        /// <date>2012.07.04</date>
279
        /// <param name="points"></param>
280
        /// <returns></returns>
281
        public static double AreaOf(List<Point> points)
282
        {
283
            double res = 0;
284
            int p = 0, q = 0;
285

    
286
            for (p = points.Count - 1, q = 0; q < points.Count; p = q++)
287
            {
288
                res += points[p].X * points[q].Y - points[p].Y * points[q].X;
289
            }
290

    
291
            return res;
292
        }
293
        /// <summary>
294
        /// return normal vector from p1 to p2
295
        /// </summary>
296
        /// <author>humkyung</author>
297
        /// <date>2012.07.19</date>
298
        /// <param name="p1"></param>
299
        /// <param name="p2"></param>
300
        /// <returns></returns>
301
        public static Point GetNormVectorBetween(Point p1, Point p2)
302
        {
303
            Point res = new Point();
304

    
305
            double d = MathSet.DistanceTo(p1, p2);
306

    
307
            if (d > 0)
308
            {
309
                res.X = (p2.X - p1.X) / d;
310
                res.Y = (p2.Y - p1.Y) / d;
311
            }
312

    
313
            return res;
314
        }
315
        public static Point FindCentroid(List<Point> pntSet)
316
        {
317
            Double getThePointX = new Double();
318
            Double getThePointY = new Double();
319

    
320
            for (int i = 0; i < pntSet.Count; i++)
321
            {
322
                int ReIndex = (i + pntSet.Count / 2) % pntSet.Count;
323
                Point p = (MathSet.getMiddlePoint(pntSet[i], pntSet[ReIndex]));
324
                getThePointX += p.X;
325
                getThePointY += p.Y;
326
            }
327
            double count = Convert.ToDouble(pntSet.Count);
328
            //return new Point(getThePointX/Convert.ToDouble(pntSet.Count(),getThePointY/Convert.ToDouble(pntSet.Count());
329
            return new Point(getThePointX / count, getThePointY / count);
330
        }
331

    
332
        public static Point RotateAbout(Point org, Point dest, double dAngle)
333
        {
334
            double ptx = dest.X - org.X;
335
            double pty = dest.Y - org.Y;
336
            double radians = Math.PI * dAngle / 180.0;
337
            double pt1x = org.X + ((Math.Cos(radians) * ptx) - (Math.Sin(radians) * pty));
338
            double pt2x = org.Y + ((Math.Sin(radians) * ptx) + (Math.Cos(radians) * pty));
339
            return new Point(pt1x, pt2x);
340
        }
341

    
342
        public static double getAngle(double x1, double y1, double x2, double y2)
343
        {
344
            double alpha = 0;
345
            double dx = x2 - x1;
346
            double dy = y2 - y1;
347
            double l = Math.Sqrt(dx * dx + dy * dy);
348

    
349
            if (l > 0)
350
            {
351
                alpha = Math.Acos(dx / l);
352
                double cross = MathSet.CrossProduct(1, 0, dx, dy);
353
                if (cross < 0) alpha = -alpha;
354

    
355
                alpha *= MathSet.Rad2Deg;
356
            }
357
            else
358
            {
359
                alpha = 0;
360
            }
361

    
362
            return alpha;
363
        }
364

    
365
        public static double DotProduct(double x1, double y1, double x2, double y2)
366
        {
367
            return (x1 * x2 + y1 * y2);
368
        }
369

    
370
        public static double CrossProduct(double x1, double y1, double x2, double y2)
371
        {
372
            return (x1 * y2 - y1 * x2);
373

    
374
        }
375

    
376
        /// <summary>
377
        /// return angle in degree between given two vectors
378
        /// </summary>
379
        /// <author>humkyung</author>
380
        /// <date>2018.05.09</date>
381
        /// <param name="vec1"></param>
382
        /// <param name="vec2"></param>
383
        /// <returns></returns>
384
        public static double getAngleBetweenVectors(Point vec1, Point vec2)
385
        {
386
            double dot = MathSet.DotProduct(vec1.X, vec1.Y, vec2.X, vec2.Y);
387
            double length1 = Math.Sqrt(vec1.X * vec1.X + vec1.Y * vec1.Y);
388
            double length2 = Math.Sqrt(vec2.X * vec2.X + vec2.Y * vec2.Y);
389
            double cross = MathSet.CrossProduct(vec1.X, vec1.Y, vec2.X, vec2.Y);
390
            double radian = Math.Acos(dot / (length1 * length2));
391

    
392
            return (cross > 0) ? radian * MathSet.Rad2Deg : -(radian * MathSet.Rad2Deg);
393
        }
394

    
395
        // 사용용도가 불분명함.
396
        public static string returnAngleString(Point start, ref Point end, bool PressShift)
397
        {
398
            double angle = MathSet.getAngle(start.X, start.Y, end.X, end.Y);
399
            double approxAngle = MathSet.getMultipleAngle(UnitAngle, angle);
400

    
401
            if (PressShift)
402
            {
403
                double distance = MathSet.DistanceTo(start, end);
404
                end = MathSet.RotateAbout(start, new Point(start.X + distance, start.Y), approxAngle);
405
                return String.Format("{1}({0})", approxAngle.ToString("0.#") + "°", Math.Abs(approxAngle - 360).ToString("0.#") + "°");
406
            }
407
            else
408
            {
409
                angle *= -1;
410

    
411
                if (angle < 0)
412
                {
413
                    angle = angle + 360;
414
                }
415
                return String.Format("{0}", angle.ToString("0.#") + "°");
416
            }
417
        }
418

    
419

    
420
        /// <summary>
421
        /// returnAngleString을 변경하여 수정
422
        /// 상단 컨트롤에 Angle값을 보여주기 위해 수정함.
423
        /// </summary>
424
        /// <param name="start"></param>
425
        /// <param name="end"></param>
426
        /// <param name="PressShift"></param>
427
        /// <returns></returns>
428
        public static double returnAngle(Point start, ref Point end, bool PressShift)
429
        {
430
            double angle = MathSet.getAngle(start.X, start.Y, end.X, end.Y);
431
            double approxAngle = MathSet.getMultipleAngle(UnitAngle, angle);
432

    
433
            if (PressShift)
434
            {
435
                double distance = MathSet.DistanceTo(start, end);
436
                end = MathSet.RotateAbout(start, new Point(start.X + distance, start.Y), approxAngle);
437

    
438
                angle = approxAngle;
439
            }
440

    
441
            if (angle < 0)
442
            {
443
                angle = angle + 360;
444
            }
445

    
446
            return angle;
447
        }
448

    
449
        public static Point getRectMiddlePoint(Rect data)
450
        {
451
            Point startP = new Point(data.X, data.Y);
452
            Point endP = new Point(data.Right, data.Bottom);
453
            return MathSet.getMiddlePoint(startP, endP);
454
        }
455
    }
456
}
클립보드 이미지 추가 (최대 크기: 500 MB)