Search code examples
gisopenstreetmapopenlayers

Rotate labels on tiles generated by Maperitive


I'm using custom generated tiles on web map (displayed using openlayers). Tiles are generated by maperetive and it's great. However my map is rotated -3/4Pi (openlayers has this feature) and many labels are rendered upside down. I belive maperitive has no feature to render labels relative to arbitrary angle. May be there are other options to fix this?

Example of rotated label


Solution

  • I was able to solve the problem altering dll's of Maperitive (v2.4.1) using dnSpy.

    Placement of labels is done by Karta.MapLabeling.Igor2LineFeatureLabelPlacementAlgorithm.EvaluatePosition() method (from Karta.dll). Below is the altered method. I added + 225f in three places. 225(deg) is equvalent of -3/4*Pi(radians). The added value should be positive.

    public static LabelPositionEvaluation EvaluatePosition(IPolylineAnalysis polylineAnalysis, float position, float? lengthAround)
            {
                if (lengthAround != null)
                {
                    float? num = lengthAround;
                    if (num.GetValueOrDefault() <= 0f && num != null)
                    {
                        throw new ArgumentOutOfRangeException("lengthAround");
                    }
                }
                LabelPositionEvaluation labelPositionEvaluation = new LabelPositionEvaluation(position);
                float polylineLength = polylineAnalysis.PolylineLength;
                float num2 = (lengthAround != null) ? (position * polylineLength - lengthAround.Value) : 0f;
                float num3 = (lengthAround != null) ? (position * polylineLength + lengthAround.Value) : (polylineLength * 0.9999f);
                labelPositionEvaluation.Fits = (num2 >= 0f && num3 <= polylineLength);
                if (!labelPositionEvaluation.Fits)
                {
                    return labelPositionEvaluation;
                }
                IPolylineWalker polylineWalker = polylineAnalysis.CreateWalker();
                polylineWalker.MoveTo(num2);
                int currentSegment = polylineWalker.CurrentSegment;
                float num4 = (polylineAnalysis.SegmentLengths[polylineWalker.CurrentSegment] - polylineWalker.CurrentOffsetWithinSegment) * polylineWalker.CurrentAngle;
                polylineWalker.MoveTo(num3);
                int currentSegment2 = polylineWalker.CurrentSegment;
                if (currentSegment2 == currentSegment)
                {
                    num4 = ((lengthAround != null) ? (polylineWalker.CurrentAngle * lengthAround.Value * 2f) : (polylineWalker.CurrentAngle * polylineLength));
                }
                else
                {
                    num4 += polylineWalker.CurrentOffsetWithinSegment * polylineWalker.CurrentAngle;
                }
                float num5 = 0f;
                for (int i = currentSegment; i < currentSegment2; i++)
                {
                    float num6 = (float)GeometryUtils.DifferenceBetweenAngles((double)polylineAnalysis.SegmentAngles[i], (double)polylineAnalysis.SegmentAngles[i + 1], 360.0);
                    if (num6 > num5)
                    {
                        num5 = num6;
                    }
                    if (i > currentSegment)
                    {
                        num4 += polylineAnalysis.SegmentLengths[i] * polylineAnalysis.SegmentAngles[i];
                    }
                }
                labelPositionEvaluation.AverageAngle = (float)GeometryUtils.NormalizeAngle((double)((lengthAround != null) ? (num4 / (lengthAround.Value * 2f) + 225f) : (num4 / polylineLength + 225f)), 360.0);
                labelPositionEvaluation.MaxCornerAngle = num5;
                float angleForPosition = (float)GeometryUtils.NormalizeAngle((double)(polylineAnalysis.GetAngleForPosition(labelPositionEvaluation.Position) + 225f), 360.0);
                labelPositionEvaluation.ForwardDirection = (angleForPosition < 90f || angleForPosition > 270f);
                return labelPositionEvaluation;
            }