add a Point to a renderd Vectorlayer openlayers-7 - javascript

how to add a feature to a exist layer on map , openlayers-7
this is my code : I defined a vector Layer named myJson and i want to add a Point to this layer in code
how can i achieve that ?
const myJson = new VectorLayer({
source: new VectorSource({
format: new GeoJSON(),
url: 'geo.json'
})
})
map.addLayer(myJson);
const P1= new Feature (new Point(coordinate));
myJson.addFeature(P1);

Related

convert dae to gltf, horizontal vector invalidation

I converted .dae to .gltf through this tool, and display through three.js, and found that the horizontal vector of the model seems to be invalid.
Example file
Convert tool interface:
The situation when I use .dae file to display:
let loaderDae = new ColladaLoader();
loaderDae.load(`assets/untitled.dae`, (dae: any) => {
this.buildingModel = dae.scene;
this.buildingModel.position.multiplyScalar(0);
this.scene.add(this.buildingModel);
});
The situation when I use .gltf file to display:
let loaderGLTF = new GLTFLoader();
loaderGLTF.load(`assets/untitled.glft`, (glft: any) => {
this.buildingModel = glft.scene;
this.buildingModel.position.multiplyScalar(0);
this.scene.add(this.buildingModel);
});
After zooming in(or out):
The gloss of the texture is also not the same. I don't know if it's a file conversion problem or a lighting problem. I am using ambientLight:
let ambColor = new THREE.Color('rgb(118, 240, 147');
this.ambientLight = new THREE.AmbientLight(ambColor);
this.ambientLight.name = 'testname';
this.scene.add(this.ambientLight)

How to get the geometry of a model imported from STL in three.js

I'm using STLLoader to load STL file into three.js and I want to get the vertices (and the geometry) of the model after I call the loader for further usage. How can I do that? My current code is as below but I cannot get the geometry after calling the loader.
var loader = new THREE.STLLoader();
var myModel = new THREE.Object3D();
loader.load("myModel.stl", function (geometry) {
var mat = new THREE.MeshLambertMaterial({color: 0x7777ff});
var geo = new THREE.Geometry().fromBufferGeometry(geometry);
myModel = new THREE.Mesh(geo, mat);
scene.add(myModel);
});
console.log(myModel.geometry.vertices)
As of three.js R125, the recommended way to do this is with the loadAsync method, which is now native to three.js:
https://threejs.org/docs/#api/en/loaders/Loader.loadAsync
That method returns a promise. You couldthen use a 'then' to get the geometry of the STL and create the mesh. You could also use a traditional callback, or an async/await structure, but I think the example below using the native three.js method is the simplest way. The example shows how you can get geometry to a global variable once the promise is resolved and the STL file is loaded:
// Global variables for bounding boxes
let bbox;
const loader = new STLLoader();
const promise = loader.loadAsync('model1.stl');
promise.then(function ( geometry ) {
const material = new THREE.MeshPhongMaterial();
const mesh = new THREE.Mesh( geometry, material );
mesh.geometry.computeBoundingBox();
bbox = mesh.geometry.boundingBox;
scene.add( mesh );
buildScene();
console.log('STL file loaded!');
}).catch(failureCallback);
function failureCallback(){
console.log('Could not load STL file!');
}
function buildScene() {
console.log('STL file is loaded, so now build the scene');
// !VA bounding box of the STL mesh accessible now
console.log(bbox);
// Build the rest of your scene...
}

React + three.js: Error thrown by TextureLoader when trying to loading image

