How to draw a dynamic Grid with XNA - silverlight

I'm trying to draw grid using the XNA framework, this grid should have a fixed dimension, during the execution of XNA, but should be given to the user the opportunity to customize it before launch the game page (I'm building my app with the silverlight/xna template).
Does anyone has a suggestion on how achieve this goal?
Thank you

Set a tileSize, and then draw a texture over the size of grid you want.
Here is some reworked code. This is how I would start with generating a tilemap, by using a 2d array.
int tileSize = 32;
Vector2 position = Vector2.Zero;
Texture2D gridTexture;
int[,] map = new int[,]
{
{1, 1, 0,},
{0, 1, 1,},
{1, 1, 0,},
};
Then add something like this to your draw function:
for (int i = 0; i <= map.GetUpperBound(0); i++)
{
for (int j = 0; j <= map.GetUpperBound(1); j++)
{
int textureId = map[i, j];
if (textureId != 0)
{
Vector2 texturePosition = new Vector2(i * tileSize, j * tileSize) + position;
//Here you would typically index to a Texture based on the textureId.
spriteBatch.Draw(gridTexture, texturePosition, null, Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0f);
}
}
}

ContentManager contentManager;
GameTimer timer;
SpriteBatch spriteBatch;
LifeGrid life;
int tileSize = 32;
Vector2 position = Vector2.Zero;
Texture2D gridTexture;
int[,] map;
public GamePage()
{
InitializeComponent();
// Get the content manager from the application
contentManager = (Application.Current as App).Content;
// Create a timer for this page
timer = new GameTimer();
//timer.UpdateInterval = TimeSpan.FromTicks(333333);
timer.UpdateInterval = TimeSpan.Zero;
timer.Update += OnUpdate;
timer.Draw += OnDraw;
List<Position> p = new List<Position>();
p.Add(new Position(1,1));
p.Add(new Position(1,4));
p.Add(new Position(1,5));
p.Add(new Position(1,6));
p.Add(new Position(1,7));
this.life = new LifeGrid(10, 10, p);
map = new int[,]{{1, 1, 0,},{0, 1, 1,},{1, 1, 0,},};
// LayoutUpdated += new EventHandler(GamePage_LayoutUpdated);
}
/// <summary>
/// Allows the page to draw itself.
/// </summary>
private void OnDraw(object sender, GameTimerEventArgs e)
{
// SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.CornflowerBlue);
// SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.Black);
// Draw the sprite
spriteBatch.Begin();
for (int i = 0; i <= map.GetUpperBound(0); i++)
{
for (int j = 0; j <= map.GetUpperBound(1); j++)
{
int textureId = map[i, j];
if (textureId != 0)
{
Vector2 texturePosition = new Vector2(i * tileSize, j * tileSize) + position;
//Here you would typically index to a Texture based on the textureId.
spriteBatch.Draw(gridTexture, texturePosition, null, Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0f);
}
}
}
spriteBatch.End();
}

Related

Setting up a Timeline with a for loop in JavaFX

