File: clipPolygon_clipper.m

package info (click to toggle)
octave-geometry 4.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 720 kB
  • sloc: cpp: 5,358; python: 379; objc: 328; makefile: 25
file content (181 lines) | stat: -rw-r--r-- 7,281 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
## Copyright (C) 2015-2019 - Philip Nienhuis
## Copyright (C) 2017 - Juan Pablo Carbajal
## Copyright (C) 2017 - Piyush Jain
##
## This program is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deffn {}  [@var{outpol}, @var{npol}] = clipPolygon_clipper (@var{inpol}, @var{clippol})
## @deffnx {} [@var{outpol}, @var{npol}] = clipPolygon_clipper (@var{inpol}, @var{clippol}, @var{op})
## @deffnx {} [@var{outpol}, @var{npol}] = clipPolygon_clipper (@var{inpol}, @var{clippol}, @var{op}, @var{rules}, @var{rulec})
## Perform boolean operation on polygon(s) using the Clipper library.
##
## @var{inpol} = Nx2 matrix of (X, Y) coordinates constituting the polygons(s)
## to be clipped. Polygons are separated by [NaN NaN] rows. @var{clippol} =
## another Nx2 matrix of (X, Y) coordinates representing the clip polygon(s).
##
## Optional argument @var{op}, the boolean operation, can be:
##
## @itemize
## @item 0: difference @var{inpol} - @var{clippol}
##
## @item 1: intersection ("AND") of @var{inpol} and @var{clippol} (= default)
##
## @item 2: exclusiveOR ("XOR") of @var{inpol} and @var{clippol}
##
## @item 3: union ("OR") of @var{inpol} and @var{clippol}
## @end itemize
##
## In addition a rule can be specified to instruct polyclip how to assess
## holes, or rather, how to assess polygon fill. This works as follows: start
## with a winding number of zero (0). From a point outside all polygons
## specified in @var{INPOL}, go to the center of the innermost polygon and note
## which polygons are crossed. For each polygon boundary crossing from right
## to left, increase the winding number, while for each polygon crossing from
## left to right, decrement it, and then assign it to the crossed polygon.
## @var{rules} and @var{rulec} can be set individually for subject and clip
## polygons, respectively, as follows:
##
## @itemize
## @item 0 Even-Odd, also called Alternate (= default):
## The first polygon crossed specifies the outer boundary of a filled polygon,
## the next polygon (if present) specifies the inner boundary of that filled
## polygon, and so on. Winding direction (clockwise or counterclockwise) is
## irrelevant here.
##
## @item 1 Non-Zero:
## All polygons with a non-zero winding number are filled.
##
## @item 2 Positive:
## All polygons with a winding number > 0 are filled. This is the usual setting
## for counterclockwise polygons to be the outer, and clockwise polygons to be
## the inner boundary ("holes") of complex polygons.
##
## @item 3 Negative:
## All polygons with a winding number < 0 are filled.
## @end itemize
## (for details see [1])
##
## Output array @var{outpol} will be an Nx2 array of polygons resulting from
## the requested boolean operation, or in case of just one input argument an
## Nx1 array indicating winding direction of each subpolygon in input argument
## @var{inpol}.
##
## [1]: @uref{http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/PolyFillType.htm}
##
## @seealso{clipPolygon_mrf,clipPolygon}
## @end deffn

## Author: Philip Nienhuis <prnienhuis@users.sf.net>
## Created: 2015-05-03
## Based on Clipper library, polyclipping.sf.net, 3rd Party, Matlab

function [outpoly, npol] = clipPolygon_clipper (inpoly, clippoly, method=1, rules=0, rulec=0)

  ## Input validation
  if (nargin < 3)
    print_usage ();
  endif
  if (! isnumeric (inpoly) || size (inpoly, 2) < 2)
    error ("Octave:invalid-input-arg", ...
           "clipPolygon: inpoly should be a numeric Nx2 array");
  endif
  if (! isnumeric (clippoly) || size (clippoly, 2) < 2)
    error ("Octave:invalid-input-arg", ...
           "clipPolygon: clippoly should be a numeric Nx2 array");
  elseif (! isnumeric (method) || method < 0 || method > 3)
    error ("Octave:invalid-input-arg", ...
           "clipPolygon: operation must be a number in the range [0..3]");
  elseif (! isnumeric (rules) || ! isnumeric (rulec) || rules < 0 || rulec < 0)
    error ("Octave:invalid-input-arg", ...
           "clipPolygon: fill type rules must be nummbers in range [0..3]");
  endif

  [inpol, xy_mean, xy_magn] = __dbl2int64__ (inpoly, clippoly);

  clpol = __dbl2int64__ (clippoly, [], xy_mean, xy_magn);

  ## Perform boolean operation
  outpol = clipper (inpol, clpol, method, rules, rulec);
  npol   = numel (outpol);

  if (! isempty (outpol))
    ## Morph struct output into [X,Y] array. Put NaNs between sub-polys. First X:
    [tmp(1:2:2*npol, 1)] = deal ({outpol.x});
    [tmp(2:2:2*npol, 1)] = ...
                cellfun (@(x) [x(1); NaN], tmp(1:2:2*npol, 1), "uni", 0);
    ## Convert back from in64 into double, wipe trailing NaN
    X = double (cell2mat (tmp))(1:end-1);
    ## Y-coordinates:
    [tmp(1:2:2*npol, 1)] = deal ({outpol.y});
    [tmp(2:2:2*npol, 1)] = ...
                cellfun (@(y) [y(1); NaN], tmp(1:2:2*npol, 1), "uni", 0);
    Y = double (cell2mat (tmp))(1:end-1);

    outpoly = ([X Y] / xy_magn) + xy_mean;
  else
    outpoly = zeros (0, 2);
  endif

endfunction

%!demo
%! pol1 = [2 2; 6 2; 6 6; 2 6; 2 2; NaN NaN; 3 3; 3 5; 5 5; 5 3; 3 3];
%! pol2 = [1 2; 7 4; 4 7; 1 2; NaN NaN; 2.5 3; 5.5 4; 4 5.5; 2.5 3];
%! lw   = 2;
%!
%! subplot (2, 7, [1 2])
%! pol1a = polygon2patch (pol1);
%! patch (pol1a(:, 1), pol1a(:, 2), 'facecolor', 'c', 'edgecolor', 'k', 'linewidth', lw);
%! axis image
%! title ("1. Subject polygon")
%! axis off
%!
%! subplot (2, 7, [3 4])
%! patch (pol1a(:, 1), pol1a(:, 2), 'facecolor', 'c', 'edgecolor', 'none');
%! hold on
%! pol2a = polygon2patch (pol2);
%! patch (pol2a(:, 1), pol2a(:, 2), 'facecolor', 'y', 'edgecolor', 'b', 'linewidth', lw);
%! axis image
%! title "2. Clip polygon"
%! axis off
%!
%! op   = {"Sub - clip", "AND / Intersection", "Exclusive OR", "OR / Union"};
%! for i=1:numel(op)
%!   subplot (6, 4, [12 16]+i);
%!   [opol, npol] = clipPolygon_clipper (pol1, pol2, i-1);
%!   opol = polygon2patch (opol);
%!   patch (pol1a(:, 1), pol1a(:, 2), 'facecolor', 'c', 'edgecolor', 'none');
%!   hold on
%!   patch (pol2a(:, 1), pol2a(:, 2), 'facecolor', 'y', 'edgecolor', 'none');
%!   patch (opol(:,1),opol(:,2), 'facecolor', 'g', 'edgecolor', 'r', ...
%!         'linewidth', lw);
%!   axis image
%!   grid on
%!   title (sprintf("%d. %s", i+3, op{i}));
%!   axis off
%! endfor
%!
%! subplot (2, 7, [6 7]);
%!   [opol, npol] = clipPolygon_clipper (pol2, pol1, 0);
%!   opol = polygon2patch (opol);
%!   patch (pol1a(:, 1), pol1a(:, 2), 'facecolor', 'c', 'edgecolor', 'none');
%!   hold on
%!   patch (pol2a(:, 1), pol2a(:, 2), 'facecolor', 'y', 'edgecolor', 'none');
%!   patch (opol(:,1),opol(:,2), 'facecolor', 'g', 'edgecolor', 'r', ...
%!         'linewidth', lw);
%!   axis image
%!   grid on
%!   axis off
%!   title "3. Clip - sub";