Sign in to follow this  
BoltBait

Drawing Triangles, Pentagons, Stars, etc. Plugin: 2007-02-09

Recommended Posts

Then you will see my secrets... But it's ok I'm a "sharer" !

The trick is to do the stuff in two pass.

1st loop I use a binary table as large as the image. It's where I "plot" the spots.

2nd loop I read as normaly the selection and read the binary table to decide what to draw on the 'dst'. I learnt it's better to set 'dst' line by line.

So the 'precalculation' in the table AND normal 'plotting' in the dst make the rendering going faster!

here is the source of the newer version

I leave the old one if you want to compare.

I'm still missing a good solution for anti-aliasing :(

Share this post


Link to post
Share on other sites

Hi, I am new here. I am also new to the .net programming, but I can read it.

What I want to suggest are: for staris parameter, it need only start from 1 to (int)((double)n/2 - 0.5), because staris = k and staris = n-k is same thing.

For the computation efficiency, I think using vector and rotation is a faster way than call cos and sin all the times. For example, center point o, first point A, then vector oA is the Radius*(cos(offset), sin(offset)) where offset is the rotation I think. Calculate the angle AoB by anglestep = 2*pi/n, then create the 2D rotation matrix. The oB can be calculated by applying rotation on oA, which only need 4 double multiplications and 4 double additions (2 for add the o cord). Cos and sin will no longer be called every loop.

Probably for today's computer there is no problem, however, I experience a significant slowing down when in one of my openGL projects transplanted to a pentium II computer. And I think this is not harmful.

Share this post


Link to post
Share on other sites

What a post for a first one!

1. using float instead double is already a speed gain.

2. I'm not sure that 4 double multiplications and 4 double addition are computed faster than float cos...

3. If I could imagine vector and rotation on paper, I don't see how to write it in the program. Could you do it?

4. BTW I think we could improove this but anyhow is .Net running on your pentium II ? Which operating system ?

Share this post


Link to post
Share on other sites

