mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 17:40:23 +08:00
Using shadows on all texts and icons to see them better when background is white. Buffering database previews to show faster the Library. Updated how RAM usage is computed and now show max memory. Added warnings when RAM usage is low.
This commit is contained in:
@@ -79,7 +79,6 @@
|
||||
</stackView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="wordWrap" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KlF-4H-k6I">
|
||||
<rect key="frame" x="16" y="79" width="31" height="14.333333333333329"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.29820365646258501" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -146,18 +145,8 @@
|
||||
<action selector="clipDistanceAction:" destination="zah-iI-EPt" eventType="valueChanged" id="iKj-nz-0KW"/>
|
||||
</connections>
|
||||
</slider>
|
||||
<slider opaque="NO" contentMode="scaleToFill" placeholderIntrinsicWidth="114" placeholderIntrinsicHeight="30" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="90" minValue="0.0" maxValue="180" translatesAutoresizingMaskIntoConstraints="NO" id="Z1x-Af-hdf" userLabel="GridRotationSlider">
|
||||
<rect key="frame" x="135.66666666666666" y="727" width="121.99999999999997" height="31"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="118" id="KDl-lP-Jj7"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<action selector="rotateGridAction:" destination="zah-iI-EPt" eventType="valueChanged" id="eiC-QR-TYH"/>
|
||||
</connections>
|
||||
</slider>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Toast Label" textAlignment="center" lineBreakMode="wordWrap" numberOfLines="4" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JMv-UE-cvK" userLabel="ToastLabel">
|
||||
<rect key="frame" x="51" y="668.33333333333337" width="291" height="20.333333333333371"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.3002232142857143" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<rect key="frame" x="51" y="637.33333333333337" width="291" height="20.333333333333371"/>
|
||||
<accessibility key="accessibilityConfiguration">
|
||||
<accessibilityTraits key="traits" staticText="YES" notEnabled="YES"/>
|
||||
</accessibility>
|
||||
@@ -165,6 +154,15 @@
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<slider opaque="NO" contentMode="scaleToFill" placeholderIntrinsicWidth="114" placeholderIntrinsicHeight="30" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="90" minValue="0.0" maxValue="180" translatesAutoresizingMaskIntoConstraints="NO" id="Z1x-Af-hdf" userLabel="GridRotationSlider">
|
||||
<rect key="frame" x="132" y="727" width="122" height="31"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="118" id="KDl-lP-Jj7"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<action selector="rotateGridAction:" destination="zah-iI-EPt" eventType="valueChanged" id="eiC-QR-TYH"/>
|
||||
</connections>
|
||||
</slider>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="qAR-pI-uT2"/>
|
||||
<constraints>
|
||||
@@ -184,12 +182,12 @@
|
||||
<constraint firstItem="3Sc-lx-YKH" firstAttribute="top" secondItem="ozY-dg-YOd" secondAttribute="bottom" constant="16" id="abR-Tj-Nua"/>
|
||||
<constraint firstItem="qAR-pI-uT2" firstAttribute="bottom" secondItem="012-W3-dOS" secondAttribute="bottom" constant="24" id="dcl-mV-bH1"/>
|
||||
<constraint firstItem="9oq-op-NGV" firstAttribute="centerX" secondItem="sqF-4e-2HU" secondAttribute="centerX" id="g5b-gW-Amg"/>
|
||||
<constraint firstItem="Z1x-Af-hdf" firstAttribute="centerX" secondItem="sqF-4e-2HU" secondAttribute="centerX" id="i2j-zQ-m1V"/>
|
||||
<constraint firstItem="Z1x-Af-hdf" firstAttribute="top" secondItem="JMv-UE-cvK" secondAttribute="bottom" constant="38.5" id="icg-DR-ZpX"/>
|
||||
<constraint firstItem="9oq-op-NGV" firstAttribute="top" secondItem="JMv-UE-cvK" secondAttribute="bottom" constant="113.33" id="icg-DR-ZpX"/>
|
||||
<constraint firstItem="qAR-pI-uT2" firstAttribute="bottom" secondItem="9oq-op-NGV" secondAttribute="bottom" constant="25" id="lFI-66-D3N"/>
|
||||
<constraint firstAttribute="trailing" secondItem="kPv-DO-hpd" secondAttribute="trailing" constant="10" id="lFv-p3-LIS"/>
|
||||
<constraint firstItem="qAR-pI-uT2" firstAttribute="trailing" secondItem="ozY-dg-YOd" secondAttribute="trailing" constant="20" id="ov4-d2-OMy"/>
|
||||
<constraint firstItem="012-W3-dOS" firstAttribute="top" secondItem="30J-Tx-NRW" secondAttribute="bottom" constant="60" id="tbj-nG-nfI"/>
|
||||
<constraint firstItem="Z1x-Af-hdf" firstAttribute="leading" secondItem="30J-Tx-NRW" secondAttribute="trailing" constant="16" id="uMj-kM-hlH"/>
|
||||
<constraint firstItem="qAR-pI-uT2" firstAttribute="trailing" secondItem="3Sc-lx-YKH" secondAttribute="trailing" constant="10" id="v2K-Dp-Kyn"/>
|
||||
<constraint firstItem="Jj4-ow-MwD" firstAttribute="centerY" secondItem="sqF-4e-2HU" secondAttribute="centerY" id="vmc-4u-BtF"/>
|
||||
</constraints>
|
||||
@@ -215,7 +213,7 @@
|
||||
</glkViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="plN-WG-seA" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-234.375" y="-586.25"/>
|
||||
<point key="canvasLocation" x="-235.87786259541983" y="-586.61971830985919"/>
|
||||
</scene>
|
||||
<!--Unsupported View Controller-->
|
||||
<scene sceneID="sJB-xy-u63">
|
||||
@@ -226,14 +224,14 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Unsupported Device" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" enabled="NO" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kZt-ct-4KD">
|
||||
<rect key="frame" x="28" y="341.33333333333331" width="337.33333333333331" height="33.666666666666686"/>
|
||||
<rect key="frame" x="21" y="352.33333333333331" width="351.33333333333331" height="33.666666666666686"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" enabled="NO" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4Js-Hw-3QU">
|
||||
<rect key="frame" x="28" y="383" width="337.33333333333331" height="86.333333333333314"/>
|
||||
<string key="text">This sample app requires a LiDAR-capable device, such as the second-generation iPad Pro 11-inch and fourth-generation iPad Pro 12.9-inch.</string>
|
||||
<rect key="frame" x="21" y="394" width="351.33333333333326" height="64.333333333333314"/>
|
||||
<string key="text">This app requires a LiDAR-capable device, such as the second-generation iPad Pro 11-inch and fourth-generation iPad Pro 12.9-inch.</string>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -262,9 +260,9 @@
|
||||
<image name="eye" catalog="system" width="128" height="79"/>
|
||||
<image name="folder" catalog="system" width="128" height="96"/>
|
||||
<image name="plus.app" catalog="system" width="128" height="114"/>
|
||||
<image name="record.circle" catalog="system" width="128" height="123"/>
|
||||
<image name="record.circle" catalog="system" width="32" height="32"/>
|
||||
<image name="square.and.arrow.up" catalog="system" width="108" height="128"/>
|
||||
<image name="stop.circle" catalog="system" width="128" height="123"/>
|
||||
<image name="stop.circle" catalog="system" width="32" height="32"/>
|
||||
<image name="xmark.square" catalog="system" width="128" height="114"/>
|
||||
<systemColor name="systemRedColor">
|
||||
<color red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
||||
@@ -55,11 +55,19 @@ class DatabaseView: UIView {
|
||||
super.init(frame: frame)
|
||||
self.databaseURL = databaseURL
|
||||
commonInit(databasePath: databaseURL.path)
|
||||
DispatchQueue.global().async {
|
||||
let downloadedImage = getPreviewImage(databasePath: databaseURL.path)
|
||||
DispatchQueue.main.async {
|
||||
self.coverImageView.image = downloadedImage
|
||||
}
|
||||
if let image = ViewController.previewImages[databaseURL.path]
|
||||
{
|
||||
self.coverImageView.image = image
|
||||
}
|
||||
else
|
||||
{
|
||||
DispatchQueue.global().async {
|
||||
let downloadedImage = getPreviewImage(databasePath: databaseURL.path)
|
||||
DispatchQueue.main.async {
|
||||
self.coverImageView.image = downloadedImage
|
||||
ViewController.previewImages[databaseURL.path] = downloadedImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
|
||||
private var mReviewRequested = false
|
||||
|
||||
private var mMaximumMemory: Int = 0
|
||||
|
||||
// UI states
|
||||
private enum State {
|
||||
case STATE_WELCOME, // Camera/Motion off - showing only buttons open and start new scan
|
||||
@@ -96,6 +98,8 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
private var mHudVisible: Bool = true
|
||||
private var mLastTimeHudShown: DispatchTime = .now()
|
||||
private var mMenuOpened: Bool = false
|
||||
private var lowMemoryWarningShown: Bool = false
|
||||
static var previewImages: [String: UIImage] = [:]
|
||||
|
||||
@IBOutlet weak var stopButton: UIButton!
|
||||
@IBOutlet weak var recordButton: UIButton!
|
||||
@@ -175,13 +179,41 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
}
|
||||
}
|
||||
|
||||
func addShadow(_ view: UIView, _ offset: Int = 4)
|
||||
{
|
||||
view.layer.shadowColor = UIColor.black.cgColor
|
||||
view.layer.shadowRadius = 3.0
|
||||
view.layer.shadowOpacity = 1.0
|
||||
view.layer.shadowOffset = CGSize(width: offset, height: offset)
|
||||
view.layer.masksToBounds = false
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
mMaximumMemory = getAvailableMemory()
|
||||
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view.
|
||||
|
||||
self.toastLabel.isHidden = true
|
||||
session.delegate = self
|
||||
|
||||
addShadow(stopButton)
|
||||
addShadow(recordButton)
|
||||
addShadow(menuButton)
|
||||
addShadow(viewButton)
|
||||
addShadow(newScanButtonLarge)
|
||||
addShadow(libraryButton)
|
||||
addShadow(closeVisualizationButton)
|
||||
addShadow(stopCameraButton)
|
||||
addShadow(exportOBJPLYButton)
|
||||
|
||||
addShadow(statusLabel, 0)
|
||||
addShadow(toastLabel, 0)
|
||||
|
||||
addShadow(orthoDistanceSlider, 0)
|
||||
addShadow(orthoGridSlider, 0)
|
||||
|
||||
depthSupported = ARWorldTrackingConfiguration.supportsFrameSemantics(.sceneDepth)
|
||||
|
||||
rtabmap = RTABMap()
|
||||
@@ -236,6 +268,20 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
self.updateState(state: self.mState)
|
||||
}
|
||||
}
|
||||
|
||||
func progressStatusUpdate() {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
||||
if self.mState == .STATE_PROCESSING && self.statusShown
|
||||
{
|
||||
let availableMem = self.getAvailableMemory()
|
||||
let usedMem = self.mMaximumMemory - availableMem;
|
||||
self.statusLabel.text =
|
||||
"Status: \(self.getStateString(state: self.mState))\n" +
|
||||
"RAM Usage (MB): \(usedMem) / \(self.mMaximumMemory)"
|
||||
self.progressStatusUpdate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func progressUpdated(_ rtabmap: RTABMap, count: Int, max: Int) {
|
||||
DispatchQueue.main.async {
|
||||
@@ -280,10 +326,11 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
self.showToast(message: "Optimized mesh detected in the database, it is shown while the database is loading...", seconds: 3)
|
||||
}
|
||||
|
||||
let usedMem = self.getMemoryUsage()
|
||||
let availableMem = self.getAvailableMemory()
|
||||
let usedMem = self.mMaximumMemory - availableMem;
|
||||
self.statusLabel.text =
|
||||
"Status: " + (status == 1 && msg.isEmpty ? self.mState == State.STATE_CAMERA ? "Camera Preview" : "Idle" : msg) + "\n" +
|
||||
"Memory Usage: \(usedMem) MB"
|
||||
"RAM Usage (MB): \(usedMem) / \(self.mMaximumMemory)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +363,8 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
pitch: Float,
|
||||
yaw: Float)
|
||||
{
|
||||
let usedMem = self.getMemoryUsage()
|
||||
let availableMem = self.getAvailableMemory()
|
||||
let usedMem = self.mMaximumMemory - availableMem;
|
||||
|
||||
if(loopClosureId > 0)
|
||||
{
|
||||
@@ -339,7 +387,7 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
self.statusLabel.text =
|
||||
self.statusLabel.text! +
|
||||
"Status: \(self.getStateString(state: self.mState))\n" +
|
||||
"Memory Usage : \(usedMem) MB"
|
||||
"RAM Usage (MB): \(usedMem) / \(self.mMaximumMemory)"
|
||||
}
|
||||
if self.debugShown {
|
||||
self.statusLabel.text =
|
||||
@@ -426,6 +474,43 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
self.showToast(message: "Landmark \(landmarkDetected) detected!", seconds: 1);
|
||||
}
|
||||
}
|
||||
if(self.mState == .STATE_MAPPING)
|
||||
{
|
||||
if(availableMem < 400)
|
||||
{
|
||||
let msg = "Scanning will be stopped because the free memory is too "
|
||||
+ "low (\(availableMem) MB). You should be able to save the database but some post-processing and exporting options may fail. "
|
||||
+ "\n\nNote that for large environments, you can save multiple databases and "
|
||||
+ "merge them with RTAB-Map Desktop version."
|
||||
let alert = UIAlertController(title: "Memory is full!", message: msg, preferredStyle: .alert)
|
||||
let alertActionYes = UIAlertAction(title: "Ok", style: .default) {
|
||||
(UIAlertAction) -> Void in
|
||||
self.stopMapping(ignoreSaving: false, offerPostProcessing: false);
|
||||
}
|
||||
alert.addAction(alertActionYes)
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
else if(!self.lowMemoryWarningShown && usedMem*3 > availableMem && !self.mDataRecording)
|
||||
{
|
||||
self.lowMemoryWarningShown = true
|
||||
let msg = "Available memory (\(availableMem) MB) should be at least 3 times the "
|
||||
+ "memory used (\(usedMem) MB) so that some post-processing and exporting options "
|
||||
+ "have enough memory to work correctly. If you just want to save the database "
|
||||
+ "after scanning, you can continue until the next warning.\n\n"
|
||||
+ "Note that showing only point clouds and/or decrease density reduce memory needed for rendering."
|
||||
let alert = UIAlertController(title: "Memory is full!", message: msg, preferredStyle: .alert)
|
||||
let alertActionYes = UIAlertAction(title: "Stop Now", style: .default) {
|
||||
(UIAlertAction) -> Void in
|
||||
self.stopMapping(ignoreSaving: false);
|
||||
}
|
||||
alert.addAction(alertActionYes)
|
||||
let alertActionNo = UIAlertAction(title: "Continue", style: .cancel) {
|
||||
(UIAlertAction) -> Void in
|
||||
}
|
||||
alert.addAction(alertActionNo)
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,23 +524,8 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
}
|
||||
}
|
||||
|
||||
func getMemoryUsage() -> UInt64 {
|
||||
var taskInfo = mach_task_basic_info()
|
||||
var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size)/4
|
||||
let kerr: kern_return_t = withUnsafeMutablePointer(to: &taskInfo) {
|
||||
$0.withMemoryRebound(to: integer_t.self, capacity: 1) {
|
||||
task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), $0, &count)
|
||||
}
|
||||
}
|
||||
|
||||
if kerr == KERN_SUCCESS {
|
||||
return taskInfo.resident_size / (1024*1024)
|
||||
}
|
||||
else {
|
||||
print("Error with task_info(): " +
|
||||
(String(cString: mach_error_string(kerr), encoding: String.Encoding.ascii) ?? "unknown error"))
|
||||
return 0
|
||||
}
|
||||
func getAvailableMemory() -> Int {
|
||||
return os_proc_available_memory()/(1024*1024)
|
||||
}
|
||||
|
||||
@objc func appMovedToBackground() {
|
||||
@@ -1750,6 +1820,8 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
self.progressView!.tintColor = self.view.tintColor
|
||||
alertView.view.addSubview(self.progressView!)
|
||||
|
||||
self.progressStatusUpdate() // This will update memory usage during post processing
|
||||
|
||||
var success : Bool = false
|
||||
DispatchQueue.background(background: {
|
||||
|
||||
@@ -1856,6 +1928,8 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
self.progressView!.tintColor = self.view.tintColor
|
||||
alertView.view.addSubview(self.progressView!)
|
||||
|
||||
self.progressStatusUpdate() // This will update memory usage during post processing
|
||||
|
||||
var loopDetected : Int = -1
|
||||
DispatchQueue.background(background: {
|
||||
loopDetected = self.rtabmap!.postProcessing(approach: approach);
|
||||
@@ -1898,7 +1972,7 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
})
|
||||
}
|
||||
|
||||
func stopMapping(ignoreSaving: Bool)
|
||||
func stopMapping(ignoreSaving: Bool, offerPostProcessing: Bool = true)
|
||||
{
|
||||
session.pause()
|
||||
locationManager?.stopUpdatingLocation()
|
||||
@@ -1917,7 +1991,7 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
|
||||
if !ignoreSaving
|
||||
{
|
||||
if(mDataRecording)
|
||||
if(mDataRecording || !offerPostProcessing)
|
||||
{
|
||||
// Go directly to save
|
||||
self.save()
|
||||
@@ -2313,6 +2387,7 @@ class ViewController: GLKViewController, ARSessionDelegate, RTABMapObserver, UIP
|
||||
|
||||
@IBAction func recordAction(_ sender: UIButton) {
|
||||
rtabmap?.setPausedMapping(paused: false);
|
||||
lowMemoryWarningShown = false
|
||||
updateState(state: .STATE_MAPPING)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user