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

iTowns / itowns / 19039246919

03 Nov 2025 03:08PM UTC coverage: 85.988% (-1.3%) from 87.328%
19039246919

Pull #2504

github

web-flow
Merge e70dfeccf into c6f59647a
Pull Request #2504: VPC PointCloudData

2938 of 3898 branches covered (75.37%)

Branch coverage included in aggregate %.

354 of 374 new or added lines in 13 files covered. (94.65%)

28268 of 32393 relevant lines covered (87.27%)

1194.19 hits per line

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

93.71
/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 { CopcSource, EntwinePointTileSource } from 'Main';
1✔
6
import { LRUCache } from 'lru-cache';
1✔
7

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

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

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

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

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

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

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

2✔
51
                // Set boundsConformings (the bbox) of the VPC Layer
2✔
52
                const boundsConformings = metadata.features.map(f => f.properties['proj:bbox']);
2✔
53
                this.boundsConforming = [
2✔
54
                    Math.min(...boundsConformings.map(b => b[0])),
2✔
55
                    Math.min(...boundsConformings.map(b => b[1])),
2✔
56
                    Math.min(...boundsConformings.map(b => b[2])),
2✔
57
                    Math.max(...boundsConformings.map(b => b[3])),
2✔
58
                    Math.max(...boundsConformings.map(b => b[4])),
2✔
59
                    Math.max(...boundsConformings.map(b => b[5])),
2✔
60
                ];
2✔
61

2✔
62
                // Set the zmin and zmax from the source
2✔
63
                this.minElevation = this.boundsConforming[2];
2✔
64
                this.maxElevation = this.boundsConforming[5];
2✔
65

2✔
66
                // Set the Crs of the VPC Layer (currently we only use the first)
2✔
67
                const projsWkt2 = [...new Set(metadata.features.map(f => f.properties['proj:wkt2']))];
2✔
68
                if (projsWkt2.length !== 1) {
2!
NEW
69
                    console.warn('Only 1 crs is currently supported for 1 vpc. The extra crs will not be considered');
×
NEW
70
                }
×
71
                this.crs = CRS.defsFromWkt(projsWkt2[0]);
2✔
72

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

2,504✔
95
                    const mockSource = {
2,504✔
96
                        url,
2,504✔
97
                        boundsConforming: boundsConformings[i],
2,504✔
98
                        whenReady,
2,504✔
99
                        sId: i,
2,504✔
100
                    };
2,504✔
101
                    this.sources.push(mockSource);
2,504✔
102
                });
2✔
103

2✔
104
                return this.sources;
2✔
105
            });
2✔
106
    }
2✔
107

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

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

© 2026 Coveralls, Inc