eaeb29cb创建于 2025年2月7日历史提交
import GeoJSON from '../../../../../src/ol/format/GeoJSON.js';
import {
  inflateEnds,
  linearRingIsClockwise,
  linearRingsAreOriented,
  linearRingssAreOriented,
  orientLinearRings,
  orientLinearRingsArray,
} from '../../../../../src/ol/geom/flat/orient.js';
import RenderFeature from '../../../../../src/ol/render/Feature.js';
import expect from '../../../expect.js';

describe('ol/geom/flat/orient.js', function () {
  describe('linearRingIsClockwise', function () {
    it('identifies clockwise rings', function () {
      const flatCoordinates = [0, 1, 1, 4, 4, 3, 3, 0];
      const isClockwise = linearRingIsClockwise(
        flatCoordinates,
        0,
        flatCoordinates.length,
        2,
      );
      expect(isClockwise).to.be(true);
    });

    it('identifies anti-clockwise rings', function () {
      const flatCoordinates = [2, 2, 3, 2, 3, 3, 2, 3];
      const isClockwise = linearRingIsClockwise(
        flatCoordinates,
        0,
        flatCoordinates.length,
        2,
      );
      expect(isClockwise).to.be(false);
    });

    it('identifies clockwise with duplicated coordinates', function () {
      const flatCoordinates = [0, 1, 0, 1, 1, 4, 1, 4, 4, 3, 4, 3, 3, 0, 3, 0];
      const isClockwise = linearRingIsClockwise(
        flatCoordinates,
        0,
        flatCoordinates.length,
        2,
      );
      expect(isClockwise).to.be(true);
    });

    it('identifies anti-clockwise with duplicated coordinates', function () {
      const flatCoordinates = [2, 2, 2, 2, 3, 2, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3];
      const isClockwise = linearRingIsClockwise(
        flatCoordinates,
        0,
        flatCoordinates.length,
        2,
      );
      expect(isClockwise).to.be(false);
    });

    it('identifies clockwise when last coordinate equals first', function () {
      const flatCoordinates = [0, 1, 1, 4, 4, 3, 3, 0, 0, 1];
      const isClockwise = linearRingIsClockwise(
        flatCoordinates,
        0,
        flatCoordinates.length,
        2,
      );
      expect(isClockwise).to.be(true);
    });

    it('identifies anti-clockwise when last coordinate equals first', function () {
      const flatCoordinates = [2, 2, 3, 2, 3, 3, 2, 3, 2, 2];
      const isClockwise = linearRingIsClockwise(
        flatCoordinates,
        0,
        flatCoordinates.length,
        2,
      );
      expect(isClockwise).to.be(false);
    });

    it('returns undefined when ring has too few vertices', function () {
      const flatCoordinates = [2, 2, 3, 2];
      const isClockwise = linearRingIsClockwise(
        flatCoordinates,
        0,
        flatCoordinates.length,
        2,
      );
      expect(isClockwise).to.be(undefined);
    });
  });

  describe('linearRingsAreOriented', function () {
    const oriented = linearRingsAreOriented;

    const rightCoords = [
      -180, -90, 180, -90, 180, 90, -180, 90, -180, -90, -100, -45, -100, 45,
      100, 45, 100, -45, -100, -45,
    ];

    const leftCoords = [
      -180, -90, -180, 90, 180, 90, 180, -90, -180, -90, -100, -45, 100, -45,
      100, 45, -100, 45, -100, -45,
    ];

    const ends = [10, 20];

    it('checks for left-hand orientation by default', function () {
      expect(oriented(rightCoords, 0, ends, 2)).to.be(false);
      expect(oriented(leftCoords, 0, ends, 2)).to.be(true);
    });

    it('can check for right-hand orientation', function () {
      expect(oriented(rightCoords, 0, ends, 2, true)).to.be(true);
      expect(oriented(leftCoords, 0, ends, 2, true)).to.be(false);
    });
  });

  describe('linearRingssAreOriented', function () {
    const oriented = linearRingssAreOriented;

    const rightCoords = [
      -180, -90, 180, -90, 180, 90, -180, 90, -180, -90, -100, -45, -100, 45,
      100, 45, 100, -45, -100, -45, -180, -90, 180, -90, 180, 90, -180, 90,
      -180, -90, -100, -45, -100, 45, 100, 45, 100, -45, -100, -45,
    ];

    const leftCoords = [
      -180, -90, -180, 90, 180, 90, 180, -90, -180, -90, -100, -45, 100, -45,
      100, 45, -100, 45, -100, -45, -180, -90, -180, 90, 180, 90, 180, -90,
      -180, -90, -100, -45, 100, -45, 100, 45, -100, 45, -100, -45,
    ];

    const ends = [
      [10, 20],
      [30, 40],
    ];

    it('checks for left-hand orientation by default', function () {
      expect(oriented(rightCoords, 0, ends, 2)).to.be(false);
      expect(oriented(leftCoords, 0, ends, 2)).to.be(true);
    });

    it('can check for right-hand orientation', function () {
      expect(oriented(rightCoords, 0, ends, 2, true)).to.be(true);
      expect(oriented(leftCoords, 0, ends, 2, true)).to.be(false);
    });
  });

  describe('orientLinearRings', function () {
    const orient = orientLinearRings;

    const rightCoords = [
      -180, -90, 180, -90, 180, 90, -180, 90, -180, -90, -100, -45, -100, 45,
      100, 45, 100, -45, -100, -45,
    ];

    const leftCoords = [
      -180, -90, -180, 90, 180, 90, 180, -90, -180, -90, -100, -45, 100, -45,
      100, 45, -100, 45, -100, -45,
    ];

    const ends = [10, 20];

    it('orients using the left-hand rule by default', function () {
      const rightClone = rightCoords.slice();
      orient(rightClone, 0, ends, 2);
      expect(rightClone).to.eql(leftCoords);

      const leftClone = leftCoords.slice();
      orient(leftClone, 0, ends, 2);
      expect(leftClone).to.eql(leftCoords);
    });

    it('can orient using the right-hand rule', function () {
      const rightClone = rightCoords.slice();
      orient(rightClone, 0, ends, 2, true);
      expect(rightClone).to.eql(rightCoords);

      const leftClone = leftCoords.slice();
      orient(leftClone, 0, ends, 2, true);
      expect(leftClone).to.eql(rightCoords);
    });
  });

  describe('orientLinearRingsArray', function () {
    const orient = orientLinearRingsArray;

    const rightCoords = [
      -180, -90, 180, -90, 180, 90, -180, 90, -180, -90, -100, -45, -100, 45,
      100, 45, 100, -45, -100, -45, -180, -90, 180, -90, 180, 90, -180, 90,
      -180, -90, -100, -45, -100, 45, 100, 45, 100, -45, -100, -45,
    ];

    const leftCoords = [
      -180, -90, -180, 90, 180, 90, 180, -90, -180, -90, -100, -45, 100, -45,
      100, 45, -100, 45, -100, -45, -180, -90, -180, 90, 180, 90, 180, -90,
      -180, -90, -100, -45, 100, -45, 100, 45, -100, 45, -100, -45,
    ];

    const ends = [
      [10, 20],
      [30, 40],
    ];

    it('orients using the left-hand rule by default', function () {
      const rightClone = rightCoords.slice();
      orient(rightClone, 0, ends, 2);
      expect(rightClone).to.eql(leftCoords);

      const leftClone = leftCoords.slice();
      orient(leftClone, 0, ends, 2);
      expect(leftClone).to.eql(leftCoords);
    });

    it('can orient using the right-hand rule', function () {
      const rightClone = rightCoords.slice();
      orient(rightClone, 0, ends, 2, true);
      expect(rightClone).to.eql(rightCoords);

      const leftClone = leftCoords.slice();
      orient(leftClone, 0, ends, 2, true);
      expect(leftClone).to.eql(rightCoords);
    });
  });

  describe('inflateEnds', function () {
    const data = `{
      "type": "FeatureCollection",
      "name": "7-64-55",
      "features": [
      { "type": "Feature", "properties": { "mvt_id": 1 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 0.11810302734375, 24.046463999666589 ], [ 0.237579345703125, 24.046463999666589 ], [ 0.237579345703125, 23.956136333969283 ], [ 0.11810302734375, 23.956136333969283 ], [ 0.11810302734375, 24.046463999666589 ] ], [ [ 0.153121948242188, 24.01949779624486 ], [ 0.153121948242188, 23.979978958263413 ], [ 0.2032470703125, 23.979978958263413 ], [ 0.2032470703125, 24.01949779624486 ], [ 0.153121948242188, 24.01949779624486 ] ] ] ] } },
      { "type": "Feature", "properties": { "mvt_id": 26 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 0.293197631835938, 24.036430724667376 ], [ 0.389328002929688, 24.036430724667376 ], [ 0.3570556640625, 23.95864629158493 ], [ 0.260238647460938, 23.95864629158493 ], [ 0.293197631835938, 24.036430724667376 ] ], [ [ 0.342636108398438, 24.0332951655089 ], [ 0.32684326171875, 23.988761970899695 ], [ 0.352935791015625, 23.988761970899695 ], [ 0.369415283203125, 24.0332951655089 ], [ 0.342636108398438, 24.0332951655089 ] ], [ [ 0.291824340820312, 24.018870607907278 ], [ 0.291824340820312, 23.971195346707443 ], [ 0.319290161132813, 23.971195346707443 ], [ 0.319290161132813, 24.018870607907278 ], [ 0.291824340820312, 24.018870607907278 ] ] ] ] } },
      { "type": "Feature", "properties": { "mvt_id": 30 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 0.287704467773438, 24.219414393426444 ], [ 0.350875854492188, 24.219414393426444 ], [ 0.33233642578125, 24.147380157655896 ], [ 0.268478393554688, 24.147380157655896 ], [ 0.287704467773438, 24.219414393426444 ] ] ], [ [ [ 0.3460693359375, 24.166802085303235 ], [ 0.372848510742188, 24.166802085303235 ], [ 0.383148193359375, 24.144873887414654 ], [ 0.355682373046875, 24.144873887414654 ], [ 0.3460693359375, 24.166802085303235 ] ] ], [ [ [ 0.352249145507812, 24.218161971731128 ], [ 0.377655029296875, 24.218161971731128 ], [ 0.383834838867187, 24.186847428521244 ], [ 0.358428955078125, 24.186847428521244 ], [ 0.352249145507812, 24.218161971731128 ] ] ] ] } },
      { "type": "Feature", "properties": { "mvt_id": 33 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 0.10986328125, 24.168055011483165 ], [ 0.199813842773438, 24.168055011483165 ], [ 0.199813842773438, 24.075305297879073 ], [ 0.10986328125, 24.075305297879073 ], [ 0.10986328125, 24.168055011483165 ] ] ], [ [ [ 0.202560424804687, 24.16742854993004 ], [ 0.240325927734375, 24.16742854993004 ], [ 0.240325927734375, 24.128581933124689 ], [ 0.202560424804687, 24.128581933124689 ], [ 0.202560424804687, 24.16742854993004 ] ] ] ] } },
      { "type": "Feature", "properties": { "mvt_id": 48 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 0.268478393554688, 24.136101554583817 ], [ 0.336456298828125, 24.136101554583817 ], [ 0.31585693359375, 24.047718103928766 ], [ 0.247879028320312, 24.047718103928766 ], [ 0.268478393554688, 24.136101554583817 ] ], [ [ 0.27191162109375, 24.123568606548453 ], [ 0.27191162109375, 24.07279761626851 ], [ 0.31585693359375, 24.07279761626851 ], [ 0.31585693359375, 24.123568606548453 ], [ 0.27191162109375, 24.123568606548453 ] ] ], [ [ [ 0.328216552734375, 24.077812930451806 ], [ 0.357742309570313, 24.077812930451806 ], [ 0.3680419921875, 24.05085331099432 ], [ 0.339202880859375, 24.05085331099432 ], [ 0.328216552734375, 24.077812930451806 ] ] ] ] } }
      ]
      }`;
    const features = new GeoJSON().readFeatures(data);
    const renderFeatures = features.map((feature) => {
      const multipolygon = feature.getGeometry();
      const flatCoordinates = multipolygon.getFlatCoordinates();
      const ends = multipolygon.getEndss().flat();
      return new RenderFeature(
        'Polygon',
        flatCoordinates,
        ends,
        2,
        {},
        feature.getId(),
      );
    });

    it('inflates ends', function () {
      renderFeatures.forEach((renderFeature, i) => {
        const ends = renderFeature.getEnds();
        expect(inflateEnds(renderFeature.getFlatCoordinates(), ends)).to.eql(
          features[i].getGeometry().getEndss(),
        );
      });
    });
  });
});