C# :: Aufgabe #176 :: Lösung #1
3 Lösungen

#176
Konvexe Hüllkurve um Punktwolke
Fortgeschrittener - C#
von hollst
- 04.05.2017 um 10:36 Uhr
In der X-Y-Ebene seinen N Punkte zufällig verteilt (Bild 1). Man schreibe ein Programm, das die konvexe Hüllkurve um diese Punktwolke zeichnet (Bild 2).
Zum Verständnid, was die konvexe Hüllkurve um eine Punktwolke ist, stelle man sich die Punkte als fixierte Push-Pins oder Nägel auf einem Pinbord (möglichst nicht aus Kork) oder Holzbrett vor. Jetzt nehme man einen Gummiring (z. B. vom Einweckglas) und spanne diesen so um die Pins, dass sich alle im „Inneren“ des Gummiringes befinden (eine „360-Grad-Umwicklung“ eines Pins ist nicht erlaibt). Der so verformte Gummiring ergibt aus physikalischen Gründen einen geschlossenen Linienzug. Dieser Linienzug wird konvexe Hüllkurve um die Punktwolke genannt.
Zum Verständnid, was die konvexe Hüllkurve um eine Punktwolke ist, stelle man sich die Punkte als fixierte Push-Pins oder Nägel auf einem Pinbord (möglichst nicht aus Kork) oder Holzbrett vor. Jetzt nehme man einen Gummiring (z. B. vom Einweckglas) und spanne diesen so um die Pins, dass sich alle im „Inneren“ des Gummiringes befinden (eine „360-Grad-Umwicklung“ eines Pins ist nicht erlaibt). Der so verformte Gummiring ergibt aus physikalischen Gründen einen geschlossenen Linienzug. Dieser Linienzug wird konvexe Hüllkurve um die Punktwolke genannt.
#1

von daniel59 (4260 Punkte)
- 05.05.2017 um 15:47 Uhr
MainWindow.xaml.cs
C#-Code
MainWindow.xaml
XML-Code