I quickly encounter errors with both plugins :(

for the polygon, I try to produce a pentagon and then rotate a small amount and it crashes every time.

imo, antialiasing is essential.

also, the polygones aren't symmetrical all the time, the lines look as though they don't quite match up; the odd extra pixel where there shouldn't be any. perhaps this is due to rounding.

sorry to be the bearer of bad news...

This text file was created because Paint.NET crashed.
Please e-mail this file to paint.net@hotmail.com so we can diagnose and fix the problem.

Application version: Paint.NET v3.0 (Final Release build 3.0.2580.31)
Time of crash: 29/01/2007 05:22:26 PM
Application uptime: 00:02:49.5538064
OS Version: 5.1.2600.131072 Service Pack 2 Workstation x86
.NET Framework version: 2.0.50727.42 x86
Processor: 1x mobile AMD Athlon(tm) XP 1400+  
Physical memory: 190 MB
Tablet PC: no
Locale: pdnr.c: en-US, hklm: en-US, hkcu: n/a, cc: en-GB, cuic: en-US

Exception details:
PaintDotNet.WorkerThreadException: Worker thread threw an exception ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
  at Polygones.Polygones.Render(ThreeAmountsConfigToken token, Surface dst, Surface src, Rectangle rect)
  at Polygones.Polygones.Render(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs, Rectangle[] rois, Int32 startIndex, Int32 length)
  at PaintDotNet.Effects.BackgroundEffectRenderer.RendererContext.RenderImpl()
  --- End of inner exception stack trace ---
  at PaintDotNet.Effects.BackgroundEffectRenderer.Join()
  at PaintDotNet.Effects.BackgroundEffectRenderer.Start()
  at PaintDotNet.Menus.EffectMenuBase.EffectConfigTokenChangedHandler(Object sender, EventArgs e)
  at PaintDotNet.Effects.EffectConfigDialog.OnEffectTokenChanged()
  at PaintDotNet.Effects.TwoAmountsConfigDialogBase.amount2Slider_ValueChanged(Object sender, EventArgs e)
  at System.Windows.Forms.TrackBar.OnValueChanged(EventArgs e)
  at System.Windows.Forms.TrackBar.WndProc(Message& m)
  at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
  at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
  at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
------------------------------------------------------------------------------
This text file was created because Paint.NET crashed.
Please e-mail this file to paint.net@hotmail.com so we can diagnose and fix the problem.

Application version: Paint.NET v3.0 (Final Release build 3.0.2580.31)
Time of crash: 29/01/2007 05:27:35 PM
Application uptime: 00:03:07.6197840
OS Version: 5.1.2600.131072 Service Pack 2 Workstation x86
.NET Framework version: 2.0.50727.42 x86
Processor: 1x mobile AMD Athlon(tm) XP 1400+  
Physical memory: 190 MB
Tablet PC: no
Locale: pdnr.c: en-US, hklm: en-US, hkcu: n/a, cc: en-GB, cuic: en-US

Exception details:
PaintDotNet.WorkerThreadException: Worker thread threw an exception ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
  at PaintDotNet.Effects.SpiroShapes.Render(SpiroShapesConfigToken token, Surface dst, Surface src, Rectangle rect)
  at PaintDotNet.Effects.SpiroShapes.Render(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs, Rectangle[] rois, Int32 startIndex, Int32 length)
  at PaintDotNet.Effects.BackgroundEffectRenderer.RendererContext.RenderImpl()
  --- End of inner exception stack trace ---
  at PaintDotNet.Effects.BackgroundEffectRenderer.Join()
  at PaintDotNet.Effects.BackgroundEffectRenderer.Start()
  at PaintDotNet.Menus.EffectMenuBase.EffectConfigTokenChangedHandler(Object sender, EventArgs e)
  at PaintDotNet.Effects.EffectConfigDialog.OnEffectTokenChanged()
  at PaintDotNet.Effects.EffectConfigDialog.FinishTokenUpdate()
  at PaintDotNet.Effects.SpiroShapesConfigDialog.numericUpDownFrequency_ValueChanged(Object sender, EventArgs e)
  at System.Windows.Forms.NumericUpDown.OnValueChanged(EventArgs e)
  at System.Windows.Forms.NumericUpDown.set_Value(Decimal value)
  at PaintDotNet.Effects.SpiroShapesConfigDialog.trackbar_Frequency_ValueChanged(Object sender, EventArgs e)
  at System.Windows.Forms.TrackBar.OnScroll(EventArgs e)
  at System.Windows.Forms.TrackBar.WndProc(Message& m)
  at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
  at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
  at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
------------------------------------------------------------------------------

Share this post


Link to post
Share on other sites

Hi, Madjik:

I must agree that the idea lies in the polygon plugin is great. It might need no change if there is no more PII. My computer is not not PII, it runs opengl with no problem, but paint.net seems starting slow on it. Now because nearly every program is written in a way that requires more system resources, I really need a new computer for the tendency.

To use the vector operation is just a suggestion. In most of 3D calculation, including optical ray tracing, vector operation is widely applied for the calculation efficiency.

For your listed answers.

1. using float instead double is already a speed gain.

2. I'm not sure that 4 double multiplications and 4 double addition are computed faster than float cos...

3. If I could imagine vector and rotation on paper, I don't see how to write it in the program. Could you do it?

4. BTW I think we could improove this but anyhow is .Net running on your pentium II ? Which operating system ?

1. cos and sin might return double, but vector operation can be limited to float.

2. As I remember (it was long ago),

cos x = 1 - x^2/2 + x^4/4! - x^6/6! + .......

sin x = x - x^3/3! + x^5/5! - .......

this might be how they are calculated, the math functions loop until the precision is reached. However, this is just my guess from the old knowledge and mathematics, things might change

3. Let me see if I can draw something and put it online, but it might easier to find a website or a book on the vectors and matrix.

In optical tracing, refraction and reflection are calculated by vector operation, not the Trigonometric function. In 3D graphics, rotation matrix is a widely used tech to avoid intensive calculation by cos and sin.

a 2D rotation matrix A is

[cos(a) sin(a)]

[-sin(a) cos(a)]

a is the angle couterclockwise, in rad

a vector means a directional line from one point (x,y) to another point (X,Y)

note that it is same for the line from (0,0) to (X-x, Y-y), this means vector can be movable

Rotation is implemented by matrix operation: *A

for now I can only write a code for the operation in C to show the algorithm, it is not compiled

render(x0, y0, n, k, R, offset)

// x0, y0 : center cords

// n number of vertex

// k staris

// offset rotation offset

// R raduis

{

double a = 2*pi/n*k;

float cosa = cos(a), sina = sin(a);

float cosb = cos(offset), sinb = sin(offset);

// now we calculate a side without offset.

// imagine without offset, the first point is (x0+R, y0)

// next point is (x0+R*cosa, y0+R*sina)

// the coord difference gives the vector

float vx1 = R*(cosa-1), vy1 = R*sina;

// now rotate it by offset suppose it is in rad

float vx2 = vx1*cosb - vy1*sinb, vy2 = vx1*sinb + vy1*cosb;

// this stands for all the parallel lines with same length as the first side

// we need to determine its starting point

float x1 = x0 + R*cosb, y1 = y0 + R*cosb;

// now we loop

for (int i=1; i

{

// the next point can be calculated

// two float/double addition here

float x2 = x1 + vx2, y2 = y1 + vx2;

// now draw the line

drawline((int)x1, (int)y1, (int)x2,(int)y2)

// update the starting point, rotate the side vector

x1 = x2; y1 = y2;

vx1 = vx2; vy1 =vy2;

// two addition here, four multiplication here

vx2 = vx1*cosb - vy1*sinb; vy2 = vx1*sinb + vy1*cosb;

}

}

4. My computer is PenIV. When I was in school and using opengl, the computer is PenII. The code transplanted from

my computer to the school computer gets slow, one reason was the intensive cos and sin call.

I'd like to write in C#, but as I said, I am new to it. I have the runtime v2 on this machine, but coding and debug will be slow.

If you can help me on it (how to test it and maybe correct some syntax error), I will be glad to work with you. Or you can search the internet for vector and matrix operation or just borrow a book. It is quite easy.

Other than use the vector for sides, we also use the vector starting from center and pointing to vertex

render(x0, y0, n, k, R, offset)

// x0, y0 : center cords

// n number of vertex

// k staris

// offset rotation offset

// R raduis

{

double a = 2*pi/n*k;

float cosa = cos(a), sina = sin(a);

float cosb = cos(offset), sinb = sin(offset);

// now we calculate the vector from center to first vertex

float vx1 = R*cosb, vy1 = R*sinb;

// the vertex is

float x1 = x0 + vx1, y1 = y0 + vy1;

float vx2, vy2, x2, y2;

// now we loop

for (int i=1; i

{

// rotate the vector -- two add, four multiplication here

vx2 = vx1*cosa - vy1*sina;

vy2 = vx1*sina + vy1*cosa;

//next vertex two more addition here

x2 = x0 + vx2, y2 = y0 + vx2;

// now draw the line

drawline((int)x1, (int)y1, (int)x2,(int)y2)

// update the starting point, rotate the side vector

x1 = x2; y1 = y2;

vx1 = vx2; vy1 =vy2;

}

}

I modified madjik's code, don't know how to upload here or how to test it. Need help!

Share this post


Link to post
Share on other sites

Now here is a link on the rotation matrix

http://mathworld.wolfram.com/RotationMatrix.html

I am glad I have nothing wrongly explained. They express vector as a column vector and use right multiplication (matrix on left), I use row vector and left multiply the rotation matrix. Therefore the -sinx location is different.

The idea lies in the fact that the new side can be acquired by rotating the last side.

Moreover, it might be reasonable to draw the last side by connecting back to the first point. Otherwise, we might have an open at the end.

One more idea to create the hollow star: use two circle with Radius R1 and Radius R2, n vertexes, offset by alpha. This can create a holly star.

void render(x0,y0,R1,R2,alpha,beta,n)

{

// alpha, internal offset angle

// beta, extenal offet angle

// n, vertexes

float aa = 2*pi/n;

float cosaa2 = cos(aa/2), sinaa = sin(aa/2);

float cosaaa = 1 - 2*sinaa2*sinaa2, sinaaa = 2*sinaa2*cosaa2;

float cosa = cos(alpha), sina2 = sin(alpha); //alpha in rad

float cosb = cos(beta), sinb = sin(beta);

// this time we calculate the vertexes by vector from center to the vertex

float vx1 = R1, vy1 = 0;

float vx2 = R2*cosa2, vy2 = R2*sina2; // note that alpha is applied

// apply the offset beta on both v1 and v2

float vxt = vx2, vyt = vy2;

vx2 = vxt*cosb - vyt*sinb;

vy2 = vxt*sinb + vyt*cosb;

vxt = vx1; vyt = vy1;

vx1 = vxt*cosb - vyt*sinb;

vy1 = vxt*sinb + vyt*cosb;

// temperory varible for illustration

float x1, y1, x2, y2;

x1 = x0 + vx1; y1 = x0 + vy1;

x2 = x0 + vx2; y2 = y0 + vy2;

// now we loop

for (i=1; i

{

drawline((int)x1, (int)y1, (int)x2, (int)y2);

// rotate vector v1

vxt = vx1; vyt = vy1;

vx1 = vxt*cosb - vyt*sinb;

vy1 = vxt*sinb + vyt*cosb;

// draw another line

x1 = x0 + vx1; y1 = x0 +vy1;

drawline(x2,y2,x1,y1)

// rotate vector v2

vxt = vx2; vyt = vy2;

vx2 = vxt*cosb - vyt*sinb;

vy2 = vxt*sinb + vyt*cosb;

x2 = x0 + vx2; y2 = x0 +vy2;

}

}

BTW, the idea to use the variable radius is good, the result is anstonishing. That might be something that vector can't be helpful.

Share this post


Link to post
Share on other sites
I quickly encounter errors with both plugins :(

for the polygon, I try to produce a pentagon and then rotate a small amount and it crashes every time.

Can't reproduce that error... Could you tell me the picture size you're working on ?

imo, antialiasing is essential.

also, the polygones aren't symmetrical all the time, the lines look as though they don't quite match up; the odd extra pixel where there shouldn't be any. perhaps this is due to rounding.

I agree for antialiasing, but I've not viable solution yet for that... :oops:

Rounding could create some "extra" pixels. I'll have a look at that.

Share this post


Link to post
Share on other sites
Hi, Madjik:

I modified madjik's code, don't know how to upload here or how to test it. Need help!

You could try to PM it to me...

EDIT: BTW for a pentagone or a 5 spines star, We calculate only 5 times sin/cos matter. The biggest part of computation is for drawing the straight lines. So I'm not sure we'll gain something in the end.

Share this post


Link to post
Share on other sites

Yes, only if we drawing a polygon with over 1000 vertex, the difference might be seen, but the polygon will became a circle anyway:)

OK, I figured out my Javascript is disabled for this site, but I still can't find out how to attach a file. Do I need a webspace?

Following code is wat you posted before. I am not sure it is latest but I think the looping part is a little overlapped with each other, as I noted down in the code. I am not quite sure what you are trying to do in the loop from left to right, from top to bottom.

using Polygones.Properties;
.....
using System.Windows.Forms;

// the revised version on madjik's polygon, by Ghost_Archer.
// replace the cos and sin with vector operation, no other changes
namespace Polygones
   {
...
       {
...
       public override void Render(...)
           {
...

//  I am not sure what the startIndex and length refers to, is that the counter for selections and masks?
////////////////////////////////////////////////////////////////////////////
//  yet it seems that there are too many loops here.
//  I guess there will be lots of overlapping pixels inside
//  i.e., some pixel will be treated more than once if there are overlap
///////////////////////////////////////////////////////////////////////////

           for (int i = startIndex; i < startIndex + length; ++i)
// all these are inside the loop
// including the draw polygon part.
               {
               Rectangle rect = rois[i];
               // Because I have to reset the destination every time 
               // this is reeeeeaaaaallllly slow 
               for (int y = rect.Top; y < rect.Bottom; y++)
                   {
                   for (int x = rect.Left; x < rect.Right; x++)
                       {
                       if (selectionRegion.IsVisible(x, y))
                           {
                           dstArgs.Surface[x, y] = srcArgs.Surface[x, y];
                           }
                       }
                   }
// including the drawline calls, polygon is drawn several times
........
           }

       public void DrawLine(int x1, int y1, int x2, int y2, Surface dst, ColorBgra LineColor, PdnRegion selectionRegion)
           {
...
           }
       public override EffectConfigDialog CreateConfigDialog()
           {
...
           }

       public Polygones()
           : base(Strings.Polygones_Name, Resources.Polygones, Keys.None, null, EffectDirectives.None, true)
           {
...
           }
       }
   }

Share this post


Link to post
Share on other sites
I quickly encounter errors with both plugins :(

for the polygon, I try to produce a pentagon and then rotate a small amount and it crashes every time.

Can't reproduce that error... Could you tell me the picture size you're working on ?

I noticed that your internal buffer is not clipping, so I was able to reproduce the error on the first try...

Here is a screenshot of the error:

polyerror.gif

Here is the crash log:

This text file was created because Paint.NET crashed.
Please e-mail this file to paint.net@hotmail.com so we can diagnose and fix the problem.

Application version: Paint.NET v3.0 (Final Release build 3.0.2580.31)
Time of crash: 1/30/2007 9:38:47 AM
Application uptime: 00:00:59.4977152
OS Version: 5.1.2600.131072 Service Pack 2 Workstation x86
.NET Framework version: 2.0.50727.42 x86
Processor: 2x Intel(R) Pentium(R) 4 CPU 3.20GHz
Physical memory: 1022 MB
Tablet PC: no
Locale: pdnr.c: en-US, hklm: en-US, hkcu: en-US, cc: en-US, cuic: en-US

Exception details:
PaintDotNet.WorkerThreadException: Worker thread threw an exception ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
  at Polygones.Polygones.Render(ThreeAmountsConfigToken token, Surface dst, Surface src, Rectangle rect)
  at Polygones.Polygones.Render(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs, Rectangle[] rois, Int32 startIndex, Int32 length)
  at PaintDotNet.Effects.BackgroundEffectRenderer.RendererContext.RenderImpl()
  --- End of inner exception stack trace ---
  at PaintDotNet.Effects.BackgroundEffectRenderer.Join()
  at PaintDotNet.Effects.BackgroundEffectRenderer.Start()
  at PaintDotNet.Menus.EffectMenuBase.EffectConfigTokenChangedHandler(Object sender, EventArgs e)
  at PaintDotNet.Effects.EffectConfigDialog.OnEffectTokenChanged()
  at PaintDotNet.Effects.TwoAmountsConfigDialogBase.amount2Slider_ValueChanged(Object sender, EventArgs e)
  at System.Windows.Forms.TrackBar.OnValueChanged(EventArgs e)
  at System.Windows.Forms.TrackBar.WndProc(Message& m)
  at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
  at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
  at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
------------------------------------------------------------------------------

BTW for a pentagone or a 5 spines star, We calculate only 5 times sin/cos matter. The biggest part of computation is for drawing the straight lines. So I'm not sure we'll gain something in the end.

I totally agree. Don't waste time optimizing code that hardly ever runs.

Share this post


Link to post
Share on other sites

great, thanks. Works nicely now. Sorry I didn't answer your question earlier.

I'm using it with a transparent layer above and tracing antialiased lines for the moment. But then I'm only doing simple shapes. Just a (obvious) tip for anyone else wanting antialiasing.

cheers.

Share this post


Link to post
Share on other sites

I think my thread is getting jacked... Oh well. Time to "split" the thread into two parts. :)

On to important business!

I have updated the first post with a link to the Draw Shapes/Stars Plugin UI that I wrote.

And the speed of line drawing has been GREATLY increased!

Enjoy. :cool:

Source code coming soon... really...

Share this post


Link to post
Share on other sites
corners.png

Fixable?

Absolutely fixable.

Actually, when the user is drawing stars, I change the line ends to be more pointed. This looks really good for stars with lots of points, but apparantly, not so good for less points. :D

I just had to delete a couple of lines of code, recompile, upload...

Try updating your dll now.

Share this post


Link to post
Share on other sites
Really good job with this new version. I'ld like to have the source to learn from your technic. Thanks.

Since you asked, in the first post, I have added a link to the VS2005 souce code.

Please let me know if there are not enough files included to build the project.

Share this post


Link to post
Share on other sites
Absolutely fixable.

Actually, when the user is drawing stars, I change the line ends to be more pointed. This looks really good for stars with lots of points, but apparantly, not so good for less points. :D

I just had to delete a couple of lines of code, recompile, upload...

Try updating your dll now.

I liked it the other way better! I got some cool looking gear-like shapes.

Could you have a check box on the GUI or something so you can have both options?

Or, can you post the old dll as well? Then I will just run both depending on my need...

Share this post


Link to post
Share on other sites

Please let me know if there are not enough files included to build the project.

Everything is fine : I've opened the project with VS C# (express version). I press F6, "built success"...

This source shows me how much I need to learn about C#. I have some technics but if I don't know the words...

Thanks a lot!

Share this post


Link to post
Share on other sites
I liked it the other way better! I got some cool looking gear-like shapes.

Could you have a check box on the GUI or something so you can have both options?

Or, can you post the old dll as well? Then I will just run both depending on my need...

Well, I guess you can't please everybody. :(

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this