I'm trying to write an animated sort for a class I'm in. My goal is to have the sort displayed as vertical white bars that will be rendered on the canvas I've created.
I've attempted to accomplish this using a Timeline and Keyframes, but the output I get is a blank white canvas that after a few moments outputs the finished and sorted array.
I've resorted to just shuffling around code with no success, and can't find any helpful examples online. I'm hoping someone with some more experience with JavaFX animation can help me learn more about how to properly set this up!
Note that in the code below the array created with the random method is commented out because when used it makes the program hang for long time. The code will output in a reasonable time with a smaller array.
import java.util.Random;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.util.Duration;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
public class Project06 extends Application
{
final int SCALE = 16;
final int WIDTH = 64;
final int HEIGHT = 32;
int[][] pixels;
Timeline sortLoop;
int[] myArray = {32,28,22,20,16,13,10,9,5,3};
#Override
public void start(Stage primaryStage) throws Exception
{
pixels = new int[WIDTH][HEIGHT];
int[] myArray = new int[WIDTH];
/*
Random rand = new Random();
for (int i = 0; i < WIDTH; i++)
{
myArray[i] = rand.nextInt((HEIGHT) + 1);
}
*/
Canvas display = new Canvas (WIDTH*SCALE, HEIGHT*SCALE);
GraphicsContext gc = display.getGraphicsContext2D();
GridPane grid = new GridPane();
grid.add(display, 0, 0);
primaryStage.setTitle("Sort");
primaryStage.setScene(new Scene(grid, WIDTH*SCALE, HEIGHT*SCALE));
primaryStage.show();
sortLoop = new Timeline();
sortLoop.setCycleCount(Timeline.INDEFINITE);
// Sort array
for (int i = 0; i < myArray.length - 1; i++)
{
if (myArray[i] > myArray[i + 1])
{
int swap = myArray[i];
myArray[i] = myArray[i + 1];
myArray[i + 1] = swap;
i = -1;
}
// Clear screen by zeroing out pixel array
for (int k = 0; k < WIDTH; k++)
{
for (int j = 0; j < HEIGHT; j++)
{
pixels[k][j] = 0;
}
}
// Draw array with vertical bars (assign values to canvas array)
for (int k = 0; k < myArray.length; k++)
{
for (int j = (HEIGHT - 1); j > ((HEIGHT - myArray[k]) - 1); j--)
{
pixels[k][j] = 1;
}
}
KeyFrame kf = new KeyFrame(Duration.seconds(1), actionEvent -> {
// Render canvas
for (int k = 0; k < WIDTH; k++)
{
for (int j = 0; j < HEIGHT; j++)
{
if (pixels[k][j] == 1)
{
gc.setFill(Color.WHITE);
gc.fillRect((k*SCALE), (j*SCALE), SCALE, SCALE);
}
else
{
gc.setFill(Color.BLACK);
gc.fillRect((k*SCALE), (j*SCALE), SCALE, SCALE);
}
}
}
});
sortLoop.getKeyFrames().add(kf);
sortLoop.play();
}
}
public static void main(String[] args)
{
launch(args);
}
}
First, you are setting the timepoint for all your key frames to the same value (one second), so they all happen simultaneously. You need each key frame to have a different timepoint, so they happen sequentially.
Second, you sort the array, and then the event handlers for the keyframes reference the array. Since the event handlers for the keyframes are executed later, they only see the sorted array. You need to actually manipulate the array in the event handlers for the key frames.
Third, you play the timeline multiple times. You only need to play it once. Additionally, you set the cycle count to INDEFINITE: I think you only need to animate the sort once. (If you actually want it to repeat, you would need to set the array back to its original order at the beginning of the timeline.)
Finally, you have some issues in the implementation of the actual sort algorithm. This is why your application hangs when you randomly populate the array. I won't address those issues here, because the question is about how to perform the animation.
The following code performs a step-by-step animation. It's probably not the correctly-implemented sort, so you won't see the animation you necessarily expect, but it at least repaints the effect of the swaps in an animation:
import java.util.Random;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.util.Duration;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
public class AnimatedSort extends Application
{
final int SCALE = 16;
final int WIDTH = 64;
final int HEIGHT = 32;
int[][] pixels;
Timeline sortLoop;
int[] myArray = {32,28,22,20,16,13,10,9,5,3};
#Override
public void start(Stage primaryStage) throws Exception
{
pixels = new int[WIDTH][HEIGHT];
// int[] myArray = new int[WIDTH];
//
//
// Random rand = new Random();
// for (int i = 0; i < WIDTH; i++)
// {
// myArray[i] = rand.nextInt((HEIGHT) + 1);
// }
Canvas display = new Canvas (WIDTH*SCALE, HEIGHT*SCALE);
GraphicsContext gc = display.getGraphicsContext2D();
GridPane grid = new GridPane();
grid.add(display, 0, 0);
primaryStage.setTitle("Sort");
primaryStage.setScene(new Scene(grid, WIDTH*SCALE, HEIGHT*SCALE));
primaryStage.show();
sortLoop = new Timeline();
// sortLoop.setCycleCount(Timeline.INDEFINITE);
// Sort array
for (int index = 0; index < myArray.length - 1; index++)
{
final int i = index ;
KeyFrame kf = new KeyFrame(Duration.seconds(i+1), actionEvent -> {
if (myArray[i] > myArray[i + 1])
{
int swap = myArray[i];
myArray[i] = myArray[i + 1];
myArray[i + 1] = swap;
// i = -1;
}
// Clear screen by zeroing out pixel array
for (int k = 0; k < WIDTH; k++)
{
for (int j = 0; j < HEIGHT; j++)
{
pixels[k][j] = 0;
}
}
// Draw array with vertical bars (assign values to canvas array)
for (int k = 0; k < myArray.length; k++)
{
for (int j = (HEIGHT - 1); j > ((HEIGHT - myArray[k]) - 1); j--)
{
pixels[k][j] = 1;
}
}
// Render canvas
for (int k = 0; k < WIDTH; k++)
{
for (int j = 0; j < HEIGHT; j++)
{
if (pixels[k][j] == 1)
{
gc.setFill(Color.WHITE);
gc.fillRect((k*SCALE), (j*SCALE), SCALE, SCALE);
}
else
{
gc.setFill(Color.BLACK);
gc.fillRect((k*SCALE), (j*SCALE), SCALE, SCALE);
}
}
}
});
sortLoop.getKeyFrames().add(kf);
}
sortLoop.play();
}
public static void main(String[] args)
{
launch(args);
}
}
The time property of KeyFrame denotes the time since the start of the animation, not the time since the previously added KeyFrame. You need to position. You need to pass different times to the KeyFrame constructor.
Furthermore you "sort" a fresh array instead of using the field. Also your pixels array contains the last value from the start.
Better save the swaps to a data structure and use a Timeline to render the changes step by step:
final int SCALE = 16;
final int WIDTH = 64;
final int HEIGHT = 32;
Timeline sortLoop;
int[] myArray = {32, 28, 22, 20, 16, 13, 10, 9, 5, 3};
private void renderBar(GraphicsContext gc, int barIndex, double canvasHeight, int barHeight) {
double rectHeight = barHeight * SCALE;
gc.fillRect(SCALE * barIndex, canvasHeight - rectHeight, SCALE, rectHeight);
}
#Override
public void start(Stage primaryStage) throws Exception {
int[] myArray = this.myArray.clone(); // copy field (you may also simply delete this declaration, if you never reuse the initial array)
class Swap {
final int lowerIndex, value1, value2;
public Swap(int lowerIndex, int value1, int value2) {
this.lowerIndex = lowerIndex;
this.value1 = value1;
this.value2 = value2;
}
}
final double canvasHeight = HEIGHT * SCALE;
Canvas display = new Canvas(WIDTH * SCALE, canvasHeight);
GraphicsContext gc = display.getGraphicsContext2D();
primaryStage.setTitle("Sort");
primaryStage.setScene(new Scene(new Group(display)));
primaryStage.show();
// render initial state
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, display.getWidth(), canvasHeight);
gc.setFill(Color.BLACK);
for (int i = 0; i < myArray.length; i++) {
renderBar(gc, i, canvasHeight, myArray[i]);
}
// Sort array & save changes
List<Swap> swaps = new ArrayList<>();
for (int i = 0; i < myArray.length - 1; i++) {
if (myArray[i] > myArray[i + 1]) {
int swap = myArray[i];
myArray[i] = myArray[i + 1];
myArray[i + 1] = swap;
swaps.add(new Swap(i, myArray[i], swap));
i = -1;
} else {
// no change
swaps.add(null);
}
}
sortLoop = new Timeline();
sortLoop.setCycleCount(swaps.size());
final Iterator<Swap> iter = swaps.iterator();
sortLoop.getKeyFrames().add(new KeyFrame(Duration.seconds(1), evt -> {
Swap swap = iter.next();
if (swap != null) {
// clear old area
gc.setFill(Color.WHITE);
gc.fillRect(SCALE * swap.lowerIndex, 0, SCALE * 2, canvasHeight);
// draw new bars
gc.setFill(Color.BLACK);
renderBar(gc, swap.lowerIndex, canvasHeight, swap.value1);
renderBar(gc, swap.lowerIndex+1, canvasHeight, swap.value2);
}
}));
sortLoop.play();
}

