public IEnumerator CreateArcTest(VoxelRegion region) { m_innerRing = int.MaxValue; m_outerRing = int.MinValue; Clear(); Text.Log(@"Max rings: {0}=========================<<<<<<<<<<<<<<<<<<<<<<<<", m_maxRings); // NOTE: // This assumes ring 0 is at the origin of the plate; // a slightly better version could have ring 0 start // nozzleSize * 0.5f mm away from the origin. This // would help account for the slight spill over from // the nozzle into adjacent rings… for (int forRing = 0; forRing < 72; forRing += 3) { Arc testingArc = Extend(null, (byte)1, 0000, forRing); Close(testingArc, 1600, forRing); Text.Log(@"Ring {0}: Added testing arc {1}.", forRing, testingArc); UpdateRingBounds(forRing); if (Scheduler.ShouldYield()) { yield return(null); } } Contract.Assert(m_ringCount <= m_maxRings, @"Ring count ({0}) is larger than max rings ({1}).", m_ringCount, m_maxRings); Contract.Assert(m_ringCount <= layerWidthInRings, @"Ring count of {0} larger than width of {1}.", m_ringCount, layerWidthInRings); }
public List <CartesianSegment> GetSegments(VoxelRegion region) { int flag; List <CartesianSegment> result = new List <CartesianSegment>(); List <int2> voxelsToRemove = new List <int2>(); // NOTE: 0,0 is in the bottom-left. for (int x = 0; x < region.width; ++x) { for (int z = 0; z < region.depth; ++z) { flag = ((x < 1 || z < 1) ? 0 : (region[x - 1, z - 1] != 0 ? 0x1 : 0x0)) | ((z < 1) ? 0 : (region[x, z - 1] != 0 ? 0x2 : 0x0)) | (region[x, z] != 0 ? 0x4 : 0x0) | ((x < 1) ? 0 : (region[x - 1, z] != 0 ? 0x8 : 0x0)); int x0 = Mathf.Clamp(x - 1, 0, region.width - 1); int z0 = Mathf.Clamp(z - 1, 0, region.depth - 1); byte usedMaterial = MathUtil.ModeIgnore(0, region[x0, z0], region[x, z0], region[x, z], region[x0, z]); if (usedMaterial == 0) { continue; } float[] tableRow = kContourTable[flag]; int numSegments = (int)tableRow[0]; if (numSegments != 0) { voxelsToRemove.Add(new int2(x, z)); voxelsToRemove.Add(new int2(x0, z)); voxelsToRemove.Add(new int2(x, z0)); voxelsToRemove.Add(new int2(x0, z0)); } for (int aSegment = 0; aSegment < numSegments; ++aSegment) { Vector2 p0 = VoxelBlob.kVoxelSizeInMm * new Vector2( x + tableRow[aSegment * 4 + 1], z + tableRow[aSegment * 4 + 2]); Vector2 p1 = VoxelBlob.kVoxelSizeInMm * new Vector2( x + tableRow[aSegment * 4 + 3], z + tableRow[aSegment * 4 + 4]); CartesianSegment product = new CartesianSegment(p0, p1, usedMaterial); result.Add(product); } } } foreach (int2 vox in voxelsToRemove) { region[vox.x, vox.y] = 0; } //Text.Log(@"{0} segment{1} found in outlines and {2} voxels removed.", result.Count, Text.S(result.Count), voxelsToRemove.Count); return(result); }
/// <summary> /// Region voxels with non-zero material are removed from the blob. /// </summary> /// <param name="r">The voxel region to subtract.</param> /// <param name="layer">The layer height of the region.</param> public void SubtractRegion(VoxelRegion r, int layer) { for (int col = 0; col < width; col++) { for (int row = 0; row < depth; row++) { if (r[col, row] != 0) { this[col, layer, row] = 0; } } } }
/// <summary> /// Converts a layer of voxels to a layer of arcs. /// </summary> /// <param name='aBlob'> /// A 3D voxel blob. /// </param> /// <param name='atLayer'> /// The layer to sample at. /// </param> public IEnumerator ConvertVoxelLayer(VoxelRegion region) { m_innerRing = int.MaxValue; m_outerRing = int.MinValue; Clear(); // NOTE: // This assumes ring 0 is at the origin of the plate; // a slightly better version could have ring 0 start // nozzleSize * 0.5f mm away from the origin. This // would help account for the slight spill over from // the nozzle into adjacent rings… for (int forRing = 0; forRing < m_maxRings; forRing += infillStep) { SampleArcsFrom(region, forRing); if (Scheduler.ShouldYield()) { yield return(null); } } // NOTE for TESTING // If we didn't added anything for ring 0, add a complete ring. if (m_arcs[0].Count == 0) { int origin = Mathf.RoundToInt(region.GetSampleFromMm(m_printer.platformRadiusInMm)); byte material = region.IsValidPoint(origin, origin) ? region[origin, origin] : (byte)0; Arc currentArc = null; Extend(currentArc, material, 0, 0); Extend(currentArc, 0, m_printer.platform.stepsPerRotation, 0); UpdateRingBounds(0); } else { Text.Log(@"No worries!"); } //*/ Contract.Assert(m_ringCount <= m_maxRings, @"Ring count ({0}) is larger than max rings ({1}).", m_ringCount, m_maxRings); Contract.Assert(m_ringCount <= layerWidthInRings, @"Ring count of {0} larger than width of {1}.", m_ringCount, layerWidthInRings); }
/// <summary> /// Samples the blob for the given [ring, layer] by sampling /// kSamplingScale * the circumference points moving in a /// positive (ccw) angle. /// </summary> /// <param name='aBlob'> /// A BLOB. /// </param> /// <param name='atLayer'> /// At layer. /// </param> /// <param name='forRing'> /// For ring. /// </param> void SampleArcsFrom(VoxelRegion region, int forRing) { Contract.Assert(forRing >= 0, @"Negative ring: {0}", forRing); Contract.Assert(forRing < m_maxRings, @"Ring {0} out of bounds.", forRing); float platformStepInDeg = m_printer.platform.degreesPerStep; int stepsPerRotation = m_printer.platform.stepsPerRotation; int samplesToTake = Mathf.CeilToInt(forRing * MathUtil.kTau * kSamplingScale); float sampleSizeInRadians = MathUtil.kTau / samplesToTake; Arc currentArc = null; // Origin of the platform, in voxels. int origin = Mathf.RoundToInt(region.GetSampleFromMm(m_printer.platformRadiusInMm)); // Rings -> Mm -> Voxels float voxelRadius = region.GetSampleFromMm(forRing * m_printer.nozzleWidthInMm); for (int sampleIndex = 0; sampleIndex < samplesToTake; ++sampleIndex) { float radians = sampleIndex * sampleSizeInRadians; // Since the number of samples we're taking depends on the radius, // we can't pre-compute the angles and use them for everything… float sampleX = voxelRadius * Mathf.Cos(radians); float sampleY = voxelRadius * Mathf.Sin(radians); // NOTE: This should probably be rounded, not floored. int sampleXInt = Mathf.RoundToInt(sampleX); int sampleYInt = Mathf.RoundToInt(sampleY); float sampleXFractional = sampleX - sampleXInt; float sampleYFractional = sampleY - sampleYInt; float xFractionalSqr = sampleXFractional * sampleXFractional; float yFractionalSqr = sampleYFractional * sampleYFractional; // If the sample is sufficiently good, then take the sample // and update the arc. if (xFractionalSqr + yFractionalSqr <= kSampleThresholdSqr) { int sampleAtWidth = sampleXInt + origin; int sampleAtDepth = sampleYInt + origin; byte material = region.IsValidPoint(sampleAtWidth, sampleAtDepth) ? region[sampleAtWidth, sampleAtDepth] : (byte)0; // NOTE: If we round to int, then we can get the same step // number even if we sample different points! Doing so // could lead to 0-length arcs. int platformStep = Mathf.FloorToInt(radians * Mathf.Rad2Deg / platformStepInDeg); platformStep = Mathf.Min(platformStep, stepsPerRotation); currentArc = Extend(currentArc, material, platformStep, forRing); } } // Close off the arc if open. Extend(currentArc, 0, stepsPerRotation, forRing); UpdateRingBounds(forRing); }