Efficient way to draw a single point on canvas - c#

I am looking for a way to draw a single point (with a color) on C# canvas.
In android I would do something like
paint.Color = Color.Rgb (10, 10, 10);
canvas.DrawPoint (x, y, paint);
So I thought that I would be able to find it in the Shape class, but it was not there. Am I missing something or there is no way to draw a single point?
In the second case, what is a recommended way of drawing a point? In HTML5 canvas there is a similar problem and people are drawing points using rectangles/circles.
P.S. a question with similar title Add Point to Canvas is not answering it and moving into "how to draw a shape".

I just ran in the same question for UWP, I finally decided to use an Ellipse:
int dotSize = 10;
Ellipse currentDot = new Ellipse();
currentDot.Stroke = new SolidColorBrush(Colors.Green);
currentDot.StrokeThickness = 3;
Canvas.SetZIndex(currentDot, 3);
currentDot.Height = dotSize;
currentDot.Width = dotSize;
currentDot.Fill = new SolidColorBrush(Colors.Green);
currentDot.Margin = new Thickness(100, 200, 0, 0); // Sets the position.
myGrid.Children.Add(currentDot);

What about a Polyline?
xaml:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Canvas x:Name="canvas" Background="#00FFFFFF" MouseMove="Canvas_MouseMove">
<Polyline x:Name="polyline" Stroke="DarkGreen" StrokeThickness="3"/>
</Canvas>
</Grid>
c#:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
polyline.Points.Add(new Point(0,0));
polyline.Points.Add(new Point(0, 1));
polyline.Points.Add(new Point(1, 0));
polyline.Points.Add(new Point(1, 1));
}

Related

Why are my polygons being drawn in the wrong location?

I am practicing C# basic WPF/XAML drawing for an assignment and right off the bat I cannot figure out why my polygons are being drawn in the wrong place.
My window is of 1280x720 fixed, non-resizeable. I am trying to programmatically create my polygons by:
Creating points in the coordinates I want them to be:
`
[0,0]
[max height, 0],
[max height, max width],
[0, max width],
[max height/2, max width/2]
`
Creating polygons that consists of three points each, [0,0] and two edges. My screen is supposed to be split into four triangles.
I tried breaking down the code to something really explicit to see if I could figure out where the issue is, so this is what I have:
private void CreatePolygons()
{
List<Point> PointList = new List<Point>
{
new Point(MainUI.Height / 2, MainUI.Width / 2),
new Point(0, 0),
new Point(0, MainUI.Height),
new Point(MainUI.Width, MainUI.Height),
new Point(MainUI.Width, 0)
};
Polygon p1 = new Polygon();
Polygon p2 = new Polygon();
Polygon p3 = new Polygon();
Polygon p4 = new Polygon();
p1.Points.Add(PointList[0]);
p1.Points.Add(PointList[1]);
p1.Points.Add(PointList[2]);
p2.Points.Add(PointList[0]);
p2.Points.Add(PointList[2]);
p2.Points.Add(PointList[3]);
p3.Points.Add(PointList[0]);
p3.Points.Add(PointList[3]);
p3.Points.Add(PointList[4]);
p4.Points.Add(PointList[0]);
p4.Points.Add(PointList[4]);
p4.Points.Add(PointList[1]);
p1.Stroke = System.Windows.Media.Brushes.LightSkyBlue;
p2.Stroke = System.Windows.Media.Brushes.LightSkyBlue;
p3.Stroke = System.Windows.Media.Brushes.LightSkyBlue;
p4.Stroke = System.Windows.Media.Brushes.LightSkyBlue;
p1.StrokeThickness = 1;
p2.StrokeThickness = 1;
p3.StrokeThickness = 1;
p4.StrokeThickness = 1;
MainGrid.Children.Add(p1);
MainGrid.Children.Add(p2);
MainGrid.Children.Add(p3);
MainGrid.Children.Add(p4);
}
The end result is a completely misplaced grid and I can't understand what the coordinates it ended up creating refer to:
What am I missing?
You have accidentally swapped the Width and Height in the first point:
new Point(MainUI.Height / 2, MainUI.Width / 2),
Should be:
new Point(MainUI.Width / 2, MainUI.Height / 2),
Further, assuming MainUI is the app window itself, the points will still be a bit off, because the Height of the window includes its title bar height. You should better use MainGrid.ActualWidth and MainGrid.ActualHeight:
List<Point> PointList = new List<Point>
{
new Point(MainGrid.ActualWidth / 2, MainGrid.ActualHeight / 2),
new Point(0, 0),
new Point(0, MainGrid.ActualHeight),
new Point(MainGrid.ActualWidth, MainGrid.ActualHeight),
new Point(MainGrid.ActualWidth, 0)
};
As an alternative to all the Polygon point calcuations, you may use this simple Path element, which produces the same output and stretches automatically:
<Grid>
<Path Stretch="Fill" Stroke="LightSkyBlue" StrokeThickness="1"
Data="M0,0 L1,0 1,1 0,1Z M0,0 L1,1 M0,1 L1,0"/>
</Grid>
Besides that you have confused Width and Height of the first point, I'd suggest not to create UI elements like Polygons in code behind. Better use an ItemsControl like this:
<Grid SizeChanged="MainUISizeChanged">
<ItemsControl x:Name="polygons">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Polygon Stroke="LightSkyBlue" StrokeThickness="1"
Points="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
and assign its ItemsSource property to a collection of PointCollections, e.g. whenever the size of your MainUI element changes:
private void MainUISizeChanged(object sender, SizeChangedEventArgs e)
{
var points = new List<Point>
{
new Point(e.NewSize.Width / 2, e.NewSize.Height / 2),
new Point(0, 0),
new Point(0, e.NewSize.Height),
new Point(e.NewSize.Width, e.NewSize.Height),
new Point(e.NewSize.Width, 0)
};
polygons.ItemsSource = new List<PointCollection>
{
new PointCollection(new Point[] { points[0], points[1], points[2] }),
new PointCollection(new Point[] { points[0], points[2], points[3] }),
new PointCollection(new Point[] { points[0], points[3], points[4] }),
new PointCollection(new Point[] { points[0], points[4], points[1] }),
};
}