2D over 3D anti-aliasing artifacts

We have 3D models in WPF and use a cursor made from a Canvas and some internal parts. We turn the HW cursor off and move the Canvas through MouseEvent. The issue is that there are terrible artifacts on the screen as you move from left to right (not nearly as bad right to left). I have played with snaptodevicepixels, Edge mode and nvidea AA settings but the only thing that "fixes" is setting edge mode to aliased for the 3dviewport - and we don't want that. I have even made the cursor completely transparent and it still leaves artifacts.
I broke out some of the code for demonstration. You can especially see the artifacts moving upper-left to lower-right.
Anyone think they can help me out here? I'm head banging and not in a good way. It's looking more like a bug in the AA code.
Thanks
T
FYI: I used some Petzold code here for the beach ball.
Bad AA BeachBall
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Shapes;
namespace Cursoraa2
{
class Program : Window
{
[STAThread]
public static void Main() => new Application().Run(new Program());
public Program()
{
Width = 500;
Height = 500;
var grid = new Grid();
var viewport = new Viewport3D();
grid.Children.Add(viewport);
Content = grid;
//RenderOptions.SetEdgeMode(viewport,EdgeMode.Aliased);
DynamicCurosr.Start(grid, grid, 40, Color.FromArgb(40, 0x33, 0x33, 0xff), Colors.Blue);
MouseMove += MainWindow_MouseMove;
MakeBeachBallSphere(viewport);
}
private void MainWindow_MouseMove(object sender, MouseEventArgs e) => DynamicCurosr.Move(e.GetPosition(this));
public void MakeBeachBallSphere(Viewport3D viewport)
{
// Get the MeshGeometry3D from the GenerateSphere method.
var mesh = GenerateSphere(new Point3D(0, 0, 0), 1, 36, 18);
mesh.Freeze();
// Define a brush for the sphere.
var brushes = new Brush[6] { Brushes.Red, Brushes.Blue,
Brushes.Yellow, Brushes.Orange,
Brushes.White, Brushes.Green };
var drawgrp = new DrawingGroup();
for (var i = 0; i < brushes.Length; i++)
{
var rectgeo = new RectangleGeometry(new Rect(10 * i, 0, 10, 60));
var geodraw = new GeometryDrawing(brushes[i], null, rectgeo);
drawgrp.Children.Add(geodraw);
}
var drawbrsh = new DrawingBrush(drawgrp);
drawbrsh.Freeze();
// Define the GeometryModel3D.
var geomod = new GeometryModel3D
{
Geometry = mesh,
Material = new DiffuseMaterial(drawbrsh)
};
// Create a ModelVisual3D for the GeometryModel3D.
var modvis = new ModelVisual3D { Content = geomod };
viewport.Children.Add(modvis);
// Create another ModelVisual3D for light.
var modgrp = new Model3DGroup();
modgrp.Children.Add(new AmbientLight(Color.FromRgb(128, 128, 128)));
modgrp.Children.Add(new DirectionalLight(Color.FromRgb(128, 128, 128), new Vector3D(2, -3, -1)));
modvis = new ModelVisual3D {Content = modgrp};
viewport.Children.Add(modvis);
// Create the camera.
var cam = new PerspectiveCamera(new Point3D(0, 0, 8), new Vector3D(0, 0, -1), new Vector3D(0, 1, 0), 45);
viewport.Camera = cam;
// Create a transform for the GeometryModel3D.
var axisangle = new AxisAngleRotation3D(new Vector3D(1, 1, 0), 180);
var rotate = new RotateTransform3D(axisangle);
geomod.Transform = rotate;
// Animate the RotateTransform3D.
//DoubleAnimation anima = new DoubleAnimation(360, new Duration(TimeSpan.FromSeconds(5)));
//anima.RepeatBehavior = RepeatBehavior.Forever;
//axisangle.BeginAnimation(AxisAngleRotation3D.AngleProperty, anima);
}
MeshGeometry3D GenerateSphere(Point3D center, double radius, int slices, int stacks)
{
// Create the MeshGeometry3D.
var mesh = new MeshGeometry3D();
// Fill the Position, Normals, and TextureCoordinates collections.
for (var stack = 0; stack <= stacks; stack++)
{
var phi = Math.PI / 2 - stack * Math.PI / stacks;
var y = radius * Math.Sin(phi);
var scale = -radius * Math.Cos(phi);
for (var slice = 0; slice <= slices; slice++)
{
var theta = slice * 2 * Math.PI / slices;
var x = scale * Math.Sin(theta);
var z = scale * Math.Cos(theta);
var normal = new Vector3D(x, y, z);
mesh.Normals.Add(normal);
mesh.Positions.Add(normal + center);
mesh.TextureCoordinates.Add(
new Point((double)slice / slices,
(double)stack / stacks));
}
}
// Fill the TriangleIndices collection.
for (var stack = 0; stack < stacks; stack++)
for (var slice = 0; slice < slices; slice++)
{
var n = slices + 1; // Keep the line length down.
if (stack != 0)
{
mesh.TriangleIndices.Add((stack + 0) * n + slice);
mesh.TriangleIndices.Add((stack + 1) * n + slice);
mesh.TriangleIndices.Add((stack + 0) * n + slice + 1);
}
if (stack != stacks - 1)
{
mesh.TriangleIndices.Add((stack + 0) * n + slice + 1);
mesh.TriangleIndices.Add((stack + 1) * n + slice);
mesh.TriangleIndices.Add((stack + 1) * n + slice + 1);
}
}
return mesh;
}
}
public static class DynamicCurosr
{
static public bool InSession { get; private set; }
private static Panel theCursor;
private static readonly ScaleTransform ScaleTransform = new ScaleTransform(1, 1);
private static readonly MatrixTransform MatrixTransform = new MatrixTransform(1, 0, 0, 1, 0, 0);
private static Color defaultFill = Color.FromArgb(20, 255, 255, 255);
private static Color fillFromUser;
private static double strokeFromUser = 0;
private static Color strokeColorFromUser = Colors.Black;
private static int centerDotSizeFromUser = 10; // need to get from user
private static double initialDiameter = double.NaN;
private static Panel cursorPanel;
private static Panel mousePanel;
public static bool Start(Panel cursorPanelIn, Panel mousePanelIn, double radius)
{
return Start(cursorPanelIn, mousePanelIn, radius, defaultFill);
}
public static bool Start(Panel cursorPanelIn, Panel mousePanelIn, double radius, Color fill, Color strokeColor = default(Color), double strokeSize = .16)
{
strokeColor = strokeColor == default(Color) ? Colors.Black : strokeColor;
strokeColorFromUser = strokeColor;
fillFromUser = fill;
strokeFromUser = strokeColor == default(Color) ? 0 : strokeSize;
initialDiameter = double.IsNaN(initialDiameter) ? radius * 2 : initialDiameter;
return Start(cursorPanelIn, mousePanelIn);
}
private static bool Start(Panel cursorPanelIn, Panel mousePanelIn)
{
if (InSession) return false;
cursorPanel = cursorPanelIn;
mousePanel = mousePanelIn;
var point = Mouse.GetPosition(cursorPanel);
theCursor = MakeACursor(theCursor, initialDiameter / 2);
InSession = true;
cursorPanel.Cursor = Cursors.None;
theCursor.Visibility = Visibility.Visible;
Move(point);
if (cursorPanel.Children.Contains(theCursor))
return false;
cursorPanel.Children.Add(theCursor);
Mouse.OverrideCursor = Cursors.None;
return true;
}
public static void Stop()
{
if (InSession)
{
Mouse.OverrideCursor = null;
theCursor.Visibility = Visibility.Collapsed;
cursorPanel.Children.Remove(theCursor);
InSession = false;
}
}
public static void Move(Point point)
{
if (InSession && theCursor.Visibility == Visibility.Visible)
{
var m = MatrixTransform.Matrix;
m.OffsetX = point.X - theCursor.Width / 2;
m.OffsetY = point.Y - theCursor.Height / 2;
MatrixTransform.Matrix = m;
theCursor.RenderTransform = MatrixTransform;
}
}
public static Panel MakeACursor(Panel theCursor, double radius, Color fillColorIn = default(Color), Color strokeColorIn = default(Color))
{
var strokeColor = new SolidColorBrush(strokeColorIn == default(Color) ? strokeColorFromUser : strokeColorIn);
if (theCursor == null)
{
theCursor = new Grid()
{
Width = radius * 2,
Height = radius * 2,
Background = null,
VerticalAlignment = VerticalAlignment.Top,
HorizontalAlignment = HorizontalAlignment.Left,
RenderTransform = ScaleTransform,
RenderTransformOrigin = new Point(.5, .5),
};
var cursorElement = new Ellipse
{
Width = radius * 2,
Height = radius * 2,
Fill = new SolidColorBrush(fillColorIn == default(Color) ? fillFromUser : fillColorIn),
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
StrokeThickness = strokeFromUser,
Stroke = strokeColor,
RenderTransformOrigin = new Point(.5, .5)
};
theCursor.Children.Add(cursorElement);
}
MakeCursorOverlay(theCursor, radius, strokeColor);
return theCursor;
}
public static void MakeCursorOverlay(Panel theCursor, double radius, SolidColorBrush strokeColor)
{
var save = theCursor.Children[0];
theCursor.Children.Clear();
theCursor.Children.Add(save);
var circle = new Ellipse
{
Width = centerDotSizeFromUser,
Height = centerDotSizeFromUser,
Fill = null,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
StrokeThickness = strokeFromUser,
Stroke = strokeColor,
RenderTransformOrigin = new Point(.5, .5)
};
theCursor.Children.Add(circle);
}
}
}

