Changing a linked list of Ellipses to images in c# - wpf

I've made a simple snake game in c# wpf forms.The problem is that Iv'e made the food as Ellipses and I want to change that to an image of an apple.
This is the food class where I specified the type/shape of the food :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Controls;
namespace WpfApp1
{
class Food
{
public double x, y;
public Ellipse e = new Ellipse();
public Food(double x, double y)
{
this.x = x;
this.y = y;
}
public void setFoodPosition()
{
Random r = new Random();
if (Settings.size != 0)
e.Width = e.Height = Settings.g.Size;
else
e.Width = e.Height = 10;
e.Stroke = Brushes.Black;
e.Fill = new SolidColorBrush(Color.FromRgb((byte)r.Next(255), (byte)r.Next(255), (byte)r.Next(255))); ;
Canvas.SetLeft(e, x);
Canvas.SetTop(e, y);
}
}
}
does anyone have any idea how I do that?

If you have an image of an apple in an image file, you should add that file to your Visual Studio project (e.g. in a project folder named Images) and set its Build Action to Resource.
You would then load the image by a Resource File Pack URI, and use it with an ImageBrush as Fill Brush of a Rectangle:
private Rectangle rect = new Rectangle();
...
rect.Fill = new ImageBrush(
new BitmapImage(new Uri("pack://application:,,,/Images/Apple.png")));
Or you use an Image element instead of a Rectangle:
private Image image = new Image();
...
image.Source = new BitmapImage(new Uri("pack://application:,,,/Images/Apple.png"));

