source: node_modules/d3-geo/src/clip/rectangle.js@ e4c61dd

Last change on this file since e4c61dd was e4c61dd, checked in by istevanoska <ilinastevanoska@…>, 6 months ago

Prototype 1.1

  • Property mode set to 100644
File size: 4.9 KB
Line 
1import {abs, epsilon} from "../math.js";
2import clipBuffer from "./buffer.js";
3import clipLine from "./line.js";
4import clipRejoin from "./rejoin.js";
5import {merge} from "d3-array";
6
7var clipMax = 1e9, clipMin = -clipMax;
8
9// TODO Use d3-polygon’s polygonContains here for the ring check?
10// TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
11
12export default function clipRectangle(x0, y0, x1, y1) {
13
14 function visible(x, y) {
15 return x0 <= x && x <= x1 && y0 <= y && y <= y1;
16 }
17
18 function interpolate(from, to, direction, stream) {
19 var a = 0, a1 = 0;
20 if (from == null
21 || (a = corner(from, direction)) !== (a1 = corner(to, direction))
22 || comparePoint(from, to) < 0 ^ direction > 0) {
23 do stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
24 while ((a = (a + direction + 4) % 4) !== a1);
25 } else {
26 stream.point(to[0], to[1]);
27 }
28 }
29
30 function corner(p, direction) {
31 return abs(p[0] - x0) < epsilon ? direction > 0 ? 0 : 3
32 : abs(p[0] - x1) < epsilon ? direction > 0 ? 2 : 1
33 : abs(p[1] - y0) < epsilon ? direction > 0 ? 1 : 0
34 : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
35 }
36
37 function compareIntersection(a, b) {
38 return comparePoint(a.x, b.x);
39 }
40
41 function comparePoint(a, b) {
42 var ca = corner(a, 1),
43 cb = corner(b, 1);
44 return ca !== cb ? ca - cb
45 : ca === 0 ? b[1] - a[1]
46 : ca === 1 ? a[0] - b[0]
47 : ca === 2 ? a[1] - b[1]
48 : b[0] - a[0];
49 }
50
51 return function(stream) {
52 var activeStream = stream,
53 bufferStream = clipBuffer(),
54 segments,
55 polygon,
56 ring,
57 x__, y__, v__, // first point
58 x_, y_, v_, // previous point
59 first,
60 clean;
61
62 var clipStream = {
63 point: point,
64 lineStart: lineStart,
65 lineEnd: lineEnd,
66 polygonStart: polygonStart,
67 polygonEnd: polygonEnd
68 };
69
70 function point(x, y) {
71 if (visible(x, y)) activeStream.point(x, y);
72 }
73
74 function polygonInside() {
75 var winding = 0;
76
77 for (var i = 0, n = polygon.length; i < n; ++i) {
78 for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
79 a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
80 if (a1 <= y1) { if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding; }
81 else { if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding; }
82 }
83 }
84
85 return winding;
86 }
87
88 // Buffer geometry within a polygon and then clip it en masse.
89 function polygonStart() {
90 activeStream = bufferStream, segments = [], polygon = [], clean = true;
91 }
92
93 function polygonEnd() {
94 var startInside = polygonInside(),
95 cleanInside = clean && startInside,
96 visible = (segments = merge(segments)).length;
97 if (cleanInside || visible) {
98 stream.polygonStart();
99 if (cleanInside) {
100 stream.lineStart();
101 interpolate(null, null, 1, stream);
102 stream.lineEnd();
103 }
104 if (visible) {
105 clipRejoin(segments, compareIntersection, startInside, interpolate, stream);
106 }
107 stream.polygonEnd();
108 }
109 activeStream = stream, segments = polygon = ring = null;
110 }
111
112 function lineStart() {
113 clipStream.point = linePoint;
114 if (polygon) polygon.push(ring = []);
115 first = true;
116 v_ = false;
117 x_ = y_ = NaN;
118 }
119
120 // TODO rather than special-case polygons, simply handle them separately.
121 // Ideally, coincident intersection points should be jittered to avoid
122 // clipping issues.
123 function lineEnd() {
124 if (segments) {
125 linePoint(x__, y__);
126 if (v__ && v_) bufferStream.rejoin();
127 segments.push(bufferStream.result());
128 }
129 clipStream.point = point;
130 if (v_) activeStream.lineEnd();
131 }
132
133 function linePoint(x, y) {
134 var v = visible(x, y);
135 if (polygon) ring.push([x, y]);
136 if (first) {
137 x__ = x, y__ = y, v__ = v;
138 first = false;
139 if (v) {
140 activeStream.lineStart();
141 activeStream.point(x, y);
142 }
143 } else {
144 if (v && v_) activeStream.point(x, y);
145 else {
146 var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
147 b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
148 if (clipLine(a, b, x0, y0, x1, y1)) {
149 if (!v_) {
150 activeStream.lineStart();
151 activeStream.point(a[0], a[1]);
152 }
153 activeStream.point(b[0], b[1]);
154 if (!v) activeStream.lineEnd();
155 clean = false;
156 } else if (v) {
157 activeStream.lineStart();
158 activeStream.point(x, y);
159 clean = false;
160 }
161 }
162 }
163 x_ = x, y_ = y, v_ = v;
164 }
165
166 return clipStream;
167 };
168}
Note: See TracBrowser for help on using the repository browser.