-1

This is my implementation of Sutherland-Hodgman Polygon Clipping Algorithm.

I am trying to clip a Positively Oriented and Convex polygon with a rectangular clipping area.

I am using BGI library from colorado university. I am using OS=Win7. Visual C++ 2008 Express.

This program isn't working correctly.

enter image description here

//Sutherland-Holdgman Line Clipping
#include "Line2d.h"
#include "Rectangle2d.h"
#include "Coordinates2d.h"
#include "Bits.h"
#include "Polygon2d.h"
#include <list>

typedef enum PointPosition 
{
    Left, Right
} PointPosition;

typedef enum LinePosition 
{
    CompletelyOut, CompletelyIn, ClippingCandidate, ClippingCandidateExtended
} LinePosition;

class ClippingPolygon2d
{
private:
    Rectangle2d rectangle;
    Polygon2d polygon;

public:
    ClippingPolygon2d(){}
    //ClippingPolygon2d(Rectangle2d & rectangle, Polygon2d & polygon): rectangle(rectangle), polygon(polygon){}
    void SetCandidatePolygon(Polygon2d & pol)
    {
        polygon = pol;
    }
    void SetClippingPolygon(Rectangle2d & rect)
    {
        rectangle = rect;
    }
public:
    std::vector<Point2d> GetClippedPoints()
    {
        std::vector<Point2d> vertexList = polygon.GetVertices();
        std::vector<Point2d> clipping = rectangle.GetVertices();

        for (size_t i = 0; i < clipping.size(); i++) 
        {
            //obtaining one vertex and the next one from the clipping region.
            //Then, constructing a line from them.
            Line2d clippingEdge(clipping[i], clipping[(i + 1) % clipping.size()]);
            std::vector<Point2d> temp;

            for (size_t j = 0; j < vertexList.size(); j++) 
            {
                Point2d polygonEdgeStart = vertexList[j];
                Point2d polygonEdgeEnd = vertexList[(j + 1) % vertexList.size()];

                if (clippingEdge.onLeft(polygonEdgeStart)) 
                {
                    if (clippingEdge.onLeft(polygonEdgeEnd)) 
                    {
                        // point on the left, just add to vertexList
                        temp.push_back(polygonEdgeEnd);
                    } 
                    else //Right
                    {
                        // calculate intersection I and add it to vertexList
                        temp.push_back(clippingEdge.GetIntersection(Line2d(polygonEdgeStart, polygonEdgeEnd)));
                    }
                } 
                else //Right
                {
                    if (clippingEdge.onLeft(polygonEdgeEnd)) 
                    {
                        //calculate intersection I and add I and polygonEdgeEnd to vertexList
                        temp.push_back(clippingEdge.GetIntersection(Line2d(polygonEdgeStart, polygonEdgeEnd)));
                        temp.push_back(polygonEdgeEnd);
                    } 
                    else //Right
                    {
                        // nothing to do: outside of the window
                    }
                }
            }
            vertexList = temp;
        }
        return vertexList;
    }
};

int main()
{
    ////////////////////////    Initialize  ///////////////////////
    Coordinates2d::ShowWindow("Sutherland-Hodgeman Line Clipping"); 
    ///////////////////////////////////////////////////////////////

    Rectangle2d rectangle(Point2d(20, 20), Point2d(200, 140));  

Polygon2d polygon;
polygon.Add(Point2d(30, 40));
polygon.Add(Point2d(110,40));
polygon.Add(Point2d(130,110));
polygon.Add(Point2d(70,150));
polygon.Add(Point2d(10,110));

    ClippingPolygon2d clip;
    clip.SetClippingPolygon(rectangle);
    clip.SetCandidatePolygon(polygon);

    std::vector<Point2d> clippedVerticesList = clip.GetClippedPoints();

    Coordinates2d::Draw(polygon, Red);
    Coordinates2d::Draw(rectangle, Magenta);
    Coordinates2d::Draw(clippedVerticesList, Thick, Yellow);

    ////////////////////////     Draw     /////////////////////////
    Coordinates2d::Wait(); return 0;
    ///////////////////////////////////////////////////////////////
}

double Line2d :: orientationOf(Point2d & point)
{
    return (end.x - start.x) * (point.y - start.y) - (end.y - start.y) * (point.x - start.x);
}

bool Line2d :: onRight(Point2d & point) 
{
    return orientationOf(point) < -E; //for precision reason
}

bool Line2d :: onLeft(Point2d & point)
{
    return orientationOf(point) > E;//for precision reason
}
user366312
  • 16,949
  • 65
  • 235
  • 452
  • Pardon the obvious question... but what is the "desired result"? Could you clearly state what you are hoping to achieve? Also there are a lot of includes, what (if any) external libraries are you using? Finally, what OS and compiler (And compiler version) are you using? – Lilith Daemon Jul 20 '15 at 23:24
  • Could you upload it to imgur or a similar site if SO isn't functioning? It appears that you have uploaded an image, but try imgur if you need to use more. – Lilith Daemon Jul 21 '15 at 00:50
  • 1
    Looking at the image you posted, are points (4,2) and (9,6) false positives? – Lilith Daemon Jul 21 '15 at 00:53
  • That is what I was expecting. I don't have the library in question installed to test it, but that is what appeared to be the case. It appears your code is only checking for interceptions at the vertices, rather than through the entire scenario. I would honestly suggest setting it up to output to a console every calculation/decision that it makes so you can determine where it is generating the false-positives/negatives. Otherwise, you could use a debugger to run through it line-by-line. Regardless the path, try and find some discrepancy between the data and expected data. – Lilith Daemon Jul 21 '15 at 01:13
  • TLDR; Try and make sure the detection algorithm works on the vertices (This should be the easiest to start at) before working towards finding intersecting lines. – Lilith Daemon Jul 21 '15 at 01:16

1 Answers1

1

I found at least 2 problems in GetClippedPoints function:

  1. you use if(i) - it's not right because i iterates on windows edges. I think that you suppose to use if(j).
  2. supposed that for(size_t i=0 ; i<clippingRegionLines.size() ; i++) should transform (generate new) vertexList (initially vertexList==allPolygonVertexes) and use it in next step. (so after all iterations of this loop you will get clipped polygon). So my advice here: represent input polygon as list of vertexes instead of list of edges.

Also you need to be sure that std::vector<Line2d> clippingRegionLines = rectangle.GetLines(); returns segments oriented counter-clockwise.

knok16
  • 581
  • 1
  • 5
  • 15
  • I did some prototyping in java - and got something like [this](https://ideone.com/wYJ4rS), not sure that it will work for all inputs (maybe I missed some edge cases) but it works at least for original polygon and windows. – knok16 Jul 21 '15 at 23:13