// iterate through the grid in the x directions /// <summary> /// Iterate through the grid and add voxels that are inside the Brep /// </summary> /// <param name="brepVolume"></param> /// <param name="vg"></param> public void AddSolidBrep(Brep brepVolume, ref VoxelGrid3D vg) { // get the axis direction for each point var pt1 = vg.EvaluatePoint(new Point3i(0, 0, 0)); var pt2 = vg.EvaluatePoint(new Point3i(1, 0, 0)); var pln = new Plane(pt1, (pt2 - pt1)); for (var x = 0; x < vg.SizeUVW.X; x++) { pln.Origin = vg.EvaluatePoint(new Point3i(x, 0, 0)); Intersection.BrepPlane(brepVolume, pln, DocumentHelper.GetModelTolerance(), out var sections, out var pts); var surfaces = Brep.CreatePlanarBreps(sections); // perhaps check first if the points are inside the bounding box of the surface. if (surfaces == null) { continue; } for (var y = 0; y < vg.SizeUVW.Y; y++) { for (var z = 0; z < vg.SizeUVW.Z; z++) { var pt = vg.EvaluatePoint(new Point3i(x, y, z)); var hasPixel = surfaces.Any(t => t.ClosestPoint(pt).DistanceTo(pt) < DocumentHelper.GetModelTolerance()); if (hasPixel) { vg.SetValue(new Point3i(x, y, z), true); } } } } }
/// <summary> /// Add point to the grid. /// </summary> /// <param name="pt">Point in world space</param> /// <param name="vg">Voxelgrid</param> public void AddPt(Point3d pt, ref VoxelGrid3D vg) { if (Distance < RhinoMath.ZeroTolerance) { var pti = vg.ClosestPoint(pt); if (pti >= Point3i.Origin && pti <= vg.SizeUVW) { vg.SetValue(pti, true); } } else { var bb = new BoundingBox(new [] { pt }); bb.Inflate(Distance * 1.1); foreach (var subPt in vg.PointsInBox(bb)) { if (vg.PointInGrid(subPt) && !vg[subPt] && vg.EvaluatePoint(subPt).DistanceTo(pt) < Distance) { vg[subPt] = true; } } } }
/// <summary> /// Create a mesh quad from a voxelgrid /// </summary> /// <param name="vg">VoxelGrid</param> /// <param name="i">The voxel number in the grid</param> /// <param name="faceId">The id of the face (faces are defined in FaceDirections)</param> /// <param name="m">The mesh to add the face to</param> /// <param name="FaceDirections">(Predefined) List of directions for each face</param> /// <param name="AxisDirections">(Predefined) List of directions of Axis (x,y,z)</param> /// <param name="FaceAxis">(Predefined) Define which axis lies on which plane</param> public static void AddFacadeToMesh(VoxelGrid3D vg, int i, int faceId, ref Mesh m, Vector3d[] FaceDirections, Vector3d[] AxisDirections, int[,] FaceAxis) { // 0 for x, 1 for y, 2 for z int iDir = Convert.ToInt16(Math.Floor((double)faceId / 2)); // get the position and the location var position = vg.EvaluatePoint(i); // to determine the correct position of the plane // we have to aim the x or y direction var distance = FaceDirections[faceId] * (vg.VoxelSize[iDir] * 0.5); position.Transform(Transform.Translation(distance)); var pln = new Plane(position, AxisDirections[FaceAxis[iDir, 0]], AxisDirections[FaceAxis[iDir, 1]]); //planes.Add(pln); var sizeU = vg.VoxelSize[FaceAxis[iDir, 0]] / 2; var sizeV = vg.VoxelSize[FaceAxis[iDir, 1]] / 2; var pts = new Point3d[] { new Point3d(-sizeU, -sizeV, 0), new Point3d(-sizeU, sizeV, 0), new Point3d(sizeU, sizeV, 0), new Point3d(sizeU, -sizeV, 0) }; var p3fs = new List <Point3f>(); foreach (var ptd in pts) { var worldpt = pln.PointAt(ptd.X, ptd.Y, ptd.Z); p3fs.Add(new Point3f((float)worldpt.X, (float)worldpt.Y, (float)worldpt.Z)); } // try to use unique vertices var cCount = m.Vertices.Count; m.Vertices.AddVertices(p3fs); var iFaceIndex = m.Faces.Count; var facenormal = Vector3d.CrossProduct(p3fs[1] - p3fs[0], p3fs[2] - p3fs[0]); if (Vector3d.VectorAngle(facenormal, FaceDirections[faceId]) > Math.PI / 2) { m.Faces.AddFace(cCount + 3, cCount + 2, cCount + 1, cCount); } else { m.Faces.AddFace(cCount, cCount + 1, cCount + 2, cCount + 3); } m.FaceNormals.SetFaceNormal(iFaceIndex, FaceDirections[faceId]); }
/// <summary> /// Converts a voxelgrid to a mesh hull. /// TODO: Add hashmap vertex id > pixel/pixelface; to compute the pixel to which the mesh belongs. /// </summary> /// <param name="vg"></param> /// <returns></returns> public static Mesh VoxelGridToMesh(VoxelGrid3D vg) { Vector3d[] FaceDirections; Vector3d[] AxisDirections; Point3i[] RelativePosition; int[,] FaceAxis; double[] FaceSizes; FaceDirections = new Vector3d[6] { vg.BBox.Plane.XAxis, -vg.BBox.Plane.XAxis, vg.BBox.Plane.YAxis, -vg.BBox.Plane.YAxis, vg.BBox.Plane.ZAxis, -vg.BBox.Plane.ZAxis }; AxisDirections = new Vector3d[3] { vg.BBox.Plane.XAxis, vg.BBox.Plane.YAxis, vg.BBox.Plane.ZAxis }; // the different faces RelativePosition = new Point3i[6] { new Point3i(1, 0, 0), new Point3i(-1, 0, 0), new Point3i(0, 1, 0), new Point3i(0, -1, 0), new Point3i(0, 0, 1), new Point3i(0, 0, -1) }; FaceAxis = new int[3, 2] { { 1, 2 }, { 2, 0 }, { 0, 1 } }; // the sizes of the faces FaceSizes = new double[3] { vg.SizeUVW.X, vg.SizeUVW.Y, vg.SizeUVW.Z }; var m = new Mesh(); for (var i = 0; i < vg.Count; i++) { if (vg[i] == false) { continue; } for (var faceId = 0; faceId < 6; faceId++) { if (vg.GetRelativePointValue(i, RelativePosition[faceId]) != 1) { AddFacadeToMesh(vg, i, faceId, ref m, FaceDirections, AxisDirections, FaceAxis); } } } //m.Vertices.CombineIdentical(false, true); m.Normals.ComputeNormals(); m.Compact(); return(m); }
private void AddBox(Box oBox, ref VoxelGrid3D vg) { var newBox = oBox.BoundingBox; for (var i = 0; i < vg.Count; i++) { var pt = vg.EvaluatePoint(i); if (newBox.Contains(pt, false)) { vg[i] = true; } } }
/// <summary> /// Add a line in world coordinates to a voxelgrid /// </summary> /// <param name="line"></param> /// <param name="vg"></param> private void AddLine(Line line, ref VoxelGrid3D vg) { var start = vg.ClosestPoint(line.From); var end = vg.ClosestPoint(line.To); foreach (var pt in InterateLine(start, end)) { if (pt < Point3i.Origin || pt >= vg.SizeUVW) { continue; } vg[pt] = true; } }
/// <summary> /// Adds the mesh. /// </summary> /// <param name="m">The m.</param> /// <param name="vg">The vg.</param> private void AddMesh(Mesh m, ref VoxelGrid3D vg) { if (Distance < RhinoMath.ZeroTolerance) { // add closed mesh var bb = m.GetBoundingBox(true); var length = bb.Diagonal.Length * 1.1; for (var i = 0; i < vg.Count; i++) { var pt = vg.EvaluatePoint(i); var isInside = false; if (bb.Contains(pt)) { Intersection.MeshLine(m, new Line(pt, Vector3d.XAxis, length), out var faces); if (faces != null) { isInside = faces.Length % 2 == 1; } } if (isInside) { vg.SetValue(i, true); } } } else { // add open mesh var bb = m.GetBoundingBox(true); bb.Inflate(Distance * 0.6); for (var i = 0; i < vg.Count; i++) { var isInside = false; var pt = vg.EvaluatePoint(i); if (bb.Contains(pt)) { var foundPoint = m.ClosestPoint(pt); if (foundPoint.DistanceTo(pt) <= Distance) { isInside = true; } } if (isInside) { vg[i] = true; } } } }
/// <summary> /// Add a brep to the voxelgrid /// </summary> /// <param name="b"></param> /// <param name="vg"></param> public void AddBrep(Brep b, ref VoxelGrid3D vg) { if (b == null || b.Equals(default(Brep)) || !b.IsValid) { return; } if (!b.IsSolid || Distance > RhinoMath.ZeroTolerance) { AddOpenBrep(b, ref vg); } else { AddSolidBrep(b, ref vg); } }
/// <summary> /// Convert a voxelgrid to a bytearray /// </summary> /// <param name="vg"></param> /// <returns></returns> public static byte[] ToByte(VoxelGrid3D vg) { // check for integer overflows checked { var byteGrid = ToByte(vg.Grid); var byteLength = 120 + 24 + 4 + byteGrid.Length; var output = new byte[byteLength]; // voxelsize can be float = 9 bytes ToByte(vg.VoxelSize).CopyTo(output, 0); // bbox can be ptA, ptB + plane equation. 3x3x2 = 18 // plane equation = normalize plane. Take a plane and take the origin out of the equation // plane equation - ToByte(vg.BBox).CopyTo(output, 24); ToByte(vg.Grid).CopyTo(output, 144); return(output); } }
/// <summary> /// Adds the mesh. /// </summary> /// <param name="m">The m.</param> /// <param name="vg">The vg.</param> private void AddMeshNew(Mesh m, ref VoxelGrid3D vg) { if (Distance < RhinoMath.ZeroTolerance) { // test in 3 directions. var vgX = vg.CloneEmpty(); var vgY = vg.CloneEmpty(); var vgZ = vg.CloneEmpty(); VoxelateMeshInDirection(m, 0, ref vgX); VoxelateMeshInDirection(m, 1, ref vgY); VoxelateMeshInDirection(m, 2, ref vgZ); vgX.And(vgY); vgX.And(vgZ); vg.Or(vgX); } else { // add open mesh var bb = m.GetBoundingBox(true); bb.Inflate(Distance * 0.6); for (var i = 0; i < vg.Count; i++) { var isInside = false; var pt = vg.EvaluatePoint(i); if (bb.Contains(pt)) { var foundPoint = m.ClosestPoint(pt); if (foundPoint.DistanceTo(pt) <= Distance) { isInside = true; } } if (isInside) { vg[i] = true; } } } }
/// <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 bb = new Box(); double x, y, z; x = y = z = 0; DA.GetData(1, ref x); DA.GetData(2, ref y); DA.GetData(3, ref z); DA.GetData(0, ref bb); var vg = new VoxelGrid3D(bb, new Point3d(x, y, z)); if (!vg.IsValid) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Result was an invalid grid"); } DA.SetData(0, (VoxelGrid3D)vg.Clone()); AddRenderGrid(vg); }
/// <summary> /// Add a non closed brep by using a distance to the grid /// </summary> /// <param name="b"></param> /// <param name="vg"></param> public void AddOpenBrep(Brep b, ref VoxelGrid3D vg) { var bb = b.GetBoundingBox(false); bb.Inflate(Distance * 0.6); for (var i = 0; i < vg.Grid.Count; i++) { var pt = vg.EvaluatePoint(i); if (!bb.Contains(pt)) { continue; } var cp = b.ClosestPoint(pt); AddPt(cp, ref vg); if (pt.DistanceTo(cp) < Distance) { AddPt(pt, ref vg); } } }
/// <summary> /// Add curve that intersects with voxels to the grid /// TODO: /// Improve by dividing the curve? /// Getting more intervals? /// Getting custom distance on the curve? /// </summary> /// <param name="curve"></param> /// <param name="vg"></param> public void AddCrv(Curve curve, ref VoxelGrid3D vg) { // todo: explode curves, and only search in radius of box? if (Distance > RhinoMath.ZeroTolerance) { var bb = curve.GetBoundingBox(true); bb.Inflate((vg.VoxelSize.X + Distance) * 2, (vg.VoxelSize.Y + Distance) * 2, (vg.VoxelSize.Z + Distance) * 2); var maxDistance = Math.Sqrt(Math.Pow(vg.VoxelSize.X, 2) + Math.Pow(vg.VoxelSize.Y, 2) + Math.Pow(vg.VoxelSize.Z, 2)); for (var i = 0; i < vg.Count; i++) { var pt = vg.EvaluatePoint(i); if (bb.Contains(pt)) { curve.ClosestPoint(pt, out var t); var cp = curve.PointAt(t); var dist = cp.DistanceTo(pt); if (Math.Abs(Distance) < RhinoMath.ZeroTolerance && dist <= maxDistance) { AddPt(cp, ref vg); } else if (dist < Distance) { vg[i] = true; } } } } else { var plc = curve.ToPolyline(0, 0, 0.1, 0, 0.5, RhinoDoc.ActiveDoc.ModelAbsoluteTolerance, 0, vg.VoxelSize.MinimumCoordinate, true); plc.TryGetPolyline(out var pl); foreach (var item in pl.GetSegments()) { AddLine(item, ref vg); } } }
private static void LimitGrid(ref VoxelGrid3D vg, int i) { // limit, start with Z size. var trueCount = vg.CountNonZero; for (var z = vg.SizeUVW.Z - 1; z >= 0; z--) { for (var y = 0; y < vg.SizeUVW.Y; y++) { for (var x = 0; x < vg.SizeUVW.X; x++) { if (vg[new Point3i(x, y, z)]) { vg[new Point3i(x, y, z)] = false; trueCount--; } if (trueCount == i) { return; } } } } }
/// <summary> /// Add voxels to the grid building up from the bottom to the top. /// </summary> /// <param name="vg">VoxelGrid</param> /// <param name="count">Amount of voxels to be added.</param> private void IncreaseGridFromBottom(ref VoxelGrid3D vg, int count) { var trueIncCount = vg.CountNonZero; for (var z = 0; z < vg.SizeUVW.Z; z++) { for (var y = 0; y < vg.SizeUVW.Y; y++) { for (var x = 0; x < vg.SizeUVW.X; x++) { var pt = new Point3i(x, y, z); if (vg[pt] == false) { vg[pt] = true; trueIncCount++; if (trueIncCount == count) { return; } } } } } }
/// <summary> /// Add a grid to the render queue /// </summary> /// <param name="grid">The grid.</param> public void AddRenderGrid(VoxelGrid3D grid) { RenderGrid.Add(grid); RenderBb.Union(grid.BBox.BoundingBox); GenerateBoxGrid(grid); }
/// <summary> /// Gets the voxelgrid mesh by plane /// Return a seperate list for each face direction /// </summary> /// <param name="vg"></param> /// <returns></returns> public static List <Mesh> VoxelGridToMeshByPlanes(VoxelGrid3D vg) { Vector3d[] FaceDirections; Vector3d[] AxisDirections; Point3i[] RelativePosition; int[,] FaceAxis; double[] FaceSizes; var Meshes = new List <Mesh>(); for (var i = 0; i < 6; i++) { Meshes.Add(new Mesh()); } FaceDirections = new Vector3d[6] { vg.BBox.Plane.XAxis, -vg.BBox.Plane.XAxis, vg.BBox.Plane.YAxis, -vg.BBox.Plane.YAxis, vg.BBox.Plane.ZAxis, -vg.BBox.Plane.ZAxis }; AxisDirections = new Vector3d[3] { vg.BBox.Plane.XAxis, vg.BBox.Plane.YAxis, vg.BBox.Plane.ZAxis }; // the different faces RelativePosition = new Point3i[6] { new Point3i(1, 0, 0), new Point3i(-1, 0, 0), new Point3i(0, 1, 0), new Point3i(0, -1, 0), new Point3i(0, 0, 1), new Point3i(0, 0, -1) }; FaceAxis = new int[3, 2] { { 1, 2 }, { 2, 0 }, { 0, 1 } }; // the sizes of the faces FaceSizes = new double[3] { vg.SizeUVW.X, vg.SizeUVW.Y, vg.SizeUVW.Z }; for (var i = 0; i < vg.Count; i++) { if (vg[i] == false) { continue; } for (var faceId = 0; faceId < 6; faceId++) { var m = Meshes[faceId]; if (vg.GetRelativePointValue(i, RelativePosition[faceId]) != 1) { try { AddFacadeToMesh(vg, i, faceId, ref m, FaceDirections, AxisDirections, FaceAxis); } catch (Exception e) { throw new Exception( $"Adding Facade {faceId} of Voxel {i} to Mesh failed: {e.ToString()}"); } } } } //m.Vertices.CombineIdentical(false, true); for (var i = 0; i < 6; i++) { Meshes[i].Normals.ComputeNormals(); Meshes[i].Compact(); } return(Meshes); }
private void VoxelateMeshInDirection(Mesh m, int dir, ref VoxelGrid3D vg) { var box = new Box(vg.Plane, vg.BBox.ToBrep()); box.Inflate(box.X.Length * 0.1, box.Y.Length * 0.1, box.Z.Length * 0.1); Plane min; Plane max; int dirA; int dirB; switch (dir) { case 0: { dirA = 1; dirB = 2; min = new Plane(box.PointAt(0, 0, 0), vg.Plane.XAxis); max = new Plane(box.PointAt(1, 0, 0), vg.Plane.XAxis); break; } case 1: { dirA = 0; dirB = 2; min = new Plane(box.PointAt(0, 0, 0), vg.Plane.YAxis); max = new Plane(box.PointAt(0, 1, 0), vg.Plane.YAxis); break; } case 2: { dirA = 0; dirB = 1; min = new Plane(box.PointAt(0, 0, 0), vg.Plane.ZAxis); max = new Plane(box.PointAt(0, 0, 1), vg.Plane.ZAxis); break; } default: throw new Exception("Invalid direction"); } for (var a = 0; a < vg.SizeUVW[dirA]; a++) { for (var b = 0; b < vg.SizeUVW[dirB]; b++) { var idx = new Point3i { [dirA] = a, [dirB] = b }; var pt = vg.EvaluatePoint(idx); var ptMin = min.ClosestPoint(pt); var ptMax = max.ClosestPoint(pt); var line = new Line(ptMin, ptMax); var pts = Intersection.MeshLine(m, new Line(ptMin, ptMax), out _); // sort by line direction, the points should be in the same order as the line. pts = pts.OrderBy(intPt => line.ClosestParameter(intPt)).ToArray(); for (var i = 0; i < pts.Length - 1; i += 2) { AddLine(new Line(pts[i], pts[i + 1]), ref vg); } } } }
private void IncreaseGrid(ref VoxelGrid3D vg, int count) { var trueCount = vg.CountNonZero; var possibleLocations = new List <int>(); var foundRoof = false; for (var z = vg.SizeUVW.Z - 1; z >= 0; z--) { if (foundRoof) { break; } for (var y = 0; y < vg.SizeUVW.Y; y++) { for (var x = 0; x < vg.SizeUVW.X; x++) { var pt = new Point3i(x, y, z); if (vg[pt] != true) { continue; } foundRoof = true; possibleLocations.Add(Point3i.PointUvwToIndex(vg.SizeUVW, pt)); } } } // location division // goal-current // difference: the first x voxels get extra. // then add x voxels to each location. var difference = count - trueCount; var height = Convert.ToInt32(Math.Floor((double)difference / possibleLocations.Count)); var rest = difference % possibleLocations.Count; for (var i = 0; i < possibleLocations.Count; i++) { var makeheight = height; if (rest > 0) { makeheight += 1; rest--; } for (var j = 1; j <= makeheight; j++) { var pt = new Point3i(0, 0, j); var position = Point3i.IndexToPointUvw(vg.SizeUVW, possibleLocations[i]) + pt; vg[position] = true; } } if (vg.CountNonZero != count) { // the grid is empty / reaches to the roof. // add from the bottom. IncreaseGridFromBottom(ref vg, count); } }
/// <summary> /// Polygonize grid using the marching cubes algorithm /// </summary> /// <param name="vg">Voxelgrid</param> /// <param name="points">List of points in the voxelgrid</param> /// <param name="val">Values (0 or 1 list)</param> /// <param name="isolevel">Isolevel at value val (between 0 and 1)</param> /// <param name="m">Mesh to add faces to</param> /// <param name="cubeindex">Unknown parameter at this point, why was this an out value again?</param> /// <returns>The amount of trianges added to the mesh</returns> public int Polygonise(VoxelGrid3D vg, Point3i[] points, float[] val, float isolevel, ref Mesh m, out int cubeindex) { cubeindex = 0; if (val[0] < isolevel) { cubeindex |= 1; } if (val[1] < isolevel) { cubeindex |= 2; } if (val[2] < isolevel) { cubeindex |= 4; } if (val[3] < isolevel) { cubeindex |= 8; } if (val[4] < isolevel) { cubeindex |= 16; } if (val[5] < isolevel) { cubeindex |= 32; } if (val[6] < isolevel) { cubeindex |= 64; } if (val[7] < isolevel) { cubeindex |= 128; } /* Cube is entirely in/out of the surface */ if (_edgeTable[cubeindex] == 0) { return(0); } var vertlist = new Point3d[12]; /* Find the vertices where the surface intersects the cube */ if ((_edgeTable[cubeindex] & 1) == 1) { vertlist[0] = VertexInterp(isolevel, points[0], points[1], val[0], val[1]); } if ((_edgeTable[cubeindex] & 2) == 2) { vertlist[1] = VertexInterp(isolevel, points[1], points[2], val[1], val[2]); } if ((_edgeTable[cubeindex] & 4) == 4) { vertlist[2] = VertexInterp(isolevel, points[2], points[3], val[2], val[3]); } if ((_edgeTable[cubeindex] & 8) == 8) { vertlist[3] = VertexInterp(isolevel, points[3], points[0], val[3], val[0]); } if ((_edgeTable[cubeindex] & 16) == 16) { vertlist[4] = VertexInterp(isolevel, points[4], points[5], val[4], val[5]); } if ((_edgeTable[cubeindex] & 32) == 32) { vertlist[5] = VertexInterp(isolevel, points[5], points[6], val[5], val[6]); } if ((_edgeTable[cubeindex] & 64) == 64) { vertlist[6] = VertexInterp(isolevel, points[6], points[7], val[6], val[7]); } if ((_edgeTable[cubeindex] & 128) == 128) { vertlist[7] = VertexInterp(isolevel, points[7], points[4], val[7], val[4]); } if ((_edgeTable[cubeindex] & 256) == 256) { vertlist[8] = VertexInterp(isolevel, points[0], points[4], val[0], val[4]); } if ((_edgeTable[cubeindex] & 512) == 512) { vertlist[9] = VertexInterp(isolevel, points[1], points[5], val[1], val[5]); } if ((_edgeTable[cubeindex] & 1024) == 1024) { vertlist[10] = VertexInterp(isolevel, points[2], points[6], val[2], val[6]); } if ((_edgeTable[cubeindex] & 2048) == 2048) { vertlist[11] = VertexInterp(isolevel, points[3], points[7], val[3], val[7]); } // evaluate all points between these 8 vertices /* Create the triangle */ var vertexCount = m.Vertices.Count; var triangles = 0; for (var k = 0; _triTable[cubeindex, k] != -1; k += 3) { var facePts = new Point3d[3]; facePts[0] = vg.EvaluatePoint(vertlist[_triTable[cubeindex, k]]); facePts[1] = vg.EvaluatePoint(vertlist[_triTable[cubeindex, k + 1]]); facePts[2] = vg.EvaluatePoint(vertlist[_triTable[cubeindex, k + 2]]); m.Vertices.AddVertices(facePts); // perhaps this should be switched around for the right normal direction m.Faces.AddFace(vertexCount, vertexCount + 1, vertexCount + 2); vertexCount += 3; triangles++; } return(triangles); }
/// <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 vg = default(VoxelGrid3D); DA.GetData(0, ref vg); var isRoof = new VoxelGrid3D(vg.BBox, vg.VoxelSize); var hasAccessible = new VoxelGrid3D(vg.BBox, vg.VoxelSize); var accessViaStairs = new VoxelGrid3D(vg.BBox, vg.VoxelSize); var tr = new Point3i(0, 0, 1); var t1 = new Point3i(0, 1, 1); var t2 = new Point3i(1, 0, 1); var t3 = new Point3i(-1, 0, 1); var t4 = new Point3i(0, -1, 1); for (var i = 0; i < vg.Count; i++) { if (vg[i] == false) { continue; } // there's nothing above us.. only sky if (vg.GetRelativePointValue(i, tr) == 0) { var accessible = false; if (vg.GetRelativePointValue(i, t1) == 1) { accessible = true; hasAccessible.SetRelativePointValue(i, t1, true); } if (vg.GetRelativePointValue(i, t2) == 1) { accessible = true; hasAccessible.SetRelativePointValue(i, t2, true); } if (vg.GetRelativePointValue(i, t3) == 1) { accessible = true; hasAccessible.SetRelativePointValue(i, t3, true); } if (vg.GetRelativePointValue(i, t4) == 1) { accessible = true; hasAccessible.SetRelativePointValue(i, t4, true); } if (accessible) { isRoof[i] = true; } else { accessViaStairs[i] = true; } } } DA.SetData(0, hasAccessible); DA.SetData(1, isRoof); DA.SetData(2, accessViaStairs); }