Pre loader

iOS & macOS RealTime 3D Geoid Chart

iOS & macOS charts - Examples

Please note! These examples are new to SciChart iOS v4 release! SciChart’s OpenGL ES and Metal iOS and Metal macOS Chart library ships with hundred of Objective-C and Swift iOS & macOS Chart Examples which you can browse, play with and view the source-code. All of this is possible with the new and improved SciChart iOS Examples Suite and demo application for Mac, which ships as part of the SciChart SDK.

Download Examples

This example among other Relatime high-performance iOS Chart examples demonstrates how to use SCIEllipsoidDataSeries3D in realtime to render Realtime Geoid Chart.

Read more in SciChart 3D iOS Chart Tutorial:

Realtime Data Plotting in 3D iOS Charts;

Ellipsoid Mesh 3D Chart Type in SciChart iOS.

The Swift and Objective-C source code for the iOS and macOS RealTime 3D Geoid Chart example is included below (Scroll down!).

Did you know that we have the source code for all our example available for free on Github?

Clone the SciChart.iOS.Examples from Github.

Also the SciChart iOS and Scichart macOS Trials contain the full source for the examples (link below).

DOWNLOAD THE IOS CHART EXAMPLES

RealTimeGeoid3DChartView.m
View source code
//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2019. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales:   sales@scichart.com
//
// RealTimeGeoid3DChartView.m is part of the SCICHART® Examples. Permission is hereby granted
// to modify, create derivative works, distribute and publish any part of this source
// code whether for commercial, private or personal use.
//
// The SCICHART® examples are distributed in the hope that they will be useful, but
// without any warranty. It is provided "AS IS" without warranty of any kind, either
// expressed or implied.
//******************************************************************************

#import "RealTimeGeoid3DChartView.h"

@interface RealTimeGeoid3DChartView ()

@property (strong, nonatomic) NSTimer *timer;
@property (strong, nonatomic) SCIEllipsoidDataSeries3D *dataSeries;
@property (strong, nonatomic) SCIDoubleValues *globeHeightMap;
@property (strong, nonatomic) SCIDoubleValues *buffer;

@property (nonatomic) int frames;
@property (nonatomic) int size;
@property (nonatomic) double heightOffsetScale;

@end

@implementation RealTimeGeoid3DChartView

- (Class)associatedType { return SCIChartSurface3D.class; }

