Initial commit
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2016 The Cartographer Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using CartographerSharp.Sensor;
|
||||
using CartographerSharp.Transform;
|
||||
using RobotNet10.Shared.Numbers;
|
||||
|
||||
namespace CartographerSharp.Mapping.D3D;
|
||||
|
||||
/// <summary>
|
||||
/// Options for 3D submaps.
|
||||
/// </summary>
|
||||
public struct SubmapsOptions3D(
|
||||
double highResolution,
|
||||
double highResolutionMaxRange,
|
||||
double lowResolution,
|
||||
int numRangeData,
|
||||
RangeDataInserterOptions3D rangeDataInserterOptions)
|
||||
{
|
||||
public double HighResolution { get; set; } = highResolution;
|
||||
public double HighResolutionMaxRange { get; set; } = highResolutionMaxRange;
|
||||
public double LowResolution { get; set; } = lowResolution;
|
||||
public int NumRangeData { get; set; } = numRangeData;
|
||||
public RangeDataInserterOptions3D RangeDataInserterOptions { get; set; } = rangeDataInserterOptions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The first active submap will be created on the insertion of the first range
|
||||
/// data. Except during this initialization when no or only one single submap
|
||||
/// exists, there are always two submaps into which range data is inserted: an
|
||||
/// old submap that is used for matching, and a new one, which will be used for
|
||||
/// matching next, that is being initialized.
|
||||
///
|
||||
/// Once a certain number of range data have been inserted, the new submap is
|
||||
/// considered initialized: the old submap is no longer changed, the "new" submap
|
||||
/// is now the "old" submap and is used for scan-to-map matching. Moreover, a
|
||||
/// "new" submap gets created. The "old" submap is forgotten by this object.
|
||||
/// </summary>
|
||||
public class ActiveSubmaps3D
|
||||
{
|
||||
private readonly SubmapsOptions3D _options;
|
||||
private readonly List<Submap3D> _submaps = [];
|
||||
private readonly RangeDataInserter3D _rangeDataInserter;
|
||||
|
||||
public ActiveSubmaps3D(SubmapsOptions3D options)
|
||||
{
|
||||
if (options.NumRangeData <= 0)
|
||||
{
|
||||
throw new ArgumentException("num_range_data must be greater than 0", nameof(options));
|
||||
}
|
||||
|
||||
_options = options;
|
||||
_rangeDataInserter = new RangeDataInserter3D(options.RangeDataInserterOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts 'range_data_in_local' into the Submap collection.
|
||||
/// 'local_from_gravity_aligned' is used for the orientation of new submaps so
|
||||
/// that the z axis approximately aligns with gravity.
|
||||
/// 'rotational_scan_matcher_histogram_in_gravity' will be accumulated in all
|
||||
/// submaps of the Submap collection.
|
||||
/// </summary>
|
||||
public List<Submap3D> InsertData(
|
||||
RangeData rangeDataInLocal,
|
||||
Quaternion localFromGravityAligned,
|
||||
List<double> rotationalScanMatcherHistogramInGravity)
|
||||
{
|
||||
// Create new submap if needed
|
||||
if (_submaps.Count == 0 ||
|
||||
_submaps[^1].NumRangeData == _options.NumRangeData)
|
||||
{
|
||||
var localSubmapPose = new Rigid3d(
|
||||
(Vector3)rangeDataInLocal.Origin,
|
||||
localFromGravityAligned);
|
||||
AddSubmap(localSubmapPose, rotationalScanMatcherHistogramInGravity.Count);
|
||||
}
|
||||
|
||||
// Insert into all active submaps
|
||||
foreach (var submap in _submaps)
|
||||
{
|
||||
submap.InsertData(
|
||||
rangeDataInLocal,
|
||||
_rangeDataInserter,
|
||||
_options.HighResolutionMaxRange,
|
||||
localFromGravityAligned,
|
||||
rotationalScanMatcherHistogramInGravity);
|
||||
}
|
||||
|
||||
// Finish the first submap if it has reached 2 * num_range_data
|
||||
if (_submaps.Count > 0 && _submaps[0].NumRangeData == 2 * _options.NumRangeData)
|
||||
{
|
||||
_submaps[0].Finish();
|
||||
}
|
||||
|
||||
return [.. _submaps];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current active submaps.
|
||||
/// </summary>
|
||||
public List<Submap3D> Submaps()
|
||||
{
|
||||
return [.. _submaps];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new submap to the collection.
|
||||
/// </summary>
|
||||
private void AddSubmap(Rigid3d localSubmapPose, int rotationalScanMatcherHistogramSize)
|
||||
{
|
||||
if (_submaps.Count >= 2)
|
||||
{
|
||||
// This will crop the finished Submap before inserting a new Submap to
|
||||
// reduce peak memory usage a bit.
|
||||
if (!_submaps[0].InsertionFinished)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"First submap must be finished before adding a new one");
|
||||
}
|
||||
|
||||
// We use `ForgetIntensityHybridGrid` to reduce memory usage. Since we use
|
||||
// active submaps and their associated intensity hybrid grids for scan
|
||||
// matching, we call `ForgetIntensityHybridGrid` once we remove the submap
|
||||
// from active submaps and no longer need the intensity hybrid grid.
|
||||
_submaps[0].ForgetIntensityHybridGrid();
|
||||
_submaps.RemoveAt(0);
|
||||
}
|
||||
|
||||
var initialRotationalScanMatcherHistogram = new List<double>(rotationalScanMatcherHistogramSize);
|
||||
for (int i = 0; i < rotationalScanMatcherHistogramSize; i++)
|
||||
{
|
||||
initialRotationalScanMatcherHistogram.Add(0.0);
|
||||
}
|
||||
|
||||
var submap = new Submap3D(
|
||||
_options.HighResolution,
|
||||
_options.LowResolution,
|
||||
localSubmapPose,
|
||||
initialRotationalScanMatcherHistogram);
|
||||
|
||||
_submaps.Add(submap);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user