How to resize a FileModelVisual3D in a helix Viewport with Codebehind WPF

i am a real newbe in the world of helixtoolkit and Graphics 3D.
What i make:
I have the homework to code a programm which lets you decorate a christmastree with different types of decoration.
One type of decoration is a candle. The problem. The candle is too small in relation to the tree.
My question:
How can i resize my FileModelVisual3D inside of the view_tree with code behind?
private void view_tree_MouseDown(object sender, MouseButtonEventArgs e)
{
if (typeOfdecoration == 1)
{
Decoration1Visual3D decoration;
decoration = new Decoration1Visual3D();
decoration.Fill = Brushes.Red;
Point3D? pt = view_tree.FindNearestPoint(e.GetPosition(view_tree));
if (pt.HasValue)
{
Point3D p = pt.Value;
decoration.Transform = new TranslateTransform3D(p.X, p.Y, p.Z);
view_tree.Children.Add(decoration);
MessageBox.Show(decoration.ToString());
decoration = null;
}
}
else if (typeOfdecoration == 2)
{
FileModelVisual3D fmv3D = new FileModelVisual3D();
fmv3D.Source = "C:/Users/flori/Documents/Schulisches/WFSST/christmastree_burtscherflorian/christmastree_burtscherflorian/2245176fd65db964db79f88f870f8154/candle.3DS";
Point3D? pt = view_tree.FindNearestPoint(e.GetPosition(view_tree));
if (pt.HasValue)
{
Point3D p = pt.Value;
fmv3D.Transform = new TranslateTransform3D(p.X, p.Y, p.Z);
view_tree.Children.Add(fmv3D);
MessageBox.Show(fmv3D.ToString());
fmv3D = null;
}
}
}
XAML-Code
<helix:HelixViewport3D x:Name="view_tree" Camera="{helix:PerspectiveCamera 5.3,-12.3,900,-6.3,11,-6.6}" CameraChanged="view_tree_CameraChanged" MouseDown="view_tree_MouseDown" Grid.Row="0" Grid.Column="0">
<helix:SunLight/>
<helix:FileModelVisual3D x:Name="model_tree" Source="c:/Users/flori/Documents/Schulisches/WFSST/christmastree_burtscherflorian/christmastree_burtscherflorian/Conifers tree 1 N100616.3DS"/>
</helix:HelixViewport3D>
<StackPanel Grid.Row="0" Grid.Column="1">
<RadioButton Name="rb_candle" Margin="10,10,10,0" IsChecked="True" Checked="rb_candle_Checked">Kerze</RadioButton>
<RadioButton Name="rb_ball" Margin="10,10,10,10" Checked="rb_candle_Checked">Kugel</RadioButton>
</StackPanel>
Hope that anybode can help!
I know for others its easy but i have no experiences in 3D-coding.
Thanks
In addition to your TranslateTransform3D, apply a ScaleTransform3D. Put both of them into a Transform3DGroup and use this as Transform on your FileModelVisual3D:
double factor = 2.0;
var transformGroup = new Transform3DGroup();
transformGroup.Children.Add(new TranslateTransform3D(p.X, p.Y, p.Z));
transformGroup.Children.Add(new ScaleTransform3D(factor, factor, factor));
fmv3D.Transform = transformGroup;
Of course, you may want to adjust the factor.