Change the ellipse to a rectangle with no stroke and fill it with a drawing brush that represents an apple.
Apple graphic taken from xamalot
class Food
{
public double x, y;
public Rectangle e = new Rectangle();
private SolidColorBrush brush1 = (SolidColorBrush)(new BrushConverter().ConvertFrom("#FFB5121B"));
private SolidColorBrush brush2 = (SolidColorBrush)(new BrushConverter().ConvertFrom("#FF4F6E18"));
private DrawingBrush apple;
private double size = 20.0;
public Food(double x, double y)
{
this.x = x;
this.y = y;
GeometryDrawing a1 = new GeometryDrawing(brush1, null, Geometry.Parse("F1M513.300,368.290C513.300,368.290 530.719,179.903 449.429,135.387 368.139,90.871 273.945,91.516 273.945,91.516 273.945,91.516 228.783,79.903 216.526,80.548 204.269,81.193 125.559,84.419 68.784,142.484 12.009,200.549 4.268,237.322 6.849,285.064 9.430,332.806 34.590,438.613 34.590,438.613 34.590,438.613 70.074,516.677 76.526,521.839 82.978,527.001 122.333,570.871 149.429,576.678 176.525,582.485 234.590,580.549 248.138,578.614 261.686,576.679 339.106,581.194 366.848,576.033 394.590,570.872 475.881,490.870 490.720,461.193 505.559,431.516 513.300,368.290 513.300,368.290z"));
GeometryDrawing a2 = new GeometryDrawing(brush2, null, Geometry.Parse("F1M435.881,122.484L437.171,113.452 462.332,105.710 463.623,92.807C463.623,92.807 495.881,67.000 497.171,55.388 498.461,43.776 505.559,20.549 505.559,20.549L479.107,16.033C479.107,16.033 424.269,12.807 421.688,12.807 419.107,12.807 395.881,14.742 395.881,14.742L337.171,28.936 290.720,72.807 285.559,78.613 272.656,125.710 253.946,143.129 251.365,121.839C251.365,121.839 242.978,94.097 238.462,94.097 233.946,94.097 232.655,90.871 232.655,90.871L229.429,90.871 216.526,99.258 201.687,111.516 208.139,123.129C208.139,123.129 222.977,134.097 226.203,140.548 229.429,146.999 237.171,163.774 233.945,170.225 230.719,176.676 222.332,192.161 222.332,192.161L241.041,200.548C241.041,200.548 247.492,207.645 260.395,196.677 273.298,185.709 257.169,175.387 257.169,175.387 257.169,175.387 251.362,165.710 261.040,159.903 270.718,154.096 304.267,143.774 314.589,144.419 324.911,145.064 350.718,148.290 361.040,149.580 371.362,150.870 435.881,122.484 435.881,122.484z"));
GeometryDrawing a3 = new GeometryDrawing(Brushes.Black, null, Geometry.Parse("F1M128.784,96.677C148.139,88.935 174.369,81.601 174.369,81.601 192.987,77.160 211.565,75.052 230.540,78.296 243.012,80.428 260.740,87.167 273.042,86.000 279.480,78.644 278.052,68.304 283.253,60.448 289.458,51.076 294.940,59.933 294.042,67.000 298.067,54.331 338.001,6.529 351.082,18.709 355.593,22.908 420.671,2.572 431.042,0.000 431.254,3.071 430.920,6.071 430.042,9.000 447.617,12.292 466.476,8.608 484.313,10.769 491.850,11.682 502.369,18.105 509.042,12.000 510.861,24.711 509.113,25.330 507.578,37.200 505.575,52.679 495.643,69.019 484.589,79.747 481.237,83.199 477.389,85.950 473.042,88.000 476.148,95.075 479.028,93.481 472.860,101.040 465.707,109.805 455.381,113.436 445.042,117.000 443.998,125.386 466.546,138.834 471.035,145.778 474.307,150.839 498.550,187.608 495.042,187.000 507.285,204.943 506.970,226.532 513.235,245.733 522.462,274.010 518.921,309.492 517.366,338.795 516.019,364.167 516.886,390.178 509.973,413.289 507.449,421.729 494.598,479.776 483.041,479.000 465.660,528.203 414.718,579.661 361.111,583.683 329.023,586.090 297.163,578.453 265.041,583.000 228.602,589.404 195.545,594.889 159.306,584.585 109.315,570.372 66.443,528.234 48.386,479.739 36.691,448.332 21.452,420.930 14.912,387.631 10.008,362.661 8.375,340.614 3.621,315.216 -4.386,272.435 0.070,221.175 25.211,187.212 35.862,172.824 41.077,151.323 58.022,142.155 67.303,137.134 76.285,126.810 85.433,120.915 85.434,120.915 109.429,104.419 128.784,96.677z M414.042,64.000C426.498,46.435 406.256,32.395 410.042,15.000 397.805,14.493 376.430,18.708 370.022,30.011 365.638,37.745 365.836,46.995 363.872,55.425 361.380,66.117 354.186,75.110 352.042,86.000 372.512,78.557 395.099,75.228 414.042,64.000 M424.042,44.000C426.543,35.314 430.940,27.446 434.042,19.000 426.020,18.754 420.768,21.745 414.042,16.000 411.001,25.542 419.895,36.289 424.042,44.000 M486.042,19.000C472.684,19.179 444.659,13.770 437.010,24.751 430.706,33.800 422.828,52.810 422.042,64.000 422.318,61.028 457.493,47.482 462.096,44.739 472.277,38.671 481.678,31.404 490.042,23.000 490.150,23.019 486.233,18.620 486.042,19.000 M440.042,61.000C452.222,62.766 467.215,65.806 479.105,61.050 494.224,55.002 490.026,34.660 497.042,23.000 480.410,39.150 461.330,51.814 440.042,61.000 M346.042,85.000C360.129,68.533 348.792,47.819 340.042,32.000 326.577,39.407 310.909,52.613 309.903,68.758 309.348,77.656 310.249,86.590 309.428,95.476 308.989,100.234 302.330,109.552 304.041,114.000 312.835,99.033 334.394,96.711 346.042,85.000 M350.042,44.000C354.103,48.646 353.819,55.803 357.042,61.000 359.240,51.294 361.521,41.627 364.042,32.000 357.967,34.124 352.835,38.096 350.042,44.000 M450.042,66.000C455.537,84.095 470.575,77.818 478.042,66.000 471.350,60.585 458.358,70.389 450.042,66.000 M454.042,87.000C455.526,85.148 457.193,83.482 459.042,82.000 445.923,68.860 442.985,62.996 423.392,67.247 405.870,71.048 390.012,79.535 373.042,85.000 393.934,85.236 445.185,125.197 461.042,94.000 458.086,92.294 455.752,89.961 454.042,87.000 M298.042,84.000C301.484,86.409 303.150,89.742 303.042,94.000 309.970,90.194 305.458,75.576 304.042,70.000 300.866,74.154 298.866,78.820 298.042,84.000 M253.042,167.000C255.620,156.719 277.769,140.995 285.505,133.386 289.170,129.709 292.900,126.098 296.694,122.554 305.692,114.337 297.166,117.338 300.555,108.030 304.820,96.323 297.702,85.367 288.041,77.999 283.160,91.979 279.528,106.245 277.362,120.899 275.648,132.500 271.666,134.028 266.362,143.800 266.022,144.426 255.032,154.911 255.041,154.999 242.339,144.154 252.806,121.622 241.041,108.999 239.498,119.949 235.243,128.783 223.041,129.999 230.159,139.753 239.442,156.768 237.195,169.056 236.041,175.365 232.919,181.129 231.137,187.251 228.116,197.635 243.199,198.698 251.041,201.000 255.475,189.287 250.187,178.388 253.042,167.000 M265.042,118.000C269.094,104.222 280.259,94.104 259.664,90.569 244.997,88.051 225.689,88.648 211.924,83.869 203.397,80.909 180.969,88.489 172.042,91.000 151.675,96.730 132.840,106.511 114.042,116.000 59.130,143.718 15.553,199.202 11.810,265.090 10.780,283.229 37.230,442.912 46.748,450.542 46.493,450.617 75.058,505.521 78.999,511.549 98.081,540.728 124.864,561.761 154.786,573.244 185.512,585.036 222.415,572.249 254.209,572.179 287.252,572.107 323.348,579.623 356.163,572.754 409.424,561.606 459.076,499.925 483.924,454.159 499.973,424.601 504.615,389.266 506.601,355.349 508.976,314.777 510.741,268.100 499.309,229.172 491.641,203.060 484.325,173.871 465.068,153.539 457.862,145.930 445.945,137.601 436.101,134.470 422.571,130.166 410.572,144.028 396.597,144.031 392.777,144.031 382.531,152.867 374.192,153.647 361.430,154.841 348.647,152.575 336.316,149.477 312.818,143.572 284.786,153.807 265.044,167.000 265.087,170.391 260.293,187.917 269.044,185.000 277.091,182.317 285.950,184.333 294.044,182.000 305.589,178.673 322.379,168.044 330.044,177.000 312.169,181.677 292.999,183.728 276.811,193.246 257.709,204.477 252.581,208.797 233.053,198.284 224.684,193.779 215.928,191.070 205.814,188.840 194.013,186.238 162.420,187.285 154.045,179.000 166.925,178.886 189.962,181.909 199.045,184.000 234.266,192.062 241.788,151.281 216.045,133.000 209.051,128.034 205.179,127.053 200.594,118.534 192.155,102.850 209.268,103.866 218.033,96.492 245.519,73.367 251.513,109.054 258.045,130.001 267.876,129.306 263.289,123.961 265.042,118.000 M404.042,131.000C417.720,127.298 408.380,124.138 401.849,117.237 391.482,106.280 391.701,92.772 373.814,89.802 361.629,87.780 348.714,90.862 337.491,95.545 332.421,97.660 308.279,109.915 310.043,117.001 320.520,113.944 337.908,121.959 347.446,126.279 362.393,133.047 385.319,136.065 404.042,131.000 M231.042,91.000C225.165,95.639 189.601,111.553 209.254,117.255 227.381,122.514 245.094,103.026 231.042,91.000 M424.042,121.000C420.158,119.020 416.825,116.353 414.042,113.000 419.381,110.729 427.969,113.629 431.042,107.000 418.474,105.041 407.407,98.614 395.042,96.000 398.688,106.570 409.105,129.552 424.042,121.000 M216.042,124.000C221.159,124.441 233.190,128.531 232.042,118.000 229.843,121.464 215.554,118.883 216.042,124.000z M289.042,140.000C309.452,138.049 328.829,142.222 349.042,141.000 339.229,118.123 296.925,112.520 289.042,140.000 M364.042,142.000C366.373,146.741 373.152,140.349 375.042,139.000 365.356,138.139 356.896,132.194 347.042,132.000 348.719,138.333 357.071,149.190 364.042,142.000"));
DrawingGroup innerGroup = new DrawingGroup();
innerGroup.Children.Add(a3);
DrawingGroup outerGroup = new DrawingGroup();
outerGroup.Children.Add(a1);
outerGroup.Children.Add(a2);
outerGroup.Children.Add(innerGroup);
apple = new DrawingBrush();
apple.Drawing = outerGroup;
}
public void SetFoodPosition()
{
Random r = new Random();
if (size != 0)
e.Width = e.Height = size;
else
e.Width = e.Height = 10;
//e.Stroke = Brushes.Black;
e.Fill = apple;// new SolidColorBrush(Color.FromRgb((byte)r.Next(255), (byte)r.Next(255), (byte)r.Next(255))); ;
Canvas.SetLeft(e, x);
Canvas.SetTop(e, y);
}
}

