/** * Removes the the symbols that overlap with area labels. * * @param symbols * list of symbols * @param pTC * list of labels */ private void removeOverlappingSymbolsWithAreaLabels(List <SymbolContainer> symbols, List <pointTextContainer> pTC) { int dis = LABEL_DISTANCE_TO_SYMBOL; for (int x = 0; x < pTC.Count; x++) { this.label = pTC[x]; this.rect1 = new Rect((int)this.label.x - dis, (int)(this.label.y - this.label.boundary.Height) - dis, (int)(this.label.x + this.label.boundary.Width + dis), (int)(this.label.y + dis)); for (int y = 0; y < symbols.Count; y++) { this.symbolContainer = symbols[y]; this.rect2 = new Rect((int)this.symbolContainer.point.X, (int)this.symbolContainer.point.Y, (int)(this.symbolContainer.point.X + this.symbolContainer.symbol.Width), (int)(this.symbolContainer.point.Y + this.symbolContainer.symbol.Height)); if (Utils.Intersects(this.rect1, this.rect2)) { symbols.Remove(this.symbolContainer); y--; } } } }
/** * This method removes the labels, that are not visible in the actual tile. * * @param labels * Labels from the actual tile */ private void removeOutOfTileLabels(List <pointTextContainer> labels) { for (int i = 0; i < labels.Count;) { this.label = labels[i]; if (this.label.x - this.label.boundary.Width / 2 > Tile.TileSize) { labels.Remove(this.label); this.label = null; } else if (this.label.y - this.label.boundary.Height > Tile.TileSize) { labels.Remove(this.label); this.label = null; } else if ((this.label.x - this.label.boundary.Width / 2 + this.label.boundary.Width) < 0.0f) { labels.Remove(this.label); this.label = null; } else if (this.label.y < 0.0f) { labels.Remove(this.label); this.label = null; } else { i++; } } }
/** * This method removes all the area labels, that overlap each other. So that the output is collision free * * @param areaLabels * area labels from the actual tile */ private void removeOverlappingAreaLabels(List <pointTextContainer> areaLabels) { int dis = LABEL_DISTANCE_TO_LABEL; for (int x = 0; x < areaLabels.Count; x++) { this.label = areaLabels[x]; this.rect1 = new Rect((int)this.label.x - dis, (int)this.label.y - dis, (int)(this.label.x + this.label.boundary.Width) + dis, (int)(this.label.y + this.label.boundary.Height + dis)); for (int y = x + 1; y < areaLabels.Count; y++) { if (y != x) { this.label = areaLabels[y]; this.rect2 = new Rect((int)this.label.x, (int)this.label.y, (int)(this.label.x + this.label.boundary.Width), (int)(this.label.y + this.label.boundary.Height)); if (Utils.Intersects(this.rect1, this.rect2)) { areaLabels.Remove(this.label); y--; } } } } }
/** * This method removes the area labels, that are not visible in the actual tile. * * @param areaLabels * area Labels from the actual tile */ private void removeOutOfTileAreaLabels(List <pointTextContainer> areaLabels) { for (int i = 0; i < areaLabels.Count; i++) { this.label = areaLabels[i]; if (this.label.x > Tile.TileSize) { areaLabels.Remove(this.label); i--; } else if (this.label.y - this.label.boundary.Height > Tile.TileSize) { areaLabels.Remove(this.label); i--; } else if (this.label.x + this.label.boundary.Width < 0.0f) { areaLabels.Remove(this.label); i--; } else if (this.label.y + this.label.boundary.Height < 0.0f) { areaLabels.Remove(this.label); i--; } } }
/** * Centers the labels. * * @param labels * labels to center */ private void centerLabels(List <pointTextContainer> labels) { for (int i = 0; i < labels.Count; i++) { this.label = labels[i]; this.label.x = this.label.x - this.label.boundary.Width / 2; } }
private void removeEmptySymbolReferences(List <pointTextContainer> nodes, List <SymbolContainer> symbols) { for (int i = 0; i < nodes.Count; i++) { this.label = nodes[i]; if (!symbols.Contains(this.label.symbol)) { this.label.symbol = null; } } }
/** * This method uses an adapted greedy strategy for the fixed two position model, above and under. It uses no * priority search tree, because it will not function with symbols only with points. Instead it uses two minimum * heaps. They work similar to a sweep line algorithm but have not a O(n log n +k) runtime. To find the rectangle * that has the leftest edge, I use also a minimum Heap. The rectangles are sorted by their x coordinates. * * @param labels * label positions and text * @param symbols * symbol positions * @param areaLabels * area label positions and text * @return list of labels without overlaps with symbols and other labels by the two fixed position greedy strategy */ private List <pointTextContainer> processTwopointGreedy(List <pointTextContainer> labels, List <SymbolContainer> symbols, List <pointTextContainer> areaLabels) { List <pointTextContainer> resolutionSet = new List <pointTextContainer>(); // Array for the generated reference positions around the points of interests ReferencePosition[] refPos = new ReferencePosition[labels.Count * 2]; // lists that sorts the reference points after the minimum right edge x position PriorityQueue <ReferencePosition> priorRight = new PriorityQueue <ReferencePosition>(labels.Count * 2 + labels.Count / 10 * 2, ReferencePositionWidthComparator.INSTANCE); // lists that sorts the reference points after the minimum left edge x position PriorityQueue <ReferencePosition> priorLeft = new PriorityQueue <ReferencePosition>(labels.Count * 2 + labels.Count / 10 * 2, ReferencePositionXComparator.INSTANCE); // creates the reference positions for (int z = 0; z < labels.Count; z++) { this.label = labels[z]; if (this.label.symbol != null) { refPos[z * 2] = new ReferencePosition(this.label.x - (this.label.boundary.Width / 2) - 0.1f, this.label.y - this.label.boundary.Height - LabelPlacement.START_DISTANCE_TO_SYMBOLS, z, this.label.boundary.Width, this.label.boundary.Height, this.label.symbol); refPos[z * 2 + 1] = new ReferencePosition(this.label.x - (this.label.boundary.Width / 2), this.label.y + this.label.symbol.symbol.Height + LabelPlacement.START_DISTANCE_TO_SYMBOLS, z, this.label.boundary.Width, this.label.boundary.Height, this.label.symbol); } else { refPos[z * 2] = new ReferencePosition(this.label.x - (this.label.boundary.Width / 2) - 0.1f, this.label.y, z, this.label.boundary.Width, this.label.boundary.Height, null); refPos[z * 2 + 1] = null; } } // removes reference positions that overlaps with other symbols or dependency objects removeNonValidateReferencePosition(refPos, symbols, areaLabels); for (int i = 0; i < refPos.Length; i++) { this.referencePosition = refPos[i]; if (this.referencePosition != null) { priorLeft.Add(this.referencePosition); priorRight.Add(this.referencePosition); } } while (priorRight.Count != 0) { this.referencePosition = priorRight.Pool(); this.label = labels[this.referencePosition.nodeNumber]; resolutionSet.Add(new PointTextContainer(this.label.text, this.referencePosition.x, this.referencePosition.y, this.label.paintFront, this.label.paintBack, this.referencePosition.symbol)); // Removes the other position that is a possible position for the label of one point // of interest priorRight.Remove(refPos[this.referencePosition.nodeNumber * 2 + 1]); if (priorRight.Count == 0) { return(resolutionSet); } priorLeft.Remove(this.referencePosition); priorLeft.Remove(refPos[this.referencePosition.nodeNumber * 2 + 1]); // find overlapping labels and deletes the reference points and delete them LinkedList <ReferencePosition> linkedRef = new LinkedList <ReferencePosition>(); while (priorLeft.Count != 0) { if (priorLeft.Peek().x < this.referencePosition.x + this.referencePosition.width) { linkedRef.AddLast(priorLeft.Pool()); } else { break; } } // brute Force collision test (faster then sweep line for a small amount of // objects) linkedRef.RemoveAll(e => (e.x <= this.referencePosition.x + this.referencePosition.width) && (e.y >= this.referencePosition.y - e.height) && (e.y <= this.referencePosition.y + e.height)); priorLeft.AddRange(linkedRef); } return(resolutionSet); }
/** * This method uses an adapted greedy strategy for the fixed four position model, above, under left and right form * the point of interest. It uses no priority search tree, because it will not function with symbols only with * points. Instead it uses two minimum heaps. They work similar to a sweep line algorithm but have not a O(n log n * +k) runtime. To find the rectangle that has the top edge, I use also a minimum Heap. The rectangles are sorted by * their y coordinates. * * @param labels * label positions and text * @param symbols * symbol positions * @param areaLabels * area label positions and text * @return list of labels without overlaps with symbols and other labels by the four fixed position greedy strategy */ private List <pointTextContainer> processFourpointGreedy(List <pointTextContainer> labels, List <SymbolContainer> symbols, List <pointTextContainer> areaLabels) { List <pointTextContainer> resolutionSet = new List <pointTextContainer>(); // Array for the generated reference positions around the points of interests ReferencePosition[] refPos = new ReferencePosition[(labels.Count) * 4]; // lists that sorts the reference points after the minimum top edge y position PriorityQueue <ReferencePosition> priorUp = new PriorityQueue <ReferencePosition>(labels.Count * 4 * 2 + labels.Count / 10 * 2, ReferencePositionYComparator.INSTANCE); // lists that sorts the reference points after the minimum bottom edge y position PriorityQueue <ReferencePosition> priorDown = new PriorityQueue <ReferencePosition>(labels.Count * 4 * 2 + labels.Count / 10 * 2, ReferencePositionHeightComparator.INSTANCE); pointTextContainer tmp; int dis = START_DISTANCE_TO_SYMBOLS; // creates the reference positions for (int z = 0; z < labels.Count; z++) { if (labels[z] != null) { if (labels[z].symbol != null) { tmp = labels[z]; // up refPos[z * 4] = new ReferencePosition(tmp.x - tmp.boundary.Width / 2, tmp.y - tmp.symbol.symbol.Height / 2 - dis, z, tmp.boundary.Width, tmp.boundary.Height, tmp.symbol); // down refPos[z * 4 + 1] = new ReferencePosition(tmp.x - tmp.boundary.Width / 2, tmp.y + tmp.symbol.symbol.Height / 2 + tmp.boundary.Height + dis, z, tmp.boundary.Width, tmp.boundary.Height, tmp.symbol); // left refPos[z * 4 + 2] = new ReferencePosition(tmp.x - tmp.symbol.symbol.Width / 2 - tmp.boundary.Width - dis, tmp.y + tmp.boundary.Height / 2, z, tmp.boundary.Width, tmp.boundary.Height, tmp.symbol); // right refPos[z * 4 + 3] = new ReferencePosition(tmp.x + tmp.symbol.symbol.Width / 2 + dis, tmp.y + tmp.boundary.Height / 2 - 0.1f, z, tmp.boundary.Width, tmp.boundary.Height, tmp.symbol); } else { refPos[z * 4] = new ReferencePosition(labels[z].x - ((labels[z].boundary.Width) / 2), labels[z].y, z, labels[z].boundary.Width, labels[z].boundary.Height, null); refPos[z * 4 + 1] = null; refPos[z * 4 + 2] = null; refPos[z * 4 + 3] = null; } } } removeNonValidateReferencePosition(refPos, symbols, areaLabels); // do while it gives reference positions for (int i = 0; i < refPos.Length; i++) { this.referencePosition = refPos[i]; if (this.referencePosition != null) { priorUp.Add(this.referencePosition); priorDown.Add(this.referencePosition); } } while (priorUp.Count != 0) { this.referencePosition = priorUp.Pool(); this.label = labels[this.referencePosition.nodeNumber]; resolutionSet.Add(new PointTextContainer(this.label.text, this.referencePosition.x, this.referencePosition.y, this.label.paintFront, this.label.paintBack, this.label.symbol)); if (priorUp.Count == 0) { return(resolutionSet); } priorUp.Remove(refPos[this.referencePosition.nodeNumber * 4 + 0]); priorUp.Remove(refPos[this.referencePosition.nodeNumber * 4 + 1]); priorUp.Remove(refPos[this.referencePosition.nodeNumber * 4 + 2]); priorUp.Remove(refPos[this.referencePosition.nodeNumber * 4 + 3]); priorDown.Remove(refPos[this.referencePosition.nodeNumber * 4 + 0]); priorDown.Remove(refPos[this.referencePosition.nodeNumber * 4 + 1]); priorDown.Remove(refPos[this.referencePosition.nodeNumber * 4 + 2]); priorDown.Remove(refPos[this.referencePosition.nodeNumber * 4 + 3]); LinkedList <ReferencePosition> linkedRef = new LinkedList <ReferencePosition>(); while (priorDown.Count != 0) { if (priorDown.Peek().x < this.referencePosition.x + this.referencePosition.width) { linkedRef.AddLast(priorDown.Pool()); } else { break; } } // brute Force collision test (faster then sweep line for a small amount of // objects) linkedRef.RemoveAll(e => (e.x <= this.referencePosition.x + this.referencePosition.width) && (e.y >= this.referencePosition.y - e.height) && (e.y <= this.referencePosition.y + e.height)); priorDown.AddRange(linkedRef); } return(resolutionSet); }