• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

iTowns / itowns / 19370027693

14 Nov 2025 03:55PM UTC coverage: 87.899% (+0.08%) from 87.824%
19370027693

push

github

ftoromanoff
fix(VPC): reprojection for VPC layer

2756 of 3555 branches covered (77.52%)

Branch coverage included in aggregate %.

25 of 29 new or added lines in 2 files covered. (86.21%)

167 existing lines in 14 files now uncovered.

28043 of 31484 relevant lines covered (89.07%)

1228.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.98
/packages/Main/src/Source/VpcSource.js
1
import { CRS } from '@itowns/geographic';
1✔
2
import LASParser from 'Parser/LASParser';
1✔
3
import Fetcher from 'Provider/Fetcher';
1✔
4
import Source from 'Source/Source';
1✔
5
import EntwinePointTileSource from 'Source/EntwinePointTileSource';
1✔
6
import CopcSource from 'Source/CopcSource';
1✔
7
import { LRUCache } from 'lru-cache';
1✔
8

1✔
9
const cachedSources = new LRUCache({ max: 500 });
1✔
10

1✔
11
/**
1✔
12
 * An object defining the source of Entwine Point Tile data. It fetches and
1✔
13
 * parses the main configuration file of Entwine Point Tile format,
1✔
14
 * [`ept.json`](https://entwine.io/entwine-point-tile.html#ept-json).
1✔
15
 *
1✔
16
 * @extends Source
1✔
17
 *
1✔
18
 * @property {boolean} isEntwinePointTileSource - Used to checkout whether this
1✔
19
 * source is a EntwinePointTileSource. Default is true. You should not change
1✔
20
 * this, as it is used internally for optimisation.
1✔
21
 * @property {string} url - The URL of the directory containing the whole
1✔
22
 * Entwine Point Tile structure.
1✔
23
 * @property {Object[]|PointCloudSource[]} sources - Array of all the source described in the VPC.
1✔
24
 * initialized with mockSource that will be replace by COPC or EPT Source as soon as any data need
1✔
25
 * to be loaded.
1✔
26
 */
1✔
27
class VpcSource extends Source {
1✔
28
    /**
1✔
29
     * @param {Object} config - The configuration, see {@link Source} for
1✔
30
     * available values.
1✔
31
     * @param {number} [config.colorDepth] - Color depth (in bits).
1✔
32
     * Either 8 or 16 bits. By defaults it will be set to 8 bits for LAS 1.2 and
1✔
33
     * 16 bits for later versions (as mandatory by the specification).
1✔
34
     */
1✔
35
    constructor(config) {
1✔
36
        super(config);
2✔
37

2✔
38
        this.isVpcSource = true;
2✔
39
        this.sources = [];
2✔
40

2✔
41
        this.parser = LASParser.parseChunk;
2✔
42
        this.fetcher = Fetcher.arrayBuffer;
2✔
43

2✔
44
        this.colorDepth = config.colorDepth;
2✔
45

2✔
46
        this.spacing = Infinity;
2✔
47

2✔
48
        this.whenReady = Fetcher.json(this.url, this.networkOptions)
2✔
49
            .then((metadata) => {
2✔
50
                this.metadata = metadata;
2✔
51

2✔
52
                // Set the Crs of the VPC Layer.
2✔
53
                const projsWkt2 = metadata.features.map(f => f.properties['proj:wkt2']);
2✔
54
                const crs = [...new Set(projsWkt2)];
2✔
55
                if (crs.length !== 1) {
2!
NEW
56
                    console.warn('Only 1 crs is supported for 1 vpc.');
×
NEW
57
                }
×
58
                this.crs = CRS.defsFromWkt(projsWkt2[0]);
2✔
59

2✔
60
                // Set boundsConformings (the bbox) of the VPC Layer
2✔
61
                const boundsConformings = metadata.features
2✔
62
                    .filter(f => f.properties['proj:wkt2'] === projsWkt2[0])
2✔
63
                    .map(f => f.properties['proj:bbox']);
2✔
64

2✔
65
                this.boundsConforming = [
2✔
66
                    Math.min(...boundsConformings.map(b => b[0])),
2✔
67
                    Math.min(...boundsConformings.map(b => b[1])),
2✔
68
                    Math.min(...boundsConformings.map(b => b[2])),
2✔
69
                    Math.max(...boundsConformings.map(b => b[3])),
2✔
70
                    Math.max(...boundsConformings.map(b => b[4])),
2✔
71
                    Math.max(...boundsConformings.map(b => b[5])),
2✔
72
                ];
2✔
73

2✔
74
                // Set the zmin and zmax from the source
2✔
75
                this.zmin = this.boundsConforming[2];
2✔
76
                this.zmax = this.boundsConforming[5];
2✔
77

2✔
78
                /* Set  several object (MockSource) to mock the source that will need to be instantiated.
2✔
79
                 We don't want all child source to be instantiated at once as it will send the fetch request
2✔
80
                 (current architectural choice) thus we want to delay the instanciation of the child source
2✔
81
                 when the data need to be load on a particular node.
2✔
82
                 Creation of 1 mockSource for each item in the stack (that will be replace by a real source
2✔
83
                 when needed, when we will call the load on a node depending of that source).
2✔
84
                */
2✔
85
                this._promises = [];
2✔
86
                this.urls = metadata.features.map(f => f.assets.data.href);
2✔
87
                this.urls.forEach((url, i) => {
2✔
88
                    const whenReady = new Promise((re, rj) => {
2,504✔
89
                        // waiting for this.instantiate(source);
2,504✔
90
                        this._promises.push({ resolve: re, reject: rj });
2,504✔
91
                    }).then((res) => {
2,504✔
92
                        // replace the mock source by the real source (instantiated)
2✔
93
                        this.sources[i] = res;
2✔
94
                        return res;
2✔
95
                    }).catch((err) => {
2,504✔
96
                        console.warn(err);
×
97
                        this.handlingError(err);
×
98
                    });
2,504✔
99

2,504✔
100
                    const mockSource = {
2,504✔
101
                        url,
2,504✔
102
                        boundsConforming: boundsConformings[i],
2,504✔
103
                        whenReady,
2,504✔
104
                        crs: CRS.defsFromWkt(projsWkt2[i]),
2,504✔
105
                        sId: i,
2,504✔
106
                    };
2,504✔
107
                    this.sources.push(mockSource);
2,504✔
108
                });
2✔
109

2✔
110
                return this.sources;
2✔
111
            });
2✔
112
    }
2✔
113

1✔
114
    /**
1✔
115
     * We created several objects mocking a source at the intantiation of the vpc layer.
1✔
116
     * The following method will be called when we need to instantiate the real source (COPC or EPT).
1✔
117
     * The mock source contain the url to instantiate the source as well as a promise that
1✔
118
     * will be resolve when the source.whenReady promise will resolve.
1✔
119
     * To avoid instanciating several time the same source, we use a cache to store the
1✔
120
     * whenReady promise of the source (cachedSources).
1✔
121
     *
1✔
122
     * @param {object} source - The mock source used to instantiate the real source.
1✔
123
     * @param {object} source.url - The url of the source to instanciate.
1✔
124
     */
1✔
125
    instantiate(source) {
1✔
126
        let newSource;
3✔
127
        const url = source.url;
3✔
128
        let cachedSrc = cachedSources.get(url);
3✔
129
        if (!cachedSrc) {
3✔
130
            if (url.includes('.copc')) {
2✔
131
                newSource = new CopcSource({ url });
1✔
132
            } else if (url.includes('.json')) {
1✔
133
                newSource = new EntwinePointTileSource({ url });
1✔
134
            } else {
1!
135
                const msg = '[VPCLayer]: stack point cloud format not supporter';
×
136
                console.warn(msg);
×
137
                this.handlingError(msg);
×
138
            }
×
139
            cachedSrc = newSource;
2✔
140
            cachedSources.set(url, cachedSrc);
2✔
141
        }
2✔
142
        this._promises[source.sId].resolve(cachedSrc.whenReady);
3✔
143
    }
3✔
144
}
1✔
145

1✔
146
export default VpcSource;
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc