Skip to content

Enhancement - SceneKitExtension / map a lat / lng coordinate to scenekit earth planet of where user is #47

@johndpope

Description

@johndpope
        let earthNode = PlanetoidGroupNode(planet: Planet.earth)
        earthNode.updatePlanetLocation(earthAA.position())

currently these lines map SwiftAA into the scenekit.
however, I don't believe there's any way to get scenekit camera to specific point of latitude / longitude.

this plist contains a bunch of cities with lat / lngs
https://github.com/op1000/EarthTravel/blob/master/EarthTravel/Resources/AllCititesToTravel_258.plist

        NSString* filePath = [[NSBundle mainBundle] pathForResource:@"AllCititesToTravel_258" ofType:@"plist"];
        NSDictionary* objectData = [NSDictionary dictionaryWithContentsOfFile:filePath];
        
        NSArray* arrayList = [objectData valueForKeyPath:@"list"];
        NSMutableArray* arrayCordinate = [[NSMutableArray alloc] init];
        for (NSDictionary* dicInfo in arrayList) {
            
            NSString* cityName = dicInfo[@"dest_name"];
            float lat = [dicInfo[@"lat"] floatValue];
            float lng = [dicInfo[@"lng"] floatValue];
            NSString* countryCode = [dicInfo objectForKey:@"country_code"];
            
            // drop some pins
            KGLEarthCoordinate *pin = [KGLEarthCoordinate coordinateWithLatitude:lat
                                                                    andLongitude:lng
                                                                andPinIdentifier:cityName
                                                                  andConturyCode:countryCode];
            [arrayCordinate addObject:pin];
        }
        [self dropPinsAtLocations:arrayCordinate];


