Google Place Autocomplete - geometry bounds properties - google-maps

I cannot find this answer in the Google docs so I am posting my question here.
As per the Google Places Autocomplete response docs, bounds is one of the returned fields.
However, when console logging bounds in the browser, the object has strangely named keys such as Ba, Ab, Ra and so on..
Furthermore, I have noticed that these keys change overtime.
For example, the following code might fail within a few days. In the initial search for say, New York, bounds.Ab.g may contain a number value.
however, after a few days bounds.Ab.g might become bounds.Bb.g and the original value will be undefined.
import PlacesAutocomplete, { geocodeByAddress } from 'react-places-autocomplete'
const GooglePlacesSearchBar = () => {
const handleSelect = async userInput => {
const result = await geocodeByAddress(userInput)
const { place_id, geometry, formatted_address } = result[0]
const { bounds } = geometry
const swBounds = [bounds.Ab.g, bounds.Ra.g]
const neBounds = [bounds.Ab.h, bounds.Ra.h]
...
}
This is an example of the bounds object printed in console.
bounds: _.Wf
Bb: Vf
g: 49.19817700000001
h: 49.3172939
[[Prototype]]: Object
Ra: Qf
g: -123.22474
h: -123.023068
Could anyone point to a doc or explain what these keys stand for and why they keep changing?

thanks to #geocodezip for the answers in the comments section.
here is the solution
const result = await geocodeByAddress(userInput)
const { geometry } = result[0]
const { bounds } = geometry
const NELat = bounds.getNorthEast().lat()
const NELng = bounds.getNorthEast().lng()
const SWLat = bounds.getSouthWest().lat()
const SWLng = bounds.getSouthWest().lng()
Strange decision by Google indeed.

Related

x, y, z coordinates of an object for a nwc file in forge viewer

I am trying to find x,y,z coordinates of an object inside nwc model, and I am using below code.
Despite that this code was working for rvt files, it is not working for nwc model.
Is there a way to get x,y,z coordinates from a nwc model?
getFragmentWorldMatrixByNodeId(nodeId) {
let result = {
fragId: [],
matrix: [],
};
let viewer = this.viewer;
this.tree.enumNodeFragments(nodeId, function (frag) {
let fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
let matrix = new THREE.Matrix4();
fragProxy.getWorldMatrix(matrix);
result.fragId.push(frag);
result.matrix.push(matrix);
});
return result;
}
You mentioned you are looking for the "x,y,z coordinates of an object". What exactly do you mean by that? I'm going to assume that you want the coordinates of the center point of the object's bounding box, as that is what people ask for usually. In your code snippet, however, you're retrieving the entire transformation matrix, not a position.
If the center point of a bounding box works for you, you could obtain it like so:
function getObjectBoundingBox(model, dbid) {
const tree = model.getInstanceTree();
const frags = model.getFragmentList();
let totalBounds = new THREE.Box3();
tree.enumNodeFragments(dbid, function (fragid) {
let fragBounds = new THREE.Box3();
frags.getWorldBounds(fragid, fragBounds);
totalBounds.union(fragBounds);
}, true);
return totalBounds;
}
getObjectBoundingBox(viewer.model, 123).center();

Can I estimate the distance traveled per country between two or more waypoints?

I would like to be able to estimate the distance traveled per country through the Google Maps APIs.
Example: the origin of my path is in Amsterdam (Netherlands) then I have one waypoint in Berlin (Germany) and the final destination is Warsaw (Poland).
I would like to estimate the amount of KM traveled per country.
I have searched through the Google Maps API but I could not find a way to do this.
The software program output should be something like:
Netherlands: 53km
Germany 504km
Poland 304km
After messing around with it myself for a little bit I came to the following solution:
import turf from '#turf/turf'
import polyline from '#mapbox/polyline'
import shapefile from 'shapefile'
// The google routes api result
import data from './coords.js';
// The compete route polyline
const polydata = polyline.toGeoJSON(data.routes[0].overview_polyline.points);
async function fetchWorldData() {
let worldData = [];
try {
let overBorder = false;
// Load country borders shapeFile
const source = await shapefile.open("TM_WORLD_BORDERS-0.3.shp");
// Loop over all countries
while (true) {
// Read the source for a specific country
const result = await source.read();
if (result.done) break;
// Check if the trip will cross any borders, if they do, set overBorder to true
if (turf.lineIntersect(polydata, result.value.geometry).features.length !== 0) {
overBorder = true;
// Append intersected borders
worldData.push(result.value);
}
}
// Return a list with all the country data
return worldData;
} catch (e) {
console.log(e);
}
}
async function makePrediction() {
console.time("execution time");
// Object to returned
let countries = []
// When leaving a border you will intersect with it(1) You will then intersect with the next border (2) causing another intersect.
// This bool ignores the entering intersect.
let ignoreNextBorder = false;
try {
// Fetch the world data
let worldData = await fetchWorldData();
worldData.map(async border => {
// Store distance and duration per country
let distance = 0;
let duration = 0;
data.routes[0].legs[0].steps.map(async (step) => {
// Get the step starting point
let pt = turf.point([step.start_location.lng, step.start_location.lat]);
const pointInCountry = turf.booleanPointInPolygon(pt, border.geometry);
// Check if the step starting point is in the current country
if (pointInCountry) {
// Add the step distance to the total
distance += step.distance.value;
duration += step.duration.value;
}
});
countries[border.properties.NAME] = {
duration: duration,
distance: distance
}
});
console.timeEnd("execution time");
return countries;
} catch (e) {
console.log(e)
}
}
makePrediction().then(console.log);
You can pass a different shape file if you would want to. It displays the results like so:
Example result
The downside is, countries are not ordered. But this suits my needs plenty fine.

Forge Viewer: Properties Window

The Properties window does not populate any properties even though the 2D view has properties info for the selected room
Here is the function that loads the model. what am I missing?
function loadModel() {
var initialViewable = viewables[indexViewable];
var svfUrl = lmvDoc.getViewablePath(initialViewable);
var modelOptions = {
sharedPropertyDbPath: lmvDoc.getFullPath(lmvDoc.getRoot().findPropertyDbPath())
};
viewer.loadModel(svfUrl, modelOptions, onLoadModelSuccess, onLoadModelError);
}
One line missing in your code, please try the following instead:
var sharedDbPath = initialViewable.findPropertyDbPath();
sharedDbPath = lmvDoc.getFullPath( sharedDbPath );
var modelOptions = {
sharedPropertyDbPath: sharedDbPath
};
However, you should not need to specify the sharedPropertyDbPath manually now. You can take advantage of the Viewer3D#loadDocumentNode to load the model directly. It will automatically determine the path for you. (started from v7 viewer)
const initialViewable = viewables[0];
viewer.loadDocumentNode( lmvDoc, initialViewable, loadOptions )
.then( onLoadModelSuccess )
.catch( onLoadModelError );

How to get Course Id from Classroom URL?

Goal: I want to quickly connect to a Google Classroom using a Google Classroom URL via Google Apps Script.
Problem: Need help filtering Map of courses by URL.
Background:
Classroom API has little documentation for GAS. Furthermore, COURSE_ID is used for nearly all connections. I can map the active courses, but I cannot filter the map. The code below originated from Yagisanatode with modifications in an attempt to map active courses by URL. Changing the Logger to (courseData) reveals the creation of the double array.
function findCourseByUrl() {
const courseList = Classroom.Courses.list({"courseStates":["ACTIVE"]}).courses;
const courseData = courseList.map(course => {
let ownerName = Classroom
.Courses
.Teachers
.get(course.id, course.ownerId)
.profile
.name
.fullName;
return `[${course.name}, ${course.id}, ${ownerName}, ${course.alternateLink}]`;
});
const link = 'https://classroom.google.com/c/YOUCLASSROOMURL'; //change this
const data = courseData.filter(function(item){return item[4] === link;});
Logger.log(data);
};
Any help would be appreciated. I'm stuck.
Answer:
link is not defined since it is outside of the courseData.filter(function(item){}). The solution is to call a global variable or create a conditional with the declared variable within the function(item).
The toString is looking for an exact match for the URL text, which is naturally unique.
Video reference: https://youtu.be/PT_TDhMhWsE
Code:
function findCourseByUrl() {
const courseList = Classroom.Courses.list({"courseStates":["ACTIVE"]}).courses;
const courseData = courseList.map(course => {
let ownerName = Classroom
.Courses
.Teachers
.get(course.id, course.ownerId)
.profile
.name
.fullName;
return `[${course.name}, ${course.id}, ${ownerName}, ${course.alternateLink}]`;
});
const filterCourse = function(item){
let link = 'https://classroom.google.com/c/YOURCOURSEURL' ///Change this or replace with a global variable
if(item.toString().indexOf(link) === -1){
return false;
} else {
return true
}
};
let theCourse = courseData.filter(filterCourse); //this could be a return if called by function in Test.gs
Logger.log(theCourse); //remove if using a function with console.log in Test.gs
};

How to change the color of sphere objects dynamically (used SceneBuilder in Autodesk forge)

I am working on the example from Custom models in Forge Viewer blog by Petr Broz. I am facing issue in updating the color of sphere objects dynamically. I am getting the value of sphere's color from a json file like this "color": "#FF0000". I have created 3 spheres and I am getting the color of first sphere for the rest also. Why the color is not updating for the other spheres? If the problem is on using same material then I tried giving the sphereMaterial in array also as shown below. Is that wrong or how can i update the color?
var spherecolor='';
var sphereMaterial = [];
const button = document.getElementById('button-geometry');
button.addEventListener('click', async function () {
const sceneBuilder = await viewer.loadExtension('Autodesk.Viewing.SceneBuilder');
const modelBuilder = await sceneBuilder.addNewModel({ conserveMemory: true, modelNameOverride: 'My Custom Model' });
for (var i = 0; i < numOfSphere;i++) {
addGeometry(modelBuilder, jsonGeomConfig.geom[i].dbId, i);
}
});
function addGeometry(modelBuilder, dbId, i) {
const sphereGeometry = new THREE.BufferGeometry().fromGeometry(new THREE.SphereGeometry(0.05, 8, 10));
//Getting spherecolor from json file
spherecolor = jsonGeomConfig.geom[i].color;
sphereMaterial[i] = new THREE.MeshPhongMaterial({ color: spherecolor });
const sphereTransform = new THREE.Matrix4().compose(
new THREE.Vector3(jsonGeomConfig.geom[i].Position.posX, jsonGeomConfig.geom[i].Position.posY, jsonGeomConfig.geom[i].Position.posZ),
new THREE.Quaternion(0, 0, 0, 1),
new THREE.Vector3(2,2,2)
);
modelBuilder.addMaterial('MyCustomMaterial', sphereMaterial[i]);
const sphereGeomId = modelBuilder.addGeometry(sphereGeometry);
const sphereFragId = modelBuilder.addFragment(sphereGeomId, 'MyCustomMaterial', sphereTransform);
modelBuilder.changeFragmentsDbId(sphereFragId, dbId);
}
Be sure to give the materials with different colors different names ... otherwise it'd get overridden - see this live environment:
modelBuilder.addMaterial('MyCustomMaterial'+i, sphereMaterial[i]);
const sphereGeomId = modelBuilder.addGeometry(sphereGeometry);
const sphereFragId = modelBuilder.addFragment(sphereGeomId, 'MyCustomMaterial'+i, sphereTransform);