I am working on a AR based POC using the sample given by Apple.
Is there a way to place a 3D object above another 3D object in SceneKit?
For example I have placed a table above which I have to place something else like a flower vase. How to achieve this?
Because as far as I know, ARKit is detecting only floor surface and if I try to place the flower vase over the already kept table, it is placing it under the table overlapping the existing 3D object. Is this doable?
When you're making hitTest, you could check if there's any nodes:
let results = sceneView.hitTest(checkLocation, options: [.boundingBoxOnly: true])
guard let node = results.first?.node else { return }
Then you can place your new node as child node for touched node.
Related
I am using GMap.NET to display a lot of Marker (about more than 10.000 markers). R-Tree is a solution to optimize render markers at area which window is showing.
STRtree in NetTopologySuite is a library to support R-tree. But I'm not sure it suitable for this problem.
My question is how to use R-Tree in NetTopologySuite to show markers. I don't know how to use library. (I'm new in WPF). How to catch event when GMap render marker to get marker from R-Tree and remove previous marker at same time?
Please give me some example about R-tree in NetTopologySuite.
I did it by my way. This is the way STRtree is decleared: STRtree<Coordinate> gpsSTRtree = new STRtree<Coordinate>(); You can change Coordinate data type by any other data type but STRtree need to Envelope to insert to tree.
For example: insert to STRtree:
Coordinate gps = new Coordinate(9.74233, 106.0213);
Envelope item = new Envelope(gps);
gpsSTRtree.Insert(item, gps);
Envelope is a node in STRtree to store the boundary of item.
STRtree query from two points. point1 and point2 are Coordinate
Envelope gpsQuery = new Envelope(p1, p2);
Coordinate gpsItems = gpsSTRtree.Query(gpsQuery);
Then you have a list of Coordinate
Good luck
I have a geography column in database. This column holds the original polygon. Next to it I have another column that holds the simplified version of this polygon. The simplification has been done with geography.Reduce()(I use tolerance of 100) function that operates with Douglas-Peucker algorithm. When the client asks for this area I fetch it from database and do a quick convert into GeoJSON and serve it to my client.
If I query the original polygon it will take good 20 seconds before it is successfully retreived but it works. In the end only problem is the speed and that is why I introdouced the second column that holds the simplified polygon. Fetching this polygon from database happens in an instant but a curious thing happens on the client side.
As you can see multiple markers are shown on my map. None of them are clickable expect the top most(slightly south-west from Melbourne) but this one is actually a marker that I have added. Where do the other ones come from?
Another thing I noticed is the more I reduce simplicity the less of these fanthom markers shows. So if I serve the original polygon as GeoJSON all is fine. As soon as I start simplifying I get these fantom markers.
When I query for this simplified polygon I use geography::STAsText() function. After that I use NetTopologySuite to read this as WKT and create a NetSuiteTopology Geometry object. With this object I create a Feature and use GeoJsonWriter to create the actual GeoJSON.
var query = new SqlQuery("Location")
.Select("LocationServicingAreaSimplified.STAsText()")
.Where("LocationID", SqlOp.Equals, "#LocationID");
// This object query will be convertet to
// SELECT LocationServicingAreaSimplified.STAsText() FROM Location WHERE LocationID = ?
query.Parameters.Add("#LocationID", LocationID);
var simplifiedPolygon = await query.ExecuteScalarAsync<string>();
var wktReader = new WKTReader() { DefaultSRID = 4326 };
var geoJsonWriter = new GeoJsonWriter();
var feature = new Feature
{
Geometry = wktReader.Read(simplifiedPolygon)
};
return geoJsonWriter.Write(feature);
After an extensive research I have concluded that the proces of simplification will produce points when some polygons are oversimplified. google maps will represent the points as markers therefore, the greater the simplification the more points are produced the more markers are present.
I have found an article where it is described how to get rid of these points but haven't yet tested it.
Hope this helps some spatial noob(like me).
Is there a way to solidify a SCNNode scale and orientation by recalculating its geometry?
Basically I am loading a SCNNode out of a scn file that was converted from a sketchup file that was exported to a DAE file. Because ARKit works in meters and with a different axis orientation I have to set the loaded SCNNode’s scale (to 0.0254) and eulerangle (x -90deg) to correctly show it. This all works fine however thus scaling and rotation messes up some logic down the line because this logic also uses rotation thus overriding the previous one... :(
I think it would be great if I could simply tell the SCNNode to recalculate its geometry based on its current scale, orientation... (basically its transformation matrix) which would result in an SCNNode with transformation matrix the zero matrix....
If you “simply” want to tell the node to scale its vertices permanently, you will have to write a function to do so as there is no standard option.
That function should read the vertex source of the node’s geometry into an array of vectors, then use GLKMatrix4MultiplyAndProjectVector3 to apply the transformation to each vector, and then create a new SCNGeometry with the new verts as a source.
GLKMatrix4 scalemat = GLKMatrix4MakeScale(aNode.scale.x, aNode.scale.y, aNode.scale.z);
for (HEVertex* vert in toBeTransformedVerts) {
vert.pos = SCNVector3FromGLKVector3(GLKMatrix4MultiplyAndProjectVector3(scalemat, SCNVector3ToGLKVector3(vert.pos)) );
}
//reset node scale property.
aNode.scale = SCNVector3Make(1.0, 1.0, 1.0);
HEVertex is a class I use to store vertices, the pos property is a SCNVector3. In your case you would have to read the vertex source of the .geometry of the SCNNode into an array of SCNVector3 and loop through those instead.
After transforming the position of each vertex, you need to update the node's geometry. I.e. something like this:
SCNGeometrySource *_vertexSource =
[SCNGeometrySource geometrySourceWithVertices:_meshVertices count:_vertexCount];
aNode.geometry = [SCNGeometry geometryWithSources:#[_vertexSource, _aNode.geometry.geometrySources[1], _aNode.geometry.geometrySources[2]] elements:#[_aNode.geometry.geometryElements.firstObject]];
That is just a rough example, it updates only the vertex source, and reuses the normal and color geometry sources and the geometryElement, which can differ highly per model.
Very doable, but not nearly as simple as re-exporting the model with the appropriate size.
If the node doesn't have any subnodes, you can simply parent your node to an empty node, perform the desired transforms on your node, then call flatten on the empty parent node. Your node's center and orientation will match what was the empty parent node. If your node has a tree of child nodes, you'll need to do this recursively.
As an alternative to more complicated approaches you can easily accomplish this with a simple child node...
Create a new node
Move the geometry (and any other node properties you wish) from your original node to the new node
Add the new node as a child of the original node
Apply the scale transform to the child node.
Essentially, after step 3 you should be back exactly where you were before doing anything, except you now have a new child node to apply your scale transforms to, leaving the parent node alone so it can use the identity matrix (or whatever matrix you want.)
A similar approach is to use the existing node as-is...
Create a new parent node
Add it to the same parent as your existing node
Move your existing node from the old parent to this new parent
Copy the transform from your existing child node to the new parent node
Replace the transform on the child node with the scale transform only
Choosing between the two really depends on how much stuff you have on your node that you want to move as well as what transforms it originally had on it. (i.e. if you scale a node, it may be out of place from its original position relative to the model.) You choose which of the above you wish to do based on that information.
That said, if it's just the geometry alone and scaling it in-place works, go with the first. If there are lots of node properties, go with the second. Point being, you're adding a new node specifically to apply the scaling to your existing node, no direct geometry modifications needed.
I am working on an animation in AS2 which requires that all text MovieClips (instance names starting with "txt_") will be manually placed initially on stage and I need to store their own initial placed positions (x,y) so they will be retrievable later when I want to animate them to these same final coordinates regardless of where they move around in the meantime.
So the following steps needed:
All these text movieclips are placed on stage manually from library (not dynamically) matching their expected target keyframe end position (x,y) to get desired final screen layout.
Then a frame script loops through all these MovieClip instances on stage before rendering them on stage and stores their initial (also future target) (mc.targetPosX or mc.targetPosY) positions.
Then frame script also moves all of these MovieClip instances before rendering them on stage and moves/offsets them elsewhere on stage (eg. mc._x +=25px;) and hides them (eg. mc._alpha =0;)
Finally by using a tween like Greensock I want to use their stored target end position to animate each of them to their stored final target position.
(eg. TweenLite.to(mc, 1,{_alpha:100, _x:mc.targetPosX, ease:Quad.easeOut});)
I was able to create a loop to get "txt_" movieclips but then I don't know how to save their target positions with their instance and use them outside the loop afterwards.
Thank you in advance,
Attila
I don't know what problems do you have trying store some variables inside instances, but here my suggestions about proccess you described.
First of all we have loop which do all thing you described at question.
To do so we must have some list of you mc's or pattern to make this list dynamically. From you question i suppose that you use this kind of loop.
for(var i=0, txtCount=10; i<txtCount; i++){
textMc = this['txt_'+i];
//do stuff
...
}
From here on your points.
You already did it.
Use loop described above to store current object properties inside his instance
textMc.storedX=textMc._x;
textMc.storedY=textMc._y;
Here is same loop place object wherever you like
textMc._x+=25;
textMc._alpha=0;
Finally right after that in the same loop use greensock.
TweenLite.to(textMc, 1,{_alpha:100, _x:mc.storedX, ease:Quad.easeOut});
That's it.
So, I'm creating a fairly basic overhead 2d game where users can "draw" a map. (Actually, they dont draw it, the manually input a list of x/y's, but the design aspect isnt important just now.)
When a new tile is added, that tile goes into an array of all tiles ingame.
The centrepoint is 0,0. Tiles can be added in all directions, so may be at 1,1 or 100,100 or -50,-50.
Sometimes I want to determine what tile is at a location. One (imho bad) way of doing this would be to get the x/y and loop through all tiles and check if they are that location.
The way I'm currently doing it is to have a seperate 2d array of null elements, and when a tile is added, its set at that array. (ie tilemap[10][10] = tile[100])
Of course, because the values can go negative, tilemap [0][0] is actually the -1000/-1000 tile. (chosen as an arbitrary limit)
Is there a better way of doing this? I feel like using a massive array of mostly empty objects could be more optimal.
Many thanks.
One possible solution would be to keep an Object or Dictionary where the key is the x/y location.
So if you're adding a tile at 10,20, you can store it in the Object like:
this.m_objs[tileX + "_" + tileY] = new Tile;
So if you want to check if something's at position 10,20 you can by using something like:
public function checkIfExists( x:int, y:int ):void
{
return ( this.m_objs[x + "_" + y] != undefined );
}
I recomend using Dictionary, as searching in it much more faster then searching array. Judhing by possible coords -1000/-1000 it would be a great advantage!