/// <summary> /// Divide scope into portions as described by divisors list. /// Add snap planes at the dividend bounds if a snap id is given in the divisor. /// If any snap planes in the selector list are found within a dividend scope, snap the bounds to match the nearest snap plane of that selector type. /// </summary> /// <param name="divider"> </param> /// <returns></returns> public override ProductionScope[] Divide(DivideProduction divider) { // step 1: validate divisor magnitudes. scopeLength > absolute length; scopeLength - absolute lengths = availableRelLength var absSpan = divider.Divisors.Where(div => div.IsAbsolute).Sum(div => div.Magnitude); var relSpan = divider.Divisors.Where(div => !div.IsAbsolute).Sum(div => div.Magnitude); if (Math.Abs(relSpan - 1) > Mathf.Epsilon || absSpan > Bounds.size[(int)divider.DivisionAxis]) { throw new Exception("Division length is invalid."); } var divAxisExtent = Vector3.zero; divAxisExtent[(int)divider.DivisionAxis] = Bounds.extents[(int)divider.DivisionAxis]; var frontierPoint = Bounds.center - Rotation * (divAxisExtent); var dividends = new ProductionScope[divider.Divisors.Count()]; for (var i = 0; i < divider.Divisors.Length; i++) { var divisor = divider.Divisors[i]; // slice volume along our division axis, slicing off [magnitude] volume or [magnitude]% of the volume available for relative divisions Vector3 dividendSpan = Vector3.zero; dividendSpan[(int)divider.DivisionAxis] = divisor.IsAbsolute ? divisor.Magnitude : Bounds.size[(int)divider.DivisionAxis] * divisor.Magnitude; // compute dividend volume's center; just move from frontier point (min) to terminal point (max) along the division axis var dividendCenter = frontierPoint + (Rotation * (dividendSpan / 2f)); var s = Bounds.size; s[(int)divider.DivisionAxis] = dividendSpan[(int)divider.DivisionAxis]; var proposedBounds = new Bounds(dividendCenter, s); dividends[i] = new CubeProductionScope(SnapBoundsToSnapPlanes(divider.DivisionAxis, SelectSnapPlanes(divider.DivisionAxis, divider.SnapToPlanes), proposedBounds), Rotation); if (!string.IsNullOrEmpty(divisor.SnapPlaneKey)) { // add another snap plane to the module AddSnapPlane(divider.DivisionAxis, divisor.SnapPlaneKey, dividends[i].Bounds); } if (dividends[i].Bounds.size.x <= 0 || dividends[i].Bounds.size.y <= 0 || dividends[i].Bounds.size.z <= 0) { Debug.Log("Dividing to a negative size..."); } // update frontier point frontierPoint = frontierPoint + Rotation * dividendSpan; } return(dividends); }
public PrismProductionScope(ProductionScope parent) : base(parent) { }
protected ProductionScope(ProductionScope parent) { Bounds = parent.Bounds; Rotation = parent.Rotation; }
/// <summary> /// Create scopes for each repetition of the repeat production. /// Add snap planes at the replicand bounds if a snap id is given in the repeater. /// If any snap planes in the selector list are found within a replicand scope, snap the bounds to match the nearest snap plane of that selector type. /// /// Some replicand scopes may vary in size depending on the volume remainder and a specified remainder mode. /// Remainders below RepeatEpsilon epsilon are always distributed (to avoid teeny-tiny inserts). /// </summary> /// <param name="repeater"> </param> /// <returns></returns> public override ProductionScope[] Repeat(RepeatProduction repeater) { if (repeater.Magnitude > Bounds.size[(int)repeater.RepetitionAxis] || Math.Abs(repeater.Magnitude - 0) < Mathf.Epsilon) { throw new Exception("Repetition length is invalid."); } var repetitionAxisExtent = Vector3.zero; repetitionAxisExtent[(int)repeater.RepetitionAxis] = Bounds.extents[(int)repeater.RepetitionAxis]; var frontierPoint = Bounds.center - Rotation * (repetitionAxisExtent); var repetitions = Bounds.size[(int)repeater.RepetitionAxis] / repeater.Magnitude; var repRemainder = repetitions - (int)repetitions; Vector3 firstRepSize; var replicandSize = Vector3.zero; Vector3 lastRepSize; ProductionScope[] replicands; if (repeater.RemainderMode == RepeatRemainderMode.DistributeRemainder || repRemainder < RepetitionEpsilon) { // evenly distribute remainder (if any) to replicands replicands = new ProductionScope[(int)repetitions]; replicandSize[(int)repeater.RepetitionAxis] = Bounds.size[(int)repeater.RepetitionAxis] / repetitions; firstRepSize = replicandSize; lastRepSize = replicandSize; } else { replicandSize[(int)repeater.RepetitionAxis] = repeater.Magnitude; firstRepSize = replicandSize; lastRepSize = replicandSize; if (repeater.RemainderMode == RepeatRemainderMode.MergeFirst || repeater.RemainderMode == RepeatRemainderMode.MergeLast || repeater.RemainderMode == RepeatRemainderMode.MergeFirstAndLast) { replicands = new ProductionScope[(int)repetitions]; if (repeater.RemainderMode == RepeatRemainderMode.MergeFirst) { firstRepSize[(int)repeater.RepetitionAxis] = replicandSize[(int)repeater.RepetitionAxis] + Bounds.size[(int)repeater.RepetitionAxis] % repeater.Magnitude; } else if (repeater.RemainderMode == RepeatRemainderMode.MergeLast) { lastRepSize[(int)repeater.RepetitionAxis] = replicandSize[(int)repeater.RepetitionAxis] + Bounds.size[(int)repeater.RepetitionAxis] % repeater.Magnitude; } else // if (repeater.RemainderMode == RepeatRemainderMode.MergeFirstAndLast) { firstRepSize[(int)repeater.RepetitionAxis] = replicandSize[(int)repeater.RepetitionAxis] + (Bounds.size[(int)repeater.RepetitionAxis] % repeater.Magnitude / 2); lastRepSize[(int)repeater.RepetitionAxis] = replicandSize[(int)repeater.RepetitionAxis] + (Bounds.size[(int)repeater.RepetitionAxis] % repeater.Magnitude / 2); } } else { //if (repeater.RemainderMode == RepeatRemainderMode.InsertFirst || repeater.RemainderMode == RepeatRemainderMode.InsertLast || repeater.RemainderMode == RepeatRemainderMode.InsertFirstAndLast) replicands = new ProductionScope[(int)repetitions + 1]; if (repeater.RemainderMode == RepeatRemainderMode.InsertFirst) { // insert replicand for remainder at first position firstRepSize[(int)repeater.RepetitionAxis] = Bounds.size[(int)repeater.RepetitionAxis] % repeater.Magnitude; } else if (repeater.RemainderMode == RepeatRemainderMode.InsertLast) { // insert replicand for remainder at last position lastRepSize[(int)repeater.RepetitionAxis] = Bounds.size[(int)repeater.RepetitionAxis] % repeater.Magnitude; } else //if (repeater.RemainderMode == RepeatRemainderMode.InsertFirstAndLast) { // insert replicands for remainder at first and last positions replicands = new ProductionScope[(int)repetitions + 2]; firstRepSize[(int)repeater.RepetitionAxis] = Bounds.size[(int)repeater.RepetitionAxis] % repeater.Magnitude / 2; lastRepSize[(int)repeater.RepetitionAxis] = Bounds.size[(int)repeater.RepetitionAxis] % repeater.Magnitude / 2; } } } for (var i = 0; i < replicands.Length; ++i) { Vector3 replicandCenter; Bounds proposedBounds; if (i == 0) { replicandCenter = frontierPoint + Rotation * (firstRepSize / 2f); frontierPoint = frontierPoint + Rotation * (firstRepSize); var s = Bounds.size; s[(int)repeater.RepetitionAxis] = firstRepSize[(int)repeater.RepetitionAxis]; proposedBounds = new Bounds(replicandCenter, s); } else if (i == replicands.Length - 1) { replicandCenter = frontierPoint + Rotation * (lastRepSize / 2f); frontierPoint = frontierPoint + Rotation * (lastRepSize); var s = Bounds.size; s[(int)repeater.RepetitionAxis] = lastRepSize[(int)repeater.RepetitionAxis]; proposedBounds = new Bounds(replicandCenter, s); } else { // compute dividend volume's center; just move from frontier point (min) to terminal point (max) along the division axis replicandCenter = frontierPoint + Rotation * (replicandSize / 2f); frontierPoint = frontierPoint + Rotation * (replicandSize); var s = Bounds.size; s[(int)repeater.RepetitionAxis] = replicandSize[(int)repeater.RepetitionAxis]; proposedBounds = new Bounds(replicandCenter, s); } // todo: will also need to update frontier point in a case where bounds get snapped to some plane replicands[i] = new CubeProductionScope( SnapBoundsToSnapPlanes(repeater.RepetitionAxis, SelectSnapPlanes(repeater.RepetitionAxis, repeater.SnapToPlanes), proposedBounds), Rotation); if (!string.IsNullOrEmpty(repeater.SnapPlaneKey)) { // add another snap plane to the module AddSnapPlane(repeater.RepetitionAxis, repeater.SnapPlaneKey, replicands[i].Bounds); } } return(replicands); }
public CubeProductionScope(ProductionScope parent) : base(parent) { }
public CylinderProductionScope(ProductionScope parent) : base(parent) { }