static void Main(string[] args) { ComputeServer.AuthToken = Rhino.Compute.AuthToken.Get(); Curve curveA = Curve.CreateControlPointCurve(new Point3d[] { new Point3d(0.0, 0.0, 0.0), new Point3d(0.0, 0.5, -0.5), new Point3d(0.0, 1.0, 0.0) }); Curve curveB = Curve.CreateControlPointCurve(new Point3d[] { new Point3d(1.0, 0.0, 0.0), new Point3d(1.0, 0.3, 0.6), new Point3d(1.0, 0.5, 0.0), new Point3d(1.0, 0.7, 0.8), new Point3d(1.0, 1.0, 0.0) }); NurbsSurface ruled = NurbsSurface.CreateRuledSurface(curveA, curveB); Mesh mesh1 = MeshCompute.CreateFromSurface(ruled); Rhino.Compute.ObjExport.ExportMeshesToObj("ruled_mesh_default.obj", new Mesh[] { mesh1 }); MeshingParameters meshingParameters = new MeshingParameters(); meshingParameters.MaximumEdgeLength = 0.1; Mesh mesh2 = MeshCompute.CreateFromSurface(ruled, meshingParameters); Rhino.Compute.ObjExport.ExportMeshesToObj("ruled_mesh_refined1.obj", new Mesh[] { mesh2 }); meshingParameters.MaximumEdgeLength = 0.05; Mesh mesh3 = MeshCompute.CreateFromSurface(ruled, meshingParameters); Rhino.Compute.ObjExport.ExportMeshesToObj("ruled_mesh_refined2.obj", new Mesh[] { mesh3 }); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { double num = 0; List <Brep> list = new List <Brep>(); if (DA.GetDataList <Brep>(0, list) && DA.GetData <double>(1, ref num)) { Brep[] brepArray = null; brepArray = Brep.CreateBooleanUnion(list.ToArray(), 0.1); MeshingParameters meshingParameters = new MeshingParameters { MaximumEdgeLength = num }; Mesh[] meshArray = Mesh.CreateFromBrep(brepArray[0], meshingParameters); Mesh msh = new Mesh(); int num3 = meshArray.Length - 1; for (int i = 0; i <= num3; i++) { msh.Append(meshArray[i]); } msh.Vertices.CullUnused(); msh.Vertices.CombineIdentical(true, true); msh.UnifyNormals(); msh = this.triangulation(msh); DA.SetData(0, msh); } }
public static void BuildPreview ( DB.Element element, MeshingParameters meshingParameters, DB.ViewDetailLevel DetailLevel, out Rhino.Display.DisplayMaterial[] materials, out Mesh[] meshes, out Curve[] wires ) { DB.Options options = null; using (var geometry = element?.GetGeometry(DetailLevel == DB.ViewDetailLevel.Undefined ? DB.ViewDetailLevel.Medium : DetailLevel, out options)) using (options) { if (geometry is null) { materials = null; meshes = null; wires = null; } else { var categoryMaterial = element.Category?.Material.ToRhino(null); var elementMaterial = geometry.MaterialElement.ToRhino(categoryMaterial); meshes = geometry.GetPreviewMeshes(meshingParameters).Where(x => x is object).ToArray(); wires = geometry.GetPreviewWires().Where(x => x is object).ToArray(); materials = geometry.GetPreviewMaterials(element.Document, elementMaterial).Where(x => x is object).ToArray(); foreach (var mesh in meshes) { mesh.Normals.ComputeNormals(); } } } }
//C++ TO C# CONVERTER WARNING: The original C++ declaration of the following method implementation was not found: public PointFunction1(Mesh.T_POINTS apoints, Array <INDEX_3> afaces, MeshingParameters amp, double ah) { this.points = apoints; this.faces = afaces; this.mp = amp; h = ah; }
/// <summary> /// Shorthand tool for map mesh objects. /// </summary> /// <param name="Map_Srf">A NURBS surface to mesh.</param> /// <param name="Increment">the maximum dimension between vertices.</param> /// <returns>the map mesh object.</returns> public static Mesh Create_Map_Mesh(IEnumerable <Brep> Map_Srf, double Increment) { Mesh Map_Mesh = new Mesh(); MeshingParameters mp = new MeshingParameters(); mp.MaximumEdgeLength = Increment; mp.MinimumEdgeLength = Increment; mp.SimplePlanes = false; mp.JaggedSeams = false; Brep[] Srfs = Map_Srf.ToArray <Brep>(); for (int i = 0; i < Map_Srf.ToArray <Brep>().Length; i++) { Mesh m = Rhino.Geometry.Mesh.CreateFromBrep(Srfs[i], mp)[0]; Point3d pt; double s, t; ComponentIndex ci; Vector3d Snormal; Srfs[i].ClosestPoint(m.Vertices[m.Vertices.Count() / 2], out pt, out ci, out s, out t, 1.0f, out Snormal); Vector3d Mnormal = m.Normals[m.Vertices.Count() / 2]; if ((Snormal.X * Mnormal.X + Snormal.Y * Mnormal.Y + Snormal.Z * Mnormal.Z) < 0) { m.Flip(true, true, true); } Map_Mesh.Append(m); } return(Map_Mesh); }
// Breps public static SpeckleBrep ToSpeckle(this Brep brep) { var joinedMesh = new Mesh(); if (SpeckleRhinoConverter.SetBrepDisplayMesh) { MeshingParameters mySettings; #if R6 mySettings = new MeshingParameters(0); #else mySettings = MeshingParameters.Coarse; mySettings.SimplePlanes = true; mySettings.RelativeTolerance = 0; mySettings.GridAspectRatio = 6; mySettings.GridAngle = Math.PI; mySettings.GridAspectRatio = 0; mySettings.SimplePlanes = true; #endif Mesh.CreateFromBrep(brep, mySettings).All(meshPart => { joinedMesh.Append(meshPart); return(true); }); } return(new SpeckleBrep(displayValue: SpeckleRhinoConverter.SetBrepDisplayMesh?joinedMesh.ToSpeckle() : null, rawData: JsonConvert.SerializeObject(brep), provenance: "Rhino", properties: brep.UserDictionary.ToSpeckle(root: brep))); }
// Place calls to RhinoCommon in a separate function from main so the jit doesn't // try to load RhinoCommon until after RhinoLib.LaunchInProcess is called static void MeshABrep() { var sphere = new Sphere(Point3d.Origin, 12); var brep = sphere.ToBrep(); var mp = new MeshingParameters(0.5); var mesh = Mesh.CreateFromBrep(brep, mp); Console.WriteLine($"Mesh with {mesh[0].Vertices.Count} vertices created"); }
public virtual int GenerateMesh(ref Mesh mesh, MeshingParameters mparam) { if (mesh == null) { return(1); } if (mparam.perfstepsstart <= (int)MESHING_STEP.MESHCONST_MESHVOLUME) { multithread.task = "Volume meshing"; MESHING3_RESULT res = MeshVolume(mparam, mesh); if (res != MESHING3_RESULT.MESHING3_OK) { return(1); } if (multithread.terminate) { return(0); } RemoveIllegalElements(mesh); if (multithread.terminate) { return(0); } MeshQuality3d(mesh); } if (multithread.terminate || mparam.perfstepsend <= (int)MESHING_STEP.MESHCONST_MESHVOLUME) { return(0); } if (mparam.perfstepsstart <= (int)MESHING_STEP.MESHCONST_OPTVOLUME) { multithread.task = "Volume optimization"; OptimizeVolume(mparam, mesh); if (multithread.terminate) { return(0); } } return(0); }
private List <Rhino.Geometry.Mesh> CheckOrCreateMesh(Brep brep, MeshingParameters mp) { List <Rhino.Geometry.Mesh> ret = null; if (brep != null) { ret = new List <Rhino.Geometry.Mesh>( Rhino.Geometry.Mesh.CreateFromBrep(brep, mp)); } // no mesh/brep face found return(ret); }
// Breps public static SpeckleBrep ToSpeckle(this Brep brep) { var joinedMesh = new Mesh(); MeshingParameters mySettings; mySettings = new MeshingParameters(0); Mesh.CreateFromBrep(brep, mySettings).All(meshPart => { joinedMesh.Append(meshPart); return(true); }); return(new SpeckleBrep(displayValue: joinedMesh.ToSpeckle(), rawData: JsonConvert.SerializeObject(brep), provenance: "Rhino", properties: brep.UserDictionary.ToSpeckle(root: brep))); }
public void DrawViewportMeshes(GH_PreviewMeshArgs args) { if (args.Pipeline.SupportsShading) { if (this._mesh == null) { if (this.m_value == null) { return; } MeshingParameters @params = args.MeshingParameters; if (@params == null) { return; } if (this._extrusion == null) { // Set extrusion List <Brep> breps = Utilities.CreateSectionSweeps(this.Value); _extrusion = Brep.JoinBreps(breps, Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance)[0]; } Mesh[] rc = Mesh.CreateFromBrep(this._extrusion, @params); if (rc == null) { this._mesh = new Mesh(); } else if (rc.Length == 1) { this._mesh = rc[0]; } else { this._mesh = new Mesh(); Mesh[] array = rc; for (int j = 0; j < array.Length; j++) { Mesh i = array[j]; this._mesh.Append(i); } } } if (this._mesh == null) { return; } args.Pipeline.DrawMeshShaded(this._mesh, args.Material); } }
public Mesh[] TryGetPreviewMeshes(MeshingParameters parameters = default) { if (parameters is object && !ReferenceEquals(meshingParameters, parameters)) { meshingParameters = parameters; if (geometryPreview is object) { if (geometryPreview.MeshingParameters?.RelativeTolerance != meshingParameters.RelativeTolerance) { GeometryPreview = null; } } } return(GeometryPreview.meshes); }
public static Mesh FromFacesToMesh(List <Face> faces) { Mesh mesh = new Mesh(); MeshingParameters settings = new MeshingParameters(); settings.SimplePlanes = true; foreach (Face face in faces) { Brep brep = FromFaceToBrep(face); mesh.Append(Mesh.CreateFromBrep(brep, settings)[0]); } return(mesh); }
private void test01_click(object sender, RibbonControlEventArgs e) { //Open Excel Worksheet Microsoft.Office.Interop.Excel.Worksheet activeWorksheet = Globals.RhinoInsideAddIn.Application.ActiveSheet; try { var sphere = new Sphere(Point3d.Origin, 12); var brep = sphere.ToBrep(); var mp = new MeshingParameters(0.5); var mesh = Mesh.CreateFromBrep(brep, mp); System.Windows.Forms.MessageBox.Show($"Mesh with {mesh[0].Vertices.Count} vertices created"); } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); } }
Mesh[] Meshes(MeshingParameters meshingParameters) { if (meshes is null && IsValid) { meshes = Enumerable.Repeat(Value, 1).GetPreviewMeshes(meshingParameters).ToArray(); if (Value.IsElementGeometry && Document?.GetElement(Reference) is DB.Instance instance) { var xform = instance.GetTransform().ToTransform(); foreach (var mesh in meshes) { mesh.Transform(xform); } } foreach (var mesh in meshes) { mesh.Normals.ComputeNormals(); } } return(meshes); }
public static Mesh ConvertBrepToTriMeshSolid(Brep brep) { // convert to mesh MeshingParameters mparams = MeshingParameters.Minimal; mparams.JaggedSeams = false; mparams.SimplePlanes = true; Mesh[] ms = Mesh.CreateFromBrep(brep, mparams); Mesh m = new Mesh(); m.Append(ms); // test if mesh is closed if (!m.IsClosed) { // try fill holes m.FillHoles(); // if not succesfull return null if (!m.IsClosed) { return(null); } } // weld mesh (collapse verticies) m.Weld(Math.PI); // triangulate all faces m.Faces.ConvertQuadsToTriangles(); m.CollapseFacesByEdgeLength(false, GhSA.Units.Tolerance); return(m); }
public SurfaceSource(IEnumerable <Brep> Surfaces, List <String> CodeList, int el_m, int SrcID, Phase_Regime ph) : base(new double[8] { 0, 0, 0, 0, 0, 0, 0, 0 }, new Point3d(0, 0, 0), ph, SrcID) { samplespermeter = el_m; Srfs = Surfaces.ToList <Brep>(); Samples = new Point3d[Srfs.Count][]; MeshingParameters mp = new MeshingParameters(); mp.MaximumEdgeLength = 1.0 / (double)samplespermeter; mp.MinimumEdgeLength = 1.0 / (double)samplespermeter; Sub_A = new double[Srfs.Count]; SubDomains = new double[Srfs.Count][]; T = new Topology[Srfs.Count]; //for(int i = 0; i < Curves.Count; i++) System.Threading.Tasks.Parallel.For(0, Srfs.Count, ips => { int i = (int)ips; //Divide each curve up in ~equal length segments. Mesh[] m = Mesh.CreateFromBrep(Srfs[i], mp); BoundingBox Box = m[0].GetBoundingBox(true); for (int j = 1; j < m.Length; j++) { Box.Union(m[j].GetBoundingBox(true)); } T[i] = new Topology(Utilities.PachTools.RPttoHPt(Box.Min), Utilities.PachTools.RPttoHPt(Box.Max)); List <Point3d> pts = new List <Point3d>(); SubDomains[i] = new double[m[i].Faces.Count + 1]; for (int j = 0; j < m[i].Faces.Count; j++) { double u, v; ComponentIndex ci; Point3d no; Vector3d V; Point3d A = m[i].Vertices[m[i].Faces[j].A]; Srfs[i].ClosestPoint(A, out no, out ci, out u, out v, 1, out V); A += V; Point3d B = m[i].Vertices[m[i].Faces[j].B]; Srfs[i].ClosestPoint(B, out no, out ci, out u, out v, 1, out V); B += V; Point3d C = m[i].Vertices[m[i].Faces[j].C]; Srfs[i].ClosestPoint(C, out no, out ci, out u, out v, 1, out V); C += V; Point3d D = m[i].Vertices[m[i].Faces[j].D]; Srfs[i].ClosestPoint(D, out no, out ci, out u, out v, 1, out V); D += V; if (m[i].Faces[j].IsQuad) { Hare.Geometry.Point[] poly = new Hare.Geometry.Point[4]; poly[0] = new Hare.Geometry.Point(A.X, A.Y, A.Z); poly[1] = new Hare.Geometry.Point(B.X, B.Y, B.Z); poly[2] = new Hare.Geometry.Point(C.X, C.Y, C.Z); poly[3] = new Hare.Geometry.Point(D.X, D.Y, D.Z); T[i].Add_Polygon(poly); } else { Hare.Geometry.Point[] poly = new Hare.Geometry.Point[3]; poly[0] = new Hare.Geometry.Point(A.X, A.Y, A.Z); poly[1] = new Hare.Geometry.Point(B.X, B.Y, B.Z); poly[2] = new Hare.Geometry.Point(C.X, C.Y, C.Z); T[i].Add_Polygon(poly); } pts.Add(m[i].Faces[j].IsQuad ? new Point3d(A.X + B.X + C.X + D.X, A.Y + B.Y + C.Y + D.Y, A.Z + B.Z + C.Z + D.Z) / 4 : new Point3d(A.X + B.X + C.X, A.Y + B.Y + C.Y, A.Z + B.Z + C.Z) / 3); SubDomains[i][j + 1] = Sub_A[i] += T[i].Polygon_Area(j); } Samples[i] = pts.ToArray(); }); Domains = new double[Srfs.Count + 1]; DomainLevel = new double[Srfs.Count][]; DomainPower = new double[Srfs.Count][]; Total_A = 0; for (int i = 0; i < Srfs.Count; i++) { for (int j = 0; j < SubDomains[i].Length; j++) { SubDomains[i][j] /= Sub_A[i]; } double A = Srfs[i].GetArea(); Domains[i + 1] = Total_A += A; DomainLevel[i] = Utilities.PachTools.DecodeSourcePower(CodeList[i]); DomainPower[i] = new double[8]; double PowerMod = A; for (int oct = 0; oct < 8; oct++) { DomainPower[i][oct] = 1E-12 * Math.Pow(10, .1 * DomainLevel[i][oct]) / PowerMod; } } for (int i = 0; i < Domains.Length; i++) { Domains[i] /= Total_A; } }
/*internal*/ public static IEnumerable <Mesh> GetPreviewMeshes ( this IEnumerable <DB.GeometryObject> geometries, MeshingParameters meshingParameters ) { foreach (var geometry in geometries) { if (geometry.Visibility != DB.Visibility.Visible) { continue; } switch (geometry) { case DB.GeometryInstance instance: { var xform = instance.Transform.ToTransform(); foreach (var g in instance.SymbolGeometry.GetPreviewMeshes(meshingParameters)) { g?.Transform(xform); yield return(g); } break; } case DB.Mesh mesh: { if (mesh.NumTriangles <= 0) { continue; } var f = Geometry.Raw.RawDecoder.ToRhino(mesh); UnitConverter.Scale(f, UnitConverter.ToRhinoUnits); yield return(f); break; } case DB.Face face: { var faceMesh = face.Triangulate(meshingParameters.LevelOfDetail()); var f = Geometry.Raw.RawDecoder.ToRhino(faceMesh); UnitConverter.Scale(f, UnitConverter.ToRhinoUnits); yield return(f); break; } case DB.Solid solid: { if (solid.Faces.IsEmpty) { continue; } var solidFaces = solid.Faces.OfType <DB.Face>(); bool useMultipleMaterials = solidFaces.HasMultipleMaterials(); var facesMeshes = useMultipleMaterials ? null : new List <Mesh>(solid.Faces.Size); foreach (var face in solidFaces) { var faceMesh = face.Triangulate(meshingParameters.LevelOfDetail()); var f = Geometry.Raw.RawDecoder.ToRhino(faceMesh); UnitConverter.Scale(f, UnitConverter.ToRhinoUnits); if (facesMeshes is null) { yield return(f); } else if (f is object) { facesMeshes.Add(f); } } if (facesMeshes is object) { if (facesMeshes.Count > 0) { var mesh = new Mesh(); mesh.Append(facesMeshes); yield return(mesh); } else { yield return(null); } } break; } } } }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { #region updateInputs //if (!cap && this.Params.Input.Count ==7) //{ // this.Params.Input[5].RemoveAllSources(); // this.Params.UnregisterInputParameter(this.Params.Input[5]); // this.Params.Input[6].RemoveAllSources(); // this.Params.UnregisterInputParameter(this.Params.Input[6]); // Params.OnParametersChanged(); //} //if (cap && this.Params.Input.Count == 5) //{ // this.Params.RegisterInputParam(new Param_Colour // { // Name = "MinColor", // NickName = "MinColor", // Description = "MinColor", // Access = GH_ParamAccess.item, // Optional = true // }); // this.Params.RegisterInputParam(new Param_Colour // { // Name = "MaxColor", // NickName = "MaxColor", // Description = "MinColor", // Access = GH_ParamAccess.item, // Optional = true // }); // Params.OnParametersChanged(); //} #endregion updateInputs //bool caps = DA.Fetch<bool>("Cap"); Color?maxColor = DA.Fetch <Color?>(i_inputSelecterMax); Color?minColor = DA.Fetch <Color?>(i_inputSelectorMin); var allResults = DA.FetchTree <GH_Number>("Results"); var grids = DA.FetchList <Grid>("Grids"); //var gradientRange = DA.Fetch<string>("GradientRange"); //int maxCount = DA.Fetch<int>("MaxCount"); int maxCount = 200; //var inStepSize = DA.Fetch<int>("StepSize"); //var inSteps = DA.Fetch<int>("Steps"); InputSelector inputSelector = DA.Fetch <InputSelector>("_Section Type"); double globalMin = double.MaxValue; double globalMax = double.MinValue; for (int g = 0; g < grids.Count; g++) { globalMin = Math.Min(globalMin, ((List <GH_Number>)allResults.get_Branch(g)).Select(r => r.Value).Min()); globalMax = Math.Max(globalMax, ((List <GH_Number>)allResults.get_Branch(g)).Select(r => r.Value).Max()); } if (inputSelector == null) { inputSelector = new InputSelector(10, globalMin, globalMax); } if (allResults.Branches.Count != grids.Count) { throw new Exception("Grid count doesnt match results"); } //var colorDomain = Misc.AutoDomain(gradientRange, allResults); //Rhino.RhinoApp.WriteLine($"{range} -> {domain[0]} to {domain[1]}"); GH_GradientControl gc; try { gc = (GH_GradientControl)Params.Input[i_inputGradient].Sources[0].Attributes.GetTopLevel.DocObject; } catch (System.ArgumentOutOfRangeException) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Remember to add a gradient component in grasshopper!"); gc = null; } GradientParser gp = new GradientParser(gc) { //Cap = caps, AboveMax = maxColor == default(Color) ? null : maxColor, BelowMin = minColor == default(Color) ? null : minColor, //Min = domain[0], //Max = domain[1], Reverse = Params.Input[i_inputGradient].Reverse }; IDictionary <string, Color> colorDescriptions = new Dictionary <string, Color>(); IDictionary <string, int> colorPaths = new Dictionary <string, int>(); #region coloredMesh var outMeshes = new List <Mesh>(); for (int i = 0; i < grids.Count; i++) { //AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, $"Mesh vertices: {grids[i].SimMesh.Vertices.Count}, colors = {gp.GetColors(allResults.Branches[i].Select(p => p.Value).ToArray()).Length} f"); outMeshes.Add(grids[i].GetColoredMesh(gp.GetColors(allResults.Branches[i].Select(p => p.Value).ToArray()))); Mesh m = grids[i].SimMesh; Point3d[] points = grids[i].SimPoints.ToArray(); outMeshes[outMeshes.Count - 1].Translate(0, 0, Units.ConvertFromMeter(0.001)); } DA.SetDataList(0, outMeshes); #endregion coloredMesh #region layeredMesh if (grids[0].UseCenters == true) { return; } //Outputs GH_Structure <GH_Mesh> oLayeredMeshes = new GH_Structure <GH_Mesh>(); List <GH_Mesh> previewMeshes = new List <GH_Mesh>(); List <GH_Plane> outPlanes = new List <GH_Plane>(); GH_Structure <GH_Curve> outCurves = new GH_Structure <GH_Curve>(); GH_Structure <GH_String> outValues = new GH_Structure <GH_String>(); GH_Structure <GH_Colour> outColors = new GH_Structure <GH_Colour>(); const double SCALAR = 1; // don't change. if (((GH_Structure <GH_Number>)gc.Params.Input[1].VolatileData)[0][0].Value == 1) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "The gradient connected has 1 as max. Is that on purpose? Check the inputs of your gradient component." + $"\nI suggest you set your max somewhere around {globalMax:0.0}"); } for (int g = 0; g < grids.Count; g++) { //GH_Structure<GH_Curve> curves = new GH_Structure<GH_Curve>(); Grid grid = grids[g]; Mesh inputMesh = grids[g].SimMesh.DuplicateMesh(); //Mesh meshToCut = grids[g].SimMesh; List <double> results = ((List <GH_Number>)allResults.get_Branch(g)).Select(r => r.Value).ToList(); if (grids[g].UseCenters == true) { results = RTreeSolver.FindClosestWeightedValues(grids[g], results, true).ToList(); // ADD CONVERSION TODO: } inputMesh.Normals.ComputeNormals(); Vector3f normal = inputMesh.FaceNormals[0]; Plane basePlane = new Plane(inputMesh.Vertices[0], normal); Transform ProjectToBase = Transform.PlanarProjection(basePlane); Plane cuttingPlane = new Plane(basePlane); Mesh meshToCut = CreateMeshToBeCut(SCALAR, inputMesh, results, cuttingPlane); previewMeshes.Add(new GH_Mesh(inputMesh)); MeshingParameters mp = new MeshingParameters(0); List <Mesh> layeredMeshesThisGrid = new List <Mesh>(); double valueForSmallAreas = double.MinValue; double resultsMin = results.Min(); foreach (var item in inputSelector) { if (resultsMin >= item) { valueForSmallAreas = item; break; } } //Color col = gp.GetColors(new List<double>() { inputSelector.Min.Value })[0]; Color col = gp.GetColors(new List <double>() { gp.BelowMin.HasValue&& inputSelector.Min.Value <= gp.Min ? resultsMin > gp.Min ? valueForSmallAreas : double.MinValue : inputSelector.Min.Value })[0]; Polyline[] outlinePolylines = inputMesh.GetNakedEdges(); PolylineCurve[] curvesFromOutline = new PolylineCurve[outlinePolylines.Length]; for (int i = 0; i < outlinePolylines.Length; i++) { curvesFromOutline[i] = new PolylineCurve(outlinePolylines[i]); curvesFromOutline[i].Transform(ProjectToBase); } Mesh meshFromCurves = GetMeshFromCurves(curvesFromOutline, mp, in col); GH_Path startPath = new GH_Path(g, -1); oLayeredMeshes.Append(new GH_Mesh(meshFromCurves), startPath); string lessThanKey = gp.BelowMin.HasValue && inputSelector.Min.Value < gp.Min ? $"<{gp.Min:0.0}" : $"<{inputSelector.Min.Value:0.0}"; if (!colorDescriptions.ContainsKey(lessThanKey) && inputSelector.First() < gp.Min) { colorDescriptions.Add(lessThanKey, col); colorPaths.Add(lessThanKey, -1); } ////outColors.Append(new GH_Colour(col), startPath); ////outValues.Append(new GH_Number(double.MinValue), startPath); //Mesh[] meshesFromCurves = GetMeshesFromCurves(curvesFromOutline, mp, in col); //oLayeredMeshes.AppendRange(meshesFromCurves.Select(m => new GH_Mesh(m)), new GH_Path(g, -1)); int cuttingCount = 0; double previousValue = 0; foreach (double currentValue in inputSelector) { if (cuttingCount > maxCount) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"Too many steps... I reached {maxCount} and then stopped"); break; } if (gp.BelowMin.HasValue && currentValue < gp.Min) { continue; } if (currentValue > results.Max()) { break; } // Create planes Vector3f moveUpVector = normal * (float)((currentValue - previousValue) * SCALAR); Transform t = Transform.Translation(moveUpVector); GH_Path path = new GH_Path(g, cuttingCount); cuttingPlane.Transform(t); outPlanes.Add(new GH_Plane(cuttingPlane)); // Create boundary intersected curves Curve[] intersectedCurves = GetIntersectedCurves(inputMesh, cuttingPlane); if (intersectedCurves != null) { outCurves.AppendRange(intersectedCurves.Select(c => new GH_Curve(c.DuplicateCurve())), path); foreach (var curve in intersectedCurves) { curve.Transform(ProjectToBase); } // Create meshes col = gp.GetColors(new List <double>() { currentValue })[0]; meshFromCurves = GetMeshFromCurves(intersectedCurves, mp, in col); meshFromCurves.Transform(Transform.Translation(0, 0, (cuttingCount + 1) * Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance * 12.0)); if (meshFromCurves != null) { //oLayeredMeshes.AppendRange(meshesFromCurves.Select(m => new GH_Mesh(m)), path); oLayeredMeshes.Append(new GH_Mesh(meshFromCurves), path); string key = currentValue >= gp.Max.Value ? $">{currentValue:0.0}" : $"{currentValue:0.0}"; if (!colorDescriptions.ContainsKey(key)) { colorDescriptions.Add(key, col); colorPaths.Add(key, cuttingCount); } } if (currentValue >= gp.Max.Value) { break; } } previousValue = currentValue; cuttingCount++; } } foreach (KeyValuePair <string, Color> valuePair in colorDescriptions) { GH_Path path = new GH_Path(colorPaths[valuePair.Key]); outColors.Append(new GH_Colour(valuePair.Value), path); outValues.Append(new GH_String(valuePair.Key), path); } DA.SetDataTree(1, oLayeredMeshes); DA.SetDataTree(2, outCurves); DA.SetDataList("Planes", outPlanes); DA.SetDataList("TempMeshes", previewMeshes); DA.SetDataTree(6, outValues); DA.SetDataTree(5, outColors); #endregion layeredMesh }
private Mesh GetMeshFromCurves(Curve[] intersectedCurves, MeshingParameters mp, in Color col)
Preview(GeometricElement element) { geometricElement = element; clippingBox = element.ClippingBox; MeshingParameters = element.meshingParameters; }
static double LevelOfDetail(this MeshingParameters value) => value?.RelativeTolerance ?? 0.15;
protected override Result RunCommand(RhinoDoc doc, RunMode mode) { // TODO: start here modifying the behaviour of your command. // --- RhinoApp.WriteLine("MeshMachine WIP test", EnglishName); Brep SB; using (GetObject getBrep = new GetObject()) { getBrep.SetCommandPrompt("Please select the brep to remesh"); getBrep.Get(); SB = getBrep.Object(0).Brep(); } //GetNumber TargetLength = new GetNumber(); //double L = TargetLength.Number(); Rhino.Input.Custom.GetNumber gn = new Rhino.Input.Custom.GetNumber(); gn.SetCommandPrompt("Specify a Target Edge Length"); gn.SetLowerLimit(0.5, false); gn.Get(); if (gn.CommandResult() != Rhino.Commands.Result.Success) { return(gn.CommandResult()); } double L = gn.Number(); //Point3d pt0; //using (GetPoint getPointAction = new GetPoint()) //{ // getPointAction.SetCommandPrompt("Please select the start point"); // if (getPointAction.Get() != GetResult.Point) // { // RhinoApp.WriteLine("No start point was selected."); // return getPointAction.CommandResult(); // } // pt0 = getPointAction.Point(); //} //Point3d pt1; //using (GetPoint getPointAction = new GetPoint()) //{ // getPointAction.SetCommandPrompt("Please select the end point"); // getPointAction.SetBasePoint(pt0, true); // getPointAction.DynamicDraw += // (sender, e) => e.Display.DrawLine(pt0, e.CurrentPoint, System.Drawing.Color.DarkRed); // if (getPointAction.Get() != GetResult.Point) // { // RhinoApp.WriteLine("No end point was selected."); // return getPointAction.CommandResult(); // } // pt1 = getPointAction.Point(); //} //doc.Objects.AddLine(pt0, pt1); PlanktonMesh P = new PlanktonMesh(); List <int> AnchorV = new List <int>(); List <int> FeatureV = new List <int>(); List <int> FeatureE = new List <int>(); double FixT = 0.00001; double LengthTol = 0.15; //a tolerance for when to split/collapse edges double SmoothStrength = 0.8; //smoothing strength double PullStrength = 0.8; //pull to target mesh strength double CurvDep = 0; int Flip = 1; MeshingParameters MeshParams = new MeshingParameters(); MeshParams.MaximumEdgeLength = 3 * L; MeshParams.MinimumEdgeLength = L; MeshParams.JaggedSeams = false; MeshParams.SimplePlanes = false; Mesh[] BrepMeshes = Mesh.CreateFromBrep(SB, MeshParams); Mesh M = new Mesh(); foreach (var mesh in BrepMeshes) { M.Append(mesh); } M.Faces.ConvertQuadsToTriangles(); P = M.ToPlanktonMesh(); var FC = new List <Curve>(); foreach (BrepEdge E in SB.Edges) { if (!E.IsSmoothManifoldEdge(0.01)) { FC.Add(E.ToNurbsCurve()); } } var Corners = SB.Vertices; List <Point3d> FV = new List <Point3d>(); foreach (Point Pt in Corners) { FV.Add(Pt.Location); } //Mark any vertices or edges lying on features for (int i = 0; i < P.Vertices.Count; i++) { Point3d Pt = P.Vertices[i].ToPoint3d(); AnchorV.Add(-1); for (int j = 0; j < FV.Count; j++) { if (Pt.DistanceTo(FV[j]) < FixT) { AnchorV[AnchorV.Count - 1] = j; } } FeatureV.Add(-1); for (int j = 0; j < FC.Count; j++) { double param = new double(); FC[j].ClosestPoint(Pt, out param); if (Pt.DistanceTo(FC[j].PointAt(param)) < FixT) { FeatureV[FeatureV.Count - 1] = j; } } } int EdgeCount = P.Halfedges.Count / 2; for (int i = 0; i < EdgeCount; i++) { FeatureE.Add(-1); int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; Point3d PStart = P.Vertices[vStart].ToPoint3d(); Point3d PEnd = P.Vertices[vEnd].ToPoint3d(); for (int j = 0; j < FC.Count; j++) { double paramS = new double(); double paramE = new double(); Curve thisFC = FC[j]; thisFC.ClosestPoint(PStart, out paramS); thisFC.ClosestPoint(PEnd, out paramE); if ((PStart.DistanceTo(thisFC.PointAt(paramS)) < FixT) && (PEnd.DistanceTo(thisFC.PointAt(paramE)) < FixT)) { FeatureE[FeatureE.Count - 1] = j; } } } for (int iter = 0; iter < 30; iter++) { EdgeCount = P.Halfedges.Count / 2; double[] EdgeLength = P.Halfedges.GetLengths(); List <bool> Visited = new List <bool>(); Vector3d[] Normals = new Vector3d[P.Vertices.Count]; for (int i = 0; i < P.Vertices.Count; i++) { Visited.Add(false); Normals[i] = Util.Normal(P, i); } double t = LengthTol; //a tolerance for when to split/collapse edges double smooth = SmoothStrength; //smoothing strength double pull = PullStrength; //pull to target mesh strength // Split the edges that are too long for (int i = 0; i < EdgeCount; i++) { if (P.Halfedges[2 * i].IsUnused == false) { int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; if ((Visited[vStart] == false) && (Visited[vEnd] == false)) { double L2 = L; Point3d Mid = Util.MidPt(P, i); //if (CurvDep > 0) //{ // double NormDiff = Vector3d.VectorAngle(Normals[vStart], Normals[vEnd]); // L2 = Math.Min((1.0 / (3.0 * NormDiff) * L), 5 * L); // if (CurvDep != 1) // { // L2 = L2 * (CurvDep) + L * (1.0 - CurvDep); // } //} //if (BoundScale != 1.0) //{ // double MinDist = 99954; // for (int j = 0; j < FC.Count; j++) // { // double param = new double(); // FC[j].ClosestPoint(Mid, out param); // double ThisDist = Mid.DistanceTo(FC[j].PointAt(param)); // if (ThisDist < MinDist) // { MinDist = ThisDist; } // } // if (MinDist < BoundDist) // { // L2 = L2 * BoundScale + (MinDist / BoundDist) * (L2 * (1 - BoundScale)); // } //} //if (SizP.Count > 0) //{ // L2 = WeightedCombo(Mid, SizP, SizV, WExp, L2, BGW); // // L2 = (WL * (1.0 - BGW)) + (BGW * L2); //} if (EdgeLength[2 * i] > (1 + t) * (4f / 3f) * L2) { int SplitHEdge = P.Halfedges.TriangleSplitEdge(2 * i); if (SplitHEdge != -1) { int SplitCenter = P.Halfedges[SplitHEdge].StartVertex; P.Vertices.SetVertex(SplitCenter, Util.MidPt(P, i)); //update the feature information FeatureE.Add(FeatureE[i]); FeatureV.Add(FeatureE[i]); AnchorV.Add(-1); //2 additional new edges have also been created (or 1 if split was on a boundary) //mark these as non-features int CEdgeCount = P.Halfedges.Count / 2; while (FeatureE.Count < CEdgeCount) { FeatureE.Add(-1); } Visited.Add(true); int[] Neighbours = P.Vertices.GetVertexNeighbours(SplitCenter); foreach (int n in Neighbours) { Visited[n] = true; } } } } } } //Collapse the edges that are too short for (int i = 0; i < EdgeCount; i++) { if (P.Halfedges[2 * i].IsUnused == false) { int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; if ((Visited[vStart] == false) && (Visited[vEnd] == false)) { if (!(AnchorV[vStart] != -1 && AnchorV[vEnd] != -1)) // if both ends are anchored, don't collapse { int Collapse_option = 0; //0 for none, 1 for collapse to midpt, 2 for towards start, 3 for towards end //if neither are anchorV if (AnchorV[vStart] == -1 && AnchorV[vEnd] == -1) { // if both on same feature (or neither on a feature) if (FeatureV[vStart] == FeatureV[vEnd]) { Collapse_option = 1; } // if start is on a feature and end isn't if ((FeatureV[vStart] != -1) && (FeatureV[vEnd] == -1)) { Collapse_option = 2; } // if end is on a feature and start isn't if ((FeatureV[vStart] == -1) && (FeatureV[vEnd] != -1)) { Collapse_option = 3; } } else // so one end must be an anchor { // if start is an anchor if (AnchorV[vStart] != -1) { // if both are on same feature, or if the end is not a feature if ((FeatureE[i] != -1) || (FeatureV[vEnd] == -1)) { Collapse_option = 2; } } // if end is an anchor if (AnchorV[vEnd] != -1) { // if both are on same feature, or if the start is not a feature if ((FeatureE[i] != -1) || (FeatureV[vStart] == -1)) { Collapse_option = 3; } } } double L2 = L; Point3d Mid = Util.MidPt(P, i); if (CurvDep > 0) { double NormDiff = Vector3d.VectorAngle(Normals[vStart], Normals[vEnd]); L2 = Math.Min((1.0 / (3.0 * NormDiff) * L), 5 * L); if (CurvDep != 1) { L2 = L2 * (CurvDep) + L * (1.0 - CurvDep); } } //if (BoundScale != 1.0) //{ // double MinDist = 99954; // for (int j = 0; j < FC.Count; j++) // { // double param = new double(); // FC[j].ClosestPoint(Mid, out param); // double ThisDist = Mid.DistanceTo(FC[j].PointAt(param)); // if (ThisDist < MinDist) // { MinDist = ThisDist; } // } // if (MinDist < BoundDist) // { // L2 = L2 * BoundScale + (MinDist / BoundDist) * (L2 * (1 - BoundScale)); // } //} //if (SizP.Count > 0) //{ // L2 = WeightedCombo(Mid, SizP, SizV, WExp, L2, BGW); // //double WL = WeightedCombo(Mid, SizP, SizV, WExp); // //L2 = (WL * (1.0 - BGW)) + (BGW * L2); //} if ((Collapse_option != 0) && (EdgeLength[2 * i] < (1 - t) * 4f / 5f * L2)) { int Collapsed = -1; int CollapseRtn = -1; if (Collapse_option == 1) { Collapsed = P.Halfedges[2 * i].StartVertex; P.Vertices.SetVertex(Collapsed, Util.MidPt(P, i)); CollapseRtn = P.Halfedges.CollapseEdge(2 * i); } if (Collapse_option == 2) { Collapsed = P.Halfedges[2 * i].StartVertex; CollapseRtn = P.Halfedges.CollapseEdge(2 * i); } if (Collapse_option == 3) { Collapsed = P.Halfedges[2 * i + 1].StartVertex; CollapseRtn = P.Halfedges.CollapseEdge(2 * i + 1); } if (CollapseRtn != -1) { int[] Neighbours = P.Vertices.GetVertexNeighbours(Collapsed); foreach (int n in Neighbours) { Visited[n] = true; } } } } } } } EdgeCount = P.Halfedges.Count / 2; if ((Flip == 0) && (PullStrength > 0)) { //Flip edges to reduce valence error for (int i = 0; i < EdgeCount; i++) { if (!P.Halfedges[2 * i].IsUnused && (P.Halfedges[2 * i].AdjacentFace != -1) && (P.Halfedges[2 * i + 1].AdjacentFace != -1) && (FeatureE[i] == -1) // don't flip feature edges ) { int Vert1 = P.Halfedges[2 * i].StartVertex; int Vert2 = P.Halfedges[2 * i + 1].StartVertex; int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex; int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex; int Valence1 = P.Vertices.GetValence(Vert1); int Valence2 = P.Vertices.GetValence(Vert2); int Valence3 = P.Vertices.GetValence(Vert3); int Valence4 = P.Vertices.GetValence(Vert4); if (P.Vertices.NakedEdgeCount(Vert1) > 0) { Valence1 += 2; } if (P.Vertices.NakedEdgeCount(Vert2) > 0) { Valence2 += 2; } if (P.Vertices.NakedEdgeCount(Vert3) > 0) { Valence3 += 2; } if (P.Vertices.NakedEdgeCount(Vert4) > 0) { Valence4 += 2; } int CurrentError = Math.Abs(Valence1 - 6) + Math.Abs(Valence2 - 6) + Math.Abs(Valence3 - 6) + Math.Abs(Valence4 - 6); int FlippedError = Math.Abs(Valence1 - 7) + Math.Abs(Valence2 - 7) + Math.Abs(Valence3 - 5) + Math.Abs(Valence4 - 5); if (CurrentError > FlippedError) { P.Halfedges.FlipEdge(2 * i); } } } } else { //Flip edges based on angle for (int i = 0; i < EdgeCount; i++) { if (!P.Halfedges[2 * i].IsUnused && (P.Halfedges[2 * i].AdjacentFace != -1) && (P.Halfedges[2 * i + 1].AdjacentFace != -1) && (FeatureE[i] == -1) // don't flip feature edges ) { int Vert1 = P.Halfedges[2 * i].StartVertex; int Vert2 = P.Halfedges[2 * i + 1].StartVertex; int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex; int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex; Point3d P1 = P.Vertices[Vert1].ToPoint3d(); Point3d P2 = P.Vertices[Vert2].ToPoint3d(); Point3d P3 = P.Vertices[Vert3].ToPoint3d(); Point3d P4 = P.Vertices[Vert4].ToPoint3d(); double A1 = Vector3d.VectorAngle(new Vector3d(P3 - P1), new Vector3d(P4 - P1)) + Vector3d.VectorAngle(new Vector3d(P4 - P2), new Vector3d(P3 - P2)); double A2 = Vector3d.VectorAngle(new Vector3d(P1 - P4), new Vector3d(P2 - P4)) + Vector3d.VectorAngle(new Vector3d(P2 - P3), new Vector3d(P1 - P3)); if (A2 > A1) { P.Halfedges.FlipEdge(2 * i); } } } } //if (Minim) //{ // Vector3d[] SmoothC = LaplacianSmooth(P, 1, smooth); // for (int i = 0; i < P.Vertices.Count; i++) // { // if (AnchorV[i] == -1) // don't smooth feature vertices // { // P.Vertices.MoveVertex(i, 0.5 * SmoothC[i]); // } // } //} Vector3d[] Smooth = Util.LaplacianSmooth(P, 0, smooth); for (int i = 0; i < P.Vertices.Count; i++) { if (AnchorV[i] == -1) // don't smooth feature vertices { // make it tangential only Vector3d VNormal = Util.Normal(P, i); double ProjLength = Smooth[i] * VNormal; Smooth[i] = Smooth[i] - (VNormal * ProjLength); P.Vertices.MoveVertex(i, Smooth[i]); if (P.Vertices.NakedEdgeCount(i) != 0)//special smoothing for feature edges { int[] Neighbours = P.Vertices.GetVertexNeighbours(i); int ncount = 0; Point3d Avg = new Point3d(); for (int j = 0; j < Neighbours.Length; j++) { if (P.Vertices.NakedEdgeCount(Neighbours[j]) != 0) { ncount++; Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d(); } } Avg = Avg * (1.0 / ncount); Vector3d move = Avg - P.Vertices[i].ToPoint3d(); move = move * smooth; P.Vertices.MoveVertex(i, move); } if (FeatureV[i] != -1)//special smoothing for feature edges { int[] Neighbours = P.Vertices.GetVertexNeighbours(i); int ncount = 0; Point3d Avg = new Point3d(); for (int j = 0; j < Neighbours.Length; j++) { if ((FeatureV[Neighbours[j]] == FeatureV[i]) || (AnchorV[Neighbours[j]] != -1)) { ncount++; Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d(); } } Avg = Avg * (1.0 / ncount); Vector3d move = Avg - P.Vertices[i].ToPoint3d(); move = move * smooth; P.Vertices.MoveVertex(i, move); } //projecting points onto the target along their normals if (pull > 0) { Point3d Point = P.Vertices[i].ToPoint3d(); Vector3d normal = Util.Normal(P, i); Ray3d Ray1 = new Ray3d(Point, normal); Ray3d Ray2 = new Ray3d(Point, -normal); double RayPt1 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray1); double RayPt2 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray2); Point3d ProjectedPt; if ((RayPt1 < RayPt2) && (RayPt1 > 0) && (RayPt1 < 1.0)) { ProjectedPt = Point * (1 - pull) + pull * Ray1.PointAt(RayPt1); } else if ((RayPt2 < RayPt1) && (RayPt2 > 0) && (RayPt2 < 1.0)) { ProjectedPt = Point * (1 - pull) + pull * Ray2.PointAt(RayPt2); } else { ProjectedPt = Point * (1 - pull) + pull * M.ClosestPoint(Point); } P.Vertices.SetVertex(i, ProjectedPt); } if (FeatureV[i] != -1) //pull feature vertices onto feature curves { Point3d Point = P.Vertices[i].ToPoint3d(); Curve CF = FC[FeatureV[i]]; double param1 = 0.0; Point3d onFeature = new Point3d(); CF.ClosestPoint(Point, out param1); onFeature = CF.PointAt(param1); P.Vertices.SetVertex(i, onFeature); } } else { P.Vertices.SetVertex(i, FV[AnchorV[i]]); //pull anchor vertices onto their points } } AnchorV = Util.CompactByVertex(P, AnchorV); //compact the fixed points along with the vertices FeatureV = Util.CompactByVertex(P, FeatureV); FeatureE = Util.CompactByEdge(P, FeatureE); P.Compact(); //this cleans the mesh data structure of unused elements } Mesh MR = P.ToRhinoMesh(); MR.Unweld(0.4, true); doc.Objects.AddMesh(MR); doc.Views.Redraw(); RhinoApp.WriteLine("The {0} command added one mesh to the document.", EnglishName); // --- return(Result.Success); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { #region updateInputs //if (!cap && this.Params.Input.Count ==7) //{ // this.Params.Input[5].RemoveAllSources(); // this.Params.UnregisterInputParameter(this.Params.Input[5]); // this.Params.Input[6].RemoveAllSources(); // this.Params.UnregisterInputParameter(this.Params.Input[6]); // Params.OnParametersChanged(); //} //if (cap && this.Params.Input.Count == 5) //{ // this.Params.RegisterInputParam(new Param_Colour // { // Name = "MinColor", // NickName = "MinColor", // Description = "MinColor", // Access = GH_ParamAccess.item, // Optional = true // }); // this.Params.RegisterInputParam(new Param_Colour // { // Name = "MaxColor", // NickName = "MaxColor", // Description = "MinColor", // Access = GH_ParamAccess.item, // Optional = true // }); // Params.OnParametersChanged(); //} #endregion updateInputs //bool caps = DA.Fetch<bool>("Cap"); var maxColor = DA.Fetch <Color>(inputSelecterMax); var minColor = DA.Fetch <Color>(inputSelectorMin); var allResults = DA.FetchTree <GH_Number>("Results"); var grids = DA.FetchList <Grid>("Grids"); var range = DA.Fetch <string>("Range"); var inStepSize = DA.Fetch <int>("StepSize"); var inSteps = DA.Fetch <int>("Steps"); if (allResults.Branches.Count != grids.Count) { throw new Exception("Grid count doesnt match results"); } if (!caps) { this.Params.Input[inputSelectorMin].NickName = "-"; this.Params.Input[inputSelectorMin].Name = "-"; this.Params.Input[inputSelecterMax].NickName = "-"; this.Params.Input[inputSelecterMax].Name = "-"; } else { this.Params.Input[inputSelectorMin].NickName = "MinColor"; this.Params.Input[inputSelectorMin].Name = "MinColor"; this.Params.Input[inputSelecterMax].NickName = "MaxColor"; this.Params.Input[inputSelecterMax].Name = "MaxColor"; } var domain = Misc.AutoDomain(range, allResults); //Rhino.RhinoApp.WriteLine($"{range} -> {domain[0]} to {domain[1]}"); GH_GradientControl gc; try { gc = (GH_GradientControl)Params.Input[inputGradient].Sources[0].Attributes.GetTopLevel.DocObject; } catch (System.ArgumentOutOfRangeException) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Remember to add a gradient component in grasshopper!"); gc = null; } GradientParser gp = new GradientParser(gc) { Cap = caps, AboveMax = maxColor, BelowMin = minColor, Min = domain[0], Max = domain[1], Reverse = Params.Input[inputGradient].Reverse }; //Rhino.RhinoApp.WriteLine($"Probing {domain[0]} to the value of {gp.GetColors(new List<double> { domain[0] })[0]}"); //Rhino.RhinoApp.WriteLine($"Probing {domain[1]} to the value of {gp.GetColors(new List<double> { domain[1] })[0]}"); #region coloredMesh var outMeshes = new List <Mesh>(); for (int i = 0; i < grids.Count; i++) { //AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, $"Mesh vertices: {grids[i].SimMesh.Vertices.Count}, colors = {gp.GetColors(allResults.Branches[i].Select(p => p.Value).ToArray()).Length} f"); outMeshes.Add(grids[i].GetColoredMesh(gp.GetColors(allResults.Branches[i].Select(p => p.Value).ToArray()))); Mesh m = grids[i].SimMesh; Point3d[] points = grids[i].SimPoints.ToArray(); outMeshes[outMeshes.Count - 1].Translate(0, 0, Units.ConvertFromMeter(0.001)); } DA.SetDataList(0, outMeshes); #endregion coloredMesh #region layeredMesh if (grids[0].UseCenters == true) { return; } //Outputs GH_Structure <GH_Mesh> layeredMeshes = new GH_Structure <GH_Mesh>(); List <GH_Mesh> tempMeshes = new List <GH_Mesh>(); List <GH_Plane> outPlanes = new List <GH_Plane>(); GH_Structure <GH_Curve> outCurves = new GH_Structure <GH_Curve>(); const double SCALAR = 1; // don't change. const float OFFSET = 0.0001f; double allMin = double.MaxValue; double allMax = -double.MaxValue; for (int i = 0; i < allResults.Branches.Count; i++) { //System.Collections.IList results = allResults.get_Branch(i); for (int j = 0; j < allResults[i].Count; j++) { double result = allResults[i][j].Value; if (result < allMin) { allMin = result; } if (result > allMax) { allMax = result; } } } stepSize = inStepSize; double roundToNearest = 1; if (inStepSize == 0) // auto { //double digits = Math.Round(Math.Log10((domain[1] - domain[0]))) + 1; //double multiplier = Math.Pow(10, digits); //stepSize = Math.Log10((domain[1] - domain[0])); //if (allMax > 1000) // stepSize = 100; //else if (allMax > 100) // stepSize = 10; //else if (allMax > 10) // stepSize = 1; //else // stepSize = 0.1; stepSize = Misc.AutoStep(domain, out roundToNearest); // <-- TODO: We can set each slice in exactly the "round to nearest" number. } else if (inStepSize < 0) // fragment { stepSize = 1 / Math.Abs(inStepSize); } steps = Convert.ToInt32((domain[1] - domain[0]) / stepSize); for (int g = 0; g < grids.Count; g++) { //GH_Structure<GH_Curve> curves = new GH_Structure<GH_Curve>(); Grid grid = grids[g]; Mesh meshToCut = grids[g].SimMesh.DuplicateMesh(); //Mesh meshToCut = grids[g].SimMesh; List <double> results = ((List <GH_Number>)allResults.get_Branch(g)).Select(r => r.Value).ToList(); if (grids[g].UseCenters == true) { results = RTreeSolver.FindClosestWeightedValues(grids[g], results, true).ToList(); // ADD CONVERSION TODO: } //Rhino.RhinoApp.WriteLine($"min = {allMin}, max = {allMax}, steps = {steps}, stepsize = {stepSize}"); if (steps <= 1 || steps > 100) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"too {(steps < 4 ? "few" : "many")} steps (should be between 1 to 100)"); AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"min = {allMin}, max = {allMax}, steps = {steps}, stepsize = {stepSize}"); continue; } if (allMax == allMin) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"max==min"); continue; } meshToCut.Normals.ComputeNormals(); Plane cuttingPlane = new Plane(meshToCut.Vertices[0], meshToCut.FaceNormals[0]); //var planeOut = new Plane(plane); var planeBottom = new Plane(cuttingPlane); //List<int> belongsToWhichLayer = new List<int>(); Vector3f normal = (Vector3f)(cuttingPlane.ZAxis); //AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"normal x = {normal.X}, Y = {normal.Y}, Z = {normal.Z}"); planeBottom.Transform(Transform.Translation(-cuttingPlane.ZAxis)); //Moving the bottom down meshToCut.Translate(-normal * OFFSET); //Moving the vertices up for (int i = 0; i < results.Count; i++) { meshToCut.Vertices[i] += (normal) * (float)SCALAR * (OFFSET + (float)results[i]); } Mesh topMesh = meshToCut.DuplicateMesh(); tempMeshes.Add(new GH_Mesh(topMesh)); Mesh edgeMesh = new Mesh(); List <Point3d> ptOut = new List <Point3d>(); Polyline[] edges = meshToCut.GetNakedEdges(); double totalLength = 0; for (int i = 0; i < edges.Length; i++) { totalLength += edges[i].Length; } Polyline[] edgesProjected = new Polyline[edges.Length]; Transform p = Transform.PlanarProjection(planeBottom); for (int i = 0; i < edges.Length; i++) { for (int j = 0; j < edges[i].SegmentCount; j++) { Mesh msh = new Mesh(); Point3d[] pts = new Point3d[4]; int id = (j == edges[i].SegmentCount - 1) ? 0 : j + 1; pts[0] = new Point3d(edges[i].X[j], edges[i].Y[j], edges[i].Z[j]); pts[1] = new Point3d(edges[i].X[id], edges[i].Y[id], edges[i].Z[id]); pts[2] = new Point3d(pts[1]); pts[3] = new Point3d(pts[0]); pts[2].Transform(p); pts[3].Transform(p); msh.Vertices.AddVertices(pts); var fc = new MeshFace(3, 2, 1, 0); ptOut.AddRange(pts); msh.Faces.AddFace(fc); edgeMesh.Append(msh); } } meshToCut.Append(edgeMesh); meshToCut.Weld(Math.PI); tempMeshes.Add(new GH_Mesh(meshToCut)); //Transform t = Transform.Translation(new Vector3d(0, 0, inStepSize * SCALAR)); Vector3f v = normal * (float)(stepSize.RoundTo(roundToNearest) * SCALAR); Transform t = Transform.Translation(v); //AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"Vector v = {v.X}, {v.Y}, {v.Z}, instep = "); Mesh meshPerArea = new Mesh(); MeshingParameters mp = new MeshingParameters(0); //double resultValue = inputMin; //stepSize = (inputMax - inputMin) / (float)steps; double currentValue = domain[0]; int cuttingCount = -1; while (currentValue <= domain[1]) { cuttingCount++; if (cuttingCount == 0) { currentValue = domain[0]; } if (cuttingCount == 1) { cuttingPlane.Translate(new Vector3d(0, 0, domain[0].RoundTo(roundToNearest))); //currentValue = domain[0]; } if (cuttingCount > 0) { currentValue += stepSize; } if (cuttingCount > 80) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "ERROR CUT THE CUTTINGCOUNT"); break; } //Rhino.RhinoApp.WriteLine($"CurrentValue = {currentValue}, cuttingCount = {cuttingCount}"); //var resultValue = (double)cuttingCount / steps * (allMax - allMin) + allMin; //resultValue = (double)cuttingCount / steps * (domain[1] - domain[0]) + domain[0]; //resultValue = (double)cuttingCount / steps * (domain[1] - domain[0]) + domain[0]; //var resultValue = currentValue; // new //Rhino.RhinoApp.WriteLine($"Cutting {cuttingCount}, {resultValue}, {currentValue}, {allMin} - {allMax}"); //if (resultValue < domain[0]) // continue; //if (resultValue > domain[1]) // break; Polyline[] pl = Rhino.Geometry.Intersect.Intersection.MeshPlane(meshToCut, cuttingPlane); outPlanes.Add(new GH_Plane(cuttingPlane)); if (pl == null) { break; } Color col = gp.GetColors(new List <double>() { cuttingCount == 0 ? double.MinValue : currentValue.RoundTo(roundToNearest) })[0]; //Rhino.RhinoApp.WriteLine($"Probing value {currentValue} to {col}"); //Mesh meshPerCut = new Mesh(); GH_Path path = new GH_Path(g, cuttingCount); if (pl.Length > 0) { List <Curve> curves = new List <Curve>(); for (int j = 0; j < pl.Length; j++) { Curve curve = new PolylineCurve(pl[j]); if (cuttingCount <= 0) { curve.Translate(normal * (float)(domain[0] - stepSize)); } curve.Translate(-normal * (float)(currentValue * 0.95 - stepSize)); // was 0.95 nice //curve.Translate(-normal * (float)allMin + normal * (float)(cuttingCount * Units.ConvertFromMeter(0.01))); curves.Add(curve); // to create brep later outCurves.Append(new GH_Curve(curve), path); // for output } Brep[] breps2 = Brep.CreatePlanarBreps(curves, Units.ConvertFromMeter(0.001)); for (int j = 0; j < breps2.Length; j++) { Mesh[] mesh2 = Mesh.CreateFromBrep(breps2[j], mp); for (int k = 0; k < mesh2.Length; k++) { mesh2[k].VertexColors.CreateMonotoneMesh(col); //meshPerCut.Append(mesh2[k]); layeredMeshes.Append(new GH_Mesh(mesh2[k]), path); } } } //meshPerCut.VertexColors.CreateMonotoneMesh(col); if (cuttingCount > 0) { cuttingPlane.Transform(t); } } //layeredMeshes.Append(new GH_Mesh(meshPerArea), new GH_Path(g, ); } //for (int j = 0; j < pl.Length; j++) //{ // Curve curve = pl[j].ToNurbsCurve(); // GH_Path path = new GH_Path(g, cuttingCount); // outCurves.Append(new GH_Curve(curve), path); // Brep[] breps = Brep.CreatePlanarBreps(curve, Units.ConvertFromMeter(0.001)); // if (breps == null) // continue; // Brep brep = breps[0]; // var area = AreaMassProperties.Compute(brep); // if (area.Area > maxSize) // { // maxSize = area.Area; // outerIndex = j; // } //} //boundaryEdge = pl[outerIndex]; //for (int j = 0; j < pl.Length; j++) //{ // if (j != outerIndex) // holes.Add(pl[j].ToNurbsCurve()); //} //Mesh mesh = null; //if (boundaryEdge.IsClosed) //{ // mesh = Mesh.CreatePatch(boundaryEdge, Math.PI / 2.0, null, holes, null, null, false, 0); //} //else //{ // AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, $"Curve is not closed"); //} //outPlanes.Add(new GH_Plane(new Plane(cuttingPlane))); //int curvesCount = pl.Length; //int[] pointsRanges = new int[curvesCount]; //Point3d[][] pts = new Point3d[curvesCount][]; //for (int j = 0; j < pl.Length; j++) //{ // //Mesh mesh = GreenScenario.MeshUtil.CreateMeshWithHoles(pl); // //Mesh mesh = Mesh.CreateFromTessellation(points, pl, Plane.WorldXY, false); // //var mesh = Mesh.CreateFromClosedPolyline(pl[j]); // if (mesh == null) // continue; // //outCurves.Append(new GH_Curve(pl[j].ToNurbsCurve())); // //List<Color> colorList = new List<Color>(); // ////for (int i = 0; i < mesh.Faces.Count; i++) // ////{ // //// colorList.Add(col); // //// colorList.Add(col); // //// colorList.Add(col); // //// if (mesh.Faces[i].IsQuad) // //// colorList.Add(col); // ////} // //for (int i = 0; i < mesh.Vertices.Count; i++) // //{ // // colorList.Add(col); // //} // ////mesh.VertexColors.SetColors(colorList.ToArray()); // //AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, $"Vertices = {mesh.Vertices.Count}, colors = {mesh.VertexColors.Count}"); // // mesh.VertexColors.CreateMonotoneMesh(col); // //mesh.Translate(-normal * inStepSize * (float)SCALAR * cuttingCount * 0.90f); // // meshPerArea.Append(mesh); // // we don't have more heights to cut off. // //if (brep == null) // // continue; // //for (int i = 0; i < brep.Length; i++) // //{ // // belongsToWhichLayer.Add(count); // //} // //pts.Add(polylinecrv.PointAtStart); //} // By now curves are moved to different elevations. //crvs = crvs; //Rhino.RhinoApp.WriteLine("adding a mesh"); //oNumbers = outNumbers; //B = breps; //meshOut = mesh; Message = $"Cap = {(this.caps ? "on" : "off")} | Steps = {steps} | Step = {stepSize:0.0}"; DA.SetDataTree(1, layeredMeshes); DA.SetDataTree(2, outCurves); DA.SetDataList("Planes", outPlanes); DA.SetDataList("TempMeshes", tempMeshes); #endregion layeredMesh }
protected override void SolveInstance(IGH_DataAccess DA) { ITargetLength TargetLength = null; bool reset = false; int Flip = 0; List<Curve> FC = new List<Curve>(); List<Point3d> FV = new List<Point3d>(); double FixT = 0.01; double PullStrength = 0.8; double SmoothStrength = 0.8; double LengthTol = 0.15; bool Minim = false; int Iters = 1; GH_ObjectWrapper Surf = new GH_ObjectWrapper(); DA.GetData<GH_ObjectWrapper>(0, ref Surf); GH_ObjectWrapper Obj = null; DA.GetData<GH_ObjectWrapper>(1, ref Obj); TargetLength = Obj.Value as ITargetLength; DA.GetDataList<Curve>(2, FC); DA.GetDataList<Point3d>(3, FV); DA.GetData<int>(4, ref Flip); DA.GetData<double>(5, ref PullStrength); DA.GetData<int>(6, ref Iters); DA.GetData<bool>(7, ref reset); if (PullStrength == 0) { Minim = true; } if (Surf.Value is GH_Mesh) { DA.GetData<Mesh>(0, ref M); M.Faces.ConvertQuadsToTriangles(); } else { double L = 1.0; MeshingParameters MeshParams = new MeshingParameters(); MeshParams.MaximumEdgeLength = 3 * L; MeshParams.MinimumEdgeLength = L; MeshParams.JaggedSeams = false; MeshParams.SimplePlanes = false; Brep SB = null; DA.GetData<Brep>(0, ref SB); Mesh[] BrepMeshes = Mesh.CreateFromBrep(SB, MeshParams); M = new Mesh(); foreach (var mesh in BrepMeshes) M.Append(mesh); } if (reset || initialized == false) { #region reset M.Faces.ConvertQuadsToTriangles(); P = M.ToPlanktonMesh(); initialized = true; AnchorV.Clear(); FeatureV.Clear(); FeatureE.Clear(); //Mark any vertices or edges lying on features for (int i = 0; i < P.Vertices.Count; i++) { Point3d Pt = P.Vertices[i].ToPoint3d(); AnchorV.Add(-1); for (int j = 0; j < FV.Count; j++) { if (Pt.DistanceTo(FV[j]) < FixT) { AnchorV[AnchorV.Count - 1] = j; } } FeatureV.Add(-1); for (int j = 0; j < FC.Count; j++) { double param = new double(); FC[j].ClosestPoint(Pt, out param); if (Pt.DistanceTo(FC[j].PointAt(param)) < FixT) { FeatureV[FeatureV.Count - 1] = j; } } } int EdgeCount = P.Halfedges.Count / 2; for (int i = 0; i < EdgeCount; i++) { FeatureE.Add(-1); int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; Point3d PStart = P.Vertices[vStart].ToPoint3d(); Point3d PEnd = P.Vertices[vEnd].ToPoint3d(); for (int j = 0; j < FC.Count; j++) { double paramS = new double(); double paramE = new double(); Curve thisFC = FC[j]; thisFC.ClosestPoint(PStart, out paramS); thisFC.ClosestPoint(PEnd, out paramE); if ((PStart.DistanceTo(thisFC.PointAt(paramS)) < FixT) && (PEnd.DistanceTo(thisFC.PointAt(paramE)) < FixT)) { FeatureE[FeatureE.Count - 1] = j; } } } #endregion } else { for (int iter = 0; iter < Iters; iter++) { int EdgeCount = P.Halfedges.Count / 2; double[] EdgeLength = P.Halfedges.GetLengths(); List<bool> Visited = new List<bool>(); Vector3d[] Normals = new Vector3d[P.Vertices.Count]; for (int i = 0; i < P.Vertices.Count; i++) { Visited.Add(false); Normals[i] = Normal(P, i); } double t = LengthTol; //a tolerance for when to split/collapse edges double smooth = SmoothStrength; //smoothing strength double pull = PullStrength; //pull to target mesh strength // Split the edges that are too long for (int i = 0; i < EdgeCount; i++) { if (P.Halfedges[2 * i].IsUnused == false) { int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; if ((Visited[vStart] == false) && (Visited[vEnd] == false)) { double L2 = TargetLength.Calculate(P, 2 * i); if (EdgeLength[2 * i] > (1 + t) * (4f / 3f) * L2) { int SplitHEdge = P.Halfedges.TriangleSplitEdge(2 * i); if (SplitHEdge != -1) { int SplitCenter = P.Halfedges[SplitHEdge].StartVertex; P.Vertices.SetVertex(SplitCenter, MidPt(P, i)); //update the feature information FeatureE.Add(FeatureE[i]); FeatureV.Add(FeatureE[i]); AnchorV.Add(-1); //2 additional new edges have also been created (or 1 if split was on a boundary) //mark these as non-features int CEdgeCount = P.Halfedges.Count / 2; while (FeatureE.Count < CEdgeCount) { FeatureE.Add(-1); } Visited.Add(true); int[] Neighbours = P.Vertices.GetVertexNeighbours(SplitCenter); foreach (int n in Neighbours) { Visited[n] = true; } } } } } } //Collapse the edges that are too short for (int i = 0; i < EdgeCount; i++) { if (P.Halfedges[2 * i].IsUnused == false) { int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; if ((Visited[vStart] == false) && (Visited[vEnd] == false)) { if (!(AnchorV[vStart] != -1 && AnchorV[vEnd] != -1)) // if both ends are anchored, don't collapse { int Collapse_option = 0; //0 for none, 1 for collapse to midpt, 2 for towards start, 3 for towards end //if neither are anchorV if (AnchorV[vStart] == -1 && AnchorV[vEnd] == -1) { // if both on same feature (or neither on a feature) if (FeatureV[vStart] == FeatureV[vEnd]) { Collapse_option = 1; } // if start is on a feature and end isn't if ((FeatureV[vStart] != -1) && (FeatureV[vEnd] == -1)) { Collapse_option = 2; } // if end is on a feature and start isn't if ((FeatureV[vStart] == -1) && (FeatureV[vEnd] != -1)) { Collapse_option = 3; } } else // so one end must be an anchor { // if start is an anchor if (AnchorV[vStart] != -1) { // if both are on same feature, or if the end is not a feature if ((FeatureE[i] != -1) || (FeatureV[vEnd] == -1)) { Collapse_option = 2; } } // if end is an anchor if (AnchorV[vEnd] != -1) { // if both are on same feature, or if the start is not a feature if ((FeatureE[i] != -1) || (FeatureV[vStart] == -1)) { Collapse_option = 3; } } } Point3d Mid = MidPt(P, i); double L2 = TargetLength.Calculate(P, 2 * i); if ((Collapse_option != 0) && (EdgeLength[2 * i] < (1 - t) * 4f / 5f * L2)) { int Collapsed = -1; int CollapseRtn = -1; if (Collapse_option == 1) { Collapsed = P.Halfedges[2 * i].StartVertex; P.Vertices.SetVertex(Collapsed, MidPt(P, i)); CollapseRtn = P.Halfedges.CollapseEdge(2 * i); } if (Collapse_option == 2) { Collapsed = P.Halfedges[2 * i].StartVertex; CollapseRtn = P.Halfedges.CollapseEdge(2 * i); } if (Collapse_option == 3) { Collapsed = P.Halfedges[2 * i + 1].StartVertex; CollapseRtn = P.Halfedges.CollapseEdge(2 * i + 1); } if (CollapseRtn != -1) { int[] Neighbours = P.Vertices.GetVertexNeighbours(Collapsed); foreach (int n in Neighbours) { Visited[n] = true; } } } } } } } EdgeCount = P.Halfedges.Count / 2; if ((Flip == 0) && (PullStrength > 0)) { //Flip edges to reduce valence error for (int i = 0; i < EdgeCount; i++) { if (!P.Halfedges[2 * i].IsUnused && (P.Halfedges[2 * i].AdjacentFace != -1) && (P.Halfedges[2 * i + 1].AdjacentFace != -1) && (FeatureE[i] == -1) // don't flip feature edges ) { int Vert1 = P.Halfedges[2 * i].StartVertex; int Vert2 = P.Halfedges[2 * i + 1].StartVertex; int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex; int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex; int Valence1 = P.Vertices.GetValence(Vert1); int Valence2 = P.Vertices.GetValence(Vert2); int Valence3 = P.Vertices.GetValence(Vert3); int Valence4 = P.Vertices.GetValence(Vert4); if (P.Vertices.NakedEdgeCount(Vert1) > 0) { Valence1 += 2; } if (P.Vertices.NakedEdgeCount(Vert2) > 0) { Valence2 += 2; } if (P.Vertices.NakedEdgeCount(Vert3) > 0) { Valence3 += 2; } if (P.Vertices.NakedEdgeCount(Vert4) > 0) { Valence4 += 2; } int CurrentError = Math.Abs(Valence1 - 6) + Math.Abs(Valence2 - 6) + Math.Abs(Valence3 - 6) + Math.Abs(Valence4 - 6); int FlippedError = Math.Abs(Valence1 - 7) + Math.Abs(Valence2 - 7) + Math.Abs(Valence3 - 5) + Math.Abs(Valence4 - 5); if (CurrentError > FlippedError) { P.Halfedges.FlipEdge(2 * i); } } } } else { //Flip edges based on angle for (int i = 0; i < EdgeCount; i++) { if (!P.Halfedges[2 * i].IsUnused && (P.Halfedges[2 * i].AdjacentFace != -1) && (P.Halfedges[2 * i + 1].AdjacentFace != -1) && (FeatureE[i] == -1) // don't flip feature edges ) { int Vert1 = P.Halfedges[2 * i].StartVertex; int Vert2 = P.Halfedges[2 * i + 1].StartVertex; int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex; int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex; Point3d P1 = P.Vertices[Vert1].ToPoint3d(); Point3d P2 = P.Vertices[Vert2].ToPoint3d(); Point3d P3 = P.Vertices[Vert3].ToPoint3d(); Point3d P4 = P.Vertices[Vert4].ToPoint3d(); double A1 = Vector3d.VectorAngle(new Vector3d(P3 - P1), new Vector3d(P4 - P1)) + Vector3d.VectorAngle(new Vector3d(P4 - P2), new Vector3d(P3 - P2)); double A2 = Vector3d.VectorAngle(new Vector3d(P1 - P4), new Vector3d(P2 - P4)) + Vector3d.VectorAngle(new Vector3d(P2 - P3), new Vector3d(P1 - P3)); if (A2 > A1) { P.Halfedges.FlipEdge(2 * i); } } } } if (Minim) { Vector3d[] SmoothC = LaplacianSmooth(P, 1, smooth); for (int i = 0; i < P.Vertices.Count; i++) { if (AnchorV[i] == -1) // don't smooth feature vertices { P.Vertices.MoveVertex(i, 0.5 * SmoothC[i]); } } } Vector3d[] Smooth = LaplacianSmooth(P, 0, smooth); for (int i = 0; i < P.Vertices.Count; i++) { if (AnchorV[i] == -1) // don't smooth feature vertices { // make it tangential only Vector3d VNormal = Normal(P, i); double ProjLength = Smooth[i] * VNormal; Smooth[i] = Smooth[i] - (VNormal * ProjLength); P.Vertices.MoveVertex(i, Smooth[i]); if (P.Vertices.NakedEdgeCount(i) != 0)//special smoothing for feature edges { int[] Neighbours = P.Vertices.GetVertexNeighbours(i); int ncount = 0; Point3d Avg = new Point3d(); for (int j = 0; j < Neighbours.Length; j++) { if (P.Vertices.NakedEdgeCount(Neighbours[j]) != 0) { ncount++; Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d(); } } Avg = Avg * (1.0 / ncount); Vector3d move = Avg - P.Vertices[i].ToPoint3d(); move = move * smooth; P.Vertices.MoveVertex(i, move); } if (FeatureV[i] != -1)//special smoothing for feature edges { int[] Neighbours = P.Vertices.GetVertexNeighbours(i); int ncount = 0; Point3d Avg = new Point3d(); for (int j = 0; j < Neighbours.Length; j++) { if ((FeatureV[Neighbours[j]] == FeatureV[i]) || (AnchorV[Neighbours[j]] != -1)) { ncount++; Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d(); } } Avg = Avg * (1.0 / ncount); Vector3d move = Avg - P.Vertices[i].ToPoint3d(); move = move * smooth; P.Vertices.MoveVertex(i, move); } //projecting points onto the target along their normals if (pull > 0) { Point3d Point = P.Vertices[i].ToPoint3d(); Vector3d normal = Normal(P, i); Ray3d Ray1 = new Ray3d(Point, normal); Ray3d Ray2 = new Ray3d(Point, -normal); double RayPt1 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray1); double RayPt2 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray2); Point3d ProjectedPt; if ((RayPt1 < RayPt2) && (RayPt1 > 0) && (RayPt1 < 1.0)) { ProjectedPt = Point * (1 - pull) + pull * Ray1.PointAt(RayPt1); } else if ((RayPt2 < RayPt1) && (RayPt2 > 0) && (RayPt2 < 1.0)) { ProjectedPt = Point * (1 - pull) + pull * Ray2.PointAt(RayPt2); } else { ProjectedPt = Point * (1 - pull) + pull * M.ClosestPoint(Point); } P.Vertices.SetVertex(i, ProjectedPt); } if (FeatureV[i] != -1) //pull feature vertices onto feature curves { Point3d Point = P.Vertices[i].ToPoint3d(); Curve CF = FC[FeatureV[i]]; double param1 = 0.0; Point3d onFeature = new Point3d(); CF.ClosestPoint(Point, out param1); onFeature = CF.PointAt(param1); P.Vertices.SetVertex(i, onFeature); } } else { P.Vertices.SetVertex(i, FV[AnchorV[i]]); //pull anchor vertices onto their points } } //end new AnchorV = CompactByVertex(P, AnchorV); //compact the fixed points along with the vertices FeatureV = CompactByVertex(P, FeatureV); FeatureE = CompactByEdge(P, FeatureE); P.Compact(); //this cleans the mesh data structure of unused elements } } DA.SetData(0, P); }
public SurfaceSource(IEnumerable<Brep> Surfaces, List<String> CodeList, int el_m, int SrcID, Phase_Regime ph) :base(new double[8]{0, 0, 0, 0, 0, 0, 0, 0}, new Point3d(0,0,0), ph, SrcID) { samplespermeter = el_m; Srfs = Surfaces.ToList<Brep>(); Samples = new Point3d[Srfs.Count][]; MeshingParameters mp = new MeshingParameters(); mp.MaximumEdgeLength = 1.0 / (double)samplespermeter; mp.MinimumEdgeLength = 1.0 / (double)samplespermeter; Sub_A = new double[Srfs.Count]; SubDomains = new double[Srfs.Count][]; T = new Topology[Srfs.Count]; //for(int i = 0; i < Curves.Count; i++) System.Threading.Tasks.Parallel.For(0, Srfs.Count, ips => { int i = (int)ips; //Divide each curve up in ~equal length segments. Mesh[] m = Mesh.CreateFromBrep(Srfs[i],mp); BoundingBox Box = m[0].GetBoundingBox(true); for (int j = 1; j < m.Length; j++) Box.Union(m[j].GetBoundingBox(true)); T[i] = new Topology(Utilities.PachTools.RPttoHPt(Box.Min), Utilities.PachTools.RPttoHPt(Box.Max)); List<Point3d> pts = new List<Point3d>(); SubDomains[i] = new double[m[i].Faces.Count + 1]; for (int j = 0; j < m[i].Faces.Count; j++) { double u,v; ComponentIndex ci; Point3d no; Vector3d V; Point3d A = m[i].Vertices[m[i].Faces[j].A]; Srfs[i].ClosestPoint(A, out no, out ci, out u, out v, 1, out V); A += V; Point3d B = m[i].Vertices[m[i].Faces[j].B]; Srfs[i].ClosestPoint(B, out no, out ci, out u, out v, 1, out V); B += V; Point3d C = m[i].Vertices[m[i].Faces[j].C]; Srfs[i].ClosestPoint(C, out no, out ci, out u, out v, 1, out V); C += V; Point3d D = m[i].Vertices[m[i].Faces[j].D]; Srfs[i].ClosestPoint(D, out no, out ci, out u, out v, 1, out V); D += V; if (m[i].Faces[j].IsQuad) { Hare.Geometry.Point[] poly = new Hare.Geometry.Point[4]; poly[0] = new Hare.Geometry.Point(A.X, A.Y, A.Z); poly[1] = new Hare.Geometry.Point(B.X, B.Y, B.Z); poly[2] = new Hare.Geometry.Point(C.X, C.Y, C.Z); poly[3] = new Hare.Geometry.Point(D.X, D.Y, D.Z); T[i].Add_Polygon(poly); } else { Hare.Geometry.Point[] poly = new Hare.Geometry.Point[3]; poly[0] = new Hare.Geometry.Point(A.X, A.Y, A.Z); poly[1] = new Hare.Geometry.Point(B.X, B.Y, B.Z); poly[2] = new Hare.Geometry.Point(C.X, C.Y, C.Z); T[i].Add_Polygon(poly); } pts.Add(m[i].Faces[j].IsQuad ? new Point3d(A.X + B.X + C.X + D.X, A.Y + B.Y + C.Y + D.Y, A.Z + B.Z + C.Z + D.Z) / 4 : new Point3d(A.X + B.X + C.X, A.Y + B.Y + C.Y, A.Z + B.Z + C.Z) / 3); SubDomains[i][j + 1] = Sub_A[i] += T[i].Polygon_Area(j); } Samples[i] = pts.ToArray(); }); Domains = new double[Srfs.Count+1]; DomainLevel = new double[Srfs.Count][]; DomainPower = new double[Srfs.Count][]; Total_A = 0; for (int i = 0; i < Srfs.Count; i++) { for (int j = 0; j < SubDomains[i].Length; j++) SubDomains[i][j] /= Sub_A[i]; double A = Srfs[i].GetArea(); Domains[i + 1] = Total_A += A; DomainLevel[i] = Utilities.PachTools.DecodeSourcePower(CodeList[i]); DomainPower[i] = new double[8]; double PowerMod = A; for (int oct = 0; oct < 8; oct++) DomainPower[i][oct] = 1E-12 * Math.Pow(10, .1 * DomainLevel[i][oct]) / PowerMod; } for (int i = 0; i < Domains.Length; i++) { Domains[i] /= Total_A; } }
/// <summary> /// Searches for locations where the distance from a RhinoObject, in one set of objects, /// is less than the specified distance to another RhinoObject in a second set of objects. /// This function uses the object's mesh to calculate the interferences. /// Acceptable object types include: BrepObject, ExtrusionObject, MeshObject, and SubDObject. /// </summary> /// <param name="setA">The first set of Rhino objects.</param> /// <param name="setB">The second set of Rhino objects.</param> /// <param name="distance">The largest distance at which a clash can occur.</param> /// <param name="meshType">The type of mesh to be used for the calculation.</param> /// <param name="meshingParameters">The meshing parameters used to generate meshes for the calculation.</param> /// <returns>An array of mesh interference object if successful, or an empty array on failure.</returns> public static MeshInterference[] Search(IEnumerable <RhinoObject> setA, IEnumerable <RhinoObject> setB, double distance, MeshType meshType, MeshingParameters meshingParameters) { using (var set_a_array = new Runtime.InternalRhinoObjectArray(setA)) using (var set_b_array = new Runtime.InternalRhinoObjectArray(setB)) { var ptr_set_a = set_a_array.NonConstPointer(); var ptr_set_b = set_b_array.NonConstPointer(); var ptr_mp = meshingParameters.ConstPointer(); var ptr_clash_events = UnsafeNativeMethods.RhObjectClashEventArray_New(); // new var count = UnsafeNativeMethods.RHC_CRhClashDetect_TestClash(ptr_set_a, ptr_set_b, distance, (int)meshType, ptr_mp, ptr_clash_events); var rc = new MeshInterference[count]; for (var i = 0; i < count; i++) { var index_a = -1; var index_b = -1; var hit_points = new SimpleArrayPoint3d(); // new var ptr_hit_points = hit_points.NonConstPointer(); var mi = new MeshInterference(); if (UnsafeNativeMethods.RhObjectClashEventArray_GetAt(ptr_clash_events, i, ref index_a, ref index_b, ptr_hit_points)) { mi.IndexA = index_a; mi.IndexB = index_b; mi.HitPoints = hit_points.Count > 0 ? hit_points.ToArray() : new Point3d[0]; } else { mi.IndexA = -1; mi.IndexB = -1; mi.HitPoints = new Point3d[0]; } hit_points.Dispose(); // delete rc[i] = mi; } UnsafeNativeMethods.RhObjectClashEventArray_Delete(ptr_clash_events); // delete GC.KeepAlive(setA); GC.KeepAlive(setB); return(rc); } }
protected override void SolveInstance(IGH_DataAccess DA) { ETABS2013.cOAPI activate = null; List <GeometryBase> surfaces = new List <GeometryBase>(); if (!DA.GetData(0, ref activate)) { return; } if (!DA.GetDataList(1, surfaces)) { return; } /* for (int i = 0; i < meshes.Count(); i++) * { * * * * //Get the contour polyline and its points (this is done to get the points in the right order * Rhino.Geometry.Plane mshPlane = new Rhino.Geometry.Plane(Plane.WorldXY.Origin, new Vector3d(0, 0, 1)); * Polyline[] mshOutlines = meshes[i].GetOutlines(mshPlane); * List<Point3d> pts = mshOutlines[0].GetRange(0, mshOutlines[0].Count - 1).ToList(); // Last value in the range is the first point again * * //I uset arrays cus the AddByCoord function can only handle arrays * double[] xValues = new double[pts.Count]; * double[] yValues = new double[pts.Count]; * double[] zValues = new double[pts.Count]; * for(int j = 0; j < pts.Count; j++) * { * xValues[j] =pts[j].X; * yValues[j] = pts[j].Y; * zValues[j] = pts[j].Z; * } * * * * string Name = "Slab" + i; * ETABS.SapModel.AreaObj.AddByCoord(pts.Count(), ref xValues, ref yValues, ref zValues, ref Name); * ETABS.SapModel.View.RefreshView(0, false); * } */ //Connect from the input ETABS file ETABS2013.cOAPI ETABS = (ETABS2013.cOAPI)activate; Mesh mesh = new Mesh(); for (int i = 0; i < surfaces.Count(); i++) { //If input is brep convert to mesh (easiest way to get the points) if (surfaces[i].GetType() == typeof(Rhino.Geometry.Brep)) { MeshingParameters mshParam = new MeshingParameters(); mshParam.MinimumTolerance = 0.01; //we can get meshing params from a standard GH component as it is a generic type Mesh[] mshArray = Mesh.CreateFromBrep((Brep)surfaces[i], mshParam); mesh = mshArray[0]; } //If input is a mesh no convertion is needed else if (surfaces[i].GetType() == typeof(Rhino.Geometry.Mesh)) { mesh = (Mesh)surfaces[i]; } //If not mesh or brep do nothing (return) else { return; } //Get the contour polyline and its points (this is done to get the points in the right order BoundingBox bMesh = new BoundingBox(); Rhino.Geometry.Plane mshPlane = new Rhino.Geometry.Plane(bMesh.Center, mesh.FaceNormals[0]); //Just take one normal on the surface since it's planar Polyline[] mshOutlines = mesh.GetOutlines(mshPlane); List <Point3d> pts = mshOutlines[0].GetRange(0, mshOutlines[0].Count - 1).ToList(); // Last value in the range is the first point again //I use arrays because the AddByCoord function can only handle arrays double[] xValues = new double[pts.Count]; double[] yValues = new double[pts.Count]; double[] zValues = new double[pts.Count]; for (int j = 0; j < pts.Count; j++) { //Add all the x,y,z values from the mesh into arrays, used in AddByCoord function xValues[j] = pts[j].X; yValues[j] = pts[j].Y; zValues[j] = pts[j].Z; } string Name = "Slab" + i; //Add the mesh in ETABS and refresh the view ETABS.SapModel.AreaObj.AddByCoord(pts.Count(), ref xValues, ref yValues, ref zValues, ref Name); ETABS.SapModel.View.RefreshView(0, false); DA.SetData(0, ETABS); } }
/// <summary> /// Shorthand tool for map mesh objects. /// </summary> /// <param name="Map_Srf">A NURBS surface to mesh.</param> /// <param name="Increment">the maximum dimension between vertices.</param> /// <returns>the map mesh object.</returns> public static Mesh Create_Map_Mesh(IEnumerable<Brep> Map_Srf, double Increment) { Mesh Map_Mesh = new Mesh(); MeshingParameters mp = new MeshingParameters(); mp.MaximumEdgeLength = Increment; mp.MinimumEdgeLength = Increment; mp.SimplePlanes = false; mp.JaggedSeams = false; Brep[] Srfs = Map_Srf.ToArray<Brep>(); for (int i = 0; i < Map_Srf.ToArray<Brep>().Length; i++) Map_Mesh.Append(Rhino.Geometry.Mesh.CreateFromBrep(Srfs[i], mp)[0]); return Map_Mesh; }
/// <summary> /// Finds all of the mesh faces on each of two Rhino objects that interfere within a clash distance. /// This function uses the object's mesh to calculate the interferences. /// Acceptable object types include: BrepObject, ExtrusionObject, MeshObject, and SubDObject. /// </summary> /// <param name="objA">The first Rhino object.</param> /// <param name="objB">The second Rhino object.</param> /// <param name="distance">The largest distance at which a clash can occur.</param> /// <param name="meshType">The type of mesh to be used for the calculation.</param> /// <param name="meshingParameters">The meshing parameters used to generate meshes for the calculation.</param> /// <returns>The resulting meshes are sub-meshes of the input meshes if successful, or an empty array on error.</returns> public static Mesh[] FindDetail(RhinoObject objA, RhinoObject objB, double distance, MeshType meshType, MeshingParameters meshingParameters) { if (null == objA) { throw new ArgumentNullException(nameof(objA)); } if (null == objB) { throw new ArgumentNullException(nameof(objB)); } using (var out_meshes = new SimpleArrayMeshPointer()) { var ptr_obj_a = objA.ConstPointer(); var ptr_obj_b = objB.ConstPointer(); var ptr_mp = meshingParameters.ConstPointer(); var ptr_out_meshes = out_meshes.NonConstPointer(); var count = UnsafeNativeMethods.RHC_CRhClashDetect_FindClashDetail(ptr_obj_a, ptr_obj_b, distance, (int)meshType, ptr_mp, ptr_out_meshes); GC.KeepAlive(objA); GC.KeepAlive(objB); return(count > 0 ? out_meshes.ToNonConstArray() : new Mesh[0]); } }
/// <summary> /// input a List/IGH_GeometricGoo/ /// List/IGH_GeometricGoo/ shapes = new List/IGH_GeometricGoo/(); /// DA.GetDataList/IGH_GeometricGoo/(2, shapes); /// </summary> /// <param name="geometricGoos">List IGH_GeometricGoo shapes, can be Brep and Mesh</param> /// <returns>joinedMesh</returns> /// public static Mesh ParseToJoinedMesh(List <IGH_GeometricGoo> geometricGoos, out BoundingBox boundingBox, bool parallel = true) { boundingBox = new BoundingBox(); if (geometricGoos.Count == 0) { return(null); } Mesh[] meshes = new Mesh[geometricGoos.Count]; Mesh joinedMesh = new Mesh(); if (parallel) { Parallel.For(0, geometricGoos.Count, delegate(int i) { IGH_GeometricGoo shape = geometricGoos[i]; if (shape is Mesh || shape is GH_Mesh) { var geobase = GH_Convert.ToGeometryBase(shape); meshes[i] = geobase as Mesh; } else if (shape is Brep || shape is GH_Brep) { var geobase = GH_Convert.ToGeometryBase(shape); Brep brep = geobase as Brep; MeshingParameters mp = MeshingParameters.Default; Mesh[] meshParts = Mesh.CreateFromBrep(brep, mp); meshes[i] = meshParts[0]; for (int j = 1; j < meshParts.Length; j++) { meshes[i].Append(meshParts[j]); } } }); } else { for (int i = 0; i < geometricGoos.Count; i++) { IGH_GeometricGoo shape = geometricGoos[i]; if (shape is Mesh || shape is GH_Mesh) { var geobase = GH_Convert.ToGeometryBase(shape); meshes[i] = geobase as Mesh; } else if (shape is Brep || shape is GH_Brep) { var geobase = GH_Convert.ToGeometryBase(shape); Brep brep = geobase as Brep; MeshingParameters mp = MeshingParameters.Default; Mesh[] meshParts = Mesh.CreateFromBrep(brep, mp); meshes[i] = meshParts[0]; for (int j = 1; j < meshParts.Length; j++) { meshes[i].Append(meshParts[j]); } } } } foreach (var mesh in meshes) { if (mesh != null) { joinedMesh.Append(mesh); } } CleanMesh(joinedMesh); boundingBox = joinedMesh.GetBoundingBox(true); return(joinedMesh); }
internal static IEnumerable <Mesh> GetPreviewMeshes ( this IEnumerable <DB.GeometryObject> geometries, MeshingParameters meshingParameters ) { var scaleFactor = Revit.ModelUnits; foreach (var geometry in geometries) { if (geometry.Visibility != DB.Visibility.Visible) { continue; } switch (geometry) { case DB.GeometryInstance instance: { var xform = instance.Transform.ToRhino().ChangeUnits(scaleFactor); foreach (var g in instance.SymbolGeometry.GetPreviewMeshes(meshingParameters)) { g?.Transform(xform); yield return(g); } break; } case DB.Mesh mesh: { if (mesh.NumTriangles <= 0) { continue; } var m = mesh.ToRhino(); yield return(m?.ChangeUnits(scaleFactor)); break; } case DB.Face face: { var faceMesh = (meshingParameters is null ? face.Triangulate() : face.Triangulate(meshingParameters.RelativeTolerance)); var f = faceMesh?.ToRhino(); yield return(f?.ChangeUnits(scaleFactor));; break; } case DB.Solid solid: { if (solid.Faces.IsEmpty) { continue; } var solidFaces = solid.Faces.OfType <DB.Face>(); bool useMultipleMaterials = solidFaces.HasMultipleMaterials(); var facesMeshes = useMultipleMaterials ? null : new List <Mesh>(solid.Faces.Size); foreach (var face in solidFaces) { var faceMesh = (meshingParameters is null ? face.Triangulate() : face.Triangulate(meshingParameters.RelativeTolerance)); var f = faceMesh?.ToRhino().ChangeUnits(scaleFactor); if (facesMeshes is null) { yield return(f); } else if (f is object) { facesMeshes.Add(f); } } if (facesMeshes is object) { if (facesMeshes.Count > 0) { var mesh = new Mesh(); mesh.Append(facesMeshes); yield return(mesh); } else { yield return(null); } } break; } } } }
private void Construct(List<Rhino.DocObjects.RhinoObject> ObjectList) { BoundingBox Box = ObjectList[0].Geometry.GetBoundingBox(true); for (int i = 1; i < ObjectList.Count; i++) Box.Union(ObjectList[i].Geometry.GetBoundingBox(true)); List<GeometryBase> BList = new List<GeometryBase>(); Brep_ids = new List<int>(); List<Material> Mat_Layer = new List<Material>(); List<Scattering> Scat_Layer = new List<Scattering>(); List<Material> Mat_Obj = new List<Material>(); List<Scattering> Scat_Obj = new List<Scattering>(); List<double[]> Trans_Layer = new List<double[]>(); List<double[]> Trans_Obj = new List<double[]>(); List<bool> Finite_Layers = new List<bool>(); List<bool> Finite_Obj = new List<bool>(); //Organize the geometry into Breps //Get materials for each layer: for (int l = 0; l < Rhino.RhinoDoc.ActiveDoc.Layers.Count; l++) { Rhino.DocObjects.Layer Layer = Rhino.RhinoDoc.ActiveDoc.Layers[l]; string abstype = Layer.GetUserString("ABSType"); if (abstype == "Buildup") { Finite_Layers.Add(false); string BU = Layer.GetUserString("BuildUp"); string[] BU_split = BU.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); List<AbsorptionModels.ABS_Layer> Buildup = new List<AbsorptionModels.ABS_Layer>(); foreach (string swatch in BU_split) Buildup.Add(AbsorptionModels.ABS_Layer.LayerFromCode(swatch)); Mat_Layer.Add(new Environment.Smart_Material(Buildup, 44100, Env_Prop.Rho(0), Env_Prop.Sound_Speed(0), 2)); double[] Abs = new double[8], Scat = new double[8], Trans = new double[8]; Pachyderm_Acoustic.UI.PachydermAc_PlugIn.DecodeAcoustics(Layer.GetUserString("Acoustics"), ref Abs, ref Scat, ref Trans); ///Other properties are still coefficient based... Scat_Layer.Add(new Environment.Lambert_Scattering(Scat, SplitRatio)); Trans_Layer.Add(Trans); } else if (abstype == "Buildup_Finite") { Finite_Layers.Add(true); string BU = Layer.GetUserString("BuildUp"); string[] BU_split = BU.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); List<AbsorptionModels.ABS_Layer> Buildup = new List<AbsorptionModels.ABS_Layer>(); foreach (string swatch in BU_split) Buildup.Add(AbsorptionModels.ABS_Layer.LayerFromCode(swatch)); Environment.Smart_Material sm = new Environment.Smart_Material(Buildup, 44100, Env_Prop.Rho(0), Env_Prop.Sound_Speed(0), 2); Mat_Layer.Add(sm); double[] Abs = new double[8], Scat = new double[8], Trans = new double[8]; Pachyderm_Acoustic.UI.PachydermAc_PlugIn.DecodeAcoustics(Layer.GetUserString("Acoustics"), ref Abs, ref Scat, ref Trans); ///Other properties are still coefficient based... Scat_Layer.Add(new Environment.Lambert_Scattering(Scat, SplitRatio)); Trans_Layer.Add(Trans); } else { Finite_Layers.Add(false); string spec = Layer.GetUserString("Acoustics"); if (spec == "") { ///Layer is not used. As long as there is no geometry for pachyderm on this layer without object set properties, this is ok. Mat_Layer.Add(null); Scat_Layer.Add(null); Trans_Layer.Add(null); continue; } double[] Abs = new double[8], Scat = new double[8], Trans = new double[8]; Pachyderm_Acoustic.UI.PachydermAc_PlugIn.DecodeAcoustics(spec, ref Abs, ref Scat, ref Trans); Mat_Layer.Add(new Environment.Basic_Material(Abs, new double[8] { 0, 0, 0, 0, 0, 0, 0, 0 })); Scat_Layer.Add(new Environment.Lambert_Scattering(Scat, SplitRatio)); Trans_Layer.Add(Trans); } } for (int q = 0; q <= ObjectList.Count - 1; q++) { List<Brep> B = new List<Brep>(); if (ObjectList[q].ObjectType == Rhino.DocObjects.ObjectType.Brep) { Rhino.DocObjects.BrepObject BObj = ((Rhino.DocObjects.BrepObject)ObjectList[q]); B.Add(BObj.BrepGeometry.DuplicateBrep()); //string m = ObjectList[q].Geometry.GetUserString("Acoustics_User"); if (ObjectList[q].Geometry.GetUserString("Acoustics_User") == "yes") { double[] ABS = new double[8], SCAT = new double[8], TRANS = new double[8]; Pachyderm_Acoustic.UI.PachydermAc_PlugIn.DecodeAcoustics(ObjectList[q].Geometry.GetUserString("Acoustics"), ref ABS, ref SCAT, ref TRANS); Mat_Obj.Add(new Basic_Material(ABS, new double[] { 0, 0, 0, 0, 0, 0, 0, 0 })); Finite_Obj.Add(false); Scat_Obj.Add(new Lambert_Scattering(SCAT, SplitRatio)); Trans_Obj.Add(TRANS); } else { //Rhino.DocObjects.Layer Layer = Rhino.RhinoDoc.ActiveDoc.Layers[ObjectList[q].Attributes.LayerIndex]; //AcousticsData.Add(Layer.GetUserString("Acoustics")); Mat_Obj.Add(Mat_Layer[ObjectList[q].Attributes.LayerIndex]); Scat_Obj.Add(Scat_Layer[ObjectList[q].Attributes.LayerIndex]); Trans_Obj.Add(Trans_Layer[ObjectList[q].Attributes.LayerIndex]); Finite_Obj.Add(Finite_Layers[ObjectList[q].Attributes.LayerIndex]); } } else if (ObjectList[q].ObjectType == Rhino.DocObjects.ObjectType.Extrusion) { Rhino.Geometry.Brep BObj = ((Rhino.DocObjects.ExtrusionObject)ObjectList[q]).ExtrusionGeometry.ToBrep(); for (int i = 0; i < BObj.Faces.Count; i++) { if (ObjectList[q].Geometry.GetUserString("Acoustics_User") == "yes") { //AcousticsData.Add(ObjectList[q].Geometry.GetUserString("Acoustics")); double[] ABS = new double[8], SCAT = new double[8], TRANS = new double[8]; Pachyderm_Acoustic.UI.PachydermAc_PlugIn.DecodeAcoustics(ObjectList[q].Geometry.GetUserString("Acoustics"), ref ABS, ref SCAT, ref TRANS); Mat_Obj.Add(new Basic_Material(ABS, new double[] { 0, 0, 0, 0, 0, 0, 0, 0 })); Scat_Obj.Add(new Lambert_Scattering(SCAT, SplitRatio)); Trans_Obj.Add(TRANS); Finite_Obj.Add(false); } else { //Rhino.DocObjects.Layer Layer = Rhino.RhinoDoc.ActiveDoc.Layers[ObjectList[q].Attributes.LayerIndex]; //AcousticsData.Add(Layer.GetUserString("Acoustics")); //Rhino.DocObjects.Layer Layer = Rhino.RhinoDoc.ActiveDoc.Layers[ObjectList[q].Attributes.LayerIndex]; //AcousticsData.Add(Layer.GetUserString("Acoustics")); Mat_Obj.Add(Mat_Layer[ObjectList[q].Attributes.LayerIndex]); Scat_Obj.Add(Scat_Layer[ObjectList[q].Attributes.LayerIndex]); Trans_Obj.Add(Trans_Layer[ObjectList[q].Attributes.LayerIndex]); Finite_Obj.Add(Finite_Layers[ObjectList[q].Attributes.LayerIndex]); } //B.Add(BObj.Faces[0].ToBrep()); //for (int i = 1; i < BObj.Faces.Count; i++) //{ // if (ObjectList[q].Geometry.GetUserString("Acoustics_User") == "yes") // { // AcousticsData.Add(ObjectList[q].Geometry.GetUserString("Acoustics")); // } // else // { // Rhino.DocObjects.Layer Layer = Rhino.RhinoDoc.ActiveDoc.Layers[ObjectList[q].Attributes.LayerIndex]; // AcousticsData.Add(Layer.GetUserString("Acoustics")); // } B.Add(BObj.Faces[i].ToBrep()); } } else { continue; } BList.AddRange(B); } //////////////////////////////////////// Topo = new Hare.Geometry.Topology[1]; Topo[0] = new Topology(Utilities.PachTools.RPttoHPt(Box.Min), Utilities.PachTools.RPttoHPt(Box.Max)); //////////////////////////////////////// for (int q = 0; q < BList.Count; q++) { for (int r = 0; r < ((Brep)BList[q]).Faces.Count; r++) { BrepList.Add(((Brep)BList[q]).Faces[r].DuplicateFace(false)); //Material Abs = null ; //Scattering Scat = null; //double[] Transparency = new double[8]; double[] Transmission = new double[8]; //double[] Scat = new double[8]; //if (!string.IsNullOrEmpty(AcousticsData[q])) //if (Mat_Obj[q] != null) //{ // //double[] Absorption = new double[8]; // //double[] phase = new double[8]; // //double[] Scattering = new double[8]; // ////double[,] Scattering = new double[8, 3]; // //double[] Reflection = new double[8]; // //UI.PachydermAc_PlugIn.DecodeAcoustics(AcousticsData[q], ref Absorption, ref Scattering, ref Transparency); // Abs = Mat_Obj[q]; // Scat = Scat_Obj[q]; // Transmission = Trans_Obj[q]; //} //else if ((Mat_Obj[q] == null) || (Scat_Obj[q] == null) || (Trans_Obj[q] == null)) { if (!Custom_Method) { Status = System.Windows.Forms.MessageBox.Show("A material is not specified correctly. Please assign absorption and scattering to all layers in the model.", "Materials Error", System.Windows.Forms.MessageBoxButtons.OK); Complete = false; return; } ///Materials do not need to be specified, as it will not be used for an acoustical simulation... (hopefully...) } //for (int i = 0; i < 8; i++) //{ // Reflection[i] = (1 - Absorption[i]); // Transmission[i] = Transparency[i]; // Scattering[i, 1] = Scat[i]; // double Mod = ((Scattering[i, 1] < (1 - Scattering[i, 1])) ? (Scattering[i, 1] * SplitRatio / 2) : ((1 - Scattering[i, 1]) * SplitRatio / 2)); // Scattering[i, 0] = Scattering[i, 1] - Mod; // Scattering[i, 2] = Scattering[i, 1] + Mod; // phase[i] = 0; //} Mesh[] meshes; MeshingParameters mp = new MeshingParameters(); if (Finite_Obj[q]) { mp.MinimumEdgeLength = 0.1; mp.SimplePlanes = false; } else { mp.MinimumEdgeLength = 0.1; mp.SimplePlanes = true; } meshes = Rhino.Geometry.Mesh.CreateFromBrep((Brep)BrepList[BrepList.Count - 1], mp); if (meshes == null) throw new Exception("Problem with meshes"); for (int t = 0; t < meshes.Length; t++) { if (meshes[t].Faces.Count < 1) { Status = System.Windows.Forms.MessageBox.Show("A surface in the model does not generate a rendermesh. This surface will not be represented in the simulation. It is recommended that you cancel this simulation and repair the affected surface. It can be located in shaded view by finding the surface which generates boundary and isoparm lines, but does not generate a fill. It can sometimes be repaired by running the command 'ShrinkTrimmedSurface'. If this does not work, it will have to be replaced by some means which would generate a proper surface.", "Surface without Rendermesh", System.Windows.Forms.MessageBoxButtons.OKCancel); if (Status == System.Windows.Forms.DialogResult.Cancel) { Complete = false; return; } continue; } for (int u = 0; u < meshes[t].Faces.Count; u++) { Hare.Geometry.Point[] P; if (meshes[t].Faces[u].IsQuad) { P = new Hare.Geometry.Point[4]; Point3f FP = meshes[t].Vertices[meshes[t].Faces[u][0]]; P[0] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z); FP = meshes[t].Vertices[meshes[t].Faces[u][1]]; P[1] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z); FP = meshes[t].Vertices[meshes[t].Faces[u][2]]; P[2] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z); FP = meshes[t].Vertices[meshes[t].Faces[u][3]]; P[3] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z); } else { P = new Hare.Geometry.Point[3]; Point3f FP = meshes[t].Vertices[meshes[t].Faces[u][0]]; P[0] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z); FP = meshes[t].Vertices[meshes[t].Faces[u][1]]; P[1] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z); FP = meshes[t].Vertices[meshes[t].Faces[u][2]]; P[2] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z); } if (Finite_Obj[q]) { if (!(Mat_Obj[q] is Smart_Material)) throw new Exception("Finite Material must have a Smart_Material..."); Smart_Material mat = Mat_Obj[q] as Smart_Material; AbsorptionData.Add(new Finite_Material(mat, BrepList[q], meshes[t], u, Env_Prop)); } else AbsorptionData.Add(Mat_Obj[q]); ScatteringData.Add(Scat_Obj[q]); TransmissionData.Add(Trans_Obj[q]); bool Trans = false; for (int t_oct = 0; t_oct < 8; t_oct++) { if (Transmission[t_oct] > 0) { Trans = true; break; } } Transmissive.Add(Trans); if (BrepList[BrepList.Count - 1].Faces[t].IsPlanar()) { Topo[0].Add_Polygon(P); Brep_ids.Add(BrepList.Count - 1); } else { Topo[0].Add_Polygon(new Hare.Geometry.Point[3] { P[0], P[1], P[2] }); Brep_ids.Add(BrepList.Count - 1); if (P.Length > 3) { //break this quad into two polygons in order to avoid warping... if (Finite_Obj[q]) { if (!(Mat_Obj[q] is Smart_Material)) throw new Exception("Finite Material must have a Smart_Material..."); Smart_Material mat = Mat_Obj[q] as Smart_Material; AbsorptionData.Add(new Finite_Material(mat, BrepList[q], meshes[t], u, Env_Prop)); } else AbsorptionData.Add(Mat_Obj[q]); ScatteringData.Add(Scat_Obj[q]); TransmissionData.Add(Trans_Obj[q]); Transmissive.Add(Trans); Topo[0].Add_Polygon(new Hare.Geometry.Point[3] { P[0], P[2], P[3] }); Brep_ids.Add(BrepList.Count - 1); } } } } } } //Set up a system to find random points on planes.// Plane_Area = new double[Topo[0].Plane_Members.Length]; PolyPlaneFract = new double[Topo[0].Plane_Members.Length][]; for (int q = 0; q < Topo[0].Plane_Members.Length; q++) { foreach (int t in Topo[0].Plane_Members[q]) { Plane_Area[q] += Topo[0].Polygon_Area(t); } } ////////////////////////// for (int i = 0; i < Topo[0].planeList.Count; i++) for (int j = 0; j < Topo[0].Plane_Members[i].Count; j++) { Point3d pt = Utilities.PachTools.HPttoRPt(Topo[0].Polygon_Centroid(Topo[0].Plane_Members[i][j])); string n = Topo[0].Polys[Topo[0].Plane_Members[i][j]].Plane_ID.ToString(); } ////////////////////////// for (int q = 0; q < Topo[0].Plane_Members.Length; q++) { PolyPlaneFract[q] = new double[Topo[0].Plane_Members[q].Count]; PolyPlaneFract[q][0] = Topo[0].Polygon_Area(Topo[0].Plane_Members[q][0]) / Plane_Area[q]; for (int t = 1; t < Topo[0].Plane_Members[q].Count; t++) { PolyPlaneFract[q][t] += PolyPlaneFract[q][t - 1] + Topo[0].Polygon_Area(Topo[0].Plane_Members[q][t]) / Plane_Area[q]; } } Valid = true; //Utilities.PachTools.Plot_Hare_Topology(Topo[0]); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object can be used to retrieve data from input parameters and /// to store data in output parameters.</param> protected override void SolveInstance(IGH_DataAccess DA) { ITargetLength TargetLength = null; bool reset = false; int Flip = 0; List <Curve> FC = new List <Curve>(); List <Point3d> FV = new List <Point3d>(); double FixT = 0.01; double PullStrength = 0.8; double SmoothStrength = 0.8; double LengthTol = 0.15; bool Minim = false; int Iters = 1; GH_ObjectWrapper Surf = new GH_ObjectWrapper(); DA.GetData <GH_ObjectWrapper>(0, ref Surf); GH_ObjectWrapper Obj = null; DA.GetData <GH_ObjectWrapper>(1, ref Obj); TargetLength = Obj.Value as ITargetLength; DA.GetDataList <Curve>(2, FC); DA.GetDataList <Point3d>(3, FV); DA.GetData <int>(4, ref Flip); DA.GetData <double>(5, ref PullStrength); DA.GetData <int>(6, ref Iters); DA.GetData <bool>(7, ref reset); if (PullStrength == 0) { Minim = true; } if (Surf.Value is GH_Mesh) { DA.GetData <Mesh>(0, ref M); M.Faces.ConvertQuadsToTriangles(); } else { double L = 1.0; MeshingParameters MeshParams = new MeshingParameters(); MeshParams.MaximumEdgeLength = 3 * L; MeshParams.MinimumEdgeLength = L; MeshParams.JaggedSeams = false; MeshParams.SimplePlanes = false; Brep SB = null; DA.GetData <Brep>(0, ref SB); Mesh[] BrepMeshes = Mesh.CreateFromBrep(SB, MeshParams); M = new Mesh(); foreach (var mesh in BrepMeshes) { M.Append(mesh); } } if (reset || initialized == false) { #region reset M.Faces.ConvertQuadsToTriangles(); P = M.ToPlanktonMesh(); initialized = true; AnchorV.Clear(); FeatureV.Clear(); FeatureE.Clear(); //Mark any vertices or edges lying on features for (int i = 0; i < P.Vertices.Count; i++) { Point3d Pt = P.Vertices[i].ToPoint3d(); AnchorV.Add(-1); for (int j = 0; j < FV.Count; j++) { if (Pt.DistanceTo(FV[j]) < FixT) { AnchorV[AnchorV.Count - 1] = j; } } FeatureV.Add(-1); for (int j = 0; j < FC.Count; j++) { double param = new double(); FC[j].ClosestPoint(Pt, out param); if (Pt.DistanceTo(FC[j].PointAt(param)) < FixT) { FeatureV[FeatureV.Count - 1] = j; } } } // int EdgeCount = P.Halfedges.Count / 2; for (int i = 0; i < EdgeCount; i++) { FeatureE.Add(-1); //同一条线分为两条线编号分别为2i和2i+1,朝向相对,两个的起始点为 int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; Point3d PStart = P.Vertices[vStart].ToPoint3d(); Point3d PEnd = P.Vertices[vEnd].ToPoint3d(); for (int j = 0; j < FC.Count; j++) { double paramS = new double(); double paramE = new double(); Curve thisFC = FC[j]; thisFC.ClosestPoint(PStart, out paramS); thisFC.ClosestPoint(PEnd, out paramE); if ((PStart.DistanceTo(thisFC.PointAt(paramS)) < FixT) && (PEnd.DistanceTo(thisFC.PointAt(paramE)) < FixT)) { FeatureE[FeatureE.Count - 1] = j; } } } #endregion } else { for (int iter = 0; iter < Iters; iter++) { int EdgeCount = P.Halfedges.Count / 2; double[] EdgeLength = P.Halfedges.GetLengths(); List <bool> Visited = new List <bool>(); Vector3d[] Normals = new Vector3d[P.Vertices.Count]; for (int i = 0; i < P.Vertices.Count; i++) { Visited.Add(false); Normals[i] = Normal(P, i); } double t = LengthTol; //a tolerance for when to split/collapse edges double smooth = SmoothStrength; //smoothing strength double pull = PullStrength; //pull to target mesh strength // Split the edges that are too long for (int i = 0; i < EdgeCount; i++) { if (P.Halfedges[2 * i].IsUnused == false) { int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; if ((Visited[vStart] == false) && (Visited[vEnd] == false)) { double L2 = TargetLength.Calculate(P, 2 * i); if (EdgeLength[2 * i] > (1 + t) * (4f / 3f) * L2) { int SplitHEdge = P.Halfedges.TriangleSplitEdge(2 * i); if (SplitHEdge != -1) { int SplitCenter = P.Halfedges[SplitHEdge].StartVertex; P.Vertices.SetVertex(SplitCenter, MidPt(P, i)); //update the feature information FeatureE.Add(FeatureE[i]); FeatureV.Add(FeatureE[i]); AnchorV.Add(-1); //2 additional new edges have also been created (or 1 if split was on a boundary) //mark these as non-features int CEdgeCount = P.Halfedges.Count / 2; while (FeatureE.Count < CEdgeCount) { FeatureE.Add(-1); } Visited.Add(true); int[] Neighbours = P.Vertices.GetVertexNeighbours(SplitCenter); foreach (int n in Neighbours) { Visited[n] = true; } } } } } } //Collapse the edges that are too short for (int i = 0; i < EdgeCount; i++) { if (P.Halfedges[2 * i].IsUnused == false) { int vStart = P.Halfedges[2 * i].StartVertex; int vEnd = P.Halfedges[2 * i + 1].StartVertex; if ((Visited[vStart] == false) && (Visited[vEnd] == false)) { if (!(AnchorV[vStart] != -1 && AnchorV[vEnd] != -1)) // if both ends are anchored, don't collapse { int Collapse_option = 0; //0 for none, 1 for collapse to midpt, 2 for towards start, 3 for towards end //if neither are anchorV if (AnchorV[vStart] == -1 && AnchorV[vEnd] == -1) { // if both on same feature (or neither on a feature) if (FeatureV[vStart] == FeatureV[vEnd]) { Collapse_option = 1; } // if start is on a feature and end isn't if ((FeatureV[vStart] != -1) && (FeatureV[vEnd] == -1)) { Collapse_option = 2; } // if end is on a feature and start isn't if ((FeatureV[vStart] == -1) && (FeatureV[vEnd] != -1)) { Collapse_option = 3; } } else // so one end must be an anchor { // if start is an anchor if (AnchorV[vStart] != -1) { // if both are on same feature, or if the end is not a feature if ((FeatureE[i] != -1) || (FeatureV[vEnd] == -1)) { Collapse_option = 2; } } // if end is an anchor if (AnchorV[vEnd] != -1) { // if both are on same feature, or if the start is not a feature if ((FeatureE[i] != -1) || (FeatureV[vStart] == -1)) { Collapse_option = 3; } } } Point3d Mid = MidPt(P, i); double L2 = TargetLength.Calculate(P, 2 * i); if ((Collapse_option != 0) && (EdgeLength[2 * i] < (1 - t) * 4f / 5f * L2)) { int Collapsed = -1; int CollapseRtn = -1; if (Collapse_option == 1) { Collapsed = P.Halfedges[2 * i].StartVertex; P.Vertices.SetVertex(Collapsed, MidPt(P, i)); CollapseRtn = P.Halfedges.CollapseEdge(2 * i); } if (Collapse_option == 2) { Collapsed = P.Halfedges[2 * i].StartVertex; CollapseRtn = P.Halfedges.CollapseEdge(2 * i); } if (Collapse_option == 3) { Collapsed = P.Halfedges[2 * i + 1].StartVertex; CollapseRtn = P.Halfedges.CollapseEdge(2 * i + 1); } if (CollapseRtn != -1) { int[] Neighbours = P.Vertices.GetVertexNeighbours(Collapsed); foreach (int n in Neighbours) { Visited[n] = true; } } } } } } } EdgeCount = P.Halfedges.Count / 2; if ((Flip == 0) && (PullStrength > 0)) { //Flip edges to reduce valence error for (int i = 0; i < EdgeCount; i++) { if (!P.Halfedges[2 * i].IsUnused && (P.Halfedges[2 * i].AdjacentFace != -1) && (P.Halfedges[2 * i + 1].AdjacentFace != -1) && (FeatureE[i] == -1) // don't flip feature edges ) { int Vert1 = P.Halfedges[2 * i].StartVertex; int Vert2 = P.Halfedges[2 * i + 1].StartVertex; int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex; int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex; int Valence1 = P.Vertices.GetValence(Vert1); int Valence2 = P.Vertices.GetValence(Vert2); int Valence3 = P.Vertices.GetValence(Vert3); int Valence4 = P.Vertices.GetValence(Vert4); if (P.Vertices.NakedEdgeCount(Vert1) > 0) { Valence1 += 2; } if (P.Vertices.NakedEdgeCount(Vert2) > 0) { Valence2 += 2; } if (P.Vertices.NakedEdgeCount(Vert3) > 0) { Valence3 += 2; } if (P.Vertices.NakedEdgeCount(Vert4) > 0) { Valence4 += 2; } int CurrentError = Math.Abs(Valence1 - 6) + Math.Abs(Valence2 - 6) + Math.Abs(Valence3 - 6) + Math.Abs(Valence4 - 6); int FlippedError = Math.Abs(Valence1 - 7) + Math.Abs(Valence2 - 7) + Math.Abs(Valence3 - 5) + Math.Abs(Valence4 - 5); if (CurrentError > FlippedError) { P.Halfedges.FlipEdge(2 * i); } } } } else { //Flip edges based on angle for (int i = 0; i < EdgeCount; i++) { if (!P.Halfedges[2 * i].IsUnused && (P.Halfedges[2 * i].AdjacentFace != -1) && (P.Halfedges[2 * i + 1].AdjacentFace != -1) && (FeatureE[i] == -1) // don't flip feature edges ) { int Vert1 = P.Halfedges[2 * i].StartVertex; int Vert2 = P.Halfedges[2 * i + 1].StartVertex; int Vert3 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i].NextHalfedge].NextHalfedge].StartVertex; int Vert4 = P.Halfedges[P.Halfedges[P.Halfedges[2 * i + 1].NextHalfedge].NextHalfedge].StartVertex; Point3d P1 = P.Vertices[Vert1].ToPoint3d(); Point3d P2 = P.Vertices[Vert2].ToPoint3d(); Point3d P3 = P.Vertices[Vert3].ToPoint3d(); Point3d P4 = P.Vertices[Vert4].ToPoint3d(); double A1 = Vector3d.VectorAngle(new Vector3d(P3 - P1), new Vector3d(P4 - P1)) + Vector3d.VectorAngle(new Vector3d(P4 - P2), new Vector3d(P3 - P2)); double A2 = Vector3d.VectorAngle(new Vector3d(P1 - P4), new Vector3d(P2 - P4)) + Vector3d.VectorAngle(new Vector3d(P2 - P3), new Vector3d(P1 - P3)); if (A2 > A1) { P.Halfedges.FlipEdge(2 * i); } } } } if (Minim) { Vector3d[] SmoothC = LaplacianSmooth(P, 1, smooth); for (int i = 0; i < P.Vertices.Count; i++) { if (AnchorV[i] == -1) // don't smooth feature vertices { P.Vertices.MoveVertex(i, 0.5 * SmoothC[i]); } } } Vector3d[] Smooth = LaplacianSmooth(P, 0, smooth); for (int i = 0; i < P.Vertices.Count; i++) { if (AnchorV[i] == -1) // don't smooth feature vertices { // make it tangential only Vector3d VNormal = Normal(P, i); double ProjLength = Smooth[i] * VNormal; Smooth[i] = Smooth[i] - (VNormal * ProjLength); P.Vertices.MoveVertex(i, Smooth[i]); if (P.Vertices.NakedEdgeCount(i) != 0)//special smoothing for feature edges { int[] Neighbours = P.Vertices.GetVertexNeighbours(i); int ncount = 0; Point3d Avg = new Point3d(); for (int j = 0; j < Neighbours.Length; j++) { if (P.Vertices.NakedEdgeCount(Neighbours[j]) != 0) { ncount++; Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d(); } } Avg = Avg * (1.0 / ncount); Vector3d move = Avg - P.Vertices[i].ToPoint3d(); move = move * smooth; P.Vertices.MoveVertex(i, move); } if (FeatureV[i] != -1)//special smoothing for feature edges { int[] Neighbours = P.Vertices.GetVertexNeighbours(i); int ncount = 0; Point3d Avg = new Point3d(); for (int j = 0; j < Neighbours.Length; j++) { if ((FeatureV[Neighbours[j]] == FeatureV[i]) || (AnchorV[Neighbours[j]] != -1)) { ncount++; Avg = Avg + P.Vertices[Neighbours[j]].ToPoint3d(); } } Avg = Avg * (1.0 / ncount); Vector3d move = Avg - P.Vertices[i].ToPoint3d(); move = move * smooth; P.Vertices.MoveVertex(i, move); } //projecting points onto the target along their normals if (pull > 0) { Point3d Point = P.Vertices[i].ToPoint3d(); Vector3d normal = Normal(P, i); Ray3d Ray1 = new Ray3d(Point, normal); Ray3d Ray2 = new Ray3d(Point, -normal); double RayPt1 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray1); double RayPt2 = Rhino.Geometry.Intersect.Intersection.MeshRay(M, Ray2); Point3d ProjectedPt; if ((RayPt1 < RayPt2) && (RayPt1 > 0) && (RayPt1 < 1.0)) { ProjectedPt = Point * (1 - pull) + pull * Ray1.PointAt(RayPt1); } else if ((RayPt2 < RayPt1) && (RayPt2 > 0) && (RayPt2 < 1.0)) { ProjectedPt = Point * (1 - pull) + pull * Ray2.PointAt(RayPt2); } else { ProjectedPt = Point * (1 - pull) + pull * M.ClosestPoint(Point); } P.Vertices.SetVertex(i, ProjectedPt); } if (FeatureV[i] != -1) //pull feature vertices onto feature curves { Point3d Point = P.Vertices[i].ToPoint3d(); Curve CF = FC[FeatureV[i]]; double param1 = 0.0; Point3d onFeature = new Point3d(); CF.ClosestPoint(Point, out param1); onFeature = CF.PointAt(param1); P.Vertices.SetVertex(i, onFeature); } } else { P.Vertices.SetVertex(i, FV[AnchorV[i]]); //pull anchor vertices onto their points } } //end new AnchorV = CompactByVertex(P, AnchorV); //compact the fixed points along with the vertices FeatureV = CompactByVertex(P, FeatureV); FeatureE = CompactByEdge(P, FeatureE); P.Compact(); //this cleans the mesh data structure of unused elements } } DA.SetData(0, P); }