├── .gitignore
├── MeshMachine.sln
├── README.md
├── Reading.md
├── examples
└── colorlength3.gh
├── lib
└── README
└── src
├── ITargetLength.cs
├── Properties
├── AssemblyInfo.cs
├── Resources.Designer.cs
└── Resources.resx
├── Resources
├── remesh.png
└── remesh2.png
├── remesher.cs
├── remesher.csproj
└── remesherInfo.cs
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 |
11 | [Dd]ebug/
12 | [Rr]elease/
13 | x64/
14 | build/
15 | [Bb]in/
16 | [Oo]bj/
17 |
18 | # Referenced Libraries
19 | [Ll]ib/**/*.dll
20 | [Ll]ib/**/*.xml
21 | [Ll]ib/**/*.gha
22 |
23 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
24 | !packages/*/build/
25 |
26 | # MSTest test Results
27 | [Tt]est[Rr]esult*/
28 | [Bb]uild[Ll]og.*
29 |
30 | *_i.c
31 | *_p.c
32 | *.ilk
33 | *.meta
34 | *.obj
35 | *.pch
36 | *.pdb
37 | *.pgc
38 | *.pgd
39 | *.rsp
40 | *.sbr
41 | *.tlb
42 | *.tli
43 | *.tlh
44 | *.tmp
45 | *.tmp_proj
46 | *.log
47 | *.vspscc
48 | *.vssscc
49 | .builds
50 | *.pidb
51 | *.log
52 | *.scc
53 |
54 | # Visual C++ cache files
55 | ipch/
56 | *.aps
57 | *.ncb
58 | *.opensdf
59 | *.sdf
60 | *.cachefile
61 |
62 | # Visual Studio profiler
63 | *.psess
64 | *.vsp
65 | *.vspx
66 |
67 | # Guidance Automation Toolkit
68 | *.gpState
69 |
70 | # ReSharper is a .NET coding add-in
71 | _ReSharper*/
72 | *.[Rr]e[Ss]harper
73 |
74 | # TeamCity is a build add-in
75 | _TeamCity*
76 |
77 | # DotCover is a Code Coverage Tool
78 | *.dotCover
79 |
80 | # NCrunch
81 | *.ncrunch*
82 | .*crunch*.local.xml
83 |
84 | # Installshield output folder
85 | [Ee]xpress/
86 |
87 | # DocProject is a documentation generator add-in
88 | DocProject/buildhelp/
89 | DocProject/Help/*.HxT
90 | DocProject/Help/*.HxC
91 | DocProject/Help/*.hhc
92 | DocProject/Help/*.hhk
93 | DocProject/Help/*.hhp
94 | DocProject/Help/Html2
95 | DocProject/Help/html
96 |
97 | # Click-Once directory
98 | publish/
99 |
100 | # Publish Web Output
101 | *.Publish.xml
102 | *.pubxml
103 |
104 | # NuGet Packages Directory
105 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
106 | #packages/
107 |
108 | # Windows Azure Build Output
109 | csx
110 | *.build.csdef
111 |
112 | # Windows Store app package directory
113 | AppPackages/
114 |
115 | # Others
116 | sql/
117 | *.Cache
118 | ClientBin/
119 | [Ss]tyle[Cc]op.*
120 | ~$*
121 | *~
122 | *.dbmdl
123 | *.[Pp]ublish.xml
124 | *.pfx
125 | *.publishsettings
126 |
127 | # RIA/Silverlight projects
128 | Generated_Code/
129 |
130 | # Backup & report files from converting an old project file to a newer
131 | # Visual Studio version. Backup files are not needed, because we have git ;-)
132 | _UpgradeReport_Files/
133 | Backup*/
134 | UpgradeLog*.XML
135 | UpgradeLog*.htm
136 |
137 | # SQL Server files
138 | App_Data/*.mdf
139 | App_Data/*.ldf
140 |
141 | # =========================
142 | # Windows detritus
143 | # =========================
144 |
145 | # Windows image file caches
146 | Thumbs.db
147 | ehthumbs.db
148 |
149 | # Folder config file
150 | Desktop.ini
151 |
152 | # Recycle Bin used on file shares
153 | $RECYCLE.BIN/
154 |
155 | # Mac crap
156 | .DS_Store
157 |
--------------------------------------------------------------------------------
/MeshMachine.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.30723.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "remesher", "src\remesher.csproj", "{9EA05C6C-A88C-4FF2-8E7D-98FC412F4944}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug32|Any CPU = Debug32|Any CPU
11 | Debug64|Any CPU = Debug64|Any CPU
12 | Release|Any CPU = Release|Any CPU
13 | EndGlobalSection
14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
15 | {9EA05C6C-A88C-4FF2-8E7D-98FC412F4944}.Debug32|Any CPU.ActiveCfg = Debug32|Any CPU
16 | {9EA05C6C-A88C-4FF2-8E7D-98FC412F4944}.Debug32|Any CPU.Build.0 = Debug32|Any CPU
17 | {9EA05C6C-A88C-4FF2-8E7D-98FC412F4944}.Debug64|Any CPU.ActiveCfg = Debug64|Any CPU
18 | {9EA05C6C-A88C-4FF2-8E7D-98FC412F4944}.Debug64|Any CPU.Build.0 = Debug64|Any CPU
19 | {9EA05C6C-A88C-4FF2-8E7D-98FC412F4944}.Release|Any CPU.ActiveCfg = Release|Any CPU
20 | {9EA05C6C-A88C-4FF2-8E7D-98FC412F4944}.Release|Any CPU.Build.0 = Release|Any CPU
21 | EndGlobalSection
22 | GlobalSection(SolutionProperties) = preSolution
23 | HideSolutionNode = FALSE
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | MeshMachine
2 | ===========
3 |
4 | Remeshing component for Grasshopper using Plankton
5 |
--------------------------------------------------------------------------------
/Reading.md:
--------------------------------------------------------------------------------
1 | The approach to triangular remeshing used in MeshMachine draws on the following papers and presentations:
2 |
3 | [Dynamic Remeshing and Applications](https://domino.mpi-inf.mpg.de/intranet/ag4/ag4publ.nsf/0/690dfda53d7bd4d8c1256cd4004eb2f0/$FILE/vorsatz.pdf), by Vorsatz, Rossl, and Seidel
4 |
5 | [A Remeshing Approach to Multiresolution Modeling](http://graphics.uni-bielefeld.de/publications/sgp04.pdf), by Botsch and Kobbelt
6 |
7 | [Mesh Optimization](http://research.microsoft.com/en-us/um/people/hoppe/meshopt.pdf), by Hoppe, DeRose, Duchampy, McDonaldz and Stuetzlez
8 |
9 | [Direct Triangle Meshes Remeshing using Stellar Operators](http://w3.impa.br/~zang/pg2012/pg2012-slides.pdf), by Zang and Prada
10 |
11 | [Explicit Surface Remeshing](http://www.cs.technion.ac.il/~vitus/papers/ExplicitRemeshing.pdf), by Surazhsky and Gotsman
12 |
13 | [Delaunay Mesh Construction](http://www.cs.sfu.ca/~haoz/pubs/dyer_et_al_sgp07.pdf), by Dyer, Zhang and Möller
14 |
15 | [Triangulations and meshes in computational geometry](http://www.cis.upenn.edu/~cis610/sp06edelsbrunner1.pdf), by Edelsbrunner
16 |
17 | [Updating and Constructing Constrained Delaunay and Constrained Regular Triangulations by Flips](http://www.cs.berkeley.edu/~jrs/papers/cdtflip.pdf), by Shewchuk
18 |
19 | [Iterative method for edge length equalization](http://www.gcg.ufjf.br/pub/doc74.pdf), by Pecanha, Souza Filho, Vieira, Lobosco and Dantas
20 |
--------------------------------------------------------------------------------
/examples/colorlength3.gh:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dan-Piker/MeshMachine/e47321af77b6b8048c1b0fcf29c758fecebfc481/examples/colorlength3.gh
--------------------------------------------------------------------------------
/lib/README:
--------------------------------------------------------------------------------
1 | Put any third-party assemblies in here.
2 |
--------------------------------------------------------------------------------
/src/ITargetLength.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Grasshopper;
7 | using Grasshopper.Kernel;
8 | using Grasshopper.Kernel.Types;
9 | using Grasshopper.Kernel.Data;
10 | using Grasshopper.Kernel.Parameters;
11 | using Rhino.Geometry;
12 | using Plankton;
13 | using PlanktonGh;
14 |
15 | namespace remesher
16 | {
17 | public interface ITargetLength
18 | {
19 | double Calculate(PlanktonMesh P, int HalfEdge);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 | using Rhino.PlugIns;
5 |
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("MeshMachine")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("MeshMachine")]
15 | [assembly: AssemblyCopyright("Copyright © Daniel Piker 2014")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | [assembly: Guid("427ba99f-32eb-4df7-a2fd-0c37912565e2")] // This will also be the Guid of the Rhino plug-in
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // [assembly: AssemblyVersion("1.0.*")]
37 | [assembly: AssemblyVersion("1.0.0.0")]
38 | [assembly: AssemblyFileVersion("1.0.0.0")]
39 |
--------------------------------------------------------------------------------
/src/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.34014
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace remesher.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("remesher.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized resource of type System.Drawing.Bitmap.
65 | ///
66 | internal static System.Drawing.Bitmap remesh {
67 | get {
68 | object obj = ResourceManager.GetObject("remesh", resourceCulture);
69 | return ((System.Drawing.Bitmap)(obj));
70 | }
71 | }
72 |
73 | ///
74 | /// Looks up a localized resource of type System.Drawing.Bitmap.
75 | ///
76 | internal static System.Drawing.Bitmap remesh2 {
77 | get {
78 | object obj = ResourceManager.GetObject("remesh2", resourceCulture);
79 | return ((System.Drawing.Bitmap)(obj));
80 | }
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | ..\Resources\remesh.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
123 |
124 |
125 | ..\Resources\remesh2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
126 |
127 |
--------------------------------------------------------------------------------
/src/Resources/remesh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dan-Piker/MeshMachine/e47321af77b6b8048c1b0fcf29c758fecebfc481/src/Resources/remesh.png
--------------------------------------------------------------------------------
/src/Resources/remesh2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dan-Piker/MeshMachine/e47321af77b6b8048c1b0fcf29c758fecebfc481/src/Resources/remesh2.png
--------------------------------------------------------------------------------
/src/remesher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Grasshopper.Kernel;
4 | using Grasshopper.Kernel.Types;
5 | using Grasshopper.Kernel.Data;
6 | using Grasshopper.Kernel.Parameters;
7 | using Rhino.Geometry;
8 | using Plankton;
9 | using PlanktonGh;
10 |
11 |
12 |
13 | namespace remesher
14 | {
15 | public class remesher : GH_Component
16 | {
17 | public remesher()
18 | : base("remesher", "remesher",
19 | "Remeshing tool",
20 | "Kangaroo", "Mesh")
21 | {
22 | }
23 |
24 |
25 | protected override void RegisterInputParams(GH_InputParamManager pManager)
26 | {
27 | //0
28 | pManager.AddGeometryParameter("Geometry", "Geom", "Input Surface or Mesh", GH_ParamAccess.item);
29 |
30 | //1
31 | pManager.AddGenericParameter("TargetLengthFunction", "L", "A function determining local edge length", GH_ParamAccess.item);
32 |
33 | //2
34 | pManager.AddCurveParameter("FixCurves", "FixC", "Curves which will be kept sharp during remeshing. Can be boundary or internal curves", GH_ParamAccess.list);
35 | pManager[2].Optional = true;
36 |
37 | //3
38 | pManager.AddPointParameter("FixVertices", "FixV", "Points to keep fixed during remeshing", GH_ParamAccess.list);
39 | pManager[3].Optional = true;
40 |
41 | //4
42 | pManager.AddIntegerParameter("Flip", "Flip", "Criterion used to decide when to flip edges (0 for valence based, 1 for angle based)", GH_ParamAccess.item, 1);
43 |
44 | //5
45 | pManager.AddNumberParameter("PullStrength", "Pull", "Strength of pull to target geometry (between 0 and 1). Set to 0 for minimal surfaces", GH_ParamAccess.item, 0.8);
46 |
47 | //6
48 | pManager.AddIntegerParameter("Iterations", "Iter", "Number of steps between outputs", GH_ParamAccess.item, 1);
49 |
50 | //7
51 | pManager.AddBooleanParameter("Reset", "Reset", "True to initialize, false to run remeshing. Connect a timer for continuous remeshing", GH_ParamAccess.item, true);
52 | }
53 |
54 | protected override void RegisterOutputParams(GH_OutputParamManager pManager)
55 | {
56 | pManager.AddGenericParameter("Mesh", "M", "Remeshed result as Plankton Mesh", GH_ParamAccess.item);
57 | }
58 |
59 | private PlanktonMesh P = new PlanktonMesh();
60 | private Mesh M = new Mesh();
61 | private List AnchorV = new List();
62 | private List FeatureV = new List();
63 | private List FeatureE = new List();
64 | private bool initialized;
65 |
66 | protected override void SolveInstance(IGH_DataAccess DA)
67 | {
68 | ITargetLength TargetLength = null;
69 | bool reset = false;
70 | int Flip = 0;
71 | List FC = new List();
72 | List FV = new List();
73 | double FixT = 0.01;
74 | double PullStrength = 0.8;
75 | double SmoothStrength = 0.8;
76 | double LengthTol = 0.15;
77 | bool Minim = false;
78 | int Iters = 1;
79 |
80 | GH_ObjectWrapper Surf = new GH_ObjectWrapper();
81 | DA.GetData(0, ref Surf);
82 |
83 | GH_ObjectWrapper Obj = null;
84 | DA.GetData(1, ref Obj);
85 | TargetLength = Obj.Value as ITargetLength;
86 |
87 | DA.GetDataList(2, FC);
88 | DA.GetDataList(3, FV);
89 | DA.GetData(4, ref Flip);
90 |
91 | DA.GetData(5, ref PullStrength);
92 |
93 | DA.GetData(6, ref Iters);
94 | DA.GetData(7, ref reset);
95 |
96 |
97 | if (PullStrength == 0) { Minim = true; }
98 |
99 | if (Surf.Value is GH_Mesh)
100 | {
101 | DA.GetData(0, ref M);
102 | M.Faces.ConvertQuadsToTriangles();
103 | }
104 | else
105 | {
106 | double L = 1.0;
107 | MeshingParameters MeshParams = new MeshingParameters();
108 | MeshParams.MaximumEdgeLength = 3 * L;
109 | MeshParams.MinimumEdgeLength = L;
110 | MeshParams.JaggedSeams = false;
111 | MeshParams.SimplePlanes = false;
112 | Brep SB = null;
113 | DA.GetData(0, ref SB);
114 | Mesh[] BrepMeshes = Mesh.CreateFromBrep(SB, MeshParams);
115 | M = new Mesh();
116 | foreach (var mesh in BrepMeshes)
117 | M.Append(mesh);
118 | }
119 |
120 | if (reset || initialized == false)
121 | {
122 | #region reset
123 | M.Faces.ConvertQuadsToTriangles();
124 | P = M.ToPlanktonMesh();
125 |
126 | initialized = true;
127 |
128 | AnchorV.Clear();
129 | FeatureV.Clear();
130 | FeatureE.Clear();
131 |
132 | //Mark any vertices or edges lying on features
133 | for (int i = 0; i < P.Vertices.Count; i++)
134 | {
135 | Point3d Pt = P.Vertices[i].ToPoint3d();
136 | AnchorV.Add(-1);
137 | for (int j = 0; j < FV.Count; j++)
138 | {
139 | if (Pt.DistanceTo(FV[j]) < FixT)
140 | { AnchorV[AnchorV.Count - 1] = j; }
141 | }
142 |
143 | FeatureV.Add(-1);
144 | for (int j = 0; j < FC.Count; j++)
145 | {
146 | double param = new double();
147 | FC[j].ClosestPoint(Pt, out param);
148 | if (Pt.DistanceTo(FC[j].PointAt(param)) < FixT)
149 | { FeatureV[FeatureV.Count - 1] = j; }
150 | }
151 | }
152 |
153 | int EdgeCount = P.Halfedges.Count / 2;
154 | for (int i = 0; i < EdgeCount; i++)
155 | {
156 | FeatureE.Add(-1);
157 | int vStart = P.Halfedges[2 * i].StartVertex;
158 | int vEnd = P.Halfedges[2 * i + 1].StartVertex;
159 |
160 | Point3d PStart = P.Vertices[vStart].ToPoint3d();
161 | Point3d PEnd = P.Vertices[vEnd].ToPoint3d();
162 |
163 | for (int j = 0; j < FC.Count; j++)
164 | {
165 | double paramS = new double();
166 | double paramE = new double();
167 | Curve thisFC = FC[j];
168 | thisFC.ClosestPoint(PStart, out paramS);
169 | thisFC.ClosestPoint(PEnd, out paramE);
170 | if ((PStart.DistanceTo(thisFC.PointAt(paramS)) < FixT) &&
171 | (PEnd.DistanceTo(thisFC.PointAt(paramE)) < FixT))
172 | {
173 | FeatureE[FeatureE.Count - 1] = j;
174 | }
175 | }
176 | }
177 | #endregion
178 | }
179 |
180 | else
181 | {
182 | for (int iter = 0; iter < Iters; iter++)
183 | {
184 | int EdgeCount = P.Halfedges.Count / 2;
185 | double[] EdgeLength = P.Halfedges.GetLengths();
186 | List Visited = new List();
187 | Vector3d[] Normals = new Vector3d[P.Vertices.Count];
188 |
189 | for (int i = 0; i < P.Vertices.Count; i++)
190 | {
191 | Visited.Add(false);
192 | Normals[i] = Normal(P, i);
193 | }
194 |
195 | double t = LengthTol; //a tolerance for when to split/collapse edges
196 | double smooth = SmoothStrength; //smoothing strength
197 | double pull = PullStrength; //pull to target mesh strength
198 |
199 | // Split the edges that are too long
200 | for (int i = 0; i < EdgeCount; i++)
201 | {
202 | if (P.Halfedges[2 * i].IsUnused == false)
203 | {
204 | int vStart = P.Halfedges[2 * i].StartVertex;
205 | int vEnd = P.Halfedges[2 * i + 1].StartVertex;
206 |
207 | if ((Visited[vStart] == false)
208 | && (Visited[vEnd] == false))
209 | {
210 |
211 | double L2 = TargetLength.Calculate(P, 2 * i);
212 |
213 | if (EdgeLength[2 * i] > (1 + t) * (4f / 3f) * L2)
214 | {
215 |
216 | int SplitHEdge = P.Halfedges.TriangleSplitEdge(2 * i);
217 | if (SplitHEdge != -1)
218 | {
219 | int SplitCenter = P.Halfedges[SplitHEdge].StartVertex;
220 | P.Vertices.SetVertex(SplitCenter, MidPt(P, i));
221 |
222 | //update the feature information
223 | FeatureE.Add(FeatureE[i]);
224 | FeatureV.Add(FeatureE[i]);
225 | AnchorV.Add(-1);
226 |
227 | //2 additional new edges have also been created (or 1 if split was on a boundary)
228 | //mark these as non-features
229 | int CEdgeCount = P.Halfedges.Count / 2;
230 | while (FeatureE.Count < CEdgeCount)
231 | { FeatureE.Add(-1); }
232 |
233 | Visited.Add(true);
234 | int[] Neighbours = P.Vertices.GetVertexNeighbours(SplitCenter);
235 | foreach (int n in Neighbours)
236 | { Visited[n] = true; }
237 | }
238 | }
239 |
240 | }
241 | }
242 | }
243 |
244 | //Collapse the edges that are too short
245 | for (int i = 0; i < EdgeCount; i++)
246 | {
247 | if (P.Halfedges[2 * i].IsUnused == false)
248 | {
249 | int vStart = P.Halfedges[2 * i].StartVertex;
250 | int vEnd = P.Halfedges[2 * i + 1].StartVertex;
251 | if ((Visited[vStart] == false)
252 | && (Visited[vEnd] == false))
253 | {
254 | if (!(AnchorV[vStart] != -1 && AnchorV[vEnd] != -1)) // if both ends are anchored, don't collapse
255 | {
256 | int Collapse_option = 0; //0 for none, 1 for collapse to midpt, 2 for towards start, 3 for towards end
257 | //if neither are anchorV
258 | if (AnchorV[vStart] == -1 && AnchorV[vEnd] == -1)
259 | {
260 | // if both on same feature (or neither on a feature)
261 | if (FeatureV[vStart] == FeatureV[vEnd])
262 | { Collapse_option = 1; }
263 | // if start is on a feature and end isn't
264 | if ((FeatureV[vStart] != -1) && (FeatureV[vEnd] == -1))
265 | { Collapse_option = 2; }
266 | // if end is on a feature and start isn't
267 | if ((FeatureV[vStart] == -1) && (FeatureV[vEnd] != -1))
268 | { Collapse_option = 3; }
269 | }
270 | else // so one end must be an anchor
271 | {
272 | // if start is an anchor
273 | if (AnchorV[vStart] != -1)
274 | {
275 | // if both are on same feature, or if the end is not a feature
276 | if ((FeatureE[i] != -1) || (FeatureV[vEnd] == -1))
277 | { Collapse_option = 2; }
278 | }
279 | // if end is an anchor
280 | if (AnchorV[vEnd] != -1)
281 | {
282 | // if both are on same feature, or if the start is not a feature
283 | if ((FeatureE[i] != -1) || (FeatureV[vStart] == -1))
284 | { Collapse_option = 3; }
285 | }
286 | }
287 |
288 | Point3d Mid = MidPt(P, i);
289 |
290 |
291 | double L2 = TargetLength.Calculate(P, 2 * i);
292 |
293 |
294 |
295 | if ((Collapse_option != 0) && (EdgeLength[2 * i] < (1 - t) * 4f / 5f * L2))
296 | {
297 | int Collapsed = -1;
298 | int CollapseRtn = -1;
299 | if (Collapse_option == 1)
300 | {
301 | Collapsed = P.Halfedges[2 * i].StartVertex;
302 | P.Vertices.SetVertex(Collapsed, MidPt(P, i));
303 | CollapseRtn = P.Halfedges.CollapseEdge(2 * i);
304 | }
305 | if (Collapse_option == 2)
306 | {
307 | Collapsed = P.Halfedges[2 * i].StartVertex;
308 | CollapseRtn = P.Halfedges.CollapseEdge(2 * i);
309 | }
310 | if (Collapse_option == 3)
311 | {
312 | Collapsed = P.Halfedges[2 * i + 1].StartVertex;
313 | CollapseRtn = P.Halfedges.CollapseEdge(2 * i + 1);
314 | }
315 | if (CollapseRtn != -1)
316 | {
317 | int[] Neighbours = P.Vertices.GetVertexNeighbours(Collapsed);
318 | foreach (int n in Neighbours)
319 | { Visited[n] = true; }
320 | }
321 | }
322 | }
323 | }
324 | }
325 | }
326 |
327 | EdgeCount = P.Halfedges.Count / 2;
328 |
329 | if ((Flip == 0) && (PullStrength > 0))
330 | {
331 | //Flip edges to reduce valence error
332 | for (int i = 0; i < EdgeCount; i++)
333 | {
334 | if (!P.Halfedges[2 * i].IsUnused
335 | && (P.Halfedges[2 * i].AdjacentFace != -1)
336 | && (P.Halfedges[2 * i + 1].AdjacentFace != -1)
337 | && (FeatureE[i] == -1) // don't flip feature edges
338 | )
339 | {
340 | int Vert1 = P.Halfedges[2 * i].StartVertex;
341 | int Vert2 = P.Halfedges[2 * i + 1].StartVertex;
342 | int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex;
343 | int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex;
344 |
345 | int Valence1 = P.Vertices.GetValence(Vert1);
346 | int Valence2 = P.Vertices.GetValence(Vert2);
347 | int Valence3 = P.Vertices.GetValence(Vert3);
348 | int Valence4 = P.Vertices.GetValence(Vert4);
349 |
350 | if (P.Vertices.NakedEdgeCount(Vert1) > 0) { Valence1 += 2; }
351 | if (P.Vertices.NakedEdgeCount(Vert2) > 0) { Valence2 += 2; }
352 | if (P.Vertices.NakedEdgeCount(Vert3) > 0) { Valence3 += 2; }
353 | if (P.Vertices.NakedEdgeCount(Vert4) > 0) { Valence4 += 2; }
354 |
355 | int CurrentError =
356 | Math.Abs(Valence1 - 6) +
357 | Math.Abs(Valence2 - 6) +
358 | Math.Abs(Valence3 - 6) +
359 | Math.Abs(Valence4 - 6);
360 | int FlippedError =
361 | Math.Abs(Valence1 - 7) +
362 | Math.Abs(Valence2 - 7) +
363 | Math.Abs(Valence3 - 5) +
364 | Math.Abs(Valence4 - 5);
365 | if (CurrentError > FlippedError)
366 | {
367 | P.Halfedges.FlipEdge(2 * i);
368 | }
369 | }
370 | }
371 | }
372 | else
373 | {
374 | //Flip edges based on angle
375 | for (int i = 0; i < EdgeCount; i++)
376 | {
377 | if (!P.Halfedges[2 * i].IsUnused
378 | && (P.Halfedges[2 * i].AdjacentFace != -1)
379 | && (P.Halfedges[2 * i + 1].AdjacentFace != -1)
380 | && (FeatureE[i] == -1) // don't flip feature edges
381 | )
382 | {
383 | int Vert1 = P.Halfedges[2 * i].StartVertex;
384 | int Vert2 = P.Halfedges[2 * i + 1].StartVertex;
385 | int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex;
386 | int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex;
387 |
388 | Point3d P1 = P.Vertices[Vert1].ToPoint3d();
389 | Point3d P2 = P.Vertices[Vert2].ToPoint3d();
390 | Point3d P3 = P.Vertices[Vert3].ToPoint3d();
391 | Point3d P4 = P.Vertices[Vert4].ToPoint3d();
392 |
393 | double A1 = Vector3d.VectorAngle(new Vector3d(P3 - P1), new Vector3d(P4 - P1))
394 | + Vector3d.VectorAngle(new Vector3d(P4 - P2), new Vector3d(P3 - P2));
395 |
396 | double A2 = Vector3d.VectorAngle(new Vector3d(P1 - P4), new Vector3d(P2 - P4))
397 | + Vector3d.VectorAngle(new Vector3d(P2 - P3), new Vector3d(P1 - P3));
398 |
399 | if (A2 > A1)
400 | {
401 | P.Halfedges.FlipEdge(2 * i);
402 | }
403 | }
404 | }
405 | }
406 |
407 | if (Minim)
408 | {
409 | Vector3d[] SmoothC = LaplacianSmooth(P, 1, smooth);
410 |
411 | for (int i = 0; i < P.Vertices.Count; i++)
412 | {
413 | if (AnchorV[i] == -1) // don't smooth feature vertices
414 | {
415 | P.Vertices.MoveVertex(i, 0.5 * SmoothC[i]);
416 | }
417 | }
418 | }
419 |
420 | Vector3d[] Smooth = LaplacianSmooth(P, 0, smooth);
421 |
422 | for (int i = 0; i < P.Vertices.Count; i++)
423 | {
424 | if (AnchorV[i] == -1) // don't smooth feature vertices
425 | {
426 | // make it tangential only
427 | Vector3d VNormal = Normal(P, i);
428 | double ProjLength = Smooth[i] * VNormal;
429 | Smooth[i] = Smooth[i] - (VNormal * ProjLength);
430 |
431 | P.Vertices.MoveVertex(i, Smooth[i]);
432 |
433 | if (P.Vertices.NakedEdgeCount(i) != 0)//special smoothing for feature edges
434 | {
435 | int[] Neighbours = P.Vertices.GetVertexNeighbours(i);
436 | int ncount = 0;
437 | Point3d Avg = new Point3d();
438 |
439 | for (int j = 0; j < Neighbours.Length; j++)
440 | {
441 | if (P.Vertices.NakedEdgeCount(Neighbours[j]) != 0)
442 | {
443 | ncount++;
444 | Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d();
445 | }
446 | }
447 | Avg = Avg * (1.0 / ncount);
448 | Vector3d move = Avg - P.Vertices[i].ToPoint3d();
449 | move = move * smooth;
450 | P.Vertices.MoveVertex(i, move);
451 | }
452 |
453 | if (FeatureV[i] != -1)//special smoothing for feature edges
454 | {
455 | int[] Neighbours = P.Vertices.GetVertexNeighbours(i);
456 | int ncount = 0;
457 | Point3d Avg = new Point3d();
458 |
459 | for (int j = 0; j < Neighbours.Length; j++)
460 | {
461 | if ((FeatureV[Neighbours[j]] == FeatureV[i]) || (AnchorV[Neighbours[j]] != -1))
462 | {
463 | ncount++;
464 | Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d();
465 | }
466 | }
467 | Avg = Avg * (1.0 / ncount);
468 | Vector3d move = Avg - P.Vertices[i].ToPoint3d();
469 | move = move * smooth;
470 | P.Vertices.MoveVertex(i, move);
471 | }
472 |
473 | //projecting points onto the target along their normals
474 |
475 | if (pull > 0)
476 | {
477 | Point3d Point = P.Vertices[i].ToPoint3d();
478 | Vector3d normal = Normal(P, i);
479 | Ray3d Ray1 = new Ray3d(Point, normal);
480 | Ray3d Ray2 = new Ray3d(Point, -normal);
481 | double RayPt1 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray1);
482 | double RayPt2 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray2);
483 | Point3d ProjectedPt;
484 |
485 | if ((RayPt1 < RayPt2) && (RayPt1 > 0) && (RayPt1 < 1.0))
486 | {
487 | ProjectedPt = Point * (1 - pull) + pull * Ray1.PointAt(RayPt1);
488 | }
489 | else if ((RayPt2 < RayPt1) && (RayPt2 > 0) && (RayPt2 < 1.0))
490 | {
491 | ProjectedPt = Point * (1 - pull) + pull * Ray2.PointAt(RayPt2);
492 | }
493 | else
494 | {
495 | ProjectedPt = Point * (1 - pull) + pull * M.ClosestPoint(Point);
496 | }
497 |
498 | P.Vertices.SetVertex(i, ProjectedPt);
499 | }
500 |
501 |
502 | if (FeatureV[i] != -1) //pull feature vertices onto feature curves
503 | {
504 | Point3d Point = P.Vertices[i].ToPoint3d();
505 | Curve CF = FC[FeatureV[i]];
506 | double param1 = 0.0;
507 | Point3d onFeature = new Point3d();
508 | CF.ClosestPoint(Point, out param1);
509 | onFeature = CF.PointAt(param1);
510 | P.Vertices.SetVertex(i, onFeature);
511 | }
512 | }
513 | else
514 | {
515 | P.Vertices.SetVertex(i, FV[AnchorV[i]]); //pull anchor vertices onto their points
516 | }
517 | }
518 |
519 |
520 |
521 |
522 | //end new
523 |
524 |
525 |
526 |
527 | AnchorV = CompactByVertex(P, AnchorV); //compact the fixed points along with the vertices
528 | FeatureV = CompactByVertex(P, FeatureV);
529 | FeatureE = CompactByEdge(P, FeatureE);
530 |
531 | P.Compact(); //this cleans the mesh data structure of unused elements
532 | }
533 |
534 | }
535 |
536 | DA.SetData(0, P);
537 | }
538 |
539 | protected override System.Drawing.Bitmap Icon
540 | {
541 | get
542 | {
543 | return Properties.Resources.remesh2;
544 | }
545 | }
546 |
547 | public override Guid ComponentGuid
548 | {
549 | get { return new Guid("{2b653315-c690-4670-b001-a2070dd060d4}"); }
550 | }
551 |
552 | private Point3d MidPt(PlanktonMesh P, int E)
553 | {
554 | Point3d Pos1 = P.Vertices[P.Halfedges[2 * E].StartVertex].ToPoint3d();
555 | Point3d Pos2 = P.Vertices[P.Halfedges[2 * E + 1].StartVertex].ToPoint3d();
556 | return (Pos1 + Pos2) * 0.5;
557 | }
558 |
559 | private List CompactByVertex(PlanktonMesh P, List L)
560 | {
561 | List L2 = new List();
562 |
563 | for (int i = 0; i < P.Vertices.Count; i++)
564 | {
565 | if (P.Vertices[i].IsUnused == false)
566 | {
567 | L2.Add(L[i]);
568 | }
569 | }
570 | return L2;
571 | }
572 |
573 | private List CompactByEdge(PlanktonMesh P, List L1)
574 | {
575 | List L2 = new List();
576 |
577 | int EdgeCount = P.Halfedges.Count / 2;
578 |
579 | for (int i = 0; i < EdgeCount; i++)
580 | {
581 | if (P.Halfedges[2 * i].IsUnused == false)
582 | {
583 | L2.Add(L1[i]);
584 | }
585 | }
586 | return L2;
587 | }
588 |
589 | private Vector3d Normal(PlanktonMesh P, int V)
590 | {
591 | Point3d Vertex = P.Vertices[V].ToPoint3d();
592 | Vector3d Norm = new Vector3d();
593 |
594 | int[] OutEdges = P.Vertices.GetHalfedges(V);
595 | int[] Neighbours = P.Vertices.GetVertexNeighbours(V);
596 | Vector3d[] OutVectors = new Vector3d[Neighbours.Length];
597 | int Valence = P.Vertices.GetValence(V);
598 |
599 | for (int j = 0; j < Valence; j++)
600 | {
601 | OutVectors[j] = P.Vertices[Neighbours[j]].ToPoint3d() - Vertex;
602 | }
603 |
604 | for (int j = 0; j < Valence; j++)
605 | {
606 | if (P.Halfedges[OutEdges[(j + 1) % Valence]].AdjacentFace != -1)
607 | {
608 | Norm += (Vector3d.CrossProduct(OutVectors[(j + 1) % Valence], OutVectors[j]));
609 | }
610 | }
611 |
612 | Norm.Unitize();
613 | return Norm;
614 | }
615 |
616 | private double CreaseAngle(PlanktonMesh P, int HE)
617 | {
618 | if (P.Halfedges[HE].IsUnused)
619 | { return -1; }
620 | else
621 | {
622 | int Pair = P.Halfedges.GetPairHalfedge(HE);
623 | if (P.Halfedges[HE].AdjacentFace == -1 || P.Halfedges[Pair].AdjacentFace == -1)
624 | { return 0; }
625 | else
626 | {
627 | int Vert1 = P.Halfedges[HE].StartVertex;
628 | int Vert2 = P.Halfedges[Pair].StartVertex;
629 | int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[HE].NextHalfedge].NextHalfedge].StartVertex;
630 | int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[Pair].NextHalfedge].NextHalfedge].StartVertex;
631 |
632 | Point3d P1 = P.Vertices[Vert1].ToPoint3d();
633 | Point3d P2 = P.Vertices[Vert2].ToPoint3d();
634 | Point3d P3 = P.Vertices[Vert3].ToPoint3d();
635 | Point3d P4 = P.Vertices[Vert4].ToPoint3d();
636 |
637 | Vector3d ThisEdge = P2 - P1;
638 | Vector3d Edge1 = P3 - P1;
639 | Vector3d Edge2 = P4 - P1;
640 |
641 | Vector3d Normal1 = Vector3d.CrossProduct(ThisEdge, Edge1);
642 | Vector3d Normal2 = Vector3d.CrossProduct(Edge2, ThisEdge);
643 |
644 | return (Vector3d.VectorAngle(Normal1, Normal2));
645 | }
646 | }
647 | }
648 |
649 | public double WeightedCombo(Point3d Pos, List SizePoints, List Sizes, int Falloff, double BVal, double BWeight)
650 | {
651 | double WeightedSize = 0, WeightSum = 0;
652 | double[] Weighting = new double[SizePoints.Count];
653 |
654 | for (int j = 0; j < SizePoints.Count; j++)
655 | {
656 | Weighting[j] = Math.Pow(Pos.DistanceTo(SizePoints[j]), -1.0 * Falloff);
657 | WeightSum += Weighting[j];
658 | }
659 |
660 | WeightSum += BWeight;
661 | WeightedSize += BWeight * (1.0 / WeightSum) * BVal;
662 | for (int j = 0; j < SizePoints.Count; j++)
663 | {
664 | WeightedSize += Weighting[j] * (1.0 / WeightSum) * Sizes[j];
665 | }
666 | return WeightedSize;
667 | }
668 |
669 | private static Vector3d[] LaplacianSmooth(PlanktonMesh P, int W, double Strength)
670 | {
671 | int VertCount = P.Vertices.Count;
672 | Vector3d[] Smooth = new Vector3d[VertCount];
673 |
674 | for (int i = 0; i < VertCount; i++)
675 | {
676 | if ((P.Vertices[i].IsUnused == false) && (P.Vertices.IsBoundary(i) == false))
677 | {
678 | int[] Neighbours = P.Vertices.GetVertexNeighbours(i);
679 | Point3d Vertex = P.Vertices[i].ToPoint3d();
680 | Point3d Centroid = new Point3d();
681 | if (W == 0)
682 | {
683 | for (int j = 0; j < Neighbours.Length; j++)
684 | { Centroid = Centroid + P.Vertices[Neighbours[j]].ToPoint3d(); }
685 | Smooth[i] = ((Centroid * (1.0 / P.Vertices.GetValence(i))) - Vertex) * Strength;
686 | }
687 | if (W == 1)
688 | {
689 | //get the radial vectors of the 1-ring
690 | //get the vectors around the 1-ring
691 | //get the cotangent weights for each edge
692 |
693 | int valence = Neighbours.Length;
694 |
695 | Point3d[] NeighbourPts = new Point3d[valence];
696 | Vector3d[] Radial = new Vector3d[valence];
697 | Vector3d[] Around = new Vector3d[valence];
698 | double[] CotWeight = new double[valence];
699 | double WeightSum = 0;
700 |
701 | for (int j = 0; j < valence; j++)
702 | {
703 | NeighbourPts[j] = P.Vertices[Neighbours[j]].ToPoint3d();
704 | Radial[j] = NeighbourPts[j] - Vertex;
705 | }
706 |
707 | for (int j = 0; j < valence; j++)
708 | {
709 | Around[j] = NeighbourPts[(j + 1) % valence] - NeighbourPts[j];
710 | }
711 |
712 | for (int j = 0; j < Neighbours.Length; j++)
713 | {
714 | //get the cotangent weights
715 | int previous = (j + valence - 1) % valence;
716 | Vector3d Cross1 = Vector3d.CrossProduct(Radial[previous], Around[previous]);
717 | double Cross1Length = Cross1.Length;
718 | double Dot1 = Radial[previous] * Around[previous];
719 |
720 | int next = (j + 1) % valence;
721 | Vector3d Cross2 = Vector3d.CrossProduct(Radial[next], Around[j]);
722 | double Cross2Length = Cross2.Length;
723 | double Dot2 = Radial[next] * Around[j];
724 |
725 | CotWeight[j] = Math.Abs(Dot1 / Cross1Length) + Math.Abs(Dot2 / Cross2Length);
726 | WeightSum += CotWeight[j];
727 | }
728 |
729 | double InvWeightSum = 1.0 / WeightSum;
730 |
731 | Vector3d ThisSmooth = new Vector3d();
732 |
733 | for (int j = 0; j < Neighbours.Length; j++)
734 | {
735 | ThisSmooth = ThisSmooth + Radial[j] * CotWeight[j];
736 | }
737 |
738 | Smooth[i] = ThisSmooth * InvWeightSum * Strength;
739 | }
740 |
741 | }
742 | }
743 | return Smooth;
744 | }
745 | }
746 | }
--------------------------------------------------------------------------------
/src/remesher.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug32
5 | AnyCPU
6 | 8.0.30703
7 | 2.0
8 | {9EA05C6C-A88C-4FF2-8E7D-98FC412F4944}
9 | Library
10 | Properties
11 | remesher
12 | remesher
13 | v4.0
14 | 512
15 | false
16 |
17 |
18 |
19 | true
20 | full
21 | false
22 | ..\bin\Debug32\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 |
27 |
28 | true
29 | full
30 | false
31 | ..\bin\Debug\
32 | DEBUG;TRACE
33 | prompt
34 | false
35 |
36 |
37 | pdbonly
38 | true
39 | ..\bin\Release\
40 | TRACE
41 | prompt
42 | 4
43 |
44 |
45 |
46 | ..\lib\GH_IO.dll
47 | False
48 |
49 |
50 | ..\lib\Grasshopper.dll
51 | False
52 |
53 |
54 | ..\lib\Plankton.dll
55 | False
56 |
57 |
58 | ..\lib\Plankton.gha
59 | False
60 |
61 |
62 | ..\lib\RhinoCommon.dll
63 | False
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | True
77 | True
78 | Resources.resx
79 |
80 |
81 |
82 |
83 | ResXFileCodeGenerator
84 | Resources.Designer.cs
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
101 |
102 | Copy "$(TargetPath)" "$(TargetDir)$(ProjectName).gha"
103 | Erase "$(TargetPath)"
104 |
105 |
106 |
107 |
108 | Program
109 | C:\Program Files (x86)\Rhinoceros 5.0\System\Rhino4.exe
110 |
111 |
112 | en-US
113 |
114 |
115 | C:\Program Files\Rhinoceros 5.0 (64-bit)\System\Rhino.exe
116 |
117 |
118 | Program
119 |
120 |
--------------------------------------------------------------------------------
/src/remesherInfo.cs:
--------------------------------------------------------------------------------
1 | using Grasshopper.Kernel;
2 |
3 | namespace remesher
4 | {
5 | public class remesherInfo : GH_AssemblyInfo
6 | {
7 | public override string AssemblyName
8 | {
9 | get
10 | {
11 | return "MeshMachine";
12 | }
13 | }
14 |
15 | //Override here any more methods you see fit.
16 | //Start typing public override..., select a property and push Enter.
17 | }
18 | }
--------------------------------------------------------------------------------