Save the circle and circle again output in the next line in WPF in code Behind

I want to copy the circle.
2.When you click the start animation button, The animation is run only once.
And copy the circle below.
Howerver, I have failed. this is result.
I do not know why you have failed. I can not upload photos.
So I raise all of the code instead.
I want result ... this
ex) 10 1 2 3 4 5 6 9 8 7 (Various sizes of circles, one line)
start animation is run only once ->
print a new Circles
10 1 2 3 4 5 6 9 8 7
1 10 2 3 4 5 6 9 8 7 (new line)
Adding a new source every time you click the button.
The color conversion is animated, moving spot.
public partial class MainWindow : Window
{
int num_count = 10; // use data number
List<int> sampleNumbers; // Save a number to use for sorting
Ellipse[] Circle;
List<Ellipse> SaveCircleInfos = new List<Ellipse>();
// 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[num_count];
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
rtb.AppendText(num[i].ToString() + "\r\n");
}
BubbleSort();
drawCircle(num_count, sampleNumbers);
}
//create number button
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);
if (sortingInfos.Count <= sortingInfosIndex)
{
start.IsEnabled = false;
}
}
//reprint circle
private void rePrint(List<Ellipse> circles)
{
int location = ((685 / SaveCircleInfos.Count) - 5); // circle startpoint
int x = 50;
for (int i = 0; i < num_count; i++)
{
SaveCircleInfos[i].Stroke = Brushes.Red;
Canvas.SetLeft(SaveCircleInfos[i], x); // startpoint x-axis
Canvas.SetTop(SaveCircleInfos[i], 230); // startpoint Y-axis
x += location;
}
}
// draw circle
private void drawCircle(int num, List<int> size)
{
// 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] + 15;
double radius = circlesize / 2; // radius
double st_posX = x - radius; // circular X-axis position
double st_posY = y - radius; // circular Y-axis position
// 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;
SaveCircleInfos.Add(Circle[i]);
// position of canvs
Canvas.SetLeft(Circle[i], st_posX); // startpoint x-axis
Canvas.SetTop(Circle[i], st_posY); // startpoint Y-axis
// startpoint
x += location;
// add canvas
canvas.Children.Add(Circle[i]);
}
}
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];
circle1.Stroke = Brushes.Blue;
circle2.Stroke = Brushes.Purple;
// 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();
var temp = SaveCircleInfos[pos1];
SaveCircleInfos[pos1] = SaveCircleInfos[pos2];
SaveCircleInfos[pos2] = temp;
rePrint(SaveCircleInfos);
}
// bubble sort
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);
}
}
}
return sorting;
}
private void Swap(List<int> num, int i, int j)
{
int temp = num[i];
num[i] = num[j];
num[j] = temp;
}
}
}

Silverlight - Fill a rectangle with animation on mouseclick

I want to be able to fill a rectangle with an animation on leftmousebuttondown (this will later be changed to run on load).
My rectangles are drawn to a canvas in code behind based on the data that is passed (one rectangle per row of data)
At the moment they are filled with a static image but I want this Fill to be an animation, a spinner if I can.
I am very new to Silverlight and am not sure how to achieve this. Can someone point me in the right direction?
My code (part) so far.
XAML:
<Canvas x:Name="Grid" Background="LightGray"></Canvas>
CS:
public partial class ProductView : UserControl
{
Processing processingDialog = new Processing();
private int colsRequired = 0;
private int rowsRequired = 0;
private const int minSize = 5;
private int cellSize = 1;
public ProductView()
{
InitializeComponent();
}
public void UpdateGrid(ObservableCollection<Product> productList)
{
calculateRowsCols(productList);
drawGrid(productList);
}
public void calculateRowsCols(ObservableCollection<Product> productList)
{
int tileCount = productList.Count();
double tileHeight = Grid.ActualHeight;
double tileWidth = Grid.ActualWidth;
if (tileCount == 0)
return;
double maxSize = Math.Sqrt((tileHeight * tileWidth) / tileCount);
double noOfTilesHeight = Math.Floor(tileHeight / maxSize);
double noOfTilesWidth = Math.Floor(tileWidth / maxSize);
double total = noOfTilesHeight * noOfTilesWidth;
cellSize = (maxSize < minSize) ? minSize : Convert.ToInt32(maxSize);
while ((cellSize >= minSize) && (total < tileCount))
{
cellSize--;
noOfTilesHeight = Math.Floor(tileHeight / cellSize);
noOfTilesWidth = Math.Floor(tileWidth / cellSize);
total = noOfTilesHeight * noOfTilesWidth;
}
rowsRequired = Convert.ToInt32(Math.Floor(tileHeight / cellSize));
colsRequired = Convert.ToInt32(Math.Floor(tileWidth / cellSize));
}
private void drawCell(int row, int col, string label, Color fill)
{
Rectangle innertec = new Rectangle();
innertec.Height = cellSize * 0.7;
innertec.Width = cellSize * 0.9;
innertec.StrokeThickness = 1;
innertec.Stroke = new SolidColorBrush(Colors.Black);
ImageBrush imageBrush = new ImageBrush();
imageBrush.ImageSource = new BitmapImage(new Uri("Assets/loading.png", UriKind.Relative));
innertec.Fill = imageBrush;
Grid.Children.Add(innertec);
Canvas.SetLeft(innertec, (col * cellSize) + ((cellSize - innertec.Width) / 2));
Canvas.SetTop(innertec, row * cellSize + 4);
Border productLabelBorder = new Border();
Grid.Children.Add(productLabelBorder);
Canvas.SetLeft(productLabelBorder, col * cellSize);
Canvas.SetTop(productLabelBorder, row * cellSize);
TextBlock productLabel = new TextBlock();
productLabel.Margin = new Thickness(0, innertec.Height + 5, 0, 5);
productLabel.TextAlignment = TextAlignment.Center;
productLabel.TextWrapping = TextWrapping.NoWrap;
productLabel.TextTrimming = TextTrimming.WordEllipsis;
productLabel.MaxWidth = cellSize;
productLabel.Height = cellSize * 0.3;
productLabel.Width = cellSize;
productLabel.Text = label;
productLabel.HorizontalAlignment = HorizontalAlignment.Center;
productLabel.VerticalAlignment = VerticalAlignment.Center;
productLabel.FontSize = cellSize * 0.13;
ToolTipService.SetToolTip(productLabel, label);
productLabelBorder.Child = productLabel;
}
public void drawGrid(ObservableCollection<Product> data)
{
int dataIndex = 0;
Grid.Children.Clear();
for (int i = 0; i < rowsRequired; i++)
{
for (int j = 0; j < colsRequired; j++)
{
Product product = (dataIndex < data.Count) ? data.ElementAt(dataIndex) : null;
if (product != null)
{
drawCell(i, j, product.productName, Colors.White);
}
dataIndex++;
}
}
}
}
Any help anyone can give, even a pointer in the right direction would be great.
Thanks in advance
Try creating custom control which will encapsulate everything you want from rectangle to do.
you can add new VisualState "MouseDownState" and do required animatin in xaml.
Please let me know if you need more details regarding the implementation.
late simply add new control instead of rectangle.

