601 lines
26 KiB
Swift
601 lines
26 KiB
Swift
//
|
|
// RTABMap.swift
|
|
// RTABMapApp
|
|
//
|
|
// Created by Mathieu Labbe on 2020-12-31.
|
|
//
|
|
|
|
import Foundation
|
|
import ARKit
|
|
|
|
class RTABMap {
|
|
var native_rtabmap: UnsafeMutableRawPointer
|
|
|
|
struct Observation {
|
|
weak var observer: RTABMapObserver?
|
|
}
|
|
private var observations = [ObjectIdentifier : Observation]()
|
|
|
|
func addObserver(_ observer: RTABMapObserver) {
|
|
let id = ObjectIdentifier(observer)
|
|
observations[id] = Observation(observer: observer)
|
|
}
|
|
|
|
func removeObserver(_ observer: RTABMapObserver) {
|
|
let id = ObjectIdentifier(observer)
|
|
observations.removeValue(forKey: id)
|
|
}
|
|
|
|
init() {
|
|
native_rtabmap = UnsafeMutableRawPointer(mutating: createNativeApplication())
|
|
}
|
|
|
|
func setupCallbacksWithCPP()
|
|
{
|
|
setupCallbacksNative(native_rtabmap,
|
|
UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()),
|
|
//progressCallback
|
|
{(observer, count, max) -> Void in
|
|
// Extract pointer to `self` from void pointer:
|
|
let mySelf = Unmanaged<RTABMap>.fromOpaque(observer!).takeUnretainedValue()
|
|
// Call instance method:
|
|
//mySelf.TestMethod();
|
|
for (id, observation) in mySelf.observations {
|
|
// If the observer is no longer in memory, we
|
|
// can clean up the observation for its ID
|
|
guard let observer = observation.observer else {
|
|
mySelf.observations.removeValue(forKey: id)
|
|
continue
|
|
}
|
|
|
|
observer.progressUpdated(mySelf, count: Int(count), max: Int(max))
|
|
}
|
|
},
|
|
//initCallback
|
|
{(observer, status, msg) -> Void in
|
|
// Extract pointer to `self` from void pointer:
|
|
let mySelf = Unmanaged<RTABMap>.fromOpaque(observer!).takeUnretainedValue()
|
|
// Call instance method:
|
|
//mySelf.TestMethod();
|
|
for (id, observation) in mySelf.observations {
|
|
// If the observer is no longer in memory, we
|
|
// can clean up the observation for its ID
|
|
guard let observer = observation.observer else {
|
|
mySelf.observations.removeValue(forKey: id)
|
|
continue
|
|
}
|
|
|
|
let str = String(cString: msg!)
|
|
observer.initEventReceived(mySelf, status: Int(status), msg: str)
|
|
}
|
|
},
|
|
//statsUpdatedCallback
|
|
{(observer, nodes, words, points, polygons, updateTime, loopClosureId, highestHypId, databaseMemoryUsed, inliers, matches, featuresExtracted, hypothesis, nodesDrawn, fps, rejected, rehearsalValue, optimizationMaxError, optimizationMaxErrorRatio, distanceTravelled, fastMovement, landmarkDetected, x, y, z, roll, pitch, yaw) -> Void in
|
|
// Extract pointer to `self` from void pointer:
|
|
let mySelf = Unmanaged<RTABMap>.fromOpaque(observer!).takeUnretainedValue()
|
|
// Call instance method:
|
|
//mySelf.TestMethod();
|
|
for (id, observation) in mySelf.observations {
|
|
// If the observer is no longer in memory, we
|
|
// can clean up the observation for its ID
|
|
guard let observer = observation.observer else {
|
|
mySelf.observations.removeValue(forKey: id)
|
|
continue
|
|
}
|
|
|
|
observer.statsUpdated(mySelf, nodes: Int(nodes), words: Int(words), points: Int(points), polygons: Int(polygons), updateTime: updateTime, loopClosureId: Int(loopClosureId), highestHypId: Int(highestHypId), databaseMemoryUsed: Int(databaseMemoryUsed), inliers: Int(inliers), matches: Int(matches), featuresExtracted: Int(featuresExtracted), hypothesis: hypothesis, nodesDrawn: Int(nodesDrawn), fps: fps, rejected: Int(rejected), rehearsalValue: rehearsalValue, optimizationMaxError: optimizationMaxError, optimizationMaxErrorRatio: optimizationMaxErrorRatio, distanceTravelled: distanceTravelled, fastMovement: Int(fastMovement), landmarkDetected: Int(landmarkDetected), x: x, y: y, z: z, roll: roll, pitch: pitch, yaw: yaw)
|
|
}
|
|
},
|
|
//cameraInfoEventCallback
|
|
{(observer, type, key, value) -> Void in
|
|
// Extract pointer to `self` from void pointer:
|
|
let mySelf = Unmanaged<RTABMap>.fromOpaque(observer!).takeUnretainedValue()
|
|
// Call instance method:
|
|
//mySelf.TestMethod();
|
|
for (id, observation) in mySelf.observations {
|
|
// If the observer is no longer in memory, we
|
|
// can clean up the observation for its ID
|
|
guard let observer = observation.observer else {
|
|
mySelf.observations.removeValue(forKey: id)
|
|
continue
|
|
}
|
|
|
|
let strKey = String(cString: key!)
|
|
let strValue = String(cString: value!)
|
|
observer.cameraInfoEventReceived(mySelf, type: Int(type), key: strKey, value: strValue)
|
|
}
|
|
})
|
|
}
|
|
|
|
deinit {
|
|
destroyNativeApplication(native_rtabmap)
|
|
}
|
|
|
|
func initGlContent() {
|
|
initGlContentNative(native_rtabmap)
|
|
}
|
|
|
|
func setupGraphic(size: CGSize, orientation: UIInterfaceOrientation) {
|
|
var rotation: Int32
|
|
switch orientation.rawValue {
|
|
case 4:
|
|
rotation=2
|
|
case 1:
|
|
rotation=3
|
|
case 2:
|
|
rotation=1
|
|
default:
|
|
rotation=0
|
|
}
|
|
//NSLog("Orientation: ios %d android %d, view=%dx%d", orientation.rawValue, rotation, Int32(size.width), Int32(size.height))
|
|
setScreenRotationNative(native_rtabmap, rotation)
|
|
setupGraphicNative(native_rtabmap, Int32(size.width), Int32(size.height));
|
|
}
|
|
|
|
func openDatabase(databasePath:String, databaseInMemory:Bool, optimize:Bool, clearDatabase: Bool) -> Int {
|
|
databasePath.utf8CString.withUnsafeBufferPointer { buffer -> Int in
|
|
return Int(openDatabaseNative(native_rtabmap, buffer.baseAddress, databaseInMemory, optimize, clearDatabase))
|
|
}
|
|
}
|
|
|
|
func save(databasePath:String) {
|
|
databasePath.utf8CString.withUnsafeBufferPointer { buffer in
|
|
saveNative(native_rtabmap, databasePath)
|
|
}
|
|
}
|
|
|
|
func recover(from: String, to: String) -> Bool {
|
|
from.utf8CString.withUnsafeBufferPointer { bufferFrom -> Bool in
|
|
to.utf8CString.withUnsafeBufferPointer { bufferTo -> Bool in
|
|
return recoverNative(native_rtabmap, bufferFrom.baseAddress, bufferTo.baseAddress)
|
|
}
|
|
}
|
|
}
|
|
|
|
func removeMeasure() {
|
|
removeMeasureNative(native_rtabmap)
|
|
}
|
|
func addMeasureButtonClicked() {
|
|
addMeasureNative(native_rtabmap)
|
|
}
|
|
func teleportButtonClicked() {
|
|
teleportNative(native_rtabmap)
|
|
}
|
|
func setMeasuringMode(_ mode: Int) {
|
|
setMeasuringModeNative(native_rtabmap, Int32(mode))
|
|
}
|
|
func setMetricSystem(_ enabled: Bool) {
|
|
setMetricSystemNative(native_rtabmap, enabled)
|
|
}
|
|
func setMeasuringTextSize(_ size: Float32) {
|
|
setMeasuringTextSizeNative(native_rtabmap, size)
|
|
}
|
|
func clearMeasures() {
|
|
clearMeasuresNative(native_rtabmap)
|
|
}
|
|
func cancelProcessing() {
|
|
cancelProcessingNative(native_rtabmap);
|
|
}
|
|
|
|
func postProcessing(approach: Int) -> Int {
|
|
return Int(postProcessingNative(native_rtabmap, Int32(approach)))
|
|
}
|
|
|
|
func exportMesh(
|
|
cloudVoxelSize: Float,
|
|
regenerateCloud: Bool,
|
|
meshing: Bool,
|
|
textureSize: Int,
|
|
textureCount: Int,
|
|
normalK: Int,
|
|
optimized: Bool,
|
|
optimizedVoxelSize: Float,
|
|
optimizedDepth: Int,
|
|
optimizedMaxPolygons: Int,
|
|
optimizedColorRadius: Float,
|
|
optimizedCleanWhitePolygons: Bool,
|
|
optimizedMinClusterSize: Int,
|
|
optimizedMaxTextureDistance: Float,
|
|
optimizedMinTextureClusterSize: Int,
|
|
textureVertexColorPolicy: Int,
|
|
blockRendering: Bool) -> Bool
|
|
{
|
|
return exportMeshNative(native_rtabmap,
|
|
cloudVoxelSize,
|
|
regenerateCloud,
|
|
meshing,
|
|
Int32(textureSize),
|
|
Int32(textureCount),
|
|
Int32(normalK),
|
|
optimized,
|
|
optimizedVoxelSize,
|
|
Int32(optimizedDepth),
|
|
Int32(optimizedMaxPolygons),
|
|
optimizedColorRadius,
|
|
optimizedCleanWhitePolygons,
|
|
Int32(optimizedMinClusterSize),
|
|
optimizedMaxTextureDistance,
|
|
Int32(optimizedMinTextureClusterSize),
|
|
Int32(textureVertexColorPolicy),
|
|
blockRendering)
|
|
}
|
|
|
|
func postExportation(visualize: Bool) -> Bool
|
|
{
|
|
return postExportationNative(native_rtabmap, visualize)
|
|
}
|
|
|
|
func writeExportedMesh(directory: String, name: String) -> Bool
|
|
{
|
|
directory.utf8CString.withUnsafeBufferPointer { bufferDir in
|
|
name.utf8CString.withUnsafeBufferPointer { bufferName in
|
|
return writeExportedMeshNative(native_rtabmap, bufferDir.baseAddress, bufferName.baseAddress)
|
|
}
|
|
}
|
|
}
|
|
|
|
func onTouchEvent(touch_count: Int, event: Int, x0: Float, y0: Float, x1: Float, y1: Float) {
|
|
onTouchEventNative(native_rtabmap, Int32(touch_count), Int32(event), x0, y0, x1, y1)
|
|
}
|
|
|
|
func setPausedMapping(paused: Bool) {
|
|
setPausedMappingNative(native_rtabmap, paused)
|
|
}
|
|
|
|
func render() -> Int {
|
|
return Int(renderNative(native_rtabmap))
|
|
}
|
|
|
|
func startCamera(imageOverlayInFirstPerson: Bool = true) -> Bool {
|
|
return startCameraNative(native_rtabmap)
|
|
}
|
|
|
|
func stopCamera() {
|
|
stopCameraNative(native_rtabmap)
|
|
}
|
|
|
|
func setCamera(type: Int) {
|
|
setCameraNative(native_rtabmap, Int32(type))
|
|
}
|
|
|
|
func postOdometryEvent(frame: ARFrame, orientation: UIInterfaceOrientation, viewport: CGSize) {
|
|
let pose = frame.camera.transform // ViewMatrix
|
|
let rotation = GLKMatrix3(
|
|
m: (pose[0,0], pose[0,1], pose[0,2],
|
|
pose[1,0], pose[1,1], pose[1,2],
|
|
pose[2,0], pose[2,1], pose[2,2]))
|
|
|
|
let quat = GLKQuaternionMakeWithMatrix3(rotation)
|
|
|
|
let confMap = frame.sceneDepth?.confidenceMap
|
|
let depthMap = frame.sceneDepth?.depthMap
|
|
let points = frame.rawFeaturePoints?.points
|
|
|
|
if points != nil && (depthMap != nil || points!.count>0)
|
|
{
|
|
let v = frame.camera.viewMatrix(for: orientation)
|
|
let p = frame.camera.projectionMatrix(for: orientation, viewportSize: viewport, zNear: 0.5, zFar: 50.0)
|
|
|
|
let rotation = GLKMatrix3(
|
|
m: (v[0,0], v[0,1], v[0,2],
|
|
v[1,0], v[1,1], v[1,2],
|
|
v[2,0], v[2,1], v[2,2]))
|
|
|
|
let quatv = GLKQuaternionMakeWithMatrix3(rotation)
|
|
|
|
let texX1 = (1-(2*frame.camera.intrinsics[0,0]/Float(frame.camera.imageResolution.width)) / p[0,0])/2
|
|
let texY1 = (1-(2*frame.camera.intrinsics[1,1]/Float(frame.camera.imageResolution.height)) / p[1,1])/2
|
|
|
|
let texX2 = (1-(2*frame.camera.intrinsics[0,0]/Float(frame.camera.imageResolution.width)) / p[1,1])/2
|
|
let texY2 = (1-(2*frame.camera.intrinsics[1,1]/Float(frame.camera.imageResolution.height)) / p[0,0])/2
|
|
|
|
//11 10 01 00 // portrait
|
|
//01 11 00 10 // right
|
|
//10 00 11 01 // left
|
|
//00 01 10 11 // down
|
|
var texCoord: [Float]
|
|
switch orientation {
|
|
case .portrait:
|
|
texCoord = [1-texX2, 1-texY2, 1-texX2,texY2, texX2, 1-texY2, texX2, texY2]
|
|
case .landscapeRight:
|
|
texCoord = [texX1, 1-texY1, 1-texX1, 1-texY1, texX1, texY1, 1-texX1, texY1]
|
|
case .landscapeLeft:
|
|
texCoord = [1-texX1, texY1, texX1, texY1, 1-texX1, 1-texY1, texX1, 1-texY1]
|
|
default: // down
|
|
texCoord = [texX2, texY2, texX2, 1-texY2, 1-texX2, texY2, 1-texX2, 1-texY2]
|
|
}
|
|
|
|
frame.rawFeaturePoints?.points.withUnsafeBufferPointer { bufferPoints in
|
|
|
|
CVPixelBufferLockBaseAddress(frame.capturedImage, CVPixelBufferLockFlags.readOnly)
|
|
var depthDataPtr: UnsafeMutableRawPointer?
|
|
var depthSize: Int32 = 0
|
|
var depthWidth: Int32 = 0
|
|
var depthHeight: Int32 = 0
|
|
var depthFormat: Int32 = 0
|
|
if depthMap != nil {
|
|
CVPixelBufferLockBaseAddress(depthMap!, CVPixelBufferLockFlags.readOnly)
|
|
depthDataPtr = CVPixelBufferGetBaseAddress(depthMap!)!
|
|
depthSize = Int32(CVPixelBufferGetDataSize(depthMap!))
|
|
depthWidth = Int32(CVPixelBufferGetWidth(depthMap!))
|
|
depthHeight = Int32(CVPixelBufferGetHeight(depthMap!))
|
|
depthFormat = Int32(CVPixelBufferGetPixelFormatType(depthMap!))
|
|
}
|
|
|
|
var confDataPtr: UnsafeMutableRawPointer?
|
|
var confSize: Int32 = 0
|
|
var confWidth: Int32 = 0
|
|
var confHeight: Int32 = 0
|
|
var confFormat: Int32 = 0
|
|
if confMap != nil {
|
|
CVPixelBufferLockBaseAddress(confMap!, CVPixelBufferLockFlags.readOnly)
|
|
confDataPtr = CVPixelBufferGetBaseAddress(confMap!)!
|
|
confSize = Int32(CVPixelBufferGetDataSize(confMap!))
|
|
confWidth = Int32(CVPixelBufferGetWidth(confMap!))
|
|
confHeight = Int32(CVPixelBufferGetHeight(confMap!))
|
|
confFormat = Int32(CVPixelBufferGetPixelFormatType(confMap!))
|
|
}
|
|
|
|
if(frame.lightEstimate != nil) {
|
|
addEnvSensor(type: 4, value: Float(frame.lightEstimate!.ambientIntensity))
|
|
}
|
|
|
|
var lost = false
|
|
switch frame.camera.trackingState {
|
|
case .normal:
|
|
lost = false
|
|
case .limited(.excessiveMotion):
|
|
lost = false
|
|
case .limited(.insufficientFeatures):
|
|
lost = false
|
|
default:
|
|
lost = true
|
|
}
|
|
// Notify lost with pose=null
|
|
|
|
postOdometryEventNative(native_rtabmap,
|
|
!lost ? pose[3,0]:0, !lost ? pose[3,1]:0, !lost ? pose[3,2]:0, !lost ? quat.x:0, !lost ? quat.y:0, !lost ? quat.z:0, !lost ? quat.w:0,
|
|
frame.camera.intrinsics[0,0], // fx
|
|
frame.camera.intrinsics[1,1], // fy
|
|
frame.camera.intrinsics[2,0], // cx
|
|
frame.camera.intrinsics[2,1], // cy
|
|
frame.timestamp,
|
|
CVPixelBufferGetBaseAddressOfPlane(frame.capturedImage, 0), // y plane pointer
|
|
nil, // u plane pointer
|
|
CVPixelBufferGetBaseAddressOfPlane(frame.capturedImage, 1), // v plane pointer
|
|
Int32(CVPixelBufferGetBytesPerRowOfPlane(frame.capturedImage, 0)) * Int32(CVPixelBufferGetHeightOfPlane(frame.capturedImage, 0)), // yPlaneLen
|
|
Int32(CVPixelBufferGetWidth(frame.capturedImage)), // rgb width
|
|
Int32(CVPixelBufferGetHeight(frame.capturedImage)), // rgb height
|
|
Int32(CVPixelBufferGetPixelFormatType(frame.capturedImage)), // rgb format
|
|
depthDataPtr, // depth pointer
|
|
depthSize, // depth size
|
|
depthWidth, // depth width
|
|
depthHeight, // depth height
|
|
depthFormat, // depth format
|
|
confDataPtr, // conf pointer
|
|
confSize, // conf size
|
|
confWidth, // conf width
|
|
confHeight, // conf height
|
|
confFormat, // conf format
|
|
bufferPoints.baseAddress, Int32(frame.rawFeaturePoints!.points.count), 4,
|
|
v[3,0], v[3,1], v[3,2], quatv.x, quatv.y, quatv.z, quatv.w,
|
|
p[0,0], p[1,1], p[2,0], p[2,1], p[2,2], p[2,3], p[3,2],
|
|
texCoord[0],texCoord[1],texCoord[2],texCoord[3],texCoord[4],texCoord[5],texCoord[6],texCoord[7])
|
|
if depthMap != nil {
|
|
CVPixelBufferUnlockBaseAddress(depthMap!, CVPixelBufferLockFlags.readOnly)
|
|
}
|
|
if confMap != nil {
|
|
CVPixelBufferUnlockBaseAddress(confMap!, CVPixelBufferLockFlags.readOnly)
|
|
}
|
|
CVPixelBufferUnlockBaseAddress(frame.capturedImage, CVPixelBufferLockFlags.readOnly)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Parameters
|
|
func setOnlineBlending(enabled: Bool) {
|
|
setOnlineBlendingNative(native_rtabmap, enabled)
|
|
}
|
|
func setMapCloudShown(shown: Bool) {
|
|
setMapCloudShownNative(native_rtabmap, shown)
|
|
}
|
|
func setOdomCloudShown(shown: Bool) {
|
|
setOdomCloudShownNative(native_rtabmap, shown)
|
|
}
|
|
func setMeshRendering(enabled: Bool, withTexture: Bool) {
|
|
setMeshRenderingNative(native_rtabmap, enabled, withTexture)
|
|
}
|
|
func setPointSize(value: Float) {
|
|
setPointSizeNative(native_rtabmap, value)
|
|
}
|
|
func setFOV(angle: Float) {
|
|
setFOVNative(native_rtabmap, angle)
|
|
}
|
|
func setOrthoCropFactor(value: Float) {
|
|
setOrthoCropFactorNative(native_rtabmap, value)
|
|
}
|
|
func setGridRotation(value: Float) {
|
|
setGridRotationNative(native_rtabmap, value)
|
|
}
|
|
func setLighting(enabled: Bool) {
|
|
setLightingNative(native_rtabmap, enabled)
|
|
}
|
|
func setBackfaceCulling(enabled: Bool) {
|
|
setBackfaceCullingNative(native_rtabmap, enabled)
|
|
}
|
|
func setWireframe(enabled: Bool) {
|
|
setWireframeNative(native_rtabmap, enabled)
|
|
}
|
|
func setTextureColorSeamsHidden(hidden: Bool) {
|
|
setTextureColorSeamsHiddenNative(native_rtabmap, hidden)
|
|
}
|
|
func setLocalizationMode(enabled: Bool) {
|
|
setLocalizationModeNative(native_rtabmap, enabled)
|
|
}
|
|
func setDataRecorderMode(enabled: Bool) {
|
|
setDataRecorderModeNative(native_rtabmap, enabled)
|
|
}
|
|
func setGraphOptimization(enabled: Bool) {
|
|
setGraphOptimizationNative(native_rtabmap, enabled)
|
|
}
|
|
func setNodesFiltering(enabled: Bool) {
|
|
setNodesFilteringNative(native_rtabmap, enabled)
|
|
}
|
|
func setGraphVisible(visible: Bool) {
|
|
setGraphVisibleNative(native_rtabmap, visible)
|
|
}
|
|
func setGridVisible(visible: Bool) {
|
|
setGridVisibleNative(native_rtabmap, visible)
|
|
}
|
|
func setFullResolution(enabled: Bool) {
|
|
setFullResolutionNative(native_rtabmap, enabled)
|
|
}
|
|
func setSmoothing(enabled: Bool) {
|
|
setSmoothingNative(native_rtabmap, enabled)
|
|
}
|
|
func setDepthBleedingError(value: Float) {
|
|
setDepthBleedingErrorNative(native_rtabmap, value)
|
|
}
|
|
func setAppendMode(enabled: Bool) {
|
|
setAppendModeNative(native_rtabmap, enabled)
|
|
}
|
|
func setUpstreamRelocalizationAccThr(value: Float) {
|
|
setUpstreamRelocalizationAccThrNative(native_rtabmap, value)
|
|
}
|
|
func setMaxCloudDepth(value: Float) {
|
|
setMaxCloudDepthNative(native_rtabmap, value)
|
|
}
|
|
func setMinCloudDepth(value: Float) {
|
|
setMinCloudDepthNative(native_rtabmap, value)
|
|
}
|
|
func setCloudDensityLevel(value: Int) {
|
|
setCloudDensityLevelNative(native_rtabmap, Int32(value))
|
|
}
|
|
func setMeshAngleTolerance(value: Float) {
|
|
setMeshAngleToleranceNative(native_rtabmap, value)
|
|
}
|
|
func setMeshDecimationFactor(value: Float) {
|
|
setMeshDecimationFactorNative(native_rtabmap, value)
|
|
}
|
|
func setMeshTriangleSize(value: Int) {
|
|
setMeshTriangleSizeNative(native_rtabmap, Int32(value))
|
|
}
|
|
func setClusterRatio(value: Float) {
|
|
setClusterRatioNative(native_rtabmap, value)
|
|
}
|
|
func setMaxGainRadius(value: Float) {
|
|
setMaxGainRadiusNative(native_rtabmap, value)
|
|
}
|
|
func setRenderingTextureDecimation(value: Int) {
|
|
setRenderingTextureDecimationNative(native_rtabmap, Int32(value))
|
|
}
|
|
func setBackgroundColor(gray: Float) {
|
|
setBackgroundColorNative(native_rtabmap, gray)
|
|
}
|
|
func setDepthConfidence(value: Int) {
|
|
setDepthConfidenceNative(native_rtabmap, Int32(value))
|
|
}
|
|
func setExportPointCloudFormat(format: String) {
|
|
format.utf8CString.withUnsafeBufferPointer { bufferFormat in
|
|
return setExportPointCloudFormatNative(native_rtabmap, bufferFormat.baseAddress)
|
|
}
|
|
}
|
|
func setMappingParameter(key: String, value: String) {
|
|
key.utf8CString.withUnsafeBufferPointer { bufferKey in
|
|
value.utf8CString.withUnsafeBufferPointer { bufferValue in
|
|
setMappingParameterNative(native_rtabmap, bufferKey.baseAddress, bufferValue.baseAddress)
|
|
}
|
|
}
|
|
}
|
|
func setGPS(location: CLLocation)
|
|
{
|
|
setGPSNative(native_rtabmap, location.timestamp.timeIntervalSince1970, location.coordinate.longitude, location.coordinate.latitude, location.altitude, location.horizontalAccuracy, location.course < 0.0 ? 0.0 : location.course)
|
|
}
|
|
func addEnvSensor(type: Int, value: Float)
|
|
{
|
|
addEnvSensorNative(native_rtabmap, Int32(type), value)
|
|
}
|
|
func setOrthoCropFactor(_ value: Float)
|
|
{
|
|
setOrthoCropFactorNative(native_rtabmap, value)
|
|
}
|
|
func setGridRotation(_ value: Float)
|
|
{
|
|
setGridRotationNative(native_rtabmap, value)
|
|
}
|
|
}
|
|
|
|
func getPreviewImage(databasePath: String) -> UIImage?
|
|
{
|
|
let imageOut = databasePath.utf8CString.withUnsafeBufferPointer { buffer -> UIImage? in
|
|
var image = ImageNative()
|
|
image = getPreviewImageNative(buffer.baseAddress)
|
|
if let dataPtr = UnsafeRawPointer(image.data)
|
|
{
|
|
// copy data in swift
|
|
let data = Data(bytes: dataPtr, count: Int(image.width*image.height*image.channels))
|
|
// release memory
|
|
releasePreviewImageNative(image)
|
|
// Create bitmap image
|
|
let bitmap = CIImage(bitmapData: data, bytesPerRow: Int(image.width*image.channels), size: CGSize(width: Int(image.width), height: Int(image.height)), format: CIFormat.BGRA8, colorSpace: nil)
|
|
return UIImage(ciImage: bitmap)
|
|
}
|
|
return UIImage(named: "RTAB-Map1024")
|
|
}
|
|
return imageOut
|
|
}
|
|
|
|
protocol RTABMapObserver: class {
|
|
func progressUpdated(_ rtabmap: RTABMap, count: Int, max: Int)
|
|
func initEventReceived(_ rtabmap: RTABMap, status: Int, msg: String)
|
|
func statsUpdated(_ rtabmap: RTABMap,
|
|
nodes: Int,
|
|
words: Int,
|
|
points: Int,
|
|
polygons: Int,
|
|
updateTime: Float,
|
|
loopClosureId: Int,
|
|
highestHypId: Int,
|
|
databaseMemoryUsed: Int,
|
|
inliers: Int,
|
|
matches: Int,
|
|
featuresExtracted: Int,
|
|
hypothesis: Float,
|
|
nodesDrawn: Int,
|
|
fps: Float,
|
|
rejected: Int,
|
|
rehearsalValue: Float,
|
|
optimizationMaxError: Float,
|
|
optimizationMaxErrorRatio: Float,
|
|
distanceTravelled: Float,
|
|
fastMovement: Int,
|
|
landmarkDetected: Int,
|
|
x: Float,
|
|
y: Float,
|
|
z: Float,
|
|
roll: Float,
|
|
pitch: Float,
|
|
yaw: Float)
|
|
func cameraInfoEventReceived(_ rtabmap: RTABMap, type: Int, key: String, value: String)
|
|
}
|
|
|
|
extension String {
|
|
|
|
func toPointer() -> UnsafePointer<UInt8>? {
|
|
guard let data = self.data(using: String.Encoding.utf8) else { return nil }
|
|
|
|
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
|
|
let stream = OutputStream(toBuffer: buffer, capacity: data.count)
|
|
|
|
stream.open()
|
|
data.withUnsafeBytes({ (p: UnsafePointer<UInt8>) -> Void in
|
|
stream.write(p, maxLength: data.count)
|
|
})
|
|
|
|
stream.close()
|
|
|
|
return UnsafePointer<UInt8>(buffer)
|
|
}
|
|
}
|
|
|