|
8 | 8 |
|
9 | 9 |
|
10 | 10 | 'use strict';
|
| 11 | +var dot = require('./matrix').dot; |
11 | 12 |
|
12 | 13 | /**
|
13 | 14 | * Turn an array of [x, y] pairs into a polygon object
|
@@ -118,4 +119,80 @@ polygon.tester = function tester(ptsIn) {
|
118 | 119 | };
|
119 | 120 | };
|
120 | 121 |
|
| 122 | +/** |
| 123 | + * Test if a segment of a points array is bent or straight |
| 124 | + * |
| 125 | + * @param pts Array of [x, y] pairs |
| 126 | + * @param start the index of the proposed start of the straight section |
| 127 | + * @param end the index of the proposed end point |
| 128 | + * @param tolerance the max distance off the line connecting start and end |
| 129 | + * before the line counts as bent |
| 130 | + * @returns boolean: true means this segment is bent, false means straight |
| 131 | + */ |
| 132 | +var isBent = polygon.isSegmentBent = function isBent(pts, start, end, tolerance) { |
| 133 | + var startPt = pts[start], |
| 134 | + segment = [pts[end][0] - startPt[0], pts[end][1] - startPt[1]], |
| 135 | + segmentSquared = dot(segment, segment), |
| 136 | + segmentLen = Math.sqrt(segmentSquared), |
| 137 | + unitPerp = [-segment[1] / segmentLen, segment[0] / segmentLen], |
| 138 | + i, |
| 139 | + part, |
| 140 | + partParallel; |
| 141 | + |
| 142 | + for(i = start + 1; i < end; i++) { |
| 143 | + part = [pts[i][0] - startPt[0], pts[i][1] - startPt[1]]; |
| 144 | + partParallel = dot(part, segment); |
| 145 | + |
| 146 | + if(partParallel < 0 || partParallel > segmentSquared || |
| 147 | + Math.abs(dot(part, unitPerp)) > tolerance) return true; |
| 148 | + } |
| 149 | + return false; |
| 150 | +}; |
| 151 | + |
| 152 | +/** |
| 153 | + * Make a filtering polygon, to minimize the number of segments |
| 154 | + * |
| 155 | + * @param pts Array of [x, y] pairs (must start with at least 1 pair) |
| 156 | + * @param tolerance the maximum deviation from straight allowed for |
| 157 | + * removing points to simplify the polygon |
| 158 | + * |
| 159 | + * @returns Object {addPt, raw, filtered} |
| 160 | + * addPt is a function(pt: [x, y] pair) to add a raw point and |
| 161 | + * continue filtering |
| 162 | + * raw is all the input points |
| 163 | + * filtered is the resulting filtered Array of [x, y] pairs |
| 164 | + */ |
| 165 | +polygon.filter = function filter(pts, tolerance) { |
| 166 | + var ptsFiltered = [pts[0]], |
| 167 | + doneRawIndex = 0, |
| 168 | + doneFilteredIndex = 0; |
| 169 | + |
| 170 | + function addPt(pt) { |
| 171 | + pts.push(pt); |
| 172 | + var prevFilterLen = ptsFiltered.length, |
| 173 | + iLast = doneRawIndex; |
| 174 | + ptsFiltered.splice(doneFilteredIndex + 1); |
| 175 | + |
| 176 | + for(var i = iLast + 1; i < pts.length; i++) { |
| 177 | + if(i === pts.length - 1 || isBent(pts, iLast, i + 1, tolerance)) { |
| 178 | + ptsFiltered.push(pts[i]); |
| 179 | + if(ptsFiltered.length < prevFilterLen - 2) { |
| 180 | + doneRawIndex = i; |
| 181 | + doneFilteredIndex = ptsFiltered.length - 1; |
| 182 | + } |
| 183 | + iLast = i; |
| 184 | + } |
| 185 | + } |
| 186 | + } |
121 | 187 |
|
| 188 | + if(pts.length > 1) { |
| 189 | + var lastPt = pts.pop(); |
| 190 | + addPt(lastPt); |
| 191 | + } |
| 192 | + |
| 193 | + return { |
| 194 | + addPt: addPt, |
| 195 | + raw: pts, |
| 196 | + filtered: ptsFiltered |
| 197 | + }; |
| 198 | +}; |
0 commit comments