I've been trying to add three.js to a React project and have mostly been successful. I can't, however, figure out why my texture images aren't loading. I'm running my own local server, have added a callback method to run when loading is complete, and have tried loading my images from multiple locations, but so far nothing has worked.
My images are stored in public/animation/js/img/texture1.png, and my animation file in public/animation/js/animation.js, and hereÅ› the code I'm working with right now:
const Pilot = function () {
let faceMaterial;
const geometry = new THREE.CircleGeometry(10, 128);
const manager = new THREE.LoadingManager();
manager.onStart = function (url, itemsLoaded, itemsTotal) {
console.log('Started loading file: ',
url,
'.\nLoaded ',
itemsLoaded,
' of ',
itemsTotal,
' files.');
};
manager.onLoad = () => {
console.log('Loading complete!');
};
manager.onProgress = function (url, itemsLoaded, itemsTotal) {
console.log('Loading file: ',
url,
'.\nLoaded ',
itemsLoaded,
' of ',
itemsTotal,
' files.');
};
manager.onError = function (url) {
console.error( 'There was an error loading ', url);
};
const textureLoader = new THREE.TextureLoader(manager);
textureLoader.setCrossOrigin('anonymous');
textureLoader.load('/img/texture1.png',
texture => {
faceMaterial = new THREE.MeshFaceMaterial([
new THREE.MeshBasicMaterial({map: texture}),
new THREE.MeshBasicMaterial({map: texture}),
new THREE.MeshBasicMaterial({map: texture}),
new THREE.MeshBasicMaterial({map: texture}),
new THREE.MeshBasicMaterial({map: texture}),
new THREE.MeshBasicMaterial({map: texture})
]);
},
undefined,
err => {
console.error('An error occured:', err);
}
);
this.mesh = new THREE.Mesh(geometry, faceMaterial);
this.mesh.name = 'profile';
};
It may be due to your image path being absolute, ie: '/img/texture1.png'
From what directory is your web server being run? If your web server is running from say, the /public directory, then you will likely need to update your image path that is passed to your textureLoader's load method as follows:
textureLoader.load('/animation/js/img/texture1.png',
You will also need to ensure that your mesh is using the same material instance that your texture data is loaded into. You can make the following adjustment to your code to ensure this:
// Declare material instance outside of texture load handler
const faceMaterial = new THREE.MeshFaceMaterial([
new THREE.MeshBasicMaterial(),
new THREE.MeshBasicMaterial(),
new THREE.MeshBasicMaterial(),
new THREE.MeshBasicMaterial(),
new THREE.MeshBasicMaterial(),
new THREE.MeshBasicMaterial()
])
const textureLoader = new THREE.TextureLoader(manager);
textureLoader.setCrossOrigin('anonymous');
textureLoader.load('/animation/js/img/texture1.png',
texture => {
// When texture loads, apply the texture to the map of each sub
// material of faceMaterial instance
faceMaterial.materials[0].map = texture;
faceMaterial.materials[1].map = texture;
faceMaterial.materials[2].map = texture;
faceMaterial.materials[3].map = texture;
faceMaterial.materials[4].map = texture;
faceMaterial.materials[5].map = texture;
},
undefined,
err => {
console.error('An error occured:', err);
}
);
// Apply the faceMaterial instance declared above, to your mesh
this.mesh = new THREE.Mesh(geometry, faceMaterial);
this.mesh.name = 'profile';

Is there a way to wait for THREE.TextureLoader.load() to finish?

I'm working with release R73.
My current task is to fill an array with materials. The content of this array is supposed to be used later. That usage depends on all materials to me completely loaded.
By now I loop through an array of JSON information and call this code for every element:
TLoader.load(
BASE_ODB_URL + jsonMat.pic,
function (texture) {
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(jsonMat.scaleu, jsonMat.scalev);
Mat = new THREE.MeshLambertMaterial({
map : texture,
side : THREE.DoubleSide,
name : jsonMat.mname
});
THREEMatList.push(Mat);
},
function (xhr) {
}, //onProgress
function (xhr) {
Mat = new THREE.MeshLambertMaterial({
color : 0xff0000,
side : THREE.DoubleSide,
name : jsonMat.mname
});
THREEMatList.push(Mat);
}
)
TLoader is initialized earlier: var TLoader = new THREE.TextureLoader();
If a material isn't there, when it is needed, I get a fallback material. This was only intended as an error option.
Is there a way to wait until .load() finishes?
Threejs already provides a callback for all elements loaded - via the use of a LoadingManager. By default, TextureLoader uses the DefaultLoadingManager:
import {TextureLoader, DefaultLoadingManager} from './three.module.js';
const getTextures = ()=> new Promise((resolve, reject)=>{
const loader = new TextureLoader();
DefaultLoadingManager.onLoad = ()=>resolve(textures);
const textures = [
"image1.jpg",
"image2.jpg",
"image3.jpg"
].map(filename=>loader.load(filename));
});
getTextures().then(result=>console.log("We received,", result,"!"));
That's going to wait for all assets to load, though. If you want to be listening for a specific subset of assets loaded, you can do that by constructing a custom LoadingManager and passing it into your TextureLoader to manage different asset bundles separately:
import {TextureLoader, LoadingManager} from './three.module.js';
const getTextures = ()=> new Promise((resolve, reject)=>{
const manager = new LoadingManager(()=>resolve(textures));
const loader = new TextureLoader(manager);
const textures = [
"image1.jpg",
"image2.jpg",
"image3.jpg"
].map(filename=>loader.load(filename));
});
getTextures().then(result=>console.log("We received,", result,"!"));
You can also use this simple helper if you need to load multiple textures before rendering your scene :
/**
*
* #param {Array} texturesSources - List of Strings that represent texture sources
* #returns {Array} Array containing a Promise for each source
*/
function getTextures (texturesSources) {
const loader = new THREE.TextureLoader()
return texturesSources.map(textureSource => {
return new Promise((resolve, reject) => {
loader.load(
textureSource,
texture => resolve(texture),
undefined, // onProgress callback not supported from r84
err => reject(err)
)
})
})
}
Then wrap your code using Promise.all, allowing to fetch the sources in parallel, and fail properly by catching the error.
Example :
const texturesBasePath = '../assets/textures/'
const texturesSRC = [
'image1.jpg',
'image2.jpg',
'image3.jpg',
].map(texture => texturesBasePath + texture)
Promise.all(getTextures(texturesSRC))
.then(textures => {
// create your materials, meshs...
// render the scene
})
.catch(err => console.error(err))
A way to solve this is through Promise's as they are really the way forward and I personally think it's a shame TextureLoader doesn't return a Promise to start with (it would make this a little bit easier). However, do keep in mind that IE11 will need a polyfill as it lacks native support for promises.
Something like this should do it, where textureArray represents your JSON data in an iterable Array:
var allPromises = [];
textureArray.forEach( function( jsonMat ) {
allPromises.push( new Promise( function( resolve, reject ) {
TLoader.load(
BASE_ODB_URL + jsonMat.pic,
function( texture ) {
// Success callback of TextureLoader
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( jsonMat.scaleu, jsonMat.scalev );
var material = new THREE.MeshLambertMaterial({
map: texture,
side: THREE.DoubleSide,
name: jsonMat.mname
});
THREEMatList.push( material );
// We're done, so tell the promise it is complete
resolve( material );
},
function( xhr ) {
// Progress callback of TextureLoader
// ...
},
function( xhr ) {
// Failure callback of TextureLoader
// Reject the promise with the failure
reject( new Error( 'Could not load ' + jsonMat.pic ) );
}
);
}));
});
Promise.all( allPromises )
.then( function( arrayOfMaterials ) {
// All textures are now loaded, and this array
// contains all the materials that you created
}, function( error ) {
console.error( "Could not load all textures:", error );
});
So what's happening here is that one overarching Promise is used to keep track of the status of the other Promises. Each texture being loaded is wrapped in a Promise, which are added to allPromises. Finally that entire set of promises is tested for success or failure, and at that point you know about the overall success or failure.
One important thing to keep in mind here is that the Promise.all will only succeed if all the textures were loaded, and it will fail as soon as any one fails. If you need finer control than that you'll need a Promise polyfill with more features than the Promise/A+ spec offers, such as RSVP.js. Or instead of reject()ing the promise you could resolve() it and handle the result gracefully.

Loading an object with Three.js fails (missing formal parameter)

I want to use Three.js (OGL + JavaScript) to load an object from file. I have an working example without loading it (some basic elements rendered). But when I try to load object using JSONLoader.load(...), Firefox console shows error:
SyntaxError: missing formal parameter
The reference: http://threejs.org/docs/#Reference/Loaders/JSONLoader
The source code for my added fragment (loading object), which cause an error:
//loading an object
var loader = new THREE.JSONLoader(); //works so far
loader.load("./Project2/proj/grzyb.js",
function(geometry,
new THREE.MeshLambertMaterial( { map: texture, ambient: 0xbbbbbb } )
//for the line above, in Firefox console i get
//"SyntaxError: missing formal parameter"
){
var materials = new THREE.MeshFaceMaterial(
new THREE.MeshLambertMaterial( { map: texture, ambient: 0xbbbbbb } )
);
grzyb = new THREE.Mesh(geometry, materials);
grzyb.scale.set(5, 5, 5);
grzyb.position.set(2,2,2);
grzyb.receiveShadow = true;
grzyb.castShadow = true;
scene.add(grzyb);
}
);
You are trying to insert MeshLambertMaterial creation into a function header definition. Function header can only contain parameter names - not any actual code to create them.
Also it is not clear whether you want to use material coming from model file or your own material with texture that you loaded elsewhere (in the example there is no code that would set texture variable). Assuming you want to use materials from model, your code should look like this:
var loader = new THREE.JSONLoader(); //works so far
loader.load("./Project2/proj/grzyb.js",
function(geometry, materials) {
var material = new THREE.MeshFaceMaterial( materials );
grzyb = new THREE.Mesh(geometry, material);
grzyb.scale.set(5, 5, 5);
grzyb.position.set(2,2,2);
grzyb.receiveShadow = true;
grzyb.castShadow = true;
scene.add(grzyb);
}
);
if you want to use different material, then set material variable to anything you want. exmaple:
var texture = THREE.ImageUtils.LoadTexture( "../path/image.jpg" );
var material = new THREE.MeshBasicMaterial( { map:texture } );
var grzyb = new THREE.Mesh(geometry, material);

Categories