How to move drawn graphics by dragging its body in C#? - c#

I'm currently making a program to drawn lines by coordinates and the lines can be edited or moved.
For now if want to move or edit the line, the cursor location will be the new A or B point. so moving the line is only possible by dragging the edge.
Is there any method to make it possible to drag it by the body?
For the lines I'm using
Graphics g = e.Graphics;
Pen pen1 = new Pen(Color.Black, 3);
g.DrawLine(pen1, line1X1, line1Y1, line1X2, line1Y2);
pen1.Dispose();
and for the edge calculation in mousemove event right now I`m using
int oldX1 = line1X1; //Saving old coordinates for calculation
int oldY1 = line1Y1;
int oldX2 = line1X2;
int oldY2 = line1Y2;
int newX1 = e.Location.X; //New coordinates for calculation
int newY1 = e.Location.Y;
int difX = newX1 - oldX1; //Calculate the difference between old & new coordinates
int difY = newY1 - oldY1;
line1X1 = e.Location.X; //Move point 1 coordinates to new one
line1Y1 = e.Location.Y;
line1X2 = oldX2 + difX; //Move point 2 coordinates to old point 2 + difference
line1Y2 = oldY2 + difY;
x1Box.Text = line1X1.ToString();
y1Box.Text = line1Y1.ToString();
x2Box.Text = line1X2.ToString();
y2Box.Text = line1Y2.ToString();
tried to make 2nd calculation in mousemove event for click & drag anywhere on the screen to move but its not moving at all. if changed the calculation a bit it moved but shaking weirdly to both sides of the cursor example top & bottom of the cursor with same distance or left & right and keep swapping places when moving the cursor.
int clickPointX = e.Location.X;
int clickPointY = e.Location.Y;
int oldX1 = line1X1;
int oldY1 = line1Y1;
int difX = clickPointX - oldX1;
int difY = clickPointY - oldY1;
int dif1to2X = line1X2 - oldX1;
int dif1to2Y = line1Y2 - oldY1;
line1X1 = clickPointX - difX;
line1Y1 = clickPointY - difY;
line1X2 = line1X1 + dif1to2X;
line1Y2 = line1Y1 + dif1to2Y;
x1Box.Text = line1X1.ToString();
y1Box.Text = line1Y1.ToString();
x2Box.Text = line1X2.ToString();
y2Box.Text = line1Y2.ToString();
application image
Question is.
Anyone know how to move the line by clicking & dragging the body not the edge?
Anyone know what is wrong with my 2nd calculation to move the line by click & drag anywhere?
Thank you very much

Related

Moving groups of shapes on canvas: shape moves every couple of frames to opposite x and y position

I'm working on a schoolproject were I need to make a drawing app and use design patterns.
When I'm dragging a group of shapes over the canvas with the mouse. They move in the right directionbut it every couple of frames it glitches in the oposite direction. For example if the location of shape is x = 100 y = 50, every couple of frames it glitches to x = -100 y = -50. What can it be?
Note: The shapes are grouped in groups and the visitor is executed on every shape of a group when a dragevent occurs.
DragEventArgs dragEvent = (DragEventArgs)e;
Point dropPosition = dragEvent.GetPosition(MyCanvas);
double x = dropPosition.X;
double y = dropPosition.Y;
var moveVisitor = new MoveVisitor(MyCanvas,x, y, e);
matchingCompoundShape.parent.Accept(moveVisitor);
public void VisitShape(CompoundShape compoundShape)
{
double oldTop = Canvas.GetTop(compoundShape.shape) ;
double oldLeft = Canvas.GetLeft(compoundShape.shape);
double newLeft = (xc - (oldLeft - xc)) - 50;
double newTop = (yc - (oldTop - yc)) - 50;
Canvas.SetLeft(compoundShape.shape, newLeft);
Canvas.SetTop(compoundShape.shape, newTop);
}
If I set the left andTop for testing to the mouse position the shapes move without glitching.

Setting fixed major grid marks independent of data range

This is my first project in c# and I'm trying to create plots from data.
I'm struggling with drawing minor and major grid lines and labels on a logarithmic scale.
I've set the scale to logarithmic, set the base to 10 and both major and minor intervals to 1, and it works great, however, the interval starts with the minimum value on scale, so for example if data starts at 30M (I'm dealing with frequencies) the next major tick is at 300M and 3G, which is not as it should be.
Is there a way to set major grid to 1, 10, 100 etc, independent of what data is displayed? i've tried changing intervals, base and offset but have not achieved much.
area.AxisX.IsLogarithmic = true;
area.AxisX.LogarithmBase = 10;
area.AxisX.Interval = 1;
//area.AxisX.IntervalOffset = 10000;
area.AxisX.IntervalAutoMode = IntervalAutoMode.FixedCount;
area.AxisX.MajorGrid.Enabled = true;
area.AxisX.MajorTickMark.Enabled = true;
area.AxisX.MinorGrid.Enabled = true;
area.AxisX.MinorGrid.Interval = 1;
area.AxisX.MinorTickMark.Enabled = true;
area.AxisX.MinorTickMark.Interval = 1;
area.AxisX.Minimum = minMaxXY[0]; // in this example 30 M
area.AxisX.Maximum = minMaxXY[1]; // in this example 1 G
here's the link to the current grid
https://ibb.co/3WkxLfc
Thank you for your time and answers!
Thanks to TaW replay I managed to get my program working.
Here is my solution using customLabels location to draw the grid lines.
private void Chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
if (e.Chart.ChartAreas.Count > 0) // I don't yet truly understand when this event occurs,
// so I got plenty of null references.
{
Graphics g = e.ChartGraphics.Graphics;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
Color minorGridColor = Color.Gainsboro;
ChartArea area = e.Chart.ChartAreas[0];
double aymin = area.AxisY.Minimum;
double aymax = area.AxisY.Maximum;
int y0 = (int)area.AxisY.ValueToPixelPosition(aymin);
int y1 = (int)area.AxisY.ValueToPixelPosition(aymax);
foreach (var label in chart1.ChartAreas[0].AxisX.CustomLabels)
{
double xposition = area.AxisX.ValueToPixelPosition(Math.Pow(10, label.FromPosition + 0.1));
if (xposition > area.AxisX.ValueToPixelPosition(minMaxXY[0]) && xposition < area.AxisX.ValueToPixelPosition(minMaxXY[1]))
//this prevents drawing of lines outside of the chart area
{
int x = (int)xposition;
using (Pen dashed_pen = new Pen(Color.FromArgb(10, 0, 0, 0), 1))
{
dashed_pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
g.DrawLine(dashed_pen, x, y0, x, y1);
}
}
}
}
}
I also found the CustomLabel.GridTicks Property, but for some reason it did not work.

How to scroll an zoomed image C#

I have a picturebox and i can zoom it.
When i zoom the picturebox i need to scroll left or right the image.
Can you tell me why when i zoom the image the left side is fixed and i can't scroll on left?
I have activated the AutoScroll on the main panel, but i can scroll only to right, but my image is centered and i need to scoll also to left.
What i want is like when you zoom and scroll an image inside a Photo app in Win 10. But i'm using the scoll bar and not the mouse pointer.
The structure is like in the next image, in red the main panel, and i green the picturebox.
private void image_Scroll(object sender, EventArgs e)
{
int pbWidth = pbImg.Image.Width + (pbImg.Image.Width * ztb.Value / 100);
int pbHeight = pbImg.Image.Height + (pbImg.Image.Height * ztb.Value / 100);
int mpWidth = mainPanel.Width:
int mpHeight = mainPanel.Height;
int pbX = (mpWidth - pbWidth) / 2;
int pbY = (mpHeight - pbHeight) / 2;
pbImg.Size = new Size(pbWidth, pbHeight);
Point p = new Point(pbX, pbY);
pictureBox.Location = p;
}

Resize a box with the mouse while maintaining the aspect ratio?

I'm trying to create a resizable image overlay (for cropping purposes). It seems pretty easy to resize the overlay if I ignore the aspect ratio, but I can't figure out how to perform a constrained resize that respects the AR. I figure that I obviously can't obey the overlay's "grip" positions (or even borders) unless I force the mouse to follow it, but that seems unnatural, so I'll just have to rely on the mouse gesture (which I don't mind doing).
I can also easily resize the overlay and then force it into the proper dimensions afterwards (like every other question about this topic on this site is about), but it's not very intuitive when using a mouse.
This is sort of what I'm going for:
http://deepliquid.com/projects/Jcrop/demos.php?demo=live_crop
I've written an application like this before but it was browser-based so I used a javascript library. This is a desktop application and I haven't found a suitable library for this.
I've left a lot of details out of this code snippet and simplified some conditions with booleans.
private void pbImage_Paint(object sender, PaintEventArgs e)
{
//Overlay
e.Graphics.FillRectangle(brushRect, overlayRect);
// Grips
e.Graphics.FillRectangle(gripRect, leftTopGrip);
e.Graphics.FillRectangle(gripRect, rightTopGrip);
e.Graphics.FillRectangle(gripRect, leftBottomGrip);
e.Graphics.FillRectangle(gripRect, rightBottomGrip);
AdjustGrips();
base.OnPaint(e);
}
public void AdjustGrips()
{
// The next section only causes the grips to partly obey
// the AR - the rest of the overlay ignores it
if (overlayRect.Height * arWidth <= overlayRect.Width)
overlayRect.Width = overlayRect.Height * arWidth;
else if (overlayRect.Width * arHeight <= overlayRect.Height)
overlayRect.Height = overlayRect.Width * arHeight;
leftTopGrip.X = overlayRect.Left;
leftTopGrip.Y = overlayRect.Top;
rightTopGrip.X = overlayRect.Right - rightTopGrip.Width;
rightTopGrip.Y = overlayRect.Top;
leftBottomGrip.Y = overlayRect.Bottom - leftBottomGrip.Height;
leftBottomGrip.X = overlayRect.Left;
rightBottomGrip.X = overlayRect.Right - rightBottomGrip.Width;
rightBottomGrip.Y = overlayRect.Bottom - rightBottomGrip.Height;
}
private void pbImage_MouseMove(object sender, MouseEventArgs e)
{
Point pt = new Point(e.X, e.Y);
// Details elided
if (e.Button == MouseButtons.Left && mouseinGrip)
{
if (bottomRightIsGripped)
{
newOverlayRect.X = overlayRect.X;
newOverlayRect.Y = overlayRect.Y;
newOverlayRect.Width = pt.X - newOverlayRect.Left;
newOverlayRect.Height = pt.Y - newOverlayRect.Top;
if (newOverlayRect.X > newOverlayRect.Right)
{
newOverlayRect.Offset(-width, 0);
if (newOverlayRect.X < 0)
newOverlayRect.X = 0;
}
if (newOverlayRect.Y > newOverlayRect.Bottom)
{
newOverlayRect.Offset(0, -height);
if (newOverlayRect.Y < 0)
newOverlayRect.Y = 0;
}
pbImage.Invalidate();
oldOverlayRect = overlayRect = newOverlayRect;
Cursor = Cursors.SizeNWSE;
}
// Code for other grips elided
}
AdjustGrips();
pbImage.Update();
base.OnMouseMove(e);
}
// Mouse up and down elided
You have complete control over the new size for the overlay as it drags.
The example link that you've given, is simply selecting a starting point based on the click down, then selecting Max(Abs(pt.x - start.x), Abs(pt.y - start.y)), and basing the crop square off of that.
To use a non square ratio, normalize the distances first.
// given known data
//
// Point start;
// The starting location of the mouse down for the drag,
// or the top left / bottom right of the crop based on if the mouse is
// left/above the starting point
//
// Size ratio;
// The ratio of the result crop
//
// pt = (20)x(-20)
// start = (0),(0)
// ratio = (1)x(2)
var dist = new Point(pt.X - start.X, pt.Y - start.Y);
// "normalize" the vector from the ratio
// normalized vector is the distances with respect to the ratio
// ratio is (1)x(2). A (20)x(-20) is normalized as (20),(-10)
var normalized = new Point(dist.X / ratio.Width, dist.Y / ratio.Height);
// In our (20),(-10) example, we choose the ratio's height 20 as the larger normal.
// we will base our new size on the height
var largestNormal = (Math.Abs(normalized.X) > Math.Abs(normalized.Y)
? Math.Abs(normalized.X) : Math.Abs(normalized.Y);
// The calcedX will be 20, calcedY will be 40
var calcedOffset = (largestNormal * ratio.Width, largestNormal * ratio.Height);
// reflect the calculation back to the correct quarter
// final size is (20)x(-40)
if (distX < 0) calcedOffset.X *= -1;
if (distY < 0) calcedOffset.Y *= -1;
var newPt = new Point(start.X + calcedOffset.X, start.Y + calcedOffset.Y);
Notice that one of the lengths can grow greater than the mouse location, but it will never be less. This will have the effect of the mouse traveling along the edge of the new crop box, and the box maintaining ratio.
I've figured out what was causing the original problems in my code. Unlike a static image resize, the aspect ratio code depends on which grip you're "holding", so putting it in a common location for all cases (eg. when the grip positions are set) will not work. You can easily calculate the size of the what the rect should be on the next update, but the position should be set depending on which grip is being held.
If, for example, you're resizing by holding the top left grip, then the bottom and right sides of the cropping rectangle should remain stationary. If you leave the code the same, then the rectangle resizes correctly, but it moves around the canvas and/or the grips go out of sync with the corners of the rect. There is probably a better way to do this but here's some crude code that works. I've only included code for the bottom right and top left grips to illustrate the differences. Extraneous things like setting the mouse pointer and error checking omitted.
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
Point mousePosition = new Point(e.X, e.Y);
if (e.Button == MouseButtons.Left)
{
// This resizeMode, moveMode and other booleans
// are set in the MouseUp event
if (resizeBottomLeft)
{
// Top and Right should remain static!
newCropRect.X = mousePosition.X;
newCropRect.Y = currentCropRect.Y;
newCropRect.Width = currentCropRect.Right - mousePosition.X;
newCropRect.Height = mousePosition.Y - newCropRect.Top;
if (newCropRect.X > newCropRect.Right)
{
newCropRect.Offset(cropBoxWidth, 0);
if (newCropRect.Right > ClientRectangle.Width)
newCropRect.Width = ClientRectangle.Width - newCropRect.X;
}
if (newCropRect.Y > newCropRect.Bottom)
{
newCropRect.Offset(0, -cropBoxHeight);
if (newCropRect.Y < 0)
newCropRect.Y = 0;
}
// Aspect Ratio + Positioning
if (newCropRect.Width > newCropRect.Height)
{
newCropRect.Height = (int)(newCropRect.Width / ASPECT_RATIO);
}
else
{
int newWidth = (int)(newCropRect.Height * ASPECT_RATIO);
newCropRect.X = newCropRect.Right - newWidth;
newCropRect.Width = newWidth;
}
}
else if (resizeTopRight)
{
// Bottom and Left should remain static!
newCropRect.X = oldCropRect.X;
newCropRect.Y = mousePosition.Y;
newCropRect.Width = mousePosition.X - newCropRect.Left;
newCropRect.Height = oldCropRect.Bottom - mousePosition.Y;
if (newCropRect.X > newCropRect.Right)
{
newCropRect.Offset(-cropBoxWidth, 0);
if (newCropRect.X < 0)
newCropRect.X = 0;
}
if (newCropRect.Y > newCropRect.Bottom)
{
newCropRect.Offset(0, cropBoxHeight);
if (newCropRect.Bottom > ClientRectangle.Height)
newCropRect.Y = ClientRectangle.Height - newCropRect.Height;
}
// Aspect Ratio + Positioning
if (newCropRect.Width > newCropRect.Height)
{
int newHeight = (int)(newCropRect.Width / ASPECT_RATIO);
newCropRect.Y = newCropRect.Bottom - newHeight;
newCropRect.Height = newHeight;
}
else
{
int newWidth = (int)(newCropRect.Height * ASPECT_RATIO);
newCropRect.Width = newWidth;
}
}
else if (moveMode) //Moving the rectangle
{
newMousePosition = mousePosition;
int dx = newMousePosition.X - oldMousePosition.X;
int dy = newMousePosition.Y - oldMousePosition.Y;
currentCropRect.Offset(dx, dy);
newCropRect = currentCropRect;
oldMousePosition = newMousePosition;
}
if (resizeMode || moveMode)
{
oldCropRect = currentCropRect = newCropRect;
// Set the new position of the grips
AdjustGrips();
pictureBox1.Invalidate();
pictureBox1.Update();
}
}
}

Looking for sample code to rotate by touch WinRT xaml round button or image like a stereo radio's button

I'm looking for sample code to rotate by touch or mouse WinRT xaml round button or image like a stereo radio's button. The idea to is be able to touch the control to rotate to the right of left in a infinite way. The delta value is used to increase or decrease another object's value. The rotation angle is not important. Just the action of turning the control to the right or left is.
Any tips for the good way to achieve this would be appreciated ?
Part of the code here:
private RotateTransform rotateTransform;
void ManipulationStarting(object sender, ManipulationStartingRoutedEventArgs e)
{
e.Handled = true;
var image = sender as Image;
var container = image.Parent as UIElement;
var localCenter = new Point(image.ActualWidth / 2, image.ActualHeight / 2);
var pivot = new ManipulationPivot(localCenter, 20);
e.Pivot = pivot;
rotateTransform.CenterX = image.ActualWidth / 2;
rotateTransform.CenterY = image.ActualHeight / 2;
e.Container = container;
}
void ImageManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
e.Handled = true;
var image = sender as Image;
double newAngle;
var valueDrawline = 1;
if (e.Delta.Rotation < 0)
{
valueDrawline = -1;
newAngle = rotateTransform.Angle - (1 + e.Delta.Rotation);
}
else
{
valueDrawline = 1;
newAngle = rotateTransform.Angle + (1 + e.Delta.Rotation);
}
rotateTransform.Angle = newAngle;
image.RenderTransform = rotateTransform;
}
The "real" problem is coming from the direction which is not constant. Ex: when I turn the control with the mouse or finger doing rounds from left to right, the value is supposed to be incremented by +1. This is not working well with the current code as the value is mostly incremented by +1 but also with -1 even if I still turning in the direction.
To be more clear, let's imagine I want to draw an horizontal line with my control. I need to turn it in right to draw to right and the inverse to draw the the left. With this code, it's going to the correct direction but with a lot of steps back along the path of the line...
Txs in advance

Categories