- (void)initExample {
    _buffer = [SCIDoubleValues new];
    _frames = 0;
    _size = 100;
    _heightOffsetScale = 0.5;
    
    SCINumericAxis3D *xAxis = [SCINumericAxis3D new];
    xAxis.visibleRange = [[SCIDoubleRange alloc] initWithMin:-8 max:8];
    xAxis.autoRange = SCIAutoRange_Never;
    
    SCINumericAxis3D *yAxis = [SCINumericAxis3D new];
    yAxis.visibleRange = [[SCIDoubleRange alloc] initWithMin:-8 max:8];
    yAxis.autoRange = SCIAutoRange_Never;
    
    SCINumericAxis3D *zAxis = [SCINumericAxis3D new];
    zAxis.visibleRange = [[SCIDoubleRange alloc] initWithMin:-8 max:8];
    zAxis.autoRange = SCIAutoRange_Never;
    
    _dataSeries = [[SCIEllipsoidDataSeries3D alloc] initWithDataType:SCIDataType_Double uSize:_size vSize:_size];
    _dataSeries.a = @(6);
    _dataSeries.b = @(6);
    _dataSeries.c = @(6);
    
    _globeHeightMap = [self createGlobeHeightMap];
    [_dataSeries copyFromValues:_globeHeightMap];
    
    unsigned int colors[7] = { 0xFF1D2C6B, 0xFF0000FF, 0xFF00FFFF, 0xFFADFF2F, 0xFFFFFF00, 0xFFFF0000, 0xFF8B0000 };
    float stops[7] = { 0.0, 0.1, 0.3, 0.5, 0.7, 0.9, 1.0 };
    SCIGradientColorPalette *palette = [[SCIGradientColorPalette alloc] initWithColors:colors stops:stops count:7];

    SCIFreeSurfaceRenderableSeries3D *rSeries = [SCIFreeSurfaceRenderableSeries3D new];
    rSeries.dataSeries = _dataSeries;
    rSeries.drawMeshAs = SCIDrawMeshAs_SolidMesh;
    rSeries.stroke = 0x77228B22;
    rSeries.contourStroke = 0x77228B22;
    rSeries.strokeThickness = 2.0;
    rSeries.meshColorPalette = palette;
    rSeries.paletteMinimum = [[SCIVector3 alloc] initWithX:0.0 y:6.0 z:0.0];
    rSeries.paletteMaximum = [[SCIVector3 alloc] initWithX:0.0 y:7.0 z:0.0];

    [SCIUpdateSuspender usingWithSuspendable:self.surface withBlock:^{
        [self.surface.worldDimensions assignX:200 y:200 z:200];
        self.surface.xAxis = xAxis;
        self.surface.yAxis = yAxis;
        self.surface.zAxis = zAxis;
        [self.surface.renderableSeries add:rSeries];
        [self.surface.chartModifiers add:[SCDExampleBaseViewController createDefaultModifiers3D]];
    }];
    
    _timer = [NSTimer scheduledTimerWithTimeInterval:0.033 target:self selector:@selector(updateData) userInfo:nil repeats:YES];
#if TARGET_OS_OSX
    if (_timer) {
        [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
    }
#endif
}

- (SCIDoubleValues *)createGlobeHeightMap {
    SCIBitmap *bitmap = [SCIImage imageNamed:@"image.globe.heightmap"].sciBitmap;
    const double stepU = bitmap.width / _size;
    const double stepV = bitmap.height / _size;
    
    SCIDoubleValues *globeHeightMap = [SCIDoubleValues new];
    globeHeightMap.count = _size * _size;
    double *heightMapItems = globeHeightMap.itemsArray;
    
    for (int v = 0; v < _size; v++) {
        for (int u = 0; u < _size; u++) {
            const int index = v * _size + u;
            const int x = u * stepU;
            const int y = v * stepV;

            unsigned int pixelColor = [bitmap pixelAtX:x y:y];
            heightMapItems[index] = [SCIColor red:pixelColor]  / 255.0;
        }
    }
    
    return globeHeightMap;
}

- (void)updateData {
    __weak typeof(self) wSelf = self;
    [SCIUpdateSuspender usingWithSuspendable:self.surface withBlock:^{
        wSelf.frames++;
        
        const double freq = (sin(wSelf.frames * 0.1) + 1.0) / 2.0;
        const double exp = freq * 10.0;
        
        const int offset = wSelf.frames % wSelf.size;
        const NSInteger size = wSelf.globeHeightMap.count;
        
        wSelf.buffer.count = size;
        
        double *heightMapItems = wSelf.globeHeightMap.itemsArray;
        double *bufferItems = wSelf.buffer.itemsArray;
        
        for (int i = 0; i < size; i++) {
            int currentValueIndex = i + offset;
            if (currentValueIndex >= size) {
                currentValueIndex -= wSelf.size;
            }
            
            double currentValue = heightMapItems[currentValueIndex];
            bufferItems[i] = currentValue + pow(currentValue, exp) * wSelf.heightOffsetScale;
        }
        
        [wSelf.dataSeries copyFromValues:wSelf.buffer];
    }];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    
    [_timer invalidate];
    _timer = nil;
}

@end
RealTimeGeoid3DChartView.swift
View source code
//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2019. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales:   sales@scichart.com
//
// RealTimeGeoid3DChartView.swift is part of the SCICHART® Examples. Permission is hereby granted
// to modify, create derivative works, distribute and publish any part of this source
// code whether for commercial, private or personal use.
//
// The SCICHART® examples are distributed in the hope that they will be useful, but
// without any warranty. It is provided "AS IS" without warranty of any kind, either
// expressed or implied.
//******************************************************************************

class RealTimeGeoid3DChartView: SCDSingleChartViewController<SCIChartSurface3D> {
    
    override var associatedType: AnyClass { return SCIChartSurface3D.self }
    
    private let Size: UInt32 = 100
    private let HeightOffsetScale = 0.5
    private var frames = 0
    private let buffer = SCIDoubleValues()
    private var timer: Timer!
    private var globeHeightMap: SCIDoubleValues!
    private var ds: SCIEllipsoidDataSeries3D!
    
    override func initExample() {
        let xAxis = SCINumericAxis3D()
        xAxis.visibleRange = SCIDoubleRange(min: -8.0, max: 8.0)
        xAxis.autoRange = .never
        
        let yAxis = SCINumericAxis3D()
        yAxis.visibleRange = SCIDoubleRange(min: -8.0, max: 8.0)
        yAxis.autoRange = .never
        
        let zAxis = SCINumericAxis3D()
        zAxis.visibleRange = SCIDoubleRange(min: -8.0, max: 8.0)
        zAxis.autoRange = .never
        
        ds = SCIEllipsoidDataSeries3D(dataType: .double, uSize: Int(Size), vSize: Int(Size))
        ds.set(a: 6.0)
        ds.set(b: 6.0)
        ds.set(c: 6.0)
        globeHeightMap = getGlobeHightMap()
        ds.copy(from: globeHeightMap)
        
        let palette = SCIGradientColorPalette(
            colors: [0xFF1D2C6B, 0xFF0000FF, 0xFF00FFFF, 0xFFADFF2F, 0xFFFFFF00, 0xFFFF0000, 0xFF8B0000],
            stops: [0.0, 0.1, 0.3, 0.5, 0.7, 0.9, 1.0]
        )
        
        let rSeries = SCIFreeSurfaceRenderableSeries3D()
        rSeries.dataSeries = ds
        rSeries.drawMeshAs = .solidMesh
        rSeries.stroke = 0x77228B22
        rSeries.contourStroke = 0x77228B22
        rSeries.strokeThickness = 2.0
        rSeries.meshColorPalette = palette
        rSeries.paletteMinimum = SCIVector3(x: 0.0, y: 6.0, z: 0.0)
        rSeries.paletteMaximum = SCIVector3(x: 0.0, y: 7.0, z: 0.0)
        
        SCIUpdateSuspender.usingWith(surface) {
            self.surface.xAxis = xAxis
            self.surface.yAxis = yAxis
            self.surface.zAxis = zAxis
            self.surface.renderableSeries.add(rSeries)
            self.surface.chartModifiers.add(SCDExampleBaseViewController.createDefaultModifiers3D())
            
            self.surface.worldDimensions.assignX(200, y: 200, z: 200)
        }
        
        timer = Timer.scheduledTimer(timeInterval: 0.02, target: self, selector: #selector(updateData), userInfo: nil, repeats: true)
#if os(OSX)
        if let _timer = timer {
            RunLoop.main.add(timer, forMode: .common)
        }
#endif
    }
    
    func getGlobeHightMap() -> SCIDoubleValues {
        let bitmap = #imageLiteral(resourceName: "image.globe.heightmap").sciBitmap()
        let stepU = bitmap.width / Size
        let stepV = bitmap.height / Size
        
        let globeheightMap = SCIDoubleValues()
        globeheightMap.count = Int(Size * Size)
        
        for v in 0 ..< Size {
            for u in 0 ..< Size {
                let index = Int(v * Size + u)
                let x = u * stepU
                let y = v * stepV

                globeheightMap.set(Double(SCIColor.red(bitmap.pixelAt(x: x, y: y))) / 255.0, at: index)
            }
        }
        
        return globeheightMap
    }
    
    @objc fileprivate func updateData(_ timer: Timer) {
        SCIUpdateSuspender.usingWith(surface) {
            self.frames += 1
            let freq = (sin(Double(self.frames) * 0.1) + 1.0) / 2.0
            let exp  = freq * 10.0
            
            let offset = self.frames % Int(self.Size)
            let size = self.globeHeightMap.count
            
            self.buffer.count = size
            
            for i in 0 ..< size {
                var currentIndex = Int(i) + offset
                if (currentIndex >= size ){
                    currentIndex -= Int(self.Size)
                }
                
                let currentValue = self.globeHeightMap.getValueAt(currentIndex)
                self.buffer.set(currentValue + pow(currentValue, exp) * self.HeightOffsetScale, at: i)
            }
            self.ds.copy(from: self.buffer)
        }
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
        timer.invalidate()
        timer = nil
    }
}
Back to iOS & macOS charts Examples