/// <summary> /// Initializes the positions of the vertices. Assign a random position inside the 'bounding box' to the vertices without positions. /// It does NOT modify the position of the other vertices. /// /// It generates an <code>IterationEnded</code> event. /// /// Bounding box: /// x coordinates: double.Epsilon - <code>width</code> /// y coordinates: double.Epsilon - <code>height</code> /// </summary> /// <param name="width">Width of the bounding box.</param> /// <param name="height">Height of the bounding box.</param> /// <param name="translate_x">Translates the generated x coordinate.</param> /// <param name="translate_y">Translates the generated y coordinate.</param> protected virtual void InitializeWithRandomPositions(double width, double height, double translate_x, double translate_y) { var rnd = new Random(Parameters.Seed); //initialize with random position foreach (TVertex v in VisitedGraph.Vertices) { //for vertices without assigned position if (!VertexPositions.ContainsKey(v)) { if (EnsureUniqueRandomInitialPositions) { Point newPoint; do { newPoint = new Point( Math.Max(double.Epsilon, rnd.NextDouble() * width + translate_x), Math.Max(double.Epsilon, rnd.NextDouble() * height + translate_y)); } while (VertexPositions.Values.Contains(newPoint)); VertexPositions[v] = newPoint; } else { VertexPositions[v] = new Point( Math.Max(double.Epsilon, rnd.NextDouble() * width + translate_x), Math.Max(double.Epsilon, rnd.NextDouble() * height + translate_y)); } } } }
public void Dispose() { Graph = default(TGraph); VertexPositions.Clear(); VisibleEdges.Clear(); AlgorithmStorage = null; }
/// <summary> /// Initializes the data of the compound vertices. /// </summary> /// <param name="vertexBorders">Dictionary of the border thicknesses.</param> /// <param name="vertexSizes">Dictionary of the vertex sizes.</param> /// <param name="layoutTypes">Dictionary of the layout types.</param> /// <param name="movableParentUpdateQueue">The compound vertices with fixed layout /// should be added to this queue.</param> private void InitCompoundVertices( IDictionary <TVertex, Thickness> vertexBorders, IDictionary <TVertex, Size> vertexSizes, IDictionary <TVertex, CompoundVertexInnerLayoutType> layoutTypes, Queue <TVertex> movableParentUpdateQueue) { for (int i = _levels.Count - 1; i >= 0; i--) { foreach (var vertex in _levels[i]) { if (!_compoundGraph.IsCompoundVertex(vertex)) { continue; } //get the data of the vertex Thickness border; vertexBorders.TryGetValue(vertex, out border); Size vertexSize; vertexSizes.TryGetValue(vertex, out vertexSize); var layoutType = CompoundVertexInnerLayoutType.Automatic; layoutTypes.TryGetValue(vertex, out layoutType); if (layoutType == CompoundVertexInnerLayoutType.Fixed) { movableParentUpdateQueue.Enqueue(vertex); } var position = new Point(); VertexPositions.TryGetValue(vertex, out position); //create the information container for this compound vertex var dataContainer = new CompoundVertexData(vertex, _rootCompoundVertex, false, position, vertexSize, border, layoutType); if (i == 0) { dataContainer.Parent = _rootCompoundVertex; _rootCompoundVertex.Children.Add(dataContainer); } _compoundVertexDatas[vertex] = dataContainer; _vertexDatas[vertex] = dataContainer; //add the datas of the childrens var children = _compoundGraph.GetChildrenVertices(vertex); var childrenData = children.Select(v => _vertexDatas[v]).ToList(); dataContainer.Children = childrenData; foreach (var child in dataContainer.Children) { _rootCompoundVertex.Children.Remove(child); child.Parent = dataContainer; } } } }
/// <summary> /// It computes the layout of the vertices. /// </summary> public override void Compute(CancellationToken cancellationToken) { if (VisitedGraph.VertexCount == 1) { VertexPositions.Add(VisitedGraph.Vertices.First(), new Point(0, 0)); return; } //initializing the positions if (Parameters is BoundedFRLayoutParameters) { var param = Parameters as BoundedFRLayoutParameters; InitializeWithRandomPositions(param.Width, param.Height); _maxWidth = param.Width; _maxHeight = param.Height; } else { InitializeWithRandomPositions(1000.0, 1000.0); } Parameters.VertexCount = VisitedGraph.VertexCount; // Actual temperature of the 'mass'. Used for cooling. var minimalTemperature = Parameters.InitialTemperature * 0.01; _temperature = Parameters.InitialTemperature; for (int i = 0; i < Parameters._iterationLimit && _temperature > minimalTemperature; i++) { IterateOne(cancellationToken); //make some cooling switch (Parameters._coolingFunction) { case FRCoolingFunction.Linear: _temperature *= (1.0 - i / (double)Parameters._iterationLimit); break; case FRCoolingFunction.Exponential: _temperature *= Parameters._lambda; break; } //iteration ended, do some report /*if (ReportOnIterationEndNeeded) * { * double statusInPercent = (double)i / (double)Parameters._iterationLimit; * OnIterationEnded(i, statusInPercent, string.Empty, true); * }*/ } }
protected override Point OnOriginalPosition(YodiiGraphVertex v, Point p) { // Keep existing positions if (p.IsValid()) { return(p); } Point newPoint = new Point(0, 0); if (VertexPositions == null) { return(newPoint); } if (v.IsService) { if (v.LabServiceInfo.ServiceInfo.Generalization != null) { // Find & get point of generalization var generalizationQuery = VertexPositions.Where(kvp => kvp.Key.IsService && kvp.Key.LabServiceInfo.ServiceInfo == v.LabServiceInfo.ServiceInfo.Generalization); if (generalizationQuery.Count() > 0) { Point generalizationPoint = generalizationQuery.First().Value; if (generalizationPoint.IsValid()) { newPoint.X = generalizationPoint.X; newPoint.Y = generalizationPoint.Y + VERTICAL_MARGIN_SIZE; } } } } else if (v.IsPlugin) { if (v.LabPluginInfo.PluginInfo.Service != null) { // Find & get point of service var serviceQuery = VertexPositions.Where(kvp => kvp.Key.IsService && kvp.Key.LabServiceInfo.ServiceInfo == v.LabPluginInfo.PluginInfo.Service); if (serviceQuery.Count() > 0) { Point generalizationPoint = serviceQuery.First().Value; if (generalizationPoint.IsValid()) { newPoint.X = generalizationPoint.X; newPoint.Y = generalizationPoint.Y + VERTICAL_MARGIN_SIZE; } } } } return(newPoint); }
public override void Compute(CancellationToken cancellationToken) { if (VisitedGraph.VertexCount == 1) { if (!VertexPositions.ContainsKey(VisitedGraph.Vertices.First())) { VertexPositions.Add(VisitedGraph.Vertices.First(), new Point(0, 0)); } return; } //initialize vertex positions InitializeWithRandomPositions(Parameters.Width, Parameters.Height); //initialize ISOM data foreach (var vertex in VisitedGraph.Vertices) { ISOMData isomData; if (!_isomDataDict.TryGetValue(vertex, out isomData)) { isomData = new ISOMData(); _isomDataDict[vertex] = isomData; } } _radius = Parameters.InitialRadius; var rnd = new Random(Parameters.Seed); for (var epoch = 0; epoch < Parameters.MaxEpoch; epoch++) { cancellationToken.ThrowIfCancellationRequested(); Adjust(cancellationToken, rnd); //Update Parameters var factor = Math.Exp(-1 * Parameters.CoolingFactor * (1.0 * epoch / Parameters.MaxEpoch)); _adaptation = Math.Max(Parameters.MinAdaption, factor * Parameters.InitialAdaption); if (_radius > Parameters.MinRadius && epoch % Parameters.RadiusConstantTime == 0) { _radius--; } //report /*if ( ReportOnIterationEndNeeded ) * OnIterationEnded( epoch, (double)epoch / (double)Parameters.MaxEpoch, "Iteration " + epoch + " finished.", true ); * else if (ReportOnProgressChangedNeeded) * OnProgressChanged( (double)epoch / (double)Parameters.MaxEpoch * 100 );*/ } }
public override void Compute(CancellationToken cancellationToken) { InitTheGraph(); //first step DoPreparing(); BuildSparseNormalizedGraph(cancellationToken); DoCrossingMinimizations(cancellationToken); CalculatePositions(); var offsetY = 0d; if (Parameters.Direction == LayoutDirection.LeftToRight) { offsetY = VertexPositions.Values.Min(p => p.X); if (offsetY < 0) { offsetY = -offsetY; } foreach (var item in VertexPositions.ToDictionary(a => a.Key, b => b.Value)) { VertexPositions[item.Key] = new Point(item.Value.Y * 1.5 + 0, item.Value.X + offsetY); } } if (Parameters.Direction == LayoutDirection.RightToLeft) { offsetY = VertexPositions.Values.Min(p => p.X); if (offsetY < 0) { offsetY = -offsetY; } foreach (var item in VertexPositions.ToDictionary(a => a.Key, b => b.Value)) { VertexPositions[item.Key] = new Point(-item.Value.Y * 1.5, -item.Value.X + offsetY); } } if (Parameters.Direction == LayoutDirection.BottomToTop) { foreach (var item in VertexPositions.ToDictionary(a => a.Key, b => b.Value)) { VertexPositions[item.Key] = new Point(item.Value.X, -item.Value.Y); } } DoEdgeRouting(offsetY); }
private void ArrangeRectangle(Rect rectangle, int groupId, Rect originalRect) { var offsetX = rectangle.X - originalRect.X; var offsetY = rectangle.Y - originalRect.Y; VertexPositions.Where(a => a.Key.GroupId == groupId).Select(a => a.Key).ToList().ForEach(a => { VertexPositions[a] = new Point(VertexPositions[a].X + offsetX, VertexPositions[a].Y + offsetY); }); var gp = _params.GroupParametersList.FirstOrDefault(a => a.GroupId == groupId); if (gp == null) { throw new GX_ObjectNotFoundException("Grouped graph -> Can't find group data after calc!"); } gp.ZoneRectangle = rectangle; }
protected override void InitializeWithRandomPositions(double width, double height, double translate_x, double translate_y) { var rnd = GetRandomWithCurrentSeed(); //initialize with random position foreach (TVertex v in VisitedGraph.Vertices) { //for vertices without assigned position if (!VertexPositions.ContainsKey(v)) { VertexPositions[v] = new Point( Math.Max(double.Epsilon, rnd.NextDouble() * width + translate_x), Math.Max(double.Epsilon, rnd.NextDouble() * height + translate_y)); } } }
/// <summary> /// Initializes the positions of the vertices. Assign a random position inside the 'bounding box' to the vertices without positions. /// It does NOT modify the position of the other vertices. /// /// It generates an <code>IterationEnded</code> event. /// /// Bounding box: /// x coordinates: double.Epsilon - <code>width</code> /// y coordinates: double.Epsilon - <code>height</code> /// </summary> /// <param name="width">Width of the bounding box.</param> /// <param name="height">Height of the bounding box.</param> /// <param name="translate_x">Translates the generated x coordinate.</param> /// <param name="translate_y">Translates the generated y coordinate.</param> protected virtual void InitializeWithRandomPositions(double width, double height, double translate_x, double translate_y) { var rnd = new Random(DateTime.Now.Millisecond); //initialize with random position foreach (TVertex v in VisitedGraph.Vertices) { //for vertices without assigned position if (!VertexPositions.ContainsKey(v)) { VertexPositions[v] = new Point( Math.Max(double.Epsilon, rnd.NextDouble() * width + translate_x), Math.Max(double.Epsilon, rnd.NextDouble() * height + translate_y)); } } }
/// <summary> /// Initializes the data of the simple vertices. /// </summary> /// <param name="vertexSizes">Dictionary of the vertex sizes.</param> private void InitSimpleVertices(IDictionary <TVertex, Size> vertexSizes) { foreach (var vertex in _compoundGraph.SimpleVertices) { Size vertexSize; vertexSizes.TryGetValue(vertex, out vertexSize); var position = new Point(); VertexPositions.TryGetValue(vertex, out position); //create the information container for this simple vertex var dataContainer = new SimpleVertexData(vertex, _rootCompoundVertex, false, position, vertexSize); dataContainer.Parent = _rootCompoundVertex; _simpleVertexDatas[vertex] = dataContainer; _vertexDatas[vertex] = dataContainer; _rootCompoundVertex.Children.Add(dataContainer); } }
public IDictionary <HyperEdge, Point[]> RouteEdges() { var edges = Graph.HyperEdges; var resDict = new Dictionary <HyperEdge, Point[]>(); foreach (var edge in edges) { var vertexPositions = VertexPositions .Where(pair => edge.Vertices.Contains(pair.Key)) .Select(pair => pair.Value).ToList(); var medianPoint = new Point { X = vertexPositions.Average(p => p.X), Y = vertexPositions.Average(p => p.Y) }; resDict.Add(edge, vertexPositions.Append(medianPoint).ToArray()); } return(resDict); }
protected override void InternalCompute() { if (_graph.VertexCount == 0) { return; } if (_graph.VertexCount == 1) { VertexPositions.Clear(); VertexPositions[_graph.Vertices.First().Original] = new Point(0, 0); return; } // //Phase 1 - Filters & Removals // FiltersAndRemovals(); _statusInPercent = percentOfPreparation; // //Phase 2 - Layer assignment // AssignLayers(); // //Phase 3 - Crossing reduction // PrepareForSugiyama(); SugiyamaLayout(); _statusInPercent = percentOfPreparation + percentOfSugiyama; // //Phase 4 - Horizontal position assignment // CopyPositions(); OnIterationEnded("Position adjusting finished"); //Phase 5 - Incremental extension, add vertices connected with only general edges //IncrementalExtensionImproved(); _statusInPercent = percentOfPreparation + percentOfSugiyama + percentOfIncrementalExtension; _statusInPercent = 100; }
public override void Compute(CancellationToken cancellationToken) { if (_graph.VertexCount == 0) { return; } if (_graph.VertexCount == 1) { VertexPositions.Clear(); VertexPositions[_graph.Vertices.First().Original] = new Point(0, 0); return; } // //Phase 1 - Filters & Removals // FiltersAndRemovals(); _statusInPercent = PERCENT_OF_PREPARATION; // //Phase 2 - Layer assignment // AssignLayers(); // //Phase 3 - Crossing reduction // PrepareForSugiyama(cancellationToken); SugiyamaLayout(cancellationToken); _statusInPercent = PERCENT_OF_PREPARATION + PERCENT_OF_SUGIYAMA; // //Phase 4 - Horizontal position assignment // CopyPositions(cancellationToken); OnIterationEnded("Position adjusting finished"); //Phase 5 - Incremental extension, add vertices connected with only general edges //IncrementalExtensionImproved(); _statusInPercent = PERCENT_OF_PREPARATION + PERCENT_OF_SUGIYAMA + PERCENT_OF_INCREMENTAL_EXTENSION; _statusInPercent = 100; }
public override void Compute(CancellationToken cancellationToken) { VertexPositions.Clear(); var bounds = _parameters == null ? new RandomLayoutAlgorithmParams().Bounds : _parameters.Bounds; var boundsWidth = (int)bounds.Width; var boundsHeight = (int)bounds.Height; var seed = _parameters == null?Guid.NewGuid().GetHashCode() : _parameters.Seed; var rnd = new Random(seed); foreach (var item in VisitedGraph.Vertices) { if (item.SkipProcessing != ProcessingOptionEnum.Freeze || VertexPositions.Count == 0) { var x = (int)bounds.X; var y = (int)bounds.Y; var size = VertexSizes.FirstOrDefault(a => a.Key == item).Value; VertexPositions.Add(item, new Point(rnd.Next(x, x + boundsWidth - (int)size.Width), rnd.Next(y, y + boundsHeight - (int)size.Height))); } } }
protected override void Initialize() { VertexPositions.Initialize(); EventInput.Initialize(Window); Blocks.InitialzizeBlocks(); _graphics.PreferredBackBufferWidth = Config.Width; _graphics.PreferredBackBufferHeight = Config.Height; if (!Config.VSync) { IsFixedTimeStep = false; _graphics.SynchronizeWithVerticalRetrace = false; } _graphics.ApplyChanges(); _camera = new Camera(0.3f, 0.002f, GraphicsDevice); //move speed, rotate speed, ... _spriteBatch = new SpriteBatch(GraphicsDevice); _statistics = new StatisticOverlay(Content.Load <SpriteFont>("NormalFont"), new Vector2(48, 48)); //debug _mainMenu = new MainMenu(Content); base.Initialize(); }
public override void Compute(CancellationToken cancellationToken) { var groups = _params.GroupParametersList.Select(a => a.GroupId).OrderByDescending(a => a).ToList(); var listRect = new Dictionary <object, Rect>(); foreach (var group in groups) { cancellationToken.ThrowIfCancellationRequested(); var groupId = group; var gp = _params.GroupParametersList.First(a => a.GroupId == groupId); //get vertices of the same group //var vertices = new List<TVertex>(); var vertices = VisitedGraph.Vertices.Where(a => a.GroupId == groupId).ToList(); //skip processing if there are no vertices in this group if (vertices.Count == 0) { continue; } //get edges between vertices in the same group var edges = VisitedGraph.Edges.Where(a => a.Source.GroupId == a.Target.GroupId && a.Target.GroupId == groupId).ToList(); //create and compute graph for a group var graph = GenerateGroupGraph(vertices, edges); //inject custom vertex and edge set into existing algorithm gp.LayoutAlgorithm.ResetGraph(graph.Vertices, graph.Edges); //assign vertex sizes to internal algorithm if needed if (gp.LayoutAlgorithm.NeedVertexSizes) { gp.LayoutAlgorithm.VertexSizes = VertexSizes.Where(a => a.Key.GroupId == groupId) .ToDictionary(a => a.Key, b => b.Value); } gp.LayoutAlgorithm.Compute(cancellationToken); //Move vertices to bound box if layout algorithm don't use bounds if (gp.ZoneRectangle.HasValue && !gp.IsAlgorithmBounded) { var offsetX = gp.ZoneRectangle.Value.X; var offsetY = gp.ZoneRectangle.Value.Y; gp.LayoutAlgorithm.VertexPositions.ForEach(a => { a.Value.Offset(offsetX, offsetY); }); } //write results to global positions storage double?[] left = { null }; double?[] top = { null }; double?[] right = { null }; double?[] bottom = { null }; gp.LayoutAlgorithm.VertexPositions.ForEach(a => { left[0] = left[0].HasValue ? (a.Value.X < left[0] ? a.Value.X : left[0]) : a.Value.X; var w = a.Value.X + VertexSizes[a.Key].Width; var h = a.Value.Y + VertexSizes[a.Key].Height; right[0] = right[0].HasValue ? (w > right[0] ? w : right[0]) : w; top[0] = top[0].HasValue ? (a.Value.Y < top[0] ? a.Value.Y : top[0]) : a.Value.Y; bottom[0] = bottom[0].HasValue ? (h > bottom[0] ? h : bottom[0]) : h; if (VertexPositions.ContainsKey(a.Key)) { VertexPositions[a.Key] = a.Value; } else { VertexPositions.Add(a.Key, a.Value); } }); if (_params.ArrangeGroups) { if (left[0] == null) { left[0] = 0; } if (right[0] == null) { right[0] = 0; } if (top[0] == null) { top[0] = 0; } if (bottom[0] == null) { bottom[0] = 0; } listRect.Add(gp.GroupId, gp.ZoneRectangle ?? new Rect(new Point(left[0].Value, top[0].Value), new Point(right[0].Value, bottom[0].Value))); } } if (_params.ArrangeGroups) { cancellationToken.ThrowIfCancellationRequested(); var origList = listRect.ToDictionary(a => a.Key, a => a.Value); var ora = _params != null && _params.OverlapRemovalAlgorithm != null ? _params.OverlapRemovalAlgorithm : new FSAAlgorithm <object>(listRect, new OverlapRemovalParameters { HorizontalGap = 10, VerticalGap = 10 }); ora.Initialize(listRect); ora.Compute(cancellationToken); cancellationToken.ThrowIfCancellationRequested(); ora.Rectangles.ForEach(a => { int group = (int)a.Key; //_params.GroupParametersList.FirstOrDefault(b => b.GroupId == (int)a.Key).ZoneRectangle = origList[a.Key]; ArrangeRectangle(a.Value, group, origList[a.Key]); }); } }
private void EdgeRoutingTest(TEdge ctrl) { //bad edge data check if (ctrl.Source.ID == -1 || ctrl.Target.ID == -1) { throw new GX_InvalidDataException("SimpleEdgeRouting() -> You must assign unique ID for each vertex to use SimpleER algo!"); } if (ctrl.Source.ID == ctrl.Target.ID || !VertexPositions.ContainsKey(ctrl.Target)) { return; } var start_point = VertexPositions[ctrl.Source]; // new Point(GraphAreaBase.GetX(ctrl.Source), GraphAreaBase.GetY(ctrl.Source)); var end_point = VertexPositions[ctrl.Target]; // new Point(GraphAreaBase.GetX(ctrl.Target), GraphAreaBase.GetY(ctrl.Target)); if (start_point == end_point) { return; } var originalSizes = getSizesCollection(ctrl, end_point); var CHECKLIST = new Dictionary <TVertex, KeyValuePair <TVertex, Rect> >(originalSizes); var leftSIZES = new Dictionary <TVertex, KeyValuePair <TVertex, Rect> >(originalSizes); var tempList = new List <Point>(); tempList.Add(start_point); bool HaveIntersections = true; //while we have some intersections - proceed while (HaveIntersections) { var cur_drawback = drawback_distance; while (true) { var item = CHECKLIST.Keys.FirstOrDefault(); //set last route point as current start point start_point = tempList.Last(); if (item == null) { //checked all vertices and no intersection was found - quit HaveIntersections = false; break; } else { var r = originalSizes[item].Value; Point checkpoint; //check for intersection point. if none found - remove vertex from checklist if (MathHelper.GetIntersectionPoint(r, start_point, end_point, out checkpoint) == -1) { CHECKLIST.Remove(item); continue; } var main_vector = new Vector(end_point.X - start_point.X, end_point.Y - start_point.Y); double X = 0; double Y = 0; //calculate drawback X coordinate if (start_point.X == checkpoint.X || Math.Abs(start_point.X - checkpoint.X) < cur_drawback) { X = start_point.X; } else if (start_point.X < checkpoint.X) { X = checkpoint.X - cur_drawback; } else { X = checkpoint.X + cur_drawback; } //calculate drawback Y coordinate if (start_point.Y == checkpoint.Y || Math.Abs(start_point.Y - checkpoint.Y) < cur_drawback) { Y = start_point.Y; } else if (start_point.Y < checkpoint.Y) { Y = checkpoint.Y - cur_drawback; } else { Y = checkpoint.Y + cur_drawback; } //set drawback checkpoint checkpoint = new Point(X, Y); bool isStartPoint = checkpoint == start_point; bool routeFound = false; bool viceversa = false; int counter = 1; var joint = new Point(); bool?blocked_direction = null; while (!routeFound) { //choose opposite vector side each cycle var signedDistance = viceversa ? side_distance : -side_distance; //get new point coordinate joint = new Point( checkpoint.X + signedDistance * counter * (main_vector.Y / main_vector.Length), checkpoint.Y - signedDistance * counter * (main_vector.X / main_vector.Length)); //now check if new point is in some other vertex var iresult = false; var forced_break = false; foreach (var sz in originalSizes) { if (sz.Value.Value.Contains(joint)) { iresult = true; //block this side direction if (blocked_direction == null) { blocked_direction = viceversa; } else { //both sides blocked - need to drawback forced_break = true; } break; } } if (forced_break) { break; } //get vector intersection if its ok if (!iresult) { iresult = MathHelper.IsIntersected(r, joint, end_point); } //if no vector intersection - we've found it! if (!iresult) { routeFound = true; blocked_direction = null; } else { //still have an intersection with current vertex HaveIntersections = true; //skip point search if too many attempts was made (bad logic hack) if (counter > 300) { break; } counter++; //switch vector search side if (blocked_direction == null || (blocked_direction == viceversa)) { viceversa = !viceversa; } } } //if blocked and this is not start point (nowhere to drawback) - then increase drawback distance if (blocked_direction != null && !isStartPoint) { //search has been blocked - need to drawback cur_drawback += drawback_distance; } else { //add new route point if we found it // if(routeFound) tempList.Add(joint); leftSIZES.Remove(item); } } //remove currently evaded obstacle vertex from the checklist CHECKLIST.Remove(item); } //assign possible left vertices as a new checklist if any intersections was found if (HaveIntersections) { CHECKLIST = new Dictionary <TVertex, KeyValuePair <TVertex, Rect> >(leftSIZES); } } //finally, add an end route point tempList.Add(end_point); if (EdgeRoutes.ContainsKey(ctrl)) { EdgeRoutes[ctrl] = tempList.Count > 2 ? tempList.ToArray() : null; } else { EdgeRoutes.Add(ctrl, tempList.Count > 2 ? tempList.ToArray() : null); } }
public override void Compute(CancellationToken cancellationToken) { switch (VisitedGraph.VertexCount) { case 0: return; case 1: VertexPositions.Add(VisitedGraph.Vertices.First(), new Point(0, 0)); return; } InitializeWithRandomPositions(1, 1, -0.5, -0.5); InitAlgorithm(); var finalRepuExponent = Parameters.repulsiveExponent; var finalAttrExponent = Parameters.attractionExponent; for (var step = 1; step <= Parameters.iterationCount; step++) { cancellationToken.ThrowIfCancellationRequested(); ComputeBaryCenter(); var quadTree = BuildQuadTree(); #region hûlési függvény meghatározása if (Parameters.iterationCount >= 50 && finalRepuExponent < 1.0) { Parameters.attractionExponent = finalAttrExponent; Parameters.repulsiveExponent = finalRepuExponent; if (step <= 0.6 * Parameters.iterationCount) { // use energy model with few local minima Parameters.attractionExponent += 1.1 * (1.0 - finalRepuExponent); Parameters.repulsiveExponent += 0.9 * (1.0 - finalRepuExponent); } else if (step <= 0.9 * Parameters.iterationCount) { // gradually move to final energy model Parameters.attractionExponent += 1.1 * (1.0 - finalRepuExponent) * (0.9 - step / (double)Parameters.iterationCount) / 0.3; Parameters.repulsiveExponent += 0.9 * (1.0 - finalRepuExponent) * (0.9 - step / (double)Parameters.iterationCount) / 0.3; } } #endregion #region Move each node for (var i = 0; i < _vertices.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); var v = _vertices[i]; var oldEnergy = GetEnergy(i, quadTree); // compute direction of the move of the node Vector bestDir; GetDirection(i, quadTree, out bestDir); // line search: compute length of the move var oldPos = v.Position; var bestEnergy = oldEnergy; var bestMultiple = 0; bestDir /= 32; //kisebb mozgatások esetén a legjobb eset meghatározása for (var multiple = 32; multiple >= 1 && (bestMultiple == 0 || bestMultiple / 2 == multiple); multiple /= 2) { cancellationToken.ThrowIfCancellationRequested(); v.Position = oldPos + bestDir * multiple; var curEnergy = GetEnergy(i, quadTree); if (curEnergy < bestEnergy) { bestEnergy = curEnergy; bestMultiple = multiple; } } //nagyobb mozgatás esetén van-e jobb megoldás? for (var multiple = 64; multiple <= 128 && bestMultiple == multiple / 2; multiple *= 2) { cancellationToken.ThrowIfCancellationRequested(); v.Position = oldPos + bestDir * multiple; var curEnergy = GetEnergy(i, quadTree); if (curEnergy < bestEnergy) { bestEnergy = curEnergy; bestMultiple = multiple; } } //legjobb megoldással mozgatás v.Position = oldPos + bestDir * bestMultiple; if (bestMultiple > 0) { quadTree.MoveNode(oldPos, v.Position, v.RepulsionWeight); } } #endregion /*if ( ReportOnIterationEndNeeded ) * Report( step );*/ } CopyPositions(); NormalizePositions(); }
public override void Compute(CancellationToken cancellationToken) { if (VisitedGraph.VertexCount == 1) { VertexPositions.Add(VisitedGraph.Vertices.First(), new Point(0, 0)); return; } #region Initialization _distances = new double[VisitedGraph.VertexCount, VisitedGraph.VertexCount]; _edgeLengths = new double[VisitedGraph.VertexCount, VisitedGraph.VertexCount]; _springConstants = new double[VisitedGraph.VertexCount, VisitedGraph.VertexCount]; _vertices = new TVertex[VisitedGraph.VertexCount]; _positions = new Point[VisitedGraph.VertexCount]; //initializing with random positions InitializeWithRandomPositions(Parameters.Width, Parameters.Height); //copy positions into array (speed-up) int index = 0; foreach (var v in VisitedGraph.Vertices) { _vertices[index] = v; _positions[index] = VertexPositions[v]; index++; } //calculating the diameter of the graph //TODO check the diameter algorithm _diameter = VisitedGraph.GetDiameter <TVertex, TEdge, TGraph>(out _distances); //L0 is the length of a side of the display area double l0 = Math.Min(Parameters.Width, Parameters.Height); //ideal length = L0 / max d_i,j _idealEdgeLength = (l0 / _diameter) * Parameters.LengthFactor; //calculating the ideal distance between the nodes for (int i = 0; i < VisitedGraph.VertexCount - 1; i++) { cancellationToken.ThrowIfCancellationRequested(); for (int j = i + 1; j < VisitedGraph.VertexCount; j++) { cancellationToken.ThrowIfCancellationRequested(); //distance between non-adjacent vertices double dist = _diameter * Parameters.DisconnectedMultiplier; //calculating the minimal distance between the vertices if (_distances[i, j] != double.MaxValue) { dist = Math.Min(_distances[i, j], dist); } if (_distances[j, i] != double.MaxValue) { dist = Math.Min(_distances[j, i], dist); } _distances[i, j] = _distances[j, i] = dist; _edgeLengths[i, j] = _edgeLengths[j, i] = _idealEdgeLength * dist; _springConstants[i, j] = _springConstants[j, i] = Parameters.K / Math.Pow(dist, 2); } } #endregion int n = VisitedGraph.VertexCount; if (n == 0) { return; } //TODO check this condition for (int currentIteration = 0; currentIteration < Parameters.MaxIterations; currentIteration++) { cancellationToken.ThrowIfCancellationRequested(); #region An iteration double maxDeltaM = double.NegativeInfinity; int pm = -1; //get the 'p' with the max delta_m for (int i = 0; i < n; i++) { cancellationToken.ThrowIfCancellationRequested(); double deltaM = CalculateEnergyGradient(i); if (maxDeltaM < deltaM) { maxDeltaM = deltaM; pm = i; } } //TODO is needed? if (pm == -1) { return; } //calculating the delta_x & delta_y with the Newton-Raphson method //there is an upper-bound for the while (deltaM > epsilon) {...} cycle (100) for (int i = 0; i < 100; i++) { _positions[pm] += CalcDeltaXY(pm); double deltaM = CalculateEnergyGradient(pm); //real stop condition if (deltaM < double.Epsilon) { break; } } //what if some of the vertices would be exchanged? if (Parameters.ExchangeVertices && maxDeltaM < double.Epsilon) { double energy = CalcEnergy(); for (int i = 0; i < n - 1; i++) { cancellationToken.ThrowIfCancellationRequested(); for (int j = i + 1; j < n; j++) { cancellationToken.ThrowIfCancellationRequested(); double xenergy = CalcEnergyIfExchanged(i, j); if (energy > xenergy) { Point p = _positions[i]; _positions[i] = _positions[j]; _positions[j] = p; return; } } } } #endregion /* if ( ReportOnIterationEndNeeded ) * Report( currentIteration );*/ } Report(Parameters.MaxIterations); }
public override void UpdateVertexData(TVertex vertex, Point position, Rect size) { VertexPositions.AddOrUpdate(vertex, position); VertexSizes.AddOrUpdate(vertex, size); }
/// <summary> /// Converts the record/s into a Unity GameObject structure with meshes, /// materials etc and imports into the scene. /// </summary> public override void ImportIntoScene() { // Create an empty gameobject UnityGameObject = new GameObject(ID); // DuckbearLab: FIX! //UnityGameObject.transform.localScale = Vector3.one; // Apply transformations UnityGameObject.transform.localPosition = Position; UnityGameObject.transform.localRotation = Rotation; if (Scale != Vector3.one) { UnityGameObject.transform.localScale = Scale; } // Assign parent if (Parent != null && Parent is InterRecord) { // DuckbearLab: FIX! UnityGameObject.transform.SetParent((Parent as InterRecord).UnityGameObject.transform, false); //UnityGameObject.transform.parent = (Parent as InterRecord).UnityGameObject.transform; } // Add Comment if (!string.IsNullOrEmpty(Comment)) { UnityGameObject.AddComponent <UFLT.MonoBehaviours.Comment>().Value = Comment; } // Processes children base.ImportIntoScene(); // Create mesh if (Vertices != null && Vertices.Count > 0) { Mesh m = new Mesh(); m.name = ID; m.vertices = VertexPositions.ToArray(); m.normals = Normals.ToArray(); m.uv = UVS.ToArray(); // DuckbearLab: Fix for very large meshes if (VertexPositions.Count >= ushort.MaxValue) { m.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; } MeshRenderer mr = UnityGameObject.AddComponent <MeshRenderer>(); Material[] mats = new Material[SubMeshes.Count]; MeshFilter mf = UnityGameObject.AddComponent <MeshFilter>(); // Set submeshes m.subMeshCount = SubMeshes.Count; for (int i = 0; i < SubMeshes.Count; i++) { mats[i] = SubMeshes[i].Key.UnityMaterial; m.SetTriangles(SubMeshes[i].Value.ToArray(), i); } // DuckbearLab: OPTIMIZE! //mr.materials = mats; ; { bool equal = true; foreach (var material in mats) { if (material != mats[0]) { equal = false; } } if (equal && SubMeshes.Count > 1) { CombineInstance[] combine = new CombineInstance[SubMeshes.Count]; for (int i = 0; i < combine.Length; i++) { combine[i].mesh = m; combine[i].subMeshIndex = i; } var newMesh = new Mesh(); newMesh.name = ID; newMesh.CombineMeshes(combine, true, false); m = newMesh; Material[] newMats = new Material[1]; newMats[0] = mats[0]; mr.materials = newMats; } else { mr.materials = mats; } } #if UNITY_EDITOR UnityEditor.MeshUtility.Optimize(m); #endif mf.mesh = m; } }
protected void CopyPositionsSilent(bool shouldTranslate) { //calculate the topLeft position var translation = new Vector(float.PositiveInfinity, float.PositiveInfinity); if (shouldTranslate) { foreach (var v in _graph.Vertices) { if (double.IsNaN(v.RealPosition.X) || double.IsNaN(v.RealPosition.Y)) { continue; } translation.X = Math.Min(v.RealPosition.X, translation.X); translation.Y = Math.Min(v.RealPosition.Y, translation.Y); } translation *= -1; translation.X += Parameters.VerticalGap / 2; translation.Y += Parameters.HorizontalGap / 2; //translate with the topLeft position foreach (var v in _graph.Vertices) { v.RealPosition += translation; } } else { translation = new Vector(0, 0); } //copy the positions of the vertices VertexPositions.Clear(); foreach (var v in _graph.Vertices) { if (v.IsDummyVertex) { continue; } Point pos = v.RealPosition; if (!shouldTranslate) { pos.X += v.Size.Width * 0.5 + translation.X; pos.Y += v.Size.Height * 0.5 + translation.Y; } VertexPositions[v.Original] = pos; } //copy the edge routes EdgeRoutes.Clear(); foreach (var e in _graph.HiddenEdges) { if (!e.IsLongEdge) { continue; } EdgeRoutes[e.Original] = e.IsReverted ? e.DummyVertices.Reverse().Select(dv => dv.RealPosition).ToArray() : e.DummyVertices.Select(dv => dv.RealPosition).ToArray(); } }
public override void Compute(CancellationToken cancellationToken) { //calculate the size of the circle double perimeter = 0; var usableVertices = VisitedGraph.Vertices.Where(v => v.SkipProcessing != ProcessingOptionEnum.Freeze).ToList(); //if we have empty input positions list we have to fill positions for frozen vertices manualy if (VertexPositions.Count == 0) { foreach (var item in VisitedGraph.Vertices.Where(v => v.SkipProcessing == ProcessingOptionEnum.Freeze)) { VertexPositions.Add(item, new Point()); } } double[] halfSize = new double[usableVertices.Count]; int i = 0; foreach (var v in usableVertices) { cancellationToken.ThrowIfCancellationRequested(); Size s = _sizes[v]; halfSize[i] = Math.Sqrt(s.Width * s.Width + s.Height * s.Height) * 0.5; perimeter += halfSize[i] * 2; i++; } double radius = perimeter / (2 * Math.PI); // //precalculation // double angle = 0, a; i = 0; foreach (var v in usableVertices) { cancellationToken.ThrowIfCancellationRequested(); a = Math.Sin(halfSize[i] * 0.5 / radius) * 2; angle += a; //if ( ReportOnIterationEndNeeded ) VertexPositions[v] = new Point(Math.Cos(angle) * radius + radius, Math.Sin(angle) * radius + radius); angle += a; } //if ( ReportOnIterationEndNeeded ) // OnIterationEnded( 0, 50, "Precalculation done.", false ); //recalculate radius radius = angle / (2 * Math.PI) * radius; //calculation angle = 0; i = 0; foreach (var v in usableVertices) { cancellationToken.ThrowIfCancellationRequested(); a = Math.Sin(halfSize[i] * 0.5 / radius) * 2; angle += a; VertexPositions[v] = new Point(Math.Cos(angle) * radius + radius, Math.Sin(angle) * radius + radius); angle += a; } }