Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C# GDI+ WinForm
My GraphicsPath updating mechanism is really simple and clean, that's re-creating it with new updated inputs (parameters). For example, with a GraphicsPath of Rectangle, instead of translating, scaling the GraphicsPath (after moving, resizing) I just simply update the left-top Point (Location) and the Size (Width and Height) and then create a new GraphicsPath of Rectangle with those updated parameters.
 
This works very very cleanly and the code is easy to follow. But I'm facing a problem with this, that's when I need a rotating transformation applied to the GraphicsPath, the example of Rectangle in this case is not suitable, suppose, for example, the GraphicsPath now is of an Arrow (consists of connected lines). The function used to create the GraphicsPath can create only a Right Arrow, so calling to it every time (even with new parameters updated) will create only a Right Arrow (not Up and Down...). So if I apply a 90 degree rotating transformation to that GraphicsPath of Right Arrow, then resize and move the rotated GraphicsPath, I can't use my function to update the GraphicsPath, except that I have to add some code of rotating the GraphicsPath to the function. But this function is placed in a Paint handler, that means every time Paint is fired, it will create the GraphicsPath (with rotating) from scratch before drawing.
 
I don't think that's a clean way in case of having to apply a rotating transformation with moving and resizing. Because I just need to rotate the GraphicsPath only 1 time instead of rotating it every time Paint event is raised. I wonder it doing so is acceptable? I'm sure that it is acceptable in my project (about the performance) but it's not clean code. I don't want to add some code to rotate the GraphicsPath to my function. (the function for recreating GraphicsPath with new updated parameters).
 
So I can't find a better solution. To rotate only 1 time (when user needs), I have to update the GraphicsPath another way, as I said, I think I have to apply transformation of translating, scaling, rotating (and anything else possible) to the GraphicsPath instead of re-creating it with new updated parameters. This sounds clean but not really, even I'm stuck at this. The new problem is related to scaling transformation, scaling will resize the GraphicsPath as I want but it also re-positions the GraphicsPath, my idea is resizing without changing the location (position) of the GraphicsPath, so scaling can make things more complicated. I've tried translating the GraphicsPath's center to (0,0) point, scale it and translate it back with certain horizontal and vertical differences. That should work, but maybe I calculate the horizontal and vertical differences (for translating back) wrong.
 
Scaling can also be hard for me to reposition the GraphicsPath exactly because that the calculation for scaling is not completely exact. That can produce a small error of even 1 point different between the wanted position (the orginal position which is considered as fixed) and the updated position.
 
Please give me an idea for this. I'm really regret for my first mechanism to udpate GraphicsPath, simple but clean but can't help me add more transformations to the GraphicsPath before drawing except that I have to add corresponding code to the function and execute it every time (including the time when it is not necessary to do) when Paint event is fired.
 
Your help would be highly appreciated!
Thanks!
 
VipHaLong
Posted 3-Mar-13 7:39am
supernorb2.6K
Comments
Sergey Alexandrovich Kryukov at 3-Mar-13 12:50pm
   
From the first sentence, I feed that you do have some good points here, but later, you operate some very relativistic notions, such as "clean code", etc. Your search for good supportability and clean code should be well respected, but any judgment are only possible if we had some samples codes and more detail explanation... Right now, it's hard to understand what are exact problems...
Just a thought...
—SA
supernorb at 3-Mar-13 13:31pm
   
I think after this comment of mine, you will understand, the context here is to draw a shape (E.g: a right arrow), allow user to resize, move, rotate and the shape should be seen when being in the middle of the process of moving, resizing, rotating. User will input/update parameters by some way (hold mouse down, move, ...as you can see in MS Paint) or even input in textboxes. There are 2 ways to update the shape, the first I mentioned (as clean code) is re-creating the shape with new updated parameters and the second is translating, scaling, rotating the shape (after these transformations, it's still itself not a new instance) but scaling leads to re-positioning problem as I said clearly in the question. Hope you understand it now. Thanks!
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

Thank you for clarification. I think you already almost have a good solution.
 
The only concern I would have is having some paths the be recreated on paint. It's clear that it's not needed. You can pre-create some "library of shapes" in the form of some paths and store these objects as some set which is the member of, for example, your class of control where you render it all. Creation of these shapes is not a part of rendering. In your Paint handler or overridden OnPaint method, you can put these objects where needed and perform appropriate transformation to scale/rotate them. For example, you really need only one arrow.
 
I think you concern about the transform operation cost too much. Just the opposite, you should better rely on its performance, which should be one of the best in all your operation chain. Anyway, of performance of rendering is concern, I would do a little research, but I think you are already on a right path.
 
Only carry out the pre-creation I mentioned above out of rendering. More generally, don't be afraid of keeping some reusable object as instance members of your control, pens, brushed, paths and more. Only don't forget to dispose them (many of them implement System.IDisposable) when you dispose the instance of your control.
 
—SA
  Permalink  
Comments
supernorb at 4-Mar-13 5:12am
   
Thank you, I've tried going ahead with my first approach (re-creating GraphicsPath), but the thing has become more complicated than I thought before. So I've tried the second approach (scaling,.., the existing GraphicsPath without recreating) and It's OK now! Please see my solution below. =)
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

The problem when using scaling is how to re-position the GraphicsPath exactly to the original position (the fixed position) after scaling.
 
As I mentioned in the question about the way I tried to achieve this but I realize that it's not easy and unstable depending on the scaling factors. And I tried to find out another way. Here it is:
 
The steps are:
- Scale the GraphicsPath.
- Translate the GrahicsPath to the original position.
 
private void ScaleWithoutChangingPosition(GraphicsPath gp, float scalex, float scaley){
   //Scale first
   Matrix m = new Matrix();
   m.Scale(scalex, scaley);
   gp.Transform(m);
   //Translate then
   m.Reset();
   float left = float.MaxValue, top = float.MaxValue;
   foreach(PointF p in gp.PathPoints){
      if(left > p.X) left = p.X;
      if(top > p.Y) top = p.Y;
   }
   m.Translate(fixedPosition.X - left, fixedPosition.Y - top);
   gp.Transform(m);
}
 
The important thing here is how I find the new location of GraphicsPath after scaling and it's surely exact as I want.
 
Thanks!
  Permalink  

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 OriginalGriff 7,800
1 Sergey Alexandrovich Kryukov 7,072
2 DamithSL 5,604
3 Manas Bhardwaj 4,986
4 Maciej Los 4,790


Advertise | Privacy | Mobile
Web04 | 2.8.1411023.1 | Last Updated 4 Mar 2013
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100