objective c - Cylinder Orientation between two points on a sphere, Scenekit, Quaternions IOS -


i've been trying draw cylinder between 2 points on outer edge of sphere using scenekit. have produced line between these 2 points using primitive geometry , opengl scnrendering delegate, need produce cylinder between these 2 (well, not two, 2 3d vectors sit on surface of sphere). i've been working on 3 days straight now, , i've gone through find on implementing quaternions make happen, stands, can't work. academic articles, scientific studies, , nothing, nothing working realign cylinder between 2 fixed points. need algorithm this.

anyway, here's recent code doesn't work, small snippet of 2k lines of code i've worked through far without intended result. know can move more advanced building own scnprogram and/or scnrenderer access glsl, opengl, , metal complexity, seems should possible using scenekit , converting between glkit vector structs , scnvector structs, far it's impossible:

code:

the following code ingests longitude , latitude coordinates , projects them onto surface of 3d sphere. these coordinates returned through proprietary function build received scnvector3 of {x,y,z} coordinates display accurately on 3d sphere. draw line between 2 sets of longitude , latitude coordinates lines drawn using primitives shoot through center of sphere. so, mentioned above, want same functionality cylinders, not lines (by way, longitude , latitude coordinates listed here bogus, randomly generated both fall on earth's surface).

drawline = [self lat1:37.76830 lon1:-30.40096 height1:tall lat2:3.97620 lon2:63.73095 height2:tall];  float cylheight = glkvector3distance(scnvector3toglkvector3(cooridnatesetone.position), scnvector3toglkvector3(coordinatesettwo.position));  scncylinder * cyltest = [scncylinder cylinderwithradius:0.2 height:cylheight]; scnnode * test = [scnnode nodewithgeometry:cyltest];  scnmaterial *material = [scnmaterial material]; [[material diffuse] setcontents:[skcolor whitecolor]]; material.diffuse.intensity = 60; material.emission.contents = [skcolor whitecolor];  material.lightingmodelname = scnlightingmodelconstant; [cyltest setmaterials:@[material]];  glkvector3 u = scnvector3toglkvector3(cooridnatesetone.position); glkvector3 v = scnvector3toglkvector3(cooridnatesettwo.position);  glkvector3 w = glkvector3crossproduct(u, v);  glkquaternion q = glkquaternionmakewithangleandvector3axis(glkvector3dotproduct(u,v), glkvector3normalize(w)); q.w += glkquaternionlength(q); q = glkquaternionnormalize(q); scnvector4 final = scnvector4fromglkvector4(glkvector4make(q.x, q.y, q.z, q.w));  test.orientation = final; 

other code i've tried includes same sort of method, in fact, built own scnvector3 , scnvector4 math libraries in objective-c see if math methods produced different values using glkit maths, same results both methods. awesome, now, i'm not looking jump more complicated scenekit. won't diving metal and/or opengl month or two. thanks!

edit:

the variables "cooridnatesetone" , "cooridnatesettwo" scnnodes produced function forces primitive line geometry node , returns subclass implementation of scnscene.

here's entire method using objective-c

first, here's how use it:

scnnode * testnode = [self lat1:-35 lon1:108 height1:tall lat2:-35 lon2:30 height2:0]; 

inputs:

1rst location lat1 = latitude of 1rst location lon1 = longitude of 1rst location height1 = distance earth 1rst location lat2 = latitude of 2nd location lon2 = latitude of 2nd location height2 = distance earth 2nd location

the second method creates scnvector3 points each location in question above:

-(scnnode *)lat1:(double)lat1 lon1:(double)lon1 height1:(float)height1 lat2:(double)lat2 lon2:(double)lon2 height2:(float)height2 {     scnvector3 positions[] = {[self lat:lat1 lon:lon1 height:height1], [self lat:lat2 lon:lon2 height:height2]};      float cylheight = glkvector3distance(scnvector3toglkvector3(positions[0]), scnvector3toglkvector3(positions[1]))/4;      scncylinder * mastercylindernode = [scncylinder cylinderwithradius:0.05 height:cylheight];      scnmaterial *material = [scnmaterial material];     [[material diffuse] setcontents:[skcolor whitecolor]];     material.lightingmodelname = scnlightingmodelconstant;     material.emission.contents = [skcolor whitecolor];     [mastercylindernode setmaterials:@[material]];      scnnode *mainlocationpointnodetesta = [mainlocationpointnode clone];     scnnode *mainlocationpointnodetestb = [mainlocationpointnode clone];      mainlocationpointnodetesta.position = positions[0];     mainlocationpointnodetestb.position = positions[1];      scnnode * mainparentnode = [scnnode node];     scnnode * tempnode2 =[scnnode nodewithgeometry:mastercylindernode];      [mainparentnode addchildnode:mainlocationpointnodetesta];     [mainparentnode addchildnode:mainlocationpointnodetestb];     [mainparentnode addchildnode:tempnode2];      [mainparentnode setname:@"parenttolinenode"];      tempnode2.position = scnvector3make((positions[0].x+positions[1].x)/2, (positions[0].y+positions[1].y)/2, (positions[0].z+positions[1].z)/2);     tempnode2.pivot = scnmatrix4maketranslation(0, cylheight*1.5, 0);      glkvector3 normalizedvectorstartingposition = glkvector3make(0.0, 1.0, 0.0);     glkvector3 magicaxis = glkvector3normalize(glkvector3subtract(glkvector3make(positions[0].x/2, positions[0].y/2, positions[0].z/2), glkvector3make(positions[1].x/2, positions[1].y/2, positions[1].z/2)));      glkvector3 rotationaxis = glkvector3crossproduct(normalizedvectorstartingposition, magicaxis);     cgfloat rotationangle = glkvector3dotproduct(normalizedvectorstartingposition, magicaxis);      glkvector4 rotation = glkvector4makewithvector3(rotationaxis, acos(rotationangle));     tempnode2.rotation = scnvector4fromglkvector4(rotation);      return mainparentnode; } 

this second method uses hard coded numbers earth's radius , curvature, i'm showing show numbers required total 100% accuracy, how works. you'll want change correct dimensions scene, obviously, here's method. adaptation of methods used http://www.gdal.org/index.html. explanation found here: http://www.gdal.org/osr_tutorial.html. put works , accurate, feel free change number formats liking.

-(scnvector3)lat:(double)lat lon:(double)lon height:(float)height {     double latd = 0.0174532925;     double latitude = latd*lat;     double longitude = latd*lon;      float64 rad = (float64)(6378137.0);     float64 f = (float64)(1.0/298.257223563);      double coslat = cos(latitude);      double sinlat = sin(latitude);      double ff = pow((1.0-f), 2);     double c = 1/(sqrt(pow(coslat,2) + ff * pow(sinlat,2)));     double s = c * ff;      double x = ((rad * c)*coslat * cos(longitude))/(1000000/(1+height));     double y = ((rad * c)*coslat * sin(longitude))/(1000000/(1+height));     double z = ((rad * s)*sinlat)/(1000000/(1+height));      return scnvector3make(y+globenode.position.x, z+globenode.position.y, x+globenode.position.z); } 

Comments

Popular posts from this blog

c# - Validate object ID from GET to POST -

node.js - Custom Model Validator SailsJS -

php - Find a regex to take part of Email -