-(void)dropPinsAtLocations:(NSArray *)pinArray
{
    // remove any existing pins
    for (SCNNode *node in _currentPins) {
        [node removeFromParentNode];
    }
    _currentPins = [NSMutableArray array];
    
    // create new pins
    for (KGLEarthCoordinate *coord in pinArray) {
        KGLPinNode *newPin = [KGLPinNode pinAtLatitude:coord.latitude
                                          andLongitude:coord.longitude
                                                 title:coord.pinIdentifier
                                           countryCode:coord.contryCode];
        if (coord.pinIdentifier) {
            newPin.identifier = coord.pinIdentifier;
        }
        [_shadedNode addChildNode:newPin];
        [_currentPins addObject:newPin];
    }
/*!
 * @discussion Convenience method for creating a pin, with internal nodes set up, at a specified location, assuming an Earth at the center of the scene with a radius of 50 units.
 * @param latitude The pin's latitude, in degrees.
 * @param longitude The pin's longitude, in degrees.
 * @return An instance of the KGLPinNode class.
 */

+ (KGLPinNode *)pinAtLatitude:(float)latitude
                 andLongitude:(float)longitude
                        title:(NSString*)title
                  countryCode:(NSString*)countryCode
{
    KGLPinNode *pin = [super node];

    if (pin) {
        pin.latitude = latitude;
        pin.longitude = longitude;
        pin.countryCode = countryCode;
    }
    
    pin.name = @"pinWrapper";

    SCNBox* pinScene = [SCNBox boxWithWidth:1.0 height:1.0 length:1.0*108.0/159.0 chamferRadius:0];

    //SCNPyramid* pinScene = [SCNPyramid pyramidWithWidth:1.0 height:1.0 length:1.0];
    SCNNode *pinNode = [SCNNode nodeWithGeometry:pinScene];
    NSString* strCountryImagePath = [NSString stringWithFormat: @"icon_%@", countryCode];
    {
        // ambient light
        SCNMaterial *greenMaterial              = [SCNMaterial material];
        greenMaterial.diffuse.contents          = [UIColor clearColor];
        greenMaterial.locksAmbientWithDiffuse   = YES;
        
        SCNMaterial *redMaterial                = [SCNMaterial material];
        redMaterial.diffuse.contents            = [UIColor clearColor];
        redMaterial.locksAmbientWithDiffuse     = YES;
        
        SCNMaterial *blueMaterial               = [SCNMaterial material];
        blueMaterial.diffuse.contents           = [UIColor clearColor];
        blueMaterial.locksAmbientWithDiffuse    = YES;
        
        SCNMaterial *yellowMaterial             = [SCNMaterial material];
        yellowMaterial.diffuse.contents         = [UIColor clearColor];
        yellowMaterial.locksAmbientWithDiffuse  = YES;
        
        SCNMaterial *purpleMaterial             = [SCNMaterial material];
        purpleMaterial.diffuse.contents         = strCountryImagePath; // 위를 쳐다보는 면
        purpleMaterial.locksAmbientWithDiffuse  = YES;
        
        SCNMaterial *magentaMaterial            = [SCNMaterial material];
        magentaMaterial.diffuse.contents        = [UIColor clearColor];
        magentaMaterial.locksAmbientWithDiffuse = YES;
        
        
        pinScene.materials =  @[greenMaterial,  redMaterial,    blueMaterial,
                           yellowMaterial, purpleMaterial, magentaMaterial];
    }
    
    // add the pin geometry to the pin node
    [pin addChildNode:pinNode];
    
    // pins are small, especially from directly above or zoomed out, so wrap a larger rectangular node around the pin
    // this will create a greater touch area
    SCNBox *touchBrick = [SCNBox boxWithWidth:5.0f height:7.5f length:5.0f chamferRadius:0];
    SCNNode *touchNode = [SCNNode nodeWithGeometry:touchBrick];
    touchNode.hidden = YES;
    touchNode.name = @"TouchPin";
    [pin addChildNode:touchNode];
    
    // position the pin
    // calculate the pin's position along the Y axis of the Earth, based on the given latitude
    float yPos = sinf(DEGREES_TO_RADIANS(latitude)) * 27.8f*ZOOME_RATIO;
    // calculate what the radius of the horizontal circle that cuts through the Earth is at the given Y position
    float localRadius = [KGLEarthCommonMath radiusOfCircleBisectingSphereOfRadius:27.8f*ZOOME_RATIO atHeight:yPos];
    // using the local radius, calculate the X and Z positions of the pin, based on the given longitude
    HorizontalCoords coords = [KGLEarthCommonMath horizontalCoordinatesAtDegrees:longitude ofSphereRadius:localRadius];
    pin.position = SCNVector3Make(-1 * coords.x, yPos, coords.z);
    
    // rotate the pin so it stands vertically at 90 degrees from the surface of the Earth
    // first, set the pin's euler angles such that it lies flat against the surface of the Earth, given the pin's location
    // the yaw angle positions the pin so it faces out from the surface of the Earth at its location
    float yawAngle = atan2f(-1 * coords.x, coords.z);
    // the pitch angle tilts the pin so it lies on the ground
    float pitchAngle = -1 * DEGREES_TO_RADIANS(latitude) - M_PI_2;
    pin.eulerAngles = SCNVector3Make(pitchAngle, yawAngle, 0);
    
    // now rotate the pin by 180 degrees vertically, so it stands up
    SCNMatrix4 latRotation = SCNMatrix4MakeRotation(DEGREES_TO_RADIANS(180),1, 0, 0);
    pin.transform = SCNMatrix4Mult(latRotation, pin.transform);
    
    //==============================
    // label
    //==============================
    SCNText *text = [SCNText textWithString:title extrusionDepth:0.1];
    
    SCNMaterial *magentaMaterial = [SCNMaterial material];
    magentaMaterial.diffuse.contents = [UtilManager colorWithHexString:@"ec4f30"];
    magentaMaterial.locksAmbientWithDiffuse = YES;
    text.materials = @[magentaMaterial];
    
    SCNNode *textNode = [SCNNode nodeWithGeometry:text];
    textNode.position = SCNVector3Make(-1+M_PI_2, 0, 0);
    textNode.transform = SCNMatrix4Mult(SCNMatrix4MakeScale(0.05, 0.05, 0.05), textNode.transform);
    [pin addChildNode:textNode];
        
    return pin;
}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions