index.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. //index.js
  2. var deepEqual = require('deep-equal');
  3. var Equality = function(opt) {
  4. this.precision = opt && opt.precision ? opt.precision : 17;
  5. this.direction = opt && opt.direction ? opt.direction : false;
  6. this.pseudoNode = opt && opt.pseudoNode ? opt.pseudoNode : false;
  7. this.objectComparator = opt && opt.objectComparator ? opt.objectComparator : objectComparator;
  8. };
  9. Equality.prototype.compare = function(g1,g2) {
  10. if (g1.type !== g2.type || !sameLength(g1,g2)) return false;
  11. switch(g1.type) {
  12. case 'Point':
  13. return this.compareCoord(g1.coordinates, g2.coordinates);
  14. break;
  15. case 'LineString':
  16. return this.compareLine(g1.coordinates, g2.coordinates,0,false);
  17. break;
  18. case 'Polygon':
  19. return this.comparePolygon(g1,g2);
  20. break;
  21. case 'Feature':
  22. return this.compareFeature(g1, g2);
  23. default:
  24. if (g1.type.indexOf('Multi') === 0) {
  25. var context = this;
  26. var g1s = explode(g1);
  27. var g2s = explode(g2);
  28. return g1s.every(function(g1part) {
  29. return this.some(function(g2part) {
  30. return context.compare(g1part,g2part);
  31. });
  32. },g2s);
  33. }
  34. }
  35. return false;
  36. };
  37. function explode(g) {
  38. return g.coordinates.map(function(part) {
  39. return {
  40. type: g.type.replace('Multi', ''),
  41. coordinates: part}
  42. });
  43. }
  44. //compare length of coordinates/array
  45. function sameLength(g1,g2) {
  46. return g1.hasOwnProperty('coordinates') ?
  47. g1.coordinates.length === g2.coordinates.length
  48. : g1.length === g2.length;
  49. }
  50. // compare the two coordinates [x,y]
  51. Equality.prototype.compareCoord = function(c1,c2) {
  52. if (c1.length !== c2.length) {
  53. return false;
  54. }
  55. for (var i=0; i < c1.length; i++) {
  56. if (c1[i].toFixed(this.precision) !== c2[i].toFixed(this.precision)) {
  57. return false;
  58. }
  59. }
  60. return true;
  61. };
  62. Equality.prototype.compareLine = function(path1,path2,ind,isPoly) {
  63. if (!sameLength(path1,path2)) return false;
  64. var p1 = this.pseudoNode ? path1 : this.removePseudo(path1);
  65. var p2 = this.pseudoNode ? path2 : this.removePseudo(path2);
  66. if (isPoly && !this.compareCoord(p1[0],p2[0])) {
  67. // fix start index of both to same point
  68. p2 = this.fixStartIndex(p2,p1);
  69. if(!p2) return;
  70. }
  71. // for linestring ind =0 and for polygon ind =1
  72. var sameDirection = this.compareCoord(p1[ind],p2[ind]);
  73. if (this.direction || sameDirection
  74. ) {
  75. return this.comparePath(p1, p2);
  76. } else {
  77. if (this.compareCoord(p1[ind],p2[p2.length - (1+ind)])
  78. ) {
  79. return this.comparePath(p1.slice().reverse(), p2);
  80. }
  81. return false;
  82. }
  83. };
  84. Equality.prototype.fixStartIndex = function(sourcePath,targetPath) {
  85. //make sourcePath first point same as of targetPath
  86. var correctPath,ind = -1;
  87. for (var i=0; i< sourcePath.length; i++) {
  88. if(this.compareCoord(sourcePath[i],targetPath[0])) {
  89. ind = i;
  90. break;
  91. }
  92. }
  93. if (ind >= 0) {
  94. correctPath = [].concat(
  95. sourcePath.slice(ind,sourcePath.length),
  96. sourcePath.slice(1,ind+1));
  97. }
  98. return correctPath;
  99. };
  100. Equality.prototype.comparePath = function (p1,p2) {
  101. var cont = this;
  102. return p1.every(function(c,i) {
  103. return cont.compareCoord(c,this[i]);
  104. },p2);
  105. };
  106. Equality.prototype.comparePolygon = function(g1,g2) {
  107. if (this.compareLine(g1.coordinates[0],g2.coordinates[0],1,true)) {
  108. var holes1 = g1.coordinates.slice(1,g1.coordinates.length);
  109. var holes2 = g2.coordinates.slice(1,g2.coordinates.length);
  110. var cont = this;
  111. return holes1.every(function(h1) {
  112. return this.some(function(h2) {
  113. return cont.compareLine(h1,h2,1,true);
  114. });
  115. },holes2);
  116. } else {
  117. return false;
  118. }
  119. };
  120. Equality.prototype.compareFeature = function(g1,g2) {
  121. if (
  122. g1.id !== g2.id ||
  123. !this.objectComparator(g1.properties, g2.properties) ||
  124. !this.compareBBox(g1,g2)
  125. ) {
  126. return false;
  127. }
  128. return this.compare(g1.geometry, g2.geometry);
  129. };
  130. Equality.prototype.compareBBox = function(g1,g2) {
  131. if (
  132. (!g1.bbox && !g2.bbox) ||
  133. (
  134. g1.bbox && g2.bbox &&
  135. this.compareCoord(g1.bbox, g2.bbox)
  136. )
  137. ) {
  138. return true;
  139. }
  140. return false;
  141. };
  142. Equality.prototype.removePseudo = function(path) {
  143. //TODO to be implement
  144. return path;
  145. };
  146. function objectComparator(obj1, obj2) {
  147. return deepEqual(obj1, obj2, {strict: true});
  148. }
  149. module.exports = Equality;