protected override Result RunCommand(RhinoDoc doc, RunMode mode) { GetObject go = new GetObject(); go.SetCommandPrompt("Select two curves for planar curve containment test"); go.GeometryFilter = ObjectType.Curve; go.GeometryAttributeFilter = GeometryAttributeFilter.ClosedCurve; go.SubObjectSelect = false; go.GetMultiple(2, 2); if (go.CommandResult() != Result.Success) { return(go.CommandResult()); } Rhino.Geometry.Curve curveA = go.Object(0).Curve(); Rhino.Geometry.Curve curveB = go.Object(1).Curve(); if (null == curveA || null == curveB) { return(Result.Failure); } Plane planeA, planeB; if (!curveA.IsPlanar() || !curveA.TryGetPlane(out planeA)) { RhinoApp.WriteLine("Curve A is not planar."); return(Result.Success); } if (!curveB.IsPlanar() || !curveB.TryGetPlane(out planeB)) { RhinoApp.WriteLine("Curve B is not planar."); return(Result.Success); } double tol = Rhino.RhinoMath.ZeroTolerance; RegionContainment rc = Curve.PlanarClosedCurveRelationship(curveA, curveB, planeA, tol); switch (rc) { case RegionContainment.Disjoint: RhinoApp.WriteLine("There is no common area between the two regions."); break; case RegionContainment.MutualIntersection: RhinoApp.WriteLine("The two curves intersect. No full containment relationship exists."); break; case RegionContainment.AInsideB: RhinoApp.WriteLine("Region bounded by curveA (first curve) is inside of curveB (second curve)."); break; case RegionContainment.BInsideA: RhinoApp.WriteLine("Region bounded by curveB (second curve) is inside of curveA (first curve)."); break; } return(Result.Success); }
/// <summary> /// Determines whether the specified curve is outside. /// </summary> /// <param name="curve">The curve.</param> /// <param name="distance">The distance.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> public override bool isOutside(Point3d point3d, Curve curve, double distance) { Curve currentToolCurve = new ArcCurve(new Circle(point3d, (X / 2) + distance)); RegionContainment result = Curve.PlanarClosedCurveRelationship(curve, currentToolCurve, Plane.WorldXY, Properties.Settings.Default.Tolerance); if (result == RegionContainment.Disjoint) { return(true); } else { return(false); } }
/// <summary> /// Determines whether the specified curve is outside. /// </summary> /// <param name="curve">The curve.</param> /// <param name="distance">The distance.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> public override bool isOutside(Point3d point3d, Curve curve, double distance) { Curve currentToolCurve = getCurve(point3d); RegionContainment result = Curve.PlanarClosedCurveRelationship(curve, currentToolCurve, Plane.WorldXY, 0); if (result == RegionContainment.Disjoint) { return(true); } else { return(false); } }
/// <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) { // input variables var wallPanel = new Mesh(); var source = new GH_Structure <GH_Mesh>(); //this is the exposed surface on the window (source of glare) var sunVector = new List <Vector3d>(); var run = new bool(); DA.GetData(0, ref wallPanel); DA.GetDataTree(1, out source); DA.GetDataList(2, sunVector); DA.GetData(3, ref run); const double tol = 0.0001; if (run == false) { return; } // output variables var GlareMesh = new GH_Structure <GH_Mesh>(); var glareAreas = new GH_Structure <GH_Number>(); var comment = new GH_Structure <GH_String>(); //debug var MshCttr = new GH_Structure <GH_Mesh>(); // Define wall outline if (!wallPanel.IsValid) { return; } var panelOutlineList = new List <Polyline>(wallPanel.GetNakedEdges()); if (panelOutlineList.Count > 1) { return; } // Define wall normal vector wallPanel.Normals.ComputeNormals(); var wNV = wallPanel.Normals[0]; wNV.Unitize(); // Area and centroid of wall panel var propWallPanel = AreaMassProperties.Compute(wallPanel); var areaWallPanel = propWallPanel.Area; var centroidWallPanel = propWallPanel.Centroid; // Define panel outline as a nurbscurve var panelOutline = new Polyline(panelOutlineList[0]).ToNurbsCurve(); if (!panelOutline.IsClosed) { panelOutline.MakeClosed(0.01); } // Define cutter for mesh var tempCutter = Surface.CreateExtrusion(panelOutline, wNV); tempCutter.Translate(Vector3d.Multiply(new Vector3d(wNV), -0.5)); var meshCutter = Mesh.CreateFromBrep(tempCutter.ToBrep(), MeshingParameters.Smooth); // Define Wall plane Plane panelPlane = new Plane(); Plane.FitPlaneToPoints(panelOutlineList[0], out panelPlane); for (int i = 0; i < source.PathCount; i++) { // Define source Path for output var areaPath = new GH_Path(i); if (source[i].Count != sunVector.Count) { return; } for (int j = 0; j < sunVector.Count; j++) { // Define projection transform var currentProjTrans = GetObliqueTransformation(panelPlane, sunVector[j]); // Define projected source mesh var currentProjSource = new Mesh(); currentProjSource.CopyFrom(source[i][j].Value); if (!currentProjSource.IsValid) { comment.Append(new GH_String("invalid currentprojsource, mesh" + i.ToString() + " sun vector" + j.ToString() + ", the window panel is inside the projected shade or about"), areaPath); GlareMesh.Append(null, areaPath); glareAreas.Append(new GH_Number(0.00), areaPath); } else { currentProjSource.Transform(currentProjTrans); // Define centroid of current projected source var currentProjOutCentroid = AreaMassProperties.Compute(currentProjSource).Centroid; var dsjtMeshCount = currentProjSource.DisjointMeshCount; // Convex hull of the mesh vertices if (!currentProjSource.IsValid) { throw new NullReferenceException( "The projected source mesh is invalid, convexHull fail, shade number: " + i.ToString() + " ,Sun vector number: " + j.ToString()); } var convexHullCurve = ConvexHullMesh(currentProjSource, panelPlane); RegionContainment status = Curve.PlanarClosedCurveRelationship(panelOutline, convexHullCurve, panelPlane, tol); switch (status) { case RegionContainment.Disjoint: comment.Append(new GH_String("Disjoint"), areaPath); GlareMesh.Append(null, areaPath); glareAreas.Append(new GH_Number(0.00), areaPath); break; case RegionContainment.MutualIntersection: var splitMesh = currentProjSource.Split(meshCutter[0]); //MshCttr.AppendRange(splitMesh.Select(p => new GH_Mesh(p)), areaPath); MshCttr.Append(new GH_Mesh(currentProjSource), areaPath); var minCentroidDistance = 9999.0; var resultMesh = new Mesh(); for (var index = 0; index < splitMesh.Length; index++) { var tempmesh = splitMesh[index]; var centroidTempMesh = AreaMassProperties.Compute(tempmesh).Centroid; var tempDistanceCentroid = (centroidWallPanel - centroidTempMesh).Length; if (!(tempDistanceCentroid < minCentroidDistance)) { continue; } minCentroidDistance = tempDistanceCentroid; resultMesh = tempmesh; if (resultMesh.DisjointMeshCount == dsjtMeshCount) { continue; } var dsjtCurrentProjSource = currentProjSource.SplitDisjointPieces(); foreach (var dsjtmesh in dsjtCurrentProjSource) { var tempHullCurve = ConvexHullMesh(dsjtmesh, panelPlane); if (Curve.PlanarClosedCurveRelationship(panelOutline, tempHullCurve, panelPlane, tol) == RegionContainment.BInsideA) { resultMesh.Append(dsjtmesh); } } } var areaResultMesh = AreaMassProperties.Compute(resultMesh).Area; comment.Append( new GH_String( "MutualIntersection, intersection of projected source and wall, tempMesh case, " + panelOutline.Contains(AreaMassProperties.Compute(resultMesh).Centroid) + " , length of splitMesh " + splitMesh.Length.ToString()), areaPath); if (panelOutline.Contains(AreaMassProperties.Compute(resultMesh).Centroid) == PointContainment.Outside) { resultMesh = null; areaResultMesh = 0; } GlareMesh.Append(new GH_Mesh(resultMesh), areaPath); glareAreas.Append(new GH_Number(areaResultMesh), areaPath); break; case RegionContainment.AInsideB: comment.Append(new GH_String("AInsideB, wall inside convexhull of projected source"), areaPath); GlareMesh.Append(new GH_Mesh(wallPanel), areaPath); glareAreas.Append(new GH_Number(areaWallPanel), areaPath); break; case RegionContainment.BInsideA: comment.Append(new GH_String("BInsideA, projected source wholly inside wall"), areaPath); GlareMesh.Append(new GH_Mesh(currentProjSource), areaPath); glareAreas.Append(new GH_Number(AreaMassProperties.Compute(currentProjSource).Area), areaPath); break; } } } } DA.SetDataTree(0, GlareMesh); DA.SetDataTree(1, glareAreas); DA.SetDataTree(2, comment); DA.SetDataTree(3, MshCttr); }
/// <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) { var c1 = new List <Curve>(); Curve c2 = new PolylineCurve(); var intPlane = new Plane(); const double tol = 0.001; var res = new List <GH_Curve>(); var Ares = new List <GH_Number>(); var comment = new List <string>(); if (!DA.GetDataList(0, c1)) { return; } if (!DA.GetData(1, ref c2)) { return; } if (!DA.GetData(2, ref intPlane)) { return; } for (int i = 0; i < c1.Count; i++) { RegionContainment status = Curve.PlanarClosedCurveRelationship(c1[i], c2, intPlane, tol); switch (status) { case RegionContainment.Disjoint: res.Add(new GH_Curve(c1[i])); Ares.Add(new GH_Number(AreaMassProperties.Compute(c1[i]).Area)); comment.Add("Disjoint, case 1"); break; case RegionContainment.MutualIntersection: var currentDifference = Curve.CreateBooleanDifference(c1[i], c2); // test needed to determine if there is one or more distinct resulting curves if (currentDifference.Length == 0) { var areaInter = AreaMassProperties.Compute(Curve.CreateBooleanIntersection(c1[i], c2)).Area; if (areaInter < tol * AreaMassProperties.Compute(c1[i]).Area) { res.Add(new GH_Curve(c1[i])); Ares.Add(new GH_Number(AreaMassProperties.Compute(c1[i]).Area)); comment.Add("MutualIntersection, line/point intersection, case 2a_a"); } else { res.Add(new GH_Curve(c2)); res.Add(new GH_Curve(c1[i])); Ares.Add(new GH_Number(AreaMassProperties.Compute(c1[i]).Area - AreaMassProperties.Compute(c2).Area)); comment.Add("MutualIntersection, line/point intersection, case 2a_b"); } } else if (currentDifference.Length == 1) { res.Add(new GH_Curve(currentDifference[0])); Ares.Add(new GH_Number(AreaMassProperties.Compute(currentDifference[0]).Area)); comment.Add("MutualIntersection, 1 resulting closed curve, case 2b"); } else { for (int j = 0; j < currentDifference.Length; j++) { res.Add(new GH_Curve(currentDifference[j])); } Ares.Add(new GH_Number(AreaMassProperties.Compute(currentDifference).Area)); comment.Add("MutualIntersection, " + currentDifference.Length.ToString() + " resulting closed curves, case 2c"); } break; case RegionContainment.AInsideB: if (c1[i].IsClosed) { res.Add(new GH_Curve(c1[i])); Ares.Add(new GH_Number(AreaMassProperties.Compute(c1[i]).Area)); comment.Add("A Inside B, resulting curve is closed, case 3a"); } else { res.Add(new GH_Curve(c1[i])); Ares.Add(null); comment.Add("A Inside B, resulting curve is NOT closed, case 3b"); } break; case RegionContainment.BInsideA: res.Add(new GH_Curve(c2)); res.Add(new GH_Curve(c1[i])); Ares.Add(new GH_Number(AreaMassProperties.Compute(c1[i]).Area - AreaMassProperties.Compute(c2).Area)); comment.Add("B Inside A, resulting curve is closed, case 4"); break; } } DA.SetDataList(0, res); DA.SetDataList(1, Ares); DA.SetDataList(2, comment); }
/// <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) { var curveA = new List <Curve>(); Curve curveB = new PolylineCurve(); var Int_plane = new Plane(); double tol = 0.001; var res = new List <GH_Curve>(); var Ares = new List <GH_Number>(); var comment = new List <string>(); if (!DA.GetDataList(0, curveA)) { return; } if (!DA.GetData(1, ref curveB)) { return; } if (!DA.GetData(2, ref Int_plane)) { return; } // check if curveB is null if (curveB == null) { res.Add(null); Ares.Add(new GH_Number(0.00)); comment.Add("Null curveB"); } for (int i = 0; i < curveA.Count; i++) { if (curveA[i] == null) { res.Add(null); Ares.Add(new GH_Number(0.00)); comment.Add("Null curveA"); } else { RegionContainment status = Curve.PlanarClosedCurveRelationship(curveA[i], curveB, Int_plane, tol); switch (status) { case RegionContainment.Disjoint: res.Add(null); Ares.Add(new GH_Number(0.0)); comment.Add("Disjoint"); break; case RegionContainment.MutualIntersection: var current_intersection = Curve.CreateBooleanIntersection(curveA[i], curveB); // test needed to determine if there is one or more distinct resulting curves if (current_intersection.Length == 0) { res.Add(null); Ares.Add(new GH_Number(0.0)); comment.Add("MutualIntersection, line intersection"); } else if (current_intersection.Length == 1) { res.Add(new GH_Curve(current_intersection[0])); Ares.Add(new GH_Number(AreaMassProperties.Compute(current_intersection[0]).Area)); comment.Add("MutualIntersection, 1 resulting closed curve"); } else { for (int j = 0; j < current_intersection.Length; j++) { res.Add(new GH_Curve(current_intersection[j])); } Ares.Add(new GH_Number(AreaMassProperties.Compute(current_intersection).Area)); comment.Add("MutualIntersection, " + current_intersection.Length.ToString() + " resulting closed curves"); } break; case RegionContainment.AInsideB: if (curveA[i].IsClosed) { res.Add(new GH_Curve(curveA[i])); Ares.Add(new GH_Number(AreaMassProperties.Compute(curveA[i]).Area)); comment.Add("A Inside B, resulting curve is closed"); } else { res.Add(new GH_Curve(curveA[i])); Ares.Add(null); comment.Add("A Inside B, resulting curve is NOT closed"); } break; case RegionContainment.BInsideA: res.Add(new GH_Curve(curveB)); Ares.Add(new GH_Number(AreaMassProperties.Compute(curveB).Area)); comment.Add("B Inside A, resulting curve is closed"); break; } } } DA.SetDataList(0, res); DA.SetDataList(1, Ares); DA.SetDataList(2, comment); }
public Curve DrawRamp(Plot plot, Vector3d lineAxis, List <Curve> obstacles) { //규모 판별 - 50 이상? 미만? 너비 3.3 or 6.5 , 내반경 5 or 6 //innerboundary 기준 x (도로판별이힘듦)plot boundary 기준으로, '도로'에 '수직? 이어야 하나?' 인 '27m' 이상 길이 확보 가능? -> 직선 램프 //불가능 -> 곡선램프 -> 시작 선, 도로 선, 장애물 RampScale scale = RampScale.Under50; if (require > 50) { scale = RampScale.Over50; } //도로. Curve[] boundaries = plot.Boundary.DuplicateSegments(); List <Curve> roads = new List <Curve>(); for (int i = 0; i < boundaries.Length; i++) { if (plot.Surroundings[i] != 0) { roads.Add(boundaries[i]); } } for (int i = 0; i < roads.Count; i++) { for (int j = 0; j < 2; j++) { for (int l = 0; l < 100; l++) { double offsetTick = 100;//roads[i].GetLength() / 10; if (l * offsetTick > roads[i].GetLength()) { break; } Curve tempRamp = DrawLineRamp(roads[i], lineAxis, j, scale, l * offsetTick); if (tempRamp == null) { continue; } bool collCheck = CollisionCheck(tempRamp, obstacles); RegionContainment isInside = Curve.PlanarClosedCurveRelationship(tempRamp, innerBoundary, Plane.WorldXY, 0); if (collCheck && isInside == RegionContainment.AInsideB) { return(tempRamp); } } } } //for curvedramp for (int i = 0; i < roads.Count; i++) { for (int j = 0; j < 2; j++) { for (int k = 0; k < 10; k++) { for (int l = 0; l < 100; l++) { double offsetTick = 100;//roads[i].GetLength() / 10; if (l * offsetTick > roads[i].GetLength()) { break; } double beforeRamp = 10000 - k * 1000; Curve tempRamp = DrawCurvedRamp(roads[i], lineAxis, j, scale, beforeRamp, l * offsetTick); if (tempRamp == null) { continue; } bool collCheck = CollisionCheck(tempRamp, obstacles); RegionContainment isInside = Curve.PlanarClosedCurveRelationship(tempRamp, innerBoundary, Plane.WorldXY, 0); if (collCheck && isInside == RegionContainment.AInsideB) { return(tempRamp); } } } } } //cant make ramp return(null); }
/// <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) { // input variables var windowPanel = new Mesh(); var shadeModule = new List <Mesh>(); var sunVector = new List <Vector3d>(); var run = new bool(); da.GetData(0, ref windowPanel); da.GetDataList(1, shadeModule); da.GetDataList(2, sunVector); da.GetData(3, ref run); const double tol = 1e-8; if (run == false) { return; } // output variables var result = new GH_Structure <GH_Mesh>(); var areaResult = new GH_Structure <GH_Number>(); var comment = new GH_Structure <GH_String>(); // Define window outline as a nurbscurve if (!windowPanel.IsValid) { return; } var panelOutlineList = new List <Polyline>(windowPanel.GetNakedEdges()); if (panelOutlineList.Count > 1) { return; } var panelOutline = new Polyline(panelOutlineList[0]).ToNurbsCurve(); // Define window panel plane var windowPlane = new Plane(); Plane.FitPlaneToPoints(panelOutlineList[0], out windowPlane); // Surface area and centroid of window panel var propWindowPanel = AreaMassProperties.Compute(panelOutline); var windowArea = propWindowPanel.Area; var centroidWindowPanel = propWindowPanel.Centroid; // Define normal of window panel windowPanel.Normals.ComputeNormals(); var wNV = windowPanel.Normals[0]; wNV.Unitize(); //// Debug var var MshCttr = new GH_Structure <GH_Mesh>(); var hullCrv = new GH_Structure <GH_Curve>(); for (int i = 0; i < shadeModule.Count; i++) { // Define Shade path for output var p1 = new GH_Path(i); for (int j = 0; j < sunVector.Count; j++) { // Create projection transform of shade to panel plane along the sun vector direction var projectToWindowPanel = new Transform(); projectToWindowPanel = GetObliqueTransformation(windowPlane, sunVector[j]); // Project shade outline to panel plane along the sun vector direction var currentShadeProj = new Mesh(); currentShadeProj.CopyFrom(shadeModule[i]); currentShadeProj.Transform(projectToWindowPanel); // Create currentShadeProj Outline var currentShadeProjOutline = currentShadeProj.GetNakedEdges(); // Define cutter for mesh var tempCutter = new List <Surface>(); foreach (Polyline t in currentShadeProjOutline) { tempCutter.Add(Surface.CreateExtrusion(t.ToNurbsCurve(), Vector3d.Multiply(new Vector3d(wNV), 1.0))); } foreach (var mshcuttemp in tempCutter) { mshcuttemp.Translate(Vector3d.Multiply(new Vector3d(wNV), -0.5)); } var tempCutterBrep = tempCutter.Select(p => p.ToBrep()); var meshCutterLst = new List <Mesh>(); for (int k = 0; k < tempCutterBrep.ToList().Count; k++) { meshCutterLst.AddRange(Mesh.CreateFromBrep(tempCutterBrep.ToList()[k], MeshingParameters.Coarse)); } var meshCutter = meshCutterLst.ToArray(); MshCttr.AppendRange(meshCutter.Select(p => new GH_Mesh(p)), p1); // Convex hull of the projected mesh's vertices var convexHullCurve = ConvexHullMesh(currentShadeProj, windowPlane); hullCrv.Append(new GH_Curve(convexHullCurve), p1); // Determine the difference of the panel outline - the shade outline RegionContainment status = Curve.PlanarClosedCurveRelationship(panelOutline, convexHullCurve, windowPlane, tol); switch (status) { case RegionContainment.Disjoint: result.Append(new GH_Mesh(windowPanel), p1); areaResult.Append(new GH_Number(windowArea), p1); comment.Append(new GH_String("Disjoint, case 1"), p1); break; case RegionContainment.MutualIntersection: var splitMeshC2 = windowPanel.Split(meshCutter); var tempResult = new Mesh[splitMeshC2.Length]; splitMeshC2.CopyTo(tempResult, 0); var nakedEdgeCount = tempResult.Select(p => p.GetNakedEdges().Length); //var sumNkdEdge = nakedEdgeCount.Sum(); if (nakedEdgeCount.Sum() > tempResult.Length) { // Pick the mesh with the most naked edges int max = -99; var selectmesh = new Mesh(); for (int k = 0; k < tempResult.Length; k++) { if (nakedEdgeCount.ToList()[k] <= max) { continue; } max = nakedEdgeCount.ToList()[k]; selectmesh = tempResult[k]; } //if (!selectmesh.IsValid) //{ // throw new NullReferenceException("The projected mesh is invalid, case MutualIntersection, shade number: "+i.ToString()+" ,Sun vector number: "+j.ToString()); //} result.Append(new GH_Mesh(selectmesh), p1); areaResult.Append(new GH_Number(AreaMassProperties.Compute(selectmesh).Area), p1); comment.Append(new GH_String("MutualIntersection, intersection of projected source and wall, multi-module"), p1); } else if (nakedEdgeCount.Sum() == tempResult.Length) { var cutterCentroid = AreaMassProperties.Compute(meshCutter).Centroid; var max = -9999.99; var selectmesh = new Mesh(); foreach (Mesh t in tempResult) { var currentCentroidSplitmesh = AreaMassProperties.Compute(t).Centroid; var currentDistanceCentroids = (cutterCentroid - currentCentroidSplitmesh).Length; if (!(currentDistanceCentroids > max)) { continue; } max = currentDistanceCentroids; selectmesh = t; } var test = selectmesh.IsValid; //if (!selectmesh.IsValid) //{ // throw new NullReferenceException( // "The projected mesh is invalid, case MutualIntersection, shade number: " + // i.ToString() + " ,Sun vector number: " + j.ToString()); //} result.Append(new GH_Mesh(selectmesh), p1); areaResult.Append(new GH_Number(AreaMassProperties.Compute(selectmesh).Area), p1); comment.Append(new GH_String("MutualIntersection, intersection of projected source and wall, single module"), p1); } break; case RegionContainment.AInsideB: result.Append(new GH_Mesh(new Mesh()), p1); areaResult.Append(new GH_Number(0.00), p1); comment.Append(new GH_String("A Inside B, the window is inside the convex hull of the projected shade module, case 3a"), p1); break; case RegionContainment.BInsideA: var splitMeshC4 = windowPanel.Split(meshCutter);; var finalRes = new Mesh(); foreach (var msh in splitMeshC4) { foreach (var edge in msh.GetNakedEdges()) { //if (Curve.PlanarClosedCurveRelationship(edge.ToNurbsCurve(), panelOutline, windowPlane, tol)== RegionContainment.MutualIntersection) { finalRes = msh; } if (Rhino.Geometry.Intersect.Intersection.CurveCurve(edge.ToNurbsCurve(), panelOutline, tol, 0.0) != null) { finalRes = msh; } } } result.Append(new GH_Mesh(finalRes), p1); areaResult.Append(new GH_Number(AreaMassProperties.Compute(finalRes).Area), p1); comment.Append(new GH_String("B Inside A, the shade module projection is inside the window, case 4, sun vector ID: " + j.ToString() + " sun vector: " + sunVector[j].ToString() + "transformation: " + projectToWindowPanel.ToString()), p1); break; } } } da.SetDataTree(0, result); da.SetDataTree(1, areaResult); da.SetDataTree(2, comment); da.SetDataTree(3, MshCttr); da.SetDataTree(4, hullCrv); }