I need to make a background looks like this:
I found the way to do it with <DrawingBrush TileMode="Tile"> but it's not allow to make a gradient, because this generats many repeating squares. Maybe exists any ways to do it dynamicly, not in xaml?
I had to do something very similar and chose to create a grid dynamically in C#, the method was called upon on the Canvas-loaded event.
The "max_value" is the max size in pixels you want the grid to be, I set mine to 3500.
The "ScaleFactor" is the spacing in between the lines/ the size of the squares, I set mine to 15.
The "Canvas" is simply the canvas you want to apply the grid too.
I did have to extract the code and tweak it from a larger program but it should still work, but I don't have an IDE to test it currently.
class GridLine //Declares a grid-line object
{ //Declares a variety of different line lists, used for different parts of the grid.
private List<Line> XGridline { get; set; } = new List<Line>();
private List<Line> YGridline { get; set; } = new List<Line>();
private Line[] Axis { get; set; } = new Line[2];
//Used to draw the grid.
public GridLine DrawGrid(int max_value, int scale_factor, Canvas canvas) //Draws the grid
{
int x = 0;
int y = 0;
while (x < max_value) // Used to draw lines from the center out to the far right.
{
YGridline.Add(new Line() {
Stroke = new SolidColorBrush(Colors.Black),
StrokeThickness = 2,
X1 = x,
Y1 = -max_value,
X2 = x,
Y2 = max_value
});
canvas.Children.Add(YGridline[YGridline.Count - 1]);
x += scale_factor;
}
x = 0;
y = 0;
while (x > -max_value) //used to draw lines from the center to the far left.
{
YGridline.Add(new Line() {StrokeThickness = 2,
Stroke = new SolidColorBrush(Colors.Black),
X1 = x ,
Y1 = -max_value,
X2 = x,
Y2 = max_value
});
canvas.Children.Add(YGridline[YGridline.Count - 1]);
x -= scale_factor;
}
y = 0;
x = 0;
while (y < max_value) //used to draw lines from the center to the bottom
{
XGridline.Add(new Line() {
Stroke = new SolidColorBrush(Colors.Black),
StrokeThickness = 2,
X1 = -max_value,
Y1 = y,
X2 = max_value,
Y2 = y
});
canvas.Children.Add(XGridline[XGridline.Count - 1]);
y += scale_factor;
}
y = 0;
x = 0;
while (y > -max_value) //Used to draw lines from the center to the top.
{
XGridline.Add(new Line() {
Stroke = new SolidColorBrush(Colors.Black),
StrokeThickness = 2,
X1 = -max_value,
Y1 = y,
X2 = max_value,
Y2 = y
});
canvas.Children.Add(XGridline[XGridline.Count - 1]);
y -= scale_factor;
}
//VERTICLE LINE- Y Axis
Axis[0] = (new Line() { Stroke = new SolidColorBrush(Colors.Black), StrokeThickness = 3, X1 = 0, Y1 = -max_value, X2 = 0, Y2 = max_value });
canvas.Children.Add(Axis[0]);
//Horizontal line - X Axis
Axis[1] = (new Line() { Stroke = new SolidColorBrush(Colors.Black), StrokeThickness = 3, X1 = -max_value, Y1 = 0, X2 = max_value, Y2 = 0 });
canvas.Children.Add(Axis[1]);
return this;
}
}
EDIT:
If you'd just like to have a gradient background, why don't you set the rectangles to have no/ a transparent fill then set a gradient background behind them? I would still suggest looking at my code, because depending on what you intend to do with the grid later you may find it easier to generate a grid pragmatically.
Related
I want to draw Arc in Vieport3D using MeshGeometry3D.I have searched for it a lot but not found anything ,what I found is using PathGeometry.I am new to WPF so don't know much about 3D graphics.How can I do this?
thanks
here is the code which I wrote to create mesh-geometry for Arc.I hope this will help someone.
private GeometryModel3D GetModel(double radius, Vector3D normal, Point3D center, int resolution, double StartAngle, double EndAngle)
{
var mod = new GeometryModel3D();
var geo = new MeshGeometry3D();
// Generate the circle in the XZ-plane
// Add the center first
geo.Positions.Add(new Point3D(0, 0, 0));
// Iterate from angle 0 to 2*PI
double dev = (2 * Math.PI) / resolution;
double thik = 0.02;
//float spaceangle = StartAngle + 1;
if (StartAngle != EndAngle)
{
for (double i = StartAngle; i < EndAngle; i += dev)
{
geo.Positions.Add(new Point3D(radius * Math.Cos(i), 0, -radius * Math.Sin(i)));
geo.Positions.Add(new Point3D((radius-thik) * Math.Cos(i), 0, (-(radius-thik)) * Math.Sin(i)));
}
for (int i = 3; i < geo.Positions.Count; i += 1)
{
geo.TriangleIndices.Add(i - 3);
geo.TriangleIndices.Add(i - 1);
geo.TriangleIndices.Add(i - 2);
geo.TriangleIndices.Add(i - 1);
geo.TriangleIndices.Add(i);
geo.TriangleIndices.Add(i - 2);
}
}
mod.Geometry = geo;
// Create transforms
var trn = new Transform3DGroup();
// Up Vector (normal for XZ-plane)
var up = new Vector3D(0, 1, 0);
// Set normal length to 1
normal.Normalize();
var axis = Vector3D.CrossProduct(up, normal); // Cross product is rotation axis
var angle = Vector3D.AngleBetween(up, normal); // Angle to rotate
trn.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(axis, angle)));
trn.Children.Add(new TranslateTransform3D(new Vector3D(center.X, center.Y, center.Z)));
mod.Transform = trn;
return mod;
}
Need to divide a UserControl with a background picture into multiple small clickable areas. Clicking them should simply raise an event, allowing to determine which particular area of the picture was clicked.
The obvious solution is using transparent labels. However, they are heavily flickering. So it looks like labels are not designed for this purpose, they take too much time to load.
So I'm thinking if any lighter option exists? To logically "slice up" the surface.
I also need a border around the areas, though.
on the user control do:
MouseClick += new System.Windows.Forms.MouseEventHandler(this.UserControl1_MouseClick);
and now in the UserControl1_MouseClick event do:
private void UserControl1_MouseClick(object sender, MouseEventArgs e)
{
int x = e.X;
int y = e.Y;
}
now let's divide the user control to a 10x10 area:
int xIdx = x / (Width / 10);
int yIdx = y / (Height / 10);
ClickOnArea(xIdx, yIdx);
in ClickOnArea method you just need to decide what to do in each area. maybe using a 2d array of Action
as for the border do this:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
Pen p = new Pen(Color.Black);
float xIdx = (float)(Width / 10.0);
float yIdx = (float)(Height / 10.0);
for (int i = 0; i < 10; i++)
{
float currVal = yIdx*i;
g.DrawLine(p, 0, currVal, Width, currVal);
}
g.DrawLine(p, 0, Height - 1, Width, Height - 1);
for (int j = 0; j < 10; j++)
{
float currVal = xIdx * j;
g.DrawLine(p, currVal, 0, currVal, Height);
}
g.DrawLine(p, Width - 1, 0, Width - 1, Height);
}
How to create a circle in 3D with known center point, radius and it is on a plane which perpendicular to a line (vector) in WPF?
Following is an example based on the comment I posted earlier.
First we define a function to generate the model of the circle:
/// <summary>
/// Generates a model of a Circle given specified parameters
/// </summary>
/// <param name="radius">Radius of circle</param>
/// <param name="normal">Vector normal to circle's plane</param>
/// <param name="center">Center position of the circle</param>
/// <param name="resolution">Number of slices to iterate the circumference of the circle</param>
/// <returns>A GeometryModel3D representation of the circle</returns>
private GeometryModel3D GetCircleModel(double radius, Vector3D normal, Point3D center, int resolution)
{
var mod = new GeometryModel3D();
var geo = new MeshGeometry3D();
// Generate the circle in the XZ-plane
// Add the center first
geo.Positions.Add(new Point3D(0, 0, 0));
// Iterate from angle 0 to 2*PI
double t = 2 * Math.PI / resolution;
for (int i = 0; i < resolution; i++)
{
geo.Positions.Add(new Point3D(radius * Math.Cos(t * i), 0, -radius * Math.Sin(t * i)));
}
// Add points to MeshGeoemtry3D
for (int i = 0; i < resolution; i++)
{
var a = 0;
var b = i + 1;
var c = (i < (resolution - 1)) ? i + 2 : 1;
geo.TriangleIndices.Add(a);
geo.TriangleIndices.Add(b);
geo.TriangleIndices.Add(c);
}
mod.Geometry = geo;
// Create transforms
var trn = new Transform3DGroup();
// Up Vector (normal for XZ-plane)
var up = new Vector3D(0, 1, 0);
// Set normal length to 1
normal.Normalize();
var axis = Vector3D.CrossProduct(up, normal); // Cross product is rotation axis
var angle = Vector3D.AngleBetween(up, normal); // Angle to rotate
trn.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(axis, angle)));
trn.Children.Add(new TranslateTransform3D(new Vector3D(center.X, center.Y, center.Z)));
mod.Transform = trn;
return mod;
}
Setting up our ViewPort3D:
<Grid Background="Black">
<Viewport3D Name="mainViewPort">
<Viewport3D.Camera>
<PerspectiveCamera NearPlaneDistance="0.1" FarPlaneDistance="100" UpDirection="0,1,0" Position="0,0,10"
LookDirection="0,0,-1" FieldOfView="60" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<AmbientLight Color="#40FFFFFF" />
<DirectionalLight Color="#FFFFFF" Direction="1,-1,-1" />
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
Then to test:
private void AddCircleModel()
{
var mod = GetCircleModel(1.5, new Vector3D(0, 1, 1), new Point3D(0, -1, 0), 20);
mod.Material = new DiffuseMaterial(Brushes.Silver);
var vis = new ModelVisual3D() { Content = mod };
mainViewPort.Children.Add(vis);
}
Load up your window, call AddCircleModel(); and enjoy. Adjust view/parameters to your heart's content.
old thread but still, if anyone comes accross.
The "newb" Answer would work but is quitte lazy math and time consuming wize, here's why :
there are 2 for loops where really 1 is needed.
using transform after building a circle on (x,z) plane centered on (0,0,0) is overkill since you know the maths and vectors constraints.
I would suggest you implement it that way (i made it so it works for ellipses too, just set uSize = vSize for circles, u and v really just need to no be parallel for it to work but for mesh quality purposes i force them to be perpendicular):
public static Mesh CreateEllipse3D(Vector3 center, Vector3 normal, Vector3 u,
Vector3 v, float uSize, float vSize, int
subdiv = 30)
{
if (Math.Abs(Vector3.Dot(u, v)) != 0)
{
Debug.LogError("Vectors u and v must be orthogonals");
return new Mesh();
}
var mesh = new Mesh();
var vertices = new List<Vector3>();
var normals = new List<Vector3>();
var triangles = new List<int>();
vertices.Add(center);
float t = 2 * Mathf.PI / subdiv;
int a = 0, b, c;
for (int i = 0; i < subdiv; i++)
{
vertices.Add(center + u.normalized * uSize * Mathf.Cos(t * i) -
v.normalized * vSize * Mathf.Sin(t * i));
b = i + 1;
c = (i < (subdiv - 1)) ? i + 2 : 1;
triangles.Add(a);
triangles.Add(b);
triangles.Add(c);
normals.Add(normal);
normals.Add(normal);
normals.Add(normal);
}
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.normals = normals.ToArray();
return mesh;
}
The following code draw several triangles only if with Sleep(1), without sleeping it draws only one triangle:
public void Draw(Graphics g)
{
int count = 3;
for (int i = 0; i < count; i++)
{
System.Drawing.Color color = GetColor();
System.Drawing.Point[] points = GetTriangle();
g.FillPolygon(new System.Drawing.SolidBrush(color), points);
//System.Threading.Thread.Sleep(1);
}
}
Where is this code wrong?
Here is the code of routings:
private System.Drawing.Color GetColor()
{
Random rand = new Random((int)DateTime.Now.Ticks);
byte a = (byte)rand.Next(100); a += 155;
byte r = (byte)rand.Next(255);
byte g = (byte)rand.Next(255);
byte b = (byte)rand.Next(255);
return System.Drawing.Color.FromArgb(a, r, g, b);
}
private System.Drawing.Point[] GetTriangle()
{
Random rand = new Random((int)DateTime.Now.Ticks);
int x0 = rand.Next((int)IMAGE_W);
int y0 = rand.Next((int)IMAGE_H);
int x1 = rand.Next((int)IMAGE_W);
int y1 = rand.Next((int)IMAGE_H);
int x2 = rand.Next((int)IMAGE_W);
int y2 = rand.Next((int)IMAGE_H);
System.Drawing.Point x = new System.Drawing.Point(x0, y0);
System.Drawing.Point y = new System.Drawing.Point(x1, y1);
System.Drawing.Point z = new System.Drawing.Point(x2, y2);
System.Drawing.Point[] points = new System.Drawing.Point[] { x, y, z };
return points;
}
Just a guess: GetTriangle() creates a new instance of Random each time.
I have some WriteableBitmap object.
Lets say that the image that is actully on the WriteableBitmap object is 600x400.
I want to copy part of the image - some Rectangle ( for example Rectangle of 100x100 in the middle of the WriteableBitmap ) and paste the copy to some other image control.
How can i do it ?
I suspect you've got this fixed now, but I had the same problem and I found the answer so I thought I'd post it. The code at http://writeablebitmapex.codeplex.com/ has a "Crop" routine that does pretty much what you're after. Once you have a SizeOfArgb constant set to 4, you can use this:
public static WriteableBitmap Crop(this WriteableBitmap bmp, int x, int y, int width, int height)
{
var srcWidth = bmp.PixelWidth;
var srcHeight = bmp.PixelHeight;
// If the rectangle is completly out of the bitmap
if (x > srcWidth || y > srcHeight)
{
return new WriteableBitmap(0, 0);
}
// Clamp to boundaries
if (x < 0) x = 0;
if (x + width > srcWidth) width = srcWidth - x;
if (y < 0) y = 0;
if (y + height > srcHeight) height = srcHeight - y;
// Copy the pixels line by line using fast BlockCopy
var result = new WriteableBitmap(width, height);
for (var line = 0; line < height; line++)
{
var srcOff = ((y + line) * srcWidth + x) * SizeOfArgb;
var dstOff = line * width * SizeOfArgb;
Buffer.BlockCopy(bmp.Pixels, srcOff, result.Pixels, dstOff, width * SizeOfArgb);
}
return result;
}
public static BitmapSource Crop(this BitmapSource bmp, Int32Rect rect)
{
return new CroppedBitmap(bmp, rect);
}