Skip to content

Commit

Permalink
Close #816 virtual-tour: add gps option for markers
Browse files Browse the repository at this point in the history
  • Loading branch information
mistic100 committed Jan 1, 2023
1 parent 6b5c4e1 commit d650c01
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 53 deletions.
4 changes: 3 additions & 1 deletion docs/plugins/virtual-tour.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ Definition of the links of this node. See bellow.

- type: `number[]`

GPS coordinates of this node as an array of two or three values (`[longitude, latitude, altitude]`).
GPS coordinates of this node as an array of two or three values (`[longitude, latitude, altitude?]`).

::: warning Projection system
Only the [ESPG:4326 projection](https://epsg.io/4326) is supported.
Expand Down Expand Up @@ -266,6 +266,8 @@ Thumbnail for the nodes list in the gallery.

Additional markers displayed on this node, requires the [Markers plugin](./markers.md).

Since 5.0.2 the markers can be positioned with the classic `position` option (yaw + pitch) or, if `positionMode=gps`, with the `gps` option (longitude + latitude + altitude).

#### `panoData`

Refer to the main [config page](../guide/config.md#panodata).
Expand Down
65 changes: 36 additions & 29 deletions examples/plugin-virtual-tour.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@
<script>
const baseUrl = 'https://photo-sphere-viewer-data.netlify.app/assets/';

const markerLighthouse = {
id: 'marker-1',
image: baseUrl + 'pictos/pin-red.png',
tooltip: 'Cape Florida Light, Key Biscayne',
size: { width: 32, height: 32 },
anchor: 'bottom center',
gps: [-80.155973, 25.666601, 29 + 3],
data: { compass: 'red' },
};

// links.position is used in manual mode
// links.gps or node.gps is used in GPS mode
const nodes = [
Expand All @@ -34,17 +44,10 @@
thumbnail: baseUrl + 'tour/key-biscayne-1-thumb.jpg',
name: 'One',
links: [{ nodeId: '2', position: { pitch: 0, yaw: '100deg' } }],
markers: [
{
id: 'marker-1',
image: baseUrl + 'pictos/pin-red.png',
tooltip: 'Cape Florida Light, Key Biscayne',
size: { width: 32, height: 32 },
anchor: 'bottom center',
position: { yaw: '105deg', pitch: '35deg' },
data: { compass: 'red' },
},
],
markers: [{
...markerLighthouse,
position: { yaw: '105deg', pitch: '35deg' }, // only use in manual mode
}],
gps: [-80.156479, 25.666725, 3],
panoData: { poseHeading: 327 },
},
Expand All @@ -57,6 +60,10 @@
{ nodeId: '3', position: { pitch: 0, yaw: '120deg' } },
{ nodeId: '1', position: { pitch: 0, yaw: '280deg' } },
],
markers: [{
...markerLighthouse,
position: { yaw: '100deg', pitch: '55deg' }, // only use in manual mode
}],
gps: [-80.156168, 25.666623, 3],
panoData: { poseHeading: 318 },
},
Expand Down Expand Up @@ -95,7 +102,7 @@
{ nodeId: '3', position: { pitch: 0, yaw: '70deg' } },
{ nodeId: '4', position: { pitch: 0, yaw: '150deg' } },
],
gps: [-80.156292, 25.666446, 2],
gps: [-80.156292, 25.666446, 3],
panoData: { poseHeading: 190 },
},
{
Expand Down Expand Up @@ -137,25 +144,25 @@
positionMode: 'gps',
renderMode: '3d',
startNodeId: nodes[1].id,
preload: true,
// transition : false,
// rotateSpeed : false,
arrowPosition: 'bottom',
preload: true,
// transition : false,
// rotateSpeed : false,
arrowPosition: 'bottom',

// client mode
// dataMode: 'client',
nodes: nodes,
// client mode
// dataMode: 'client',
nodes: nodes,

// server mode (mock)
dataMode: 'server',
getNode: (nodeId) => {
console.log('GET node ' + nodeId);
return Promise.resolve({
...nodesById[nodeId],
links: nodesById[nodeId].links.map((link) => ({
...link,
name: nodesById[link.nodeId].name,
gps: nodesById[link.nodeId].gps,
// server mode (mock)
dataMode: 'server',
getNode: (nodeId) => {
console.log('GET node ' + nodeId);
return Promise.resolve({
...nodesById[nodeId],
links: nodesById[nodeId].links.map((link) => ({
...link,
name: nodesById[link.nodeId].name,
gps: nodesById[link.nodeId].gps,
})),
});
},
Expand Down
26 changes: 9 additions & 17 deletions packages/virtual-tour-plugin/src/VirtualTourPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import type { events as markersEvents, MarkersPlugin } from '@photo-sphere-viewe
import {
AmbientLight,
BackSide,
Group,
MathUtils,
Group,
Mesh,
MeshBasicMaterial,
MeshLambertMaterial,
Expand All @@ -19,7 +18,7 @@ import { ClientSideDatasource } from './datasources/ClientSideDatasource';
import { ServerSideDatasource } from './datasources/ServerSideDatasource';
import { NodeChangedEvent, VirtualTourEvents } from './events';
import { VirtualTourLink, VirtualTourNode, VirtualTourPluginConfig } from './model';
import { bearing, distance, setMeshColor } from './utils';
import { gpsToSpherical, setMeshColor } from './utils';

const getConfig = utils.getConfigParser<VirtualTourPluginConfig>(
{
Expand Down Expand Up @@ -354,7 +353,12 @@ export class VirtualTourPlugin extends AbstractPlugin<VirtualTourEvents> {

if (node.markers) {
if (this.markers) {
this.markers.setMarkers(node.markers);
this.markers.setMarkers(node.markers.map(marker => {
if (marker.gps && this.isGps) {
marker.position = gpsToSpherical(node.gps, marker.gps);
}
return marker;
}));
} else {
utils.logWarn(`Node ${node.id} markers ignored because the plugin is not loaded.`);
}
Expand Down Expand Up @@ -456,19 +460,7 @@ export class VirtualTourPlugin extends AbstractPlugin<VirtualTourEvents> {
*/
private __getLinkPosition(node: VirtualTourNode, link: VirtualTourLink): Position {
if (this.isGps) {
const p1: [number, number] = [MathUtils.degToRad(node.gps[0]), MathUtils.degToRad(node.gps[1])];
const p2: [number, number] = [MathUtils.degToRad(link.gps[0]), MathUtils.degToRad(link.gps[1])];
const h1 = node.gps[2] !== undefined ? node.gps[2] : link.gps[2] || 0;
const h2 = link.gps[2] !== undefined ? link.gps[2] : node.gps[2] || 0;

let pitch = 0;
if (h1 !== h2) {
pitch = Math.atan((h2 - h1) / distance(p1, p2));
}

const yaw = bearing(p1, p2);

return { yaw, pitch };
return gpsToSpherical(node.gps, link.gps);
} else {
return this.viewer.dataHelper.cleanPosition(link.position);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ export abstract class AbstractDatasource {
node.gps = node['position'];
}
if (this.plugin.isGps && !(node.gps?.length >= 2)) {
throw new PSVError(`No position provided for node ${node.id}`);
throw new PSVError(`No GPS position provided for node ${node.id}`);
}
if (!this.plugin.isGps && node.markers?.some(marker => marker.gps && !marker.position)) {
throw new PSVError(`Cannot use GPS positioning for markers in manual mode`);
}
}

Expand Down
11 changes: 8 additions & 3 deletions packages/virtual-tour-plugin/src/model.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import type { ExtendedPosition, PanoData, PanoDataProvider, SphereCorrection } from '@photo-sphere-viewer/core';
import type { MarkerConfig } from '@photo-sphere-viewer/markers-plugin';

/**
* Definition of GPS coordinates (longitude, latitude, optional altitude)
*/
export type GpsPosition = [number, number, number?];

/**
* Style of the arrow in 3D mode
*/
Expand Down Expand Up @@ -102,17 +107,17 @@ export type VirtualTourNode = {
*/
links?: VirtualTourLink[];
/**
* GPS position (longitude, latitude, optional altitude)
* GPS position
*/
gps?: [number, number, number?];
gps?: GpsPosition;
/**
* thumbnail for the gallery
*/
thumbnail?: string;
/**
* additional markers to use on this node
*/
markers?: MarkerConfig[];
markers?: (MarkerConfig & { gps?: GpsPosition })[];
};

export type VirtualTourPluginConfig = {
Expand Down
24 changes: 22 additions & 2 deletions packages/virtual-tour-plugin/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { utils } from '@photo-sphere-viewer/core';
import type { Mesh, BufferGeometry, MeshBasicMaterial } from 'three';
import { Position, utils } from '@photo-sphere-viewer/core';
import { Mesh, BufferGeometry, MeshBasicMaterial, MathUtils } from 'three';
import { GpsPosition } from './model';

/**
* Changes the color of a mesh
Expand Down Expand Up @@ -27,3 +28,22 @@ export function bearing(p1: [number, number], p2: [number, number]): number {
const x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(long2 - long1);
return Math.atan2(y, x);
}

/**
* Retursn the difference between to WS84 GPS points as yaw+pitch on the viewer
*/
export function gpsToSpherical(gps1: GpsPosition, gps2: GpsPosition): Position {
const p1: [number, number] = [MathUtils.degToRad(gps1[0]), MathUtils.degToRad(gps1[1])];
const p2: [number, number] = [MathUtils.degToRad(gps2[0]), MathUtils.degToRad(gps2[1])];
const h1 = gps1[2] ?? 0;
const h2 = gps2[2] ?? 0;

let pitch = 0;
if (h1 !== h2) {
pitch = Math.atan((h2 - h1) / distance(p1, p2));
}

const yaw = bearing(p1, p2);

return { yaw, pitch };
}

0 comments on commit d650c01

Please sign in to comment.