Exemple #1
0
 /// <summary>
 /// Gets the Potrace settings from the plug-in settings file.
 /// </summary>
 private void GetPotraceSettings()
 {
     Potrace.RestoreDefaults();
     if (Settings.TryGetInteger("turnpolicy", out var turnpolicy))
     {
         Potrace.turnpolicy = (TurnPolicy)turnpolicy;
     }
     if (Settings.TryGetInteger("turdsize", out var turdsize))
     {
         Potrace.turdsize = turdsize;
     }
     if (Settings.TryGetDouble("alphamax", out var alphamax))
     {
         Potrace.alphamax = alphamax;
     }
     if (Settings.TryGetBool("curveoptimizing", out var curveoptimizing))
     {
         Potrace.curveoptimizing = curveoptimizing;
     }
     if (Settings.TryGetDouble("opttolerance", out var opttolerance))
     {
         Potrace.opttolerance = opttolerance;
     }
     if (Settings.TryGetDouble("Treshold", out var Treshold))
     {
         Potrace.Treshold = Treshold;
     }
 }
        /// <summary>
        /// Creates the content of the dialog
        /// </summary>
        private RhinoDialogTableLayout CreateTableLayout()
        {
            // Create controls and define behaviors

            var ns_threshold = new NumericUpDownWithUnitParsing
            {
                ValueUpdateMode = NumericUpDownWithUnitParsingUpdateMode.WhenDoneChanging,
                MinValue        = 0.0,
                MaxValue        = 100.0,
                DecimalPlaces   = 0,
                Increment       = 1.0,
                ToolTip         = "Weighted RGB color evaluation threshold.",
                Value           = (int)(Potrace.Treshold * 100.0), Width = 45
            };

            var sld_threshold = new Slider
            {
                MinValue      = 0,
                MaxValue      = 100,
                TickFrequency = 25,
                Value         = (int)(Potrace.Treshold * 100.0),
                Width         = 220
            };

            ns_threshold.ValueChanged += (sender, args) =>
            {
                if (m_allow_update_and_redraw)
                {
                    m_allow_update_and_redraw = false;
                    Potrace.Treshold          = ns_threshold.Value / 100.0;
                    sld_threshold.Value       = (int)(Potrace.Treshold * 100.0);
                    m_allow_update_and_redraw = true;
                    UpdateAndRedraw();
                }
            };

            sld_threshold.ValueChanged += (sender, args) =>
            {
                if (m_allow_update_and_redraw)
                {
                    m_allow_update_and_redraw = false;
                    Potrace.Treshold          = sld_threshold.Value / 100.0;
                    ns_threshold.Value        = (int)(Potrace.Treshold * 100.0);
                    m_allow_update_and_redraw = true;
                    UpdateAndRedraw();
                }
            };

            var dd_turnpolicy = new DropDown
            {
                ToolTip = "Algorithm used to resolve ambiguities in path decomposition."
            };

            foreach (var str in Enum.GetNames(typeof(TurnPolicy)))
            {
                dd_turnpolicy.Items.Add(str);
            }
            dd_turnpolicy.SelectedIndex         = (int)Potrace.turnpolicy;
            dd_turnpolicy.SelectedIndexChanged += (sender, args) =>
            {
                if (dd_turnpolicy.SelectedIndex != 0)
                {
                    Potrace.turnpolicy = (TurnPolicy)dd_turnpolicy.SelectedIndex;
                    UpdateAndRedraw();
                }
            };

            var ns_turdsize = new NumericUpDownWithUnitParsing
            {
                ValueUpdateMode = NumericUpDownWithUnitParsingUpdateMode.WhenDoneChanging,
                MinValue        = 1.0,
                MaxValue        = 100.0,
                DecimalPlaces   = 0,
                Increment       = 1.0,
                ToolTip         = "Filter speckles of up to this size in pixels.",
                Value           = Potrace.turdsize
            };

            ns_turdsize.ValueChanged += (sender, args) =>
            {
                Potrace.turdsize = (int)ns_turdsize.Value;
                UpdateAndRedraw();
            };

            var ns_alphamax = new NumericUpDownWithUnitParsing
            {
                ValueUpdateMode = NumericUpDownWithUnitParsingUpdateMode.WhenDoneChanging,
                MinValue        = 0.0,
                MaxValue        = 100.0,
                DecimalPlaces   = 0,
                Increment       = 1.0,
                ToolTip         = "Corner rounding threshold.",
                Value           = Potrace.alphamax
            };

            ns_alphamax.ValueChanged += (sender, args) =>
            {
                Potrace.alphamax = ns_alphamax.Value;
                UpdateAndRedraw();
            };

            var chk_curveoptimizing = new CheckBox
            {
                ThreeState = false,
                ToolTip    = "Optimize of Bézier segments by a single segment when possible.",
                Checked    = Potrace.curveoptimizing
            };

            var ns_opttolerance = new NumericUpDownWithUnitParsing
            {
                ValueUpdateMode = NumericUpDownWithUnitParsingUpdateMode.WhenDoneChanging,
                MinValue        = 0.1,
                MaxValue        = 1.0,
                DecimalPlaces   = 1,
                Increment       = 0.1,
                Enabled         = Potrace.curveoptimizing,
                ToolTip         = "Tolerance used to optimize Bézier segments.",
                Value           = Potrace.opttolerance
            };

            chk_curveoptimizing.CheckedChanged += (sender, args) =>
            {
                Potrace.curveoptimizing = chk_curveoptimizing.Checked.Value;
                ns_opttolerance.Enabled = Potrace.curveoptimizing;
                UpdateAndRedraw();
            };

            ns_opttolerance.ValueChanged += (sender, args) =>
            {
                Potrace.opttolerance = ns_opttolerance.Value;
                UpdateAndRedraw();
            };

            var btn_reset = new Button
            {
                Text = "Restore Defaults"
            };

            btn_reset.Click += (sender, args) =>
            {
                m_allow_update_and_redraw = false;
                Potrace.RestoreDefaults();
                sld_threshold.Value         = (int)(Potrace.Treshold * 100.0);
                ns_threshold.Value          = sld_threshold.Value;
                dd_turnpolicy.SelectedIndex = (int)Potrace.turnpolicy;
                ns_turdsize.Value           = Potrace.turdsize;
                ns_alphamax.Value           = Potrace.alphamax;
                chk_curveoptimizing.Checked = Potrace.curveoptimizing;
                ns_opttolerance.Value       = Potrace.opttolerance;
                m_allow_update_and_redraw   = true;
                UpdateAndRedraw();
            };

            // Layout the controls

            var minimum_size = new Eto.Drawing.Size(150, 0);

            var layout = new RhinoDialogTableLayout(false)
            {
                Spacing = new Eto.Drawing.Size(10, 8)
            };

            layout.Rows.Add(new TableRow(new TableCell(new LabelSeparator {
                Text = "Vectorization options"
            }, true)));

            var panel0 = new Panel {
                MinimumSize = minimum_size, Content = new Label()
                {
                    Text = "Threshold"
                }
            };
            var table0 = new TableLayout {
                Padding = new Eto.Drawing.Padding(8, 0, 0, 0)
            };

            table0.Rows.Add(new TableRow(new TableCell(panel0), new TableCell(sld_threshold, true), new TableCell(ns_threshold)));
            layout.Rows.Add(table0);

            var panel1 = new Panel {
                MinimumSize = minimum_size, Content = new Label()
                {
                    Text = "Turn policy"
                }
            };
            var table1 = new TableLayout {
                Padding = new Eto.Drawing.Padding(8, 0, 0, 0), Spacing = new Size(10, 8)
            };

            table1.Rows.Add(new TableRow(new TableCell(panel1), new TableCell(dd_turnpolicy)));
            table1.Rows.Add(new TableRow(new TableCell(new Label()
            {
                Text = "Filter size"
            }), new TableCell(ns_turdsize)));
            table1.Rows.Add(new TableRow(new TableCell(new Label()
            {
                Text = "Corner rounding"
            }), new TableCell(ns_alphamax)));
            layout.Rows.Add(table1);

            layout.Rows.Add(new TableRow(new TableCell(new LabelSeparator {
                Text = "Curve optimization"
            }, true)));

            var panel2 = new Panel {
                MinimumSize = minimum_size, Content = new Label()
                {
                    Text = "Optimizing"
                }
            };
            var table2 = new TableLayout {
                Padding = new Eto.Drawing.Padding(8, 0, 0, 0), Spacing = new Size(10, 8)
            };

            table2.Rows.Add(new TableRow(new TableCell(panel2), new TableCell(chk_curveoptimizing)));
            table2.Rows.Add(new TableRow(new TableCell(new Label()
            {
                Text = "Tolerance"
            }), new TableCell(ns_opttolerance)));
            table2.Rows.Add(null);
            table2.Rows.Add(new TableRow(new TableCell(new Label()
            {
                Text = ""
            }), new TableCell(btn_reset)));
            layout.Rows.Add(table2);

            return(layout);
        }
