BoltBait Posted February 5 Share Posted February 5 I know @toe_head2001 has an excellent graph paper plugin, however, it doesn't include labels and shape drawing. So, I rolled my own. I won't publish this as his is better than mine. But, I thought someone might find it interesting as it is GPU accelerated. CodeLab source for BBGraphPaper.cs : Spoiler // Name: Graph Paper // Submenu: Render // Author: BoltBait // Title: BoltBait's Graph Paper v1.1 // Version: 1.1 // Desc: Render Graph Paper // Keywords: graph paper // URL: https://BoltBait.com/pdn // NSC #region UICode IntSliderControl cellSize = 20; // [10,50] Cell Size IntSliderControl offsetWidth = 0; // [-10,10] Center Offset X / Y IntSliderControl offsetHeight = 0; // [-10,10] MultiLineTextboxControl rawPoints = ""; // [32767] Points (one per line) x,y LabelComment comment = "You can close the shape by entering a comma alone on a line. You can start a new shape by entering a blank line."; // CheckboxControl labelPoints = false; // Label points #endregion protected override unsafe void OnDraw(IDeviceContext deviceContext) { deviceContext.AntialiasMode = AntialiasMode.PerPrimitive; deviceContext.TextAntialiasMode = TextAntialiasMode.Grayscale; deviceContext.UseTextRenderingMode(TextRenderingMode.Outline); IDirect2DFactory d2dFactory = this.Services.GetService<IDirect2DFactory>(); IDirectWriteFactory textFactory = this.Services.GetService<IDirectWriteFactory>(); IGdiFontMap fm = textFactory.GetGdiFontMap(); FontProperties fp = fm.TryGetFontProperties("Courier New"); ITextFormat textFormat = textFactory.CreateTextFormat(fp.FontFamilyName, null, fp.Weight, fp.Style, fp.Stretch, cellSize/2.5f); deviceContext.Clear(LinearColors.White); RectFloat sourceBounds = new RectFloat(Point2Float.Zero, Environment.Document.Size); float CenterX = sourceBounds.Center.X + (offsetWidth * cellSize); float CenterY = sourceBounds.Center.Y - (offsetHeight * cellSize); float FirstX = CenterX % cellSize; float FirstY = CenterY % cellSize; ISolidColorBrush grayBrush = deviceContext.CreateSolidColorBrush(LinearColors.Gray); ISolidColorBrush blackBrush = deviceContext.CreateSolidColorBrush(LinearColors.DarkGray); ISolidColorBrush blueBrush = deviceContext.CreateSolidColorBrush(LinearColors.SkyBlue); // draw vertical lines for (float x = FirstX; x < sourceBounds.Width; x += cellSize) { if (x == CenterX) { // Y axis deviceContext.DrawLine(new Point2Float(x,0),new Point2Float(x,sourceBounds.Bottom), blueBrush, 3); } else { if ((x-CenterX) % (cellSize * 5) == 0) { // make every 5 lines darker deviceContext.DrawLine(new Point2Float(x,0),new Point2Float(x,sourceBounds.Bottom), blackBrush, 2); } else { // normal line deviceContext.DrawLine(new Point2Float(x,0),new Point2Float(x,sourceBounds.Bottom), grayBrush, 1, d2dFactory.CreateStrokeStyle(new StrokeStyleProperties(CapStyle.Flat, CapStyle.Flat, CapStyle.Flat, LineJoin.Round, 10f, PaintDotNet.Direct2D1.DashStyle.Dash, 0f, StrokeTransformType.Normal))); } } // X labels RectFloat topTextOffset = RectFloat.Offset(sourceBounds, x+1, CenterY); deviceContext.DrawText(((x-CenterX) / (cellSize)).ToString(),textFormat,topTextOffset, blueBrush); } // draw horizontal lines for (float y = FirstY; y < sourceBounds.Height; y += cellSize) { if (y == CenterY) { // X axis deviceContext.DrawLine(new Point2Float(0,y),new Point2Float(sourceBounds.Right,y), blueBrush, 3); } else { if ((y-CenterY) % (cellSize * 5) == 0) { // make every 5 lines darker deviceContext.DrawLine(new Point2Float(0,y),new Point2Float(sourceBounds.Right,y), blackBrush, 2); } else { // normal line deviceContext.DrawLine(new Point2Float(0,y),new Point2Float(sourceBounds.Right,y), grayBrush, 1, d2dFactory.CreateStrokeStyle(new StrokeStyleProperties(CapStyle.Flat, CapStyle.Flat, CapStyle.Flat, LineJoin.Round, 10f, PaintDotNet.Direct2D1.DashStyle.Dash, 0f, StrokeTransformType.Normal))); } // Y labels RectFloat topTextOffset = RectFloat.Offset(sourceBounds, CenterX +1, y); deviceContext.DrawText(((CenterY-y) / (cellSize)).ToString(),textFormat,topTextOffset, blueBrush); } } // Draw shapes on the graph paper List<string> points = (rawPoints + "\n").Split('\n').ToList(); float previousX = 0, previousY = 0; bool prev = false; bool first = true; int brushIndex = 2; float firstX = 0, firstY = 0; char label = 'A'; List<Point2Float> currentShape = new List<Point2Float>(); FontProperties labelFP = fm.TryGetFontProperties("Arial"); // use your font properties to create a font ITextFormat labelTextFormat = textFactory.CreateTextFormat( labelFP.FontFamilyName, // font family name null, FontWeight.Bold, // font weight FontStyle.Normal, // font style labelFP.Stretch, // how to stretch the font 12); // size in points IReadOnlyList<ColorBgra> DefaultColors = Services.GetService<IPalettesService>().DefaultPalette; //IReadOnlyList<ColorBgra> DefaultColors = Services.GetService<IPalettesService>().CurrentPalette; foreach (string rawPoint in points) { string myPoint = rawPoint.Trim(); // process each line in the text box if (myPoint.Contains(",")) { float x,y; ISolidColorBrush shapeBrush = deviceContext.CreateSolidColorBrush(DefaultColors[brushIndex]); if (myPoint == ",") { x = firstX; y = firstY; } else { if (!float.TryParse(myPoint.Substring(0,myPoint.IndexOf(",")), out x)) { //x = 0; } if (!float.TryParse(myPoint.Substring(myPoint.IndexOf(",")+1), out y)) { //y = 0; } else { y = -y; } currentShape.Add(new Point2Float(x,y)); } if (first) { firstX = x; firstY = y; first = false; } // draw a dot at our specified x,y position deviceContext.DrawRoundedRectangle(new RoundedRect( CenterX+(cellSize * x)-1.5f, CenterY+(cellSize * y)-1.5f, 3, 3, 3 ), shapeBrush,3); // if we have a previous dot, draw a line between them if (prev) { deviceContext.DrawLine( new Point2Float(CenterX+(cellSize * x),CenterY+(cellSize * y)), new Point2Float(CenterX+(cellSize * previousX),CenterY+(cellSize * previousY)), shapeBrush, 2); } previousX = x; previousY = y; prev = true; } else { if (labelPoints) { // Determine the center of our shape float totalX = 0; float totalY = 0; foreach (Point2Float point in currentShape) { totalX += point.X; totalY += point.Y; } float shapeCenterX = totalX / currentShape.Count; float shapeCenterY = totalY / currentShape.Count; // Draw point labels foreach (Point2Float point in currentShape) { float differenceInX = shapeCenterX - point.X; float differenceInY = shapeCenterY - point.Y; float distance = (float)Math.Sqrt((shapeCenterX - point.X)*(shapeCenterX - point.X) + (shapeCenterY - point.Y)*(shapeCenterY - point.Y)); if (distance == 0) { differenceInX = 1; differenceInY = 1; distance = 1; } differenceInX /= distance; differenceInY /= distance; ISolidColorBrush shapeBrush = deviceContext.CreateSolidColorBrush(DefaultColors[brushIndex]); float myX = CenterX+(cellSize * (point.X - (differenceInX * 0.5f)))-4.5f; float myY = CenterY+(cellSize * (point.Y - (differenceInY * 0.5f)))-4.5f; deviceContext.DrawText(label.ToString(),labelTextFormat,new RectFloat(myX,myY,100,100),shapeBrush,DrawTextOptions.None); if (label == 'Z') { label = 'a'; } else if (label == 'z') { label = 'A'; } else { label++; } } } // start the next shape prev = false; first = true; brushIndex += 1; currentShape.Clear(); } } } I use this when helping my kids with their geometry homework. Since the script is just for my own use, it doesn't have a lot of error checking. And, I haven't bothered to go back and clean it up. // you've been warned! Each shape gets a different color. The first shape gets color index 2, red. Then, each shape after that gets the next color from the default color palette. EDIT: Download v2.1 below! 3 3 Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted February 6 Share Posted February 6 Nice! I wanted to have a play with this, but I'm unable to build the DLL from the source (using Codelab 6.11). Appears to Render fine from Codelab ...but has build errors. Edit: Is there a clever way to copy the Error List in Codelab? Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted February 6 Share Posted February 6 Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
BoltBait Posted February 6 Author Share Posted February 6 @Ego Eram Reputo the critical line is here: Make sure you save this script to a file that ends in .cs and open it from there. Make sure the file name does not have a space in it. I call mine BBGraphPaper.cs 1 Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted February 6 Share Posted February 6 10 minutes ago, BoltBait said: Make sure the file name does not have a space in it. You'd think by now I'd have learned this ^. Solved Thank you @BoltBait Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
BoltBait Posted February 6 Author Share Posted February 6 Published v1.1 with ability to label points. Basically, it calculates the center of each shape, follows a ray from the center of the object through a specific vertex to slightly beyond it and draws the label letter there. So, for regular shapes, the labels will always be outside the shape. For irregular shapes, ymmv. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
toe_head2001 Posted February 6 Share Posted February 6 (edited) 2 hours ago, BoltBait said: Make sure the file name does not have a space in it. I thought that issue was solved a very long time ago. Edit: Fixed in CodeLab. Must have been lost during the GPU refactoring. Edited February 6 by toe_head2001 Quote (September 25th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
lynxster4 Posted February 6 Share Posted February 6 @BoltBait I followed the instructions throughout (using VS 2022) and I'm getting these error messages in Codelab 6.11: A lot has changed since I was messing with code. Can you guide me? Quote My Art Gallery | My Shape Packs | ShapeMaker Mini Tut | Air Bubble Stained Glass Chrome Text with Reflections | Porcelain Text w/ Variegated Coloring | Realistic Knit PatternOpalescent Stained Glass | Frosted Snowman Cookie | Leather Texture | Plastic Text | Silk Embroidery Visit my Personal Website "Never, ever lose your sense of humor - you'll live longer" Link to comment Share on other sites More sharing options...
BoltBait Posted February 6 Author Share Posted February 6 On 2/6/2024 at 5:47 AM, lynxster4 said: Can you guide me? Before pasting the script into CodeLab, do this: Run CodeLab. File > New > GPU Drawing Effect: Only THEN should you select all and paste into the CodeLab editor. OR You could use your favorite text editor (Notepad++) to save the source code to a file BBGraphPaper.cs and then run CodeLab and open it from there. HISTORY: Way back in the day, there used to only be one type of CodeLab script. So, pasting a script into the editor just worked. Now, there are 4+ different types of CodeLab scripts (Classic, Bitmap, GPU Image, and GPU Drawing--not to mention FileTypes and Shapes). In order to compile your script, CodeLab needs to know which type of script it is. This detection happens when you open a new window (through File > New > ...) or when you open a file from disk. Once determined, the effect type can't be changed. In the future, CodeLab may get better at this, but for now, that's just the way it works. EDIT: CodeLab v6.12 no longer has this problem. It will detect what type of script you're trying to compile and adjust itself accordingly. 1 Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
lynxster4 Posted February 6 Share Posted February 6 1 hour ago, BoltBait said: Run CodeLab. File > New > GPU Drawing Effect: Thank you, BB! Worked perfectly. This is a neat plugin being able to make geometric shapes. 🤩 Quote My Art Gallery | My Shape Packs | ShapeMaker Mini Tut | Air Bubble Stained Glass Chrome Text with Reflections | Porcelain Text w/ Variegated Coloring | Realistic Knit PatternOpalescent Stained Glass | Frosted Snowman Cookie | Leather Texture | Plastic Text | Silk Embroidery Visit my Personal Website "Never, ever lose your sense of humor - you'll live longer" Link to comment Share on other sites More sharing options...
BoltBait Posted February 7 Author Share Posted February 7 Fixed a label bug in the script if there is a point right on the calculated center of the shape or if there was just a single point. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
BoltBait Posted February 8 Author Share Posted February 8 Version 2.0! By turning off "Draw lines connecting points", changing the "Label points" to numeric, I believe someone could use this to create dot-to-dot puzzles for kids. Leave the grid "on" while creating your dot-to-dot, then turn it off for the final render. If you notice in the upper left corner, I did add the Perimeter or Distance. I also found an algorithm for calculating Area... it can get confused if the shape's lines cross, but otherwise works pretty well. According to the site: Screenshots: Download: <Snip!> Download v2.1 in a post below... Source Code: Spoiler I had to switch from CodeLab script into a full project to add the tabs into the UI. I'll leave the CodeLab script for v1.1 in the first post, but it's too long now for posting. Sorry. Plans: I'm pretty much done tinkering with this. I probably won't add it into my plugin pack as it's pretty specialized. But, you can always download it here. Enjoy! 2 2 Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
Rick Brewster Posted February 15 Share Posted February 15 On 2/7/2024 at 11:37 PM, BoltBait said: I also found an algorithm for calculating Area You can also use IGeometry::ComputeArea() Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
BoltBait Posted February 18 Author Share Posted February 18 Version 2.1! Just a little clean up of the UI... Added a few more controls to change colors and other options. My son really finds this helpful in his Geometry class. Often, problems will be something like, "You have a triangle with points A(-5,0) B(2,6) and C(6,-2)..." etc. This gives him a quick way to create his drawing for working the problem. This is why I wrote this plugin. Another use for this plugin is to make simple dot-to-dot puzzles for children. Here's one I made: Spoiler 0,0 -5,0 0.5,10 6,0 1,0 1,-2 7,-2 6,-4 -5,-4 -6,-2 0,-2 , Anyway, NOW I'm done tinkering with this! BBGraphPaper.zip Enjoy. 3 3 Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.