Related

WPF Including Tooltip in Render with RenderTargetBitmap

I've searched and searched but haven't been able to find anything with the same problem as me. I'm trying to render some high resolution/dpi screenshots of a WPF application. Only problem is that I need to include information from chart tooltips in the render, other than that I can save screenshots just fine.
I'm currently using Infragistics XamDataChart and I generate the tooltips in code rather xaml.
Anyone have a clue how to get the tooltip in the visual tree so it renders? Or to be able to render the whole window and everything inside of it including tooltip overlays?
Code for the render:
public static void RenderVisualToFile(this FrameworkElement visual)
{
var width = (int)visual.RenderSize.Width;
var height = (int)visual.RenderSize.Height;
RenderTargetBitmap renderTarget = new RenderTargetBitmap(width * 4, height * 4, 384, 384, PixelFormats.Pbgra32);
renderTarget.Render(visual);
// Encode and save to PNG file
var enc = new PngBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(renderTarget));
if (Directory.Exists("Screenshots"))
{
using (var stm = File.Create(#"Screenshots\Render_" + DateTime.Now.ToString("yyMMMdd_HHmmss") + ".png"))
enc.Save(stm);
}
else
{
Directory.CreateDirectory("Screenshots");
using (var stm = File.Create(#"Screenshots\Render_" + DateTime.Now.ToString("yyMMMdd_HHmmss") + ".png"))
enc.Save(stm);
}
}
And I call this in the MainWindow code behind.
if (e.Key == Key.PrintScreen)
{
this.RenderVisualToFile();
}
It is a bit late but maybe someone can use my solution.
My Screenshot class is based on the following solutions:
The creation of the screenshots is based on a post on the QMINO technical blog High Res Screenshots
To get the currently opened ToolTips I use the code fragment posted here: Find all opened Popups in WPF application
It took me a while to find a solution on how to merge the UIElement for the screenshot with the PopUps but a comment of Clemens gave the final clue Overlay Images with PngBitmapEncoder in WPF
I use tuples to to return multiple parameters C# 7.0 Tuples.
So here is my class:
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
public class Screenshot
{
//UIElement to create screenshot
private UIElement _element;
//Bounds for the screenshot
private Rect _screenshotBounds;
//Path for Screenshot
private string _path;
private const int DPI = 384;
private const double BASEDPI = 96;
private const double DPISCALE = DPI / BASISDPI;
public Screenshot(UIElement element, string path)
{
this._element = element;
this._screenshotBounds = this.createBounds(this._element);
this._path = path;
}
//public interface to create the screenshot
public void createScreenshot()
{
if (this._element == null)
{
return;
}
//Create a list of tuples with the elements to render in the screenshot
List<(UIElement, Rect, Point)> listElements = new List<(UIElement, Rect, Point)>
{
//Fist element in the list should be the actual UIElement
this.createElementBoundPosition(this._element);
};
RenderTargetBitmap renderBitMap = this.createBitMap(this._screenshotBounds);
//Get the opened Popups, create a list of tuples for the Popups and add them to the list of elements to render
listElements.AddRange(this.createListPopUpBoundsPosition( this.getOpenPopups()));
DrawingVisual drawingVisual = this.createDrawingVisual(listElements);
renderBitMap.Render(drawingVisual);
this.saveRTBAsPNG(renderBitMap);
}
//Create DrawingVisual based on List of Tuples
private DrawingVisual createDrawingVisual(List<(UIElement, Rect, Point)> listElements)
{
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext context = drawingVisual.RenderOpen())
{
foreach((UIElement element, Rect bounds, Point position) in listElements)
{
VisualBrush visualBrush = new VisualBrush(element);
context.DrawRectangle(visualBrush, null, new Rect(position, bounds.Size));
}
}
return drawingVisual;
}
//Save RenderTargetBitmap to file
private void saveRTBAsPNG(RenderTargetBitmap bitmap)
{
PngBitmapEncoder pngBitmapEncoder = new PngBitmapEncoder()
{
Interlace = PngInterlaceOption.On
}
pngBitmapEncoder.Frames.Add(BitmapFrame.Create(bitmap));
using (FileStream fileStream = File.Create(this._path))
{
pngBitmapEncoder.Save(fileStream);
}
}
//Create Bounds for Element
private Rect createBounds(UIElement element)
{
new Rect(new Size((int)element.RenderSize.Width, (int)element.RenderSize.Height));
}
//Create a Tuple with the Element, its bounds and its position
private (UIElement element, Rect bounds, Point position) createElementBoundPosition(UIElement element)
{
return (element, this.createBounds(element), element.PointToScreen(new Point(0,0)));
}
//create the RenderTargetBitmap
private RenderTargetBitmap createBitMap(Rect bounds)
{
(int width, int height) calculatedBounds = this.calculateBounds(bounds);
return new RenderTargetBitmap(calculatedBounds.width, calculatedBounds.height, DPI, DPI, PixelFormats.Pbgra32);
}
//recalculate bounds according to the scale
private (int width, int heigth) calculateBounds(Rect bounds)
{
int width = (int)(bounds.Width * DPISCALE);
int height = (int)(bounds.Height * DPISCALE);
return (width, height);
}
//Convert the list of Popups into a List of Tuples
private List<(UIElement element, Rect bounds, Point position)> createListPopUpBoundsPosition(List<Popup> listPopup)
{
List<(UIElement, Rect, Point)> list = new List<(UIElement, Rect, Point)>();
foreach (Popup p in listPopup)
{
//The Child-Element contains the UIElement to render
UIElement uiElement = p.Child;
list.Add(this.createElementBoundPosition(uiElement));
}
return list;
}
//get the open Popups
private List<Popup> getOpenPopups()
{
return PresentationSource.CurrentSources.OfType<HwndSource>()
.Select(h => h.RootVisual)
.OfType<FrameworkElement>()
.Select(f => f.Parent)
.OfType<Popup>()
.Where(p => p.IsOpen).ToList();
}
}

Matrix animation error. in WPF in code behind

I making animation.
Draw a path with use a ArcSegment.
And moves along to the path.
However, different from startingpoint of animation and startingpoint of path.
What should modify?
this image .. Immediately after the starting the animation.
Circle location is in the middle of the Path.
I Want to help me. please...
animation part. source code
i create demo version.
my source code written in korean. so create demo version
If you continue to click the second button.
Different starting point of the path and starting point Of a circle.
If there are other methods that may be.
It does not matter all when you change the source.
This is just to succeed. We look forward to good results.
You are a really good person. thank you
xaml
<Window x:Class="WpfApplication7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="400" Width="830">
<Grid>
<Button x:Name="num_bt" Content="1.create number" HorizontalAlignment="Left" VerticalAlignment="Top" Width="118" Click="num_bt_Click"/>
<Button x:Name="start" Content="2.start animation" HorizontalAlignment="Left" Margin="-2,50,0,0" VerticalAlignment="Top" Width="118" Click="draw_bt_Click"/>
<Label Content="contiue click" HorizontalAlignment="Left" Margin="0,97,0,0" VerticalAlignment="Top" Width="116"/>
<Label Content="start animation btn" HorizontalAlignment="Left" Margin="0,120,0,0" VerticalAlignment="Top" Width="116"/>
<Canvas x:Name="canvas" HorizontalAlignment="Left" Height="373" Margin="137,0,0,0" VerticalAlignment="Top" Width="685"/>
</Grid>
code behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication7
{
/// <summary>
/// MainWindow.xaml에 대한 상호 작용 논리
/// </summary>
public partial class MainWindow : Window
{
int num_count = 10; // use data number
List<int> sampleNumbers; // Save a number to use for sorting
int count = 1; // count
Ellipse[] Circle;
List<double> SaveCircleStartPoint;
struct SaveCircleProperty
{
public double Circle_stposX;
public double Circle_stposY;
public double radian;
}
List<SaveCircleProperty> SaveCircleInfos;
// save changed sorting info
struct SortingTraceInfo
{
public int Position; // change position
public int TargetPosition; // will change position
public int[] SortingNumbers; // sorting numbers
}
// save changed sorting info
List<SortingTraceInfo> sortingInfos;
int sortingInfosIndex;
public MainWindow()
{
InitializeComponent();
}
private void num_bt_Click(object sender, RoutedEventArgs e)
{
Random _random = new Random(); // create number
int[] num = new int[10];
sampleNumbers = new List<int>();
for (int i = 0; i < num_count; i++)
{
num[i] = _random.Next(1, 50);
sampleNumbers.Add(num[i]); // save number data
}
BubbleSort();
drawCircle(num_count, sampleNumbers);
}
private void draw_bt_Click(object sender, RoutedEventArgs e)
{
// draw a path and start animation
SortingTraceInfo traceInfo = this.sortingInfos[this.sortingInfosIndex++];
draw_path(traceInfo.Position, traceInfo.TargetPosition);
}
// draw circle
private void drawCircle(int num, List<int> size)
{
// saving a position to draw a circle
SaveCircleStartPoint = new List<double>();
SaveCircleInfos = new List<SaveCircleProperty>();
// To create the circle by the number of input num
Circle = new Ellipse[num];
int location = ((685 / num) - 5); // circle startpoint
int x = 50; // Width
int y = 115; // Height
for (int i = 0; i < num; i++)
{
double circlesize = size[i] + 10;
double radius = circlesize / 2; // radius
double st_posX = x - radius; // circular X-axis position
double st_posY = y - radius; // circular Y-axis position
SaveCircleProperty cp = new SaveCircleProperty();
// define circle property
Circle[i] = new Ellipse();
Circle[i].Name = "circle" + i.ToString();
Circle[i].Stroke = Brushes.Red;
Circle[i].StrokeThickness = 5;
Circle[i].Width = circlesize;
Circle[i].Height = circlesize;
// position of canvs
Canvas.SetLeft(Circle[i], st_posX); // startpoint x-axis
Canvas.SetTop(Circle[i], st_posY); // startpoint Y-axis
// save circls's property
SaveCircleStartPoint.Add(st_posX);
cp.Circle_stposX = st_posX;
cp.Circle_stposY = st_posY;
cp.radian = radius;
SaveCircleInfos.Add(cp);
// startpoint
x += location;
// add canvas
canvas.Children.Add(Circle[i]);
this.RegisterName(Circle[i].Name, Circle[i]);
}
}
private void draw_path(int pos1, int pos2)
{
SaveCircleProperty scp = this.SaveCircleInfos[pos1];
SaveCircleProperty scp2 = this.SaveCircleInfos[pos2];
create_path(scp.Circle_stposX, scp.Circle_stposY, scp2.Circle_stposX, scp2.Circle_stposY, scp.radian, scp2.radian, pos1, pos2);
}
private void create_path(double startPoint, double startPoint2, double endPoint, double endPoint2, double radian1, double radian2, int position, int tartgetPosition)
{
// regist name
NameScope.SetNameScope(this, new NameScope());
NameScope.SetNameScope(canvas, new NameScope());
// circls position reset
Canvas.SetLeft(Circle[position], 0);
Canvas.SetTop(Circle[position], 0);
Canvas.SetLeft(Circle[tartgetPosition], 0);
Canvas.SetTop(Circle[tartgetPosition], 0);
///<summary>
/// Circle left the road going from left to right
///</summary>
PathGeometry pathGeometryLeft = new PathGeometry();
PathFigure Leftfigure = new PathFigure();
Leftfigure.StartPoint = new Point(startPoint, startPoint2); // x-axis , y-axis start point
// point(x-axis, y-axis)
Leftfigure.Segments.Add(new ArcSegment(new Point(endPoint, startPoint2), new Size(150, endPoint - startPoint), 90, false, SweepDirection.Clockwise, true));
pathGeometryLeft.Figures.Add(Leftfigure);
Path Leftpath = new Path();
Leftpath.Data = pathGeometryLeft;
Leftpath.Stroke = Brushes.Green;
canvas.Children.Add(Leftpath);
MatrixTransform LeftcircleMatrixTransform = new MatrixTransform();
Circle[position].RenderTransform = LeftcircleMatrixTransform;
this.RegisterName("LeftCircleMatrixTransform" + count.ToString(), LeftcircleMatrixTransform);
pathGeometryLeft.Freeze();
// Create a MatrixAnimationUsingPath to move the
// circle along the path by animating
// its MatrixTransform.
MatrixAnimationUsingPath Leftmatrixanimation = new MatrixAnimationUsingPath();
Leftmatrixanimation.PathGeometry = pathGeometryLeft;
Leftmatrixanimation.Duration = TimeSpan.FromSeconds(5);
Leftmatrixanimation.DoesRotateWithTangent = true;
// Set the animation to target the Matrix property
// of the MatrixTransform named "ButtonMatrixTransform".
Storyboard.SetTargetName(Leftmatrixanimation, "LeftCircleMatrixTransform" + count.ToString());
Storyboard.SetTargetProperty(Leftmatrixanimation, new PropertyPath(MatrixTransform.MatrixProperty));
// Create a Storyboard to contain and apply the animation.
Storyboard LeftpathAnimationStoryboard = new Storyboard();
LeftpathAnimationStoryboard.Children.Add(Leftmatrixanimation);
LeftpathAnimationStoryboard.Begin(this);
/// <summary>
/// The road to the right circle from right to left (path)
/// </summary>
PathGeometry RightpathGeometry = new PathGeometry();
PathFigure Rightfigure = new PathFigure();
Rightfigure.StartPoint = new Point(endPoint, endPoint2 + (radian2 * 2)); // x축 , y축 시작점
// point(x축 끝, y축 끝점)
Rightfigure.Segments.Add(new ArcSegment(new Point(startPoint, endPoint2 + (radian2 * 2)), new Size(150, endPoint - startPoint), 90, false, SweepDirection.Clockwise, true));
// this.RegisterName("RightmyArcSegment", Rightfigure.Segments);
RightpathGeometry.Figures.Add(Rightfigure);
Path Rightpath = new Path();
Rightpath.Data = RightpathGeometry;
Rightpath.Stroke = Brushes.Red;
canvas.Children.Add(Rightpath);
MatrixTransform RightcircleMatrixTransform = new MatrixTransform();
Circle[tartgetPosition].RenderTransform = RightcircleMatrixTransform;
this.RegisterName("RightCircleMatrixTransform" + count.ToString(), RightcircleMatrixTransform);
RightpathGeometry.Freeze();
MatrixAnimationUsingPath Rightmatrixanimation = new MatrixAnimationUsingPath();
Rightmatrixanimation.PathGeometry = RightpathGeometry;
Rightmatrixanimation.Duration = TimeSpan.FromSeconds(10);
// Set the animation's DoesRotateWithTangent property
// to true so that rotates the rectangle in addition
// to moving it.
Rightmatrixanimation.DoesRotateWithTangent = true;
// Set the animation to target the Matrix property
// of the MatrixTransform named "CircleMatrixTransform".
Storyboard.SetTargetName(Rightmatrixanimation, "RightCircleMatrixTransform" + count.ToString());
Storyboard.SetTargetProperty(Rightmatrixanimation, new PropertyPath(MatrixTransform.MatrixProperty));
// Create a Storyboard to contain and apply the animation.
Storyboard RightpathAnimationStoryboard = new Storyboard();
RightpathAnimationStoryboard.Children.Add(Rightmatrixanimation);
RightpathAnimationStoryboard.Begin(this);
Ellipse temp = null;
temp = Circle[position];
Circle[position] = Circle[tartgetPosition];
Circle[tartgetPosition] = temp;
count++;
}
// 버블 정렬
private List<int> BubbleSort()
{
sortingInfos = new List<SortingTraceInfo>();
List<int> sorting = new List<int>(sampleNumbers);
for (int i = 0; i < sorting.Count - 1; i++)
{
for (int j = 0; j < sorting.Count - 1 - i; j++)
{
if (sorting[j] > sorting[j + 1])
{
Swap(sorting, j, j + 1);
SortingTraceInfo sortInfo = new SortingTraceInfo(); //
sortInfo.Position = j; // save change position
sortInfo.TargetPosition = j + 1; // save will change position
sortInfo.SortingNumbers = sorting.ToArray(); // sorting number saved to array
sortingInfos.Add(sortInfo); // 변경 정보등을 sortingInfos 리스트에 저장
}
}
}
return sorting;
}
private void Swap(List<int> num, int i, int j)
{
int temp = num[i];
num[i] = num[j];
num[j] = temp;
}
}
}
private void draw_path(int pos1, int pos2)
{
var circles = canvas.Children.OfType<Ellipse>().OrderBy(q => (double)q.GetValue(Canvas.LeftProperty)).ToList();
var circle1 = circles[pos1];
var circle2 = circles[pos2];
// horizontal animation for circle1
Storyboard sb1 = new Storyboard();
double from1 = (double)circle1.GetValue(Canvas.LeftProperty);
double to1 = (double)circle2.GetValue(Canvas.LeftProperty) + circle2.ActualWidth / 2 - circle1.ActualWidth / 2;
DoubleAnimation da1 = new DoubleAnimation(from1, to1, new Duration(TimeSpan.FromSeconds(0.6)));
Storyboard.SetTarget(sb1, circle1);
Storyboard.SetTargetProperty(sb1, new PropertyPath(Canvas.LeftProperty));
sb1.Children.Add(da1);
// horizontal animation for circle2
Storyboard sb2 = new Storyboard();
double from2 = (double)circle2.GetValue(Canvas.LeftProperty);
double to2 = (double)circle1.GetValue(Canvas.LeftProperty) + circle1.ActualWidth / 2 - circle2.ActualWidth / 2;
DoubleAnimation da2 = new DoubleAnimation(from2, to2, new Duration(TimeSpan.FromSeconds(0.6)));
Storyboard.SetTarget(sb2, circle2);
Storyboard.SetTargetProperty(sb2, new PropertyPath(Canvas.LeftProperty));
sb2.Children.Add(da2);
// vertical animation for circle1
Storyboard sb3 = new Storyboard();
double from3 = (double)circle1.GetValue(Canvas.TopProperty);
double to3 = (double)circle1.GetValue(Canvas.TopProperty) + circle1.ActualWidth;
DoubleAnimation da3 = new DoubleAnimation(from3, to3, new Duration(TimeSpan.FromSeconds(0.3)));
da3.AutoReverse = true;
da3.AccelerationRatio = 0.1;
Storyboard.SetTarget(sb3, circle1);
Storyboard.SetTargetProperty(sb3, new PropertyPath(Canvas.TopProperty));
sb3.Children.Add(da3);
// vertical animation for circle2
Storyboard sb4 = new Storyboard();
double from4 = (double)circle2.GetValue(Canvas.TopProperty);
double to4 = (double)circle2.GetValue(Canvas.TopProperty) - circle2.ActualWidth;
DoubleAnimation da4 = new DoubleAnimation(from4, to4, new Duration(TimeSpan.FromSeconds(0.3)));
da4.AutoReverse = true;
da4.AccelerationRatio = 0.1;
Storyboard.SetTarget(sb4, circle2);
Storyboard.SetTargetProperty(sb4, new PropertyPath(Canvas.TopProperty));
sb4.Children.Add(da4);
sb1.Begin();
sb2.Begin();
sb3.Begin();
sb4.Begin();
}
Hope, it helps

Silverlight Pixel Perfect Collsion Detection

I am working on a project for my Uni, and I am currently stuck on a Pixel Perfect Collision Detection from this website http://www.andybeaulieu.com/Home/tabid/67/EntryID/160/Default.aspx. I have downloded example project that is using this collsion detection and it is working fine even with my own pictures. I have done the same thing in my project and it is not working. Here is the link to my app: https://www.cubby.com/pl/LostInTheMath.zip/_dd23e2c827604c068a3fe63ff42d22b2 could anyone tell me whats wrong with it? Thank you.
Here is the main code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
namespace LostInTheMath
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Page_Loaded);
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
}
private void UserCntrl_MouseMove(object sender, MouseEventArgs e)
{
Point pt = e.GetPosition(cnvHitTest);
Monkey.SetValue(Canvas.LeftProperty, pt.X);
Monkey.SetValue(Canvas.TopProperty, pt.Y);
}
void CompositionTarget_Rendering(object sender, EventArgs e)
{
Image MonkeyShell = Monkey.FindName("imgMonkey") as Image;
Image Mazer = Maze.FindName("imgMaze") as Image;
if (CheckCollision(Monkey, MonkeyShell, Maze, Mazer))
{
Monkey.Width = 1000;
txtStatus.Text = "Collision with XAML Element!";
return;
}
txtStatus.Text = string.Empty;
}
private bool CheckCollision(FrameworkElement control1, FrameworkElement controlElem1, FrameworkElement control2, FrameworkElement controlElem2)
{
// first see if sprite rectangles collide
Rect rect1 = UserControlBounds(control1);
Rect rect2 = UserControlBounds(control2);
rect1.Intersect(rect2);
if (rect1 == Rect.Empty)
{
// no collision - GET OUT!
return false;
}
else
{
bool bCollision = false;
Point ptCheck = new Point();
// NOTE that creating the writeablebitmap is a bit intense
// so we will do this once and store results in Tag property
// in a real game, you might abstract this into a Sprite class.
if (controlElem1 is Image)
controlElem1.Tag = GetWriteableBitmap(control1);
if (controlElem2 is Image)
controlElem2.Tag = GetWriteableBitmap(control2);
// now we do a more accurate pixel hit test
for (int x = Convert.ToInt32(rect1.X); x < Convert.ToInt32(rect1.X + rect1.Width); x++)
{
for (int y = Convert.ToInt32(rect1.Y); y < Convert.ToInt32(rect1.Y + rect1.Height); y++)
{
ptCheck.X = x;
ptCheck.Y = y;
if (CheckCollisionPoint(ptCheck, control1, controlElem1))
if (CheckCollisionPoint(ptCheck, control2, controlElem2))
{
bCollision = true;
break;
}
}
if (bCollision) break;
}
return bCollision;
}
}
public bool CheckCollisionPoint(Point pt, FrameworkElement control, FrameworkElement controlElem)
{
if (controlElem is Image)
{
// NOTE that we saved the WB in the Tag object for performance.
// in a real app, you might abstract this in your sprite class.
WriteableBitmap wb = controlElem.Tag as WriteableBitmap;
int width = wb.PixelWidth;
int height = wb.PixelHeight;
double offSetX = Convert.ToDouble(control.GetValue(Canvas.LeftProperty));
double offSetY = Convert.ToDouble(control.GetValue(Canvas.TopProperty));
pt.X = pt.X - offSetX;
pt.Y = pt.Y - offSetY;
int offset = Convert.ToInt32((width * pt.Y) + pt.X);
return (wb.Pixels[offset] != 0);
}
else
{
List<UIElement> hits = System.Windows.Media.VisualTreeHelper.FindElementsInHostCoordinates(pt, controlElem) as List<UIElement>;
return (hits.Contains(controlElem));
}
}
private WriteableBitmap GetWriteableBitmap(FrameworkElement control)
{
WriteableBitmap wb = new WriteableBitmap((int)control.Width, (int)control.Height); ;
wb.Render(control, new TranslateTransform());
wb.Invalidate();
return wb;
}
public Rect UserControlBounds(FrameworkElement control)
{
Point ptTopLeft = new Point(Convert.ToDouble(control.GetValue(Canvas.LeftProperty)), Convert.ToDouble(control.GetValue(Canvas.TopProperty)));
Point ptBottomRight = new Point(Convert.ToDouble(control.GetValue(Canvas.LeftProperty)) + control.Width, Convert.ToDouble(control.GetValue(Canvas.TopProperty)) + control.Height);
return new Rect(ptTopLeft, ptBottomRight);
}
}
}

