add altitude + camera spec component and calc tile size by this

also restrict detections to be no bigger than in classes.json
This commit is contained in:
Oleksandr Bezdieniezhnykh
2025-09-23 01:48:10 +03:00
parent b0e4b467c1
commit fde9a9f418
36 changed files with 715 additions and 222 deletions
@@ -0,0 +1,71 @@
<UserControl x:Class="Azaion.Common.Controls.CameraConfigControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:cfg="clr-namespace:Azaion.Common.DTO.Config"
xmlns:controls="clr-namespace:Azaion.Common.Controls"
mc:Ignorable="d"
d:DesignHeight="120" d:DesignWidth="360">
<Grid Margin="4" Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65"/>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="70"/>
</Grid.ColumnDefinitions>
<!-- Altitude -->
<TextBlock Grid.Row="0" Grid.Column="0"
Foreground="LightGray"
VerticalAlignment="Center" Margin="0,0,8,0" Text="Altitude, m:"/>
<Slider x:Name="AltitudeSlider" Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2"
Minimum="0" Maximum="10000" TickFrequency="100"
IsSnapToTickEnabled="False"
Value="{Binding Camera.Altitude, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<controls:NumericUpDown x:Name="AltitudeNud"
Grid.Row="0" Grid.Column="3"
VerticalAlignment="Center"
MinValue="50"
MaxValue="5000"
Value="{Binding Camera.Altitude, RelativeSource={RelativeSource AncestorType=UserControl},
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Step="10">
</controls:NumericUpDown>
<!-- Focal length -->
<TextBlock
Foreground="LightGray"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
VerticalAlignment="Center"
Margin="0,8,8,0" Text="Focal length, mm:"/>
<controls:NumericUpDown x:Name="FocalNud"
Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2"
MinValue="0.1"
MaxValue="100"
Step="0.05"
VerticalAlignment="Center"
Value="{Binding Camera.CameraFocalLength, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</controls:NumericUpDown>
<!-- Sensor width -->
<TextBlock Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
VerticalAlignment="Center"
Foreground="LightGray"
Margin="0,8,8,0" Text="Sensor width, mm:"/>
<controls:NumericUpDown x:Name="SensorNud"
Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2" Step="0.05"
VerticalAlignment="Center"
MinValue="0.1"
MaxValue="100"
Value="{Binding Camera.CameraSensorWidth, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</controls:NumericUpDown>
</Grid>
</UserControl>
@@ -0,0 +1,56 @@
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Azaion.Common.DTO.Config;
namespace Azaion.Common.Controls;
public partial class CameraConfigControl
{
public static readonly DependencyProperty CameraProperty = DependencyProperty.Register(
nameof(Camera), typeof(CameraConfig), typeof(CameraConfigControl),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public CameraConfig Camera
{
get => (CameraConfig)GetValue(CameraProperty) ?? new CameraConfig();
set => SetValue(CameraProperty, value);
}
// Fires whenever any camera parameter value changes in UI
public event EventHandler? CameraChanged;
public CameraConfigControl()
{
InitializeComponent();
DataContext = this;
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
// Hook up change notifications
if (AltitudeSlider != null)
AltitudeSlider.ValueChanged += (_, __) => CameraChanged?.Invoke(this, EventArgs.Empty);
SubscribeNud(AltitudeNud);
SubscribeNud(FocalNud);
SubscribeNud(SensorNud);
}
private void SubscribeNud(UserControl? nud)
{
if (nud is NumericUpDown num)
{
var dpd = DependencyPropertyDescriptor.FromProperty(NumericUpDown.ValueProperty, typeof(NumericUpDown));
dpd?.AddValueChanged(num, (_, __) => CameraChanged?.Invoke(this, EventArgs.Empty));
}
}
// Initializes the control with the provided CameraConfig instance and wires two-way binding via dependency property
public void Init(CameraConfig cameraConfig)
{
Camera = cameraConfig;
}
}
+47
View File
@@ -0,0 +1,47 @@
<UserControl x:Class="Azaion.Common.Controls.NumericUpDown"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Azaion.Common.Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Background="DimGray">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="24" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="12" />
<RowDefinition Height="12" />
</Grid.RowDefinitions>
<TextBox Name="NudTextBox"
Background="DimGray"
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
TextAlignment="Right"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type local:NumericUpDown}}}"
TextChanged="NUDTextBox_OnTextChanged"/>
<RepeatButton
Name="NudButtonUp"
Grid.Column="1"
Grid.Row="0"
FontSize="10"
VerticalAlignment="Center"
HorizontalContentAlignment="Center"
Click="NudButtonUp_OnClick"
>^</RepeatButton>
<RepeatButton
Name="NudButtonDown"
Grid.Column="1"
Grid.Row="1"
FontSize="10"
VerticalAlignment="Center"
HorizontalContentAlignment="Center"
Click="NudButtonDown_OnClick"
>˅</RepeatButton>
</Grid>
</UserControl>
@@ -0,0 +1,101 @@
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
namespace Azaion.Common.Controls;
public partial class NumericUpDown : UserControl
{
public static readonly DependencyProperty MinValueProperty = DependencyProperty.Register(
nameof(MinValue), typeof(decimal), typeof(NumericUpDown), new PropertyMetadata(0m));
public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register(
nameof(MaxValue), typeof(decimal), typeof(NumericUpDown), new PropertyMetadata(100m));
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
nameof(Value), typeof(decimal), typeof(NumericUpDown), new PropertyMetadata(10m, OnValueChanged));
public static readonly DependencyProperty StepProperty = DependencyProperty.Register(
nameof(Step), typeof(decimal), typeof(NumericUpDown), new PropertyMetadata(1m));
public decimal MinValue
{
get => (decimal)GetValue(MinValueProperty);
set => SetValue(MinValueProperty, value);
}
public decimal MaxValue
{
get => (decimal)GetValue(MaxValueProperty);
set => SetValue(MaxValueProperty, value);
}
public decimal Value
{
get => (decimal)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public decimal Step
{
get => (decimal)GetValue(StepProperty);
set => SetValue(StepProperty, value);
}
public NumericUpDown()
{
InitializeComponent();
}
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is NumericUpDown control)
{
control.NudTextBox.Text = ((decimal)e.NewValue).ToString(CultureInfo.InvariantCulture);
control.NudTextBox.SelectionStart = control.NudTextBox.Text.Length;
}
}
private void NUDTextBox_OnTextChanged(object sender, TextChangedEventArgs e)
{
if (string.IsNullOrEmpty(NudTextBox.Text) || !decimal.TryParse(NudTextBox.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out var number))
{
NudTextBox.Text = Value.ToString(CultureInfo.InvariantCulture);
return;
}
if (number > MaxValue )
{
Value = MaxValue;
NudTextBox.Text = MaxValue.ToString(CultureInfo.InvariantCulture);
}
else if (number < MinValue)
{
Value = MinValue;
NudTextBox.Text = Value.ToString(CultureInfo.InvariantCulture);
}
else
{
Value = number;
}
NudTextBox.SelectionStart = NudTextBox.Text.Length;
}
private void NudButtonUp_OnClick(object sender, RoutedEventArgs e)
{
var step = Step <= 0 ? 1m : Step;
var newVal = Math.Min(MaxValue, Value + step);
Value = newVal;
NudTextBox.Text = Value.ToString(CultureInfo.InvariantCulture);
NudTextBox.SelectionStart = NudTextBox.Text.Length;
}
private void NudButtonDown_OnClick(object sender, RoutedEventArgs e)
{
var step = Step <= 0 ? 1m : Step;
var newVal = Math.Max(MinValue, Value - step);
Value = newVal;
NudTextBox.Text = Value.ToString(CultureInfo.InvariantCulture);
NudTextBox.SelectionStart = NudTextBox.Text.Length;
}
}