Touch on screen in windows phone 8.1 RT

I am building an application to find dead pixels on the screen and I get a big problem that I can not solve by myself. My code uses to draw a rectangle on the screen at the point that user touch on.
My XAML code:
<Grid x:Name="mainGrid" Background="Gray">
<Canvas x:Name="myCanvas" Background="Purple" PointerMoved="digitizerGrid_PointerMoved" PointerReleased="digitizerGrid_PointerReleased">
<Grid x:Name="digitizerGrid" Visibility="Visible"/>
</Canvas>
</Grid>
and my c# code to handle event:
private void digitizerGrid_PointerMoved(object sender, PointerRoutedEventArgs e)
{
PointerPoint pt = e.GetCurrentPoint(myCanvas);
Point currentContactPt = pt.Position;
double x2 = currentContactPt.X;
double y2 = currentContactPt.Y;
Rectangle rect = new Rectangle()
{
Width = 50,
Height = 50,
StrokeThickness = 20.0,
Fill = new SolidColorBrush(Colors.Green)
};
Canvas.SetLeft(rect, x2);
Canvas.SetTop(rect, y2);
myCanvas.Children.Add(rect);
}
When I touch and fill all the screen like this:
I get the wrong result image below with black pixel blocks:
So I can not detect where is dead pixels. What I was wrong?
Thank in advance!

restoring image back to same position after tombstoning in WP7

I m using MouseDragElementBehavior in my WP7 application to drag an image down the canvas. I m able to get the coordinates (X,Y positions) after the image dragging. But I want to retain the same image position after tombstoning also.
private void MouseDragElementBehavior_Dragging(object sender, MouseEventArgs e)
{
Point currentPos = e.GetPosition(image1);
if (currentPos.X < 190)
{
double targetOffset = 700;
DoubleAnimation animation = new DoubleAnimation();
animation.EasingFunction = new CircleEase();
animation.Duration = new Duration(new TimeSpan(0, 0, 10));
animation.From = TextScroll.AnimatableOffset;
animation.To = targetOffset;
Storyboard.SetTarget(animation, TextScroll);
Storyboard.SetTargetProperty(animation, new PropertyPath("(AnimatableScrollViewer.AnimatableOffset)"));
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin();
}
App app = (App)Application.Current;
app.current_X = currentPos.X.ToString();
app.current_Y = currentPos.Y.ToString();
TextScroll.AnimatableOffset = -700;
}
I have stored and retrived the values from isolated storage for tombstoning.
private void LoadSettings()
{
var settings = IsolatedStorageSettings.ApplicationSettings;
current_X = settings["Xpos"].ToString();
current_Y = settings["Ypos"].ToString();
}
private void SaveSettings()
{
var settings = IsolatedStorageSettings.ApplicationSettings;
settings.Add("Xpos", current_X);
settings.Add("Ypos",current_Y);
settings.Save();
}
Now I would like to use the values to position the image at the same coordinates as before tombstoning. I dont know how to position the image with the X and Y coordinates provided.
Here is the XAML code where I use the image.
<Canvas Margin="12,0,3,-834" Grid.Row="1">
<Image Height="800" Source="37.jpg" Stretch="Fill" Width="480" Canvas.Left="-11" x:Name="image1">
<i:Interaction.Behaviors>
<el:MouseDragElementBehavior ConstrainToParentBounds="True" Dragging="MouseDragElementBehavior_Dragging" />
</i:Interaction.Behaviors>
</Image>
</Canvas>
First, Point currentPos = e.GetPosition(image1); is getting the position of the mouse relative to the image. Maybe you want to get the position relative to the canvas instead?
Or, you can use this to get the position within the canvas:
canvas1.GetLeft(image1);
canvas1.GetTop(image1);
Then, you can set the position of something within a canvas like this:
canvas1.SetLeft(image1, x);
canvas1.SetTop(image1, y);
To do that, you would need to name your Canvas:
<Canvas x:Name="canvas1" Margin="12,0,3,-834" Grid.Row="1">