Windows Form Paint equivalent event in WPF

I have used the PAINT event to draw a wave on a Panel in Winows Form Application. But when using it WPF, I didn't find any such element equivalent to a Panel which has a Paint Event. Googled a lot too but no great use.
Well, I need to draw a waveform in WPF so suggest appropriate solutions wrt PaintArgsEvent or a new solution altogether.
Thank You!
You are looking for the DrawingVisual Class
From first Link:
The DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text. This class is considered lightweight because it does not provide layout or event handling, which improves its performance. For this reason, drawings are ideal for backgrounds and clip art.
You also have access to a PolyLine Class that you can add a point Collection to. This example is a modified MSDN Forum example
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
float x0 = 100f;
float y0 = 100f;
Polyline myPoly = new Polyline();
PointCollection polyPoints = myPoly.Points;
Point[] points = new Point[200];
for (int j = 0; j < 200; j++)
{
points[j] = new Point();
points[j].X = x0 + j;
points[j].Y = y0 -
(float)(Math.Sin((2 * Math.PI * j) / 200) * (200 / (2 * Math.PI)));
}
for (int i = 0; i < points.Length ; i++)
{
polyPoints.Add(points[i]);
}
myPoly.Stroke = Brushes.Green;
myPoly.StrokeThickness = 5;
StackPanel mainPanel = new StackPanel();
mainPanel.Children.Add(myPoly);
this.Content = mainPanel;
}
}
And a Modified MSDN example:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
float x0 = 100f;
float y0 = 100f;
Point[] points = new Point[200];
for (int j = 0; j < 200; j++)
{
points[j] = new Point();
points[j].X = x0 + j;
points[j].Y = y0 -
(float)(Math.Sin((2 * Math.PI * j) / 200) * (200 / (2 * Math.PI)));
}
DrawingBrush db = new DrawingBrush(CreateDrawingVisualRectangle(points).Drawing);
StackPanel mainPanel = new StackPanel();
mainPanel.Background = db;
this.Content = mainPanel;
}
private DrawingVisual CreateDrawingVisualRectangle( Point[] pointarray)
{
DrawingVisual drawingVisual = new DrawingVisual();
// Retrieve the DrawingContext in order to create new drawing content.
DrawingContext drawingContext = drawingVisual.RenderOpen();
// Create a rectangle and draw it in the DrawingContext.
for (int i = 0; i < pointarray.Length-1; i++)
{
drawingContext.DrawLine(new Pen(new SolidColorBrush(Colors.Blue), 2), pointarray[i], pointarray[i + 1]);
}
// Persist the drawing content.
drawingContext.Close();
return drawingVisual;
}
}

