private bool hasNonSupportCellLeftOrRight(List <StructuralCell> sc, StructuralCell cell) { StructuralCell neighbour1 = sc.Find(c => c.cellType == StructuralCell.CellType.SkinCell && //only skin c.rowNum == cell.rowNum && //same row c.colNum == cell.colNum + 1 // next column ); if (neighbour1 != null) { return(true); } StructuralCell neighbour2 = sc.Find(c => c.cellType == StructuralCell.CellType.SkinCell && //only skin c.rowNum == cell.rowNum && //same row c.colNum == cell.colNum - 1 ); if (neighbour2 != null) { return(true); } return(false); }
private void makeLinks(string direction, StructuralCell c) { List <Vector3d> vectors = makeLinkVectors(direction, c.fillerCell); Vector3d linkDirection = new Vector3d(); switch (direction) { case "x": linkDirection = referencePlane.XAxis; break; case "y": linkDirection = referencePlane.YAxis; break; case "z": linkDirection = referencePlane.ZAxis; break; } Transform xform = Transform.PlaneToPlane(Plane.WorldXY, referencePlane); foreach (Vector3d v in vectors) { v.Transform(xform); Line link = new Line(c.centroid + v, linkDirection, parameters.memberSize); if (!StructuralCell.curveIsInsideMesh(link.ToNurbsCurve(), slice)) { linkElements.Add(link); } } }
private bool hasCellToSide(StructuralCell cell, List <StructuralCell> cells) { double testLength = parameters.xCell; foreach (StructuralCell othercell in cells) { if (othercell.fillerCell || cell.fillerCell) { testLength = parameters.xCell / 2 + parameters.fillerCellX / 2; } else { testLength = parameters.xCell; } if (othercell.cellType != StructuralCell.CellType.Undefined) { Vector3d v = othercell.centroid - cell.centroid; //small z and length close to xCell if (Math.Abs(v.Z) < 10 && Math.Abs(v.Length - testLength) < 10) { //angle to xdirection should be 0 if (Vector3d.VectorAngle(v, minPlane.XAxis) < Math.PI / 2) { return(true); } } } } return(false); }
private void reduceModuleYDirection(ref StructuralCell c, Plane boundPlane, Curve intersection) { c.cellType = StructuralCell.CellType.Undefined; double newY = Double.MaxValue; NurbsCurve nc = intersection.ToNurbsCurve(); foreach (ControlPoint cp in nc.Points) { Point3d plnPt = boundPlane.ClosestPoint(cp.Location); if (plnPt.DistanceTo(cp.Location) < newY) { newY = plnPt.DistanceTo(cp.Location); } } if (newY < parameters.fillerMinimum) { c = null; return; } //set the new module Point3d bPoint = boundPlane.ClosestPoint(c.centroid); Vector3d shft = c.centroid - bPoint; shft.Unitize(); Plane cellPlane = new Plane(bPoint + shft * newY / 2, minPlane.XAxis, minPlane.YAxis); c = new StructuralCell(cellPlane, c.xDim, newY, c.zDim, parameters.memberSize, c.id, false, setColor(r)); }
private List <string> fourDiagNeighbours(StructuralCell cell) { List <string> n4 = new List <string>(); n4.Add(genMCode(cell.side, cell.colNum - 1, cell.rowNum - 1)); n4.Add(genMCode(cell.side, cell.colNum + 1, cell.rowNum - 1)); n4.Add(genMCode(cell.side, cell.colNum - 1, cell.rowNum + 1)); n4.Add(genMCode(cell.side, cell.colNum + 1, cell.rowNum + 1)); return(n4); }
private void fillFromDiags(StructuralCell cell) { List <string> n4 = fourDiagNeighbours(cell); var cells = voxels.SelectMany(x => x).ToList(); foreach (string code in n4) { var n = cells.Find(x => x.id == code); if (n != null) { if (n.cellType == StructuralCell.CellType.VerticalFillCell || n.cellType == StructuralCell.CellType.PerimeterCell) { //try and fill at lower level first //break after fill as we only need a single filler if (n.rowNum < cell.rowNum) { //row below current cell var id = genMCode(cell.side, cell.colNum, cell.rowNum - 1); if (tryFillCell(id, cells)) { break; } else { //same row as current cell id = genMCode(cell.side, n.colNum, cell.rowNum); if (tryFillCell(id, cells)) { break; } } } else { //same row as current cell var id = genMCode(cell.side, n.colNum, cell.rowNum); if (tryFillCell(id, cells)) { break; } else { //row above current cell id = genMCode(cell.side, cell.colNum, cell.rowNum + 1); if (tryFillCell(id, cells)) { break; } } } } } } }
private void buildBaseModules() { List <StructuralCell> cellsZero = new List <StructuralCell>(); List <StructuralCell> cellsOne = new List <StructuralCell>(); foreach (List <StructuralCell> sc in voxels) { for (int i = 0; i < sc.Count; i++) { if (sc[i].id == cellDebugId) { int g = 0; } StructuralCell c = sc[i]; if (c.rowNum == 0) { Point3d slabPt = new Point3d(); bool foundslab = findClosestSlabPoint(sc[i], ref slabPt, false); if (foundslab) { //centroid to closest slab distance Vector3d diff = slabPt - c.centroid; double dist = Math.Abs(diff.Z); if (dist < parameters.zCell / 2 + parameters.fillerMinimum) { //smaller than half module //replace with smaller module adjustModuleVertical(ref c, slabPt, true); sc[i] = c; } else { //fill missing modules //adjust dist to be underside last module to slab //only fill if module above slab if (slabPt.Z < c.centroid.Z) { fillToSlab(c, dist - parameters.zCell / 2, ref cellsZero, ref cellsOne); } } } else { //no slab below found either we are below slab level or no slab exists // sc[i] = null; } } } } voxels[0].AddRange(cellsZero); voxels[1].AddRange(cellsOne); }
private bool cellIsInsideMesh(StructuralCell cell) { //mesh normals towards inside MeshPoint mp = slice.ClosestMeshPoint(cell.centroid, 0); Vector3d v = cell.centroid - mp.Point; if (Vector3d.VectorAngle(v, slice.FaceNormals[mp.FaceIndex]) < Math.PI / 2) { //inside return(true); } return(false); }
private bool hasNonSupportCellBelow(List <StructuralCell> sc, StructuralCell cell) { StructuralCell neighbourbelow = sc.Find(c => c.cellType == StructuralCell.CellType.SkinCell && //only skin c.rowNum == cell.rowNum - 1 && //row below c.colNum == cell.colNum //same column ); if (neighbourbelow != null) { return(true); } return(false); }
private void fillToSlab(StructuralCell c, double dist, ref List <StructuralCell> cellszero, ref List <StructuralCell> cellsone) { double nfills = dist / parameters.zCell; double fillCell = nfills % 1 * parameters.zCell; double lastCell = 0; int nCells = Convert.ToInt32(Math.Floor(nfills)); //check last cell size if (fillCell < parameters.fillerMinimum) { //oversized last cell lastCell = parameters.zCell + fillCell; } else { //undersized extra last cell lastCell = fillCell; nCells++; } double height = parameters.zCell; Vector3d shft = new Vector3d(); for (int i = 0; i < nCells; i++) { if (i == nCells - 1) { //spacing on lastcell shft = shft + Vector3d.ZAxis * lastCell / 2 + Vector3d.ZAxis * parameters.zCell / 2; height = lastCell; } else { shft = Vector3d.ZAxis * ((i + 1) * parameters.zCell); } Plane cellPlane = new Plane(c.centroid - shft, minPlane.XAxis, minPlane.YAxis); string mcode = genMCode(c.side, c.colNum, c.rowNum - (i + 1)); StructuralCell structCell = new StructuralCell(cellPlane, c.xDim, c.yDim, height, parameters.memberSize, mcode, false, setColor(r)); structCell.cellType = StructuralCell.CellType.VerticalFillCell; //store and add after/ if (c.side == 0) { cellszero.Add(structCell); } else { cellsone.Add(structCell); } } }
private void roofLevelCheck() { foreach (List <StructuralCell> sc in voxels) { for (int i = 0; i < sc.Count; i++) { if (sc[i].id == cellDebugId) { int g = 0; } Point3d slabPt = new Point3d(); findClosestSlabPoint(sc[i], ref slabPt, true); //the base is above slab cell is nulled if (slabPt.Z < sc[i].basePoints[0].Z) { sc[i] = null; continue; } double diff = slabPt.Z - sc[i].basePoints[0].Z; if (diff > parameters.zCell + parameters.fillerMinimum) { //no change needed continue; } if (diff < parameters.zCell + parameters.fillerMinimum && diff >= parameters.zCell) { //extend this cell StructuralCell c = sc[i]; adjustModuleVertical(ref c, slabPt, false); sc[i] = c; continue; } //slab is above base but diff is smaller than top cell H if (diff < parameters.fillerMinimum) { sc[i] = null; continue; } if (diff < parameters.zCell) { //reduce this cell StructuralCell c = sc[i]; adjustModuleVertical(ref c, slabPt, false); sc[i] = c; continue; } } } }
private void boundaryChecks() { Curve[] cInter; Point3d[] pInter; Plane insidePlane = new Plane(); foreach (List <StructuralCell> sc in voxels) { for (int i = 0; i < sc.Count; i++) { if (sc[i].id == cellDebugId) { int g = 0; } StructuralCell c = sc[i]; foreach (Brep w in parameters.wall) { bool inter = Rhino.Geometry.Intersect.Intersection.BrepBrep(c.outerBoundary, w, RhinoDoc.ActiveDoc.ModelAbsoluteTolerance, out cInter, out pInter); if (cInter.Length > 0) { //which cell end is inside bool end0 = MeshTools.curveInBrep(c.boundCurve0, w); bool end1 = MeshTools.curveInBrep(c.boundCurve1, w); if (!end0 && !end1) { // both ends intersect, we won't use it, move to next cell sc[i] = null; break; } if (end0) { insidePlane = c.boundPlane0; } if (end1) { insidePlane = c.boundPlane1; } reduceModuleYDirection(ref c, insidePlane, cInter[0]); sc[i] = c; break;//move to next cell } } } } }
private bool noCellsAbove(StructuralCell cell) { bool nocells = true; var cellsFill = voxels.SelectMany(x => x).ToList().FindAll(c => c.side == cell.side && c.colNum == cell.colNum && c.rowNum > cell.rowNum && c.cellType != StructuralCell.CellType.Undefined && c.cellType != StructuralCell.CellType.InsideCell); if (cellsFill.Count > 0) { nocells = false; } return(nocells); }
private void adjustModuleVertical(ref StructuralCell c, Point3d slabPt, bool floor) { double newH = 0; if (slabPt.Z > c.centroid.Z) { if (floor) { newH = parameters.zCell / 2 - (slabPt.Z - c.centroid.Z); } else { newH = parameters.zCell / 2 + (slabPt.Z - c.centroid.Z); } } else { double d = (c.centroid.Z - slabPt.Z); if (floor) { newH = parameters.zCell / 2 + d; } else { newH = parameters.zCell / 2 - d; } } if (newH < parameters.fillerMinimum) { //maybe flag as undersized c = null; return; } Point3d origin = new Point3d(c.centroid.X, c.centroid.Y, slabPt.Z); Plane cellPlane = new Plane(); if (floor) { cellPlane = new Plane(origin + Vector3d.ZAxis * newH / 2, minPlane.XAxis, minPlane.YAxis); } else { cellPlane = new Plane(origin - Vector3d.ZAxis * newH / 2, minPlane.XAxis, minPlane.YAxis); } c = new StructuralCell(cellPlane, c.xDim, c.yDim, newH, parameters.memberSize, c.id, false, setColor(r)); }
private bool hasCellsAbove(List <StructuralCell> sc, StructuralCell cell) { List <StructuralCell> cellsAbove = sc.FindAll(c => c.colNum == cell.colNum && //same column c.rowNum > cell.rowNum //row number greater ).ToList(); foreach (StructuralCell c in cellsAbove) { //any cells above inuse if (c.cellType == StructuralCell.CellType.PerimeterCell || c.cellType == StructuralCell.CellType.SkinCell) { return(true); } } return(false); }
private bool hasCellAbove(StructuralCell cell, List <StructuralCell> cells) { //check for neighbours above foreach (StructuralCell othercell in cells) { if (othercell.cellType != StructuralCell.CellType.Undefined) { Vector3d v = othercell.centroid - cell.centroid; //small x and y positive z and length close to zCell if (Math.Abs(v.X) < 10 && Math.Abs(v.Y) < 10 && v.Z > 0 && Math.Abs(v.Length - parameters.zCell) < 10) { return(true); } } } return(false); }
//public DiagonalMember(int dNum,Brep bound) //{ // dnum = dNum; // switch (dNum) // { // case 0: // endpoints.Add(bound.Vertices[1].Location); // endpoints.Add(bound.Vertices[6].Location); // points.Add(bound.Vertices[1].Location); // points.Add(bound.Vertices[0].Location); // points.Add(bound.Vertices[6].Location); // points.Add(bound.Vertices[7].Location); // break; // case 1: // endpoints.Add(bound.Vertices[2].Location); // endpoints.Add(bound.Vertices[6].Location); // points.Add(bound.Vertices[0].Location); // points.Add(bound.Vertices[2].Location); // points.Add(bound.Vertices[4].Location); // points.Add(bound.Vertices[6].Location); // break; // case 2: // endpoints.Add(bound.Vertices[2].Location); // endpoints.Add(bound.Vertices[5].Location); // points.Add(bound.Vertices[3].Location); // points.Add(bound.Vertices[2].Location); // points.Add(bound.Vertices[4].Location); // points.Add(bound.Vertices[5].Location); // break; // case 3: // endpoints.Add(bound.Vertices[5].Location); // endpoints.Add(bound.Vertices[1].Location); // points.Add(bound.Vertices[1].Location); // points.Add(bound.Vertices[3].Location); // points.Add(bound.Vertices[5].Location); // points.Add(bound.Vertices[7].Location); // break; // case 4: // endpoints.Add(bound.Vertices[1].Location); // endpoints.Add(bound.Vertices[2].Location); // points.Add(bound.Vertices[1].Location); // points.Add(bound.Vertices[0].Location); // points.Add(bound.Vertices[2].Location); // points.Add(bound.Vertices[3].Location); // break; // case 5: // endpoints.Add(bound.Vertices[5].Location); // endpoints.Add(bound.Vertices[6].Location); // points.Add(bound.Vertices[4].Location); // points.Add(bound.Vertices[5].Location); // points.Add(bound.Vertices[7].Location); // points.Add(bound.Vertices[6].Location); // break; // } // diagonal = new Line(endpoints[0], endpoints[1]); //} public void trim(Mesh m) { if (StructuralCell.curveIsInsideMesh(diagonal.ToNurbsCurve(), m)) { needed = false; } else { int[] faceIds; Point3d[] points = Rhino.Geometry.Intersect.Intersection.MeshLine(m, diagonal, out faceIds); if (points.Length > 0) { //try find new diagonal newDiagonal(m); } } }
private void buildVoxel(int x, int z, Plane pln, string ab, bool filler) { Vector3d shiftX = new Vector3d(); if (filler) { Vector3d shiftPrev = pln.XAxis * (x - 1) * parameters.xCell; Vector3d shiftFiller = pln.XAxis * (parameters.fillerCellX / 2 + parameters.xCell / 2); shiftX = shiftPrev + shiftFiller; } else { shiftX = pln.XAxis * x * parameters.xCell; } Vector3d shiftY = pln.YAxis * parameters.yCell / 2; Vector3d shiftZ = Vector3d.ZAxis * z * parameters.zCell; Vector3d shift = shiftX + shiftY + shiftZ; Point3d basePt = new Point3d(pln.OriginX, pln.OriginY, pln.OriginZ); Point3d cellCentre = basePt + shift; Plane cellpln = new Plane(cellCentre, minPlane.XAxis, maxPlane.YAxis); string mCode = genMCode(ab, x, z); if (mCode == cellDebugId) { int g = 0; } StructuralCell structCell; if (filler) { structCell = new StructuralCell(cellpln, parameters.fillerCellX, parameters.yCell, parameters.zCell, parameters.memberSize, mCode, filler, setColor(r)); } else { structCell = new StructuralCell(cellpln, parameters.xCell, parameters.yCell, parameters.zCell, parameters.memberSize, mCode, filler, setColor(r)); } if (ab == "a") { voxels[0].Add(structCell); } else { voxels[1].Add(structCell); } }
private bool findClosestSlabPoint(StructuralCell cell, ref Point3d slabPt, bool up) { List <Brep> slabs = parameters.slabs; if (up) { slabs = parameters.roofs; } List <Point3d> inters = new List <Point3d>(); foreach (Point3d p in cell.basePoints) { Line down = new Line(p - Vector3d.ZAxis * 50000, Vector3d.ZAxis, 100000); foreach (Brep s in slabs) { Curve[] curves; Point3d[] points; var inter = Rhino.Geometry.Intersect.Intersection.CurveBrep(down.ToNurbsCurve(), s, RhinoDoc.ActiveDoc.ModelAbsoluteTolerance, out curves, out points); if (points.Length > 0) { inters.Add(points[0]); break; } } } if (inters.Count == 0) { return(false); } List <Point3d> sorted = new List <Point3d>(); if (up) { sorted = inters.OrderBy(p => p.Z).ToList(); //smallest first for roofs } else { sorted = inters.OrderByDescending(p => p.Z).ToList(); //biggest first for floor slabs } slabPt = sorted[0]; return(true); }
private bool check4Neighbours(StructuralCell cell) { bool structuralNeighbour = false; List <string> n4 = fourDiagNeighbours(cell); var cells = voxels.SelectMany(x => x).ToList(); //if one of the 4 neighbours is structural cell all is good foreach (string code in n4) { var n = cells.Find(x => x.id == code); if (n != null) { if (n.cellType == StructuralCell.CellType.VerticalFillCell || n.cellType == StructuralCell.CellType.PerimeterCell) { structuralNeighbour = true; } } } return(structuralNeighbour); }
private bool hasDiagonalNeighbour(StructuralCell cell) { //does the cell have a neighbour on diagonal that is marked as structural? List <string> n4 = fourDiagNeighbours(cell); var cells = voxels.SelectMany(x => x).ToList(); bool structuralNeighbour = false; foreach (string code in n4) { var n = cells.Find(x => x.id == code); if (n != null) { if (n.cellType == StructuralCell.CellType.VerticalFillCell || n.cellType == StructuralCell.CellType.PerimeterCell) { structuralNeighbour = true; } } } return(structuralNeighbour); }
private bool hasCellInFront(StructuralCell cell, List <StructuralCell> cells) { foreach (StructuralCell othercell in cells) { if (othercell.cellType != StructuralCell.CellType.Undefined) { Vector3d v = othercell.centroid - cell.centroid; //small z and length close to yCell if (Math.Abs(v.Z) < 10 && Math.Abs(v.Length - parameters.yCell) < 10) { //angle to xdirection should be 0 if (Vector3d.VectorAngle(v, minPlane.YAxis) < Math.PI / 2) { return(true); } } } } return(false); }
public static Mesh findIntersection(Mesh meshToSplit, StructuralCell c) { Mesh extendSplitter = makeCuboid(c.cellPlane, c.xDim, c.yDim, c.zDim); Mesh result = splitMeshWithMesh(meshToSplit, extendSplitter); int inc = 0; while (result == null || isJaggedBorder(result, extendSplitter)) { //make a bigger splitter inc -= 1; if (inc < -10) { break; } extendSplitter = makeCuboid(c.cellPlane, c.xDim + inc, c.yDim + inc, c.zDim + inc); result = splitMeshWithMesh(meshToSplit, extendSplitter); } return(result); }
private void topCellReduction() { foreach (List <StructuralCell> sc in voxels) { for (int i = 0; i < sc.Count; i++) { if (sc[i].id == cellDebugId) { int g = 0; } if (sc[i].cellType == StructuralCell.CellType.PerimeterCell || sc[i].cellType == StructuralCell.CellType.VerticalFillCell) { //if its got no cells above or has not already been reduced vertically if (noCellsAbove(sc[i]) && sc[i].zDim == parameters.zCell) { Plane cellPlane = new Plane(sc[i].centroid - Vector3d.ZAxis * parameters.topCellH / 2, minPlane.XAxis, minPlane.YAxis); sc[i] = new StructuralCell(cellPlane, sc[i].xDim, sc[i].yDim, parameters.topCellH, parameters.memberSize, sc[i].id, false, setColor(r)); sc[i].cellType = StructuralCell.CellType.PerimeterCell; } } } } }
/// <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) { GH_Structure <IGH_Goo> obj = new GH_Structure <IGH_Goo>(); DA.GetDataTree(0, out obj); if (obj != null) { var paths = obj.Paths; GH_Structure <GH_Brep> cellscomplete = new GH_Structure <GH_Brep>(); GH_Structure <GH_Mesh> caveFaceMeshes = new GH_Structure <GH_Mesh>(); GH_Structure <GH_Curve> centreLines = new GH_Structure <GH_Curve>(); GH_Structure <GH_Mesh> gsameshes = new GH_Structure <GH_Mesh>(); GH_Structure <GH_Point> nodes = new GH_Structure <GH_Point>(); GH_Structure <GH_Point> centroids = new GH_Structure <GH_Point>(); GH_Structure <GH_Boolean> disjoint = new GH_Structure <GH_Boolean>(); GH_Structure <GH_String> ids = new GH_Structure <GH_String>(); for (int i = 0; i < obj.Branches.Count; i++) { GH_Path path = paths[i]; for (int j = 0; j < obj.Branches[i].Count; j++) { StructuralCell cell = null; obj[i][j].CastTo(out cell); if (cell.cellType != StructuralCell.CellType.InsideCell) { foreach (Curve cl in cell.centreLines) { centreLines.Append(new GH_Curve(cl.ToNurbsCurve()), path); } foreach (Curve cl in cell.diagonals) { centreLines.Append(new GH_Curve(cl.ToNurbsCurve()), path); } foreach (Point3d p in cell.nodes) { nodes.Append(new GH_Point(p), path); } if (cell.cellType == StructuralCell.CellType.SkinCell) { if (cell.GSAmesh != null) { gsameshes.Append(new GH_Mesh(cell.GSAmesh), path); } if (cell.caveFace != null) { caveFaceMeshes.Append(new GH_Mesh(cell.caveFace), path); } if (cell.caveFace.DisjointMeshCount > 1) { disjoint.Append(new GH_Boolean(true)); } else { disjoint.Append(new GH_Boolean(false)); } } cellscomplete.Append(new GH_Brep(cell.innerBoundary), path); centroids.Append(new GH_Point(cell.centroid), path); ids.Append(new GH_String(cell.id), path); } } } DA.SetDataTree(0, nodes); DA.SetDataTree(1, centreLines); DA.SetDataTree(2, cellscomplete); DA.SetDataTree(3, caveFaceMeshes); DA.SetDataTree(4, gsameshes); DA.SetDataTree(5, centroids); DA.SetDataTree(6, disjoint); DA.SetDataTree(7, ids); } }
private void interfaceContinuity(StructuralCell cell) { //get all the cells on the other side var cells = voxels[0]; if (cell.side == 0) { cells = voxels[1]; } //if there are no cells on the other side nothing to do here if (cells.Count == 0) { return; } //get the row of this cell var row = cells.FindAll(c => c.rowNum == cell.rowNum).OrderByDescending(x => x.colNum).ToList(); //closest is the first in the list StructuralCell closest = row[0]; if (closest.cellType == StructuralCell.CellType.PerimeterCell || closest.cellType == StructuralCell.CellType.VerticalFillCell) { return; } //get the column var col = cells.FindAll(c => c.colNum == closest.colNum).ToList(); //get the skin cell if any var skin = col.FindAll(x => x.cellType == StructuralCell.CellType.SkinCell).OrderByDescending(x => x.rowNum).ToList(); if (skin.Count > 0) { int z = cell.rowNum; var topSkin = skin[0]; if (topSkin.rowNum >= cell.rowNum) { //add continuity on filler side upwards var cellsFill = voxels.SelectMany(x => x).ToList().FindAll(c => c.side == cell.side && c.colNum == cell.colNum); while (true) { z++; var next = cellsFill.Find(x => x.id == genMCode(cell.side, cell.colNum, z)); var pair = col.Find(x => x.rowNum == z); if (pair == null || next == null) { break; } next.cellType = StructuralCell.CellType.PerimeterCell; if (pair.cellType == StructuralCell.CellType.PerimeterCell || pair.cellType == StructuralCell.CellType.VerticalFillCell) { break; } } } else { //add continuity on non filler side downwards while (true) { var pair = col.Find(x => x.rowNum == z); if (pair == null) { break; } if (pair.cellType == StructuralCell.CellType.PerimeterCell || pair.cellType == StructuralCell.CellType.VerticalFillCell) { break; } else { pair.cellType = StructuralCell.CellType.PerimeterCell; } z--; } } } else { // no skin cell found... } }