External/OxyPlot/OxyPlot/Foundation/ScreenPointHelper.cs
author StephaneLenclud
Tue, 03 Feb 2015 10:14:18 +0100
branchMiniDisplay
changeset 450 f2d8620e2434
permissions -rw-r--r--
Rebracer update.
     1 // --------------------------------------------------------------------------------------------------------------------
     2 // <copyright file="ScreenPointHelper.cs" company="OxyPlot">
     3 //   The MIT License (MIT)
     4 //   
     5 //   Copyright (c) 2012 Oystein Bjorke
     6 //   
     7 //   Permission is hereby granted, free of charge, to any person obtaining a
     8 //   copy of this software and associated documentation files (the
     9 //   "Software"), to deal in the Software without restriction, including
    10 //   without limitation the rights to use, copy, modify, merge, publish,
    11 //   distribute, sublicense, and/or sell copies of the Software, and to
    12 //   permit persons to whom the Software is furnished to do so, subject to
    13 //   the following conditions:
    14 //   
    15 //   The above copyright notice and this permission notice shall be included
    16 //   in all copies or substantial portions of the Software.
    17 //   
    18 //   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    19 //   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    20 //   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    21 //   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    22 //   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    23 //   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    24 //   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    25 // </copyright>
    26 // <summary>
    27 //   Provides various algorithms for polygons and lines of ScreenPoint.
    28 // </summary>
    29 // --------------------------------------------------------------------------------------------------------------------
    30 namespace OxyPlot
    31 {
    32     using System.Collections.Generic;
    33 
    34     /// <summary>
    35     /// Provides algorithms for polygons and lines of <see cref="ScreenPoint"/>.
    36     /// </summary>
    37     public static class ScreenPointHelper
    38     {
    39         /// <summary>
    40         /// Finds the nearest point on the specified polyline.
    41         /// </summary>
    42         /// <param name="point">
    43         /// The point.
    44         /// </param>
    45         /// <param name="points">
    46         /// The points.
    47         /// </param>
    48         /// <returns>
    49         /// The nearest point.
    50         /// </returns>
    51         public static ScreenPoint FindNearestPointOnPolyline(ScreenPoint point, IList<ScreenPoint> points)
    52         {
    53             double minimumDistance = double.MaxValue;
    54             var nearestPoint = default(ScreenPoint);
    55 
    56             for (int i = 0; i + 1 < points.Count; i++)
    57             {
    58                 var p1 = points[i];
    59                 var p2 = points[i + 1];
    60                 if (ScreenPoint.IsUndefined(p1) || ScreenPoint.IsUndefined(p2))
    61                 {
    62                     continue;
    63                 }
    64 
    65                 // Find the nearest point on the line segment.
    66                 var nearestPointOnSegment = FindPointOnLine(point, p1, p2);
    67 
    68                 if (ScreenPoint.IsUndefined(nearestPointOnSegment))
    69                 {
    70                     continue;
    71                 }
    72 
    73                 double l2 = (point - nearestPointOnSegment).LengthSquared;
    74 
    75                 if (l2 < minimumDistance)
    76                 {
    77                     nearestPoint = nearestPointOnSegment;
    78                     minimumDistance = l2;
    79                 }
    80             }
    81 
    82             return nearestPoint;
    83         }
    84 
    85         /// <summary>
    86         /// Finds the point on line.
    87         /// </summary>
    88         /// <param name="p">
    89         /// The point.
    90         /// </param>
    91         /// <param name="p1">
    92         /// The first point on the line.
    93         /// </param>
    94         /// <param name="p2">
    95         /// The second point on the line.
    96         /// </param>
    97         /// <returns>
    98         /// The nearest point on the line.
    99         /// </returns>
   100         /// <remarks>
   101         /// See <a href="http://paulbourke.net/geometry/pointlineplane/">Bourke</a>.
   102         /// </remarks>
   103         public static ScreenPoint FindPointOnLine(ScreenPoint p, ScreenPoint p1, ScreenPoint p2)
   104         {
   105             double dx = p2.x - p1.x;
   106             double dy = p2.y - p1.y;
   107             double u = FindPositionOnLine(p, p1, p2);
   108 
   109             if (double.IsNaN(u))
   110             {
   111                 u = 0;
   112             }
   113 
   114             if (u < 0)
   115             {
   116                 u = 0;
   117             }
   118 
   119             if (u > 1)
   120             {
   121                 u = 1;
   122             }
   123 
   124             return new ScreenPoint(p1.x + (u * dx), p1.y + (u * dy));
   125         }
   126 
   127         /// <summary>
   128         /// Finds the nearest point on line.
   129         /// </summary>
   130         /// <param name="p">
   131         /// The point.
   132         /// </param>
   133         /// <param name="p1">
   134         /// The start point on the line.
   135         /// </param>
   136         /// <param name="p2">
   137         /// The end point on the line.
   138         /// </param>
   139         /// <returns>
   140         /// The relative position of the nearest point.
   141         /// </returns>
   142         /// <remarks>
   143         /// See <a href="http://paulbourke.net/geometry/pointlineplane/">Bourke</a>.
   144         /// </remarks>
   145         public static double FindPositionOnLine(ScreenPoint p, ScreenPoint p1, ScreenPoint p2)
   146         {
   147             double dx = p2.x - p1.x;
   148             double dy = p2.y - p1.y;
   149             double u1 = ((p.x - p1.x) * dx) + ((p.y - p1.y) * dy);
   150             double u2 = (dx * dx) + (dy * dy);
   151 
   152             if (u2 < 1e-6)
   153             {
   154                 return double.NaN;
   155             }
   156 
   157             return u1 / u2;
   158         }
   159 
   160         /// <summary>
   161         /// Determines whether the specified point is in the specified polygon.
   162         /// </summary>
   163         /// <param name="p">
   164         /// The point.
   165         /// </param>
   166         /// <param name="pts">
   167         /// The polygon points.
   168         /// </param>
   169         /// <returns>
   170         /// <c>true</c> if the point is in the polygon; otherwise, <c>false</c>.
   171         /// </returns>
   172         public static bool IsPointInPolygon(ScreenPoint p, IList<ScreenPoint> pts)
   173         {
   174             int nvert = pts.Count;
   175             bool c = false;
   176             for (int i = 0, j = nvert - 1; i < nvert; j = i++)
   177             {
   178                 if (((pts[i].Y > p.Y) != (pts[j].Y > p.Y))
   179                     && (p.X < ((pts[j].X - pts[i].X) * ((p.Y - pts[i].Y) / (pts[j].Y - pts[i].Y))) + pts[i].X))
   180                 {
   181                     c = !c;
   182                 }
   183             }
   184 
   185             return c;
   186         }
   187 
   188         /// <summary>
   189         /// Resamples the points with the specified point distance limit.
   190         /// </summary>
   191         /// <param name="allPoints">
   192         /// All points.
   193         /// </param>
   194         /// <param name="minimumDistance">
   195         /// The minimum squared distance.
   196         /// </param>
   197         /// <returns>
   198         /// List of resampled points.
   199         /// </returns>
   200         public static IList<ScreenPoint> ResamplePoints(IList<ScreenPoint> allPoints, double minimumDistance)
   201         {
   202             double minimumSquaredDistance = minimumDistance * minimumDistance;
   203             int n = allPoints.Count;
   204             var result = new List<ScreenPoint>(n);
   205             if (n > 0)
   206             {
   207                 result.Add(allPoints[0]);
   208                 int i0 = 0;
   209                 for (int i = 1; i < n; i++)
   210                 {
   211                     double distSquared = allPoints[i0].DistanceToSquared(allPoints[i]);
   212                     if (distSquared < minimumSquaredDistance && i != n - 1)
   213                     {
   214                         continue;
   215                     }
   216 
   217                     i0 = i;
   218                     result.Add(allPoints[i]);
   219                 }
   220             }
   221 
   222             return result;
   223         }
   224 
   225         /// <summary>
   226         /// Gets the centroid of the specified polygon.
   227         /// </summary>
   228         /// <param name="points">
   229         /// The points.
   230         /// </param>
   231         /// <returns>
   232         /// The centroid.
   233         /// </returns>
   234         public static ScreenPoint GetCentroid(IList<ScreenPoint> points)
   235         {
   236             double cx = 0;
   237             double cy = 0;
   238             double a = 0;
   239 
   240             for (int i = 0; i < points.Count; i++)
   241             {
   242                 int i1 = (i + 1) % points.Count;
   243                 double da = (points[i].x * points[i1].y) - (points[i1].x * points[i].y);
   244                 cx += (points[i].x + points[i1].x) * da;
   245                 cy += (points[i].y + points[i1].y) * da;
   246                 a += da;
   247             }
   248 
   249             a *= 0.5;
   250             cx /= 6 * a;
   251             cy /= 6 * a;
   252             return new ScreenPoint(cx, cy);
   253         }
   254     }
   255 }