Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
227 views
in Technique[技术] by (71.8m points)

c# - Region.IsVisible(PointF) has very slow performance for large floating point values

I have run into a strange performance issue, and it would be great with an explanation to the behavior I'm experiencing.

I'm using System.Drawing.Region.IsVisible(PointF) to determine if a point is inside a polygon. This usually works very well, but yesterday I noticed that the performance of the IsVisible method becomes very slow if the polygon is complex and it consists of large x- and y values.

Below is some code to reproduce the issue (and an image that shows the shape of the polygon), sorry for the large array sizes, but the polygon needs to be quite complex before the issue appears.

When calling IsVisible on the original points my machine takes 460 651 milliseconds to finish, whereas when I first divide all points by 1000, and then call the method, it takes 1 millisecond. Why I'm I seeing such a big difference in the timing? I did not think the actual values of a float would affect performance.

using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;

namespace PerformanceTest
{
    class Program
    {
        static void Main(string[] args)
        {

            // Create complex polygon with large x and y values
            float[] xValues = {1.014498E+07f, 1.016254E+07f, 1.019764E+07f, 1.021519E+07f, 1.023274E+07f, 1.026785E+07f, 1.026785E+07f, 1.02854E+07f, 1.02854E+07f, 1.030295E+07f, 1.03205E+07f, 1.033805E+07f, 1.035561E+07f, 1.037316E+07f, 1.039071E+07f, 1.040826E+07f, 1.042581E+07f, 1.044337E+07f, 1.046092E+07f, 1.047847E+07f, 1.049602E+07f, 1.051357E+07f, 1.054868E+07f, 1.056623E+07f, 1.058378E+07f, 1.060133E+07f, 1.061888E+07f, 1.061888E+07f, 1.063644E+07f, 1.065399E+07f, 1.068909E+07f, 1.068909E+07f, 1.070664E+07f, 1.07242E+07f, 1.074175E+07f, 1.074175E+07f, 1.07593E+07f, 1.07593E+07f, 1.077685E+07f, 1.07944E+07f, 1.07944E+07f, 1.081196E+07f, 1.081196E+07f, 1.081196E+07f, 1.082951E+07f, 1.084706E+07f, 1.084706E+07f, 1.086461E+07f, 1.086461E+07f, 1.088216E+07f, 1.089971E+07f, 1.091727E+07f, 1.093482E+07f, 1.098747E+07f, 1.100503E+07f, 1.102258E+07f, 1.104013E+07f, 1.105768E+07f, 1.107523E+07f, 1.107523E+07f, 1.109279E+07f, 1.109279E+07f, 1.109279E+07f, 1.109279E+07f, 1.109279E+07f, 1.111034E+07f, 1.111034E+07f, 1.111034E+07f, 1.111034E+07f, 1.111034E+07f, 1.112789E+07f, 1.112789E+07f, 1.112789E+07f, 1.114544E+07f, 1.116299E+07f, 1.118054E+07f, 1.11981E+07f, 1.12332E+07f, 1.125075E+07f, 1.12683E+07f, 1.128586E+07f, 1.130341E+07f, 1.135606E+07f, 1.137361E+07f, 1.139117E+07f, 1.140872E+07f, 1.144382E+07f, 1.146137E+07f, 1.147893E+07f, 1.149648E+07f, 1.151403E+07f, 1.153158E+07f, 1.154913E+07f, 1.156669E+07f, 1.156669E+07f, 1.158424E+07f, 1.158424E+07f, 1.158424E+07f, 1.158424E+07f, 1.158424E+07f, 1.158424E+07f, 1.158424E+07f, 1.158424E+07f, 1.158424E+07f, 1.158424E+07f, 1.158424E+07f, 1.156669E+07f, 1.156669E+07f, 1.151403E+07f, 1.149648E+07f, 1.149648E+07f, 1.149648E+07f, 1.149648E+07f, 1.149648E+07f, 1.149648E+07f, 1.149648E+07f, 1.149648E+07f, 1.149648E+07f, 1.153158E+07f, 1.154913E+07f, 1.156669E+07f, 1.156669E+07f, 1.158424E+07f, 1.160179E+07f, 1.160179E+07f, 1.161934E+07f, 1.165444E+07f, 1.1672E+07f, 1.168955E+07f, 1.17071E+07f, 1.172465E+07f, 1.17422E+07f, 1.175976E+07f, 1.177731E+07f, 1.179486E+07f, 1.181241E+07f, 1.182996E+07f, 1.184752E+07f, 1.186507E+07f, 1.188262E+07f, 1.190017E+07f, 1.190017E+07f, 1.191772E+07f, 1.191772E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.193528E+07f, 1.195283E+07f, 1.197038E+07f, 1.198793E+07f, 1.200548E+07f, 1.202303E+07f, 1.204059E+07f, 1.205814E+07f, 1.207569E+07f, 1.209324E+07f, 1.211079E+07f, 1.212835E+07f, 1.21459E+07f, 1.216345E+07f, 1.2181E+07f, 1.219855E+07f, 1.221611E+07f, 1.221611E+07f, 1.223366E+07f, 1.225121E+07f, 1.226876E+07f, 1.226876E+07f, 1.228631E+07f, 1.230386E+07f, 1.230386E+07f, 1.230386E+07f, 1.232142E+07f, 1.232142E+07f, 1.232142E+07f, 1.232142E+07f, 1.232142E+07f, 1.232142E+07f, 1.232142E+07f, 1.232142E+07f, 1.235652E+07f, 1.235652E+07f, 1.237407E+07f, 1.237407E+07f, 1.239162E+07f, 1.239162E+07f, 1.240918E+07f, 1.242673E+07f, 1.242673E+07f, 1.244428E+07f, 1.247938E+07f, 1.249694E+07f, 1.251449E+07f, 1.253204E+07f, 1.254959E+07f, 1.256714E+07f, 1.258469E+07f, 1.260225E+07f, 1.263735E+07f, 1.26549E+07f, 1.267245E+07f, 1.269001E+07f, 1.270756E+07f, 1.272511E+07f, 1.272511E+07f, 1.274266E+07f, 1.274266E+07f, 1.276021E+07f, 1.276021E+07f, 1.277776E+07f, 1.277776E+07f, 1.277776E+07f, 1.277776E+07f, 1.279532E+07f, 1.279532E+07f, 1.279532E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.281287E+07f, 1.279532E+07f, 1.277776E+07f, 1.276021E+07f, 1.276021E+07f, 1.274266E+07f, 1.274266E+07f, 1.272511E+07f, 1.272511E+07f, 1.272511E+07f, 1.274266E+07f, 1.276021E+07f, 1.279532E+07f, 1.281287E+07f, 1.283042E+07f, 1.284797E+07f, 1.286552E+07f, 1.288308E+07f, 1.290063E+07f, 1.291818E+07f, 1.293573E+07f, 1.295328E+07f, 1.295328E+07f, 1.297084E+07f, 1.297084E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.298839E+07f, 1.300594E+07f, 1.300594E+07f, 1.302349E+07f, 1.304104E+07f, 1.305859E+07f, 1.30937E+07f, 1.311125E+07f, 1.31288E+07f, 1.314635E+07f, 1.316391E+07f, 1.318146E+07f, 1.319901E+07f, 1.321656E+07f, 1.323411E+07f, 1.325167E+07f, 1.325167E+07f, 1.326922E+07f, 1.326922E+07f, 1.328677E+07f, 1.330432E+07f, 1.330432E+07f, 1.330432E+07f, 1.332187E+07f, 1.333943E+07f, 1.335698E+07f, 1.335698E+07f, 1.337453E+07f, 1.339208E+07f, 1.340963E+07f, 1.340963E+07f, 1.342718E+07f, 1.344474E+07f, 1.346229E+07f, 1.347984E+07f, 1.349739E+07f, 1.351494E+07f, 1.355005E+07f, 1.35676E+07f, 1.36027E+07f, 1.363781E+07f, 1.367291E+07f, 1.367291E+07f, 1.370801E+07f, 1.372557E+07f, 1.376067E+07f, 1.377822E+07f, 1.381333E+07f, 1.383088E+07f, 1.384843E+07f, 1.386598E+07f, 1.390109E+07f, 1.391864E+07f, 1.391864E+07f, 1.393619E+07f, 1.395374E+07f, 1.397129E+07f, 1.398884E+07f, 1.40064E+07f, 1.402395E+07f, 1.405905E+07f, 1.409416E+07f, 1.412926E+07f, 1.414681E+07f, 1.418191E+07f, 1.419947E+07f, 1.421702E+07f, 1.423457E+07f, 1.426967E+07f, 1.430478E+07f, 1.433988E+07f, 1.435743E+07f, 1.437499E+07f, 1.439254E+07f, 1.439254E+07f, 1.442764E+07f, 1.442764E+07f, 1.444519E+07f, 1.446274E+07f, 1.446274E+07f, 1.446274E+07f, 1.446274E+07f, 1.446274E+07f, 1.446274E+07f, 1.446274E+07f, 1.446274E+07f, 1.446274E+07f, 1.446274E+07f, 1.446274E+07f, 1.444519E+07f, 1.442764E+07f, 1.441009E+07f, 1.439254E+07f, 1.437499E+07f, 1.435743E+07f, 1.433988E+07f, 1.432233E+07f, 1.430478E+07f, 1.430478E+07f, 1.426967E+07f, 1.426967E+07f, 1.423457E+07f, 1.421702E+07f, 1.418191E+07f, 1.414681E+07f, 1.412926E+07f, 1.409416E+07f, 1.405905E+07f, 1.402395E+07f, 1.40064E+07f, 1.395374E+07f, 1.393619E+07f, 1.391864E+07f, 1.390109E+07f, 1.390109E+07f, 1.388353E+07f, 1.388353E+07f, 1.388353E+07f, 1.388353E+07f, 1.388353E+07f, 1.388353E+07f, 1.388353E+07f, 1.388353E+07f, 1.388353E+07f, 1.388353E+07f, 1.390109E+07f, 1.391864E+07f, 1.393619E+07f, 1.395374E+07f, 1.398884E+07f, 1.398884E+07f, 1.40064E+07f, 1.402395E+07f, 1.402395E+07f, 1.40415E+07f, 1.405905E+07f, 1.40766E+07f, 1.412926E+07f, 1.414681E+07f, 1.416436E+07f, 1.418191E+07f, 1.419947E+07f, 1.421702E+07f, 1.423457E+07f, 1.423457E+07f, 1.423457E+07f, 1.423457E+07f, 1.423457E+07f, 1.423457E+07f, 1.423457E+07f, 1.423457E+07f, 1.423457E+07f, 1.423457E+07f, 1.423457E+07f, 1.423457E+07f, 1.423457E+07f, 1.421702E+07f, 1.419947E+07f, 1.418191E+07f, 1.416436E+07f, 1.416436E+07f, 1.412926E+07f, 1.411171E+07f, 1.409416E+07f, 1.40766E+07f, 1.405905E+07f, 1.40415E+07f, 1.402395E+07f, 1.40064E+07f, 1.397129E+07f, 1.397129E+07f, 1.395374E+07f, 1.393619E+07f, 1.393619E+07f, 1.391864E+07f, 1.391864E+07f, 1.390109E+07f, 1.388353E+07f, 1.388353E+07f, 1.386598E+07f, 1.384843E+07f, 1.383088E+07f, 1.379577E+07f, 1.376067E+07f, 1.372557E+07f, 1.370801E+07f, 1.369046E+07f, 1.365536E+07f, 1.363781E+07f, 1.362026E+07f, 1.36027E+07f, 1.358515E+07f, 1.35676E+07f, 1.35325E+07f, 1.351494E+07f, 1.349739E+07f, 1.347984E+07f, 1.346229E+07f, 1.344474E+07f, 1.339208E+07f, 1.337453E+07f, 1.335698E+07f, 1.333943E+07f, 1.332187E+07f, 1.332187E+07f, 1.330432E+07f, 1.326922E+07f, 1.325167E+07f, 1.323411E+07f, 1.321656E+07f, 1.319901E+07f, 1.316391E+07f, 1.314635E+07f, 1.31288E+07f, 1.311125E+07f, 1.307615E+07f, 1.304104E+07f, 1.302349E+07f, 1.300594E+07f, 1.300594E+07f, 1.300594E+07f, 1.300594E+07f, 1.300594E+07f, 1.300594E+07f, 1.300594E+07f, 1.302349E+07f, 1.304104E+07f, 1.307615E+07f, 1.30937E+07f, 1.311125E+07f, 1.314635E+07f, 1.316391E+07f, 1.318146E+07f, 1.319901E+07f, 1.321656E+07f, 1.323411E+07f, 1.323411E+07f, 1.323411E+07f, 1.323411E+07f, 1.325167E+07f, 1.325167E+07f, 1.325167E+07f, 1.325167E+07f, 1.325167E+07f, 1.325167E+07f, 1.325167E+07f, 1.325167E+07f, 1.325167E+07f, 1.325167E+07f, 1.325167E+07f, 1.325167E+07f, 1.325167E+07f, 1.325167E+07f, 1.323411E+07f, 1.323411E+07f, 1.321656E+07f, 1.319901E+07f, 1.318146E+07f, 1.316391E+07f, 1.314635E+07f, 1.31288E+07f, 1.305859E+07f, 1.304104E+07f, 1.298839E+07f, 1.295328E+07f, 1.291818E+07f, 1.288308E+07f, 1.286552E+07f, 1.284797E+07f, 1.283042E+07f, 1.279532E+07f, 1.277776E+07f, 1.276021E+07f, 1.272511E+07f, 1.270756E+07f, 1.269001E+07f, 1.26549E+07f, 1.263735E+07f, 1.260225E+07f, 1.258469E+07f, 1.256714E+07f, 1.256714E+07f, 1.254959E+07f, 1.253204E+07f, 1.253204E+07f, 1.253204E+07f, 1.251449E+07f, 1.251449E+07f, 1.251449E+07f, 1.251449E+07f, 1.251449E+07f, 1.249694E+07f, 1.249694E+07f, 1.249694E+07f, 1.249694E+07f, 1.247938E+07f, 1.247938E+07f, 1.246183E+07f, 1.244428E+07f, 1.240918E+07f, 1.239162E+07f, 1.235652E+07f, 1.233897E+07f, 1.230386E+07f, 1.226876E+07f, 1.225121E+07f, 1.221611E+07f, 1.219855E+07f, 1.219855E+07f, 1.2181E+07f, 1.216345E+07f, 1.216345E+07f, 1.21459E+07f, 1.21459E+07f, 1.212835E+07f, 1.212835E+07f, 1.212835E+07f, 1.212835E+07f, 1.212835E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.211079E+07f, 1.209324E+07f, 1.207569E+07f, 1.207569E+07f, 1.204059E+07f, 1.202303E+07f, 1.200548E+07f, 1.198793E+07f, 1.197038E+07f, 1.195283E+07f, 1.193528E+07f, 1.191772E+07f, 1.190017E+07f, 1.188262E+07f, 1.186507E+07f, 1.181241E+07f, 1.181241E+07f, 1.179486E+07f, 1.177731E+07f, 1.177731E+07f, 1.177731E+07f, 1.175976E+07f, 1.175976E+07f, 1.17422E+07f, 1.17422E+07f, 1.17422E+07f, 1.17422E+07f, 1.17422E+07f, 1.17422E+07f, 1.172465E+07f, 1.172465E+07f, 1.172465E+07f, 1.172465E+07f, 1.172465E+07f, 1.172465E+07f, 1.172465E+07f, 1.172465E+07f, 1.172465E+07f, 1.172465E+07f, 1.17071E+07f, 1.168955E+07f, 1.1672E+07f, 1.163689E+07f, 1.161934E+07f, 1.160179E+07f, 1.156669E+07f, 1.154913E+07f, 1.151403E+07f, 1.149648E+07f, 1.147893E+07f, 1.146137E+07f, 1.144382E+07f, 1.144382E+07f, 1.139117E+07f, 1.139117E+07f, 1.137361E+07f, 1.137361E+07f, 1.137361E+07f, 1.137361E+07f, 1.137361E+07f, 1.137361E+07f, 1.135606E+07f, 1.135606E+07f, 1.135606E+07f, 1.135606E+07f, 1.135606E+07f, 1.135606E+07f, 1.135606E+07f, 1.135606E+07f, 1.135606E+07f, 1.135606E+07f, 1.133851E+07f, 1.133851E+07f, 1.133851E+07f, 1.133851E+07f, 1.133851E+07f, 1.130341E+07f, 1.130341E+07f, 1.128586E+07f, 1.12683E+07f, 1.125075E+07f, 1.121565E+07f, 1.116299E+07f, 1.112789E+07f, 1.107523E+07f, 1.105768E+07f

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

TLTR

The time it takes to do one Region.IsVisible(Point) call doesn't depend on the number of points at all. Instead it depends on the number of rectangles it takes to fully and precisely cover the region. Which depends on..:

  • the shapes those points describe and usually
  • the size of the shape.

Example 1: A rectangular region has four points and it always takes one rectangle to cover it. This would not change if you would add a large number of points as long as they all lie on the sides of the rectangle!

Example 2: A circular region also (!) has four points () but the number of rectangles you need to cover it fully **depends on the diameter of that circle. See the graphics at the bottom!


Full Story

Region is not what I would call a 'well-documented' class.

You can see that the inner working seems to rely on the RegionData, which can can accessed by calling var RData = your Region.GetRegionData().

Here the very same holds: Not well-documented, to say the least. Maybe I just can't find it, but there seems to be no info on how those bytes are structured..

(The numbers below suggest that each point needed takes 1 byte as a type indicator plus 2+4 bytes for the two float coordinates. This would be like the PathPoints&PathTypes in the GraphicsPath. In your example with 924+1 points and 1+2*4 bytes this makes up 8325 bytes; another 27 bytes are there; 8 could hold the scaling..)

One thing is interesting though: Looking into the RegionData from both of your Regions one can easily see that they have the same size..: 8352. This is an indication that the RegionData are not directly relevant for the additional time anyway..

But there is another, somewhat equally mysterious, read: ill-documented call: GetRegionScans. MSDN says this about it:

Returns an array of RectangleF structures that approximate this Region after the specified matrix transformation is applied.

First lets see what happens if we pull out thoses 'scans' for both of your Regions:

Matrix M = new Matrix();

var scans1 = regionFromOriginalPoints.GetRegionScans(M);
var scans2 = regionDividedby1000.GetRegionScans(M);

I use the simple identity matrix (*), i.e. no transformation and these are the reults:

scans1.Length = 5.960.690
scans2.Length = 5.956

So it creates 1000 times more rectangles to approximate the Region, and, lo and behold for doing so it also takes a lot of time..:

This is not really surprising: The unscaled path covers a huge area and to approximate it I would expect many more rectangles are needed. I don't know how the approximation works, but it might decide that, even though RectangleF are returned, no rectangle with any side being less than 1 pixel is needed.

So I conclude that the IsVisible call internally needs to create those approximation rectangles and it needs enough of them to cover every full pixel inside the region. (Note that Region does not support partial/anti-aliased pixels!) The larger the region's bounds the more pixels fit in and the longer the scanning process takes.

I also assume that it is strictly the scanning process that eats up the time.

Next: Doing a RectangleF.Contains(Point) should be extremely fast, even for a million calls. Let's see; when I measure this:

int hits = 0;
PointF pt = new PointF(123.456f, 789.012f);
foreach (RectangleF r in scans1) if (r.Contains(pt)) hits++;

..it takes only 42ms to complete. So once you have cached the scan rectangles you can easily do a lot of hit tests on them instead of doing separate IsVisible calls..

Here is a summary of the numbers :

Your original path:

number of polygon points = 924
regionData1.Length = 8.352
scans1.Length = 5.960.690
Elapsed time1: 453.187 ms

The path scaled down by 1000:

number of polygon points = 924
regionData2.Length = 8.352
scans2.Length= 5.956
Elapsed time2: 2 ms

Elapsed time for full set of scans: 41 ms


Finally: To better understand the scan rectangles I approximated a circle with alternating colors:

for (int i = 0; i < scans.Length; i++)
     g.FillRectangle(i%2 == 0 ? Brushes.ForestGreen : Brushes.Salmon, scans[i]);

enter image description here

You can see that at the top and bottom every row is one rectangle because here the curve is flat and the x coordinates move outward quickly. The closer we get to the middle the larger (i..e. taller) the rectangles can get... So we can see that the approximation strictly follows the rows..

This holds true even if the bounding rectangle is taller than wide and, using the columns, one might do with fewer rectangles:

enter image description here

Here both ellipses (222x111 and 111x222) are approximated with 85 horizontal stripes. That is less than the circle because of the different curvature..


(*) - We have skipped over the Matrix; but it could be used to modify the result by either scaling the data up or down. The circle has a Height of 222 pixels and it takes 135 scan rectangles to approximate it. If we scale up the Matrix, (i.e. the Graphics object used to represent the Region): m.Scale(10,10); it takes 1315 scan rectangles to cover the upscaled circle.

So a matrix scaled down by 0.001f could be used instead of scaling your data points; but it would test only the scaled down version and will likely either miss pixels around the borders or include wrong ones. So best use only the correct scale you actually need..

(* *) Note that the circular GraphicsPath does have 13 PathPoints; but these are really just four real points (plus the 1st one repeated to close the figure) plus two control points in between each pair of points; so 5 + 4*2 = 13. Also note that any line in a GraphicsPath is either straight or a bezier curve. This includes arcs, ellipses and circles!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...