using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes; namespace WpfKonvexeHuellkurve { /// <summary> /// Interaktionslogik für MainWindow.xaml /// </summary> public partial class MainWindow : Window { private static readonly Random rnd = new Random(); private List<Point> points; const int size = 6; const int padding = 20; private readonly Brush brush = Brushes.Blue; public MainWindow() { InitializeComponent(); } private void DrawRandomPoints(int n) { points = new List<Point>(); listBoxPoints.Items.Clear(); canvasDraw.Children.Clear(); canvasDraw.UpdateLayout(); int width = (int)canvasDraw.ActualWidth; int height = (int)canvasDraw.ActualHeight; for (int i = 0; i < n; i++) { int x = rnd.Next(padding, width - padding); int y = rnd.Next(padding, height - padding); points.Add(new Point(x, y)); Ellipse ell = new Ellipse() { Width = size, Height = size, Stroke = brush, StrokeThickness = double.Epsilon, Fill = brush }; Canvas.SetLeft(ell, x - size / 2); Canvas.SetTop(ell, y - size / 2); canvasDraw.Children.Add(ell); listBoxPoints.Items.Add($"X: {x} | Y: {y}"); } } private void buttonDrawRandom_Click(object sender, RoutedEventArgs e) { int n; if (int.TryParse(textBoxNumber.Text, out n)) { if (n >= 3) { DrawRandomPoints(n); } } } private void DrawConvexLine() { PointCollection points = new PointCollection(GetPoints().Distinct()); Polygon convex = new Polygon() { Points = points, Stroke = Brushes.Red, StrokeThickness = 2 }; canvasDraw.Children.Add(convex); } private IEnumerable<Point> GetPoints() { var westernmost = points.Where(b => b.X == points.Min(a => a.X)).OrderByDescending(a => a.Y); var northernmost = points.Where(b => b.Y == points.Min(a => a.Y)).OrderBy(a => a.X); var easternmost = points.Where(b => b.X == points.Max(a => a.X)).OrderBy(a => a.Y); var southernmost = points.Where(b => b.Y == points.Max(a => a.Y)).OrderByDescending(a => a.X); Point west = westernmost.First(); Point north = northernmost.First(); Point east = easternmost.First(); Point south = southernmost.First(); Point start = new Point(west.X, west.Y); foreach (var point in westernmost) { west = point; yield return west; } while (west != north) { west = GetNextPointWest(west); yield return west; } foreach (var point in northernmost) { north = point; yield return north; } while (north != east) { north = GetNextPointNorth(north); yield return north; } foreach (var point in easternmost) { east = point; yield return east; } while (east != south) { east = GetNextPointEast(east); yield return east; } foreach (var point in southernmost) { south = point; yield return south; } while (south != start) { south = GetNextPointSouth(south); yield return south; } } private Point GetNextPointWest(Point west) { var northern = points.Where(p => p.X > west.X && p.Y < west.Y); foreach (Point p in northern) { Vector r = p - west; Vector s = new Vector(west.X, west.Y); double m = r.Y / r.X; double c = west.Y - (m * west.X); if (!northern.Any(a => Math.Round((a.X * m + c)) > a.Y)) { return p; } } return default(Point); } private Point GetNextPointNorth(Point north) { var eastern = points.Where(p => p.Y > north.Y && p.X > north.X); foreach (Point p in eastern) { Vector r = p - north; Vector s = new Vector(north.X, north.Y); double m = r.Y / r.X; double c = north.Y - (m * north.X); if (!eastern.Any(a => Math.Round((a.X * m + c)) > a.Y)) { return p; } } return default(Point); } private Point GetNextPointEast(Point east) { var southern = points.Where(p => p.X < east.X && p.Y > east.Y); foreach (Point p in southern) { Vector r = p - east; Vector s = new Vector(east.X, east.Y); double m = r.Y / r.X; double c = east.Y - (m * east.X); if (!southern.Any(a => Math.Round((a.X * m + c)) < a.Y)) { return p; } } return default(Point); } private Point GetNextPointSouth(Point south) { var western = points.Where(p => p.Y < south.Y && p.X < south.X); foreach (Point p in western) { Vector r = p - south; Vector s = new Vector(south.X, south.Y); double m = r.Y / r.X; double c = south.Y - (m * south.X); if (!western.Any(a => Math.Round((a.X * m + c)) < a.Y)) { return p; } } return default(Point); } private void buttonDrawConvex_Click(object sender, RoutedEventArgs e) { DrawConvexLine(); } } }
MainWindow.xaml

<Window x:Class="WpfKonvexeHuellkurve.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfKonvexeHuellkurve" mc:Ignorable="d" Title="MainWindow" Height="610" Width="755" ResizeMode="CanMinimize"> <Grid> <Border BorderBrush="Black" BorderThickness="2" Width="504" Height="504" Margin="10,10,0,0" HorizontalAlignment="Left" VerticalAlignment="Top"> <Canvas x:Name="canvasDraw" Background="#FF08F48E" Width="500" Height="500" Margin="0"/> </Border> <ListBox x:Name="listBoxPoints" Width="218" Height="504" Margin="519,10,0,0" HorizontalAlignment="Left" VerticalAlignment="Top"/> <Button x:Name="buttonDrawRandom" Content="Zufällige Punkte zeichnen" HorizontalAlignment="Left" Margin="10,548,0,0" VerticalAlignment="Top" Width="161" Click="buttonDrawRandom_Click"/> <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="10,522,0,0" TextWrapping="Wrap" Text="Anzahl" VerticalAlignment="Top"/> <TextBox x:Name="textBoxNumber" HorizontalAlignment="Left" Height="24" Margin="51,519,0,0" TextWrapping="Wrap" Text="20" VerticalAlignment="Top" Width="120" TextAlignment="Center"/> <Button x:Name="buttonDrawConvex" Content="Konvexe Hüllkurve zeichnen" HorizontalAlignment="Left" Margin="176,548,0,0" VerticalAlignment="Top" Width="172" Click="buttonDrawConvex_Click"/> </Grid> </Window>
Kommentare:
Für diese Lösung gibt es noch keinen Kommentar
Seite 1 von 0
1