How can I do both zoom and rotate on an inkcanvas?

Using the following XAML:
<Grid x:Name="grid" Background="LightBlue" ClipToBounds="True">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Viewbox x:Name="imgViewbox" >
<InkCanvas Grid.Row="0" Name="inkCanvas" Background="Red" >
<Image Source="Images/pic.png" HorizontalAlignment="Left" x:Name="imgObject" VerticalAlignment="Top" />
<Label>Testing</Label>
</InkCanvas>
</Viewbox>
</Grid>
I am trying to rotate around the center of the image and also use the wheel mouse to zoom. I have set up this transform group and event:
public MainWindow() {
InitializeComponent();
DataContext = new MainWindowViewModel();
transformGroup = new TransformGroup();
scaleTransform = new ScaleTransform();
rotateTransform = new RotateTransform();
translateTransform = new TranslateTransform();
transformGroup.Children.Add(rotateTransform);
transformGroup.Children.Add(scaleTransform);
transformGroup.Children.Add(translateTransform);
imgViewbox.RenderTransform = transformGroup;
imgViewbox.MouseWheel += ImageViewboxMouseWheel;
}
Rotate is simple:
void Rotate(object sender, RoutedEventArgs e) {
//imgViewbox.RenderTransformOrigin = new Point(0.5,0.5);
rotateTransform.Angle += 90;
}
but zoom is doing all sorts of weird stuff jumping around the screen. The code for zoom is here:
void ImageViewboxMouseWheel(object sender, MouseWheelEventArgs e) {
//imgViewbox.RenderTransformOrigin = new Point(0, 0);
double zoomFactor = DefaultZoomFactor;
if (e.Delta <= 0) zoomFactor = 1.0 / DefaultZoomFactor;
// DoZoom requires both the logical and physical location of the mouse pointer
var physicalPoint = e.GetPosition(imgViewbox);
if (transformGroup.Inverse != null) {
DoZoom(zoomFactor, transformGroup.Inverse.Transform(physicalPoint), physicalPoint);
}
else {
throw new ArgumentException("Missing Inverse");
}
//Set the center point of the ScaleTransform object to the cursor location.
scaleTransform.CenterX = e.GetPosition(imgViewbox).X;
scaleTransform.CenterY = e.GetPosition(imgViewbox).Y;
Debug.WriteLine(string.Format("IVMW Center {0},{1}", scaleTransform.CenterX, scaleTransform.CenterY));
}
public void DoZoom(double deltaZoom, Point mousePosition, Point physicalPosition) {
double currentZoom = scaleTransform.ScaleX;
currentZoom *= deltaZoom;
translateTransform.X = -1*(mousePosition.X*currentZoom - physicalPosition.X);
translateTransform.Y = -1*(mousePosition.X*currentZoom - physicalPosition.Y);
scaleTransform.ScaleX = currentZoom;
scaleTransform.ScaleY = currentZoom;
}
I have removed as much as I can, animations and such. Hopefully leaving only the key parts. I believe that the major problem is the scaleTransform.Center[X|Y] as the numbers that are being returned are all over the quadrant even when I try to click exactly in the same location. The RenderTransformOrigin doesn't seem to make any difference with the Center position but I am aware that I need it to rotate around center.
What am I doing wrong?
You need to offset the jump you get from changing the ScaleTranform's CenterX/Y in the TranslateTransform, here is a snippet from a pan & zoom control i wrote:
private void This_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (IsZoomEnabled)
{
Point cursorPos = e.GetPosition(this);
Point newCenter = _scaleT.Inverse.Transform(_translateT.Inverse.Transform(cursorPos));
Point oldCenter = new Point(_scaleT.CenterX, _scaleT.CenterY);
Vector oldToNewCenter = newCenter - oldCenter;
_scaleT.CenterX = newCenter.X;
_scaleT.CenterY = newCenter.Y;
_translateT.X += oldToNewCenter.X * (_scaleT.ScaleX - 1.0);
_translateT.Y += oldToNewCenter.Y * (_scaleT.ScaleY - 1.0);
...
Hopefully you can adapt this to your code. Where the new center is calculated you might need to take your RotateTransform into account.

Categories

Resources