WPF 3D - How can I save and load a Camera view?

I have a WPF 3D scene where I can pan, rotate and zoom using the TrackballDecorator from the 3DTools library. I would like to save the camera settings (transformation) and be able to re-apply them when the application restarts the next time (so the view is restored).
I tried to save each individual value of the Camera:
private void SaveCameraSettings()
{
var d = Properties.Settings.Default;
d.CameraPositionX = camera.Position.X;
d.CameraPositionY = camera.Position.Y;
...
d.Save();
}
This doesn't work, I guess because those settings are not updated according to the transformations applied to the camera (I always get the initial values set in xaml).
I checked the the Transformation3D class but couldn't find any way to set its value...
The problem is what values do I need to get from the PerspectiveCamera in order to be able to restore it the way it was when I closed my application the last time. The camera is set to a default position (in Xaml), then a transformation is applied to this camera by the TrackBallDecorator. How can I save this transformation (what values to store)? And how can I re-apply them at a later time?
This is going to be a bit long, so bear with me...
1st, you need to modify the 3DTools library so you can apply a transformation to the TrackballDecorator as follow:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Input;
namespace _3DTools
{
public class TrackballDecorator : Viewport3DDecorator
{
#region Private Members
private Point m_PreviousPosition2D;
private Vector3D m_PreviousPosition3D = new Vector3D(0, 0, 1);
private Transform3DGroup m_Transform;
private ScaleTransform3D m_Scale = new ScaleTransform3D();
private AxisAngleRotation3D m_Rotation = new AxisAngleRotation3D();
private TranslateTransform3D m_Translate = new TranslateTransform3D();
private readonly Border m_EventSource;
#endregion
#region Constructor
public TrackballDecorator()
{
TranslateScale = 10;
ZoomScale = 1;
RotateScale = 1;
// the transform that will be applied to the viewport 3d's camera
m_Transform = new Transform3DGroup();
m_Transform.Children.Add(m_Scale);
m_Transform.Children.Add(new RotateTransform3D(m_Rotation));
m_Transform.Children.Add(m_Translate);
// used so that we always get events while activity occurs within
// the viewport3D
m_EventSource = new Border { Background = Brushes.Transparent };
PreViewportChildren.Add(m_EventSource);
}
#endregion
#region Properties
/// <summary>
/// A transform to move the camera or scene to the trackball's
/// current orientation and scale.
/// </summary>
public Transform3DGroup Transform
{
get { return m_Transform; }
set
{
m_Transform = value;
m_Scale = m_Transform.GetScaleTransform3D();
m_Translate = m_Transform.GetTranslateTransform3D();
m_Rotation = m_Transform.GetRotateTransform3D().Rotation as AxisAngleRotation3D;
ApplyTransform();
}
}
public double TranslateScale { get; set; }
public double RotateScale { get; set; }
public double ZoomScale { get; set; }
#endregion
#region Event Handling
protected override void OnMouseDown(MouseButtonEventArgs e)
{
base.OnMouseDown(e);
m_PreviousPosition2D = e.GetPosition(this);
m_PreviousPosition3D = ProjectToTrackball(ActualWidth,
ActualHeight,
m_PreviousPosition2D);
if (Mouse.Captured == null)
{
Mouse.Capture(this, CaptureMode.Element);
}
}
protected override void OnMouseUp(MouseButtonEventArgs e)
{
base.OnMouseUp(e);
if (IsMouseCaptured)
{
Mouse.Capture(this, CaptureMode.None);
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (IsMouseCaptured)
{
Point currentPosition = e.GetPosition(this);
// avoid any zero axis conditions
if (currentPosition == m_PreviousPosition2D) return;
// Prefer tracking to zooming if both buttons are pressed.
if (e.LeftButton == MouseButtonState.Pressed)
{
Track(currentPosition);
}
else if (e.RightButton == MouseButtonState.Pressed)
{
Zoom(currentPosition);
}
else if (e.MiddleButton == MouseButtonState.Pressed)
{
Translate(currentPosition);
}
m_PreviousPosition2D = currentPosition;
ApplyTransform();
}
}
private void ApplyTransform()
{
Viewport3D viewport3D = Viewport3D;
if (viewport3D != null)
{
if (viewport3D.Camera != null)
{
if (viewport3D.Camera.IsFrozen)
{
viewport3D.Camera = viewport3D.Camera.Clone();
}
if (viewport3D.Camera.Transform != m_Transform)
{
viewport3D.Camera.Transform = m_Transform;
}
}
}
}
#endregion Event Handling
private void Track(Point currentPosition)
{
var currentPosition3D = ProjectToTrackball(ActualWidth, ActualHeight, currentPosition);
var axis = Vector3D.CrossProduct(m_PreviousPosition3D, currentPosition3D);
var angle = Vector3D.AngleBetween(m_PreviousPosition3D, currentPosition3D);
// quaterion will throw if this happens - sometimes we can get 3D positions that
// are very similar, so we avoid the throw by doing this check and just ignoring
// the event
if (axis.Length == 0) return;
var delta = new Quaternion(axis, -angle);
// Get the current orientantion from the RotateTransform3D
var r = m_Rotation;
var q = new Quaternion(m_Rotation.Axis, m_Rotation.Angle);
// Compose the delta with the previous orientation
q *= delta;
// Write the new orientation back to the Rotation3D
m_Rotation.Axis = q.Axis;
m_Rotation.Angle = q.Angle;
m_PreviousPosition3D = currentPosition3D;
}
private static Vector3D ProjectToTrackball(double width, double height, Point point)
{
var x = point.X / (width / 2); // Scale so bounds map to [0,0] - [2,2]
var y = point.Y / (height / 2);
x = x - 1; // Translate 0,0 to the center
y = 1 - y; // Flip so +Y is up instead of down
var z2 = 1 - x * x - y * y; // z^2 = 1 - x^2 - y^2
var z = z2 > 0 ? Math.Sqrt(z2) : 0;
return new Vector3D(x, y, z);
}
private void Zoom(Point currentPosition)
{
var yDelta = currentPosition.Y - m_PreviousPosition2D.Y;
var scale = Math.Exp(yDelta / 100) / ZoomScale; // e^(yDelta/100) is fairly arbitrary.
m_Scale.ScaleX *= scale;
m_Scale.ScaleY *= scale;
m_Scale.ScaleZ *= scale;
}
private void Translate(Point currentPosition)
{
// Calculate the panning vector from screen(the vector component of the Quaternion
// the division of the X and Y components scales the vector to the mouse movement
var qV = new Quaternion(((m_PreviousPosition2D.X - currentPosition.X) / TranslateScale),
((currentPosition.Y - m_PreviousPosition2D.Y) / TranslateScale), 0, 0);
// Get the current orientantion from the RotateTransform3D
var q = new Quaternion(m_Rotation.Axis, m_Rotation.Angle);
var qC = q;
qC.Conjugate();
// Here we rotate our panning vector about the the rotaion axis of any current rotation transform
// and then sum the new translation with any exisiting translation
qV = q * qV * qC;
m_Translate.OffsetX += qV.X;
m_Translate.OffsetY += qV.Y;
m_Translate.OffsetZ += qV.Z;
}
}
}
The GetXXXTransform3D methods are extension methods defined as follow:
public static ScaleTransform3D GetScaleTransform3D(this Transform3DGroup transform3DGroup)
{
ScaleTransform3D scaleTransform3D = null;
if (transform3DGroup != null)
{
foreach (var transform in transform3DGroup.Children)
{
scaleTransform3D = transform as ScaleTransform3D;
if (scaleTransform3D != null) return scaleTransform3D;
}
}
return scaleTransform3D;
}
public static RotateTransform3D GetRotateTransform3D(this Transform3DGroup transform3DGroup)
{
RotateTransform3D rotateTransform3D = null;
if (transform3DGroup != null)
{
foreach (var transform in transform3DGroup.Children)
{
rotateTransform3D = transform as RotateTransform3D;
if (rotateTransform3D != null) return rotateTransform3D;
}
}
return rotateTransform3D;
}
public static TranslateTransform3D GetTranslateTransform3D(this Transform3DGroup transform3DGroup)
{
TranslateTransform3D translateTransform3D = null;
if (transform3DGroup != null)
{
foreach (var transform in transform3DGroup.Children)
{
translateTransform3D = transform as TranslateTransform3D;
if (translateTransform3D != null) return translateTransform3D;
}
}
return translateTransform3D;
}
2nd, you need to declare a Transform to your PerspectiveCamera as follow:
(the example is taken from Sasha Barber's Elements3D project which I used to test this)
<Tools:TrackballDecorator x:Name="tbViewPort">
<Viewport3D x:Name="vpFeeds">
<Viewport3D.Camera>
<PerspectiveCamera x:Name="camera" Position="-2,2,40" LookDirection="2,-2,-40" FieldOfView="90">
<PerspectiveCamera.Transform>
<Transform3DGroup />
</PerspectiveCamera.Transform>
</PerspectiveCamera>
</Viewport3D.Camera>
<ContainerUIElement3D x:Name="container" />
<ModelVisual3D x:Name="model">
<ModelVisual3D.Content>
<DirectionalLight Color="White" Direction="-1,-1,-1" />
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Tools:TrackballDecorator>
3rd, since we are going to store each part of the whole transformation in a separate value, you need to create the relevant properties in your settings file, i.e. CameraScaleX, CameraScaleY, CameraScaleZ, CameraTranslateX, CameraTranslateY, CameraTranslateZ, CameraRotateAxisX, CameraRotateAxisY, CameraRotateAxisZ and CameraRotateAngle. All are of type double and are stored in User scope.
4th and last step is to actually save and load these settings into the camera using the following code:
private void SaveCameraSettings()
{
var transform3DGroup = camera.Transform as Transform3DGroup;
if (transform3DGroup != null)
{
foreach (var transform in transform3DGroup.Children)
{
var scale = transform as ScaleTransform3D;
if (scale != null) SaveCameraSetting(scale);
var rotate = transform as RotateTransform3D;
if (rotate != null) SaveCameraSetting(rotate);
var translate = transform as TranslateTransform3D;
if (translate != null) SaveCameraSetting(translate);
}
Settings.Default.Save();
}
}
private static void SaveCameraSetting(ScaleTransform3D transform)
{
Properties.Settings.Default.CameraScaleX = transform.ScaleX;
Properties.Settings.Default.CameraScaleY = transform.ScaleY;
Properties.Settings.Default.CameraScaleZ = transform.ScaleZ;
}
private static void SaveCameraSetting(RotateTransform3D transform)
{
var axisAngleRotation3D = transform.Rotation as AxisAngleRotation3D;
if (axisAngleRotation3D != null)
{
Properties.Settings.Default.CameraRotateAxisX = axisAngleRotation3D.Axis.X;
Properties.Settings.Default.CameraRotateAxisY = axisAngleRotation3D.Axis.Y;
Properties.Settings.Default.CameraRotateAxisZ = axisAngleRotation3D.Axis.Z;
Properties.Settings.Default.CameraRotateAngle = axisAngleRotation3D.Angle;
}
}
private static void SaveCameraSetting(TranslateTransform3D transform)
{
Properties.Settings.Default.CameraTranslateX = transform.OffsetX;
Properties.Settings.Default.CameraTranslateY = transform.OffsetY;
Properties.Settings.Default.CameraTranslateZ = transform.OffsetZ;
}
private void LoadCameraPosition()
{
var d = Settings.Default;
var transform3DGroup = new Transform3DGroup();
var scaleTransform3D = new ScaleTransform3D(d.CameraScaleX, d.CameraScaleY, d.CameraScaleZ);
var translateTransform3D = new TranslateTransform3D(d.CameraTranslateX, d.CameraTranslateY, d.CameraTranslateZ);
var axisAngleRotation3D = new AxisAngleRotation3D(new Vector3D(d.CameraRotateAxisX, d.CameraRotateAxisY, d.CameraRotateAxisZ),
d.CameraRotateAngle);
var rotateTransform3D = new RotateTransform3D(axisAngleRotation3D);
transform3DGroup.Children.Add(scaleTransform3D);
transform3DGroup.Children.Add(translateTransform3D);
transform3DGroup.Children.Add(rotateTransform3D);
tbViewPort.Transform = transform3DGroup;
}
Hopefully, I didn't forget anything. If you need more help or don't understand something, please don't hesitate to ask ;-)
You would need both the cameras view matrix data and the projection matrix data. The view matrix will contain the data about the position, rotation, scale and translation of the camera and the projection matrix will contain things like the field of view, near plane, far plane and other data.
Sorry I cant help with exporting/importing that data since I've not used WPF, but there might be rawdata properties exposed if it uses anything to do with as3's built in Matrix classes, this is usualy a as3 Vector. Object the the matrices 16 values exposed as row ordered floating point values.
I believe what you need is Position, LookDirection, UpDirection, FieldOfView, NearPlaneDistance, FarPlaneDistance. All the above properties define the camera.

Resources