/// <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); }