开发者

Region.IsVisible() not working as documented (?) [GDI+]

I see that Region.IsVisible(rectangle) is not working as I expect.

So, is me who expect that should not, or is the method that is doing not that it should ??!

I have the following situation:

alt text http://lh4.ggpht.com/_1TPOP7DzY1E/TCmxn6Tzn2I/AAAAAAAADRc/GJhbStCvabQ/s800/Capture3.gif alt text http://lh5.ggpht.com/_1TPOP7DzY1E/TCmuVyrgpTI/AAAAAAAADRU/yLNn-jZQDNA/s800/Capture2.gif

And the following code:

private void Form1_Paint(object sender, PaintEventArgs e)
{
    Point[] points1 = new Point[] {
        new Point(50, 30),
        new Point(70, 30),
        new Point(40, 40),
        new Point(60, 70),
        new Point(30, 50)
    };

    Point[] points2 = new Point[] {
        new Point(70, 150),
        new Point(50, 110 ),
        new Point(60, 80),
        new Point(90, 80),
        new Point(140, 60)                
    };

    Point[] points3 = new Point[] {
        new Point(100, 10),
        new Point(130, 40)
    };

    GraphicsPath path1 = new GraphicsPath();
    GraphicsPath path2 = new GraphicsPath();
    GraphicsPath path3 = new GraphicsPath();

    path1.AddLines(points1);
    path2.AddLines(points2);
    path3.AddLines(points3);

    e.Graphics.DrawPath(Pens.DarkBlue, path1);
    e.Graphics.DrawPath(Pens.DarkGreen, path2);
    e.Graphics.DrawPath(Pens.DarkOrange, path3);

    Region r1 = new Region(path1);
    Region r2 = new Region(path2);
    Region r3 = new Region(path3);

    // Create the first rectangle and draw it to the screen in blue.
    Rectangle blueRect = new Rectangle(20, 20, 100, 100);
    e.Graphics.DrawRectangle(Pens.Blue, blueRect);

    bool conta开发者_JAVA技巧ined;

    // Display the result.                        
    ControlPaint.DrawGrid(e.Graphics, this.ClientRectangle,
        new Size(10, 10), Color.Red);

    contained = r1.IsVisible(blueRect);
    e.Graphics.DrawString("Path blue contained = " + contained.ToString(),
        Font, myBrush, new PointF(20, 160));

    contained = r2.IsVisible(blueRect);
    e.Graphics.DrawString("Path green contained = " + contained.ToString(),
        Font, Brushes.Black, new PointF(20, 180));

    contained = r3.IsVisible(blueRect);
    e.Graphics.DrawString("Path orange contained = " + contained.ToString(),
        Font, Brushes.Black, new PointF(20, 200));
}

Also, a path that is not in the region could be "visible":

Point[] points3 = new Point[] {
  new Point(15, 35),
  new Point(15, 130),
  new Point(60 ,130)
};

EDIT:

Even Intersect does not work for the second L path:

Point[] points3 = new Point[] {
    new Point(10, 40),
    new Point(10, 130),
    new Point(50 ,130)
};

r3.Intersect(blueRect);
bool contained = !(r1.IsEmpty(e.Graphics)); 
e.Graphics.DrawString("Path orange contained = " + contained.ToString(),
    Font, Brushes.Black, new PointF(20, 200)); // TRUE! instead of desired FALSE


From the orange L-shaped example I see you are misunderstanding what your code does.

Building a region from a path does not yield a region in the form of the drawn path. Building a region from the L-shaped orange path does not yield a L-shaped one pixel width region. The path gets closed by connecting both ends forming a triangle. The region is then the interior of that triangle and the blue rectangle is obviously partial contained in that region.

For the initial example of the single orange line the resulting region is a degenerated polygon with two corners only - still looking like a line and with zero width in the direction orthogonal to the line(s). Therefore the region has zero area and does not contain anything (except maybe points on the border of the region if a region is a closed set).

What you actually want to do is performing a visibility test of a path against the rectangular region of the blue rectangle. As far as I know there is no build-in support for doing this.


So, a solution for this was to use... Widen() method for paths before checking its visibility:

private void Form1_Paint(object sender, PaintEventArgs e)
{
    Point[] points1 = new Point[] {
                new Point(50, 30),
                new Point(70, 30),
                new Point(40, 40),
                new Point(60, 70),
                new Point(30, 50)
            };

    Point[] points2 = new Point[] {
                new Point(70, 150),
                new Point(50, 110 ),
                new Point(60, 80),
                new Point(90, 80),
                new Point(140, 60)
            };

    Point[] points4 = new Point[] {
        new Point(50, 50),
        new Point(90, 90)
      };

    Point[] points3 = new Point[] {
                new Point(15, 35),
                new Point(15, 130),
                new Point(60 ,130)
            };

    GraphicsPath path1 = new GraphicsPath();
    GraphicsPath path2 = new GraphicsPath();
    GraphicsPath path3 = new GraphicsPath();
    GraphicsPath path4 = new GraphicsPath();

    path1.AddLines(points1);
    path2.AddLines(points2);
    path3.AddLines(points3);
    path4.AddLines(points4);

    e.Graphics.DrawPath(Pens.DarkBlue, path1);
    e.Graphics.DrawPath(Pens.DarkGreen, path2);
    e.Graphics.DrawPath(Pens.DarkRed, path3);
    e.Graphics.DrawPath(Pens.DarkGoldenrod, path4);

    // <<<< HERE >>>>>
    path3.Widen(Pens.DarkRed);
    path4.Widen(Pens.DarkGoldenrod);

    Region r1 = new Region(path1);
    Region r2 = new Region(path2);
    Region r3 = new Region(path3);
    Region r4 = new Region(path4);

    // Create the first rectangle and draw it to the screen in blue.
    Rectangle blueRect = new Rectangle(20, 20, 100, 100);
    e.Graphics.DrawRectangle(Pens.Blue, blueRect);

    bool contained;

    // Display the result.            
    ControlPaint.DrawGrid(e.Graphics, this.ClientRectangle,
         new Size(10, 10), Color.Red);

    contained = r1.IsVisible(blueRect);
    e.Graphics.DrawString("Path blue contained = " + contained.ToString(),
         Font, Brushes.Black, new PointF(20, 160));

    contained = r2.IsVisible(blueRect);
    e.Graphics.DrawString("Path green contained = " + contained.ToString(),
         Font, Brushes.Black, new PointF(20, 180));

    contained = r3.IsVisible(blueRect);
    e.Graphics.DrawString("Path orange contained = " + contained.ToString(),
         Font, Brushes.Black, new PointF(20, 200));

    contained = r4.IsVisible(blueRect);
    e.Graphics.DrawString("Path DarkGoldenrod contained = " + contained.ToString(),
         Font, Brushes.Black, new PointF(20, 220));
}

As for the question in the thread title: Yes, actually IsVisible of Region is not working as documented in MSDN.

Microsoft should add some precision notes in their documentation.


It may be that the Region.IsVisible method just checks whether any of the endpoints of its component line segments are within the rectangle or not. Thus, the blue and green lines (which each have multiple segment endpoints within the rectangle) are true, while the orange line (which has 0 endpoints within the rectangle) is false.

Technically, your code is actually trying to determine whether each irregular Path contains the blue rectangle (rather than the other way around). An alternative way of doing what you're actually trying to do (but that will probably return the same results) is this:

r1.Intersect(blueRect);
e.Graphics.DrawString("Path blue contained = " + 
    (!r1.IsEmpty(e.Graphics)).ToString(), Font, Brushes.Black, 
    new PointF(20, 200));   


Coming in rather late on this! After some experimentation, it makes more sense to check each point in the array individually, rather than check the region. The added advantage is that you can also see whether the whole region is in or not:

Private Function AllWithin(ByVal points() As Point, ByVal r As Region) As Boolean
    ' Checks whether all the points in an array are within a region
    Dim contained As Boolean = True
    For a As Integer = 0 To points.Length - 1
        If Not r.IsVisible(points(a)) Then
            contained = False
            Exit For
        End If
    Next
    Return contained
End Function


Private Function SomeWithin(ByVal points() As Point, ByVal r As Region) As Boolean
    ' Checks whether some of the points in an array are within a region
    Dim contained As Boolean = False
    For a As Integer = 0 To points.Length - 1
        If r.IsVisible(points(a)) Then
            contained = True
            Exit For
        End If
    Next
    Return contained
End Function
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