Exemple #3
0
        /// <summary>
        /// Command.RunCommand override
        /// </summary>
        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            Potrace.Clear();

            // Prompt the user for the name of the image file to vectorize.
            string path = GetImageFileName(mode);

            if (string.IsNullOrEmpty(path))
            {
                return(Result.Cancel);
            }

            // Creates a bitmap from the specified file.
            var bitmap = Image.FromFile(path) as Bitmap;

            if (null == bitmap)
            {
                RhinoApp.WriteLine("The specified file cannot be identifed as a supported type.");
                return(Result.Failure);
            }

            // Verify bitmap size
            if (0 == bitmap.Width || 0 == bitmap.Height)
            {
                RhinoApp.WriteLine("Error reading the specified file.");
                return(Result.Failure);
            }

            // Calculate scale factor so curves of a reasonable size are added to Rhino
            var unit_scale = (doc.ModelUnitSystem != UnitSystem.Inches)
        ? RhinoMath.UnitScale(UnitSystem.Inches, doc.ModelUnitSystem)
        : 1.0;
            var scale = (double)(1.0 / bitmap.HorizontalResolution * unit_scale);

            // I'm not convinced this is useful...
            if (true)
            {
                var format = $"F{doc.DistanceDisplayPrecision}";

                // Print image size in pixels
                RhinoApp.WriteLine("Image size in pixels: {0} x {1}",
                                   bitmap.Width,
                                   bitmap.Height
                                   );

                // Print image size in inches
                var width  = (double)(bitmap.Width / bitmap.HorizontalResolution);
                var height = (double)(bitmap.Height / bitmap.VerticalResolution);
                RhinoApp.WriteLine("Image size in inches: {0} x {1}",
                                   width.ToString(format, CultureInfo.InvariantCulture),
                                   height.ToString(format, CultureInfo.InvariantCulture)
                                   );

                // Image size in in model units, if needed
                if (doc.ModelUnitSystem != UnitSystem.Inches)
                {
                    width  = (double)(bitmap.Width / bitmap.HorizontalResolution * unit_scale);
                    height = (double)(bitmap.Height / bitmap.VerticalResolution * unit_scale);
                    RhinoApp.WriteLine("Image size in {0}: {1} x {2}",
                                       doc.ModelUnitSystem.ToString().ToLower(),
                                       width.ToString(format, CultureInfo.InvariantCulture),
                                       height.ToString(format, CultureInfo.InvariantCulture)
                                       );
                }
            }

            // Convert the bitmap to an Eto bitmap
            var eto_bitmap = ConvertBitmapToEto(bitmap);

            if (null == eto_bitmap)
            {
                RhinoApp.WriteLine("Unable to convert image to Eto bitmap.");
                return(Result.Failure);
            }

            // 12-Jan-2021 Dale Fugier
            // This should prevent Eto.Drawing.BitmapData.GetPixels() from throwing an exception
            if (!IsCompatibleBitmap(eto_bitmap))
            {
                RhinoApp.WriteLine("The image has an incompatible pixel format. Please select an image with 24 or 32 bits per pixel, or 8 bit indexed.");
                return(Result.Failure);
            }

            // This bitmap is not needed anymore, so dispose of it
            bitmap.Dispose();

            // Gets the Potrace settings from the plug-in settings file
            GetPotraceSettings();

            // Create the conduit, which does most of the work
            var conduit = new VectorizeConduit(
                eto_bitmap,
                scale,
                doc.ModelAbsoluteTolerance,
                m_select_output
          ? Rhino.ApplicationSettings.AppearanceSettings.SelectedObjectColor
          : doc.Layers.CurrentLayer.Color
                )
            {
                Enabled = true
            };

            if (mode == RunMode.Interactive)
            {
                // Show the interactive dialog box
                var dialog = new VectorizeDialog(doc, conduit);
                dialog.RestorePosition();
                var result = dialog.ShowSemiModal(doc, RhinoEtoApp.MainWindow);
                dialog.SavePosition();
                if (result != Result.Success)
                {
                    conduit.Enabled = false;
                    Potrace.Clear();
                    doc.Views.Redraw();
                    return(Result.Cancel);
                }
            }
            else
            {
                // Show the command line options
                var go = new GetOption();
                go.SetCommandPrompt("Vectorization options. Press Enter when done");
                go.AcceptNothing(true);
                while (true)
                {
                    conduit.TraceBitmap();
                    doc.Views.Redraw();

                    go.ClearCommandOptions();

                    // IgnoreArea
                    var turdsize_opt = new OptionInteger(Potrace.turdsize, 2, 100);
                    var turdsize_idx = go.AddOptionInteger("FilterSize", ref turdsize_opt, "Filter speckles of up to this size in pixels");

                    // TurnPolicy
                    var turnpolicy_idx = go.AddOptionEnumList("TurnPolicy", Potrace.turnpolicy);

                    // Optimizing
                    var curveoptimizing_opt = new OptionToggle(Potrace.curveoptimizing, "No", "Yes");
                    var curveoptimizing_idx = go.AddOptionToggle("Optimizing", ref curveoptimizing_opt);

                    // Tolerance
                    var opttolerance_opt = new OptionDouble(Potrace.opttolerance, 0.0, 1.0);
                    var opttolerance_idx = go.AddOptionDouble("Tolerance", ref opttolerance_opt, "Optimizing tolerance");

                    // CornerThreshold
                    var alphamax_opt = new OptionDouble(Potrace.alphamax, 0.0, 100.0);
                    var alphamax_idx = go.AddOptionDouble("CornerRounding", ref alphamax_opt, "Corner rounding threshold");

                    // Threshold
                    var threshold_opt = new OptionDouble(Potrace.Treshold, 0.0, 100.0);
                    var threshold_idx = go.AddOptionDouble("Threshold", ref threshold_opt, "Threshold");

                    // RestoreDefaults
                    var defaults_idx = go.AddOption("RestoreDefaults");

                    var res = go.Get();

                    if (res == GetResult.Option)
                    {
                        var option = go.Option();
                        if (null != option)
                        {
                            if (turdsize_idx == option.Index)
                            {
                                Potrace.turdsize = turdsize_opt.CurrentValue;
                            }

                            if (turnpolicy_idx == option.Index)
                            {
                                var list = Enum.GetValues(typeof(TurnPolicy)).Cast <TurnPolicy>().ToList();
                                Potrace.turnpolicy = list[option.CurrentListOptionIndex];
                            }

                            if (curveoptimizing_idx == option.Index)
                            {
                                Potrace.curveoptimizing = curveoptimizing_opt.CurrentValue;
                            }

                            if (opttolerance_idx == option.Index)
                            {
                                Potrace.opttolerance = opttolerance_opt.CurrentValue;
                            }

                            if (alphamax_idx == option.Index)
                            {
                                Potrace.alphamax = alphamax_opt.CurrentValue;
                            }

                            if (threshold_idx == option.Index)
                            {
                                Potrace.Treshold = threshold_opt.CurrentValue;
                            }

                            if (defaults_idx == option.Index)
                            {
                                Potrace.RestoreDefaults();
                            }
                        }
                        continue;
                    }

                    if (res != GetResult.Nothing)
                    {
                        conduit.Enabled = false;
                        doc.Views.Redraw();
                        Potrace.Clear();
                        return(Result.Cancel);
                    }

                    break;
                }
            }

            // Group curves
            var attributes = doc.CreateDefaultAttributes();

            attributes.AddToGroup(doc.Groups.Add());
            for (var i = 0; i < conduit.OutlineCurves.Count; i++)
            {
                var rhobj_id = doc.Objects.AddCurve(conduit.OutlineCurves[i], attributes);
                if (m_select_output)
                {
                    var rhobj = doc.Objects.Find(rhobj_id);
                    if (null != rhobj)
                    {
                        rhobj.Select(true);
                    }
                }
            }

            conduit.Enabled = false;
            Potrace.Clear();
            doc.Views.Redraw();

            // Set the Potrace settings to the plug -in settings file.
            SetPotraceSettings();

            return(Result.Success);
        }