Mercurial > hg > orthanc
comparison OrthancFramework/Sources/Images/ImageProcessing.cpp @ 4875:5dae41084ab7
fix filling polygons
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 18 Jan 2022 15:04:04 +0100 |
parents | bee6da5155dc |
children | d8c8274d4e41 |
comparison
equal
deleted
inserted
replaced
4874:bee6da5155dc | 4875:5dae41084ab7 |
---|---|
1981 }; | 1981 }; |
1982 } | 1982 } |
1983 | 1983 |
1984 | 1984 |
1985 // For an index, return y-coordinate of next nonhorizontal line | 1985 // For an index, return y-coordinate of next nonhorizontal line |
1986 static size_t GetPolygonNextY(const std::vector<ImageProcessing::ImagePoint>& points, | 1986 static int GetPolygonNextY(const std::vector<ImageProcessing::ImagePoint>& points, |
1987 size_t k) | 1987 size_t k) |
1988 { | 1988 { |
1989 // cf. "yNext()" in textbook | 1989 // cf. "yNext()" in textbook |
1990 size_t j = k; | 1990 size_t j = k; |
1991 | 1991 |
1992 for (;;) | 1992 for (;;) |
2003 } | 2003 } |
2004 } | 2004 } |
2005 } | 2005 } |
2006 | 2006 |
2007 | 2007 |
2008 static size_t GetPolygonPreviousY(const std::vector<ImageProcessing::ImagePoint>& points, | 2008 static int GetPolygonPreviousY(const std::vector<ImageProcessing::ImagePoint>& points, |
2009 size_t k) | 2009 size_t k) |
2010 { | 2010 { |
2011 size_t j = k; | 2011 size_t j = k; |
2012 | 2012 |
2013 for (;;) | 2013 for (;;) |
2014 { | 2014 { |
2044 if (points.size() < 2) | 2044 if (points.size() < 2) |
2045 { | 2045 { |
2046 return; | 2046 return; |
2047 } | 2047 } |
2048 | 2048 |
2049 bool onlyHorizontalSegments = true; | |
2050 for (size_t i = 1; i < points.size(); i++) | |
2051 { | |
2052 if (points[0].GetY() != points[i].GetY()) | |
2053 { | |
2054 onlyHorizontalSegments = false; | |
2055 break; | |
2056 } | |
2057 } | |
2058 | |
2059 if (onlyHorizontalSegments) | |
2060 { | |
2061 // Degenerate case: There are only horizontal lines. If this is | |
2062 // the case, "GetPolygonPreviousY()" will be an infinite loop | |
2063 int x1 = points[0].GetX(); | |
2064 int x2 = points[0].GetX(); | |
2065 for (size_t i = 1; i < points.size(); i++) | |
2066 { | |
2067 assert(points[i].GetY() == points[0].GetY()); | |
2068 x1 = std::min(x1, points[i].GetX()); | |
2069 x2 = std::max(x2, points[i].GetX()); | |
2070 } | |
2071 filler.Fill(points[0].GetY(), x1, x2); | |
2072 return; | |
2073 } | |
2074 | |
2049 EdgeTable globalEdgeTable; | 2075 EdgeTable globalEdgeTable; |
2050 | 2076 |
2051 // cf. "buildEdgeList()" in textbook | 2077 // cf. "buildEdgeList()" in textbook |
2052 | 2078 |
2053 // Error in the textbook: we use "GetPolygonPreviousY()" instead of "points.size() - 2" | 2079 // Error in the textbook: we use "GetPolygonPreviousY()" instead of "points.size() - 2" |
2079 } | 2105 } |
2080 | 2106 |
2081 v1 = v2; | 2107 v1 = v2; |
2082 } | 2108 } |
2083 | 2109 |
2084 if (globalEdgeTable.empty()) | 2110 assert(!globalEdgeTable.empty()); |
2085 { | |
2086 // Degenerate case: There were only horizontal lines | |
2087 int x1 = points[0].GetX(); | |
2088 int x2 = points[0].GetX(); | |
2089 for (size_t i = 1; i < points.size(); i++) | |
2090 { | |
2091 assert(points[i].GetY() == points[0].GetY()); | |
2092 x1 = std::min(x1, points[i].GetX()); | |
2093 x2 = std::max(x2, points[i].GetX()); | |
2094 } | |
2095 filler.Fill(points[0].GetY(), x1, x2); | |
2096 return; | |
2097 } | |
2098 | 2111 |
2099 std::vector<PolygonEdge> activeEdges; | 2112 std::vector<PolygonEdge> activeEdges; |
2100 | 2113 |
2101 for (EdgeTable::const_iterator it = globalEdgeTable.begin(); it != globalEdgeTable.end(); ++it) | 2114 for (EdgeTable::const_iterator it = globalEdgeTable.begin(); it != globalEdgeTable.end(); ++it) |
2102 { | 2115 { |
2145 | 2158 |
2146 assert(activeEdges.size() % 2 == 0); | 2159 assert(activeEdges.size() % 2 == 0); |
2147 std::sort(activeEdges.begin(), activeEdges.end()); | 2160 std::sort(activeEdges.begin(), activeEdges.end()); |
2148 | 2161 |
2149 // cf. "fillScan()" in textbook | 2162 // cf. "fillScan()" in textbook |
2150 for (size_t k = 0; k + 1 < activeEdges.size(); k += 2) | 2163 for (size_t k = 0; k + 1 < activeEdges.size(); ) |
2151 { | 2164 { |
2152 int a = activeEdges[k].GetExitX(); | 2165 int a = activeEdges[k].GetExitX(); |
2153 int b = activeEdges[k + 1].GetEnterX(); | 2166 int b = activeEdges[k + 1].GetEnterX(); |
2154 filler.Fill(y, std::min(a, b), std::max(a, b)); | 2167 |
2168 // Fix wrt. the textbook: merge overlapping segments | |
2169 k += 2; | |
2170 while (k + 1 < activeEdges.size() && | |
2171 activeEdges[k].GetExitX() == b) | |
2172 { | |
2173 assert(a <= b); | |
2174 b = activeEdges[k + 1].GetEnterX(); | |
2175 k += 2; | |
2176 } | |
2177 | |
2178 assert(a <= b); | |
2179 filler.Fill(y, a, b); | |
2155 } | 2180 } |
2156 | 2181 |
2157 // cf. "updateActiveList()" in textbook | 2182 // cf. "updateActiveList()" in textbook |
2158 for (size_t k = 0; k < activeEdges.size(); k++) | 2183 for (size_t k = 0; k < activeEdges.size(); k++) |
2159 { | 2184 { |