public Point NextFreePosition0(Point start, Size sizeNeeded, Dimension dimension, IEnumerable <TItem> ignore, double distance) { var result = new Rectangle(start, sizeNeeded); var loc = new GraphSceneItemShapeLocator <TItem, TEdge> { GraphScene = this.GraphScene }; var measure = new MeasureVisitBuilder <TItem> (loc); var iRect = result; while (!iRect.IsEmpty) { var elems = GraphScene.ElementsIn(iRect).Where(e => !(e is TEdge)).Except(ignore); if (!elems.Any()) { break; } Action <TItem> visit = null; var frect = measure.Bounds(ref visit); foreach (var item in elems) { visit(item); } iRect = frect(); if (!iRect.IsEmpty) { iRect = new Rectangle(new Point(iRect.Right + distance, result.Top), sizeNeeded); result = iRect; } } return(result.Location); }
protected Rectangle ReportExtent(IEnumerable <IVisual> elms, ILocator <IVisual> locator, AlignerOptions options) { var measure = new MeasureVisitBuilder <IVisual> (locator); Action <IVisual> visit = null; var fSizeToFit = measure.SizeToFit(ref visit, options.Distance, options.Dimension); var fBounds = measure.Bounds(ref visit); var fMinSize = measure.MinSize(ref visit); elms.ForEach(e => visit(e)); ReportDetail("Bounds {1}\tSizeToFit {0}\tMinSize {2}", fSizeToFit(), fBounds(), fMinSize()); return(fBounds()); }
public virtual Rectangle AlignByPath <TItem, TEdge> (IEnumerable <LevelItem <TItem> > walk, AlignerOptions options, Aligner <TItem, TEdge> aligner, Point startPoint) where TEdge : IEdge <TItem>, TItem { var bounds = new Rectangle(startPoint, Size.Zero); // contains levelitems with backtracked path var trackedSteps = new Dictionary <TItem, LevelItem <TItem> > (); // used to backtrack path var steps = new Dictionary <TItem, LevelItem <TItem> > (); var trackBounds = new Dictionary <TItem, Rectangle> (); var trackBoundsToken = new HashSet <TItem> (); Func <TItem, TEdge> asEdge = node => node is TEdge ? (TEdge)node : default(TEdge); Func <TItem, bool> isVisibleNode = node => !(node is TEdge); Func <LevelItem <TItem>, TItem> findPath = step => { var visibleNode = isVisibleNode(step.Node); while (step.Path != null) { if (isVisibleNode(step.Path)) { return(step.Path); } if ((step.Node as IEdge <TItem>).IsEdgeOfEdges()) { return(step.Path); } if ((step.Path as IEdge <TItem>).IsEdgeOfEdges()) { return(step.Path); } if (step.StepIsEdgeToEdge() && visibleNode) { return(step.Node); } if (trackBounds.ContainsKey(step.Path)) { return(step.Path); } step = steps [step.Path]; } TrackBounds = trackBounds.Values; return(step.Path); }; // steps up the paths and sums the size of trackBounds Action <LevelItem <TItem>, Rectangle> sumTrackBounds = (trackedStep, trackBound) => { var adjDimension = options.Dimension.Adjacent(); while (trackedStep.Path != null) { var trackStep = trackedSteps [trackedStep.Path]; if (trackStep.Path != null) { var backTrackBound = trackBounds [trackStep.Path].MaxExtend(trackBound, adjDimension); trackBounds [trackStep.Path] = backTrackBound; trackBound = backTrackBound; } trackedStep = trackStep; } }; // gets the trackBounds of the trackedStep.Path; ensures that the path has trackBounds Func <LevelItem <TItem>, Rectangle, Rectangle> getTrackBounds = (trackedStep, trackBound) => { while (trackedStep.Path != null) { var gb = new Rectangle(); if (trackBounds.TryGetValue(trackedStep.Path, out gb)) { return(gb); } else { // TODO: ensure that all paths have trackBounds, not only the first uppath var trackStep = trackedSteps [trackedStep.Path]; if (trackStep.Path != null) { var backTrackBound = trackBounds [trackStep.Path]; trackBound.X = backTrackBound.Right; trackBound.Y = backTrackBound.Bottom; } trackBounds [trackedStep.Path] = trackBound; break; } } return(trackBound); }; foreach (var step in walk) { steps.Add(step.Node, step); var visibleNode = isVisibleNode(step.Node); var nonAdjacent = !step.StepIsAdjacent(); var isStepEdgeToEdge = step.StepIsEdgeToEdge(); var isNodeEdgeOfEdges = (step.Node as IEdge <TItem>).IsEdgeOfEdges(); var trackedStep = new LevelItem <TItem> (step.Node, findPath(step), step.Level); trackedSteps [step.Node] = trackedStep; ReportDetail($"\t{trackedStep}"); if (!(visibleNode || isStepEdgeToEdge)) { continue; } var gb = new Rectangle(startPoint, options.Distance.InitSum(options.Dimension)); var trackBound = new Rectangle(startPoint, new Size()); if (trackedStep.Path != null) { trackBound = getTrackBounds(trackedStep, gb); gb.X = trackBound.Right; gb.Y = trackBound.Bottom; } if (isStepEdgeToEdge) { trackBounds [step.Node] = new Rectangle(gb.Location, new Size()); ReportDetail($"{step.Node}\t{trackBounds [step.Node]}\t{trackedStep.Path}\t{trackBound}"); } if (visibleNode) { var loc = gb.Location; var nodeBounds = aligner.MeasureItem(step.Node, options.Dimension, options.Distance, ref gb); nodeBounds.Location = gb.Location.Max(loc); aligner.Locator.SetLocation(step.Node, nodeBounds.Location); trackBounds [step.Node] = new Rectangle(nodeBounds.Location, gb.Size.InitSum(options.Dimension)); if (trackedStep.Path != null) { trackBound.Size = trackBound.Size.SumSize(nodeBounds.Size + options.Distance, options.Dimension.Adjacent()); trackBounds [trackedStep.Path] = trackBound; trackBoundsToken.Add(trackedStep.Path); } ReportDetail($"{step.Node}\t{nodeBounds}\t{trackedStep.Path}\t{trackBound}"); } sumTrackBounds(trackedStep, trackBound); } // aligns foreach (var trackBound in trackBounds.ToArray()) { if (trackBound.Value.Width == 0) { trackBounds [trackBound.Key] = new Rectangle(trackBound.Value.Location, new Size(options.Distance.Width / 2, trackBound.Value.Height)); } } foreach (var kvp in trackBounds.ToArray()) { var step = trackedSteps [kvp.Key]; if (step.Path == null) { continue; } var lbounds = kvp.Value; var sum = 0d; while (step.Path != null) { var trackBound = trackBounds [step.Path]; sum = Math.Max(trackBound.Right, sum); step = trackedSteps [step.Path]; } if (lbounds.X != sum) { trackBounds [kvp.Key] = new Rectangle(new Point(sum, lbounds.Y), lbounds.Size); } } Action <TItem> visitMeasure = null; var measure = new MeasureVisitBuilder <TItem> (aligner.Locator); var fBounds = measure.Bounds(ref visitMeasure); foreach (var step in trackedSteps.Values.Where(l => !(l.Node is TEdge))) { var nodeBounds = trackBounds [step.Node]; var loc = aligner.Locator.GetLocation(step.Node); var size = aligner.Locator.GetSize(step.Node); if (options.Dimension == Dimension.X) { if (nodeBounds.Height != 0) { loc.Y += options.AlignY.Delta(nodeBounds.Height - options.Distance.Height, size.Height);; } loc.X = nodeBounds.X; } else { if (nodeBounds.Width != 0) { loc.X += options.AlignX.Delta(nodeBounds.Width - options.Distance.Width, size.Width); } loc.Y = nodeBounds.Y; } aligner.Locator.SetLocation(step.Node, loc); visitMeasure(step.Node); } bounds = fBounds(); return(bounds); }