/// <summary> /// Initializes a new instance of the <see cref="VoxelizedSolid"/> class. /// </summary> /// <param name="ts">The ts.</param> /// <param name="voxelSideLength">Length of the voxel side.</param> /// <param name="bounds">The bounds.</param> public VoxelizedSolid(TessellatedSolid ts, double voxelSideLength, IReadOnlyList <Vector3> bounds = null) : this() { if (bounds != null) { Bounds = new[] { bounds[0], bounds[1] } } ; else { Bounds = new[] { ts.Bounds[0], ts.Bounds[1] } }; Dimensions = Bounds[1].Subtract(Bounds[0]); SolidColor = new Color(Constants.DefaultColor); VoxelSideLength = voxelSideLength; numVoxelsX = (int)Math.Ceiling(Dimensions.X / VoxelSideLength); numVoxelsY = (int)Math.Ceiling(Dimensions.Y / VoxelSideLength); numVoxelsZ = (int)Math.Ceiling(Dimensions.Z / VoxelSideLength); voxels = new IVoxelRow[numVoxelsY * numVoxelsZ]; for (int i = 0; i < numVoxelsY * numVoxelsZ; i++) { voxels[i] = new VoxelRowSparse(); } FillInFromTessellation(ts); FractionDense = 0; UpdateProperties(); }
/// <summary> /// Initializes a new instance of the <see cref="VoxelizedSolid"/> class. /// </summary> /// <param name="ts">The ts.</param> /// <param name="voxelsOnLongSide">The voxels on long side.</param> /// <param name="bounds">The bounds.</param> public VoxelizedSolid(TessellatedSolid ts, int voxelsOnLongSide, IReadOnlyList <Vector3> bounds = null) : this() { if (bounds != null) { Bounds = new[] { bounds[0], bounds[1] } } ; else { Bounds = new[] { ts.Bounds[0], ts.Bounds[1] } }; Dimensions = Bounds[1].Subtract(Bounds[0]); SolidColor = new Color(ts.SolidColor.A, ts.SolidColor.R, ts.SolidColor.G, ts.SolidColor.B); VoxelSideLength = Math.Max(Dimensions.X, Math.Max(Dimensions.Y, Dimensions.Z)) / voxelsOnLongSide; numVoxelsX = (int)Math.Ceiling(Dimensions.X / VoxelSideLength); numVoxelsY = (int)Math.Ceiling(Dimensions.Y / VoxelSideLength); numVoxelsZ = (int)Math.Ceiling(Dimensions.Z / VoxelSideLength); voxels = new IVoxelRow[numVoxelsY * numVoxelsZ]; for (int i = 0; i < numVoxelsY * numVoxelsZ; i++) { voxels[i] = new VoxelRowSparse(numVoxelsX); } FillInFromTessellation(ts); FractionDense = 0; UpdateProperties(); }
/// <summary> /// Intersects the specified other rows with this row. /// </summary> /// <param name="others">The others.</param> /// <param name="offset">The offset.</param> public void Intersect(IVoxelRow[] others, int offset = 0) { for (int i = 0; i < others.Length; i++) { IVoxelRow other = others[i]; if (other is VoxelRowDense) { other = new VoxelRowSparse(other, other.maxNumberOfVoxels); } var otherIndices = ((VoxelRowSparse)other).indices; var otherLength = otherIndices.Count; var indexLowerBound = 0; if (otherLength == 0) { indices.Clear(); } else { if (otherIndices[0] != 0) { TurnOffRange(0, otherIndices[0], ref indexLowerBound); } for (int j = 1; j < otherLength - 1; j += 2) { TurnOffRange(otherIndices[j], otherIndices[j + 1], ref indexLowerBound); } TurnOffRange(otherIndices[otherLength - 1], other.maxNumberOfVoxels, ref indexLowerBound); } } }
/// <summary> /// Initializes a new instance of the <see cref="VoxelRowSparse"/> struct. /// </summary> /// <param name="row">The row.</param> internal VoxelRowSparse(IVoxelRow row, int length) { maxNumberOfVoxels = (ushort)length; if (row is VoxelRowSparse sparse) { indices = new List <ushort>(sparse.indices); } else { indices = new List <ushort>(); var denseRow = ((VoxelRowDense)row); var lastVal = false; ushort i = 0; foreach (var thisByte in denseRow.values) { var currentByte = thisByte; for (int j = 0; j < 8; j++) { var currentVal = (currentByte & 0b10000000) != 0; if (currentVal != lastVal) { lastVal = currentVal; indices.Add(i); } currentByte <<= 1; i++; } } if (lastVal) { indices.Add(i); } } }
/// <summary> /// Initializes a new instance of the <see cref="VoxelizedSolid"/> class. /// </summary> /// <param name="ts">The ts.</param> /// <param name="voxelSideLength">Length of the voxel side.</param> /// <param name="bounds">The bounds.</param> public VoxelizedSolid(TessellatedSolid ts, double voxelSideLength, IReadOnlyList <double[]> bounds = null) : this() { Bounds = new double[2][]; if (bounds != null) { Bounds[0] = (double[])bounds[0].Clone(); Bounds[1] = (double[])bounds[1].Clone(); } else { Bounds[0] = (double[])ts.Bounds[0].Clone(); Bounds[1] = (double[])ts.Bounds[1].Clone(); } Dimensions = Bounds[1].subtract(Bounds[0]); SolidColor = new Color(Constants.DefaultColor); VoxelSideLength = voxelSideLength; var voxelsPerSide = Dimensions.Select(d => (int)Math.Ceiling(d / VoxelSideLength)).ToArray(); numVoxelsX = voxelsPerSide[0]; numVoxelsY = voxelsPerSide[1]; numVoxelsZ = voxelsPerSide[2]; voxels = new IVoxelRow[numVoxelsY * numVoxelsZ]; for (int i = 0; i < numVoxelsY * numVoxelsZ; i++) { voxels[i] = new VoxelRowSparse(); } FillInFromTessellation(ts); FractionDense = 0; UpdateProperties(); }
/// <summary> /// Initializes a new instance of the <see cref="VoxelizedSolid"/> class. /// </summary> /// <param name="vs">The vs.</param> internal VoxelizedSolid(VoxelizedSolid vs) : this() { Bounds = new[] { vs.Bounds[0], vs.Bounds[1] }; Dimensions = Bounds[1].Subtract(Bounds[0]); SolidColor = new Color(vs.SolidColor.A, vs.SolidColor.R, vs.SolidColor.G, vs.SolidColor.B); VoxelSideLength = vs.VoxelSideLength; numVoxelsX = vs.numVoxelsX; numVoxelsY = vs.numVoxelsY; numVoxelsZ = vs.numVoxelsZ; voxels = new IVoxelRow[numVoxelsY * numVoxelsZ]; for (int i = 0; i < numVoxelsY * numVoxelsZ; i++) { voxels[i] = new VoxelRowSparse(vs.voxels[i], numVoxelsX); } FractionDense = 0; UpdateProperties(); }
/// <summary> /// Initializes a new instance of the <see cref="VoxelRowDense"/> struct. /// This is typically used to copy an existing dense row, or convert from /// a sparse row. /// </summary> /// <param name="row">The row.</param> /// <param name="numBytes">The number bytes.</param> internal VoxelRowDense(IVoxelRow row, int length) : this(length) { if (row is VoxelRowSparse sparse) { if (sparse.indices.Any()) { for (int i = 0; i < sparse.indices.Count; i += 2) { TurnOnRange(sparse.indices[i], sparse.indices[i + 1]); } } } else { values = (byte[])((VoxelRowDense)row).values.Clone(); } }
/// <summary> /// Subtracts the specified subtrahend rows from this row. /// </summary> /// <param name="subtrahends">The subtrahends.</param> /// <param name="offset">The offset.</param> public void Subtract(IVoxelRow[] subtrahends, int offset = 0) { for (int i = 0; i < subtrahends.Length; i++) { IVoxelRow subtrahend = subtrahends[i]; if (subtrahend is VoxelRowDense) { subtrahend = new VoxelRowSparse(subtrahend, subtrahend.maxNumberOfVoxels); } var otherIndices = ((VoxelRowSparse)subtrahend).indices; var otherLength = otherIndices.Count; var indexLowerBound = 0; for (int j = 0; j < otherLength; j += 2) { TurnOffRange(otherIndices[j], otherIndices[j + 1], ref indexLowerBound); } } }
/// <summary> /// Unions the specified other rows with this row. /// </summary> /// <param name="others">The others.</param> /// <param name="offset">The offset.</param> public void Union(IVoxelRow[] others, int offset = 0) { for (int i = 0; i < others.Length; i++) { IVoxelRow other = others[i]; if (other is VoxelRowDense) { other = new VoxelRowSparse(other, other.maxNumberOfVoxels); } var otherIndices = ((VoxelRowSparse)other).indices; var otherLength = otherIndices.Count; var indexLowerBound = 0; for (int j = 0; j < otherLength; j += 2) { TurnOnRange(otherIndices[j], otherIndices[j + 1], ref indexLowerBound); } } }
public VoxelizedSolid(VoxelizedSolid vs) : this() { Bounds = new double[2][]; Bounds[0] = (double[])vs.Bounds[0].Clone(); Bounds[1] = (double[])vs.Bounds[1].Clone(); Dimensions = Bounds[1].subtract(Bounds[0]); SolidColor = new Color(vs.SolidColor.A, vs.SolidColor.R, vs.SolidColor.G, vs.SolidColor.B); VoxelSideLength = vs.VoxelSideLength; numVoxelsX = vs.numVoxelsX; numVoxelsY = vs.numVoxelsY; numVoxelsZ = vs.numVoxelsZ; voxels = new IVoxelRow[numVoxelsY * numVoxelsZ]; for (int i = 0; i < numVoxelsY * numVoxelsZ; i++) { voxels[i] = new VoxelRowSparse(vs.voxels[i], numVoxelsX); } FractionDense = 0; UpdateProperties(); }
/// <summary> /// Initializes a new instance of the <see cref="VoxelizedSolid"/> class. /// </summary> /// <param name="ts">The ts.</param> /// <param name="voxelsOnLongSide">The voxels on long side.</param> /// <param name="bounds">The bounds.</param> public VoxelizedSolid(IEnumerable <Polygon> loops, int voxelsOnLongSide, IReadOnlyList <Vector2> bounds) : this() { Bounds = new[] { new Vector3(bounds[0], 0), new Vector3(bounds[1], 1) }; Dimensions = Bounds[1].Subtract(Bounds[0]); VoxelSideLength = Math.Max(Dimensions.X, Math.Max(Dimensions.Y, Dimensions.Z)) / voxelsOnLongSide; numVoxelsX = (int)Math.Ceiling(Dimensions.X / VoxelSideLength); numVoxelsY = (int)Math.Ceiling(Dimensions.Y / VoxelSideLength); numVoxelsZ = 1; voxels = new IVoxelRow[numVoxelsY * numVoxelsZ]; for (int i = 0; i < numVoxelsY * numVoxelsZ; i++) { voxels[i] = new VoxelRowSparse(numVoxelsX); } var yBegin = Bounds[0][1] + VoxelSideLength / 2; var inverseVoxelSideLength = 1 / VoxelSideLength; // since its quicker to multiple then to divide, maybe doing this once at the top will save some time //if (loops.Any()) //{ // multiple enumeration warning so commenting out above condition. but that sound be a problem for next line var intersections = loops.AllPolygonIntersectionPointsAlongHorizontalLines(yBegin, numVoxelsY, VoxelSideLength, out var yStartIndex); var numYlines = intersections.Count; for (int j = -Math.Min(0, yStartIndex); j < numYlines; j++) { var intersectionPoints = intersections[j]; var numXRangesOnThisLine = intersectionPoints.Length; for (var m = 0; m < numXRangesOnThisLine; m += 2) { var sp = (ushort)((intersectionPoints[m] - Bounds[0][0]) * inverseVoxelSideLength); var ep = (ushort)((intersectionPoints[m + 1] - Bounds[0][0]) * inverseVoxelSideLength); if (ep >= numVoxelsX) { ep = (ushort)(numVoxelsX - 1); } ((VoxelRowSparse)voxels[yStartIndex + j]).indices.Add(sp); ((VoxelRowSparse)voxels[yStartIndex + j]).indices.Add(ep); } } //} FractionDense = 0; UpdateProperties(); }