UNPKG

rdview-service

Version:

Rdview service for loading road photos

176 lines (143 loc) 6.4 kB
import { Passage, Segment } from './interfaces'; import { RoadSegmentService } from './road-segment-service'; import { dateParser, sortPassagesByDateDesc, sortPhotosByKmAsc } from './utils'; export class PassageService { public loadingPreviousSegment: Promise<void>; public isPreviousSegmentEmpty: boolean; public loadingNextSegment: Promise<void>; public isNextSegmentEmpty: boolean; private dateDiffInMsForSamePassage = 1000 * 30; private rangeDiffInKmForSamePassage = .2; private passageInitKmRange = 1; private roadSegmentService: RoadSegmentService; private segment: Segment; constructor(settings: { apiUrl?: string, authorization: string }) { this.roadSegmentService = new RoadSegmentService({ apiUrl: settings.apiUrl, authorization: settings.authorization }); } public initByRoad(idRd: number, km: number): Promise<Segment> { return this.roadSegmentService .getSegmentByRoad(idRd, Math.max(0, km - this.passageInitKmRange), km + this.passageInitKmRange) .then(segment => this.initFirstSegment(segment)); } public initByCoordinates(lat: number, lon: number): Promise<Segment> { return this.roadSegmentService.getSegmentByCoordinates(lat, lon) .then(segment => this.initFirstSegment(segment)); } public getSegment(): Segment { return JSON.parse(JSON.stringify(this.segment), dateParser); } public loadNextSegment() { if (this.loadingNextSegment) { return; } this.loadingNextSegment = this.roadSegmentService .getSegmentByRoad(this.segment.road.id, this.segment.rdKmTo, this.segment.rdKmTo + this.passageInitKmRange) .then(segment => { this.loadingNextSegment = null; if (this.isSegmentWithPassages(segment)) { this.includeSegment(segment); } else { this.isNextSegmentEmpty = true; } }); } public loadPreviousSegment() { if (this.loadingPreviousSegment) { return; } this.loadingPreviousSegment = this.roadSegmentService .getSegmentByRoad(this.segment.road.id, Math.max(0, this.segment.rdKmFrom - this.passageInitKmRange), this.segment.rdKmFrom) .then(segment => { this.loadingPreviousSegment = null; if (this.isSegmentWithPassages(segment)) { this.includeSegment(segment); } else { this.isPreviousSegmentEmpty = true; } }); } private initFirstSegment(segment: Segment): Segment { if (!segment) { return; } this.segment = segment; this.segment.passages = sortPassagesByDateDesc(this.segment.passages); this.segment.passages = this.getPassagesWithUpdatedKmBorders(this.segment.passages); return segment; } private isSegmentWithPassages(segment: Segment): boolean { return segment != null && Array.isArray(segment.passages) && segment.passages.length > 0; } private includeSegment(segment: Segment) { if (!segment) { return; } this.segment.rdKmFrom = Math.min(this.segment.rdKmFrom, segment.rdKmFrom); this.segment.rdKmTo = Math.max(this.segment.rdKmTo, segment.rdKmTo); segment.passages.forEach(newPassage => { const existingNeighbourPassage = this.segment.passages .find(existingPassage => { if (existingPassage.direction !== newPassage.direction) { return false; } if (!this.isPassagesNeighboursByKm(newPassage, existingPassage, this.rangeDiffInKmForSamePassage)) { return false; } return this.isPassagesNeighboursByDate(newPassage, existingPassage, this.dateDiffInMsForSamePassage); }); if (existingNeighbourPassage) { existingNeighbourPassage.views = sortPhotosByKmAsc( existingNeighbourPassage.views.concat(newPassage.views)); } else { this.segment.passages.push(newPassage); } }); this.segment.passages = sortPassagesByDateDesc(this.segment.passages); this.segment.passages = this.getPassagesWithUpdatedKmBorders(this.segment.passages); } private isPassagesNeighboursByKm(passage1: Passage, passage2: Passage, maxKmDiff: number): boolean { const getPassagePhotoKmArray = (passage: Passage) => passage.views.map(photo => photo.rdKm); const passage1PhotoKmArray = getPassagePhotoKmArray(passage1); const passage2PhotoKmArray = getPassagePhotoKmArray(passage2); return this.inNumberArraysIntersects(passage1PhotoKmArray, passage2PhotoKmArray, maxKmDiff); } private isPassagesNeighboursByDate(passage1: Passage, passage2: Passage, maxMsDiff: number): boolean { const getPassagePhotoDateInMsArray = (passage: Passage) => passage.views.map(photo => photo.date.getTime()); const passage1PhotoDateInMsArray = getPassagePhotoDateInMsArray(passage1); const passage2PhotoDateInMsArray = getPassagePhotoDateInMsArray(passage2); return this.inNumberArraysIntersects(passage1PhotoDateInMsArray, passage2PhotoDateInMsArray, maxMsDiff); } private inNumberArraysIntersects(array1: number[], array2: number[], precision: number) { const minValueInArray1 = Math.min.apply(null, array1); const minValueInArray2 = Math.min.apply(null, array2); const maxValueInArray1 = Math.max.apply(null, array1); const maxValueInArray2 = Math.max.apply(null, array2); const isValueBetween = (value, borderLeft, borderRight, prec) => borderLeft - prec <= value && value <= borderRight + prec; return isValueBetween(minValueInArray1, minValueInArray2, maxValueInArray2, precision) || isValueBetween(maxValueInArray1, minValueInArray2, maxValueInArray2, precision) || isValueBetween(minValueInArray2, minValueInArray1, maxValueInArray1, precision) || isValueBetween(maxValueInArray2, minValueInArray1, maxValueInArray1, precision); } private getPassagesWithUpdatedKmBorders(passages: Passage[]): Passage[] { return passages.map(passage => { passage.rdKmFrom = Math.min.apply(null, passage.views.map(photo => photo.rdKm)); passage.rdKmTo = Math.max.apply(null, passage.views.map(photo => photo.rdKm)); return passage; }); } }