how to get the visible area of canvas in wpf

I am creating an application just like a paint in WPF, and I want to add zoom functionality to it. I am taking canvas as a parent and writable bitmap on it as child on which I draw. When the size of the canvas is small, I am drawing on writable bitmap smoothly, but when the size of the canvas is large, and zoom it, canvas size will be large, problem occur to draw on this large area. So I want to find the visible region of the canvas so that I can draw on it smoothly.
Please give me a source code to find the visible region of the canvas.
I have create this application:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Interop;
namespace MapDesigner.Controls
{
class MapCanvas : Canvas
{
#region Routed Events
public static readonly RoutedEvent SelectedColorChangeEvent = EventManager.RegisterRoutedEvent(
"SelectedColorChange", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ucToolBox));
public event RoutedEventHandler SelectedColorChange
{
add { AddHandler(SelectedColorChangeEvent, value); }
remove { RemoveHandler(SelectedColorChangeEvent, value); }
}
#endregion
#region Enums
public enum Tool
{
Pencil,
FloodFill,
Eraser,
RectSelect,
Brush,
Part
}
#endregion
WriteableBitmap _wBMP;
Image _dispImg = new Image();
ScaleTransform st = new ScaleTransform();
int canvasHeight, canvasWidth;
double zoomLevel = 1;
Border brdGrid = new Border();
Color cellColor = Colors.Black;
Tool currentTool = Tool.Pencil;
int[,] array;
bool drawing = false;
bool showGrids = true;
public TextBlock tbPos;
public Tool CurrentTool
{
get
{
return currentTool;
}
set
{
currentTool = value;
}
}
public Color CellColor
{
get
{
return cellColor;
}
set
{
cellColor = value;
}
}
public bool GridsVisible
{
get
{
return showGrids;
}
set
{
showGrids = value;
}
}
public MapCanvas()
{
this.Children.Clear();
this.Children.Add(_dispImg);
//st.ScaleX = 1;
//st.ScaleY = 1;
// this.LayoutTransform = st;
}
void Refresh()
{
//canvas = new MapCanvas();
this.Children.Clear();
this.Children.Add(_dispImg);
st.ScaleX = 1;
st.ScaleY = 1;
this.Height = 0;
this.Width = 0;
zoomLevel = 1;
drawing = false;
}
public void LoadBMP(Uri bmpUri)
{
Refresh();
BitmapImage bmi = new BitmapImage(bmpUri);
_wBMP = new WriteableBitmap(bmi);
_dispImg.Source = _wBMP;
this.Height = bmi.Height;
this.Width = bmi.Width;
ShowGrids();
}
public void CreateBMP(int width, int height)
{
Refresh();
_wBMP = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr32, BitmapPalettes.WebPalette);
_wBMP.setPixel(Colors.White);
_dispImg.Source = _wBMP;
this.Height = height;
this.Width = width;
ShowGrids();
}
public void CreateNewDesign(Size mapSize)
{
Refresh();
_wBMP = new WriteableBitmap((int)mapSize.Width, (int)mapSize.Width, 96, 96, PixelFormats.Bgr32, BitmapPalettes.WebPalette);
_wBMP.setPixel(Colors.White);
_dispImg.Source = _wBMP;
array = new int[(_wBMP.PixelHeight + 1), (_wBMP.PixelWidth + 1)];
canvasWidth = (int)mapSize.Width;
canvasHeight = (int)mapSize.Height;
this.Height = mapSize.Height;
this.Width = mapSize.Width;
ShowGrids();
}
void ShowGrids()
{
return;
double width = 1;// _tileWidth + _tileMargin;
double height = 1;// _tileHeight + _tileMargin;
double numTileToAccumulate = 16;
Polyline gridCell = new Polyline();
gridCell.Margin = new Thickness(.5);
gridCell.Stroke = Brushes.LightBlue;
gridCell.StrokeThickness = 0.1;
gridCell.Points = new PointCollection(new Point[] { new Point(0, height-0.1),
new Point(width-0.1, height-0.1), new Point(width-0.1, 0) });
VisualBrush gridLines = new VisualBrush(gridCell);
gridLines.TileMode = TileMode.Tile;
gridLines.Viewport = new Rect(0, 0, 1.0 / numTileToAccumulate, 1.0 / numTileToAccumulate);
gridLines.AlignmentX = AlignmentX.Center;
gridLines.AlignmentY = AlignmentY.Center;
VisualBrush outerVB = new VisualBrush();
Rectangle outerRect = new Rectangle();
outerRect.Width = 10.0; //can be any size
outerRect.Height = 10.0;
outerRect.Fill = gridLines;
outerVB.Visual = outerRect;
outerVB.Viewport = new Rect(0, 0,
width * numTileToAccumulate, height * numTileToAccumulate);
outerVB.ViewportUnits = BrushMappingMode.Absolute;
outerVB.TileMode = TileMode.Tile;
this.Children.Remove(brdGrid);
brdGrid = new Border();
brdGrid.Height = this.Height;
brdGrid.Width = this.Width;
brdGrid.Background = outerVB;
this.Children.Add(brdGrid);
}
protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
{
base.OnMouseMove(e);
tbPos.Text = (_wBMP.PixelWidth / zoomLevel).ToString() + "," + (_wBMP.PixelHeight / zoomLevel).ToString() + " | " + Math.Ceiling((((Point)e.GetPosition(this)).X) / zoomLevel).ToString() + "," + Math.Ceiling((((Point)e.GetPosition(this)).Y / zoomLevel)).ToString();
if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
{
Point pos = e.GetPosition(this);
int xPos = (int)Math.Ceiling((pos.X) / zoomLevel);
int yPos = (int)Math.Ceiling((pos.Y) / zoomLevel);
int xDraw = (int)Math.Ceiling(pos.X);
int yDraw = (int)Math.Ceiling(pos.Y);
array[xPos, yPos] = 1;
drawing = true;
SetPixelsFromArray((int)zoomLevel);
//for (int i = 0; i < zoomLevel; i++)
//{
// for (int j = 0; j < zoomLevel; j++)
// {
// _wBMP.setPixel(xDraw, yDraw, cellColor);
// _dispImg.Source = _wBMP;
// }
//}
//_wBMP.setPixel(xPos, yPos, cellColor);
//_wBMP.setPixel((int)pos.X, (int)pos.Y, cellColor);
//_dispImg.Source = _wBMP;
}
}
private void SetPixelsFromArray(int ZoomLevel)
{
for (int i = 1; i < _wBMP.PixelWidth / ZoomLevel; i++)
{
for (int j = 1; j < _wBMP.PixelHeight / ZoomLevel; j++)
{
if (array[i, j] == 1)
{
for (int k = 0; k < ZoomLevel; k++)
{
for (int l = 0; l < ZoomLevel; l++)
{
_wBMP.setPixel((int)(i * ZoomLevel + k), (int)(j * ZoomLevel + l), cellColor);
_dispImg.Source = _wBMP;
}
}
}
}
}
}
protected override void OnMouseUp(System.Windows.Input.MouseButtonEventArgs e)
{
//double d= this.ActualHeight;
//Double t =(double) this.GetValue(Canvas.TopProperty);
//double i = Convert.ToDouble(top);
getScreenRect();
if (e.ChangedButton == System.Windows.Input.MouseButton.Right)
{
if (cellColor == Colors.Black)
{
cellColor = Colors.Red;
}
else
{
cellColor = Colors.Black;
}
}
else if (e.ChangedButton == System.Windows.Input.MouseButton.Left)
{
Point pos = e.GetPosition(this);
int xPos = (int)Math.Ceiling((pos.X) / zoomLevel);
int yPos = (int)Math.Ceiling((pos.Y) / zoomLevel);
array[xPos, yPos] = 1;
drawing = true;
SetPixelsFromArray((int)zoomLevel);
//_wBMP.setPixel((int)pos.X, (int)pos.Y, cellColor);
//_dispImg.Source = _wBMP;
}
}
private void getScreenRect()
{
Visual _rootVisual = HwndSource.FromVisual(this).RootVisual;
GeneralTransform transformToRoot = this.TransformToAncestor(_rootVisual);
Rect screenRect = new Rect(transformToRoot.Transform(new Point(0, 0)), transformToRoot.Transform(new Point(this.ActualWidth, this.ActualHeight)));
DependencyObject parent = VisualTreeHelper.GetParent(this);
while (parent != null)
{
Visual visual = parent as Visual;
System.Windows.Controls.Control control = parent as System.Windows.Controls.Control;
if (visual != null && control != null)
{
transformToRoot = visual.TransformToAncestor(_rootVisual);
Point pointAncestorTopLeft = transformToRoot.Transform(new Point(0, 0));
Point pointAncestorBottomRight = transformToRoot.Transform(new Point(control.ActualWidth, control.ActualHeight));
Rect ancestorRect = new Rect(pointAncestorTopLeft, pointAncestorBottomRight);
screenRect.Intersect(ancestorRect);
}
parent = VisualTreeHelper.GetParent(parent);
//}
// at this point screenRect is the bounding rectangle for the visible portion of "this" element
}
// return screenRect;
}
protected override void OnMouseWheel(System.Windows.Input.MouseWheelEventArgs e)
{
base.OnMouseWheel(e);
if (e.Delta > 0)
{
zoomLevel *= 2;
}
else
{
zoomLevel /= 2;
}
if (zoomLevel > 8)
{
zoomLevel = 8;
}
if (zoomLevel <= 1)
{
zoomLevel = 1;
// brdGrid.Visibility = Visibility.Collapsed;
}
else
{
//brdGrid.Visibility = Visibility.Visible;
}
_wBMP = new WriteableBitmap((int)zoomLevel * canvasWidth, (int)zoomLevel * canvasHeight, 96, 96, PixelFormats.Bgr32, BitmapPalettes.WebPalette);
_wBMP.setPixel(Colors.White);
this.Width = zoomLevel * canvasWidth;
this.Height = zoomLevel * canvasHeight;
if (drawing == true)
{
SetPixelsFromArray((int)zoomLevel);
}
//this.InvalidateVisual();
}
internal bool SaveAsBMP(string fileName)
{
return true;
}
}
public static class bitmapextensions
{
public static void setPixel(this WriteableBitmap wbm, Color c)
{
if (!wbm.Format.Equals(PixelFormats.Bgr32))
return;
wbm.Lock();
IntPtr buff = wbm.BackBuffer;
int Stride = wbm.BackBufferStride;
int x = 0;
int y = 0;
for (x = 0; x < wbm.PixelWidth; x++)
{
for (y = 0; y < wbm.PixelHeight; y++)
{
unsafe
{
byte* pbuff = (byte*)buff.ToPointer();
int loc = y * Stride + x * 4;
pbuff[loc] = c.B;
pbuff[loc + 1] = c.G;
pbuff[loc + 2] = c.R;
//pbuff[loc + 3] = c.A;
}
}
}
wbm.AddDirtyRect(new Int32Rect(0, 0, x, y));
wbm.Unlock();
}
public static void setPixel(this WriteableBitmap wbm, int x, int y, Color c)
{
if (y > wbm.PixelHeight - 1 || x > wbm.PixelWidth - 1)
return;
if (y < 0 || x < 0)
return;
if (!wbm.Format.Equals(PixelFormats.Bgr32))
return;
wbm.Lock();
IntPtr buff = wbm.BackBuffer;
int Stride = wbm.BackBufferStride;
unsafe
{
byte* pbuff = (byte*)buff.ToPointer();
int loc = y * Stride + x * 4;
pbuff[loc] = c.B;
pbuff[loc + 1] = c.G;
pbuff[loc + 2] = c.R;
//pbuff[loc + 3] = c.A;
}
wbm.AddDirtyRect(new Int32Rect(x, y, 1, 1));
wbm.Unlock();
}
public static Color getPixel(this WriteableBitmap wbm, int x, int y)
{
if (y > wbm.PixelHeight - 1 || x > wbm.PixelWidth - 1)
return Color.FromArgb(0, 0, 0, 0);
if (y < 0 || x < 0)
return Color.FromArgb(0, 0, 0, 0);
if (!wbm.Format.Equals(PixelFormats.Bgr32))
return Color.FromArgb(0, 0, 0, 0);
IntPtr buff = wbm.BackBuffer;
int Stride = wbm.BackBufferStride;
Color c;
unsafe
{
byte* pbuff = (byte*)buff.ToPointer();
int loc = y * Stride + x * 4;
c = Color.FromArgb(pbuff[loc + 3], pbuff[loc + 2], pbuff[loc + 1], pbuff[loc]);
}
return c;
}
}
}
You should implement IScrollInfo on your canvas (or actually, create a custom Panel that inherits from Canvas and implements IScrollInfo).
That interface holds all that is relevant to your situation:
http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.iscrollinfo.aspx
http://blogs.msdn.com/b/jgoldb/archive/2008/03/08/performant-virtualized-wpf-canvas.aspx

Resources