// whether freePin's desired location overlaps static pin's actual location private static bool PinOverlap(GroupPin freePin, GroupPin againstPin) { // consider a pin's y interval is (pinY - PinNodeMargin, pinY + PinNodeHeight +PinNodeMargin) top down // freePin overlaps againstPin if the two intervals overlap var freePinInterval = new Pair<int, int>(freePin.DesiredLocation.Y - CircuitGroupPinInfo.FloatingPinNodeMargin, freePin.DesiredLocation.Y + CircuitGroupPinInfo.FloatingPinNodeHeight + CircuitGroupPinInfo.FloatingPinNodeMargin); var pinInterval = new Pair<int, int>(againstPin.Bounds.Location.Y - CircuitGroupPinInfo.FloatingPinNodeMargin, againstPin.Bounds.Location.Y + CircuitGroupPinInfo.FloatingPinNodeHeight + CircuitGroupPinInfo.FloatingPinNodeMargin); // two intervals i1 = (s1, e1) and i2 = (s2, e2) overlap if and only if s2 < e1 and s1 < e2 return ((pinInterval.First < freePinInterval.Second) && // s2 < e1 (freePinInterval.First < pinInterval.Second)); //s1 < e2 }
/// <summary> /// Propagate up group pin name changes to the parent pin (only need to take care of non-default name, /// the default names are auto-updated in Group.UpdateGroupPins())</summary> private void UpdateParentGroupPinName(bool inputSide, GroupPin childPin) { var parentGrpPin = childPin.GetAncestry(inputSide).FirstOrDefault(); if (parentGrpPin != null) { if (!childPin.IsDefaultName && parentGrpPin.IsDefaultName) { parentGrpPin.Name = childPin.Name; parentGrpPin.IsDefaultName = false; } } }
/// <summary> /// Resolve pin node position to avoid colliding with any node in againstPinNodes</summary> /// <param name="againstPinNodes">List of GroupPins to avoid collision with</param> /// <param name="floatingPin">Floating pin to adjust: use its DesiredLocation to check collisions and its ActualLocation will be set upon return</param> /// <param name="minY">Minimum Y value the floating pin is allowed to take</param> private void PositioningFloatigPin(IList<GroupPin> againstPinNodes, GroupPin floatingPin, int minY) { // resolve pin node position to avoid colliding with any against-pins bool overlapped = false; for (int p = 0; p < againstPinNodes.Count; ++p) // try to locate sufficient empty space between the static nodes { var againstpin = againstPinNodes[p]; if (againstpin.Bounds.Location.Y + CircuitGroupPinInfo.FloatingPinNodeHeight + CircuitGroupPinInfo.FloatingPinNodeMargin < minY) continue; if (PinOverlap(floatingPin, againstpin)) { overlapped = true; // find next suitable place from p down (note againstPinNodes y-ascending order, i.e. higher notes appear first) for (int j = p; j < againstPinNodes.Count - 1; ++j) { if (againstPinNodes[j+1].Bounds.Location.Y - againstPinNodes[j ].Bounds.Location.Y >= 2 * (CircuitGroupPinInfo.FloatingPinNodeHeight + CircuitGroupPinInfo.FloatingPinNodeMargin)) { // find empty space >= pin node height + margin // place the floating pin just above static pin j int pinNewY = Constrain(againstPinNodes[j].Bounds.Location.Y + CircuitGroupPinInfo.FloatingPinNodeHeight + CircuitGroupPinInfo.FloatingPinNodeMargin); floatingPin.Bounds = new Rectangle(floatingPin.Bounds.Location.X, pinNewY, floatingPin.Bounds.Width, floatingPin.Bounds.Height); return; } } } } if (overlapped) // no in-between empty space to insert, try at the top region first, then the bottom region { // top region var topStaticPin = againstPinNodes[0]; int pinNewY = Constrain(topStaticPin.Bounds.Location.Y - (CircuitGroupPinInfo.FloatingPinNodeHeight + CircuitGroupPinInfo.FloatingPinNodeMargin)); pinNewY = Math.Max(pinNewY, minY); floatingPin.DesiredLocation = new Point(floatingPin.DesiredLocation.X, pinNewY); if (pinNewY > minY && !PinOverlap(floatingPin, topStaticPin)) { floatingPin.Bounds = new Rectangle(floatingPin.Bounds.Location.X, pinNewY, floatingPin.Bounds.Width, floatingPin.Bounds.Height); } else // bottom region { var bottomStaticPin = againstPinNodes[againstPinNodes.Count - 1]; pinNewY = Constrain(bottomStaticPin.Bounds.Location.Y + (CircuitGroupPinInfo.FloatingPinNodeHeight + CircuitGroupPinInfo.FloatingPinNodeMargin)); pinNewY = Math.Max(pinNewY, minY); floatingPin.DesiredLocation = new Point(floatingPin.DesiredLocation.X, pinNewY); const int increment = 1; while (PinOverlap(floatingPin, bottomStaticPin)) { pinNewY += increment; floatingPin.DesiredLocation = new Point(floatingPin.DesiredLocation.X, pinNewY); } floatingPin.Bounds = new Rectangle(floatingPin.Bounds.Location.X, pinNewY, floatingPin.Bounds.Width, floatingPin.Bounds.Height); } } else // the disired location turns out just fine { floatingPin.Bounds = new Rectangle(floatingPin.Bounds.Location.X, Constrain(floatingPin.DesiredLocation.Y), floatingPin.Bounds.Width, floatingPin.Bounds.Height); } }